From 8e4777a5ff0b3405a0d628ef5465d97683a0276d Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Mon, 8 Jul 2024 09:01:08 -0400 Subject: [PATCH 001/315] libvirt start --- salt/libvirt/configbad | 51 ++ salt/libvirt/configgood | 50 ++ salt/libvirt/configstock | 51 ++ salt/libvirt/configstockstock | 536 ++++++++++++++++++ salt/libvirt/defaults.yaml | 53 ++ salt/libvirt/etc/libvirtd.conf.jinja | 8 + salt/libvirt/init.sls | 80 +++ salt/libvirt/map.jinja | 7 + ...python-10.5.0-cp310-cp310-linux_x86_64.whl | Bin 0 -> 504724 bytes 9 files changed, 836 insertions(+) create mode 100644 salt/libvirt/configbad create mode 100644 salt/libvirt/configgood create mode 100644 salt/libvirt/configstock create mode 100644 salt/libvirt/configstockstock create mode 100644 salt/libvirt/defaults.yaml create mode 100644 salt/libvirt/etc/libvirtd.conf.jinja create mode 100644 salt/libvirt/init.sls create mode 100644 salt/libvirt/map.jinja create mode 100644 salt/libvirt/source-packages/libvirt-python/libvirt_python-10.5.0-cp310-cp310-linux_x86_64.whl diff --git a/salt/libvirt/configbad b/salt/libvirt/configbad new file mode 100644 index 000000000..0cf5f9ef5 --- /dev/null +++ b/salt/libvirt/configbad @@ -0,0 +1,51 @@ +listen_tls = 0 +listen_tcp = 0 +tls_port = "16514" +tcp_port = "16509" +listen_addr = "0.0.0.0" +unix_sock_group = "root" +unix_sock_ro_perms = "0777" +unix_sock_rw_perms = "0770" +unix_sock_admin_perms = "0700" +unix_sock_dir = "/run/libvirt" +auth_unix_ro = "none" +auth_unix_rw = "none" +auth_tcp = "none" +auth_tls = "none" +tcp_min_ssf = 112 +access_drivers = ["nop"] +key_file = "/etc/pki/libvirt/private/serverkey.pem" +cert_file = "/etc/pki/libvirt/servercert.pem" +ca_file = "/etc/pki/CA/cacert.pem" +crl_file = "/etc/pki/CA/crl.pem" +tls_no_sanity_certificate = 0 +tls_no_verify_certificate = 0 +tls_allowed_dn_list = ["DN1", "DN2"] +tls_priority = "NORMAL" +sasl_allowed_username_list = ["joe@EXAMPLE.COM", "fred@EXAMPLE.COM"] +max_clients = 5000 +max_queued_clients = 1000 +max_anonymous_clients = 20 +min_workers = 5 +max_workers = 20 +prio_workers = 5 +max_client_requests = 5 +admin_min_workers = 1 +admin_max_workers = 5 +admin_max_clients = 5 +admin_max_queued_clients = 5 +admin_max_client_requests = 5 +log_level = 3 +log_filters = "1:qemu 1:libvirt 4:object 4:json 4:event 1:util" +log_outputs = "3:syslog:libvirtd" +audit_level = 2 +audit_logging = 1 +host_uuid = "00000000-0000-0000-0000-000000000000" +host_uuid_source = "smbios" +keepalive_interval = 5 +keepalive_count = 5 +keepalive_required = 1 +admin_keepalive_required = 1 +admin_keepalive_interval = 5 +admin_keepalive_count = 5 +ovs_timeout = 5 diff --git a/salt/libvirt/configgood b/salt/libvirt/configgood new file mode 100644 index 000000000..72369709d --- /dev/null +++ b/salt/libvirt/configgood @@ -0,0 +1,50 @@ +#listen_tls = "0" +#listen_tcp = "0" +#tls_port = "16514" +#tcp_port = "16509" +#listen_addr = "0.0.0.0" +#unix_sock_group = "root" +#unix_sock_ro_perms = "0777" +#unix_sock_rw_perms = "0770" +#unix_sock_admin_perms = "0700" +#unix_sock_dir = "/run/libvirt" +#auth_unix_ro = "none" +#auth_unix_rw = "none" +#auth_tcp = "none" +#auth_tls = "none" +#access_drivers = "[ \"nop\" ]" +#key_file = "/etc/pki/libvirt/private/serverkey.pem" +#cert_file = "/etc/pki/libvirt/servercert.pem" +#ca_file = "/etc/pki/CA/cacert.pem" +#crl_file = "/etc/pki/CA/crl.pem" +#tls_no_sanity_certificate = "0" +#tls_no_verify_certificate = "0" +#tls_allowed_dn_list = "[\"DN1\", \"DN2\"]" +#tls_priority = "NORMAL" +#sasl_allowed_username_list = "[\"joe@example.com\", \"fred@example.com\"]" +#max_clients = "5000" +#max_queued_clients = "20" +#max_anonymous_clients = "20" +#min_workers = "5" +#max_workers = "20" +#prio_workers = "5" +#max_client_requests = "5" +#admin_min_workers = "1" +#admin_max_workers = "5" +#admin_max_clients = "5" +#admin_max_queued_clients = "5" +#admin_max_client_requests = "5" +#log_level = "3" +#log_filters = "\"1:qemu 1:libvirt 4:object 4:json 4:event 1:util\"" +#log_outputs = "\"3:syslog:libvirtd\"" +#audit_level = "1" +#audit_logging = "0" +#host_uuid = "00000000-0000-0000-0000-000000000000" +#host_uuid_source = "smbios" +#keepalive_interval = "5" +#keepalive_count = "5" +#keepalive_required = "0" +#admin_keepalive_required = "0" +#admin_keepalive_interval = "5" +#admin_keepalive_count = "5" +#ovs_timeout = "5" diff --git a/salt/libvirt/configstock b/salt/libvirt/configstock new file mode 100644 index 000000000..ac1174cfb --- /dev/null +++ b/salt/libvirt/configstock @@ -0,0 +1,51 @@ +#listen_tls = 0 +#listen_tcp = 1 +#tls_port = "16514" +#tcp_port = "16509" +#listen_addr = "192.168.0.1" +#unix_sock_group = "libvirt" +#unix_sock_ro_perms = "0777" +#unix_sock_rw_perms = "0770" +#unix_sock_admin_perms = "0700" +#unix_sock_dir = "/run/libvirt" +#auth_unix_ro = "polkit" +#auth_unix_rw = "polkit" +#auth_tcp = "sasl" +#auth_tls = "none" +#tcp_min_ssf = 112 +#access_drivers = [ "polkit" ] +#key_file = "/etc/pki/libvirt/private/serverkey.pem" +#cert_file = "/etc/pki/libvirt/servercert.pem" +#ca_file = "/etc/pki/CA/cacert.pem" +#crl_file = "/etc/pki/CA/crl.pem" +#tls_no_sanity_certificate = 1 +#tls_no_verify_certificate = 1 +#tls_allowed_dn_list = ["DN1", "DN2"] +#tls_priority="NORMAL" +#sasl_allowed_username_list = ["joe@EXAMPLE.COM", "fred@EXAMPLE.COM" ] +#max_clients = 5000 +#max_queued_clients = 1000 +#max_anonymous_clients = 20 +#min_workers = 5 +#max_workers = 20 +#prio_workers = 5 +#max_client_requests = 5 +#admin_min_workers = 1 +#admin_max_workers = 5 +#admin_max_clients = 5 +#admin_max_queued_clients = 5 +#admin_max_client_requests = 5 +#log_level = 3 +#log_filters="1:qemu 1:libvirt 4:object 4:json 4:event 1:util" +#log_outputs="3:syslog:libvirtd" +#audit_level = 2 +#audit_logging = 1 +#host_uuid = "00000000-0000-0000-0000-000000000000" +#host_uuid_source = "smbios" +#keepalive_interval = 5 +#keepalive_count = 5 +#keepalive_required = 1 +#admin_keepalive_required = 1 +#admin_keepalive_interval = 5 +#admin_keepalive_count = 5 +#ovs_timeout = 5 diff --git a/salt/libvirt/configstockstock b/salt/libvirt/configstockstock new file mode 100644 index 000000000..d8bb42b6b --- /dev/null +++ b/salt/libvirt/configstockstock @@ -0,0 +1,536 @@ +# Master libvirt daemon configuration file +# + +################################################################# +# +# Network connectivity controls +# + +# Flag listening for secure TLS connections on the public TCP/IP port. +# +# To enable listening sockets with the 'libvirtd' daemon it's also required to +# pass the '--listen' flag on the commandline of the daemon. +# This is not needed with 'virtproxyd'. +# +# This setting is not required or honoured if using systemd socket +# activation. +# +# It is necessary to setup a CA and issue server certificates before +# using this capability. +# +# This is enabled by default, uncomment this to disable it +#listen_tls = 0 + +# Listen for unencrypted TCP connections on the public TCP/IP port. +# +# To enable listening sockets with the 'libvirtd' daemon it's also required to +# pass the '--listen' flag on the commandline of the daemon. +# This is not needed with 'virtproxyd'. +# +# This setting is not required or honoured if using systemd socket +# activation. +# +# Using the TCP socket requires SASL authentication by default. Only +# SASL mechanisms which support data encryption are allowed. This is +# DIGEST_MD5 and GSSAPI (Kerberos5) +# +# This is disabled by default, uncomment this to enable it. +#listen_tcp = 1 + + + +# Override the port for accepting secure TLS connections +# This can be a port number, or service name +# +# This setting is not required or honoured if using systemd socket +# activation. +# +#tls_port = "16514" + +# Override the port for accepting insecure TCP connections +# This can be a port number, or service name +# +# This setting is not required or honoured if using systemd socket +# activation. +# +#tcp_port = "16509" + + +# Override the default configuration which binds to all network +# interfaces. This can be a numeric IPv4/6 address, or hostname +# +# This setting is not required or honoured if using systemd socket +# activation. +# +# If the libvirtd service is started in parallel with network +# startup (e.g. with systemd), binding to addresses other than +# the wildcards (0.0.0.0/::) might not be available yet. +# +#listen_addr = "192.168.0.1" + + +################################################################# +# +# UNIX socket access controls +# + +# Set the UNIX domain socket group ownership. This can be used to +# allow a 'trusted' set of users access to management capabilities +# without becoming root. +# +# This setting is not required or honoured if using systemd socket +# activation. +# +# This is restricted to 'root' by default. +#unix_sock_group = "libvirt" + +# Set the UNIX socket permissions for the R/O socket. This is used +# for monitoring VM status only +# +# This setting is not required or honoured if using systemd socket +# activation. +# +# Default allows any user. If setting group ownership, you may want to +# restrict this too. +#unix_sock_ro_perms = "0777" + +# Set the UNIX socket permissions for the R/W socket. This is used +# for full management of VMs +# +# This setting is not required or honoured if using systemd socket +# activation. +# +# Default allows only root. If PolicyKit is enabled on the socket, +# the default will change to allow everyone (eg, 0777) +# +# If not using PolicyKit and setting group ownership for access +# control, then you may want to relax this too. +#unix_sock_rw_perms = "0770" + +# Set the UNIX socket permissions for the admin interface socket. +# +# This setting is not required or honoured if using systemd socket +# activation. +# +# Default allows only owner (root), do not change it unless you are +# sure to whom you are exposing the access to. +#unix_sock_admin_perms = "0700" + +# Set the name of the directory in which sockets will be found/created. +# +# This setting is not required or honoured if using systemd socket +# activation. +# +#unix_sock_dir = "/run/libvirt" + + + +################################################################# +# +# Authentication. +# +# There are the following choices available: +# +# - none: do not perform auth checks. If you can connect to the +# socket you are allowed. This is suitable if there are +# restrictions on connecting to the socket (eg, UNIX +# socket permissions), or if there is a lower layer in +# the network providing auth (eg, TLS/x509 certificates) +# +# - sasl: use SASL infrastructure. The actual auth scheme is then +# controlled from /etc/sasl2/libvirt.conf. For the TCP +# socket only GSSAPI & DIGEST-MD5 mechanisms will be used. +# For non-TCP or TLS sockets, any scheme is allowed. +# +# - polkit: use PolicyKit to authenticate. This is only suitable +# for use on the UNIX sockets. The default policy will +# require a user to supply their own password to gain +# full read/write access (aka sudo like), while anyone +# is allowed read/only access. +# + +# Set an authentication scheme for UNIX read-only sockets +# +# By default socket permissions allow anyone to connect +# +# If libvirt was compiled without support for 'polkit', then +# no access control checks are done, but libvirt still only +# allows execution of APIs which don't change state. +# +# If libvirt was compiled with support for 'polkit', then +# the libvirt socket will perform a check with polkit after +# connections. The default policy still allows any local +# user access. +# +# To restrict monitoring of domains you may wish to either +# enable 'sasl' here, or change the polkit policy definition. +#auth_unix_ro = "polkit" + +# Set an authentication scheme for UNIX read-write sockets. +# +# If libvirt was compiled without support for 'polkit', then +# the systemd .socket files will use SocketMode=0600 by default +# thus only allowing root user to connect, and 'auth_unix_rw' +# will default to 'none'. +# +# If libvirt was compiled with support for 'polkit', then +# the systemd .socket files will use SocketMode=0666 which +# allows any user to connect and 'auth_unix_rw' will default +# to 'polkit'. If you disable use of 'polkit' here, then it +# is essential to change the systemd SocketMode parameter +# back to 0600, to avoid an insecure configuration. +# +#auth_unix_rw = "polkit" + +# Change the authentication scheme for TCP sockets. +# +# If you don't enable SASL, then all TCP traffic is cleartext. +# Don't do this outside of a dev/test scenario. For real world +# use, always enable SASL and use the GSSAPI or DIGEST-MD5 +# mechanism in /etc/sasl2/libvirt.conf +#auth_tcp = "sasl" + +# Change the authentication scheme for TLS sockets. +# +# TLS sockets already have encryption provided by the TLS +# layer, and limited authentication is done by certificates +# +# It is possible to make use of any SASL authentication +# mechanism as well, by using 'sasl' for this option +#auth_tls = "none" + +# Enforce a minimum SSF value for TCP sockets +# +# The default minimum is currently 56 (single-DES) which will +# be raised to 112 in the future. +# +# This option can be used to set values higher than 112 +#tcp_min_ssf = 112 + + +# Change the API access control scheme +# +# By default an authenticated user is allowed access +# to all APIs. Access drivers can place restrictions +# on this. By default the 'nop' driver is enabled, +# meaning no access control checks are done once a +# client has authenticated with libvirtd +# +#access_drivers = [ "polkit" ] + +################################################################# +# +# TLS x509 certificate configuration +# + +# Use of TLS requires that x509 certificates be issued. The default locations +# for the certificate files is as follows: +# +# /etc/pki/CA/cacert.pem - The CA master certificate +# /etc/pki/libvirt/servercert.pem - The server certificate signed by cacert.pem +# /etc/pki/libvirt/private/serverkey.pem - The server private key +# +# It is possible to override the default locations by altering the 'key_file', +# 'cert_file', and 'ca_file' values and uncommenting them below. +# +# NB, overriding the default of one location requires uncommenting and +# possibly additionally overriding the other settings. +# + +# Override the default server key file path +# +#key_file = "/etc/pki/libvirt/private/serverkey.pem" + +# Override the default server certificate file path +# +#cert_file = "/etc/pki/libvirt/servercert.pem" + +# Override the default CA certificate path +# +#ca_file = "/etc/pki/CA/cacert.pem" + +# Specify a certificate revocation list. +# +# Defaults to not using a CRL, uncomment to enable it +#crl_file = "/etc/pki/CA/crl.pem" + + + +################################################################# +# +# Authorization controls +# + + +# Flag to disable verification of our own server certificates +# +# When libvirtd starts it performs some sanity checks against +# its own certificates. +# +# Default is to always run sanity checks. Uncommenting this +# will disable sanity checks which is not a good idea +#tls_no_sanity_certificate = 1 + +# Flag to disable verification of client certificates +# +# Client certificate verification is the primary authentication mechanism. +# Any client which does not present a certificate signed by the CA +# will be rejected. +# +# Default is to always verify. Uncommenting this will disable +# verification. +#tls_no_verify_certificate = 1 + + +# An access control list of allowed x509 Distinguished Names +# This list may contain wildcards such as +# +# "C=GB,ST=London,L=London,O=Red Hat,CN=*" +# +# Any * matches any number of consecutive spaces, like a simplified glob(7). +# +# The format of the DN for a particular certificate can be queried +# using: +# +# virt-pki-query-dn clientcert.pem +# +# NB If this is an empty list, no client can connect, so comment out +# entirely rather than using empty list to disable these checks +# +# By default, no DN's are checked +#tls_allowed_dn_list = ["DN1", "DN2"] + + +# Override the compile time default TLS priority string. The +# default is usually "NORMAL" unless overridden at build time. +# Only set this is it is desired for libvirt to deviate from +# the global default settings. +# +#tls_priority="NORMAL" + + +# An access control list of allowed SASL usernames. The format for username +# depends on the SASL authentication mechanism. Kerberos usernames +# look like username@REALM +# +# This list may contain wildcards such as +# +# "*@EXAMPLE.COM" +# +# See the g_pattern_match function for the format of the wildcards. +# +# https://developer.gnome.org/glib/stable/glib-Glob-style-pattern-matching.html +# +# NB If this is an empty list, no client can connect, so comment out +# entirely rather than using empty list to disable these checks +# +# By default, no Username's are checked +#sasl_allowed_username_list = ["joe@EXAMPLE.COM", "fred@EXAMPLE.COM" ] + + +################################################################# +# +# Processing controls +# + +# The maximum number of concurrent client connections to allow +# over all sockets combined. +#max_clients = 5000 + +# The maximum length of queue of connections waiting to be +# accepted by the daemon. Note, that some protocols supporting +# retransmission may obey this so that a later reattempt at +# connection succeeds. +#max_queued_clients = 1000 + +# The maximum length of queue of accepted but not yet +# authenticated clients. The default value is 20. Set this to +# zero to turn this feature off. +#max_anonymous_clients = 20 + +# The minimum limit sets the number of workers to start up +# initially. If the number of active clients exceeds this, +# then more threads are spawned, up to max_workers limit. +# Typically you'd want max_workers to equal maximum number +# of clients allowed +#min_workers = 5 +#max_workers = 20 + + +# The number of priority workers. If all workers from above +# pool are stuck, some calls marked as high priority +# (notably domainDestroy) can be executed in this pool. +#prio_workers = 5 + +# Limit on concurrent requests from a single client +# connection. To avoid one client monopolizing the server +# this should be a small fraction of the global max_workers +# parameter. +# Setting this too low may cause keepalive timeouts. +#max_client_requests = 5 + +# Same processing controls, but this time for the admin interface. +# For description of each option, be so kind to scroll few lines +# upwards. + +#admin_min_workers = 1 +#admin_max_workers = 5 +#admin_max_clients = 5 +#admin_max_queued_clients = 5 +#admin_max_client_requests = 5 + +################################################################# +# +# Logging controls +# + +# Logging level: 4 errors, 3 warnings, 2 information, 1 debug +# basically 1 will log everything possible +# +# WARNING: USE OF THIS IS STRONGLY DISCOURAGED. +# +# WARNING: It outputs too much information to practically read. +# WARNING: The "log_filters" setting is recommended instead. +# +# WARNING: Journald applies rate limiting of messages and so libvirt +# WARNING: will limit "log_level" to only allow values 3 or 4 if +# WARNING: journald is the current output. +# +# WARNING: USE OF THIS IS STRONGLY DISCOURAGED. +#log_level = 3 + +# Logging filters: +# A filter allows to select a different logging level for a given category +# of logs. The format for a filter is: +# +# level:match +# +# where 'match' is a string which is matched against the category +# given in the VIR_LOG_INIT() at the top of each libvirt source +# file, e.g., "remote", "qemu", or "util.json". The 'match' in the +# filter matches using shell wildcard syntax (see 'man glob(7)'). +# The 'match' is always treated as a substring match. IOW a match +# string 'foo' is equivalent to '*foo*'. +# +# 'level' is the minimal level where matching messages should +# be logged: +# +# 1: DEBUG +# 2: INFO +# 3: WARNING +# 4: ERROR +# +# Multiple filters can be defined in a single @log_filters, they just need +# to be separated by spaces. Note that libvirt performs "first" match, i.e. +# if there are concurrent filters, the first one that matches will be applied, +# given the order in @log_filters. +# +# A typical need is to capture information from a hypervisor driver, +# public API entrypoints and some of the utility code. Some utility +# code is very verbose and is generally not desired. Taking the QEMU +# hypervisor as an example, a suitable filter string for debugging +# might be to turn off object, json & event logging, but enable the +# rest of the util code: +# +#log_filters="1:qemu 1:libvirt 4:object 4:json 4:event 1:util" + +# Logging outputs: +# An output is one of the places to save logging information +# The format for an output can be: +# level:stderr +# output goes to stderr +# level:syslog:name +# use syslog for the output and use the given name as the ident +# level:file:file_path +# output to a file, with the given filepath +# level:journald +# output to journald logging system +# In all cases 'level' is the minimal priority, acting as a filter +# 1: DEBUG +# 2: INFO +# 3: WARNING +# 4: ERROR +# +# Multiple outputs can be defined, they just need to be separated by spaces. +# e.g. to log all warnings and errors to syslog under the libvirtd ident: +#log_outputs="3:syslog:libvirtd" + + +################################################################## +# +# Auditing +# +# This setting allows usage of the auditing subsystem to be altered: +# +# audit_level == 0 -> disable all auditing +# audit_level == 1 -> enable auditing, only if enabled on host (default) +# audit_level == 2 -> enable auditing, and exit if disabled on host +# +#audit_level = 2 +# +# If set to 1, then audit messages will also be sent +# via libvirt logging infrastructure. Defaults to 0 +# +#audit_logging = 1 + +################################################################### +# UUID of the host: +# Host UUID is read from one of the sources specified in host_uuid_source. +# +# - 'smbios': fetch the UUID from 'dmidecode -s system-uuid' +# - 'machine-id': fetch the UUID from /etc/machine-id +# +# The host_uuid_source default is 'smbios'. If 'dmidecode' does not provide +# a valid UUID a temporary UUID will be generated. +# +# Another option is to specify host UUID in host_uuid. +# +# Keep the format of the example UUID below. UUID must not have all digits +# be the same. + +# NB This default all-zeros UUID will not work. Replace +# it with the output of the 'uuidgen' command and then +# uncomment this entry +#host_uuid = "00000000-0000-0000-0000-000000000000" +#host_uuid_source = "smbios" + +################################################################### +# Keepalive protocol: +# This allows libvirtd to detect broken client connections or even +# dead clients. A keepalive message is sent to a client after +# keepalive_interval seconds of inactivity to check if the client is +# still responding; keepalive_count is a maximum number of keepalive +# messages that are allowed to be sent to the client without getting +# any response before the connection is considered broken. In other +# words, the connection is automatically closed approximately after +# keepalive_interval * (keepalive_count + 1) seconds since the last +# message received from the client. If keepalive_interval is set to +# -1, libvirtd will never send keepalive requests; however clients +# can still send them and the daemon will send responses. When +# keepalive_count is set to 0, connections will be automatically +# closed after keepalive_interval seconds of inactivity without +# sending any keepalive messages. +# +#keepalive_interval = 5 +#keepalive_count = 5 + +# +# These configuration options are no longer used. There is no way to +# restrict such clients from connecting since they first need to +# connect in order to ask for keepalive. +# +#keepalive_required = 1 +#admin_keepalive_required = 1 + +# Keepalive settings for the admin interface +#admin_keepalive_interval = 5 +#admin_keepalive_count = 5 + +################################################################### +# Open vSwitch: +# This allows to specify a timeout for openvswitch calls made by +# libvirt. The ovs-vsctl utility is used for the configuration and +# its timeout option is set by default to 5 seconds to avoid +# potential infinite waits blocking libvirt. +# +#ovs_timeout = 5 diff --git a/salt/libvirt/defaults.yaml b/salt/libvirt/defaults.yaml new file mode 100644 index 000000000..1905b2e8f --- /dev/null +++ b/salt/libvirt/defaults.yaml @@ -0,0 +1,53 @@ +libvirt: + config: + listen_tls: 1 + listen_tcp: 0 + tls_port: "16514" + tcp_port: "16509" + listen_addr: "0.0.0.0" + unix_sock_group: "root" + unix_sock_ro_perms: "0777" + unix_sock_rw_perms: "0770" + unix_sock_admin_perms: "0700" + unix_sock_dir: "/run/libvirt" + auth_unix_ro: "none" + auth_unix_rw: "none" + auth_tcp: "none" + auth_tls: "none" + tcp_min_ssf: 112 + access_drivers: ["polkit"] + key_file: "/etc/pki/libvirt/private/serverkey.pem" + cert_file: "/etc/pki/libvirt/servercert.pem" + ca_file: "/etc/pki/CA/cacert.pem" + #crl_file: "/etc/pki/CA/crl.pem" + tls_no_sanity_certificate: 0 + tls_no_verify_certificate: 0 + tls_allowed_dn_list: ["DN1", "DN2"] + tls_priority: "NORMAL" + sasl_allowed_username_list: ["joe@EXAMPLE.COM", "fred@EXAMPLE.COM"] + max_clients: 5000 + max_queued_clients: 1000 + max_anonymous_clients: 20 + min_workers: 5 + max_workers: 20 + prio_workers: 5 + max_client_requests: 5 + admin_min_workers: 1 + admin_max_workers: 5 + admin_max_clients: 5 + admin_max_queued_clients: 5 + admin_max_client_requests: 5 + log_level: 3 + log_filters: "1:qemu 1:libvirt 4:object 4:json 4:event 1:util" + log_outputs: "3:syslog:libvirtd" + audit_level: 2 + audit_logging: 1 + #host_uuid: "00000000-0000-0000-0000-000000000000" + host_uuid_source: "smbios" + keepalive_interval: 5 + keepalive_count: 5 + keepalive_required: 1 + admin_keepalive_required: 1 + admin_keepalive_interval: 5 + admin_keepalive_count: 5 + ovs_timeout: 5 diff --git a/salt/libvirt/etc/libvirtd.conf.jinja b/salt/libvirt/etc/libvirtd.conf.jinja new file mode 100644 index 000000000..12406e1d2 --- /dev/null +++ b/salt/libvirt/etc/libvirtd.conf.jinja @@ -0,0 +1,8 @@ +{# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one + or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at + https://securityonion.net/license; you may not use this file except in compliance with the + Elastic License 2.0. -#} + +{%- for k, v in LIBVIRTMERGED.config.items() %} +{{ k }} = {{ v | json }} +{%- endfor %} diff --git a/salt/libvirt/init.sls b/salt/libvirt/init.sls new file mode 100644 index 000000000..4b1fd6969 --- /dev/null +++ b/salt/libvirt/init.sls @@ -0,0 +1,80 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'libvirt/map.jinja' import LIBVIRTMERGED %} + +install_libvirt: + pkg.installed: + - name: libvirt + +libvirt_config: + file.managed: + - name: /etc/libvirt/libvirtd.conf + - source: salt://libvirt/etc/libvirtd.conf.jinja + - template: jinja + - defaults: + LIBVIRTMERGED: {{ LIBVIRTMERGED }} + +libvirt_service: + service.running: + - name: libvirtd + +libvirt_conf_dir: + file.directory: + - name: /opt/so/conf/libvirt + - user: 939 + - group: 939 + - makedirs: True + +libvirt_source-packages_dir: + file.directory: + - name: /opt/so/conf/libvirt/source-packages + +libvirt_python_wheel: + file.recurse: + - name: /opt/so/conf/libvirt/source-packages/libvirt-python + - source: salt://libvirt/source-packages/libvirt-python + - clean: True + +libvirt_python_module: + cmd.run: + - name: /opt/saltstack/salt/bin/python3.10 -m pip install --no-index --find-links=/opt/so/conf/libvirt/source-packages/libvirt-python libvirt-python + - onchanges: + - file: libvirt_python_wheel + +# places cacert, clientcert, clientkey, servercert and serverkey +# /etc/pki/CA/cacert.pem +# /etc/pki/libvirt/clientcert.pem and /etc/pki/libvirt/servercert.pem +# /etc/pki/libvirt/private/clientkey.pem and /etc/pki/libvirt/private/serverkey.pem +libvirt_keys: + virt.keys: + - name: libvirt_keys + +install_qemu: + pkg.installed: + - name: qemu-kvm + +install_libguestfs: + pkg.installed: + - name: libguestfs + +# required for the network states below +install_NetworkManager-updown: + pkg.installed: + - name: NetworkManager-initscripts-updown + +ens18: + network.managed: + - enabled: True + - type: eth + - bridge: virbr0 + +virbr0: + network.managed: + - enabled: True + - type: bridge + - proto: dhcp + - require: + - network: ens18 diff --git a/salt/libvirt/map.jinja b/salt/libvirt/map.jinja new file mode 100644 index 000000000..eebb50062 --- /dev/null +++ b/salt/libvirt/map.jinja @@ -0,0 +1,7 @@ +{# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one + or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at + https://securityonion.net/license; you may not use this file except in compliance with the + Elastic License 2.0. #} + +{% import_yaml 'libvirt/defaults.yaml' as LIBVIRTDEFAULTS %} +{% set LIBVIRTMERGED = salt['pillar.get']('libvirt', LIBVIRTDEFAULTS.libvirt, merge=True) %} diff --git a/salt/libvirt/source-packages/libvirt-python/libvirt_python-10.5.0-cp310-cp310-linux_x86_64.whl b/salt/libvirt/source-packages/libvirt-python/libvirt_python-10.5.0-cp310-cp310-linux_x86_64.whl new file mode 100644 index 0000000000000000000000000000000000000000..5687a286251694c55897d2ee093e07f873c79f45 GIT binary patch literal 504724 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⁢M>PQ9a*r!u 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

=;yRl?xghMpqn|U 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 z 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 BnaglM&+Fem|G$nFkig8Yz|OMJ>EuBK4DZo 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

=IzKgY6garUn`{<=f_c{ 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

==E8{Pqjs) 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 *XOOg2?!5D)LcAH?wR` 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 TTMP_5K)4E6V_aF!4&(s<(W-u< literal 0 HcmV?d00001 From 810be2c9d28766d068fc90e3b65fb943632abbcc Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Wed, 31 Jul 2024 15:19:22 -0400 Subject: [PATCH 002/315] virt start --- salt/hypervisor/defaults.sls | 61 ++++++++++++ salt/libvirt/configbad | 51 ---------- salt/libvirt/init.sls | 3 + salt/manager/tools/sbin/so-minion | 10 +- salt/reactor/createEmptyPillar.sls | 26 +++++ salt/reactor/deleteKey.sls | 11 +++ salt/reactor/setup.sls | 37 ++++++++ salt/reactor/virtReleaseHardware.sls | 67 +++++++++++++ salt/reactor/virtUpdate.sls | 95 +++++++++++++++++++ salt/salt/cloud/cloud.profiles.d/socloud.conf | 66 +++++++++++++ salt/salt/cloud/cloud.provides.d/libvirt.conf | 11 +++ salt/salt/master.sls | 14 +++ salt/setup/virt/searchnode.yaml | 18 ++++ salt/setup/virt/sensor.yaml | 19 ++++ salt/setup/virt/setHostname.sls | 61 ++++++++++++ salt/setup/virt/soinstall.map.jinja | 34 +++++++ 16 files changed, 532 insertions(+), 52 deletions(-) create mode 100644 salt/hypervisor/defaults.sls delete mode 100644 salt/libvirt/configbad create mode 100644 salt/reactor/createEmptyPillar.sls create mode 100644 salt/reactor/deleteKey.sls create mode 100644 salt/reactor/setup.sls create mode 100644 salt/reactor/virtReleaseHardware.sls create mode 100644 salt/reactor/virtUpdate.sls create mode 100644 salt/salt/cloud/cloud.profiles.d/socloud.conf create mode 100644 salt/salt/cloud/cloud.provides.d/libvirt.conf create mode 100644 salt/setup/virt/searchnode.yaml create mode 100644 salt/setup/virt/sensor.yaml create mode 100644 salt/setup/virt/setHostname.sls create mode 100644 salt/setup/virt/soinstall.map.jinja diff --git a/salt/hypervisor/defaults.sls b/salt/hypervisor/defaults.sls new file mode 100644 index 000000000..d1feb6d34 --- /dev/null +++ b/salt/hypervisor/defaults.sls @@ -0,0 +1,61 @@ +hypervisor: + model1: + hardware: + cpu: + total: 128 + free: 128 + memory: + total: 128 + free: 128 + disks: + free: + 3: pci_0000_c7_00_0 + 4: pci_0000_c8_00_0 + claimed: + 1: pci_0000_c5_00_0 + 2: pci_0000_c6_00_0 + copper: + free: + 1: pci_0000_c4_00_0 + 2: pci_0000_c4_00_1 + 3: pci_0000_c4_00_2 + 4: pci_0000_c4_00_3 + claimed: {} + sfp: + free: + 5: pci_0000_41_00_0 + 6: pci_0000_41_00_1 + claimed: {} + model2: + hardware: + cpu: + total: 128 + free: 128 + memory: + total: 512 + free: 512 + disks: + free: + 3: pci_0000_c8_00_0 + 4: pci_0000_c9_00_0 + 5: pci_0000_c10_00_0 + 6: pci_0000_c11_00_0 + claimed: + 1: pci_0000_c6_00_0 + 2: pci_0000_c7_00_0 + copper: + free: + 1: pci_0000_c4_00_0 + 2: pci_0000_c4_00_1 + 3: pci_0000_c4_00_2 + 4: pci_0000_c4_00_3 + 5: pci_0000_c5_00_0 + 6: pci_0000_c5_00_1 + 7: pci_0000_c5_00_2 + 8: pci_0000_c5_00_3 + claimed: {} + sfp: + free: + 9: pci_0000_41_00_0 + 10: pci_0000_41_00_1 + claimed: {} diff --git a/salt/libvirt/configbad b/salt/libvirt/configbad deleted file mode 100644 index 0cf5f9ef5..000000000 --- a/salt/libvirt/configbad +++ /dev/null @@ -1,51 +0,0 @@ -listen_tls = 0 -listen_tcp = 0 -tls_port = "16514" -tcp_port = "16509" -listen_addr = "0.0.0.0" -unix_sock_group = "root" -unix_sock_ro_perms = "0777" -unix_sock_rw_perms = "0770" -unix_sock_admin_perms = "0700" -unix_sock_dir = "/run/libvirt" -auth_unix_ro = "none" -auth_unix_rw = "none" -auth_tcp = "none" -auth_tls = "none" -tcp_min_ssf = 112 -access_drivers = ["nop"] -key_file = "/etc/pki/libvirt/private/serverkey.pem" -cert_file = "/etc/pki/libvirt/servercert.pem" -ca_file = "/etc/pki/CA/cacert.pem" -crl_file = "/etc/pki/CA/crl.pem" -tls_no_sanity_certificate = 0 -tls_no_verify_certificate = 0 -tls_allowed_dn_list = ["DN1", "DN2"] -tls_priority = "NORMAL" -sasl_allowed_username_list = ["joe@EXAMPLE.COM", "fred@EXAMPLE.COM"] -max_clients = 5000 -max_queued_clients = 1000 -max_anonymous_clients = 20 -min_workers = 5 -max_workers = 20 -prio_workers = 5 -max_client_requests = 5 -admin_min_workers = 1 -admin_max_workers = 5 -admin_max_clients = 5 -admin_max_queued_clients = 5 -admin_max_client_requests = 5 -log_level = 3 -log_filters = "1:qemu 1:libvirt 4:object 4:json 4:event 1:util" -log_outputs = "3:syslog:libvirtd" -audit_level = 2 -audit_logging = 1 -host_uuid = "00000000-0000-0000-0000-000000000000" -host_uuid_source = "smbios" -keepalive_interval = 5 -keepalive_count = 5 -keepalive_required = 1 -admin_keepalive_required = 1 -admin_keepalive_interval = 5 -admin_keepalive_count = 5 -ovs_timeout = 5 diff --git a/salt/libvirt/init.sls b/salt/libvirt/init.sls index 4b1fd6969..4e9d0a6af 100644 --- a/salt/libvirt/init.sls +++ b/salt/libvirt/init.sls @@ -78,3 +78,6 @@ virbr0: - proto: dhcp - require: - network: ens18 + +# virtlogd service may not restart following reboot without this +#semanage permissive -a virtlogd_t diff --git a/salt/manager/tools/sbin/so-minion b/salt/manager/tools/sbin/so-minion index 6f14104c3..e1cd48473 100755 --- a/salt/manager/tools/sbin/so-minion +++ b/salt/manager/tools/sbin/so-minion @@ -59,7 +59,11 @@ for i in "$@"; do -i=*|--ip=*) MAINIP="${i#*=}" shift - ;; + ;; + -c=*|--cpu=*) + CORECOUNT="${i#*=}" + shift + ;; -*|--*) echo "Unknown option $i" exit 1 @@ -637,6 +641,10 @@ case "$OPERATION" in updateMineAndApplyStates ;; + "addVirt") + setupMinionFiles + ;; + "delete") deleteMinionFiles deleteMinion diff --git a/salt/reactor/createEmptyPillar.sls b/salt/reactor/createEmptyPillar.sls new file mode 100644 index 000000000..95e41eef6 --- /dev/null +++ b/salt/reactor/createEmptyPillar.sls @@ -0,0 +1,26 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +#!py + +import logging +import salt.client +local = salt.client.LocalClient() +from subprocess import call +import yaml + +import os + +def run(): + #logging.error("createEmptyPillar reactor: data: %s" % data) + vm_name = data['kwargs']['name'] + logging.error("createEmptyPillar reactor: vm_name: %s" % vm_name) + pillar_root = '/opt/so/saltstack/local/pillar/minions/' + pillar_files = ['adv_' + vm_name + '.sls', vm_name + '.sls'] + for f in pillar_files: + if not os.path.exists(pillar_root + f): + os.mknod(pillar_root + f) + + return {} diff --git a/salt/reactor/deleteKey.sls b/salt/reactor/deleteKey.sls new file mode 100644 index 000000000..646e17948 --- /dev/null +++ b/salt/reactor/deleteKey.sls @@ -0,0 +1,11 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +remove_key: + wheel.key.delete: + - args: + - match: {{ data['name'] }} + +{% do salt.log.info('deleteKey reactor: deleted minion key: %s' % data['name']) %} diff --git a/salt/reactor/setup.sls b/salt/reactor/setup.sls new file mode 100644 index 000000000..b8c5ad16c --- /dev/null +++ b/salt/reactor/setup.sls @@ -0,0 +1,37 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +#!py + +import logging +import salt.client +local = salt.client.LocalClient() +from subprocess import call +import yaml + +def run(): + minionid = data['id'] + hv_name = 'jppvirt' + DATA = data['data'] + logging.error("setup reactor: %s " % DATA) + + vm_out_data = { + 'cpu': DATA['CPU'], + 'memory': DATA['MEMORY'], + 'disks': DATA['DISKS'], + 'copper': DATA['COPPER'], + 'sfp': DATA['SFP'] + } + + logging.error("setup reactor: vm_out_data: %s " % vm_out_data) + + with open("/opt/so/saltstack/local/pillar/hypervisor/" + hv_name + "/" + minionid + ".sls", 'w') as f: + yaml.dump(vm_out_data, f, default_flow_style=False) + + rc = call("NODETYPE=" + DATA['NODETYPE'] + " /usr/sbin/so-minion -o=addVirt -m=" + minionid + " -n=" + DATA['MNIC'] + " -i=" + DATA['MAINIP'] + " -a=" + DATA['INTERFACE'] + " -c=" + str(DATA['CORECOUNT']) + " -d='" + DATA['NODE_DESCRIPTION'] + "'", shell=True) + + logging.error('setup_reactor: rc: %s' % rc) + + return {} diff --git a/salt/reactor/virtReleaseHardware.sls b/salt/reactor/virtReleaseHardware.sls new file mode 100644 index 000000000..6211fc611 --- /dev/null +++ b/salt/reactor/virtReleaseHardware.sls @@ -0,0 +1,67 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +#!py + +import logging +import salt.client +local = salt.client.LocalClient() +from subprocess import call +import yaml + +import os + +def run(): + + def release_compute(hw_type): + compute = hv_data['hypervisor']['hardware'][hw_type] + compute.update({'free': compute.get('free') + vm_data.get(hw_type)}) + logging.error("virtReboot reactor: claiming %s compute: %s " % (hw_type,compute)) + + def release_pci(hw_type): + free_hw = hv_data['hypervisor']['hardware'][hw_type]['free'] + for hw in vm_data[hw_type]: + f_hw = {hw: hv_data['hypervisor']['hardware'][hw_type]['claimed'].pop(hw)} + free_hw.update(f_hw) + logging.error("virtReleaseHardware reactor: released %s: %s" % (hw_type, f_hw)) + + + + vm_name = data['name'] + hv_name = 'jppvirt' + + with open("/opt/so/saltstack/local/pillar/hypervisor/" + hv_name + "/" + vm_name + ".sls") as f: + try: + vm_data=yaml.safe_load(f) + logging.error("virtReleaseHardware reactor: vm_data %s " % vm_data) + #logging.error(yaml.safe_load(f)) + except yaml.YAMLError as exc: + logging.error(exc) + + with open("/opt/so/saltstack/local/pillar/hypervisor/" + hv_name + "/" + hv_name + ".sls") as f: + try: + hv_data=yaml.safe_load(f) + logging.error("virtReleaseHardware reactor: hv_data: %s " % hv_data) + #logging.error(yaml.safe_load(f)) + except yaml.YAMLError as exc: + logging.error(exc) + + for hw_type in ['disks', 'copper', 'sfp']: + release_pci(hw_type) + + for hw_type in ['cpu', 'memory']: + release_compute(hw_type) + + # update the free hardware for the hypervisor + with open("/opt/so/saltstack/local/pillar/hypervisor/" + hv_name + "/" + hv_name + ".sls", 'w') as f: + yaml.dump(hv_data, f, default_flow_style=False) + + # remove the old vm_data file since the vm has been purged + os.remove("/opt/so/saltstack/local/pillar/hypervisor/" + hv_name + "/" + vm_name + ".sls") + # remove minion pillar files + os.remove("/opt/so/saltstack/local/pillar/minions/adv_" + vm_name + ".sls") + os.remove("/opt/so/saltstack/local/pillar/minions/" + vm_name + ".sls") + + return {} diff --git a/salt/reactor/virtUpdate.sls b/salt/reactor/virtUpdate.sls new file mode 100644 index 000000000..e44bc8070 --- /dev/null +++ b/salt/reactor/virtUpdate.sls @@ -0,0 +1,95 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +#!py + +import logging +import salt.client +local = salt.client.LocalClient() +from subprocess import call +import yaml + + +def run(): + + def claim_compute(hw_type): + compute = hv_data['hypervisor']['hardware'][hw_type] + compute.update({'free': compute.get('free') - vm_data.get(hw_type)}) + logging.error("virtUpdate reactor: claiming %s compute: %s " % (hw_type,compute)) + + + def claim_pci(hw_type): + claimed_hw = hv_data['hypervisor']['hardware'][hw_type]['claimed'] + # if a list of devices was defined + if type(vm_data[hw_type]) == list: + for hw in vm_data[hw_type]: + c_hw = {hw: hv_data['hypervisor']['hardware'][hw_type]['free'].pop(hw)} + claimed_hw.update(c_hw) + host_devices.append(c_hw[hw]) + #hv_data['hypervisor']['hardware'][hw_type].update({'claimed': claimed_hw}) + # if a number of devices was defined + else: + n = vm_data[hw_type] + vm_data[hw_type] = [] + # grab the first number of devices as defined for the node type + claiming_hw = list(hv_data['hypervisor']['hardware'][hw_type]['free'].items())[:n] + logging.error("virtUpdate reactor: claiming %s hardware: %s " % (hw_type,claiming_hw)) + # claiming_hw is a list of tuples containing (numerical_id, pci_id) + # claiming_hw example: [(1, 'pci_0000_c4_00_0'), (2, 'pci_0000_c4_00_1')] + for hw in claiming_hw: + c_hw = {hw[0]: hv_data['hypervisor']['hardware'][hw_type]['free'].pop(hw[0])} + claimed_hw.update(c_hw) + vm_data[hw_type].append(hw[0]) + host_devices.append(hw[1]) + logging.error("virtUpdate reactor: claimed_hw: %s " % claimed_hw) + + vm_name = data['name'] + hv_name = 'jppvirt' + host_devices = [] + + with open("/opt/so/saltstack/local/pillar/hypervisor/" + hv_name + "/" + vm_name + ".sls") as f: + try: + vm_data=yaml.safe_load(f) + logging.error("virtUpdate reactor: vm_data %s " % vm_data) + #logging.error(yaml.safe_load(f)) + except yaml.YAMLError as exc: + logging.error(exc) + + with open("/opt/so/saltstack/local/pillar/hypervisor/" + hv_name + "/" + hv_name + ".sls") as f: + try: + hv_data=yaml.safe_load(f) + logging.error("virtUpdate reactor: hv_data: %s " % hv_data) + #logging.error(yaml.safe_load(f)) + except yaml.YAMLError as exc: + logging.error(exc) + + local.cmd('jppvirt', 'virt.stop', ['name=' + vm_name]) + + for hw_type in ['disks', 'copper', 'sfp']: + claim_pci(hw_type) + + for hw_type in ['cpu', 'memory']: + claim_compute(hw_type) + + logging.error("virtUpdate reactor: host_devices: %s " % host_devices) + + # update the claimed hardware for the hypervisor + with open("/opt/so/saltstack/local/pillar/hypervisor/" + hv_name + "/" + hv_name + ".sls", 'w') as f: + yaml.dump(hv_data, f, default_flow_style=False) + + # since the original hw request provided was a count of hw instead of specific pci ids + # we need to update the vm_data file with the assigned pci ids that were claimed + # update the vm_data file with the hardware it claimed + logging.error("virtUpdate reactor: new vm_data: %s " % vm_data) + with open("/opt/so/saltstack/local/pillar/hypervisor/" + hv_name + "/" + vm_name + ".sls", 'w') as f: + yaml.dump(vm_data, f, default_flow_style=False) + + mem = vm_data['memory'] * 1024 + r = local.cmd('jppvirt', 'virt.update', ['name=' + vm_name, 'mem=' + str(mem), 'cpu=' + str(vm_data['cpu']), 'host_devices=' + str(host_devices)]) + logging.error("virtUpdate reactor: virt.update: %s" % r) + + local.cmd('jppvirt', 'virt.start', ['name=' + vm_name]) + + return {} diff --git a/salt/salt/cloud/cloud.profiles.d/socloud.conf b/salt/salt/cloud/cloud.profiles.d/socloud.conf new file mode 100644 index 000000000..c410fd7c3 --- /dev/null +++ b/salt/salt/cloud/cloud.profiles.d/socloud.conf @@ -0,0 +1,66 @@ +searchnode: + provider: local-kvm + base_domain: jppol9vm + ip_source: qemu-agent + ssh_username: jpatterson + private_key: /home/jpatterson/.ssh/id_rsa + sudo: True + # /tmp is mounted noexec.. do workaround + deploy_command: sh /tmp/.saltcloud-*/deploy.sh + script_args: -F -x python3 stable 3006.1 + # grains to add to the minion + #grains: + # clones-are-awesome: true + # override minion settings + minion: + master: jppvirt + master_port: 4506 + startup_states: sls + sls_list: + - setHostname + +sensor: + provider: local-kvm + base_domain: jppol9vm + ip_source: qemu-agent + ssh_username: jpatterson + private_key: /home/jpatterson/.ssh/id_rsa + sudo: True + #preflight_cmds: + # - echo "do something" + # - hostname + # /tmp is mounted noexec.. do workaround + deploy_command: sh /tmp/.saltcloud-*/deploy.sh + script_args: -F -x python3 stable 3006.1 + # the destination directory will be created if it doesn't exist + #file_map: + # /srv/salt/filemap.txt: /remote/path/to/use/custom/filemap.txt + #inline_script: + # - echo "SLEEPING" + # - hostname + # grains to add to the minion + #grains: + # clones-are-awesome: true + # override minion settings + minion: + master: jppvirt + master_port: 4506 + startup_states: sls + sls_list: + - setHostname + +core: + provider: local-kvm + base_domain: jppol9vm + ip_source: qemu-agent + ssh_username: jpatterson + private_key: /home/jpatterson/.ssh/id_rsa + sudo: True + deploy_command: sh /tmp/.saltcloud-*/deploy.sh + script_args: -F -x python3 stable 3006.1 + minion: + master: jppvirt + master_port: 4506 + startup_states: sls + sls_list: + - setHostname diff --git a/salt/salt/cloud/cloud.provides.d/libvirt.conf b/salt/salt/cloud/cloud.provides.d/libvirt.conf new file mode 100644 index 000000000..8c57cc1e5 --- /dev/null +++ b/salt/salt/cloud/cloud.provides.d/libvirt.conf @@ -0,0 +1,11 @@ +# Set up a provider with qemu+ssh protocol +#kvm-via-ssh: +# driver: libvirt +# url: qemu+ssh://jpatterson@jppvirt/system?socket=/var/run/libvirt/libvirt-sock + +# Or connect to a local libvirt instance +local-kvm: + driver: libvirt + url: qemu:///system + # work around flag for XML validation errors while cloning + validate_xml: no diff --git a/salt/salt/master.sls b/salt/salt/master.sls index 6e320e4a6..84e18b8fc 100644 --- a/salt/salt/master.sls +++ b/salt/salt/master.sls @@ -47,6 +47,20 @@ salt_master_service: - file: engines_config - order: last +# we need to managed adding the following to salt-master config if there are hypervisors +#reactor: + #- salt/cloud/*/creating': + #- salt/cloud/*/requesting +# - 'salt/cloud/*/deploying': +# - /srv/salt/reactor/createEmptyPillar.sls +# - 'setup/so-minion': +# - /srv/salt/reactor/setup.sls +# - 'salt/cloud/*/created': +# - /srv/salt/reactor/virtUpdate.sls +# - 'salt/cloud/*/destroyed': +# - /srv/salt/reactor/virtReleaseHardware.sls +# - /srv/salt/reactor/deleteKey.sls + {% else %} {{sls}}_state_not_allowed: diff --git a/salt/setup/virt/searchnode.yaml b/salt/setup/virt/searchnode.yaml new file mode 100644 index 000000000..f48502b94 --- /dev/null +++ b/salt/setup/virt/searchnode.yaml @@ -0,0 +1,18 @@ +MAINIP: +MNIC: eth0 +NODE_DESCRIPTION: 'virt search' +ES_HEAP_SIZE: +PATCHSCHEDULENAME: +INTERFACE: bond0 +NODETYPE: SEARCHNODE +CORECOUNT: 16 +LSHOSTNAME: +LSHEAP: +CPUCORES: 16 +IDH_MGTRESTRICT: +IDH_SERVICES: +CPU: 16 +MEMORY: 32 +DISKS: 1 +COPPER: 0 +SFP: 0 diff --git a/salt/setup/virt/sensor.yaml b/salt/setup/virt/sensor.yaml new file mode 100644 index 000000000..e4946bc1e --- /dev/null +++ b/salt/setup/virt/sensor.yaml @@ -0,0 +1,19 @@ +MAINIP: +MNIC: eth0 +NODE_DESCRIPTION: 'virt sensor' +ES_HEAP_SIZE: +PATCHSCHEDULENAME: +INTERFACE: bond0 +NODETYPE: SENSOR +CORECOUNT: 4 +LSHOSTNAME: +LSHEAP: +CPUCORES: 4 +IDH_MGTRESTRICT: +IDH_SERVICES: +CPU: 16 +MEMORY: 16 +DISKS: 1 +COPPER: + - 1 +SFP: 2 diff --git a/salt/setup/virt/setHostname.sls b/salt/setup/virt/setHostname.sls new file mode 100644 index 000000000..e77ebd5a7 --- /dev/null +++ b/salt/setup/virt/setHostname.sls @@ -0,0 +1,61 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'soinstall.map.jinja' import DATA %} + +setHostname_{{grains.id.split("_") | first}}: + network.system: + - name: {{grains.id.split("_") | first}} + - enabled: True + - hostname: {{grains.id.split("_") | first}} + - apply_hostname: True + +create_pillar: + event.send: + - name: setup/so-minion + - data: + MAINIP: {{ DATA.MAINIP }} + MNIC: {{ DATA.MNIC }} + NODE_DESCRIPTION: '{{ DATA.NODE_DESCRIPTION }}' + ES_HEAP_SIZE: {{ DATA.ES_HEAP_SIZE }} + PATCHSCHEDULENAME: {{ DATA.PATCHSCHEDULENAME }} + INTERFACE: {{ DATA.INTERFACE }} + NODETYPE: {{ DATA.NODETYPE }} + CORECOUNT: {{ DATA.CORECOUNT }} + LSHOSTNAME: {{ DATA.LSHOSTNAME }} + LSHEAP: {{ DATA.LSHEAP }} + CPUCORES: {{ DATA.CPUCORES }} + IDH_MGTRESTRICT: {{ DATA.IDH_MGTRESTRICT }} + IDH_SERVICES: {{ DATA.IDH_SERVICES }} + CPU: {{ DATA.CPU }} + MEMORY: {{ DATA.MEMORY }} + DISKS: {{ DATA.DISKS }} + COPPER: {{ DATA.COPPER }} + SFP: {{ DATA.SFP }} + + +# set event for firewall rules - so-firewall-minion + +clean_sls_list: + file.line: + - name: /etc/salt/minion + - match: 'sls_list:' + - mode: delete + +clean_setHostname: + file.line: + - name: /etc/salt/minion + - match: '- setHostname' + - mode: delete + - onchanges: + - file: clean_sls_list + +set_highstate: + file.replace: + - name: /etc/salt/minion + - pattern: 'startup_states: sls' + - repl: 'startup_states: highstate' + - onchanges: + - file: clean_setHostname diff --git a/salt/setup/virt/soinstall.map.jinja b/salt/setup/virt/soinstall.map.jinja new file mode 100644 index 000000000..1c82fe3dd --- /dev/null +++ b/salt/setup/virt/soinstall.map.jinja @@ -0,0 +1,34 @@ +{# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one + or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at + https://securityonion.net/license; you may not use this file except in compliance with the + Elastic License 2.0. #} + +{% set nodetype = grains.id.split("_") | last %} +{% import_yaml nodetype ~ '.yaml' as DATA %} +{% set total_mem = grains.mem_total %} + +{% do DATA.update({'MAINIP': grains.ip_interfaces.get(DATA.MNIC)[0]}) %} +{% do DATA.update({'CORECOUNT': grains.num_cpus}) %} +{% do DATA.update({'CPUCORES': grains.num_cpus}) %} + + +{% if nodetype = "searchnode" %} + +{% do DATA.update({'LSHOSTNAME': grains.host}) %} + +{# this replicates the function es_heapsize in so-functions #} +{% if total_mem < 8000 %} +{% set ES_HEAP_SIZE = "600m" %} +{% elif total_mem >= 100000 %} +{% set ES_HEAP_SIZE = "25000m" %} +{% else %} +{% set ES_HEAP_SIZE = total_mem / 3 %} +{% if ES_HEAP_SIZE > 25000 %} +{% set ES_HEAP_SIZE = "25000m" %} +{% else %} +{% set ES_HEAP_SIZE = ES_HEAP_SIZE ~ "m" %} +{% endif %} +{% endif %} +{% do DATA.update({'ES_HEAP_SIZE': ES_HEAP_SIZE}) %} + +{% endif %} From 52e52f35f79aab950617ee846221e5ebfbb8ecdb Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Wed, 31 Jul 2024 15:49:32 -0400 Subject: [PATCH 003/315] hyper setup init --- salt/firewall/defaults.yaml | 13 +++++++++++++ salt/manager/tools/sbin/so-firewall-minion | 3 +++ setup/so-setup | 10 ++++++++++ setup/so-whiptail | 3 +++ 4 files changed, 29 insertions(+) diff --git a/salt/firewall/defaults.yaml b/salt/firewall/defaults.yaml index fc5368e12..c9b864a18 100644 --- a/salt/firewall/defaults.yaml +++ b/salt/firewall/defaults.yaml @@ -12,6 +12,7 @@ firewall: eval: [] fleet: [] heavynode: [] + hypervisor: [] idh: [] import: [] localhost: @@ -471,6 +472,15 @@ firewall: - elastic_agent_control - elastic_agent_data - elastic_agent_update + hypervisor: + portgroups: + - yum + - docker_registry + - influxdb + - elastic_agent_control + - elastic_agent_data + - elastic_agent_update + - sensoroni customhostgroup0: portgroups: [] customhostgroup1: @@ -523,6 +533,9 @@ firewall: desktop: portgroups: - salt_manager + hypervisor: + portgroups: + - salt_manager self: portgroups: - syslog diff --git a/salt/manager/tools/sbin/so-firewall-minion b/salt/manager/tools/sbin/so-firewall-minion index 66a0afcea..4b0fb766e 100755 --- a/salt/manager/tools/sbin/so-firewall-minion +++ b/salt/manager/tools/sbin/so-firewall-minion @@ -82,4 +82,7 @@ fi 'DESKTOP') so-firewall includehost desktop "$IP" --apply ;; + 'HYPERVISOR') + so-firewall includehost hypervisor "$IP" --apply + ;; esac diff --git a/setup/so-setup b/setup/so-setup index bd8a8c6ba..005bf903d 100755 --- a/setup/so-setup +++ b/setup/so-setup @@ -624,6 +624,16 @@ if ! [[ -f $install_opt_file ]]; then set_minion_info whiptail_end_settings + elif [[ $is_hypervisor ]]; then + info "Setting up as node type hypervisor" + check_requirements + networking_needful + collect_mngr_hostname + add_mngr_ip_to_hosts + check_manager_connection + set_minion_info + whiptail_end_settings + fi if [[ $waitforstate ]]; then diff --git a/setup/so-whiptail b/setup/so-whiptail index d950f2921..b25682acd 100755 --- a/setup/so-whiptail +++ b/setup/so-whiptail @@ -681,6 +681,7 @@ whiptail_install_type_dist_existing() { "HEAVYNODE" "Sensor + Search Node " \ "IDH" "Intrusion Detection Honeypot Node " \ "RECEIVER" "Receiver Node " \ + "HYPERVISOR" "Hypervisor Node " \ 3>&1 1>&2 2>&3 # "HOTNODE" "Add Hot Node (Uses Elastic Clustering)" \ # TODO # "WARMNODE" "Add Warm Node to existing Hot or Search node" \ # TODO @@ -713,6 +714,8 @@ whiptail_install_type_dist_existing() { is_receiver=true elif [ "$install_type" = 'DESKTOP' ]; then is_desktop=true + elif [ "$install_type" = 'HYPERVISOR' ]; then + is_hypervisor=true fi local exitstatus=$? From 5a24a7775e7c2b63851bf0a82e3930ffb57f16bf Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Wed, 31 Jul 2024 15:57:43 -0400 Subject: [PATCH 004/315] salt 3006.1 - avoid some cloud/virt bug in later version --- salt/salt/master.defaults.yaml | 2 +- salt/salt/minion.defaults.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/salt/salt/master.defaults.yaml b/salt/salt/master.defaults.yaml index 19677f70b..fc7a6ae16 100644 --- a/salt/salt/master.defaults.yaml +++ b/salt/salt/master.defaults.yaml @@ -1,4 +1,4 @@ # version cannot be used elsewhere in this pillar as soup is grepping for it to determine if Salt needs to be patched salt: master: - version: 3006.6 + version: 3006.1 diff --git a/salt/salt/minion.defaults.yaml b/salt/salt/minion.defaults.yaml index 2e4ebc93e..0aa315264 100644 --- a/salt/salt/minion.defaults.yaml +++ b/salt/salt/minion.defaults.yaml @@ -1,6 +1,6 @@ # version cannot be used elsewhere in this pillar as soup is grepping for it to determine if Salt needs to be patched salt: minion: - version: 3006.6 + version: 3006.1 check_threshold: 3600 # in seconds, threshold used for so-salt-minion-check. any value less than 600 seconds may cause a lot of salt-minion restarts since the job to touch the file occurs every 5-8 minutes by default service_start_delay: 30 # in seconds. From fcf859ffedde3ed209bc7ab6e8b332538620c8e1 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Mon, 5 Aug 2024 14:53:11 -0400 Subject: [PATCH 005/315] start adding bridge for hyper --- setup/so-functions | 23 +++++++++++++++++++++++ setup/so-setup | 1 + 2 files changed, 24 insertions(+) diff --git a/setup/so-functions b/setup/so-functions index 870aa77d2..7b3e7e507 100755 --- a/setup/so-functions +++ b/setup/so-functions @@ -740,6 +740,29 @@ configure_network_sensor() { return $err } +configure_hyper_bridge() { + info "Setting up hypervisor bridge" + info "Checking $MNIC is using static or DHCP" + sod=$(nmcli -f ipv4.method con show $MNIC) + + # Create the bond interface only if it doesn't already exist + nmcli -f name,uuid -p con | grep -q br0 + local found_int=$? + + if [[ $found_int != 0 ]]; then + nmcli con add ifname br0 type bridge con-name br0 >> "$setup_log" 2>&1 + fi + + # as mgmt interface as slave + nmcli con add type bridge-slave ifname "$MNIC" master br0 + + local err=0 + nmcli con down "$MNIC" + nmcli con up br0 + + return $err +} + copy_salt_master_config() { title "Copy the Salt master config template to the proper directory" diff --git a/setup/so-setup b/setup/so-setup index 005bf903d..5ae0a5218 100755 --- a/setup/so-setup +++ b/setup/so-setup @@ -628,6 +628,7 @@ if ! [[ -f $install_opt_file ]]; then info "Setting up as node type hypervisor" check_requirements networking_needful + configure_hyper_bridge collect_mngr_hostname add_mngr_ip_to_hosts check_manager_connection From a6f1a0245aa0f3b7441b81a3f4aadeece805403c Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Tue, 6 Aug 2024 12:33:09 -0400 Subject: [PATCH 006/315] configure bridge during setup --- setup/so-functions | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/setup/so-functions b/setup/so-functions index 7b3e7e507..1931180ef 100755 --- a/setup/so-functions +++ b/setup/so-functions @@ -742,25 +742,41 @@ configure_network_sensor() { configure_hyper_bridge() { info "Setting up hypervisor bridge" - info "Checking $MNIC is using static or DHCP" - sod=$(nmcli -f ipv4.method con show $MNIC) - + info "Checking $MNIC ipv4.method is auto or manual" + ipmethod=$(nmcli -f ipv4.method con show "$MNIC" | cut -d ':' -f 2 | xargs) + info "ipv4.method found $ipmethod" # Create the bond interface only if it doesn't already exist nmcli -f name,uuid -p con | grep -q br0 local found_int=$? if [[ $found_int != 0 ]]; then + info "Creating bridge br0" nmcli con add ifname br0 type bridge con-name br0 >> "$setup_log" 2>&1 fi - # as mgmt interface as slave - nmcli con add type bridge-slave ifname "$MNIC" master br0 + # add mgmt interface as slave + logCmd "nmcli con add type bridge-slave ifname $MNIC master br0" - local err=0 - nmcli con down "$MNIC" - nmcli con up br0 + # if static ip was set transfer settings to the bridge + if [[ "$ipmethod" == "manual" ]]; then + local addresses=$(nmcli -f ipv4.addresses con show "$MNIC" | cut -d ':' -f 2 | xargs) + local gateway=$(nmcli -f ipv4.gateway con show "$MNIC" | cut -d ':' -f 2 | xargs) + local dns=$(nmcli -f ipv4.dns con show "$MNIC" | cut -d ':' -f 2 | xargs) + local dnssearch=$(nmcli -f ipv4.dns-search con show "$MNIC" | cut -d ':' -f 2 | xargs) + # will need to check for proxy + #local proxy= - return $err + logCmd "nmcli con mod br0 ipv4.addresses $addresses" + logCmd "nmcli con mod br0 ipv4.gateway $gateway" + logCmd "nmcli con mod br0 ipv4.dns $dns" + logCmd "nmcli con mod br0 ipv4.dns-search $dns-search" + logCmd "nmcli con mod br0 ipv4.method manual" + logCmd "nmcli con up br0" + # we cant bring down MNIC here since it would disrupt ssh sessions. we will need to bring it down at the end of the first highstate + # network comms will take place on MNIC until it is brought down and switches to br0 + fi + + return } copy_salt_master_config() { From 9d2c5d54b0c450a4de59e539e551689de518881b Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Wed, 7 Aug 2024 10:43:53 -0400 Subject: [PATCH 007/315] hype changes --- pillar/top.sls | 4 ++ salt/allowed_states.map.jinja | 8 +++ salt/firewall/defaults.yaml | 61 ++++++++++++++++++ salt/hypervisor/init.sls | 0 salt/libvirt/init.sls | 53 +++++++-------- ...python-10.5.0-cp310-cp310-linux_x86_64.whl | Bin 504724 -> 0 bytes ...python-10.6.0-cp310-cp310-linux_x86_64.whl | Bin 0 -> 504725 bytes salt/manager/tools/sbin/so-minion | 4 ++ salt/telegraf/defaults.yaml | 4 ++ salt/top.sls | 10 +++ salt/vars/hypervisor.map.jinja | 1 + setup/so-functions | 6 +- 12 files changed, 117 insertions(+), 34 deletions(-) create mode 100644 salt/hypervisor/init.sls delete mode 100644 salt/libvirt/source-packages/libvirt-python/libvirt_python-10.5.0-cp310-cp310-linux_x86_64.whl create mode 100644 salt/libvirt/source-packages/libvirt-python/libvirt_python-10.6.0-cp310-cp310-linux_x86_64.whl create mode 100644 salt/vars/hypervisor.map.jinja diff --git a/pillar/top.sls b/pillar/top.sls index 76d1a14e1..1a0d5f8c6 100644 --- a/pillar/top.sls +++ b/pillar/top.sls @@ -307,6 +307,10 @@ base: - minions.{{ grains.id }} - minions.adv_{{ grains.id }} + '*_hypervisor': + - minions.{{ grains.id }} + - minions.adv_{{ grains.id }} + '*_desktop': - minions.{{ grains.id }} - minions.adv_{{ grains.id }} diff --git a/salt/allowed_states.map.jinja b/salt/allowed_states.map.jinja index 37795e9d7..1cdf6145e 100644 --- a/salt/allowed_states.map.jinja +++ b/salt/allowed_states.map.jinja @@ -199,6 +199,14 @@ 'kafka', 'stig' ], + 'so-hypervisor': [ + 'ssl', + 'telegraf', + 'firewall', + 'schedule', + 'docker_clean', + 'stig' + ], 'so-desktop': [ 'ssl', 'docker_clean', diff --git a/salt/firewall/defaults.yaml b/salt/firewall/defaults.yaml index c9b864a18..944c37992 100644 --- a/salt/firewall/defaults.yaml +++ b/salt/firewall/defaults.yaml @@ -1452,3 +1452,64 @@ firewall: portgroups: [] customhostgroup9: portgroups: [] + hypervisor: + chain: + DOCKER-USER: + hostgroups: + customhostgroup0: + portgroups: [] + customhostgroup1: + portgroups: [] + customhostgroup2: + portgroups: [] + customhostgroup3: + portgroups: [] + customhostgroup4: + portgroups: [] + customhostgroup5: + portgroups: [] + customhostgroup6: + portgroups: [] + customhostgroup7: + portgroups: [] + customhostgroup8: + portgroups: [] + customhostgroup9: + portgroups: [] + INPUT: + hostgroups: + anywhere: + portgroups: + - ssh + dockernet: + portgroups: + - all + localhost: + portgroups: + - all + manager: + portgroups: [] + managersearch: + portgroups: [] + standalone: + portgroups: [] + customhostgroup0: + portgroups: [] + customhostgroup1: + portgroups: [] + customhostgroup2: + portgroups: [] + customhostgroup3: + portgroups: [] + customhostgroup4: + portgroups: [] + customhostgroup5: + portgroups: [] + customhostgroup6: + portgroups: [] + customhostgroup7: + portgroups: [] + customhostgroup8: + portgroups: [] + customhostgroup9: + portgroups: [] diff --git a/salt/hypervisor/init.sls b/salt/hypervisor/init.sls new file mode 100644 index 000000000..e69de29bb diff --git a/salt/libvirt/init.sls b/salt/libvirt/init.sls index 4e9d0a6af..1e4e3dde0 100644 --- a/salt/libvirt/init.sls +++ b/salt/libvirt/init.sls @@ -9,18 +9,6 @@ install_libvirt: pkg.installed: - name: libvirt -libvirt_config: - file.managed: - - name: /etc/libvirt/libvirtd.conf - - source: salt://libvirt/etc/libvirtd.conf.jinja - - template: jinja - - defaults: - LIBVIRTMERGED: {{ LIBVIRTMERGED }} - -libvirt_service: - service.running: - - name: libvirtd - libvirt_conf_dir: file.directory: - name: /opt/so/conf/libvirt @@ -28,6 +16,28 @@ libvirt_conf_dir: - group: 939 - makedirs: True +libvirt_config: + file.managed: + - name: /opt/so/conf/libvirt/libvirtd.conf + - source: salt://libvirt/etc/libvirtd.conf.jinja + - template: jinja + - defaults: + LIBVIRTMERGED: {{ LIBVIRTMERGED }} + +# since the libvirtd service looks for the config at /etc/libvirt/libvirtd.conf, and we dont want to manage the service looking in a new location, create this symlink to the managed config +config_symlink: + file.symlink: + - name: /etc/libvirt/libvirtd.conf + - target: /opt/so/conf/libvirt/libvirtd.conf + - force: True + +libvirt_service: + service.running: + - name: libvirtd + - enable: True + - watch: + - file: libvirt_config + libvirt_source-packages_dir: file.directory: - name: /opt/so/conf/libvirt/source-packages @@ -60,24 +70,9 @@ install_libguestfs: pkg.installed: - name: libguestfs -# required for the network states below -install_NetworkManager-updown: +install-guestfs-tools: pkg.installed: - - name: NetworkManager-initscripts-updown - -ens18: - network.managed: - - enabled: True - - type: eth - - bridge: virbr0 - -virbr0: - network.managed: - - enabled: True - - type: bridge - - proto: dhcp - - require: - - network: ens18 + - name: guestfs-tools # virtlogd service may not restart following reboot without this #semanage permissive -a virtlogd_t diff --git a/salt/libvirt/source-packages/libvirt-python/libvirt_python-10.5.0-cp310-cp310-linux_x86_64.whl b/salt/libvirt/source-packages/libvirt-python/libvirt_python-10.5.0-cp310-cp310-linux_x86_64.whl deleted file mode 100644 index 5687a286251694c55897d2ee093e07f873c79f45..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 504724 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⁢M>PQ9a*r!u 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

=;yRl?xghMpqn|U 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 z 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 BnaglM&+Fem|G$nFkig8Yz|OMJ>EuBK4DZo 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

=IzKgY6garUn`{<=f_c{ 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

==E8{Pqjs) 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 *XOOg2?!5D)LcAH?wR` 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 TTMP_5K)4E6V_aF!4&(s<(W-u< diff --git a/salt/libvirt/source-packages/libvirt-python/libvirt_python-10.6.0-cp310-cp310-linux_x86_64.whl b/salt/libvirt/source-packages/libvirt-python/libvirt_python-10.6.0-cp310-cp310-linux_x86_64.whl new file mode 100644 index 0000000000000000000000000000000000000000..1ab49e39501051478aaa5f08b3a6644de1ada247 GIT binary patch literal 504725 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⁢M>PQ9a*r!u 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�i^_s2JzdPl)r)pqk{N!hdnuO}$Qm44RJFNWA*z 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

-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

hc&NM<)K6J2L<5hQ$}YaU2O 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 ~ZpS;(?1QFU^Nh)4%T_#a>6n0;?F*Aa{&-Uz;! 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 SVqo9_!d1X3 Date: Wed, 7 Aug 2024 13:13:43 -0400 Subject: [PATCH 008/315] use salt3006.1 due to issue with virt state/module - salt issues 65694 --- salt/salt/master.defaults.yaml | 2 +- salt/salt/minion.defaults.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/salt/salt/master.defaults.yaml b/salt/salt/master.defaults.yaml index e133dbd0b..fc7a6ae16 100644 --- a/salt/salt/master.defaults.yaml +++ b/salt/salt/master.defaults.yaml @@ -1,4 +1,4 @@ # version cannot be used elsewhere in this pillar as soup is grepping for it to determine if Salt needs to be patched salt: master: - version: 3006.9 + version: 3006.1 diff --git a/salt/salt/minion.defaults.yaml b/salt/salt/minion.defaults.yaml index be405b9e8..0aa315264 100644 --- a/salt/salt/minion.defaults.yaml +++ b/salt/salt/minion.defaults.yaml @@ -1,6 +1,6 @@ # version cannot be used elsewhere in this pillar as soup is grepping for it to determine if Salt needs to be patched salt: minion: - version: 3006.9 + version: 3006.1 check_threshold: 3600 # in seconds, threshold used for so-salt-minion-check. any value less than 600 seconds may cause a lot of salt-minion restarts since the job to touch the file occurs every 5-8 minutes by default service_start_delay: 30 # in seconds. From d29b0660f0bab91bf28a163ab1ed5c85432512c1 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Wed, 7 Aug 2024 14:47:01 -0400 Subject: [PATCH 009/315] add docker module for salt 3006.1 --- .../docker/certifi-2022.12.7-py3-none-any.whl | 2469 +++++++++++++++++ .../docker/chardet-4.0.0-py2.py3-none-any.whl | 2469 +++++++++++++++++ ...linux_2_17_x86_64.manylinux2014_x86_64.whl | 2469 +++++++++++++++++ .../docker/docker-5.0.2-py2.py3-none-any.whl | 1817 ++++++++++++ .../docker/idna-2.10-py2.py3-none-any.whl | 2469 +++++++++++++++++ .../requests-2.25.1-py2.py3-none-any.whl | 1817 ++++++++++++ .../urllib3-1.26.15-py2.py3-none-any.whl | 1817 ++++++++++++ .../websocket_client-1.5.1-py3-none-any.whl | 1817 ++++++++++++ 8 files changed, 17144 insertions(+) create mode 100644 salt/salt/module_packages/docker/certifi-2022.12.7-py3-none-any.whl create mode 100644 salt/salt/module_packages/docker/chardet-4.0.0-py2.py3-none-any.whl create mode 100644 salt/salt/module_packages/docker/charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl create mode 100644 salt/salt/module_packages/docker/docker-5.0.2-py2.py3-none-any.whl create mode 100644 salt/salt/module_packages/docker/idna-2.10-py2.py3-none-any.whl create mode 100644 salt/salt/module_packages/docker/requests-2.25.1-py2.py3-none-any.whl create mode 100644 salt/salt/module_packages/docker/urllib3-1.26.15-py2.py3-none-any.whl create mode 100644 salt/salt/module_packages/docker/websocket_client-1.5.1-py3-none-any.whl diff --git a/salt/salt/module_packages/docker/certifi-2022.12.7-py3-none-any.whl b/salt/salt/module_packages/docker/certifi-2022.12.7-py3-none-any.whl new file mode 100644 index 000000000..7f561460a --- /dev/null +++ b/salt/salt/module_packages/docker/certifi-2022.12.7-py3-none-any.whl @@ -0,0 +1,2469 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + securityonion/setup/files/salt_module_deps/docker/certifi-2022.12.7-py3-none-any.whl at 2.4/main · Security-Onion-Solutions/securityonion · GitHub + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + diff --git a/salt/salt/module_packages/docker/chardet-4.0.0-py2.py3-none-any.whl b/salt/salt/module_packages/docker/chardet-4.0.0-py2.py3-none-any.whl new file mode 100644 index 000000000..3b4094eb5 --- /dev/null +++ b/salt/salt/module_packages/docker/chardet-4.0.0-py2.py3-none-any.whl @@ -0,0 +1,2469 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + securityonion/setup/files/salt_module_deps/docker/chardet-4.0.0-py2.py3-none-any.whl at 2.4/main · Security-Onion-Solutions/securityonion · GitHub + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ Skip to content + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+ + + + + +
+ + + + + + + + + +
+
+
+ + + + + + + + + + + + +
+ +
+ +
+ +
+ + + + / + + securityonion + + + Public +
+ + +
+ +
+ + +
+
+ +
+
+ + + + +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + +

Latest commit

 

History

History
175 KB

chardet-4.0.0-py2.py3-none-any.whl

File metadata and controls

175 KB
+
+ + + + +
+ +
+ +
+
+ +
+ +
+

Footer

+ + + + +
+
+ + + + + © 2024 GitHub, Inc. + +
+ + +
+
+ + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + diff --git a/salt/salt/module_packages/docker/charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl b/salt/salt/module_packages/docker/charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl new file mode 100644 index 000000000..87df81cbc --- /dev/null +++ b/salt/salt/module_packages/docker/charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl @@ -0,0 +1,2469 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + securityonion/setup/files/salt_module_deps/docker/charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl at 2.4/main · Security-Onion-Solutions/securityonion · GitHub + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ Skip to content + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+ + + + + +
+ + + + + + + + + +
+
+
+ + + + + + + + + + + + +
+ +
+ +
+ +
+ + + + / + + securityonion + + + Public +
+ + +
+ +
+ + +
+
+ +
+
+ + + + +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + +

Latest commit

 

History

History
195 KB

charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

File metadata and controls

195 KB
+
+ + + + +
+ +
+ +
+
+ +
+ +
+

Footer

+ + + + +
+
+ + + + + © 2024 GitHub, Inc. + +
+ + +
+
+ + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + diff --git a/salt/salt/module_packages/docker/docker-5.0.2-py2.py3-none-any.whl b/salt/salt/module_packages/docker/docker-5.0.2-py2.py3-none-any.whl new file mode 100644 index 000000000..1b63ebdeb --- /dev/null +++ b/salt/salt/module_packages/docker/docker-5.0.2-py2.py3-none-any.whl @@ -0,0 +1,1817 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + securityonion/setup/files/salt_module_deps/docker/docker-5.0.2-py2.py3-none-any.whl at 2.4/main · Security-Onion-Solutions/securityonion · GitHub + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ Skip to content + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+ + + + + +
+ + + + + + + + + +
+
+
+ + + + + + + + + + + + +
+ +
+ +
+ +
+ + + + / + + securityonion + + + Public +
+ + +
+ +
+ + +
+
+ +
+
+ + + + +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + +
+
+ + + + +
+ +
+ +
+
+ +
+ +
+

Footer

+ + + + +
+
+ + + + + © 2024 GitHub, Inc. + +
+ + +
+
+ + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + diff --git a/salt/salt/module_packages/docker/idna-2.10-py2.py3-none-any.whl b/salt/salt/module_packages/docker/idna-2.10-py2.py3-none-any.whl new file mode 100644 index 000000000..7dfbd65fd --- /dev/null +++ b/salt/salt/module_packages/docker/idna-2.10-py2.py3-none-any.whl @@ -0,0 +1,2469 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + securityonion/setup/files/salt_module_deps/docker/idna-2.10-py2.py3-none-any.whl at 2.4/main · Security-Onion-Solutions/securityonion · GitHub + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ Skip to content + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+ + + + + +
+ + + + + + + + + +
+
+
+ + + + + + + + + + + + +
+ +
+ +
+ +
+ + + + / + + securityonion + + + Public +
+ + +
+ +
+ + +
+
+ +
+
+ + + + +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + +

Latest commit

 

History

History
57.4 KB

idna-2.10-py2.py3-none-any.whl

File metadata and controls

57.4 KB
+
+ + + + +
+ +
+ +
+
+ +
+ +
+

Footer

+ + + + +
+
+ + + + + © 2024 GitHub, Inc. + +
+ + +
+
+ + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + diff --git a/salt/salt/module_packages/docker/requests-2.25.1-py2.py3-none-any.whl b/salt/salt/module_packages/docker/requests-2.25.1-py2.py3-none-any.whl new file mode 100644 index 000000000..68e34c862 --- /dev/null +++ b/salt/salt/module_packages/docker/requests-2.25.1-py2.py3-none-any.whl @@ -0,0 +1,1817 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + securityonion/setup/files/salt_module_deps/docker/requests-2.25.1-py2.py3-none-any.whl at 2.4/main · Security-Onion-Solutions/securityonion · GitHub + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ Skip to content + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+ + + + + +
+ + + + + + + + + +
+
+
+ + + + + + + + + + + + +
+ +
+ +
+ +
+ + + + / + + securityonion + + + Public +
+ + +
+ +
+ + +
+
+ +
+
+ + + + +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + +
+
+ + + + +
+ +
+ +
+
+ +
+ +
+

Footer

+ + + + +
+
+ + + + + © 2024 GitHub, Inc. + +
+ + +
+
+ + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + diff --git a/salt/salt/module_packages/docker/urllib3-1.26.15-py2.py3-none-any.whl b/salt/salt/module_packages/docker/urllib3-1.26.15-py2.py3-none-any.whl new file mode 100644 index 000000000..686d9a9e5 --- /dev/null +++ b/salt/salt/module_packages/docker/urllib3-1.26.15-py2.py3-none-any.whl @@ -0,0 +1,1817 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + securityonion/setup/files/salt_module_deps/docker/urllib3-1.26.15-py2.py3-none-any.whl at 2.4/main · Security-Onion-Solutions/securityonion · GitHub + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ Skip to content + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+ + + + + +
+ + + + + + + + + +
+
+
+ + + + + + + + + + + + +
+ +
+ +
+ +
+ + + + / + + securityonion + + + Public +
+ + +
+ +
+ + +
+
+ +
+
+ + + + +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + +
+
+ + + + +
+ +
+ +
+
+ +
+ +
+

Footer

+ + + + +
+
+ + + + + © 2024 GitHub, Inc. + +
+ + +
+
+ + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + diff --git a/salt/salt/module_packages/docker/websocket_client-1.5.1-py3-none-any.whl b/salt/salt/module_packages/docker/websocket_client-1.5.1-py3-none-any.whl new file mode 100644 index 000000000..fa5dfd9fd --- /dev/null +++ b/salt/salt/module_packages/docker/websocket_client-1.5.1-py3-none-any.whl @@ -0,0 +1,1817 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + securityonion/setup/files/salt_module_deps/docker/websocket_client-1.5.1-py3-none-any.whl at 2.4/main · Security-Onion-Solutions/securityonion · GitHub + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ Skip to content + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+ + + + + +
+ + + + + + + + + +
+
+
+ + + + + + + + + + + + +
+ +
+ +
+ +
+ + + + / + + securityonion + + + Public +
+ + +
+ +
+ + +
+
+ +
+
+ + + + +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + +
+
+ + + + +
+ +
+ +
+
+ +
+ +
+

Footer

+ + + + +
+
+ + + + + © 2024 GitHub, Inc. + +
+ + +
+
+ + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + From 81d407f0ff4afd051ba0584cc56ad5e706b85dc8 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Wed, 7 Aug 2024 15:34:37 -0400 Subject: [PATCH 010/315] new wheels --- .../docker/docker-5.0.2-py2.py3-none-any.whl | Bin 173568 -> 145967 bytes .../websocket_client-1.8.0-py3-none-any.whl | Bin 0 -> 58826 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 salt/salt/module_packages/docker/websocket_client-1.8.0-py3-none-any.whl diff --git a/salt/salt/module_packages/docker/docker-5.0.2-py2.py3-none-any.whl b/salt/salt/module_packages/docker/docker-5.0.2-py2.py3-none-any.whl index 1b63ebdeb1c560eb4fd3daa68269b448ac5901fe..f1ed95ee122f37731b51226ccbc8d6eb07405f39 100644 GIT binary patch literal 145967 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 I0)-g#KhNfV%K!iX literal 173568 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 diff --git a/salt/salt/module_packages/docker/websocket_client-1.8.0-py3-none-any.whl b/salt/salt/module_packages/docker/websocket_client-1.8.0-py3-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..a2d768d7937a90e7c5ecbd51c1332b00c9e3cdac GIT binary patch literal 58826 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%0DCms_LKk0sdE$TuK|H_S+W&{PH9J=l4HHq1$`V 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 WD$1bVxG Date: Wed, 7 Aug 2024 16:21:49 -0400 Subject: [PATCH 011/315] remove docker 7.1.0 wheels --- .../docker/certifi-2022.12.7-py3-none-any.whl | 2469 ----------------- .../docker/chardet-4.0.0-py2.py3-none-any.whl | 2469 ----------------- ...linux_2_17_x86_64.manylinux2014_x86_64.whl | 2469 ----------------- .../docker/docker-7.1.0-py3-none-any.whl | Bin 147774 -> 0 bytes .../docker/idna-2.10-py2.py3-none-any.whl | 2469 ----------------- .../requests-2.25.1-py2.py3-none-any.whl | 1817 ------------ .../urllib3-1.26.15-py2.py3-none-any.whl | 1817 ------------ .../websocket_client-1.5.1-py3-none-any.whl | 1817 ------------ 8 files changed, 15327 deletions(-) delete mode 100644 salt/salt/module_packages/docker/certifi-2022.12.7-py3-none-any.whl delete mode 100644 salt/salt/module_packages/docker/chardet-4.0.0-py2.py3-none-any.whl delete mode 100644 salt/salt/module_packages/docker/charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl delete mode 100644 salt/salt/module_packages/docker/docker-7.1.0-py3-none-any.whl delete mode 100644 salt/salt/module_packages/docker/idna-2.10-py2.py3-none-any.whl delete mode 100644 salt/salt/module_packages/docker/requests-2.25.1-py2.py3-none-any.whl delete mode 100644 salt/salt/module_packages/docker/urllib3-1.26.15-py2.py3-none-any.whl delete mode 100644 salt/salt/module_packages/docker/websocket_client-1.5.1-py3-none-any.whl diff --git a/salt/salt/module_packages/docker/certifi-2022.12.7-py3-none-any.whl b/salt/salt/module_packages/docker/certifi-2022.12.7-py3-none-any.whl deleted file mode 100644 index 7f561460a..000000000 --- a/salt/salt/module_packages/docker/certifi-2022.12.7-py3-none-any.whl +++ /dev/null @@ -1,2469 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - securityonion/setup/files/salt_module_deps/docker/certifi-2022.12.7-py3-none-any.whl at 2.4/main · Security-Onion-Solutions/securityonion · GitHub - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

- - - -
- Skip to content - - - - - - - - - - - -
-
- - - - - - - - - - - - - - -
- -
- - - - - - - - -
- - - - - -
- - - - - - - - - -
-
-
- - - - - - - - - - - - -
- -
- -
- -
- - - - / - - securityonion - - - Public -
- - -
- -
- - -
-
- -
-
- - - - -
- - - - - - -
- - - - - - - - - - - - - - - - - - -

Latest commit

 

History

History
152 KB

certifi-2022.12.7-py3-none-any.whl

File metadata and controls

152 KB
-
- - - - -
- -
- -
-
- -
- -
-

Footer

- - - - -
-
- - - - - © 2024 GitHub, Inc. - -
- - -
-
- - - - - - - - - - - - - - - - - - - -
- -
-
- - - diff --git a/salt/salt/module_packages/docker/chardet-4.0.0-py2.py3-none-any.whl b/salt/salt/module_packages/docker/chardet-4.0.0-py2.py3-none-any.whl deleted file mode 100644 index 3b4094eb5..000000000 --- a/salt/salt/module_packages/docker/chardet-4.0.0-py2.py3-none-any.whl +++ /dev/null @@ -1,2469 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - securityonion/setup/files/salt_module_deps/docker/chardet-4.0.0-py2.py3-none-any.whl at 2.4/main · Security-Onion-Solutions/securityonion · GitHub - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -
- Skip to content - - - - - - - - - - - -
-
- - - - - - - - - - - - - - -
- -
- - - - - - - - -
- - - - - -
- - - - - - - - - -
-
-
- - - - - - - - - - - - -
- -
- -
- -
- - - - / - - securityonion - - - Public -
- - -
- -
- - -
-
- -
-
- - - - -
- - - - - - -
- - - - - - - - - - - - - - - - - - -

Latest commit

 

History

History
175 KB

chardet-4.0.0-py2.py3-none-any.whl

File metadata and controls

175 KB
-
- - - - -
- -
- -
-
- -
- -
-

Footer

- - - - -
-
- - - - - © 2024 GitHub, Inc. - -
- - -
-
- - - - - - - - - - - - - - - - - - - -
- -
-
- - - diff --git a/salt/salt/module_packages/docker/charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl b/salt/salt/module_packages/docker/charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl deleted file mode 100644 index 87df81cbc..000000000 --- a/salt/salt/module_packages/docker/charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl +++ /dev/null @@ -1,2469 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - securityonion/setup/files/salt_module_deps/docker/charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl at 2.4/main · Security-Onion-Solutions/securityonion · GitHub - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -
- Skip to content - - - - - - - - - - - -
-
- - - - - - - - - - - - - - -
- -
- - - - - - - - -
- - - - - -
- - - - - - - - - -
-
-
- - - - - - - - - - - - -
- -
- -
- -
- - - - / - - securityonion - - - Public -
- - -
- -
- - -
-
- -
-
- - - - -
- - - - - - -
- - - - - - - - - - - - - - - - - - -

Latest commit

 

History

History
195 KB

charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

File metadata and controls

195 KB
-
- - - - -
- -
- -
-
- -
- -
-

Footer

- - - - -
-
- - - - - © 2024 GitHub, Inc. - -
- - -
-
- - - - - - - - - - - - - - - - - - - -
- -
-
- - - diff --git a/salt/salt/module_packages/docker/docker-7.1.0-py3-none-any.whl b/salt/salt/module_packages/docker/docker-7.1.0-py3-none-any.whl deleted file mode 100644 index c324efbd08e43702330255be41022230df757452..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 147774 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νsv=4VNYjF8rcz{%)OXa%MGl~1G&aaT9M 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 diff --git a/salt/salt/module_packages/docker/idna-2.10-py2.py3-none-any.whl b/salt/salt/module_packages/docker/idna-2.10-py2.py3-none-any.whl deleted file mode 100644 index 7dfbd65fd..000000000 --- a/salt/salt/module_packages/docker/idna-2.10-py2.py3-none-any.whl +++ /dev/null @@ -1,2469 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - securityonion/setup/files/salt_module_deps/docker/idna-2.10-py2.py3-none-any.whl at 2.4/main · Security-Onion-Solutions/securityonion · GitHub - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -
- Skip to content - - - - - - - - - - - -
-
- - - - - - - - - - - - - - -
- -
- - - - - - - - -
- - - - - -
- - - - - - - - - -
-
-
- - - - - - - - - - - - -
- -
- -
- -
- - - - / - - securityonion - - - Public -
- - -
- -
- - -
-
- -
-
- - - - -
- - - - - - -
- - - - - - - - - - - - - - - - - - -

Latest commit

 

History

History
57.4 KB

idna-2.10-py2.py3-none-any.whl

File metadata and controls

57.4 KB
-
- - - - -
- -
- -
-
- -
- -
-

Footer

- - - - -
-
- - - - - © 2024 GitHub, Inc. - -
- - -
-
- - - - - - - - - - - - - - - - - - - -
- -
-
- - - diff --git a/salt/salt/module_packages/docker/requests-2.25.1-py2.py3-none-any.whl b/salt/salt/module_packages/docker/requests-2.25.1-py2.py3-none-any.whl deleted file mode 100644 index 68e34c862..000000000 --- a/salt/salt/module_packages/docker/requests-2.25.1-py2.py3-none-any.whl +++ /dev/null @@ -1,1817 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - securityonion/setup/files/salt_module_deps/docker/requests-2.25.1-py2.py3-none-any.whl at 2.4/main · Security-Onion-Solutions/securityonion · GitHub - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -
- Skip to content - - - - - - - - - - - -
-
- - - - - - - - - - - - - - -
- -
- - - - - - - - -
- - - - - -
- - - - - - - - - -
-
-
- - - - - - - - - - - - -
- -
- -
- -
- - - - / - - securityonion - - - Public -
- - -
- -
- - -
-
- -
-
- - - - -
- - - - - - -
- - - - - - - - - - - - - - - - - - -
-
- - - - -
- -
- -
-
- -
- -
-

Footer

- - - - -
-
- - - - - © 2024 GitHub, Inc. - -
- - -
-
- - - - - - - - - - - - - - - - - - - -
- -
-
- - - diff --git a/salt/salt/module_packages/docker/urllib3-1.26.15-py2.py3-none-any.whl b/salt/salt/module_packages/docker/urllib3-1.26.15-py2.py3-none-any.whl deleted file mode 100644 index 686d9a9e5..000000000 --- a/salt/salt/module_packages/docker/urllib3-1.26.15-py2.py3-none-any.whl +++ /dev/null @@ -1,1817 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - securityonion/setup/files/salt_module_deps/docker/urllib3-1.26.15-py2.py3-none-any.whl at 2.4/main · Security-Onion-Solutions/securityonion · GitHub - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -
- Skip to content - - - - - - - - - - - -
-
- - - - - - - - - - - - - - -
- -
- - - - - - - - -
- - - - - -
- - - - - - - - - -
-
-
- - - - - - - - - - - - -
- -
- -
- -
- - - - / - - securityonion - - - Public -
- - -
- -
- - -
-
- -
-
- - - - -
- - - - - - -
- - - - - - - - - - - - - - - - - - -
-
- - - - -
- -
- -
-
- -
- -
-

Footer

- - - - -
-
- - - - - © 2024 GitHub, Inc. - -
- - -
-
- - - - - - - - - - - - - - - - - - - -
- -
-
- - - diff --git a/salt/salt/module_packages/docker/websocket_client-1.5.1-py3-none-any.whl b/salt/salt/module_packages/docker/websocket_client-1.5.1-py3-none-any.whl deleted file mode 100644 index fa5dfd9fd..000000000 --- a/salt/salt/module_packages/docker/websocket_client-1.5.1-py3-none-any.whl +++ /dev/null @@ -1,1817 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - securityonion/setup/files/salt_module_deps/docker/websocket_client-1.5.1-py3-none-any.whl at 2.4/main · Security-Onion-Solutions/securityonion · GitHub - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -
- Skip to content - - - - - - - - - - - -
-
- - - - - - - - - - - - - - -
- -
- - - - - - - - -
- - - - - -
- - - - - - - - - -
-
-
- - - - - - - - - - - - -
- -
- -
- -
- - - - / - - securityonion - - - Public -
- - -
- -
- - -
-
- -
-
- - - - -
- - - - - - -
- - - - - - - - - - - - - - - - - - -
-
- - - - -
- -
- -
-
- -
- -
-

Footer

- - - - -
-
- - - - - © 2024 GitHub, Inc. - -
- - -
-
- - - - - - - - - - - - - - - - - - - -
- -
-
- - - From a28ac3bee6ce73221e7b35575a0ebe535b2ebad6 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Fri, 9 Aug 2024 11:53:07 -0400 Subject: [PATCH 012/315] virt --- salt/allowed_states.map.jinja | 9 +++--- salt/libvirt/init.sls | 28 ++++++++----------- salt/libvirt/packages.sls | 20 +++++++++++++ salt/salt/cloud/cloud.profiles.d/socloud.conf | 8 +++--- .../libvirt.conf | 14 +++++----- salt/salt/cloud/init.sls | 24 ++++++++++++++++ salt/salt/map.jinja | 9 ++++-- salt/salt/master.sls | 5 ++++ salt/vars/hypervisor.map.jinja | 7 ++++- 9 files changed, 90 insertions(+), 34 deletions(-) create mode 100644 salt/libvirt/packages.sls rename salt/salt/cloud/{cloud.provides.d => cloud.providers.d}/libvirt.conf (55%) create mode 100644 salt/salt/cloud/init.sls diff --git a/salt/allowed_states.map.jinja b/salt/allowed_states.map.jinja index 1cdf6145e..4c518fa92 100644 --- a/salt/allowed_states.map.jinja +++ b/salt/allowed_states.map.jinja @@ -1,7 +1,7 @@ -# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one -# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at -# https://securityonion.net/license; you may not use this file except in compliance with the -# Elastic License 2.0. +{# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one + or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at + https://securityonion.net/license; you may not use this file except in compliance with the + Elastic License 2.0. #} {% set ISAIRGAP = salt['pillar.get']('global:airgap', False) %} {% import_yaml 'salt/minion.defaults.yaml' as saltversion %} @@ -85,6 +85,7 @@ ], 'so-manager': [ 'salt.master', + 'salt.cloud', 'ca', 'ssl', 'registry', diff --git a/salt/libvirt/init.sls b/salt/libvirt/init.sls index 1e4e3dde0..4c87e22e7 100644 --- a/salt/libvirt/init.sls +++ b/salt/libvirt/init.sls @@ -5,6 +5,9 @@ {% from 'libvirt/map.jinja' import LIBVIRTMERGED %} +include: + - libvirt.packages + install_libvirt: pkg.installed: - name: libvirt @@ -38,22 +41,6 @@ libvirt_service: - watch: - file: libvirt_config -libvirt_source-packages_dir: - file.directory: - - name: /opt/so/conf/libvirt/source-packages - -libvirt_python_wheel: - file.recurse: - - name: /opt/so/conf/libvirt/source-packages/libvirt-python - - source: salt://libvirt/source-packages/libvirt-python - - clean: True - -libvirt_python_module: - cmd.run: - - name: /opt/saltstack/salt/bin/python3.10 -m pip install --no-index --find-links=/opt/so/conf/libvirt/source-packages/libvirt-python libvirt-python - - onchanges: - - file: libvirt_python_wheel - # places cacert, clientcert, clientkey, servercert and serverkey # /etc/pki/CA/cacert.pem # /etc/pki/libvirt/clientcert.pem and /etc/pki/libvirt/servercert.pem @@ -74,5 +61,14 @@ install-guestfs-tools: pkg.installed: - name: guestfs-tools +# this should only run during the first highstate after setup. it will transfer connection from mgmt to br0 +down_original_mgmt_interface: + cmd.run: + - name: "nmcli con down {{ pillar.host.mainint }}" + - unless: + - nmcli -f GENERAL.CONNECTION dev show {{ pillar.host.mainint }} | grep bridge-slave-{{ pillar.host.mainint }} + - order: last + + # virtlogd service may not restart following reboot without this #semanage permissive -a virtlogd_t diff --git a/salt/libvirt/packages.sls b/salt/libvirt/packages.sls new file mode 100644 index 000000000..dc7db9cf8 --- /dev/null +++ b/salt/libvirt/packages.sls @@ -0,0 +1,20 @@ +#libvirt_source-packages_dir: + # file.directory: + # - name: /opt/so/conf/libvirt/source-packages + +install_libvirt-libs: + pkg.installed: + - name: libvirt-libs + +libvirt_python_wheel: + file.recurse: + - name: /opt/so/conf/libvirt/source-packages/libvirt-python + - source: salt://libvirt/source-packages/libvirt-python + - makedirs: True + - clean: True + +libvirt_python_module: + cmd.run: + - name: /opt/saltstack/salt/bin/python3.10 -m pip install --no-index --find-links=/opt/so/conf/libvirt/source-packages/libvirt-python libvirt-python + - onchanges: + - file: libvirt_python_wheel diff --git a/salt/salt/cloud/cloud.profiles.d/socloud.conf b/salt/salt/cloud/cloud.profiles.d/socloud.conf index c410fd7c3..9949e219d 100644 --- a/salt/salt/cloud/cloud.profiles.d/socloud.conf +++ b/salt/salt/cloud/cloud.profiles.d/socloud.conf @@ -50,16 +50,16 @@ sensor: - setHostname core: - provider: local-kvm + provider: kvm-via-ssh base_domain: jppol9vm ip_source: qemu-agent - ssh_username: jpatterson - private_key: /home/jpatterson/.ssh/id_rsa + ssh_username: onionuser + private_key: /home/onionuser/.ssh/id_ed25519 sudo: True deploy_command: sh /tmp/.saltcloud-*/deploy.sh script_args: -F -x python3 stable 3006.1 minion: - master: jppvirt + master: jpp90man master_port: 4506 startup_states: sls sls_list: diff --git a/salt/salt/cloud/cloud.provides.d/libvirt.conf b/salt/salt/cloud/cloud.providers.d/libvirt.conf similarity index 55% rename from salt/salt/cloud/cloud.provides.d/libvirt.conf rename to salt/salt/cloud/cloud.providers.d/libvirt.conf index 8c57cc1e5..587653010 100644 --- a/salt/salt/cloud/cloud.provides.d/libvirt.conf +++ b/salt/salt/cloud/cloud.providers.d/libvirt.conf @@ -1,11 +1,11 @@ # Set up a provider with qemu+ssh protocol -#kvm-via-ssh: -# driver: libvirt -# url: qemu+ssh://jpatterson@jppvirt/system?socket=/var/run/libvirt/libvirt-sock +kvm-via-ssh: + driver: libvirt + url: qemu+ssh://onionuser@jpphype1/system?socket=/var/run/libvirt/libvirt-sock # Or connect to a local libvirt instance -local-kvm: - driver: libvirt - url: qemu:///system +#local-kvm: +# driver: libvirt +# url: qemu:///system # work around flag for XML validation errors while cloning - validate_xml: no +# validate_xml: no diff --git a/salt/salt/cloud/init.sls b/salt/salt/cloud/init.sls new file mode 100644 index 000000000..baaf44e88 --- /dev/null +++ b/salt/salt/cloud/init.sls @@ -0,0 +1,24 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls in allowed_states %} +{% from 'salt/map.jinja' import SALTVERSION %} + +include: + - libvirt.packages + +install_salt_cloud: + pkg.installed: + - name: salt-cloud + - version: {{SALTVERSION}} + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/salt/map.jinja b/salt/salt/map.jinja index 5f687ef3f..9a08304ca 100644 --- a/salt/salt/map.jinja +++ b/salt/salt/map.jinja @@ -1,15 +1,20 @@ +{# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one + or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at + https://securityonion.net/license; you may not use this file except in compliance with the + Elastic License 2.0. #} + {% import_yaml 'salt/minion.defaults.yaml' as saltminion %} {% set SALTVERSION = saltminion.salt.minion.version %} {% if grains.os_family == 'Debian' %} {% set SPLITCHAR = '+' %} {% set SALTNOTHELD = salt['cmd.run']('apt-mark showhold | grep -q salt ; echo $?', python_shell=True) %} - {% set SALTPACKAGES = ['salt-common', 'salt-master', 'salt-minion'] %} + {% set SALTPACKAGES = ['salt-common', 'salt-master', 'salt-minion', 'salt-cloud'] %} {% set SYSTEMD_UNIT_FILE = '/lib/systemd/system/salt-minion.service' %} {% else %} {% set SPLITCHAR = '-' %} {% set SALTNOTHELD = salt['cmd.run']('yum versionlock list | grep -q salt ; echo $?', python_shell=True) %} - {% set SALTPACKAGES = ['salt', 'salt-master', 'salt-minion'] %} + {% set SALTPACKAGES = ['salt', 'salt-master', 'salt-minion', 'salt-cloud'] %} {% set SYSTEMD_UNIT_FILE = '/usr/lib/systemd/system/salt-minion.service' %} {% endif %} diff --git a/salt/salt/master.sls b/salt/salt/master.sls index 84e18b8fc..9558352dd 100644 --- a/salt/salt/master.sls +++ b/salt/salt/master.sls @@ -1,3 +1,8 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + {% from 'salt/map.jinja' import SALTNOTHELD %} {% from 'allowed_states.map.jinja' import allowed_states %} {% if sls in allowed_states %} diff --git a/salt/vars/hypervisor.map.jinja b/salt/vars/hypervisor.map.jinja index 964f69663..b8fd4ac1f 100644 --- a/salt/vars/hypervisor.map.jinja +++ b/salt/vars/hypervisor.map.jinja @@ -1 +1,6 @@ -{% set ROLE_GLOBALS = {} %} +{% import 'vars/init.map.jinja' as INIT %} +{% + set ROLE_GLOBALS = { + 'node_ip': INIT.GRAINS.ip_interfaces.get('br0')[0] + } +%} From 64a0c171f3b3e6335948d173a88a9cde867e34c0 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Mon, 12 Aug 2024 12:47:04 -0400 Subject: [PATCH 013/315] ssh user, build cloud profiles and providers --- pillar/hypervisor/nodes.sls | 34 +++++++++++ pillar/top.sls | 1 + salt/libvirt/packages.sls | 5 ++ salt/libvirt/ssh/files/config | 2 + salt/libvirt/ssh/users.sls | 56 +++++++++++++++++++ .../{socloud.conf => socloud.conf.jinja} | 8 ++- .../salt/cloud/cloud.providers.d/libvirt.conf | 11 ---- .../cloud.providers.d/libvirt.conf.jinja | 19 +++++++ salt/salt/cloud/init.sls | 16 ++++++ setup/so-setup | 1 + 10 files changed, 140 insertions(+), 13 deletions(-) create mode 100644 pillar/hypervisor/nodes.sls create mode 100644 salt/libvirt/ssh/files/config create mode 100644 salt/libvirt/ssh/users.sls rename salt/salt/cloud/cloud.profiles.d/{socloud.conf => socloud.conf.jinja} (95%) delete mode 100644 salt/salt/cloud/cloud.providers.d/libvirt.conf create mode 100644 salt/salt/cloud/cloud.providers.d/libvirt.conf.jinja diff --git a/pillar/hypervisor/nodes.sls b/pillar/hypervisor/nodes.sls new file mode 100644 index 000000000..0cdec95d3 --- /dev/null +++ b/pillar/hypervisor/nodes.sls @@ -0,0 +1,34 @@ +{% set node_types = {} %} +{% for minionid, ip in salt.saltutil.runner( + 'mine.get', + tgt='G@role:so-hypervisor', + fun='network.ip_addrs', + tgt_type='compound') | dictsort() +%} + +# only add a node to the pillar if it returned an ip from the mine +{% if ip | length > 0%} +{% set hostname = minionid.split('_') | first %} +{% set node_type = minionid.split('_') | last %} +{% if node_type not in node_types.keys() %} +{% do node_types.update({node_type: {hostname: ip[0]}}) %} +{% else %} +{% if hostname not in node_types[node_type] %} +{% do node_types[node_type].update({hostname: ip[0]}) %} +{% else %} +{% do node_types[node_type][hostname].update(ip[0]) %} +{% endif %} +{% endif %} +{% endif %} +{% endfor %} + + +hypervisor: + nodes: +{% for node_type, values in node_types.items() %} + {{node_type}}: +{% for hostname, ip in values.items() %} + {{hostname}}: + ip: {{ip}} +{% endfor %} +{% endfor %} diff --git a/pillar/top.sls b/pillar/top.sls index 1a0d5f8c6..031ff5d3d 100644 --- a/pillar/top.sls +++ b/pillar/top.sls @@ -66,6 +66,7 @@ base: - kafka.nodes - kafka.soc_kafka - kafka.adv_kafka + - hypervisor.nodes - stig.soc_stig '*_sensor': diff --git a/salt/libvirt/packages.sls b/salt/libvirt/packages.sls index dc7db9cf8..bc39d4df1 100644 --- a/salt/libvirt/packages.sls +++ b/salt/libvirt/packages.sls @@ -6,6 +6,11 @@ install_libvirt-libs: pkg.installed: - name: libvirt-libs +# provides virsh +install_libvirt-client: + pkg.installed: + - name: libvirt-client + libvirt_python_wheel: file.recurse: - name: /opt/so/conf/libvirt/source-packages/libvirt-python diff --git a/salt/libvirt/ssh/files/config b/salt/libvirt/ssh/files/config new file mode 100644 index 000000000..25af86b73 --- /dev/null +++ b/salt/libvirt/ssh/files/config @@ -0,0 +1,2 @@ +Host * + IdentityFile /home/soqemussh/.ssh/id_ed25519 diff --git a/salt/libvirt/ssh/users.sls b/salt/libvirt/ssh/users.sls new file mode 100644 index 000000000..5913deb15 --- /dev/null +++ b/salt/libvirt/ssh/users.sls @@ -0,0 +1,56 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'vars/globals.map.jinja' import GLOBALS %} + +# used for qemu+ssh connection between manager and hypervisors +create_soqemussh_user: + user.present: + - name: soqemussh + - shell: /bin/bash + - home: /home/soqemussh +{% if not GLOBALS.is_manager %} + - groups: + - wheel +{% endif %} + +{% if GLOBALS.is_manager %} + +create_local_libvirt_ssh_key_dir: + file.directory: + - name: /opt/so/saltstack/local/salt/libvirt/ssh/keys + - user: socore + - group: socore + - mode: 755 + - makedirs: True + +# generate the key pair and put the pub key in salt local files roots +generate_ssh_key_soqemussh: + cmd.run: + - name: ssh-keygen -q -N '' -t ed25519 -f /home/soqemussh/.ssh/id_ed25519 + - runas: soqemussh + - unless: test -f /home/soqemussh/.ssh/id_ed25519 + - require: + - user: create_soqemussh_user + +soqemussh_ssh_key_to_local: + cmd.run: + - name: cp /home/soqemussh/.ssh/id_ed25519.pub /opt/so/saltstack/local/salt/libvirt/ssh/keys + - onchanges: + - cmd: generate_ssh_key_soqemussh + +qemu_ssh_client_config: + file.managed: + - name: /root/.ssh/config + - source: salt://libvirt/ssh/files/config + +{% else %} + +soqemussh_pub_key: + ssh_auth.present: + - user: soqemussh + - source: salt://libvirt/ssh_keys/id_ed25519.pub + +{% endif %} diff --git a/salt/salt/cloud/cloud.profiles.d/socloud.conf b/salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja similarity index 95% rename from salt/salt/cloud/cloud.profiles.d/socloud.conf rename to salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja index 9949e219d..da8044323 100644 --- a/salt/salt/cloud/cloud.profiles.d/socloud.conf +++ b/salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja @@ -49,8 +49,10 @@ sensor: sls_list: - setHostname -core: - provider: kvm-via-ssh +{%- for hv in HYPERVISORS %} + +core-{{hv}}: + provider: kvm-ssh-{{hv}} base_domain: jppol9vm ip_source: qemu-agent ssh_username: onionuser @@ -64,3 +66,5 @@ core: startup_states: sls sls_list: - setHostname + +{%- endfor %} diff --git a/salt/salt/cloud/cloud.providers.d/libvirt.conf b/salt/salt/cloud/cloud.providers.d/libvirt.conf deleted file mode 100644 index 587653010..000000000 --- a/salt/salt/cloud/cloud.providers.d/libvirt.conf +++ /dev/null @@ -1,11 +0,0 @@ -# Set up a provider with qemu+ssh protocol -kvm-via-ssh: - driver: libvirt - url: qemu+ssh://onionuser@jpphype1/system?socket=/var/run/libvirt/libvirt-sock - -# Or connect to a local libvirt instance -#local-kvm: -# driver: libvirt -# url: qemu:///system - # work around flag for XML validation errors while cloning -# validate_xml: no diff --git a/salt/salt/cloud/cloud.providers.d/libvirt.conf.jinja b/salt/salt/cloud/cloud.providers.d/libvirt.conf.jinja new file mode 100644 index 000000000..5ead21f1f --- /dev/null +++ b/salt/salt/cloud/cloud.providers.d/libvirt.conf.jinja @@ -0,0 +1,19 @@ +# Set up a provider with qemu+ssh protocol +#kvm-ssh-jpphype1: +# driver: libvirt +# url: qemu+ssh://soqemussh@jpphype1/system?socket=/var/run/libvirt/libvirt-sock + +{%- for hv in HYPERVISORS %} + +kvm-ssh-{{hv}}: + driver: libvirt + url: qemu+ssh://soqemussh@{{hv}}/system?socket=/var/run/libvirt/libvirt-sock + +{%- endfor %} + +# Or connect to a local libvirt instance +#local-kvm: +# driver: libvirt +# url: qemu:///system + # work around flag for XML validation errors while cloning +# validate_xml: no diff --git a/salt/salt/cloud/init.sls b/salt/salt/cloud/init.sls index baaf44e88..60ee23067 100644 --- a/salt/salt/cloud/init.sls +++ b/salt/salt/cloud/init.sls @@ -15,6 +15,22 @@ install_salt_cloud: - name: salt-cloud - version: {{SALTVERSION}} +cloud_providers: + file.managed: + - name: /etc/salt/cloud.providers.d/libvirt.conf + - source: salt://salt/cloud/cloud.providers.d/libvirt.conf.jinja + - defaults: + HYPERVISORS: {{pillar.hypervisor.nodes}} + - template: jinja + +cloud_profiles: + file.managed: + - name: /etc/salt/cloud.profiles.d/socloud.conf + - source: salt://salt/cloud/cloud.profiles.d/socloud.conf.jinja + - defaults: + HYPERVISORS: {{pillar.hypervisor.nodes}} + - template: jinja + {% else %} {{sls}}_state_not_allowed: diff --git a/setup/so-setup b/setup/so-setup index 5ae0a5218..1c7efbd68 100755 --- a/setup/so-setup +++ b/setup/so-setup @@ -629,6 +629,7 @@ if ! [[ -f $install_opt_file ]]; then check_requirements networking_needful configure_hyper_bridge + MNIC=br0 collect_mngr_hostname add_mngr_ip_to_hosts check_manager_connection From 957235a6566dec6568d455768ee4215c41dd441b Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Mon, 12 Aug 2024 13:31:51 -0400 Subject: [PATCH 014/315] fix dns-search --- setup/so-functions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup/so-functions b/setup/so-functions index f80f702c1..1cd59b9da 100755 --- a/setup/so-functions +++ b/setup/so-functions @@ -769,7 +769,7 @@ configure_hyper_bridge() { logCmd "nmcli con mod br0 ipv4.addresses $addresses" logCmd "nmcli con mod br0 ipv4.gateway $gateway" logCmd "nmcli con mod br0 ipv4.dns $dns" - logCmd "nmcli con mod br0 ipv4.dns-search $dns-search" + logCmd "nmcli con mod br0 ipv4.dns-search $dnssearch" logCmd "nmcli con mod br0 ipv4.method manual" logCmd "nmcli con up br0" # we cant bring down MNIC here since it would disrupt ssh sessions. we will need to bring it down at the end of the first highstate From f9eeb76518a861388951763b026abf8616f3e072 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Mon, 12 Aug 2024 14:58:10 -0400 Subject: [PATCH 015/315] mine for hyper --- salt/salt/etc/minion.d/mine_functions.conf.jinja | 8 +++++++- setup/so-setup | 1 - 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/salt/salt/etc/minion.d/mine_functions.conf.jinja b/salt/salt/etc/minion.d/mine_functions.conf.jinja index 529dee3b0..fb721512f 100644 --- a/salt/salt/etc/minion.d/mine_functions.conf.jinja +++ b/salt/salt/etc/minion.d/mine_functions.conf.jinja @@ -1,7 +1,13 @@ +{% if grains.role == 'so-hypervisor' %} +{% set interface = 'br0' %} +{% else %} +{% set interface = pillar.host.mainint %} +{% endif %} + mine_interval: 25 mine_functions: network.ip_addrs: - - interface: {{ pillar.host.mainint }} + - interface: {{ interface }} {%- if grains.role in ['so-eval','so-import','so-manager','so-managersearch','so-standalone'] %} x509.get_pem_entries: - glob_path: '/etc/pki/ca.crt' diff --git a/setup/so-setup b/setup/so-setup index 1c7efbd68..5ae0a5218 100755 --- a/setup/so-setup +++ b/setup/so-setup @@ -629,7 +629,6 @@ if ! [[ -f $install_opt_file ]]; then check_requirements networking_needful configure_hyper_bridge - MNIC=br0 collect_mngr_hostname add_mngr_ip_to_hosts check_manager_connection From aa5de9f7bd6a0da592df176881f8ada5361a5272 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Tue, 13 Aug 2024 10:17:45 -0400 Subject: [PATCH 016/315] cloud profiles and providers. libvirt net setup --- salt/libvirt/init.sls | 17 +++++++++++------ salt/libvirt/packages.sls | 19 +++++++++++++++++++ salt/libvirt/ssh/users.sls | 2 +- .../cloud/cloud.profiles.d/socloud.conf.jinja | 8 +++++--- .../cloud.providers.d/libvirt.conf.jinja | 8 +++++--- salt/salt/cloud/init.sls | 2 +- 6 files changed, 42 insertions(+), 14 deletions(-) diff --git a/salt/libvirt/init.sls b/salt/libvirt/init.sls index 4c87e22e7..7d1d19240 100644 --- a/salt/libvirt/init.sls +++ b/salt/libvirt/init.sls @@ -53,13 +53,18 @@ install_qemu: pkg.installed: - name: qemu-kvm -install_libguestfs: - pkg.installed: - - name: libguestfs +create_host_bridge: + virt.network_running: + - name: host-bridge + - bridge: br0 + - forward: bridge + - autostart: True -install-guestfs-tools: - pkg.installed: - - name: guestfs-tools +disable_default_bridge: + cmd.run: + - name: virsh net-destroy default && virsh net-autostart default --disable + - require: + - pkg: install_libvirt-client # this should only run during the first highstate after setup. it will transfer connection from mgmt to br0 down_original_mgmt_interface: diff --git a/salt/libvirt/packages.sls b/salt/libvirt/packages.sls index bc39d4df1..9b56c6f64 100644 --- a/salt/libvirt/packages.sls +++ b/salt/libvirt/packages.sls @@ -11,6 +11,25 @@ install_libvirt-client: pkg.installed: - name: libvirt-client +# allows for creating vm images +# any node manipulating images needs this +install_qemu-img: + pkg.installed: + - name: qemu-img + +install_guestfs-tools: + pkg.installed: + - name: guestfs-tools + +install_xorriso: + pkg.installed: + - name: xorriso + +install_virt-install: + pkg.installed: + - name: virt-install +### + libvirt_python_wheel: file.recurse: - name: /opt/so/conf/libvirt/source-packages/libvirt-python diff --git a/salt/libvirt/ssh/users.sls b/salt/libvirt/ssh/users.sls index 5913deb15..28d9afe0d 100644 --- a/salt/libvirt/ssh/users.sls +++ b/salt/libvirt/ssh/users.sls @@ -51,6 +51,6 @@ qemu_ssh_client_config: soqemussh_pub_key: ssh_auth.present: - user: soqemussh - - source: salt://libvirt/ssh_keys/id_ed25519.pub + - source: salt://libvirt/ssh/keys/id_ed25519.pub {% endif %} diff --git a/salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja b/salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja index da8044323..1a5243666 100644 --- a/salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja +++ b/salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja @@ -49,10 +49,11 @@ sensor: sls_list: - setHostname -{%- for hv in HYPERVISORS %} +{%- for node_type, hosts in HYPERVISORS.items() %} +{%- for host in hosts %} -core-{{hv}}: - provider: kvm-ssh-{{hv}} +core-{{host}}: + provider: kvm-ssh-{{host}} base_domain: jppol9vm ip_source: qemu-agent ssh_username: onionuser @@ -67,4 +68,5 @@ core-{{hv}}: sls_list: - setHostname +{%- endfor %} {%- endfor %} diff --git a/salt/salt/cloud/cloud.providers.d/libvirt.conf.jinja b/salt/salt/cloud/cloud.providers.d/libvirt.conf.jinja index 5ead21f1f..3f18a9124 100644 --- a/salt/salt/cloud/cloud.providers.d/libvirt.conf.jinja +++ b/salt/salt/cloud/cloud.providers.d/libvirt.conf.jinja @@ -3,12 +3,14 @@ # driver: libvirt # url: qemu+ssh://soqemussh@jpphype1/system?socket=/var/run/libvirt/libvirt-sock -{%- for hv in HYPERVISORS %} +{%- for node_type, hosts in HYPERVISORS.items() %} +{%- for host in hosts %} -kvm-ssh-{{hv}}: +kvm-ssh-{{host}}: driver: libvirt - url: qemu+ssh://soqemussh@{{hv}}/system?socket=/var/run/libvirt/libvirt-sock + url: qemu+ssh://soqemussh@{{host}}/system?socket=/var/run/libvirt/libvirt-sock +{%- endfor %} {%- endfor %} # Or connect to a local libvirt instance diff --git a/salt/salt/cloud/init.sls b/salt/salt/cloud/init.sls index 60ee23067..63c624bdb 100644 --- a/salt/salt/cloud/init.sls +++ b/salt/salt/cloud/init.sls @@ -28,7 +28,7 @@ cloud_profiles: - name: /etc/salt/cloud.profiles.d/socloud.conf - source: salt://salt/cloud/cloud.profiles.d/socloud.conf.jinja - defaults: - HYPERVISORS: {{pillar.hypervisor.nodes}} + HYPERVISORS: {{pillar.hypervisor.nodes.hypervisor}} - template: jinja {% else %} From 2a35e459202f157c509dc88f391b62d329ddcc97 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Tue, 13 Aug 2024 13:17:09 -0400 Subject: [PATCH 017/315] hyper --- salt/libvirt/init.sls | 3 +++ salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja | 8 +++----- salt/salt/cloud/cloud.providers.d/libvirt.conf.jinja | 8 +------- salt/salt/cloud/init.sls | 2 +- 4 files changed, 8 insertions(+), 13 deletions(-) diff --git a/salt/libvirt/init.sls b/salt/libvirt/init.sls index 7d1d19240..f4c9e1d5b 100644 --- a/salt/libvirt/init.sls +++ b/salt/libvirt/init.sls @@ -7,6 +7,7 @@ include: - libvirt.packages + - libvirt.ssh.users install_libvirt: pkg.installed: @@ -65,6 +66,8 @@ disable_default_bridge: - name: virsh net-destroy default && virsh net-autostart default --disable - require: - pkg: install_libvirt-client + - onlyif: + - virsh net-info | grep default # this should only run during the first highstate after setup. it will transfer connection from mgmt to br0 down_original_mgmt_interface: diff --git a/salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja b/salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja index 1a5243666..6bc914fd1 100644 --- a/salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja +++ b/salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja @@ -49,15 +49,14 @@ sensor: sls_list: - setHostname -{%- for node_type, hosts in HYPERVISORS.items() %} -{%- for host in hosts %} +{%- for host in HYPERVISORS %} core-{{host}}: provider: kvm-ssh-{{host}} base_domain: jppol9vm ip_source: qemu-agent - ssh_username: onionuser - private_key: /home/onionuser/.ssh/id_ed25519 + ssh_username: soqemussh + private_key: /home/soqemussh/.ssh/id_ed25519 sudo: True deploy_command: sh /tmp/.saltcloud-*/deploy.sh script_args: -F -x python3 stable 3006.1 @@ -68,5 +67,4 @@ core-{{host}}: sls_list: - setHostname -{%- endfor %} {%- endfor %} diff --git a/salt/salt/cloud/cloud.providers.d/libvirt.conf.jinja b/salt/salt/cloud/cloud.providers.d/libvirt.conf.jinja index 3f18a9124..a8b72faf2 100644 --- a/salt/salt/cloud/cloud.providers.d/libvirt.conf.jinja +++ b/salt/salt/cloud/cloud.providers.d/libvirt.conf.jinja @@ -1,16 +1,10 @@ # Set up a provider with qemu+ssh protocol -#kvm-ssh-jpphype1: -# driver: libvirt -# url: qemu+ssh://soqemussh@jpphype1/system?socket=/var/run/libvirt/libvirt-sock - -{%- for node_type, hosts in HYPERVISORS.items() %} -{%- for host in hosts %} +{%- for host in HYPERVISORS %} kvm-ssh-{{host}}: driver: libvirt url: qemu+ssh://soqemussh@{{host}}/system?socket=/var/run/libvirt/libvirt-sock -{%- endfor %} {%- endfor %} # Or connect to a local libvirt instance diff --git a/salt/salt/cloud/init.sls b/salt/salt/cloud/init.sls index 63c624bdb..3cbb2d991 100644 --- a/salt/salt/cloud/init.sls +++ b/salt/salt/cloud/init.sls @@ -20,7 +20,7 @@ cloud_providers: - name: /etc/salt/cloud.providers.d/libvirt.conf - source: salt://salt/cloud/cloud.providers.d/libvirt.conf.jinja - defaults: - HYPERVISORS: {{pillar.hypervisor.nodes}} + HYPERVISORS: {{pillar.hypervisor.nodes.hypervisor}} - template: jinja cloud_profiles: From 30e998edf79b01d8e317b5e6e62141b030b3ca72 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Fri, 16 Aug 2024 11:58:49 -0400 Subject: [PATCH 018/315] bridge and pools --- salt/libvirt/defaults.yaml | 6 ++--- salt/libvirt/init.sls | 49 ++++++++++++++++++++++++++++---------- salt/libvirt/ssh/users.sls | 2 ++ 3 files changed, 41 insertions(+), 16 deletions(-) diff --git a/salt/libvirt/defaults.yaml b/salt/libvirt/defaults.yaml index 1905b2e8f..b8da19cb2 100644 --- a/salt/libvirt/defaults.yaml +++ b/salt/libvirt/defaults.yaml @@ -10,9 +10,9 @@ libvirt: unix_sock_rw_perms: "0770" unix_sock_admin_perms: "0700" unix_sock_dir: "/run/libvirt" - auth_unix_ro: "none" - auth_unix_rw: "none" - auth_tcp: "none" + auth_unix_ro: "polkit" + auth_unix_rw: "polkit" + auth_tcp: "sasl" auth_tls: "none" tcp_min_ssf: 112 access_drivers: ["polkit"] diff --git a/salt/libvirt/init.sls b/salt/libvirt/init.sls index f4c9e1d5b..327bc1150 100644 --- a/salt/libvirt/init.sls +++ b/salt/libvirt/init.sls @@ -23,10 +23,11 @@ libvirt_conf_dir: libvirt_config: file.managed: - name: /opt/so/conf/libvirt/libvirtd.conf - - source: salt://libvirt/etc/libvirtd.conf.jinja - - template: jinja - - defaults: - LIBVIRTMERGED: {{ LIBVIRTMERGED }} + - source: salt://libvirt/configstockstock +# - source: salt://libvirt/etc/libvirtd.conf.jinja +# - template: jinja +# - defaults: +# LIBVIRTMERGED: {{ LIBVIRTMERGED }} # since the libvirtd service looks for the config at /etc/libvirt/libvirtd.conf, and we dont want to manage the service looking in a new location, create this symlink to the managed config config_symlink: @@ -34,6 +35,8 @@ config_symlink: - name: /etc/libvirt/libvirtd.conf - target: /opt/so/conf/libvirt/libvirtd.conf - force: True + - user: qemu + - group: qemu libvirt_service: service.running: @@ -54,20 +57,40 @@ install_qemu: pkg.installed: - name: qemu-kvm -create_host_bridge: +#create_host_bridge: +# virt.network_running: +# - name: host-bridge +# - bridge: br0 +# - forward: bridge +# - autostart: True + +set_default_bridge: virt.network_running: - - name: host-bridge + - name: default - bridge: br0 - forward: bridge - autostart: True -disable_default_bridge: - cmd.run: - - name: virsh net-destroy default && virsh net-autostart default --disable - - require: - - pkg: install_libvirt-client - - onlyif: - - virsh net-info | grep default +# set the default storage pool to point to the location we want +set_default_pool: + virt.pool_running: + - name: default + - ptype: dir + - target: /var/lib/libvirt/images/coreol9 + - permissions: + - mode: 0711 + - owner: qemu + - group: qemu + - label: "system_u:object_r:virt_image_t:s0" # this doesnt seem to set the selinux context + - autostart: True + +#disable_default_bridge: +# cmd.run: +# - name: virsh net-destroy default && virsh net-autostart default --disable +# - require: +# - pkg: install_libvirt-client +# - onlyif: +# - virsh net-info | grep default # this should only run during the first highstate after setup. it will transfer connection from mgmt to br0 down_original_mgmt_interface: diff --git a/salt/libvirt/ssh/users.sls b/salt/libvirt/ssh/users.sls index 28d9afe0d..a893b9a7d 100644 --- a/salt/libvirt/ssh/users.sls +++ b/salt/libvirt/ssh/users.sls @@ -14,6 +14,8 @@ create_soqemussh_user: {% if not GLOBALS.is_manager %} - groups: - wheel + - qemu + - libvirt {% endif %} {% if GLOBALS.is_manager %} From 67f093493030db066a377b044788ae64f0f66887 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Fri, 16 Aug 2024 12:21:41 -0400 Subject: [PATCH 019/315] set new bridge --- salt/libvirt/init.sls | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/salt/libvirt/init.sls b/salt/libvirt/init.sls index 327bc1150..689ee278e 100644 --- a/salt/libvirt/init.sls +++ b/salt/libvirt/init.sls @@ -57,16 +57,9 @@ install_qemu: pkg.installed: - name: qemu-kvm -#create_host_bridge: -# virt.network_running: -# - name: host-bridge -# - bridge: br0 -# - forward: bridge -# - autostart: True - -set_default_bridge: +create_host_bridge: virt.network_running: - - name: default + - name: host-bridge - bridge: br0 - forward: bridge - autostart: True @@ -84,13 +77,13 @@ set_default_pool: - label: "system_u:object_r:virt_image_t:s0" # this doesnt seem to set the selinux context - autostart: True -#disable_default_bridge: -# cmd.run: -# - name: virsh net-destroy default && virsh net-autostart default --disable -# - require: -# - pkg: install_libvirt-client -# - onlyif: -# - virsh net-info | grep default +disable_default_bridge: + cmd.run: + - name: virsh net-destroy default && virsh net-autostart default --disable + - require: + - pkg: install_libvirt-client + - onlyif: + - virsh net-info | grep default # this should only run during the first highstate after setup. it will transfer connection from mgmt to br0 down_original_mgmt_interface: From 7698243cafbb9688049290a9359adef3428cf456 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Fri, 16 Aug 2024 13:37:44 -0400 Subject: [PATCH 020/315] fix reactors --- salt/reactor/createEmptyPillar.sls | 10 ++-------- salt/reactor/setup.sls | 6 ++---- salt/reactor/virtReleaseHardware.sls | 8 ++------ salt/reactor/virtUpdate.sls | 6 ++---- salt/salt/master.sls | 10 +++++----- 5 files changed, 13 insertions(+), 27 deletions(-) diff --git a/salt/reactor/createEmptyPillar.sls b/salt/reactor/createEmptyPillar.sls index 95e41eef6..a182e1338 100644 --- a/salt/reactor/createEmptyPillar.sls +++ b/salt/reactor/createEmptyPillar.sls @@ -1,20 +1,14 @@ +#!py + # Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one # or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at # https://securityonion.net/license; you may not use this file except in compliance with the # Elastic License 2.0. -#!py - import logging -import salt.client -local = salt.client.LocalClient() -from subprocess import call -import yaml - import os def run(): - #logging.error("createEmptyPillar reactor: data: %s" % data) vm_name = data['kwargs']['name'] logging.error("createEmptyPillar reactor: vm_name: %s" % vm_name) pillar_root = '/opt/so/saltstack/local/pillar/minions/' diff --git a/salt/reactor/setup.sls b/salt/reactor/setup.sls index b8c5ad16c..609691223 100644 --- a/salt/reactor/setup.sls +++ b/salt/reactor/setup.sls @@ -1,13 +1,11 @@ +#!py + # Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one # or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at # https://securityonion.net/license; you may not use this file except in compliance with the # Elastic License 2.0. -#!py - import logging -import salt.client -local = salt.client.LocalClient() from subprocess import call import yaml diff --git a/salt/reactor/virtReleaseHardware.sls b/salt/reactor/virtReleaseHardware.sls index 6211fc611..ccf15a618 100644 --- a/salt/reactor/virtReleaseHardware.sls +++ b/salt/reactor/virtReleaseHardware.sls @@ -1,16 +1,12 @@ +#!py + # Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one # or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at # https://securityonion.net/license; you may not use this file except in compliance with the # Elastic License 2.0. -#!py - import logging -import salt.client -local = salt.client.LocalClient() -from subprocess import call import yaml - import os def run(): diff --git a/salt/reactor/virtUpdate.sls b/salt/reactor/virtUpdate.sls index e44bc8070..8ccee26f0 100644 --- a/salt/reactor/virtUpdate.sls +++ b/salt/reactor/virtUpdate.sls @@ -1,17 +1,15 @@ +#!py + # Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one # or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at # https://securityonion.net/license; you may not use this file except in compliance with the # Elastic License 2.0. -#!py - import logging import salt.client local = salt.client.LocalClient() -from subprocess import call import yaml - def run(): def claim_compute(hw_type): diff --git a/salt/salt/master.sls b/salt/salt/master.sls index 9558352dd..40e1d6210 100644 --- a/salt/salt/master.sls +++ b/salt/salt/master.sls @@ -57,14 +57,14 @@ salt_master_service: #- salt/cloud/*/creating': #- salt/cloud/*/requesting # - 'salt/cloud/*/deploying': -# - /srv/salt/reactor/createEmptyPillar.sls +# - /opt/so/saltstack/default/salt/reactor/createEmptyPillar.sls # - 'setup/so-minion': -# - /srv/salt/reactor/setup.sls +# - /opt/so/saltstack/default/salt/reactor/setup.sls # - 'salt/cloud/*/created': -# - /srv/salt/reactor/virtUpdate.sls +# - /opt/so/saltstack/default/salt/reactor/virtUpdate.sls # - 'salt/cloud/*/destroyed': -# - /srv/salt/reactor/virtReleaseHardware.sls -# - /srv/salt/reactor/deleteKey.sls +# - /opt/so/saltstack/default/salt/reactor/virtReleaseHardware.sls +# - /opt/so/saltstack/default/salt/reactor/deleteKey.sls {% else %} From 205560cc952211e8c2f9f37aa41cd042367f97f3 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Tue, 20 Aug 2024 08:31:46 -0400 Subject: [PATCH 021/315] updates --- salt/hypervisor/pillarExample.sls | 0 salt/reactor/setup.sls | 2 +- salt/reactor/virtReleaseHardware.sls | 33 +++++--- salt/reactor/virtUpdate.sls | 20 +++-- .../cloud/cloud.profiles.d/socloud.conf.jinja | 81 +++++++------------ .../cloud.providers.d/libvirt.conf.jinja | 15 +++- salt/salt/cloud/init.sls | 15 +++- salt/setup/virt/setHostname.sls | 9 ++- salt/setup/virt/soinstall.map.jinja | 6 +- 9 files changed, 96 insertions(+), 85 deletions(-) create mode 100644 salt/hypervisor/pillarExample.sls diff --git a/salt/hypervisor/pillarExample.sls b/salt/hypervisor/pillarExample.sls new file mode 100644 index 000000000..e69de29bb diff --git a/salt/reactor/setup.sls b/salt/reactor/setup.sls index 609691223..3e98b174e 100644 --- a/salt/reactor/setup.sls +++ b/salt/reactor/setup.sls @@ -11,8 +11,8 @@ import yaml def run(): minionid = data['id'] - hv_name = 'jppvirt' DATA = data['data'] + hv_name = DATA['HYPERVISOR_HOST'] logging.error("setup reactor: %s " % DATA) vm_out_data = { diff --git a/salt/reactor/virtReleaseHardware.sls b/salt/reactor/virtReleaseHardware.sls index ccf15a618..8e95e080f 100644 --- a/salt/reactor/virtReleaseHardware.sls +++ b/salt/reactor/virtReleaseHardware.sls @@ -1,32 +1,43 @@ #!py # Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one -# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at # https://securityonion.net/license; you may not use this file except in compliance with the # Elastic License 2.0. import logging import yaml import os +import glob def run(): - def release_compute(hw_type): + def release_compute(): compute = hv_data['hypervisor']['hardware'][hw_type] compute.update({'free': compute.get('free') + vm_data.get(hw_type)}) logging.error("virtReboot reactor: claiming %s compute: %s " % (hw_type,compute)) - def release_pci(hw_type): + def release_pci(): free_hw = hv_data['hypervisor']['hardware'][hw_type]['free'] - for hw in vm_data[hw_type]: - f_hw = {hw: hv_data['hypervisor']['hardware'][hw_type]['claimed'].pop(hw)} - free_hw.update(f_hw) - logging.error("virtReleaseHardware reactor: released %s: %s" % (hw_type, f_hw)) - + # this could be 0 if nothing is assigned + if vm_data[hw_type] != 0: + for hw in vm_data[hw_type]: + f_hw = {hw: hv_data['hypervisor']['hardware'][hw_type]['claimed'].pop(hw)} + free_hw.update(f_hw) + logging.error("virtReleaseHardware reactor: released %s: %s" % (hw_type, f_hw)) + def get_hypervisor(): + base_dir = '/opt/so/saltstack/local/pillar/hypervisor' + pattern = os.path.join(base_dir, '**', vm_name + '.sls') + files = glob.glob(pattern, recursive=True) + logging.error("virtReleaseHardware reactor: files: %s " % files) + if files: + return files[0].split('/')[7] vm_name = data['name'] - hv_name = 'jppvirt' + # since the vm has been destroyed, we can't get the hypervisor_host grain + hv_name = get_hypervisor() + logging.error("virtReleaseHardware reactor: hv_name: %s " % hv_name) with open("/opt/so/saltstack/local/pillar/hypervisor/" + hv_name + "/" + vm_name + ".sls") as f: try: @@ -45,10 +56,10 @@ def run(): logging.error(exc) for hw_type in ['disks', 'copper', 'sfp']: - release_pci(hw_type) + release_pci() for hw_type in ['cpu', 'memory']: - release_compute(hw_type) + release_compute() # update the free hardware for the hypervisor with open("/opt/so/saltstack/local/pillar/hypervisor/" + hv_name + "/" + hv_name + ".sls", 'w') as f: diff --git a/salt/reactor/virtUpdate.sls b/salt/reactor/virtUpdate.sls index 8ccee26f0..8fbd5b2d6 100644 --- a/salt/reactor/virtUpdate.sls +++ b/salt/reactor/virtUpdate.sls @@ -23,10 +23,13 @@ def run(): # if a list of devices was defined if type(vm_data[hw_type]) == list: for hw in vm_data[hw_type]: - c_hw = {hw: hv_data['hypervisor']['hardware'][hw_type]['free'].pop(hw)} - claimed_hw.update(c_hw) - host_devices.append(c_hw[hw]) - #hv_data['hypervisor']['hardware'][hw_type].update({'claimed': claimed_hw}) + try: + c_hw = {hw: hv_data['hypervisor']['hardware'][hw_type]['free'].pop(hw)} + claimed_hw.update(c_hw) + host_devices.append(c_hw[hw]) + except KeyError: + logging.error("virtUpdate reactor: could not claim %s with key %s " % (hw_type,hw)) + return {'key1': 'val1'} # if a number of devices was defined else: n = vm_data[hw_type] @@ -44,7 +47,8 @@ def run(): logging.error("virtUpdate reactor: claimed_hw: %s " % claimed_hw) vm_name = data['name'] - hv_name = 'jppvirt' + hv_name = local.cmd(vm_name, 'grains.get', ['hypervisor_host']) + host_devices = [] with open("/opt/so/saltstack/local/pillar/hypervisor/" + hv_name + "/" + vm_name + ".sls") as f: @@ -63,7 +67,7 @@ def run(): except yaml.YAMLError as exc: logging.error(exc) - local.cmd('jppvirt', 'virt.stop', ['name=' + vm_name]) + local.cmd(hv_name, 'virt.stop', ['name=' + vm_name]) for hw_type in ['disks', 'copper', 'sfp']: claim_pci(hw_type) @@ -85,9 +89,9 @@ def run(): yaml.dump(vm_data, f, default_flow_style=False) mem = vm_data['memory'] * 1024 - r = local.cmd('jppvirt', 'virt.update', ['name=' + vm_name, 'mem=' + str(mem), 'cpu=' + str(vm_data['cpu']), 'host_devices=' + str(host_devices)]) + r = local.cmd(hv_name, 'virt.update', ['name=' + vm_name, 'mem=' + str(mem), 'cpu=' + str(vm_data['cpu']), 'host_devices=' + str(host_devices)]) logging.error("virtUpdate reactor: virt.update: %s" % r) - local.cmd('jppvirt', 'virt.start', ['name=' + vm_name]) + local.cmd(hv_name, 'virt.start', ['name=' + vm_name]) return {} diff --git a/salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja b/salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja index 6bc914fd1..21d050d88 100644 --- a/salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja +++ b/salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja @@ -1,59 +1,14 @@ -searchnode: - provider: local-kvm - base_domain: jppol9vm - ip_source: qemu-agent - ssh_username: jpatterson - private_key: /home/jpatterson/.ssh/id_rsa - sudo: True - # /tmp is mounted noexec.. do workaround - deploy_command: sh /tmp/.saltcloud-*/deploy.sh - script_args: -F -x python3 stable 3006.1 - # grains to add to the minion - #grains: - # clones-are-awesome: true - # override minion settings - minion: - master: jppvirt - master_port: 4506 - startup_states: sls - sls_list: - - setHostname +{#- Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one + or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at + https://securityonion.net/license; you may not use this file except in compliance with the + Elastic License 2.0. #} -sensor: - provider: local-kvm - base_domain: jppol9vm - ip_source: qemu-agent - ssh_username: jpatterson - private_key: /home/jpatterson/.ssh/id_rsa - sudo: True - #preflight_cmds: - # - echo "do something" - # - hostname - # /tmp is mounted noexec.. do workaround - deploy_command: sh /tmp/.saltcloud-*/deploy.sh - script_args: -F -x python3 stable 3006.1 - # the destination directory will be created if it doesn't exist - #file_map: - # /srv/salt/filemap.txt: /remote/path/to/use/custom/filemap.txt - #inline_script: - # - echo "SLEEPING" - # - hostname - # grains to add to the minion - #grains: - # clones-are-awesome: true - # override minion settings - minion: - master: jppvirt - master_port: 4506 - startup_states: sls - sls_list: - - setHostname - -{%- for host in HYPERVISORS %} +{%- for role, hosts in HYPERVISORS.items() %} +{%- for host in hosts.keys() -%} core-{{host}}: provider: kvm-ssh-{{host}} - base_domain: jppol9vm + base_domain: coreol9 ip_source: qemu-agent ssh_username: soqemussh private_key: /home/soqemussh/.ssh/id_ed25519 @@ -61,10 +16,28 @@ core-{{host}}: deploy_command: sh /tmp/.saltcloud-*/deploy.sh script_args: -F -x python3 stable 3006.1 minion: - master: jpp90man + master: {{ grains.host }} master_port: 4506 startup_states: sls sls_list: - - setHostname + - setup.virt.setHostname + use_superseded: + - module.run + features: + x509_v2: true + log_level: info + log_level_logfile: info + log_file: /opt/so/log/salt/minion + grains: + hypervisor_host: {{host ~ "_" ~ role}} + #preflight_cmds: + # - echo "preflight_cmds" + # the destination directory will be created if it doesn't exist + file_map: + /opt/so/saltstack/default/salt/repo/client/files/oracle/keys/securityonion.pub: /tmp/securityonion.pub + inline_script: + - "rpm --import /tmp/securityonion.pub" + # grains to add to the minion +{%- endfor %} {%- endfor %} diff --git a/salt/salt/cloud/cloud.providers.d/libvirt.conf.jinja b/salt/salt/cloud/cloud.providers.d/libvirt.conf.jinja index a8b72faf2..c6ba0b96a 100644 --- a/salt/salt/cloud/cloud.providers.d/libvirt.conf.jinja +++ b/salt/salt/cloud/cloud.providers.d/libvirt.conf.jinja @@ -1,15 +1,22 @@ -# Set up a provider with qemu+ssh protocol -{%- for host in HYPERVISORS %} +{# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one + or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at + https://securityonion.net/license; you may not use this file except in compliance with the + Elastic License 2.0. #} + +{#- provider with qemu+ssh protocol #} +{%- for role, hosts in HYPERVISORS.items() %} +{%- for host in hosts.keys() %} kvm-ssh-{{host}}: driver: libvirt url: qemu+ssh://soqemussh@{{host}}/system?socket=/var/run/libvirt/libvirt-sock +{%- endfor %} {%- endfor %} -# Or connect to a local libvirt instance +{#- local libvirt instance #} #local-kvm: # driver: libvirt # url: qemu:///system - # work around flag for XML validation errors while cloning +{#- work around flag for XML validation errors while cloning #} # validate_xml: no diff --git a/salt/salt/cloud/init.sls b/salt/salt/cloud/init.sls index 3cbb2d991..5e160581b 100644 --- a/salt/salt/cloud/init.sls +++ b/salt/salt/cloud/init.sls @@ -6,6 +6,7 @@ {% from 'allowed_states.map.jinja' import allowed_states %} {% if sls in allowed_states %} {% from 'salt/map.jinja' import SALTVERSION %} +{% set HYPERVISORS = salt['pillar.get']('hypervisor:nodes', {} ) %} include: - libvirt.packages @@ -20,7 +21,7 @@ cloud_providers: - name: /etc/salt/cloud.providers.d/libvirt.conf - source: salt://salt/cloud/cloud.providers.d/libvirt.conf.jinja - defaults: - HYPERVISORS: {{pillar.hypervisor.nodes.hypervisor}} + HYPERVISORS: {{HYPERVISORS}} - template: jinja cloud_profiles: @@ -28,9 +29,19 @@ cloud_profiles: - name: /etc/salt/cloud.profiles.d/socloud.conf - source: salt://salt/cloud/cloud.profiles.d/socloud.conf.jinja - defaults: - HYPERVISORS: {{pillar.hypervisor.nodes.hypervisor}} + HYPERVISORS: {{HYPERVISORS}} - template: jinja +{% for role, hosts in HYPERVISORS.items() %} +{% for host in hosts.keys() %} + +hypervisor_{{host}}_{{role}}_pillar_dir: + file.directory: + - name: /opt/so/saltstack/local/pillar/hypervisor/{{host}}_{{role}} + +{% endfor %} +{% endfor %} + {% else %} {{sls}}_state_not_allowed: diff --git a/salt/setup/virt/setHostname.sls b/salt/setup/virt/setHostname.sls index e77ebd5a7..5654b859f 100644 --- a/salt/setup/virt/setHostname.sls +++ b/salt/setup/virt/setHostname.sls @@ -3,7 +3,7 @@ # https://securityonion.net/license; you may not use this file except in compliance with the # Elastic License 2.0. -{% from 'soinstall.map.jinja' import DATA %} +{% from 'setup/virt/soinstall.map.jinja' import DATA %} setHostname_{{grains.id.split("_") | first}}: network.system: @@ -16,6 +16,7 @@ create_pillar: event.send: - name: setup/so-minion - data: + HYPERVISOR_HOST: {{ grains.hypervisor_host }} MAINIP: {{ DATA.MAINIP }} MNIC: {{ DATA.MNIC }} NODE_DESCRIPTION: '{{ DATA.NODE_DESCRIPTION }}' @@ -35,6 +36,10 @@ create_pillar: COPPER: {{ DATA.COPPER }} SFP: {{ DATA.SFP }} +set_role_grain: + grains.present: + - name: role + - value: so-{{ grains.id.split("_") | last }} # set event for firewall rules - so-firewall-minion @@ -47,7 +52,7 @@ clean_sls_list: clean_setHostname: file.line: - name: /etc/salt/minion - - match: '- setHostname' + - match: '- setup.virt.setHostname' - mode: delete - onchanges: - file: clean_sls_list diff --git a/salt/setup/virt/soinstall.map.jinja b/salt/setup/virt/soinstall.map.jinja index 1c82fe3dd..e2649aab1 100644 --- a/salt/setup/virt/soinstall.map.jinja +++ b/salt/setup/virt/soinstall.map.jinja @@ -1,10 +1,10 @@ {# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one - or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at + or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at https://securityonion.net/license; you may not use this file except in compliance with the Elastic License 2.0. #} {% set nodetype = grains.id.split("_") | last %} -{% import_yaml nodetype ~ '.yaml' as DATA %} +{% import_yaml 'setup/virt/' ~ nodetype ~ '.yaml' as DATA %} {% set total_mem = grains.mem_total %} {% do DATA.update({'MAINIP': grains.ip_interfaces.get(DATA.MNIC)[0]}) %} @@ -12,7 +12,7 @@ {% do DATA.update({'CPUCORES': grains.num_cpus}) %} -{% if nodetype = "searchnode" %} +{% if nodetype == "searchnode" %} {% do DATA.update({'LSHOSTNAME': grains.host}) %} From 64bf7eb363268ed0eddcade2c79afac90700da5d Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Tue, 20 Aug 2024 15:26:05 -0400 Subject: [PATCH 022/315] hyper --- salt/repo/client/oracle.sls | 2 + .../cloud/cloud.profiles.d/socloud.conf.jinja | 9 ++-- salt/setup/virt/setHostname.sls | 50 ++++++++++--------- 3 files changed, 33 insertions(+), 28 deletions(-) diff --git a/salt/repo/client/oracle.sls b/salt/repo/client/oracle.sls index 8b55964f4..89d41beae 100644 --- a/salt/repo/client/oracle.sls +++ b/salt/repo/client/oracle.sls @@ -53,10 +53,12 @@ so_repo: - baseurl: file:///nsm/repo/ {% else %} - baseurl: https://{{ GLOBALS.repo_host }}/repo + - sslverify: 0 {% endif %} - enabled: 1 - gpgcheck: 1 + {% endif %} # TODO: Add a pillar entry for custom repos diff --git a/salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja b/salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja index 21d050d88..c8db663af 100644 --- a/salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja +++ b/salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja @@ -21,6 +21,7 @@ core-{{host}}: startup_states: sls sls_list: - setup.virt.setHostname + - salt.minion use_superseded: - module.run features: @@ -33,10 +34,10 @@ core-{{host}}: #preflight_cmds: # - echo "preflight_cmds" # the destination directory will be created if it doesn't exist - file_map: - /opt/so/saltstack/default/salt/repo/client/files/oracle/keys/securityonion.pub: /tmp/securityonion.pub - inline_script: - - "rpm --import /tmp/securityonion.pub" + #file_map: + # /opt/so/saltstack/default/salt/repo/client/files/oracle/keys/securityonion.pub: /tmp/securityonion.pub + #inline_script: + # - "rpm --import /tmp/securityonion.pub" # grains to add to the minion {%- endfor %} diff --git a/salt/setup/virt/setHostname.sls b/salt/setup/virt/setHostname.sls index 5654b859f..3dd20098f 100644 --- a/salt/setup/virt/setHostname.sls +++ b/salt/setup/virt/setHostname.sls @@ -6,36 +6,14 @@ {% from 'setup/virt/soinstall.map.jinja' import DATA %} setHostname_{{grains.id.split("_") | first}}: + cmd.run: + - name: hostnamectl set-hostname --static {{grains.id.split("_") | first}} network.system: - name: {{grains.id.split("_") | first}} - enabled: True - hostname: {{grains.id.split("_") | first}} - apply_hostname: True -create_pillar: - event.send: - - name: setup/so-minion - - data: - HYPERVISOR_HOST: {{ grains.hypervisor_host }} - MAINIP: {{ DATA.MAINIP }} - MNIC: {{ DATA.MNIC }} - NODE_DESCRIPTION: '{{ DATA.NODE_DESCRIPTION }}' - ES_HEAP_SIZE: {{ DATA.ES_HEAP_SIZE }} - PATCHSCHEDULENAME: {{ DATA.PATCHSCHEDULENAME }} - INTERFACE: {{ DATA.INTERFACE }} - NODETYPE: {{ DATA.NODETYPE }} - CORECOUNT: {{ DATA.CORECOUNT }} - LSHOSTNAME: {{ DATA.LSHOSTNAME }} - LSHEAP: {{ DATA.LSHEAP }} - CPUCORES: {{ DATA.CPUCORES }} - IDH_MGTRESTRICT: {{ DATA.IDH_MGTRESTRICT }} - IDH_SERVICES: {{ DATA.IDH_SERVICES }} - CPU: {{ DATA.CPU }} - MEMORY: {{ DATA.MEMORY }} - DISKS: {{ DATA.DISKS }} - COPPER: {{ DATA.COPPER }} - SFP: {{ DATA.SFP }} - set_role_grain: grains.present: - name: role @@ -64,3 +42,27 @@ set_highstate: - repl: 'startup_states: highstate' - onchanges: - file: clean_setHostname + +create_pillar: + event.send: + - name: setup/so-minion + - data: + HYPERVISOR_HOST: {{ grains.hypervisor_host }} + MAINIP: {{ DATA.MAINIP }} + MNIC: {{ DATA.MNIC }} + NODE_DESCRIPTION: '{{ DATA.NODE_DESCRIPTION }}' + ES_HEAP_SIZE: {{ DATA.ES_HEAP_SIZE }} + PATCHSCHEDULENAME: {{ DATA.PATCHSCHEDULENAME }} + INTERFACE: {{ DATA.INTERFACE }} + NODETYPE: {{ DATA.NODETYPE }} + CORECOUNT: {{ DATA.CORECOUNT }} + LSHOSTNAME: {{ DATA.LSHOSTNAME }} + LSHEAP: {{ DATA.LSHEAP }} + CPUCORES: {{ DATA.CPUCORES }} + IDH_MGTRESTRICT: {{ DATA.IDH_MGTRESTRICT }} + IDH_SERVICES: {{ DATA.IDH_SERVICES }} + CPU: {{ DATA.CPU }} + MEMORY: {{ DATA.MEMORY }} + DISKS: {{ DATA.DISKS }} + COPPER: {{ DATA.COPPER }} + SFP: {{ DATA.SFP }} From d110503639b4ac01ce8e7a6d1d1e53be8e599e6b Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Tue, 20 Aug 2024 15:27:19 -0400 Subject: [PATCH 023/315] example pilalr --- salt/hypervisor/pillarExample.sls | 48 +++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/salt/hypervisor/pillarExample.sls b/salt/hypervisor/pillarExample.sls index e69de29bb..4bc11434b 100644 --- a/salt/hypervisor/pillarExample.sls +++ b/salt/hypervisor/pillarExample.sls @@ -0,0 +1,48 @@ +hypervisor: + hardware: + cpu: + total: 128 + free: 128 + memory: + total: 128 + free: 128 + disks: + free: + 3: pci_0000_c7_00_0 + 4: pci_0000_c8_00_0 + claimed: + 1: pci_0000_c5_00_0 + 2: pci_0000_c6_00_0 + copper: + free: + 1: pci_0000_c4_00_0 + 2: pci_0000_c4_00_1 + 3: pci_0000_c4_00_2 + 4: pci_0000_c4_00_3 + claimed: {} + sfp: + free: + 5: pci_0000_41_00_0 + 6: pci_0000_41_00_1 + claimed: {} + + +hypervisor: + hardware: + cpu: + total: 16 + free: 16 + memory: + total: 16 + free: 16 + disks: + free: {} + claimed: {} + copper: + free: + 2: pci_0000_00_13_0 + claimed: + 1: pci_0000_00_12_0 + sfp: + free: {} + claimed: {} From 21c383532284a9d0664d1a8637b30349d98d04c3 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Tue, 27 Aug 2024 09:25:40 -0400 Subject: [PATCH 024/315] salt3006.9, redo reactors, use virt.shutdown --- salt/reactor/setHostname.sls | 22 +++++++ salt/reactor/setSalt.sls | 22 +++++++ salt/reactor/sominion.sls | 21 +++++++ .../reactor/{setup.sls => sominion_setup.sls} | 8 +-- salt/reactor/virtUpdate.sls | 30 +++++++--- .../cloud/cloud.profiles.d/socloud.conf.jinja | 13 +++-- salt/salt/master.defaults.yaml | 2 +- salt/salt/master.sls | 8 ++- salt/salt/minion.defaults.yaml | 2 +- salt/setup/virt/sensor.yaml | 11 ++-- salt/setup/virt/setHostname.sls | 57 +------------------ salt/setup/virt/setSalt.sls | 16 ++++++ salt/setup/virt/sominion.sls | 30 ++++++++++ 13 files changed, 159 insertions(+), 83 deletions(-) create mode 100644 salt/reactor/setHostname.sls create mode 100644 salt/reactor/setSalt.sls create mode 100644 salt/reactor/sominion.sls rename salt/reactor/{setup.sls => sominion_setup.sls} (82%) create mode 100644 salt/setup/virt/setSalt.sls create mode 100644 salt/setup/virt/sominion.sls diff --git a/salt/reactor/setHostname.sls b/salt/reactor/setHostname.sls new file mode 100644 index 000000000..3733a71bb --- /dev/null +++ b/salt/reactor/setHostname.sls @@ -0,0 +1,22 @@ +#!py + +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +import logging +import salt.client +local = salt.client.LocalClient() + +def run(): + + vm_name = data['name'] + logging.error("setHostname reactor: start for: %s " % vm_name) + + r = local.cmd(vm_name, 'state.apply', ['setup.virt.setHostname']) + + logging.error("setHostname reactor: return for %s: %s " % (vm_name,r)) + logging.error("setHostname reactor: end for: %s " % vm_name) + + return {} diff --git a/salt/reactor/setSalt.sls b/salt/reactor/setSalt.sls new file mode 100644 index 000000000..5d8b33a4a --- /dev/null +++ b/salt/reactor/setSalt.sls @@ -0,0 +1,22 @@ +#!py + +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +import logging +import salt.client +local = salt.client.LocalClient() + +def run(): + + vm_name = data['name'] + logging.error("setSalt reactor: start for: %s " % vm_name) + + r = local.cmd(vm_name, 'state.apply', ['setup.virt.setSalt']) + + logging.error("setSalt reactor: return for: %s: %s " % (vm_name,r)) + logging.error("setSalt reactor: end for: %s " % vm_name) + + return {} diff --git a/salt/reactor/sominion.sls b/salt/reactor/sominion.sls new file mode 100644 index 000000000..24b448f2e --- /dev/null +++ b/salt/reactor/sominion.sls @@ -0,0 +1,21 @@ +#!py + +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +import logging +import salt.client +local = salt.client.LocalClient() + +def run(): + + vm_name = data['name'] + logging.error("sominion reactor: start for: %s " % vm_name) + + r = local.cmd(vm_name, 'state.apply', ['setup.virt.sominion']) + + logging.error("sominion reactor: end for: %s " % vm_name) + + return {} diff --git a/salt/reactor/setup.sls b/salt/reactor/sominion_setup.sls similarity index 82% rename from salt/reactor/setup.sls rename to salt/reactor/sominion_setup.sls index 3e98b174e..91a4a6cb9 100644 --- a/salt/reactor/setup.sls +++ b/salt/reactor/sominion_setup.sls @@ -1,7 +1,7 @@ #!py # Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one -# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at # https://securityonion.net/license; you may not use this file except in compliance with the # Elastic License 2.0. @@ -13,7 +13,7 @@ def run(): minionid = data['id'] DATA = data['data'] hv_name = DATA['HYPERVISOR_HOST'] - logging.error("setup reactor: %s " % DATA) + logging.error("sominion_setup reactor: %s " % DATA) vm_out_data = { 'cpu': DATA['CPU'], @@ -23,13 +23,13 @@ def run(): 'sfp': DATA['SFP'] } - logging.error("setup reactor: vm_out_data: %s " % vm_out_data) + logging.error("sominion_setup reactor: vm_out_data: %s " % vm_out_data) with open("/opt/so/saltstack/local/pillar/hypervisor/" + hv_name + "/" + minionid + ".sls", 'w') as f: yaml.dump(vm_out_data, f, default_flow_style=False) rc = call("NODETYPE=" + DATA['NODETYPE'] + " /usr/sbin/so-minion -o=addVirt -m=" + minionid + " -n=" + DATA['MNIC'] + " -i=" + DATA['MAINIP'] + " -a=" + DATA['INTERFACE'] + " -c=" + str(DATA['CORECOUNT']) + " -d='" + DATA['NODE_DESCRIPTION'] + "'", shell=True) - logging.error('setup_reactor: rc: %s' % rc) + logging.error('sominion_setup reactor: rc: %s' % rc) return {} diff --git a/salt/reactor/virtUpdate.sls b/salt/reactor/virtUpdate.sls index 8fbd5b2d6..d4b56fdf6 100644 --- a/salt/reactor/virtUpdate.sls +++ b/salt/reactor/virtUpdate.sls @@ -1,7 +1,7 @@ #!py # Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one -# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at # https://securityonion.net/license; you may not use this file except in compliance with the # Elastic License 2.0. @@ -9,6 +9,7 @@ import logging import salt.client local = salt.client.LocalClient() import yaml +from time import sleep def run(): @@ -17,7 +18,6 @@ def run(): compute.update({'free': compute.get('free') - vm_data.get(hw_type)}) logging.error("virtUpdate reactor: claiming %s compute: %s " % (hw_type,compute)) - def claim_pci(hw_type): claimed_hw = hv_data['hypervisor']['hardware'][hw_type]['claimed'] # if a list of devices was defined @@ -46,8 +46,10 @@ def run(): host_devices.append(hw[1]) logging.error("virtUpdate reactor: claimed_hw: %s " % claimed_hw) - vm_name = data['name'] - hv_name = local.cmd(vm_name, 'grains.get', ['hypervisor_host']) + vm_name = data['id'] + logging.error("virtUpdate reactor: vm_name: %s " % vm_name) + hv_name = local.cmd(vm_name, 'grains.get', ['hypervisor_host']).get(vm_name) + logging.error("virtUpdate reactor: hv_name: %s " % hv_name) host_devices = [] @@ -67,7 +69,20 @@ def run(): except yaml.YAMLError as exc: logging.error(exc) - local.cmd(hv_name, 'virt.stop', ['name=' + vm_name]) + r = local.cmd(hv_name, 'virt.shutdown', ['vm_=' + vm_name]) + logging.error("virtUpdate reactor: virt.shutdown: %s return: %s " % (vm_name,r)) + + c = 0 + while True: + if c == 60: + logging.error("virtUpdate reactor: vm_name: %s failed to shutdown in time " % vm_name) + return {} + r = local.cmd(hv_name, 'virt.list_inactive_vms') + logging.error("virtUpdate reactor: virt.list_inactive_vms: %s " % r.get(hv_name)) + if vm_name in r.get(hv_name): + break + c += 1 + sleep(1) for hw_type in ['disks', 'copper', 'sfp']: claim_pci(hw_type) @@ -90,8 +105,9 @@ def run(): mem = vm_data['memory'] * 1024 r = local.cmd(hv_name, 'virt.update', ['name=' + vm_name, 'mem=' + str(mem), 'cpu=' + str(vm_data['cpu']), 'host_devices=' + str(host_devices)]) - logging.error("virtUpdate reactor: virt.update: %s" % r) + logging.error("virtUpdate reactor: virt.update: vm_name: %s return: %s" % (vm_name,r)) - local.cmd(hv_name, 'virt.start', ['name=' + vm_name]) + r = local.cmd(hv_name, 'virt.start', ['name=' + vm_name]) + logging.error("virtUpdate reactor: virt.start: vm_name: %s return: %s" % (vm_name,r)) return {} diff --git a/salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja b/salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja index c8db663af..3e797890a 100644 --- a/salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja +++ b/salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja @@ -1,5 +1,5 @@ {#- Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one - or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at + or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at https://securityonion.net/license; you may not use this file except in compliance with the Elastic License 2.0. #} @@ -14,14 +14,14 @@ core-{{host}}: private_key: /home/soqemussh/.ssh/id_ed25519 sudo: True deploy_command: sh /tmp/.saltcloud-*/deploy.sh - script_args: -F -x python3 stable 3006.1 + script_args: -F -x python3 stable 3006.9 minion: master: {{ grains.host }} master_port: 4506 - startup_states: sls - sls_list: - - setup.virt.setHostname - - salt.minion + #startup_states: sls + #sls_list: + # - setup.virt.setSalt + # - setup.virt.setHostname use_superseded: - module.run features: @@ -37,6 +37,7 @@ core-{{host}}: #file_map: # /opt/so/saltstack/default/salt/repo/client/files/oracle/keys/securityonion.pub: /tmp/securityonion.pub #inline_script: + # - "systemctl start salt-minion" # - "rpm --import /tmp/securityonion.pub" # grains to add to the minion diff --git a/salt/salt/master.defaults.yaml b/salt/salt/master.defaults.yaml index fc7a6ae16..e133dbd0b 100644 --- a/salt/salt/master.defaults.yaml +++ b/salt/salt/master.defaults.yaml @@ -1,4 +1,4 @@ # version cannot be used elsewhere in this pillar as soup is grepping for it to determine if Salt needs to be patched salt: master: - version: 3006.1 + version: 3006.9 diff --git a/salt/salt/master.sls b/salt/salt/master.sls index 40e1d6210..fc572be96 100644 --- a/salt/salt/master.sls +++ b/salt/salt/master.sls @@ -58,14 +58,18 @@ salt_master_service: #- salt/cloud/*/requesting # - 'salt/cloud/*/deploying': # - /opt/so/saltstack/default/salt/reactor/createEmptyPillar.sls -# - 'setup/so-minion': -# - /opt/so/saltstack/default/salt/reactor/setup.sls # - 'salt/cloud/*/created': +# - /opt/so/saltstack/default/salt/reactor/setSalt.sls +# - /opt/so/saltstack/default/salt/reactor/setHostname.sls +# - /opt/so/saltstack/default/salt/reactor/sominion.sls +# - 'setup/so-minion': +# - /opt/so/saltstack/default/salt/reactor/sominion_setup.sls # - /opt/so/saltstack/default/salt/reactor/virtUpdate.sls # - 'salt/cloud/*/destroyed': # - /opt/so/saltstack/default/salt/reactor/virtReleaseHardware.sls # - /opt/so/saltstack/default/salt/reactor/deleteKey.sls + {% else %} {{sls}}_state_not_allowed: diff --git a/salt/salt/minion.defaults.yaml b/salt/salt/minion.defaults.yaml index 0aa315264..be405b9e8 100644 --- a/salt/salt/minion.defaults.yaml +++ b/salt/salt/minion.defaults.yaml @@ -1,6 +1,6 @@ # version cannot be used elsewhere in this pillar as soup is grepping for it to determine if Salt needs to be patched salt: minion: - version: 3006.1 + version: 3006.9 check_threshold: 3600 # in seconds, threshold used for so-salt-minion-check. any value less than 600 seconds may cause a lot of salt-minion restarts since the job to touch the file occurs every 5-8 minutes by default service_start_delay: 30 # in seconds. diff --git a/salt/setup/virt/sensor.yaml b/salt/setup/virt/sensor.yaml index e4946bc1e..e90bece35 100644 --- a/salt/setup/virt/sensor.yaml +++ b/salt/setup/virt/sensor.yaml @@ -11,9 +11,8 @@ LSHEAP: CPUCORES: 4 IDH_MGTRESTRICT: IDH_SERVICES: -CPU: 16 -MEMORY: 16 -DISKS: 1 -COPPER: - - 1 -SFP: 2 +CPU: 8 +MEMORY: 8 +DISKS: 0 +COPPER: 0 +SFP: 0 diff --git a/salt/setup/virt/setHostname.sls b/salt/setup/virt/setHostname.sls index 3dd20098f..648559f0c 100644 --- a/salt/setup/virt/setHostname.sls +++ b/salt/setup/virt/setHostname.sls @@ -1,10 +1,8 @@ # Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one -# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at # https://securityonion.net/license; you may not use this file except in compliance with the # Elastic License 2.0. -{% from 'setup/virt/soinstall.map.jinja' import DATA %} - setHostname_{{grains.id.split("_") | first}}: cmd.run: - name: hostnamectl set-hostname --static {{grains.id.split("_") | first}} @@ -13,56 +11,3 @@ setHostname_{{grains.id.split("_") | first}}: - enabled: True - hostname: {{grains.id.split("_") | first}} - apply_hostname: True - -set_role_grain: - grains.present: - - name: role - - value: so-{{ grains.id.split("_") | last }} - -# set event for firewall rules - so-firewall-minion - -clean_sls_list: - file.line: - - name: /etc/salt/minion - - match: 'sls_list:' - - mode: delete - -clean_setHostname: - file.line: - - name: /etc/salt/minion - - match: '- setup.virt.setHostname' - - mode: delete - - onchanges: - - file: clean_sls_list - -set_highstate: - file.replace: - - name: /etc/salt/minion - - pattern: 'startup_states: sls' - - repl: 'startup_states: highstate' - - onchanges: - - file: clean_setHostname - -create_pillar: - event.send: - - name: setup/so-minion - - data: - HYPERVISOR_HOST: {{ grains.hypervisor_host }} - MAINIP: {{ DATA.MAINIP }} - MNIC: {{ DATA.MNIC }} - NODE_DESCRIPTION: '{{ DATA.NODE_DESCRIPTION }}' - ES_HEAP_SIZE: {{ DATA.ES_HEAP_SIZE }} - PATCHSCHEDULENAME: {{ DATA.PATCHSCHEDULENAME }} - INTERFACE: {{ DATA.INTERFACE }} - NODETYPE: {{ DATA.NODETYPE }} - CORECOUNT: {{ DATA.CORECOUNT }} - LSHOSTNAME: {{ DATA.LSHOSTNAME }} - LSHEAP: {{ DATA.LSHEAP }} - CPUCORES: {{ DATA.CPUCORES }} - IDH_MGTRESTRICT: {{ DATA.IDH_MGTRESTRICT }} - IDH_SERVICES: {{ DATA.IDH_SERVICES }} - CPU: {{ DATA.CPU }} - MEMORY: {{ DATA.MEMORY }} - DISKS: {{ DATA.DISKS }} - COPPER: {{ DATA.COPPER }} - SFP: {{ DATA.SFP }} diff --git a/salt/setup/virt/setSalt.sls b/salt/setup/virt/setSalt.sls new file mode 100644 index 000000000..aa6618b25 --- /dev/null +++ b/salt/setup/virt/setSalt.sls @@ -0,0 +1,16 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +set_role_grain: + grains.present: + - name: role + - value: so-{{ grains.id.split("_") | last }} + +# set event for firewall rules - so-firewall-minion + +set_highstate: + file.append: + - name: /etc/salt/minion + - text: 'startup_states: highstate' diff --git a/salt/setup/virt/sominion.sls b/salt/setup/virt/sominion.sls new file mode 100644 index 000000000..328f50311 --- /dev/null +++ b/salt/setup/virt/sominion.sls @@ -0,0 +1,30 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'setup/virt/soinstall.map.jinja' import DATA %} + +create_pillar: + event.send: + - name: setup/so-minion + - data: + HYPERVISOR_HOST: {{ grains.hypervisor_host }} + MAINIP: {{ DATA.MAINIP }} + MNIC: {{ DATA.MNIC }} + NODE_DESCRIPTION: '{{ DATA.NODE_DESCRIPTION }}' + ES_HEAP_SIZE: {{ DATA.ES_HEAP_SIZE }} + PATCHSCHEDULENAME: {{ DATA.PATCHSCHEDULENAME }} + INTERFACE: {{ DATA.INTERFACE }} + NODETYPE: {{ DATA.NODETYPE }} + CORECOUNT: {{ DATA.CORECOUNT }} + LSHOSTNAME: {{ DATA.LSHOSTNAME }} + LSHEAP: {{ DATA.LSHEAP }} + CPUCORES: {{ DATA.CPUCORES }} + IDH_MGTRESTRICT: {{ DATA.IDH_MGTRESTRICT }} + IDH_SERVICES: {{ DATA.IDH_SERVICES }} + CPU: {{ DATA.CPU }} + MEMORY: {{ DATA.MEMORY }} + DISKS: {{ DATA.DISKS }} + COPPER: {{ DATA.COPPER }} + SFP: {{ DATA.SFP }} From a425a7fda2034af268b8fc2819d1fdfc6518e2da Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Tue, 27 Aug 2024 09:37:23 -0400 Subject: [PATCH 025/315] update docker modules for 3006.9 --- .../docker/docker-5.0.2-py2.py3-none-any.whl | Bin 145967 -> 0 bytes .../docker/docker-7.1.0-py3-none-any.whl | Bin 0 -> 147774 bytes ...none-any.whl => idna-3.8-py3-none-any.whl} | Bin 66836 -> 66894 bytes .../websocket_client-1.8.0-py3-none-any.whl | Bin 58826 -> 0 bytes 4 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 salt/salt/module_packages/docker/docker-5.0.2-py2.py3-none-any.whl create mode 100644 salt/salt/module_packages/docker/docker-7.1.0-py3-none-any.whl rename salt/salt/module_packages/docker/{idna-3.7-py3-none-any.whl => idna-3.8-py3-none-any.whl} (85%) delete mode 100644 salt/salt/module_packages/docker/websocket_client-1.8.0-py3-none-any.whl diff --git a/salt/salt/module_packages/docker/docker-5.0.2-py2.py3-none-any.whl b/salt/salt/module_packages/docker/docker-5.0.2-py2.py3-none-any.whl deleted file mode 100644 index f1ed95ee122f37731b51226ccbc8d6eb07405f39..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 145967 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 I0)-g#KhNfV%K!iX diff --git a/salt/salt/module_packages/docker/docker-7.1.0-py3-none-any.whl b/salt/salt/module_packages/docker/docker-7.1.0-py3-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..c324efbd08e43702330255be41022230df757452 GIT binary patch literal 147774 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νsv=4VNYjF8rcz{%)OXa%MGl~1G&aaT9M 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 literal 0 HcmV?d00001 diff --git a/salt/salt/module_packages/docker/idna-3.7-py3-none-any.whl b/salt/salt/module_packages/docker/idna-3.8-py3-none-any.whl similarity index 85% rename from salt/salt/module_packages/docker/idna-3.7-py3-none-any.whl rename to salt/salt/module_packages/docker/idna-3.8-py3-none-any.whl index fa4c95b123751094438c2f747e5389c32d870c5b..84d04cdf9f227bef8b255e71874beff94417dd74 100644 GIT binary patch delta 8176 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 delta 8143 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 diff --git a/salt/salt/module_packages/docker/websocket_client-1.8.0-py3-none-any.whl b/salt/salt/module_packages/docker/websocket_client-1.8.0-py3-none-any.whl deleted file mode 100644 index a2d768d7937a90e7c5ecbd51c1332b00c9e3cdac..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 58826 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%0DCms_LKk0sdE$TuK|H_S+W&{PH9J=l4HHq1$`V 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 WD$1bVxG Date: Tue, 27 Aug 2024 09:42:11 -0400 Subject: [PATCH 026/315] script to fix libvirt in salt 3006.2+ --- salt/salt/scripts/fixLibvirt.py | 80 +++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 salt/salt/scripts/fixLibvirt.py diff --git a/salt/salt/scripts/fixLibvirt.py b/salt/salt/scripts/fixLibvirt.py new file mode 100644 index 000000000..853b452d6 --- /dev/null +++ b/salt/salt/scripts/fixLibvirt.py @@ -0,0 +1,80 @@ + +#!/usr/bin/env python3 + +# resolves https://github.com/saltstack/salt/issues/64962 +# 3006.2+ has and issue with libvirt +# use pip to install lief then run this script to resolve + +import datetime +import grp +import os +import pathlib +import pwd +import shutil +## +import dbus # dnf -y install python3-dbus +## +import lief # https://pypi.org/project/lief/ + +# https://github.com/saltstack/salt/issues/64962 + +salt_root = pathlib.Path('/opt/saltstack') +src_lib = pathlib.Path('/lib64/libldap.so.2') +dst_lib = salt_root.joinpath('salt', 'lib', 'libldap.so.2') + +uname = 'root' +gname = 'root' + +lib = lief.parse(str(src_lib)) +sym = next(i for i in lib.imported_symbols if i.name == 'EVP_md2') +if sym: + # Get the Salt services from DBus. + sysbus = dbus.SystemBus() + sysd = sysbus.get_object('org.freedesktop.systemd1', '/org/freedesktop/systemd1') + mgr = dbus.Interface(sysd, 'org.freedesktop.systemd1.Manager') + svcs = [] + for i in mgr.ListUnits(): + # first element is unit name. + if not str(i[0]).startswith('salt-'): + continue + svc = sysbus.get_object('org.freedesktop.systemd1', object_path = mgr.GetUnit(str(i[0]))) + props = dbus.Interface(svc, dbus_interface = 'org.freedesktop.DBus.Properties') + state = props.Get('org.freedesktop.systemd1.Unit', 'ActiveState') + if str(state) == 'active': + svcs.append(i[0]) + # Get the user/group + u = pwd.getpwnam(uname) + g = grp.getgrnam(gname) + # Modify + print('Modifications necessary.') + if svcs: + # Stop the services first. + for sn in svcs: + mgr.StopUnit(sn, 'replace') + if dst_lib.exists(): + # 3.10 deprecated .utcnow(). + #dst_lib_bak = pathlib.Path(str(dst_lib) + '.bak_{0}'.format(datetime.datetime.now(datetime.UTC).timestamp())) + dst_lib_bak = pathlib.Path(str(dst_lib) + '.bak_{0}'.format(datetime.datetime.utcnow().timestamp())) + os.rename(dst_lib, dst_lib_bak) + print('Destination file {0} exists; backed up to {1}.'.format(dst_lib, dst_lib_bak)) + lib.remove_dynamic_symbol(sym) + lib.write(str(dst_lib)) + os.chown(dst_lib, u.pw_uid, g.gr_gid) + os.chmod(dst_lib, src_lib.stat().st_mode) + # Before we restart services, we also want to remove any python caches. + for root, dirs, files in os.walk(salt_root): + for f in files: + if f.lower().endswith('.pyc'): + fpath = os.path.join(root, f) + os.remove(fpath) + print('Removed file {0}'.format(fpath)) + if '__pycache__' in dirs: + dpath = os.path.join(root, '__pycache__') + shutil.rmtree(dpath) + print('Removed directory {0}'.format(dpath)) + # And then start the units that were started before. + if svcs: + for sn in svcs: + mgr.RestartUnit(sn, 'replace') + +print('Done.') From 9ddccba7807172afbed5297932c7522daf15ce94 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Wed, 28 Aug 2024 10:09:42 -0400 Subject: [PATCH 027/315] LSHEAP and pipeline workers for virt --- salt/manager/tools/sbin/so-minion | 6 +++++- salt/reactor/sominion_setup.sls | 2 +- salt/setup/virt/soinstall.map.jinja | 12 +++++++++++- salt/setup/virt/sominion.sls | 2 +- 4 files changed, 18 insertions(+), 4 deletions(-) diff --git a/salt/manager/tools/sbin/so-minion b/salt/manager/tools/sbin/so-minion index 18c8c3224..0956840b1 100755 --- a/salt/manager/tools/sbin/so-minion +++ b/salt/manager/tools/sbin/so-minion @@ -44,6 +44,10 @@ for i in "$@"; do ES_HEAP_SIZE="${i#*=}" shift ;; + -l=*|--lsheap=*) + LSHEAP="${i#*=}" + shift + ;; -n=*|--mgmtnic=*) MNIC="${i#*=}" shift @@ -214,7 +218,7 @@ function add_logstash_to_minion() { "logstash:"\ " enabled: True"\ " config:"\ - " pipeline_x_workers: $CPUCORES"\ + " pipeline_x_workers: $CORECOUNT"\ " settings:"\ " lsheap: $LSHEAP"\ " " >> $PILLARFILE diff --git a/salt/reactor/sominion_setup.sls b/salt/reactor/sominion_setup.sls index 91a4a6cb9..a78475e6c 100644 --- a/salt/reactor/sominion_setup.sls +++ b/salt/reactor/sominion_setup.sls @@ -28,7 +28,7 @@ def run(): with open("/opt/so/saltstack/local/pillar/hypervisor/" + hv_name + "/" + minionid + ".sls", 'w') as f: yaml.dump(vm_out_data, f, default_flow_style=False) - rc = call("NODETYPE=" + DATA['NODETYPE'] + " /usr/sbin/so-minion -o=addVirt -m=" + minionid + " -n=" + DATA['MNIC'] + " -i=" + DATA['MAINIP'] + " -a=" + DATA['INTERFACE'] + " -c=" + str(DATA['CORECOUNT']) + " -d='" + DATA['NODE_DESCRIPTION'] + "'", shell=True) + rc = call("NODETYPE=" + DATA['NODETYPE'] + " /usr/sbin/so-minion -o=addVirt -m=" + minionid + " -n=" + DATA['MNIC'] + " -i=" + DATA['MAINIP'] + " -a=" + DATA['INTERFACE'] + " -c=" + str(DATA['CPU']) + " -d='" + DATA['NODE_DESCRIPTION'] + "'" + " -e=" + DATA['ES_HEAP_SIZE'] + " -l=" + DATA['LS_HEAP_SIZE'], shell=True) logging.error('sominion_setup reactor: rc: %s' % rc) diff --git a/salt/setup/virt/soinstall.map.jinja b/salt/setup/virt/soinstall.map.jinja index e2649aab1..a589250df 100644 --- a/salt/setup/virt/soinstall.map.jinja +++ b/salt/setup/virt/soinstall.map.jinja @@ -14,7 +14,8 @@ {% if nodetype == "searchnode" %} -{% do DATA.update({'LSHOSTNAME': grains.host}) %} +{# we can't use the host grain here because the grain may not be updated yet from the hostname change #} +{% do DATA.update({'LSHOSTNAME': salt['cmd.run']('hostname')}) %} {# this replicates the function es_heapsize in so-functions #} {% if total_mem < 8000 %} @@ -31,4 +32,13 @@ {% endif %} {% do DATA.update({'ES_HEAP_SIZE': ES_HEAP_SIZE}) %} +{% if total_mem >= 32000 or nodetype in ['managersearch','heavynode','standalone'] %} +{% set LS_HEAP_SIZE="1000m" %} +{% elif nodetype == 'eval' %} +{% set LS_HEAP_SIZE="700m" %} +{% else %} +{% set LS_HEAP_SIZE="500m" %} +{% endif %} +{% do DATA.update({'LS_HEAP_SIZE': LS_HEAP_SIZE}) %} + {% endif %} diff --git a/salt/setup/virt/sominion.sls b/salt/setup/virt/sominion.sls index 328f50311..55e3a796a 100644 --- a/salt/setup/virt/sominion.sls +++ b/salt/setup/virt/sominion.sls @@ -19,7 +19,7 @@ create_pillar: NODETYPE: {{ DATA.NODETYPE }} CORECOUNT: {{ DATA.CORECOUNT }} LSHOSTNAME: {{ DATA.LSHOSTNAME }} - LSHEAP: {{ DATA.LSHEAP }} + LS_HEAP_SIZE: {{ DATA.LSHEAP }} CPUCORES: {{ DATA.CPUCORES }} IDH_MGTRESTRICT: {{ DATA.IDH_MGTRESTRICT }} IDH_SERVICES: {{ DATA.IDH_SERVICES }} From d44ce0a070b9b7e9b70e4aeccccb301f84d97f06 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Wed, 28 Aug 2024 12:41:38 -0400 Subject: [PATCH 028/315] add so-salt-cloud as salt-cloud wrapper --- salt/manager/tools/sbin/so-salt-cloud | 76 +++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 salt/manager/tools/sbin/so-salt-cloud diff --git a/salt/manager/tools/sbin/so-salt-cloud b/salt/manager/tools/sbin/so-salt-cloud new file mode 100644 index 000000000..d0b87f5e7 --- /dev/null +++ b/salt/manager/tools/sbin/so-salt-cloud @@ -0,0 +1,76 @@ +#!/usr/bin/python3 + +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +import argparse +import subprocess +import re +import threading + +def call_so_firewall_minion(ip, role): + print("call_so_firewall_minion called") + try: + # Start so-firewall-minion as a subprocess + process = subprocess.Popen( + ['/usr/sbin/so-firewall-minion', f'--ip={ip}', f'--role={role}'], + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + text=True + ) + + except Exception as e: + print(f"An error occurred while calling the command: {e}") + +def call_salt_cloud(profile, vm_name): + try: + # Start the salt-cloud command as a subprocess + process = subprocess.Popen( + ['salt-cloud', '-p', profile, vm_name, '-l', 'info'], + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + text=True + ) + + role = vm_name.split("_")[1] + + ip_search_string = '[INFO ] Address =' + ip_search_pattern = re.compile(re.escape(ip_search_string)) + + # Continuously read the output + while True: + # Read stdout line by line + line = process.stdout.readline() + if line: + print(line.rstrip('\n')) + + if ip_search_pattern.search(line): + parts = line.split("Address =") + if len(parts) > 1: + ip_address = parts[1].strip() + print("Extracted IP address:", ip_address) + # Create and start a thread to run so-firewall-minion + thread = threading.Thread(target=call_so_firewall_minion, args=(ip_address,role.upper())) + thread.start() + else: + print("No IP address found.") + + # Check if the process has terminated + elif process.poll() is not None: + # process finished + break + + except Exception as e: + print(f"An error occurred while calling the command: {e}") + +if __name__ == "__main__": + + parser = argparse.ArgumentParser(description="Call salt-cloud and pass the profile and VM name to it.") + parser.add_argument('-p', '--profile', type=str, required=True, help="The cloud profile to build the VM from.") + parser.add_argument('vm_name', type=str, help="The name of the VM.") + + args = parser.parse_args() + + call_salt_cloud(args.profile, args.vm_name) From f5e6e49075aa5aa576832b8d8e16f88b90764b9d Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Wed, 28 Aug 2024 14:12:23 -0400 Subject: [PATCH 029/315] set initial schedule for vm to deal with possible manager firewall state.apply delay --- salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja | 10 +++++----- salt/salt/master.sls | 8 ++++---- salt/setup/virt/init.sls | 4 ++++ salt/setup/virt/initial_schedule.sls | 7 +++++++ salt/setup/virt/setSalt.sls | 5 ++++- 5 files changed, 24 insertions(+), 10 deletions(-) create mode 100644 salt/setup/virt/init.sls create mode 100644 salt/setup/virt/initial_schedule.sls diff --git a/salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja b/salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja index 3e797890a..4d3d33ac2 100644 --- a/salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja +++ b/salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja @@ -20,7 +20,7 @@ core-{{host}}: master_port: 4506 #startup_states: sls #sls_list: - # - setup.virt.setSalt + # - setup.virt.initial_schedule # - setup.virt.setHostname use_superseded: - module.run @@ -34,10 +34,10 @@ core-{{host}}: #preflight_cmds: # - echo "preflight_cmds" # the destination directory will be created if it doesn't exist - #file_map: - # /opt/so/saltstack/default/salt/repo/client/files/oracle/keys/securityonion.pub: /tmp/securityonion.pub - #inline_script: - # - "systemctl start salt-minion" + file_map: + /opt/so/saltstack/default/salt/setup/virt/initial_schedule.sls: /opt/so/conf/salt/cloud_file_map/salt/initial_schedule.sls + inline_script: + - "sudo salt-call state.apply initial_schedule --local --file-root=/opt/so/conf/salt/cloud_file_map/salt/" # - "rpm --import /tmp/securityonion.pub" # grains to add to the minion diff --git a/salt/salt/master.sls b/salt/salt/master.sls index fc572be96..0dd522e81 100644 --- a/salt/salt/master.sls +++ b/salt/salt/master.sls @@ -58,10 +58,10 @@ salt_master_service: #- salt/cloud/*/requesting # - 'salt/cloud/*/deploying': # - /opt/so/saltstack/default/salt/reactor/createEmptyPillar.sls -# - 'salt/cloud/*/created': -# - /opt/so/saltstack/default/salt/reactor/setSalt.sls -# - /opt/so/saltstack/default/salt/reactor/setHostname.sls -# - /opt/so/saltstack/default/salt/reactor/sominion.sls +## - 'salt/cloud/*/created': +## - /opt/so/saltstack/default/salt/reactor/setSalt.sls +## - /opt/so/saltstack/default/salt/reactor/setHostname.sls +## - /opt/so/saltstack/default/salt/reactor/sominion.sls # - 'setup/so-minion': # - /opt/so/saltstack/default/salt/reactor/sominion_setup.sls # - /opt/so/saltstack/default/salt/reactor/virtUpdate.sls diff --git a/salt/setup/virt/init.sls b/salt/setup/virt/init.sls new file mode 100644 index 000000000..be89c8588 --- /dev/null +++ b/salt/setup/virt/init.sls @@ -0,0 +1,4 @@ +include: + - setup.virt.setSalt + - setup.virt.setHostname + - setup.virt.sominion diff --git a/salt/setup/virt/initial_schedule.sls b/salt/setup/virt/initial_schedule.sls new file mode 100644 index 000000000..7535ee960 --- /dev/null +++ b/salt/setup/virt/initial_schedule.sls @@ -0,0 +1,7 @@ +init_node_schedule: + schedule.present: + - name: init_node + - function: state.sls + - job_args: + - setup.virt.init + - minutes: 1 diff --git a/salt/setup/virt/setSalt.sls b/salt/setup/virt/setSalt.sls index aa6618b25..f777d6005 100644 --- a/salt/setup/virt/setSalt.sls +++ b/salt/setup/virt/setSalt.sls @@ -8,7 +8,10 @@ set_role_grain: - name: role - value: so-{{ grains.id.split("_") | last }} -# set event for firewall rules - so-firewall-minion +# disable the initial schedule +remove_init_node_schedule: + schedule.absent: + - name: init_node set_highstate: file.append: From 267d1a27acb206a101b8719ace3c79d7c9340b67 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Wed, 28 Aug 2024 15:52:14 -0400 Subject: [PATCH 030/315] use cron instead of schedule for vm init. ensure vm shutdown --- salt/reactor/virtUpdate.sls | 14 +++++++++++++- salt/setup/virt/initial_schedule.sls | 20 +++++++++++++------- salt/setup/virt/setSalt.sls | 10 ++++++---- 3 files changed, 32 insertions(+), 12 deletions(-) diff --git a/salt/reactor/virtUpdate.sls b/salt/reactor/virtUpdate.sls index d4b56fdf6..2e691b5b1 100644 --- a/salt/reactor/virtUpdate.sls +++ b/salt/reactor/virtUpdate.sls @@ -75,7 +75,19 @@ def run(): c = 0 while True: if c == 60: - logging.error("virtUpdate reactor: vm_name: %s failed to shutdown in time " % vm_name) + logging.error("virtUpdate reactor: vm_name: %s failed virt.shutdown in time " % vm_name) + return {} + r = local.cmd(hv_name, 'virt.shutdown', ['vm_=' + vm_name]) + logging.error("virtUpdate reactor: virt.shutdown: %s return: %s " % (vm_name,r)) + if r.get(hv_name): + break + c += 1 + sleep(1) + + c = 0 + while True: + if c == 60: + logging.error("virtUpdate reactor: vm_name: %s failed to go inactive in time " % vm_name) return {} r = local.cmd(hv_name, 'virt.list_inactive_vms') logging.error("virtUpdate reactor: virt.list_inactive_vms: %s " % r.get(hv_name)) diff --git a/salt/setup/virt/initial_schedule.sls b/salt/setup/virt/initial_schedule.sls index 7535ee960..6388e7c31 100644 --- a/salt/setup/virt/initial_schedule.sls +++ b/salt/setup/virt/initial_schedule.sls @@ -1,7 +1,13 @@ -init_node_schedule: - schedule.present: - - name: init_node - - function: state.sls - - job_args: - - setup.virt.init - - minutes: 1 +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +# initially tried to use schedule.present here, but that state trys to return data to the master even if run with --local +# that causes it to fail since th firewall may not yet be open on the manager +init_node_cron: + cron.present: + - name: salt-call state.apply setup.virt.init + - identifier: init_node_cron + - user: root + - minute: '*/1' diff --git a/salt/setup/virt/setSalt.sls b/salt/setup/virt/setSalt.sls index f777d6005..c48282747 100644 --- a/salt/setup/virt/setSalt.sls +++ b/salt/setup/virt/setSalt.sls @@ -8,10 +8,12 @@ set_role_grain: - name: role - value: so-{{ grains.id.split("_") | last }} -# disable the initial schedule -remove_init_node_schedule: - schedule.absent: - - name: init_node +# remove the initial cron +remove_init_node_cron: + cron.absent: + - name: salt-call state.apply setup.virt.init + - identifier: init_node_cron + - user: root set_highstate: file.append: From 0766a5da91eeb06196a6f0c59b970da4f9ff5e1a Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Wed, 28 Aug 2024 16:59:24 -0400 Subject: [PATCH 031/315] change to LSHEAP. LSHOSTNAME from id grain --- salt/setup/virt/soinstall.map.jinja | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/salt/setup/virt/soinstall.map.jinja b/salt/setup/virt/soinstall.map.jinja index a589250df..566b27445 100644 --- a/salt/setup/virt/soinstall.map.jinja +++ b/salt/setup/virt/soinstall.map.jinja @@ -14,8 +14,7 @@ {% if nodetype == "searchnode" %} -{# we can't use the host grain here because the grain may not be updated yet from the hostname change #} -{% do DATA.update({'LSHOSTNAME': salt['cmd.run']('hostname')}) %} +{% do DATA.update({'LSHOSTNAME': grains.id.split("_") | first}) %} {# this replicates the function es_heapsize in so-functions #} {% if total_mem < 8000 %} @@ -33,12 +32,12 @@ {% do DATA.update({'ES_HEAP_SIZE': ES_HEAP_SIZE}) %} {% if total_mem >= 32000 or nodetype in ['managersearch','heavynode','standalone'] %} -{% set LS_HEAP_SIZE="1000m" %} +{% set LSHEAP="1000m" %} {% elif nodetype == 'eval' %} -{% set LS_HEAP_SIZE="700m" %} +{% set LSHEAP="700m" %} {% else %} -{% set LS_HEAP_SIZE="500m" %} +{% set LSHEAP="500m" %} {% endif %} -{% do DATA.update({'LS_HEAP_SIZE': LS_HEAP_SIZE}) %} +{% do DATA.update({'LSHEAP': LSHEAP}) %} {% endif %} From aaa48f6a1adf56fdde5f9b072f32fbd402a1392f Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Thu, 29 Aug 2024 13:41:58 -0400 Subject: [PATCH 032/315] support for fleet, heavynode, receiver, idh --- salt/manager/tools/sbin/so-salt-cloud | 1 - salt/setup/virt/fleet.yaml | 18 ++++++++++++++++++ salt/setup/virt/heavynode.yaml | 18 ++++++++++++++++++ salt/setup/virt/idh.yaml | 18 ++++++++++++++++++ salt/setup/virt/receiver.yaml | 18 ++++++++++++++++++ salt/setup/virt/searchnode.yaml | 12 ++++++------ salt/setup/virt/sensor.yaml | 4 ++-- salt/setup/virt/soinstall.map.jinja | 26 +++++++++++++++----------- 8 files changed, 95 insertions(+), 20 deletions(-) create mode 100644 salt/setup/virt/fleet.yaml create mode 100644 salt/setup/virt/heavynode.yaml create mode 100644 salt/setup/virt/idh.yaml create mode 100644 salt/setup/virt/receiver.yaml diff --git a/salt/manager/tools/sbin/so-salt-cloud b/salt/manager/tools/sbin/so-salt-cloud index d0b87f5e7..b34252730 100644 --- a/salt/manager/tools/sbin/so-salt-cloud +++ b/salt/manager/tools/sbin/so-salt-cloud @@ -11,7 +11,6 @@ import re import threading def call_so_firewall_minion(ip, role): - print("call_so_firewall_minion called") try: # Start so-firewall-minion as a subprocess process = subprocess.Popen( diff --git a/salt/setup/virt/fleet.yaml b/salt/setup/virt/fleet.yaml new file mode 100644 index 000000000..8a6aa06de --- /dev/null +++ b/salt/setup/virt/fleet.yaml @@ -0,0 +1,18 @@ +MAINIP: +MNIC: eth0 +NODE_DESCRIPTION: 'vm' +ES_HEAP_SIZE: +PATCHSCHEDULENAME: +INTERFACE: +NODETYPE: FLEET +CORECOUNT: 8 +LSHOSTNAME: +LSHEAP: +CPUCORES: 8 +IDH_MGTRESTRICT: +IDH_SERVICES: +CPU: 8 +MEMORY: 8 +DISKS: 0 +COPPER: 0 +SFP: 0 diff --git a/salt/setup/virt/heavynode.yaml b/salt/setup/virt/heavynode.yaml new file mode 100644 index 000000000..8cf2e0392 --- /dev/null +++ b/salt/setup/virt/heavynode.yaml @@ -0,0 +1,18 @@ +MAINIP: +MNIC: eth0 +NODE_DESCRIPTION: 'vm' +ES_HEAP_SIZE: +PATCHSCHEDULENAME: +INTERFACE: bond0 +NODETYPE: HEAVYNODE +CORECOUNT: 8 +LSHOSTNAME: +LSHEAP: +CPUCORES: 8 +IDH_MGTRESTRICT: +IDH_SERVICES: +CPU: 8 +MEMORY: 16 +DISKS: 0 +COPPER: 0 +SFP: 0 diff --git a/salt/setup/virt/idh.yaml b/salt/setup/virt/idh.yaml new file mode 100644 index 000000000..0e1ef8be0 --- /dev/null +++ b/salt/setup/virt/idh.yaml @@ -0,0 +1,18 @@ +MAINIP: +MNIC: eth0 +NODE_DESCRIPTION: 'vm' +ES_HEAP_SIZE: +PATCHSCHEDULENAME: +INTERFACE: +NODETYPE: IDH +CORECOUNT: 2 +LSHOSTNAME: +LSHEAP: +CPUCORES: 2 +IDH_MGTRESTRICT: +IDH_SERVICES: +CPU: 2 +MEMORY: 1 +DISKS: 0 +COPPER: 0 +SFP: 0 diff --git a/salt/setup/virt/receiver.yaml b/salt/setup/virt/receiver.yaml new file mode 100644 index 000000000..5a5c714aa --- /dev/null +++ b/salt/setup/virt/receiver.yaml @@ -0,0 +1,18 @@ +MAINIP: +MNIC: eth0 +NODE_DESCRIPTION: 'vm' +ES_HEAP_SIZE: +PATCHSCHEDULENAME: +INTERFACE: +NODETYPE: RECEIVER +CORECOUNT: 2 +LSHOSTNAME: +LSHEAP: +CPUCORES: 2 +IDH_MGTRESTRICT: +IDH_SERVICES: +CPU: 2 +MEMORY: 8 +DISKS: 0 +COPPER: 0 +SFP: 0 diff --git a/salt/setup/virt/searchnode.yaml b/salt/setup/virt/searchnode.yaml index f48502b94..2e1568f29 100644 --- a/salt/setup/virt/searchnode.yaml +++ b/salt/setup/virt/searchnode.yaml @@ -1,18 +1,18 @@ MAINIP: MNIC: eth0 -NODE_DESCRIPTION: 'virt search' +NODE_DESCRIPTION: 'vm' ES_HEAP_SIZE: PATCHSCHEDULENAME: -INTERFACE: bond0 +INTERFACE: NODETYPE: SEARCHNODE -CORECOUNT: 16 +CORECOUNT: 8 LSHOSTNAME: LSHEAP: -CPUCORES: 16 +CPUCORES: 8 IDH_MGTRESTRICT: IDH_SERVICES: -CPU: 16 -MEMORY: 32 +CPU: 8 +MEMORY: 16 DISKS: 1 COPPER: 0 SFP: 0 diff --git a/salt/setup/virt/sensor.yaml b/salt/setup/virt/sensor.yaml index e90bece35..e7064bdfe 100644 --- a/salt/setup/virt/sensor.yaml +++ b/salt/setup/virt/sensor.yaml @@ -1,6 +1,6 @@ MAINIP: MNIC: eth0 -NODE_DESCRIPTION: 'virt sensor' +NODE_DESCRIPTION: 'vm' ES_HEAP_SIZE: PATCHSCHEDULENAME: INTERFACE: bond0 @@ -12,7 +12,7 @@ CPUCORES: 4 IDH_MGTRESTRICT: IDH_SERVICES: CPU: 8 -MEMORY: 8 +MEMORY: 12 DISKS: 0 COPPER: 0 SFP: 0 diff --git a/salt/setup/virt/soinstall.map.jinja b/salt/setup/virt/soinstall.map.jinja index 566b27445..c16f6cd78 100644 --- a/salt/setup/virt/soinstall.map.jinja +++ b/salt/setup/virt/soinstall.map.jinja @@ -11,11 +11,24 @@ {% do DATA.update({'CORECOUNT': grains.num_cpus}) %} {% do DATA.update({'CPUCORES': grains.num_cpus}) %} +{% if nodetype in ['searchnode', 'receiver', 'fleet', 'heavynode'] %} -{% if nodetype == "searchnode" %} - +{# we can't use the host grain here because the grain may not be updated yet from the hostname change #} {% do DATA.update({'LSHOSTNAME': grains.id.split("_") | first}) %} +{% if total_mem >= 32000 or nodetype in ['managersearch','heavynode','standalone'] %} +{% set LSHEAP="1000m" %} +{% elif nodetype == 'eval' %} +{% set LSHEAP="700m" %} +{% else %} +{% set LSHEAP="500m" %} +{% endif %} +{% do DATA.update({'LSHEAP': LSHEAP}) %} + +{% endif %} + +{% if nodetype in ['searchnode', 'heavynode'] %} + {# this replicates the function es_heapsize in so-functions #} {% if total_mem < 8000 %} {% set ES_HEAP_SIZE = "600m" %} @@ -31,13 +44,4 @@ {% endif %} {% do DATA.update({'ES_HEAP_SIZE': ES_HEAP_SIZE}) %} -{% if total_mem >= 32000 or nodetype in ['managersearch','heavynode','standalone'] %} -{% set LSHEAP="1000m" %} -{% elif nodetype == 'eval' %} -{% set LSHEAP="700m" %} -{% else %} -{% set LSHEAP="500m" %} -{% endif %} -{% do DATA.update({'LSHEAP': LSHEAP}) %} - {% endif %} From e7ea27a1b346f1e4bfb6de0f9a26206de49749f9 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Fri, 13 Sep 2024 15:26:59 -0400 Subject: [PATCH 033/315] script to update ip address to static or dhcp inside qcow2 image --- salt/hypervisor/tools/sbin/modify_network.py | 216 +++++++++++++++++++ 1 file changed, 216 insertions(+) create mode 100644 salt/hypervisor/tools/sbin/modify_network.py diff --git a/salt/hypervisor/tools/sbin/modify_network.py b/salt/hypervisor/tools/sbin/modify_network.py new file mode 100644 index 000000000..de493e75c --- /dev/null +++ b/salt/hypervisor/tools/sbin/modify_network.py @@ -0,0 +1,216 @@ +#!/usr/bin/python3 + +import argparse +import guestfs +import re +import sys +import logging +import os +import ipaddress +import configparser +from io import StringIO + +logging.basicConfig(level=logging.INFO) +logger = logging.getLogger(__name__) + +NETWORK_CONFIG_DIR = "/etc/NetworkManager/system-connections" + +def validate_ip_address(ip_str, description="IP address"): + """ + Validates that the given string is a properly formatted IPv4 address or IPv4 interface. + """ + try: + # Try to parse as IPv4 interface (e.g., "192.168.1.10/24") + ipaddress.IPv4Interface(ip_str) + except ValueError: + try: + # Try to parse as IPv4 address (e.g., "192.168.1.10") + ipaddress.IPv4Address(ip_str) + except ValueError: + raise ValueError(f"Invalid {description}: {ip_str}") + +def validate_dns_addresses(dns_str): + """ + Validates a comma-separated list of DNS server IP addresses. + """ + dns_list = dns_str.split(',') + for dns in dns_list: + dns = dns.strip() + validate_ip_address(dns, description="DNS server address") + +def validate_interface_name(interface_name): + """ + Validates that the network interface name contains only valid characters. + """ + if not re.match(r'^[a-zA-Z0-9_\-]+$', interface_name): + raise ValueError(f"Invalid interface name: {interface_name}") + +def update_ipv4_section(content, mode, ip=None, gateway=None, dns=None, search_domain=None): + """ + Updates the IPv4 section of the network configuration file with either DHCP or static settings. + """ + config = configparser.ConfigParser(strict=False) + config.optionxform = str # Preserve case sensitivity + config.read_string(content) + + if 'ipv4' not in config.sections(): + # Handle missing [ipv4] section gracefully + config.add_section('ipv4') + + if mode == "dhcp": + config.set('ipv4', 'method', 'auto') + # Remove static addresses, DNS settings, and search domains + config.remove_option('ipv4', 'address1') + config.remove_option('ipv4', 'addresses') + config.remove_option('ipv4', 'dns') + config.remove_option('ipv4', 'dns-search') + elif mode == "static": + config.set('ipv4', 'method', 'manual') + if ip and gateway: + config.set('ipv4', 'address1', f"{ip},{gateway}") + else: + raise ValueError("Both IP address and gateway are required for static configuration.") + if dns: + config.set('ipv4', 'dns', f"{dns};") + else: + config.remove_option('ipv4', 'dns') + if search_domain: + config.set('ipv4', 'dns-search', f"{search_domain};") + else: + config.remove_option('ipv4', 'dns-search') + else: + raise ValueError(f"Invalid mode '{mode}'. Expected 'dhcp' or 'static'.") + + # Write the updated content back to a string + output = StringIO() + config.write(output, space_around_delimiters=False) + updated_content = output.getvalue() + output.close() + + return updated_content + +def modify_network_config(image_path, interface, mode, ip=None, gateway=None, dns=None, search_domain=None): + """ + Modifies the network configuration file for the given interface inside the QCOW2 image. + """ + # Check for write permissions to the image file + if not os.access(image_path, os.W_OK): + raise PermissionError(f"Write permission denied for image file: {image_path}") + + # Initialize the guestfs instance and add the image + g = guestfs.GuestFS(python_return_dict=True) + try: + g.set_network(False) # Disable network access if not needed + + # Disable SELinux relabeling + g.selinux = False # Correct way to disable SELinux relabeling + + g.add_drive_opts(image_path, format="qcow2") + g.launch() + except RuntimeError as e: + raise RuntimeError(f"Failed to initialize GuestFS or launch appliance: {e}") + + try: + # Detect and mount the operating system + os_list = g.inspect_os() + if not os_list: + raise RuntimeError(f"Unable to find any OS in {image_path}.") + + root_fs = os_list[0] + try: + g.mount(root_fs, "/") + except RuntimeError as e: + raise RuntimeError(f"Failed to mount the filesystem: {e}") + + # Check if NetworkManager configuration directory exists + if not g.is_dir(NETWORK_CONFIG_DIR): + raise FileNotFoundError(f"NetworkManager configuration directory not found in the image at {NETWORK_CONFIG_DIR}.") + + # Path to the network configuration file for the given interface + config_file_path = f"{NETWORK_CONFIG_DIR}/{interface}.nmconnection" + + # Read the current configuration file + try: + file_content = g.read_file(config_file_path) + current_content = file_content.decode('utf-8') + except RuntimeError: + raise FileNotFoundError(f"Configuration file for {interface} not found at {config_file_path}.") + except UnicodeDecodeError: + raise ValueError(f"Failed to decode the configuration file for {interface}.") + + # Update the content based on the provided arguments + updated_content = update_ipv4_section(current_content, mode, ip, gateway, dns, search_domain) + + # Write the updated content back to the configuration file + try: + g.write(config_file_path, updated_content.encode('utf-8')) + except RuntimeError as e: + raise IOError(f"Failed to write updated configuration to {config_file_path}: {e}") + + logger.info(f"Updated {interface} network configuration in {image_path} using {mode.upper()} mode.") + + except Exception as e: + raise e + finally: + g.umount_all() + g.close() + +def parse_arguments(): + """ + Parses command-line arguments for the script. + """ + parser = argparse.ArgumentParser(description="Modify IPv4 settings in a QCOW2 image for a specified network interface.") + parser.add_argument("-I", "--image", required=True, help="Path to the QCOW2 image.") + parser.add_argument("-i", "--interface", required=True, help="Network interface to modify (e.g., eth0).") + group = parser.add_mutually_exclusive_group(required=True) + group.add_argument("--dhcp", action="store_true", help="Configure interface for DHCP (IPv4).") + group.add_argument("--static4", action="store_true", help="Configure interface for static IPv4 settings.") + parser.add_argument("--ip4", help="IPv4 address (e.g., 192.168.1.10/24). Required for static IPv4 configuration.") + parser.add_argument("--gw4", help="IPv4 gateway (e.g., 192.168.1.1). Required for static IPv4 configuration.") + parser.add_argument("--dns4", help="Comma-separated list of IPv4 DNS servers (e.g., 8.8.8.8,8.8.4.4).") + parser.add_argument("--search4", help="DNS search domain for IPv4.") + + args = parser.parse_args() + + # Validate arguments + if args.static4: + if not args.ip4 or not args.gw4: + parser.error("Both --ip4 and --gw4 are required for static IPv4 configuration.") + return args + +def main(): + """ + Main entry point for the script. + """ + try: + args = parse_arguments() + + validate_interface_name(args.interface) + + # Validate mode + if args.dhcp: + mode = "dhcp" + elif args.static4: + mode = "static" + if not args.ip4 or not args.gw4: + raise ValueError("Both --ip4 and --gw4 are required for static IPv4 configuration.") + # Validate IP addresses + validate_ip_address(args.ip4, description="IPv4 address") + validate_ip_address(args.gw4, description="IPv4 gateway") + if args.dns4: + validate_dns_addresses(args.dns4) + else: + raise ValueError("Either --dhcp or --static4 must be specified.") + + # Modify the network configuration inside the image + modify_network_config(args.image, args.interface, mode, args.ip4, args.gw4, args.dns4, args.search4) + + except KeyboardInterrupt: + logger.error("Operation cancelled by user.") + sys.exit(1) + except Exception as e: + logger.error(f"An error occurred: {e}") + sys.exit(1) + +if __name__ == "__main__": + main() From 75e8c60fe29a51c19f05d44f2b244fba8e71f05b Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Fri, 20 Sep 2024 11:03:16 -0400 Subject: [PATCH 034/315] add tools to set dhcp/static ip inside the qcow2 image --- salt/_modules/qcow2.py | 73 ++++++++++++ salt/hypervisor/init.sls | 5 + ...ify_network.py => so-qcow2-modify-network} | 75 ++++-------- salt/libvirt/packages.sls | 2 +- salt/manager/tools/sbin/so-salt-cloud | 111 +++++++++++++++--- 5 files changed, 196 insertions(+), 70 deletions(-) create mode 100644 salt/_modules/qcow2.py rename salt/hypervisor/tools/sbin/{modify_network.py => so-qcow2-modify-network} (72%) diff --git a/salt/_modules/qcow2.py b/salt/_modules/qcow2.py new file mode 100644 index 000000000..56ccb36a0 --- /dev/null +++ b/salt/_modules/qcow2.py @@ -0,0 +1,73 @@ +#!py + +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +import logging +import subprocess +import shlex + +log = logging.getLogger(__name__) + +__virtualname__ = 'qcow2' + +def __virtual__(): + return __virtualname__ + +def modify_network_config(image, interface, mode, ip4=None, gw4=None, dns4=None, search4=None): + ''' + Wrapper function to call so-qcow2-modify-network + + :param image: Path to the QCOW2 image. + :param interface: Network interface to modify (e.g., 'eth0'). + :param mode: 'dhcp4' or 'static4'. + :param ip4: IPv4 address with CIDR notation (e.g., '192.168.1.100/24'). Required for static configuration. + :param gw4: IPv4 gateway (e.g., '192.168.1.1'). Required for static configuration. + :param dns4: Comma-separated list of IPv4 DNS servers (e.g., '8.8.8.8,8.8.4.4'). + :param search4: DNS search domain for IPv4. + + :return: A dictionary with the result of the script execution. + + CLI Example: + + .. code-block:: bash + + salt '*' qcow2.modify_network_config image='/path/to/image.qcow2' interface='eth0' mode='static4' ip4='192.168.1.100/24' gw4='192.168.1.1' dns4='8.8.8.8,8.8.4.4' search4='example.com' + + ''' + + cmd = ['/usr/sbin/so-qcow2-modify-network.py', '-I', image, '-i', interface] + + if mode.lower() == 'dhcp4': + cmd.append('--dhcp4') + elif mode.lower() == 'static4': + cmd.append('--static4') + if not ip4 or not gw4: + raise ValueError('Both ip4 and gw4 are required for static configuration.') + cmd.extend(['--ip4', ip4, '--gw4', gw4]) + if dns4: + cmd.extend(['--dns4', dns4]) + if search4: + cmd.extend(['--search4', search4]) + else: + raise ValueError("Invalid mode '{}'. Expected 'dhcp4' or 'static4'.".format(mode)) + + log.info('qcow2 module: Executing command: {}'.format(' '.join(shlex.quote(arg) for arg in cmd))) + + try: + result = subprocess.run(cmd, capture_output=True, text=True, check=False) + ret = { + 'retcode': result.returncode, + 'stdout': result.stdout, + 'stderr': result.stderr + } + if result.returncode != 0: + log.error('qcow2 module: Script execution failed with return code {}: {}'.format(result.returncode, result.stderr)) + else: + log.info('qcow2 module: Script executed successfully.') + return ret + except Exception as e: + log.error('qcow2 module: An error occurred while executing the script: {}'.format(e)) + raise diff --git a/salt/hypervisor/init.sls b/salt/hypervisor/init.sls index e69de29bb..3fcd33934 100644 --- a/salt/hypervisor/init.sls +++ b/salt/hypervisor/init.sls @@ -0,0 +1,5 @@ +hypervisor_sbin: + file.recurse: + - name: /usr/sbin + - source: salt://hypervisor/tools/sbin + - file_mode: 744 diff --git a/salt/hypervisor/tools/sbin/modify_network.py b/salt/hypervisor/tools/sbin/so-qcow2-modify-network similarity index 72% rename from salt/hypervisor/tools/sbin/modify_network.py rename to salt/hypervisor/tools/sbin/so-qcow2-modify-network index de493e75c..a520871d1 100644 --- a/salt/hypervisor/tools/sbin/modify_network.py +++ b/salt/hypervisor/tools/sbin/so-qcow2-modify-network @@ -1,5 +1,10 @@ #!/usr/bin/python3 +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + import argparse import guestfs import re @@ -16,55 +21,39 @@ logger = logging.getLogger(__name__) NETWORK_CONFIG_DIR = "/etc/NetworkManager/system-connections" def validate_ip_address(ip_str, description="IP address"): - """ - Validates that the given string is a properly formatted IPv4 address or IPv4 interface. - """ try: - # Try to parse as IPv4 interface (e.g., "192.168.1.10/24") ipaddress.IPv4Interface(ip_str) except ValueError: try: - # Try to parse as IPv4 address (e.g., "192.168.1.10") ipaddress.IPv4Address(ip_str) except ValueError: raise ValueError(f"Invalid {description}: {ip_str}") def validate_dns_addresses(dns_str): - """ - Validates a comma-separated list of DNS server IP addresses. - """ dns_list = dns_str.split(',') for dns in dns_list: dns = dns.strip() validate_ip_address(dns, description="DNS server address") def validate_interface_name(interface_name): - """ - Validates that the network interface name contains only valid characters. - """ if not re.match(r'^[a-zA-Z0-9_\-]+$', interface_name): raise ValueError(f"Invalid interface name: {interface_name}") def update_ipv4_section(content, mode, ip=None, gateway=None, dns=None, search_domain=None): - """ - Updates the IPv4 section of the network configuration file with either DHCP or static settings. - """ config = configparser.ConfigParser(strict=False) - config.optionxform = str # Preserve case sensitivity + config.optionxform = str config.read_string(content) if 'ipv4' not in config.sections(): - # Handle missing [ipv4] section gracefully config.add_section('ipv4') - if mode == "dhcp": + if mode == "dhcp4": config.set('ipv4', 'method', 'auto') - # Remove static addresses, DNS settings, and search domains config.remove_option('ipv4', 'address1') config.remove_option('ipv4', 'addresses') config.remove_option('ipv4', 'dns') config.remove_option('ipv4', 'dns-search') - elif mode == "static": + elif mode == "static4": config.set('ipv4', 'method', 'manual') if ip and gateway: config.set('ipv4', 'address1', f"{ip},{gateway}") @@ -79,9 +68,8 @@ def update_ipv4_section(content, mode, ip=None, gateway=None, dns=None, search_d else: config.remove_option('ipv4', 'dns-search') else: - raise ValueError(f"Invalid mode '{mode}'. Expected 'dhcp' or 'static'.") + raise ValueError(f"Invalid mode '{mode}'. Expected 'dhcp4' or 'static4'.") - # Write the updated content back to a string output = StringIO() config.write(output, space_around_delimiters=False) updated_content = output.getvalue() @@ -89,29 +77,21 @@ def update_ipv4_section(content, mode, ip=None, gateway=None, dns=None, search_d return updated_content +# modify the network config file for the interface inside the qcow2 image def modify_network_config(image_path, interface, mode, ip=None, gateway=None, dns=None, search_domain=None): - """ - Modifies the network configuration file for the given interface inside the QCOW2 image. - """ - # Check for write permissions to the image file if not os.access(image_path, os.W_OK): raise PermissionError(f"Write permission denied for image file: {image_path}") - # Initialize the guestfs instance and add the image g = guestfs.GuestFS(python_return_dict=True) try: - g.set_network(False) # Disable network access if not needed - - # Disable SELinux relabeling - g.selinux = False # Correct way to disable SELinux relabeling - + g.set_network(False) + g.selinux = False g.add_drive_opts(image_path, format="qcow2") g.launch() except RuntimeError as e: raise RuntimeError(f"Failed to initialize GuestFS or launch appliance: {e}") try: - # Detect and mount the operating system os_list = g.inspect_os() if not os_list: raise RuntimeError(f"Unable to find any OS in {image_path}.") @@ -122,14 +102,11 @@ def modify_network_config(image_path, interface, mode, ip=None, gateway=None, dn except RuntimeError as e: raise RuntimeError(f"Failed to mount the filesystem: {e}") - # Check if NetworkManager configuration directory exists if not g.is_dir(NETWORK_CONFIG_DIR): raise FileNotFoundError(f"NetworkManager configuration directory not found in the image at {NETWORK_CONFIG_DIR}.") - # Path to the network configuration file for the given interface config_file_path = f"{NETWORK_CONFIG_DIR}/{interface}.nmconnection" - # Read the current configuration file try: file_content = g.read_file(config_file_path) current_content = file_content.decode('utf-8') @@ -138,16 +115,14 @@ def modify_network_config(image_path, interface, mode, ip=None, gateway=None, dn except UnicodeDecodeError: raise ValueError(f"Failed to decode the configuration file for {interface}.") - # Update the content based on the provided arguments updated_content = update_ipv4_section(current_content, mode, ip, gateway, dns, search_domain) - # Write the updated content back to the configuration file try: g.write(config_file_path, updated_content.encode('utf-8')) except RuntimeError as e: raise IOError(f"Failed to write updated configuration to {config_file_path}: {e}") - logger.info(f"Updated {interface} network configuration in {image_path} using {mode.upper()} mode.") + logger.info(f"so-qcow2-modify-network: Updated {interface} network configuration in {image_path} using {mode.upper()} mode.") except Exception as e: raise e @@ -156,14 +131,11 @@ def modify_network_config(image_path, interface, mode, ip=None, gateway=None, dn g.close() def parse_arguments(): - """ - Parses command-line arguments for the script. - """ parser = argparse.ArgumentParser(description="Modify IPv4 settings in a QCOW2 image for a specified network interface.") parser.add_argument("-I", "--image", required=True, help="Path to the QCOW2 image.") parser.add_argument("-i", "--interface", required=True, help="Network interface to modify (e.g., eth0).") group = parser.add_mutually_exclusive_group(required=True) - group.add_argument("--dhcp", action="store_true", help="Configure interface for DHCP (IPv4).") + group.add_argument("--dhcp4", action="store_true", help="Configure interface for DHCP (IPv4).") group.add_argument("--static4", action="store_true", help="Configure interface for static IPv4 settings.") parser.add_argument("--ip4", help="IPv4 address (e.g., 192.168.1.10/24). Required for static IPv4 configuration.") parser.add_argument("--gw4", help="IPv4 gateway (e.g., 192.168.1.1). Required for static IPv4 configuration.") @@ -172,44 +144,37 @@ def parse_arguments(): args = parser.parse_args() - # Validate arguments if args.static4: if not args.ip4 or not args.gw4: parser.error("Both --ip4 and --gw4 are required for static IPv4 configuration.") return args def main(): - """ - Main entry point for the script. - """ try: args = parse_arguments() validate_interface_name(args.interface) - # Validate mode - if args.dhcp: - mode = "dhcp" + if args.dhcp4: + mode = "dhcp4" elif args.static4: - mode = "static" + mode = "static4" if not args.ip4 or not args.gw4: raise ValueError("Both --ip4 and --gw4 are required for static IPv4 configuration.") - # Validate IP addresses validate_ip_address(args.ip4, description="IPv4 address") validate_ip_address(args.gw4, description="IPv4 gateway") if args.dns4: validate_dns_addresses(args.dns4) else: - raise ValueError("Either --dhcp or --static4 must be specified.") + raise ValueError("Either --dhcp4 or --static4 must be specified.") - # Modify the network configuration inside the image modify_network_config(args.image, args.interface, mode, args.ip4, args.gw4, args.dns4, args.search4) except KeyboardInterrupt: - logger.error("Operation cancelled by user.") + logger.error("so-qcow2-modify-network: Operation cancelled by user.") sys.exit(1) except Exception as e: - logger.error(f"An error occurred: {e}") + logger.error(f"so-qcow2-modify-network: An error occurred: {e}") sys.exit(1) if __name__ == "__main__": diff --git a/salt/libvirt/packages.sls b/salt/libvirt/packages.sls index 9b56c6f64..c79f42dd8 100644 --- a/salt/libvirt/packages.sls +++ b/salt/libvirt/packages.sls @@ -39,6 +39,6 @@ libvirt_python_wheel: libvirt_python_module: cmd.run: - - name: /opt/saltstack/salt/bin/python3.10 -m pip install --no-index --find-links=/opt/so/conf/libvirt/source-packages/libvirt-python libvirt-python + - name: /opt/saltstack/salt/bin/python3 -m pip install --no-index --find-links=/opt/so/conf/libvirt/source-packages/libvirt-python libvirt-python - onchanges: - file: libvirt_python_wheel diff --git a/salt/manager/tools/sbin/so-salt-cloud b/salt/manager/tools/sbin/so-salt-cloud index b34252730..c62519182 100644 --- a/salt/manager/tools/sbin/so-salt-cloud +++ b/salt/manager/tools/sbin/so-salt-cloud @@ -1,4 +1,4 @@ -#!/usr/bin/python3 +#!/opt/saltstack/salt/bin/python3 # Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one # or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at @@ -8,7 +8,26 @@ import argparse import subprocess import re +import sys import threading +import salt.client + +local = salt.client.LocalClient() + +import logging + +logger = logging.getLogger(__name__) +logger.setLevel(logging.INFO) + +file_handler = logging.FileHandler('/opt/so/log/salt/so-salt-cloud.log') +console_handler = logging.StreamHandler() + +formatter = logging.Formatter('%(asctime)s %(message)s') +file_handler.setFormatter(formatter) +console_handler.setFormatter(formatter) + +logger.addHandler(file_handler) +logger.addHandler(console_handler) def call_so_firewall_minion(ip, role): try: @@ -20,8 +39,16 @@ def call_so_firewall_minion(ip, role): text=True ) + # Read and log the output + for line in iter(process.stdout.readline, ''): + if line: + logger.info(line.rstrip('\n')) + + process.stdout.close() + process.wait() + except Exception as e: - print(f"An error occurred while calling the command: {e}") + logger.error(f"An error occurred while calling so-firewall-minion: {e}") def call_salt_cloud(profile, vm_name): try: @@ -38,38 +65,94 @@ def call_salt_cloud(profile, vm_name): ip_search_string = '[INFO ] Address =' ip_search_pattern = re.compile(re.escape(ip_search_string)) - # Continuously read the output + # continuously read the output from salt-cloud while True: # Read stdout line by line line = process.stdout.readline() if line: - print(line.rstrip('\n')) + logger.info(line.rstrip('\n')) if ip_search_pattern.search(line): parts = line.split("Address =") if len(parts) > 1: ip_address = parts[1].strip() - print("Extracted IP address:", ip_address) + logger.info(f"Extracted IP address: {ip_address}") # Create and start a thread to run so-firewall-minion - thread = threading.Thread(target=call_so_firewall_minion, args=(ip_address,role.upper())) + thread = threading.Thread(target=call_so_firewall_minion, args=(ip_address, role.upper())) thread.start() else: - print("No IP address found.") + logger.error("No IP address found.") + else: + # check if salt-cloud has terminated + if process.poll() is not None: + break - # Check if the process has terminated - elif process.poll() is not None: - # process finished - break + process.stdout.close() + process.wait() except Exception as e: - print(f"An error occurred while calling the command: {e}") + logger.error(f"An error occurred while calling salt-cloud: {e}") -if __name__ == "__main__": +# This function requires the cloud profile to be in the form: basedomain_hypervisorhostname. The profile name will be used to target the hypervisor. +def run_qcow2_modify_network_config(profile, mode, ip=None, gateway=None, dns=None, search_domain=None): + hv_name = profile.split('-')[1] + target = hv_name + "_*" + image = '/var/lib/libvirt/images/coreol9/coreol9.qcow2.MODIFIED' + interface = 'eth0' + try: + r = local.cmd(target, 'qcow2.modify_network_config', [ + 'image=' + image, + 'interface=' + interface, + 'mode=' + mode, + 'ip4=' + ip if ip else '', + 'gw4=' + gateway if gateway else '', + 'dns4=' + dns if dns else '', + 'search4=' + search_domain if search_domain else '' + ]) + logger.info(f'qcow2.modify_network_config: {r}') + except Exception as e: + logger.error(f"An error occurred while running qcow2.modify_network_config: {e}") + +def parse_arguments(): parser = argparse.ArgumentParser(description="Call salt-cloud and pass the profile and VM name to it.") parser.add_argument('-p', '--profile', type=str, required=True, help="The cloud profile to build the VM from.") parser.add_argument('vm_name', type=str, help="The name of the VM.") + group = parser.add_mutually_exclusive_group(required=True) + group.add_argument("--dhcp4", action="store_true", help="Configure interface for DHCP (IPv4).") + group.add_argument("--static4", action="store_true", help="Configure interface for static IPv4 settings.") + parser.add_argument("--ip4", help="IPv4 address (e.g., 192.168.1.10/24). Required for static IPv4 configuration.") + parser.add_argument("--gw4", help="IPv4 gateway (e.g., 192.168.1.1). Required for static IPv4 configuration.") + parser.add_argument("--dns4", help="Comma-separated list of IPv4 DNS servers (e.g., 8.8.8.8,8.8.4.4).") + parser.add_argument("--search4", help="DNS search domain for IPv4.") args = parser.parse_args() - call_salt_cloud(args.profile, args.vm_name) + if args.static4: + if not args.ip4 or not args.gw4: + parser.error("Both --ip4 and --gw4 are required for static IPv4 configuration.") + return args + +def main(): + try: + args = parse_arguments() + + if args.dhcp4: + mode = "dhcp4" + elif args.static4: + mode = "static4" + else: + mode = "dhcp4" # Default to DHCP if not specified + + run_qcow2_modify_network_config(args.profile, mode, args.ip4, args.gw4, args.dns4, args.search4) + call_salt_cloud(args.profile, args.vm_name) + + except KeyboardInterrupt: + logger.error("so-salt-cloud: Operation cancelled by user.") + sys.exit(1) + except Exception as e: + logger.error(f"so-salt-cloud: An error occurred: {e}") + sys.exit(1) + +if __name__ == "__main__": + main() From d0963baad4bba999a9b894dbb8607d0aff92927e Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Fri, 20 Sep 2024 14:50:08 -0400 Subject: [PATCH 035/315] update logging --- salt/hypervisor/init.sls | 4 ++ .../tools/sbin/so-qcow2-modify-network | 41 ++++++++++++++++--- 2 files changed, 39 insertions(+), 6 deletions(-) diff --git a/salt/hypervisor/init.sls b/salt/hypervisor/init.sls index 3fcd33934..3fa63bbcb 100644 --- a/salt/hypervisor/init.sls +++ b/salt/hypervisor/init.sls @@ -1,3 +1,7 @@ +hypervisor_log_dir: + file.directory: + - name: /opt/so/log/hypervisor + hypervisor_sbin: file.recurse: - name: /usr/sbin diff --git a/salt/hypervisor/tools/sbin/so-qcow2-modify-network b/salt/hypervisor/tools/sbin/so-qcow2-modify-network index a520871d1..7d4612730 100644 --- a/salt/hypervisor/tools/sbin/so-qcow2-modify-network +++ b/salt/hypervisor/tools/sbin/so-qcow2-modify-network @@ -5,6 +5,17 @@ # https://securityonion.net/license; you may not use this file except in compliance with the # Elastic License 2.0. +""" +Script to modify the NetworkManager config within a qcow2 image. + +Usage: + python so-qcow2-modify-network.py -v [-c ] [-m ] [-p ] + +Example: + python so-qcow2-modify-network.py -I path_to_image -i interface --static4 --ip4 192.168.1.10 --gw4 192.168.1.1 --dns4 192.168.1.1,8.8.8.8 --seearch4 example.local + python so-qcow2-modify-network.py -I path_to_image -i interface --dhcp4 +""" + import argparse import guestfs import re @@ -15,11 +26,28 @@ import ipaddress import configparser from io import StringIO -logging.basicConfig(level=logging.INFO) -logger = logging.getLogger(__name__) - NETWORK_CONFIG_DIR = "/etc/NetworkManager/system-connections" +def setup_logging(): + logger = logging.getLogger('so-qcow2-modify-network') + logger.setLevel(logging.INFO) + + # Create handlers + c_handler = logging.StreamHandler() + f_handler = logging.FileHandler('/opt/so/log/hypervisor/so-qcow2-modify-network.log') + c_handler.setLevel(logging.INFO) + f_handler.setLevel(logging.INFO) + + # Create formatter and add it to handlers + formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s') + c_handler.setFormatter(formatter) + f_handler.setFormatter(formatter) + + # Add handlers to the logger + logger.addHandler(c_handler) + logger.addHandler(f_handler) + return logger + def validate_ip_address(ip_str, description="IP address"): try: ipaddress.IPv4Interface(ip_str) @@ -122,7 +150,7 @@ def modify_network_config(image_path, interface, mode, ip=None, gateway=None, dn except RuntimeError as e: raise IOError(f"Failed to write updated configuration to {config_file_path}: {e}") - logger.info(f"so-qcow2-modify-network: Updated {interface} network configuration in {image_path} using {mode.upper()} mode.") + logger.info(f"Updated {interface} network configuration in {image_path} using {mode.upper()} mode.") except Exception as e: raise e @@ -151,6 +179,7 @@ def parse_arguments(): def main(): try: + logger = setup_logging() args = parse_arguments() validate_interface_name(args.interface) @@ -171,10 +200,10 @@ def main(): modify_network_config(args.image, args.interface, mode, args.ip4, args.gw4, args.dns4, args.search4) except KeyboardInterrupt: - logger.error("so-qcow2-modify-network: Operation cancelled by user.") + logger.error("Operation cancelled by user.") sys.exit(1) except Exception as e: - logger.error(f"so-qcow2-modify-network: An error occurred: {e}") + logger.error(f"An error occurred: {e}") sys.exit(1) if __name__ == "__main__": From 0b326370bd7cf5c7bca4f98e77a661717f0a2786 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Fri, 20 Sep 2024 14:51:36 -0400 Subject: [PATCH 036/315] script for modifying hardware of a vm --- .../tools/sbin/so-kvm-modify-hardware | 186 ++++++++++++++++++ 1 file changed, 186 insertions(+) create mode 100644 salt/hypervisor/tools/sbin/so-kvm-modify-hardware diff --git a/salt/hypervisor/tools/sbin/so-kvm-modify-hardware b/salt/hypervisor/tools/sbin/so-kvm-modify-hardware new file mode 100644 index 000000000..299cf8df0 --- /dev/null +++ b/salt/hypervisor/tools/sbin/so-kvm-modify-hardware @@ -0,0 +1,186 @@ +#!/usr/bin/env python3 + +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +""" +Script to modify hardware parameters of a KVM virtual machine. + +Usage: + python so-kvm-modify-hardware.py -v [-c ] [-m ] [-p ] + +Example: + python so-kvm-modify-hardware.py -v my_vm -c 4 -m 8192 -p 0000:00:1f.2 +""" + +import argparse +import logging +import sys +import time +import libvirt +import xml.etree.ElementTree as ET + +def setup_logging(): + logger = logging.getLogger('so-kvm-modify-hardware') + logger.setLevel(logging.INFO) + + # Create handlers + c_handler = logging.StreamHandler() + f_handler = logging.FileHandler('/opt/so/log/hypervisor/so-kvm-modify-hardware.log') + c_handler.setLevel(logging.INFO) + f_handler.setLevel(logging.INFO) + + # Create formatter and add it to handlers + formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s') + c_handler.setFormatter(formatter) + f_handler.setFormatter(formatter) + + # Add handlers to the logger + logger.addHandler(c_handler) + logger.addHandler(f_handler) + return logger + +def parse_arguments(): + parser = argparse.ArgumentParser(description='Modify hardware parameters of a KVM virtual machine.') + parser.add_argument('-v', '--vm', required=True, help='Name of the virtual machine to modify.') + parser.add_argument('-c', '--cpu', type=int, help='Number of virtual CPUs to assign.') + parser.add_argument('-m', '--memory', type=int, help='Amount of memory to assign in MiB.') + parser.add_argument('-p', '--pci', help='PCI hardware ID to passthrough to the VM (e.g., 0000:00:1f.2).') + args = parser.parse_args() + return args + +def stop_vm(conn, vm_name, logger): + try: + dom = conn.lookupByName(vm_name) + if dom.isActive(): + logger.info(f"Shutting down VM '{vm_name}'...") + dom.shutdown() + # Wait for the VM to shut down + while dom.isActive(): + time.sleep(1) + logger.info(f"VM '{vm_name}' has been stopped.") + else: + logger.info(f"VM '{vm_name}' is already stopped.") + return dom + except libvirt.libvirtError as e: + logger.error(f"Failed to stop VM '{vm_name}': {e}") + sys.exit(1) + +def modify_vm(dom, cpu_count, memory_amount, pci_id, logger): + try: + # Get the XML description of the VM + xml_desc = dom.XMLDesc() + root = ET.fromstring(xml_desc) + + # Modify CPU count + if cpu_count is not None: + vcpu_elem = root.find('./vcpu') + if vcpu_elem is not None: + vcpu_elem.text = str(cpu_count) + logger.info(f"Set CPU count to {cpu_count}.") + else: + logger.error("Could not find element in XML.") + sys.exit(1) + + # Modify memory amount + if memory_amount is not None: + memory_elem = root.find('./memory') + current_memory_elem = root.find('./currentMemory') + if memory_elem is not None and current_memory_elem is not None: + memory_elem.text = str(memory_amount * 1024) # Convert MiB to KiB + current_memory_elem.text = str(memory_amount * 1024) + logger.info(f"Set memory to {memory_amount} MiB.") + else: + logger.error("Could not find elements in XML.") + sys.exit(1) + + # Add PCI device passthrough + if pci_id is not None: + devices_elem = root.find('./devices') + if devices_elem is not None: + hostdev_elem = ET.SubElement(devices_elem, 'hostdev', attrib={ + 'mode': 'subsystem', + 'type': 'pci', + 'managed': 'yes' + }) + source_elem = ET.SubElement(hostdev_elem, 'source') + domain_id, bus_slot_func = pci_id.split(':') + bus_slot, function = bus_slot_func.split('.') + address_attrs = { + 'domain': f'0x{domain_id}', + 'bus': f'0x{bus_slot}', + 'slot': f'0x{bus_slot}', + 'function': f'0x{function}' + } + ET.SubElement(source_elem, 'address', attrib=address_attrs) + logger.info(f"Added PCI device passthrough for {pci_id}.") + else: + logger.error("Could not find element in XML.") + sys.exit(1) + + # Convert XML back to string + new_xml_desc = ET.tostring(root, encoding='unicode') + return new_xml_desc + except Exception as e: + logger.error(f"Failed to modify VM XML: {e}") + sys.exit(1) + +def redefine_vm(conn, new_xml_desc, logger): + try: + conn.defineXML(new_xml_desc) + logger.info("VM redefined with new hardware parameters.") + except libvirt.libvirtError as e: + logger.error(f"Failed to redefine VM: {e}") + sys.exit(1) + +def start_vm(dom, logger): + try: + dom.create() + logger.info("VM started successfully.") + except libvirt.libvirtError as e: + logger.error(f"Failed to start VM: {e}") + sys.exit(1) + +def main(): + try: + logger = setup_logging() + args = parse_arguments() + + vm_name = args.vm + cpu_count = args.cpu + memory_amount = args.memory + pci_id = args.pci + + # Connect to libvirt + try: + conn = libvirt.open(None) + except libvirt.libvirtError as e: + logger.error(f"Failed to open connection to libvirt: {e}") + sys.exit(1) + + # Stop VM if running + dom = stop_vm(conn, vm_name, logger) + + # Modify VM XML + new_xml_desc = modify_vm(dom, cpu_count, memory_amount, pci_id, logger) + + # Redefine VM + redefine_vm(conn, new_xml_desc, logger) + + # Start VM + dom = conn.lookupByName(vm_name) + start_vm(dom, logger) + + # Close connection + conn.close() + except KeyboardInterrupt: + logger.error("Operation cancelled by user.") + sys.exit(1) + except Exception as e: + logger.error(f"An error occurred: {e}") + sys.exit(1) + +if __name__ == '__main__': + main() From 50bd8448cc8910ba59a71c1ef21410df149a61b3 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Mon, 23 Sep 2024 10:13:22 -0400 Subject: [PATCH 037/315] add arg to start vm after modification --- salt/hypervisor/tools/sbin/so-kvm-modify-hardware | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/salt/hypervisor/tools/sbin/so-kvm-modify-hardware b/salt/hypervisor/tools/sbin/so-kvm-modify-hardware index 299cf8df0..7bbb500af 100644 --- a/salt/hypervisor/tools/sbin/so-kvm-modify-hardware +++ b/salt/hypervisor/tools/sbin/so-kvm-modify-hardware @@ -9,10 +9,10 @@ Script to modify hardware parameters of a KVM virtual machine. Usage: - python so-kvm-modify-hardware.py -v [-c ] [-m ] [-p ] + python so-kvm-modify-hardware.py -v [-c ] [-m ] [-p ] [-s] Example: - python so-kvm-modify-hardware.py -v my_vm -c 4 -m 8192 -p 0000:00:1f.2 + python so-kvm-modify-hardware.py -v my_vm -c 4 -m 8192 -p 0000:00:1f.2 -s """ import argparse @@ -48,6 +48,7 @@ def parse_arguments(): parser.add_argument('-c', '--cpu', type=int, help='Number of virtual CPUs to assign.') parser.add_argument('-m', '--memory', type=int, help='Amount of memory to assign in MiB.') parser.add_argument('-p', '--pci', help='PCI hardware ID to passthrough to the VM (e.g., 0000:00:1f.2).') + parser.add_argument('-s', '--start', action='store_true', help='Start the VM after modification.') args = parser.parse_args() return args @@ -152,6 +153,7 @@ def main(): cpu_count = args.cpu memory_amount = args.memory pci_id = args.pci + start_vm_flag = args.start # Connect to libvirt try: @@ -169,9 +171,12 @@ def main(): # Redefine VM redefine_vm(conn, new_xml_desc, logger) - # Start VM - dom = conn.lookupByName(vm_name) - start_vm(dom, logger) + # Start VM if -s or --start argument is provided + if start_vm_flag: + dom = conn.lookupByName(vm_name) + start_vm(dom, logger) + else: + logger.info("VM start flag not provided; VM will remain stopped.") # Close connection conn.close() From 9f76371449143134071d53e44e5b93ce161e8a00 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Tue, 1 Oct 2024 08:33:37 -0400 Subject: [PATCH 038/315] add libs --- salt/common/tools/sbin/so_logging_utils.py | 53 ++++++++++++++++ .../tools/sbin/so-kvm-modify-hardware | 61 ++++--------------- .../tools/sbin/so-qcow2-modify-network | 41 +++++-------- salt/hypervisor/tools/sbin/so_vm_utils.py | 60 ++++++++++++++++++ 4 files changed, 140 insertions(+), 75 deletions(-) create mode 100644 salt/common/tools/sbin/so_logging_utils.py create mode 100644 salt/hypervisor/tools/sbin/so_vm_utils.py diff --git a/salt/common/tools/sbin/so_logging_utils.py b/salt/common/tools/sbin/so_logging_utils.py new file mode 100644 index 000000000..dae734ac6 --- /dev/null +++ b/salt/common/tools/sbin/so_logging_utils.py @@ -0,0 +1,53 @@ +#!/usr/bin/python3 + +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +import logging +import os +import sys + +def setup_logging(logger_name, log_file_path, log_level=logging.INFO, format_str='%(asctime)s - %(levelname)s - %(message)s'): + """ + Sets up logging for a script. + + Parameters: + logger_name (str): The name of the logger. + log_file_path (str): The file path for the log file. + log_level (int): The logging level (e.g., logging.INFO, logging.DEBUG). + format_str (str): The format string for log messages. + + Returns: + logging.Logger: Configured logger object. + """ + logger = logging.getLogger(logger_name) + logger.setLevel(log_level) + + # Create directory for log file if it doesn't exist + log_file_dir = os.path.dirname(log_file_path) + if log_file_dir and not os.path.exists(log_file_dir): + try: + os.makedirs(log_file_dir) + except OSError as e: + print(f"Error creating directory {log_file_dir}: {e}") + sys.exit(1) + + # Create handlers + c_handler = logging.StreamHandler() + f_handler = logging.FileHandler(log_file_path) + c_handler.setLevel(log_level) + f_handler.setLevel(log_level) + + # Create formatter and add it to handlers + formatter = logging.Formatter(format_str) + c_handler.setFormatter(formatter) + f_handler.setFormatter(formatter) + + # Add handlers to the logger if they are not already added + if not logger.hasHandlers(): + logger.addHandler(c_handler) + logger.addHandler(f_handler) + + return logger diff --git a/salt/hypervisor/tools/sbin/so-kvm-modify-hardware b/salt/hypervisor/tools/sbin/so-kvm-modify-hardware index 7bbb500af..cf4c20c49 100644 --- a/salt/hypervisor/tools/sbin/so-kvm-modify-hardware +++ b/salt/hypervisor/tools/sbin/so-kvm-modify-hardware @@ -1,4 +1,4 @@ -#!/usr/bin/env python3 +#!/usr/bin/python3 # Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one # or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at @@ -16,31 +16,12 @@ Example: """ import argparse -import logging import sys -import time import libvirt +import logging import xml.etree.ElementTree as ET - -def setup_logging(): - logger = logging.getLogger('so-kvm-modify-hardware') - logger.setLevel(logging.INFO) - - # Create handlers - c_handler = logging.StreamHandler() - f_handler = logging.FileHandler('/opt/so/log/hypervisor/so-kvm-modify-hardware.log') - c_handler.setLevel(logging.INFO) - f_handler.setLevel(logging.INFO) - - # Create formatter and add it to handlers - formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s') - c_handler.setFormatter(formatter) - f_handler.setFormatter(formatter) - - # Add handlers to the logger - logger.addHandler(c_handler) - logger.addHandler(f_handler) - return logger +from so_vm_utils import start_vm, stop_vm +from so_logging_utils import setup_logging def parse_arguments(): parser = argparse.ArgumentParser(description='Modify hardware parameters of a KVM virtual machine.') @@ -52,23 +33,6 @@ def parse_arguments(): args = parser.parse_args() return args -def stop_vm(conn, vm_name, logger): - try: - dom = conn.lookupByName(vm_name) - if dom.isActive(): - logger.info(f"Shutting down VM '{vm_name}'...") - dom.shutdown() - # Wait for the VM to shut down - while dom.isActive(): - time.sleep(1) - logger.info(f"VM '{vm_name}' has been stopped.") - else: - logger.info(f"VM '{vm_name}' is already stopped.") - return dom - except libvirt.libvirtError as e: - logger.error(f"Failed to stop VM '{vm_name}': {e}") - sys.exit(1) - def modify_vm(dom, cpu_count, memory_amount, pci_id, logger): try: # Get the XML description of the VM @@ -136,17 +100,8 @@ def redefine_vm(conn, new_xml_desc, logger): logger.error(f"Failed to redefine VM: {e}") sys.exit(1) -def start_vm(dom, logger): - try: - dom.create() - logger.info("VM started successfully.") - except libvirt.libvirtError as e: - logger.error(f"Failed to start VM: {e}") - sys.exit(1) - def main(): try: - logger = setup_logging() args = parse_arguments() vm_name = args.vm @@ -155,6 +110,14 @@ def main(): pci_id = args.pci start_vm_flag = args.start + # Set up logging using the so_logging_utils library + logger = setup_logging( + logger_name='so-kvm-modify-hardware', + log_file_path='/opt/so/log/hypervisor/so-kvm-modify-hardware.log', + log_level=logging.INFO, + format_str='%(asctime)s - %(levelname)s - %(message)s' + ) + # Connect to libvirt try: conn = libvirt.open(None) diff --git a/salt/hypervisor/tools/sbin/so-qcow2-modify-network b/salt/hypervisor/tools/sbin/so-qcow2-modify-network index 7d4612730..6ec83d3e3 100644 --- a/salt/hypervisor/tools/sbin/so-qcow2-modify-network +++ b/salt/hypervisor/tools/sbin/so-qcow2-modify-network @@ -6,14 +6,15 @@ # Elastic License 2.0. """ -Script to modify the NetworkManager config within a qcow2 image. +Script to modify the NetworkManager config within a QCOW2 image. Usage: - python so-qcow2-modify-network.py -v [-c ] [-m ] [-p ] + python so-qcow2-modify-network.py -I -i (--dhcp4 | --static4 --ip4 --gw4 ) [--dns4 ] [--search4 ] -Example: - python so-qcow2-modify-network.py -I path_to_image -i interface --static4 --ip4 192.168.1.10 --gw4 192.168.1.1 --dns4 192.168.1.1,8.8.8.8 --seearch4 example.local - python so-qcow2-modify-network.py -I path_to_image -i interface --dhcp4 +Examples: + python so-qcow2-modify-network.py -I path_to_image -i eth0 --static4 --ip4 192.168.1.10/24 --gw4 192.168.1.1 --dns4 192.168.1.1,8.8.8.8 --search4 example.local + + python so-qcow2-modify-network.py -I path_to_image -i eth0 --dhcp4 """ import argparse @@ -25,29 +26,11 @@ import os import ipaddress import configparser from io import StringIO +from so_logging_utils import setup_logging + NETWORK_CONFIG_DIR = "/etc/NetworkManager/system-connections" -def setup_logging(): - logger = logging.getLogger('so-qcow2-modify-network') - logger.setLevel(logging.INFO) - - # Create handlers - c_handler = logging.StreamHandler() - f_handler = logging.FileHandler('/opt/so/log/hypervisor/so-qcow2-modify-network.log') - c_handler.setLevel(logging.INFO) - f_handler.setLevel(logging.INFO) - - # Create formatter and add it to handlers - formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s') - c_handler.setFormatter(formatter) - f_handler.setFormatter(formatter) - - # Add handlers to the logger - logger.addHandler(c_handler) - logger.addHandler(f_handler) - return logger - def validate_ip_address(ip_str, description="IP address"): try: ipaddress.IPv4Interface(ip_str) @@ -179,7 +162,13 @@ def parse_arguments(): def main(): try: - logger = setup_logging() + # Set up logging using the so_logging_utils library + logger = setup_logging( + logger_name='so-qcow2-modify-network', + log_file_path='/opt/so/log/hypervisor/so-qcow2-modify-network.log', + log_level=logging.INFO, + format_str='%(asctime)s - %(levelname)s - %(message)s' + ) args = parse_arguments() validate_interface_name(args.interface) diff --git a/salt/hypervisor/tools/sbin/so_vm_utils.py b/salt/hypervisor/tools/sbin/so_vm_utils.py new file mode 100644 index 000000000..a6820b885 --- /dev/null +++ b/salt/hypervisor/tools/sbin/so_vm_utils.py @@ -0,0 +1,60 @@ +#!/usr/bin/python3 + +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +import sys +import time +import libvirt +import logging + +def stop_vm(conn, vm_name, logger): + """ + Stops the specified virtual machine if it is running. + + Parameters: + conn (libvirt.virConnect): The libvirt connection object. + vm_name (str): The name of the virtual machine. + logger (logging.Logger): The logger object. + + Returns: + libvirt.virDomain: The domain object of the VM. + + Raises: + SystemExit: If the VM cannot be found or an error occurs. + """ + try: + dom = conn.lookupByName(vm_name) + if dom.isActive(): + logger.info(f"Shutting down VM '{vm_name}'...") + dom.shutdown() + # Wait for the VM to shut down + while dom.isActive(): + time.sleep(1) + logger.info(f"VM '{vm_name}' has been stopped.") + else: + logger.info(f"VM '{vm_name}' is already stopped.") + return dom + except libvirt.libvirtError as e: + logger.error(f"Failed to stop VM '{vm_name}': {e}") + sys.exit(1) + +def start_vm(dom, logger): + """ + Starts the specified virtual machine. + + Parameters: + dom (libvirt.virDomain): The domain object of the VM. + logger (logging.Logger): The logger object. + + Raises: + SystemExit: If the VM cannot be started. + """ + try: + dom.create() + logger.info(f"VM '{dom.name()}' started successfully.") + except libvirt.libvirtError as e: + logger.error(f"Failed to start VM '{dom.name()}': {e}") + sys.exit(1) From 0b0ff62bc58931157d87722f21e6a1a995d7d27b Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Tue, 8 Oct 2024 09:40:44 -0400 Subject: [PATCH 039/315] update comments --- salt/_modules/qcow2.py | 6 +++--- salt/manager/tools/sbin/so-salt-cloud | 12 ++++++++++++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/salt/_modules/qcow2.py b/salt/_modules/qcow2.py index 56ccb36a0..8a4f89b59 100644 --- a/salt/_modules/qcow2.py +++ b/salt/_modules/qcow2.py @@ -23,7 +23,7 @@ def modify_network_config(image, interface, mode, ip4=None, gw4=None, dns4=None, :param image: Path to the QCOW2 image. :param interface: Network interface to modify (e.g., 'eth0'). :param mode: 'dhcp4' or 'static4'. - :param ip4: IPv4 address with CIDR notation (e.g., '192.168.1.100/24'). Required for static configuration. + :param ip4: IPv4 address with CIDR notation (e.g., '192.168.1.10/24'). Required for static configuration. :param gw4: IPv4 gateway (e.g., '192.168.1.1'). Required for static configuration. :param dns4: Comma-separated list of IPv4 DNS servers (e.g., '8.8.8.8,8.8.4.4'). :param search4: DNS search domain for IPv4. @@ -34,11 +34,11 @@ def modify_network_config(image, interface, mode, ip4=None, gw4=None, dns4=None, .. code-block:: bash - salt '*' qcow2.modify_network_config image='/path/to/image.qcow2' interface='eth0' mode='static4' ip4='192.168.1.100/24' gw4='192.168.1.1' dns4='8.8.8.8,8.8.4.4' search4='example.com' + salt '*' qcow2.modify_network_config image='/path/to/image.qcow2' interface='eth0' mode='static4' ip4='192.168.1.10/24' gw4='192.168.1.1' dns4='8.8.8.8,8.8.4.4' search4='example.local' ''' - cmd = ['/usr/sbin/so-qcow2-modify-network.py', '-I', image, '-i', interface] + cmd = ['/usr/sbin/so-qcow2-modify-network', '-I', image, '-i', interface] if mode.lower() == 'dhcp4': cmd.append('--dhcp4') diff --git a/salt/manager/tools/sbin/so-salt-cloud b/salt/manager/tools/sbin/so-salt-cloud index c62519182..600d7bb8e 100644 --- a/salt/manager/tools/sbin/so-salt-cloud +++ b/salt/manager/tools/sbin/so-salt-cloud @@ -5,6 +5,18 @@ # https://securityonion.net/license; you may not use this file except in compliance with the # Elastic License 2.0. +""" +Script to assist with salt-cloud VM provisioning. This is only intended to work with a libvirt salt-cloud provider. + +Usage: + python so-salt-cloud -p (--dhcp4 | --static4 --ip4 --gw4 ) [--dns4 ] [--search4 ] + +Examples: + python so-salt-cloud -p core-hype1 hostname_nodetype --static4 --ip4 192.168.1.10/24 --gw4 192.168.1.1 --dns4 192.168.1.1,192.168.1.2 --search4 example.local + + python so-salt-cloud -p core-hype1 hostname_nodetype --dhcp4 +""" + import argparse import subprocess import re From dcc173897823499b4d627b02c55c2af48796ddc5 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Fri, 11 Oct 2024 10:46:07 -0400 Subject: [PATCH 040/315] dynamic annotations --- salt/hypervisor/defaults.sls | 138 ++++++++++-------- salt/hypervisor/pillar.map.jinja | 29 ++++ salt/hypervisor/pillar.sls | 0 salt/hypervisor/soc_hypervisor.yaml | 35 +++++ .../hypervisor/hypervisor.yaml | 0 .../dynamic_annotations/hypervisor/init.sls | 0 .../hypervisor/soc_hypervisor.yaml.jinja | 0 7 files changed, 142 insertions(+), 60 deletions(-) create mode 100644 salt/hypervisor/pillar.map.jinja create mode 100644 salt/hypervisor/pillar.sls create mode 100644 salt/hypervisor/soc_hypervisor.yaml create mode 100644 salt/soc/dynamic_annotations/hypervisor/hypervisor.yaml create mode 100644 salt/soc/dynamic_annotations/hypervisor/init.sls create mode 100644 salt/soc/dynamic_annotations/hypervisor/soc_hypervisor.yaml.jinja diff --git a/salt/hypervisor/defaults.sls b/salt/hypervisor/defaults.sls index d1feb6d34..5157e4aed 100644 --- a/salt/hypervisor/defaults.sls +++ b/salt/hypervisor/defaults.sls @@ -1,61 +1,79 @@ hypervisor: - model1: - hardware: - cpu: - total: 128 - free: 128 - memory: - total: 128 - free: 128 - disks: - free: - 3: pci_0000_c7_00_0 - 4: pci_0000_c8_00_0 - claimed: - 1: pci_0000_c5_00_0 - 2: pci_0000_c6_00_0 - copper: - free: - 1: pci_0000_c4_00_0 - 2: pci_0000_c4_00_1 - 3: pci_0000_c4_00_2 - 4: pci_0000_c4_00_3 - claimed: {} - sfp: - free: - 5: pci_0000_41_00_0 - 6: pci_0000_41_00_1 - claimed: {} - model2: - hardware: - cpu: - total: 128 - free: 128 - memory: - total: 512 - free: 512 - disks: - free: - 3: pci_0000_c8_00_0 - 4: pci_0000_c9_00_0 - 5: pci_0000_c10_00_0 - 6: pci_0000_c11_00_0 - claimed: - 1: pci_0000_c6_00_0 - 2: pci_0000_c7_00_0 - copper: - free: - 1: pci_0000_c4_00_0 - 2: pci_0000_c4_00_1 - 3: pci_0000_c4_00_2 - 4: pci_0000_c4_00_3 - 5: pci_0000_c5_00_0 - 6: pci_0000_c5_00_1 - 7: pci_0000_c5_00_2 - 8: pci_0000_c5_00_3 - claimed: {} - sfp: - free: - 9: pci_0000_41_00_0 - 10: pci_0000_41_00_1 - claimed: {} + nodes: + jpphype1: + add_guest: [] + guests: + - sen1_sensor: + cpu: 2 + mem: 8192 + + jpphype1: + guests: + sen1_sensor: + hardware: + cpu: 2 + mem: 8192 + + + + models: + model1: + hardware: + cpu: + total: 128 + free: 128 + memory: + total: 128 + free: 128 + disks: + free: + 3: pci_0000_c7_00_0 + 4: pci_0000_c8_00_0 + claimed: + 1: pci_0000_c5_00_0 + 2: pci_0000_c6_00_0 + copper: + free: + 1: pci_0000_c4_00_0 + 2: pci_0000_c4_00_1 + 3: pci_0000_c4_00_2 + 4: pci_0000_c4_00_3 + claimed: {} + sfp: + free: + 5: pci_0000_41_00_0 + 6: pci_0000_41_00_1 + claimed: {} + model2: + hardware: + cpu: + total: 128 + free: 128 + memory: + total: 512 + free: 512 + disks: + free: + 3: pci_0000_c8_00_0 + 4: pci_0000_c9_00_0 + 5: pci_0000_c10_00_0 + 6: pci_0000_c11_00_0 + claimed: + 1: pci_0000_c6_00_0 + 2: pci_0000_c7_00_0 + copper: + free: + 1: pci_0000_c4_00_0 + 2: pci_0000_c4_00_1 + 3: pci_0000_c4_00_2 + 4: pci_0000_c4_00_3 + 5: pci_0000_c5_00_0 + 6: pci_0000_c5_00_1 + 7: pci_0000_c5_00_2 + 8: pci_0000_c5_00_3 + claimed: {} + sfp: + free: + 9: pci_0000_41_00_0 + 10: pci_0000_41_00_1 + claimed: {} diff --git a/salt/hypervisor/pillar.map.jinja b/salt/hypervisor/pillar.map.jinja new file mode 100644 index 000000000..3b6c275a3 --- /dev/null +++ b/salt/hypervisor/pillar.map.jinja @@ -0,0 +1,29 @@ +{% set HYPERVISORHOSTS = salt['pillar.get']('hypervisor:hosts', {}) %} + +{% import_yaml 'setup/virt/sensor.yaml' as SENSOR %} +{% import_yaml 'setup/virt/searchnode.yaml' as SEARCHNODE %} + +{% set vars = { + 'sensor': SENSOR, + 'searchnode': SEARCHNODE +} %} + +{% for host, guestDetails in HYPERVISORHOSTS.items() %} +{% if guestDetails['add_guest'] | length > 0 %} +{% for newGuest in guestDetails['add_guest'] %} +{% set indx = guestDetails['add_guest'].index(newGuest) %} +{% do guestDetails['add_guest'].pop(indx) %} +{% set NODETYPE = newGuest.split('_') | last %} +{% do guestDetails['guests'].update({ + newGuest: { + 'cpu': vars[NODETYPE].CPU, + 'memory': vars[NODETYPE].MEMORY, + 'disk': vars[NODETYPE].DISKS, + 'copper': vars[NODETYPE].COPPER, + 'sfp': vars[NODETYPE].SFP + } +}) %} + +{% endfor %} +{% endif %} +{% endfor %} diff --git a/salt/hypervisor/pillar.sls b/salt/hypervisor/pillar.sls new file mode 100644 index 000000000..e69de29bb diff --git a/salt/hypervisor/soc_hypervisor.yaml b/salt/hypervisor/soc_hypervisor.yaml new file mode 100644 index 000000000..8865b27ab --- /dev/null +++ b/salt/hypervisor/soc_hypervisor.yaml @@ -0,0 +1,35 @@ +hypervisor: + hosts: + defaultHost: + add_guest: + description: List of hypervisor nodes. + forcedType: "[]string" + global: True + multiline: True + guests: + defaultGuest: + copper: + description: Copper nics + forcedType: "[]int" + global: True + multiline: True + sfp: + description: sfp nics + forcedType: "[]int" + global: True + multiline: True + disks: + description: disk + forcedType: "[]int" + global: True + multiline: True + cpu: + description: cpu + forcedType: int + global: True + multiline: True + memory: + description: mem + forcedType: int + global: True + multiline: True diff --git a/salt/soc/dynamic_annotations/hypervisor/hypervisor.yaml b/salt/soc/dynamic_annotations/hypervisor/hypervisor.yaml new file mode 100644 index 000000000..e69de29bb diff --git a/salt/soc/dynamic_annotations/hypervisor/init.sls b/salt/soc/dynamic_annotations/hypervisor/init.sls new file mode 100644 index 000000000..e69de29bb diff --git a/salt/soc/dynamic_annotations/hypervisor/soc_hypervisor.yaml.jinja b/salt/soc/dynamic_annotations/hypervisor/soc_hypervisor.yaml.jinja new file mode 100644 index 000000000..e69de29bb From 047658537052b0e7df68ef3402d740366c4c69c9 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Tue, 22 Oct 2024 09:03:02 -0400 Subject: [PATCH 041/315] dynamic annotations --- salt/hypervisor/pillar.sls | 5 +++ .../hypervisor/hypervisor.yaml | 35 +++++++++++++++++++ .../dynamic_annotations/hypervisor/init.sls | 5 +++ .../hypervisor/soc_hypervisor.yaml.jinja | 12 +++++++ 4 files changed, 57 insertions(+) diff --git a/salt/hypervisor/pillar.sls b/salt/hypervisor/pillar.sls index e69de29bb..92c1cbfec 100644 --- a/salt/hypervisor/pillar.sls +++ b/salt/hypervisor/pillar.sls @@ -0,0 +1,5 @@ +soc_hypervisor_pillar: + file.managed: + - name: /opt/so/saltstack/local/pillar/hypervisor/soc_hypervisor.sls + - source: salt://hypervisor/pillar.map.jinja + - template: jinja diff --git a/salt/soc/dynamic_annotations/hypervisor/hypervisor.yaml b/salt/soc/dynamic_annotations/hypervisor/hypervisor.yaml index e69de29bb..f52779e9c 100644 --- a/salt/soc/dynamic_annotations/hypervisor/hypervisor.yaml +++ b/salt/soc/dynamic_annotations/hypervisor/hypervisor.yaml @@ -0,0 +1,35 @@ +hypervisor: + hosts: + defaultHost: + add_guest: + description: Add a new guest to the hypervisor. + forcedType: "[]string" + global: True + multiline: True + guests: + defaultGuest: + copper: + description: Copper nics + forcedType: "[]int" + global: True + multiline: True + sfp: + description: sfp nics + forcedType: string + global: True + multiline: True + disks: + description: disk + forcedType: "[]int" + global: True + multiline: True + cpu: + description: cpu + forcedType: int + global: True + multiline: True + memory: + description: mem + forcedType: int + global: True + multiline: True diff --git a/salt/soc/dynamic_annotations/hypervisor/init.sls b/salt/soc/dynamic_annotations/hypervisor/init.sls index e69de29bb..74db9d9a2 100644 --- a/salt/soc/dynamic_annotations/hypervisor/init.sls +++ b/salt/soc/dynamic_annotations/hypervisor/init.sls @@ -0,0 +1,5 @@ +hypervisor_annotation: + file.managed: + - name: /opt/so/saltstack/default/salt/hypervisor/soc_hypervisor.yaml + - source: salt://soc/dynamic_annotations/hypervisor/soc_hypervisor.yaml.jinja + - template: jinja diff --git a/salt/soc/dynamic_annotations/hypervisor/soc_hypervisor.yaml.jinja b/salt/soc/dynamic_annotations/hypervisor/soc_hypervisor.yaml.jinja index e69de29bb..f96b3ea13 100644 --- a/salt/soc/dynamic_annotations/hypervisor/soc_hypervisor.yaml.jinja +++ b/salt/soc/dynamic_annotations/hypervisor/soc_hypervisor.yaml.jinja @@ -0,0 +1,12 @@ +{% import_yaml 'soc/dynamic_annotations/hypervisor/hypervisor.yaml' as ANNOTATION %} +{% set HYPERVISORS = salt['pillar.get']('hypervisor:nodes', {}) %} + +{% set TEMPLATE = ANNOTATION.hypervisor.hosts.pop('defaultHost') %} +{# remove defaultGuest so that it is not shown in Grid Configuration UI #} +{% do TEMPLATE['guests'].pop('defaultGuest') %} + +{% for hypervisor in HYPERVISORS.hypervisor %} +{% do ANNOTATION.hypervisor.hosts.update({hypervisor: TEMPLATE}) %} +{% endfor %} + +{{ ANNOTATION | yaml(False) }} From c64a05f2ff914b632e0642b0b0697a0de6f3d2ee Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Tue, 29 Oct 2024 10:20:31 -0400 Subject: [PATCH 042/315] dynamic annotations --- .../dynamic_annotations/hypervisor/add_node | 11 +++++++++ .../hypervisor/hypervisor.yaml | 11 ++++++--- .../dynamic_annotations/hypervisor/init.sls | 23 +++++++++++++++++++ .../dynamic_annotations/hypervisor/map.jinja | 1 + .../hypervisor/soc_hypervisor.yaml.jinja | 7 +++--- 5 files changed, 47 insertions(+), 6 deletions(-) create mode 100644 salt/soc/dynamic_annotations/hypervisor/add_node create mode 100644 salt/soc/dynamic_annotations/hypervisor/map.jinja diff --git a/salt/soc/dynamic_annotations/hypervisor/add_node b/salt/soc/dynamic_annotations/hypervisor/add_node new file mode 100644 index 000000000..498db1460 --- /dev/null +++ b/salt/soc/dynamic_annotations/hypervisor/add_node @@ -0,0 +1,11 @@ +hostname: +network_mode: +ip4: +gw4: +dns4: +sarch4: +cpu: +memory: +disk: +copper: +sfp: diff --git a/salt/soc/dynamic_annotations/hypervisor/hypervisor.yaml b/salt/soc/dynamic_annotations/hypervisor/hypervisor.yaml index f52779e9c..0ec53ff30 100644 --- a/salt/soc/dynamic_annotations/hypervisor/hypervisor.yaml +++ b/salt/soc/dynamic_annotations/hypervisor/hypervisor.yaml @@ -1,9 +1,14 @@ hypervisor: hosts: defaultHost: - add_guest: - description: Add a new guest to the hypervisor. - forcedType: "[]string" + add_searchnode: + description: Add a new searchnode to the hypervisor. + file: True + global: True + multiline: True + add_sensor: + description: Add a new sensor to the hypervisor. + file: True global: True multiline: True guests: diff --git a/salt/soc/dynamic_annotations/hypervisor/init.sls b/salt/soc/dynamic_annotations/hypervisor/init.sls index 74db9d9a2..8c857e72f 100644 --- a/salt/soc/dynamic_annotations/hypervisor/init.sls +++ b/salt/soc/dynamic_annotations/hypervisor/init.sls @@ -1,5 +1,28 @@ +{% from 'soc/dynamic_annotations/hypervisor/map.jinja' import HYPERVISORS %} + hypervisor_annotation: file.managed: - name: /opt/so/saltstack/default/salt/hypervisor/soc_hypervisor.yaml - source: salt://soc/dynamic_annotations/hypervisor/soc_hypervisor.yaml.jinja - template: jinja + - defaults: + HYPERVISORS: {{ HYPERVISORS }} + +{% for role in HYPERVISORS %} +{% for hypervisor in HYPERVISORS[role].keys() %} +hypervisor_host_directory_{{hypervisor}}: + file.directory: + - name: /opt/so/saltstack/local/salt/hypervisor/hosts/{{hypervisor}} + - makedirs: True + +add_searchnode_file_{{hypervisor}}: + file.managed: + - name: /opt/so/saltstack/local/salt/hypervisor/hosts/{{hypervisor}}/add_searchnode + - source: salt://soc/dynamic_annotations/hypervisor/add_node + +add_sensor_file_{{hypervisor}}: + file.managed: + - name: /opt/so/saltstack/local/salt/hypervisor/hosts/{{hypervisor}}/add_sensor + - source: salt://soc/dynamic_annotations/hypervisor/add_node +{% endfor %} +{% endfor %} diff --git a/salt/soc/dynamic_annotations/hypervisor/map.jinja b/salt/soc/dynamic_annotations/hypervisor/map.jinja new file mode 100644 index 000000000..b14a437b5 --- /dev/null +++ b/salt/soc/dynamic_annotations/hypervisor/map.jinja @@ -0,0 +1 @@ +{% set HYPERVISORS = salt['pillar.get']('hypervisor:nodes', {}) %} diff --git a/salt/soc/dynamic_annotations/hypervisor/soc_hypervisor.yaml.jinja b/salt/soc/dynamic_annotations/hypervisor/soc_hypervisor.yaml.jinja index f96b3ea13..c9dd8200d 100644 --- a/salt/soc/dynamic_annotations/hypervisor/soc_hypervisor.yaml.jinja +++ b/salt/soc/dynamic_annotations/hypervisor/soc_hypervisor.yaml.jinja @@ -1,12 +1,13 @@ {% import_yaml 'soc/dynamic_annotations/hypervisor/hypervisor.yaml' as ANNOTATION %} -{% set HYPERVISORS = salt['pillar.get']('hypervisor:nodes', {}) %} {% set TEMPLATE = ANNOTATION.hypervisor.hosts.pop('defaultHost') %} {# remove defaultGuest so that it is not shown in Grid Configuration UI #} {% do TEMPLATE['guests'].pop('defaultGuest') %} -{% for hypervisor in HYPERVISORS.hypervisor %} -{% do ANNOTATION.hypervisor.hosts.update({hypervisor: TEMPLATE}) %} +{% for role in HYPERVISORS %} +{% for hypervisor in HYPERVISORS[role].keys() %} +{% do ANNOTATION.hypervisor.hosts.update({hypervisor: TEMPLATE}) %} +{% endfor %} {% endfor %} {{ ANNOTATION | yaml(False) }} From 3394588602508bcde6e3c58b018b901f027363fd Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Tue, 29 Oct 2024 10:56:18 -0400 Subject: [PATCH 043/315] sync hypervisor state remote to local --- salt/hypervisor/defaults.brainstorm.yaml | 0 salt/hypervisor/defaults.sls | 79 ------------------- salt/hypervisor/defaults.yaml | 62 +++++++++++++++ salt/hypervisor/soc_hypervisor.yaml | 46 +++-------- .../tools/sbin/so-kvm-modify-hardware | 16 ++-- .../tools/sbin/so-qcow2-modify-network | 18 ++--- 6 files changed, 92 insertions(+), 129 deletions(-) create mode 100644 salt/hypervisor/defaults.brainstorm.yaml delete mode 100644 salt/hypervisor/defaults.sls create mode 100644 salt/hypervisor/defaults.yaml diff --git a/salt/hypervisor/defaults.brainstorm.yaml b/salt/hypervisor/defaults.brainstorm.yaml new file mode 100644 index 000000000..e69de29bb diff --git a/salt/hypervisor/defaults.sls b/salt/hypervisor/defaults.sls deleted file mode 100644 index 5157e4aed..000000000 --- a/salt/hypervisor/defaults.sls +++ /dev/null @@ -1,79 +0,0 @@ -hypervisor: - nodes: - jpphype1: - add_guest: [] - guests: - - sen1_sensor: - cpu: 2 - mem: 8192 - - jpphype1: - guests: - sen1_sensor: - hardware: - cpu: 2 - mem: 8192 - - - - models: - model1: - hardware: - cpu: - total: 128 - free: 128 - memory: - total: 128 - free: 128 - disks: - free: - 3: pci_0000_c7_00_0 - 4: pci_0000_c8_00_0 - claimed: - 1: pci_0000_c5_00_0 - 2: pci_0000_c6_00_0 - copper: - free: - 1: pci_0000_c4_00_0 - 2: pci_0000_c4_00_1 - 3: pci_0000_c4_00_2 - 4: pci_0000_c4_00_3 - claimed: {} - sfp: - free: - 5: pci_0000_41_00_0 - 6: pci_0000_41_00_1 - claimed: {} - model2: - hardware: - cpu: - total: 128 - free: 128 - memory: - total: 512 - free: 512 - disks: - free: - 3: pci_0000_c8_00_0 - 4: pci_0000_c9_00_0 - 5: pci_0000_c10_00_0 - 6: pci_0000_c11_00_0 - claimed: - 1: pci_0000_c6_00_0 - 2: pci_0000_c7_00_0 - copper: - free: - 1: pci_0000_c4_00_0 - 2: pci_0000_c4_00_1 - 3: pci_0000_c4_00_2 - 4: pci_0000_c4_00_3 - 5: pci_0000_c5_00_0 - 6: pci_0000_c5_00_1 - 7: pci_0000_c5_00_2 - 8: pci_0000_c5_00_3 - claimed: {} - sfp: - free: - 9: pci_0000_41_00_0 - 10: pci_0000_41_00_1 - claimed: {} diff --git a/salt/hypervisor/defaults.yaml b/salt/hypervisor/defaults.yaml new file mode 100644 index 000000000..4a762e677 --- /dev/null +++ b/salt/hypervisor/defaults.yaml @@ -0,0 +1,62 @@ +hypervisor: + nodes: [] + model1: + hardware: + cpu: + total: 128 + free: 128 + memory: + total: 128 + free: 128 + disks: + free: + 3: pci_0000_c7_00_0 + 4: pci_0000_c8_00_0 + claimed: + 1: pci_0000_c5_00_0 + 2: pci_0000_c6_00_0 + copper: + free: + 1: pci_0000_c4_00_0 + 2: pci_0000_c4_00_1 + 3: pci_0000_c4_00_2 + 4: pci_0000_c4_00_3 + claimed: {} + sfp: + free: + 5: pci_0000_41_00_0 + 6: pci_0000_41_00_1 + claimed: {} + model2: + hardware: + cpu: + total: 128 + free: 128 + memory: + total: 512 + free: 512 + disks: + free: + 3: pci_0000_c8_00_0 + 4: pci_0000_c9_00_0 + 5: pci_0000_c10_00_0 + 6: pci_0000_c11_00_0 + claimed: + 1: pci_0000_c6_00_0 + 2: pci_0000_c7_00_0 + copper: + free: + 1: pci_0000_c4_00_0 + 2: pci_0000_c4_00_1 + 3: pci_0000_c4_00_2 + 4: pci_0000_c4_00_3 + 5: pci_0000_c5_00_0 + 6: pci_0000_c5_00_1 + 7: pci_0000_c5_00_2 + 8: pci_0000_c5_00_3 + claimed: {} + sfp: + free: + 9: pci_0000_41_00_0 + 10: pci_0000_41_00_1 + claimed: {} diff --git a/salt/hypervisor/soc_hypervisor.yaml b/salt/hypervisor/soc_hypervisor.yaml index 8865b27ab..571b1661d 100644 --- a/salt/hypervisor/soc_hypervisor.yaml +++ b/salt/hypervisor/soc_hypervisor.yaml @@ -1,35 +1,15 @@ +# This is the start of an example of what this file will look like. It will be generated by Salt, so this yaml file is not used by Salt. hypervisor: hosts: - defaultHost: - add_guest: - description: List of hypervisor nodes. - forcedType: "[]string" - global: True - multiline: True - guests: - defaultGuest: - copper: - description: Copper nics - forcedType: "[]int" - global: True - multiline: True - sfp: - description: sfp nics - forcedType: "[]int" - global: True - multiline: True - disks: - description: disk - forcedType: "[]int" - global: True - multiline: True - cpu: - description: cpu - forcedType: int - global: True - multiline: True - memory: - description: mem - forcedType: int - global: True - multiline: True + jpphype1: + add_searchnode: + description: Add a new searchnode to the hypervisor. + file: true + global: true + multiline: true + add_sensor: + description: Add a new sensor to the hypervisor. + file: true + global: true + multiline: true + guests: {} diff --git a/salt/hypervisor/tools/sbin/so-kvm-modify-hardware b/salt/hypervisor/tools/sbin/so-kvm-modify-hardware index cf4c20c49..4191373c4 100644 --- a/salt/hypervisor/tools/sbin/so-kvm-modify-hardware +++ b/salt/hypervisor/tools/sbin/so-kvm-modify-hardware @@ -101,6 +101,14 @@ def redefine_vm(conn, new_xml_desc, logger): sys.exit(1) def main(): + # Set up logging using the so_logging_utils library + logger = setup_logging( + logger_name='so-kvm-modify-hardware', + log_file_path='/opt/so/log/hypervisor/so-kvm-modify-hardware.log', + log_level=logging.INFO, + format_str='%(asctime)s - %(levelname)s - %(message)s' + ) + try: args = parse_arguments() @@ -110,14 +118,6 @@ def main(): pci_id = args.pci start_vm_flag = args.start - # Set up logging using the so_logging_utils library - logger = setup_logging( - logger_name='so-kvm-modify-hardware', - log_file_path='/opt/so/log/hypervisor/so-kvm-modify-hardware.log', - log_level=logging.INFO, - format_str='%(asctime)s - %(levelname)s - %(message)s' - ) - # Connect to libvirt try: conn = libvirt.open(None) diff --git a/salt/hypervisor/tools/sbin/so-qcow2-modify-network b/salt/hypervisor/tools/sbin/so-qcow2-modify-network index 6ec83d3e3..8829d3223 100644 --- a/salt/hypervisor/tools/sbin/so-qcow2-modify-network +++ b/salt/hypervisor/tools/sbin/so-qcow2-modify-network @@ -12,9 +12,9 @@ Usage: python so-qcow2-modify-network.py -I -i (--dhcp4 | --static4 --ip4 --gw4 ) [--dns4 ] [--search4 ] Examples: - python so-qcow2-modify-network.py -I path_to_image -i eth0 --static4 --ip4 192.168.1.10/24 --gw4 192.168.1.1 --dns4 192.168.1.1,8.8.8.8 --search4 example.local + python so-qcow2-modify-network.py -I /var/lib/libvirt/images/coreol9/coreol9.qcow2 -i eth0 --static4 --ip4 192.168.1.10/24 --gw4 192.168.1.1 --dns4 192.168.1.1,8.8.8.8 --search4 example.local - python so-qcow2-modify-network.py -I path_to_image -i eth0 --dhcp4 + python so-qcow2-modify-network.py -I /var/lib/libvirt/images/coreol9/coreol9.qcow2 -i eth0 --dhcp4 """ import argparse @@ -161,14 +161,14 @@ def parse_arguments(): return args def main(): + # Set up logging using the so_logging_utils library + logger = setup_logging( + logger_name='so-qcow2-modify-network', + log_file_path='/opt/so/log/hypervisor/so-qcow2-modify-network.log', + log_level=logging.INFO, + format_str='%(asctime)s - %(levelname)s - %(message)s' + ) try: - # Set up logging using the so_logging_utils library - logger = setup_logging( - logger_name='so-qcow2-modify-network', - log_file_path='/opt/so/log/hypervisor/so-qcow2-modify-network.log', - log_level=logging.INFO, - format_str='%(asctime)s - %(levelname)s - %(message)s' - ) args = parse_arguments() validate_interface_name(args.interface) From 9ac5ef09adcbd52273fb262b93c21e65d9d479ae Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Tue, 29 Oct 2024 11:01:04 -0400 Subject: [PATCH 044/315] update comment --- salt/_modules/qcow2.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/_modules/qcow2.py b/salt/_modules/qcow2.py index 8a4f89b59..48a90137b 100644 --- a/salt/_modules/qcow2.py +++ b/salt/_modules/qcow2.py @@ -34,7 +34,7 @@ def modify_network_config(image, interface, mode, ip4=None, gw4=None, dns4=None, .. code-block:: bash - salt '*' qcow2.modify_network_config image='/path/to/image.qcow2' interface='eth0' mode='static4' ip4='192.168.1.10/24' gw4='192.168.1.1' dns4='8.8.8.8,8.8.4.4' search4='example.local' + salt '*' qcow2.modify_network_config image='/path/to/image.qcow2' interface='eth0' mode='static4' ip4='192.168.1.10/24' gw4='192.168.1.1' dns4='192.168.1.1,8.8.8.8' search4='example.local' ''' From 39391c8088be1646e9899cae86bdaa92b21e7df9 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Tue, 29 Oct 2024 11:27:49 -0400 Subject: [PATCH 045/315] sync pillar top --- pillar/top.sls | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pillar/top.sls b/pillar/top.sls index 6dece952b..0f449a67c 100644 --- a/pillar/top.sls +++ b/pillar/top.sls @@ -69,6 +69,8 @@ base: - kafka.soc_kafka - kafka.adv_kafka - hypervisor.nodes + - hypervisor.soc_hypervisor + - hypervisor.adv_hypervisor - stig.soc_stig '*_sensor': From efbf62f56aec04f9469f10f159c79d98927d95ae Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Mon, 4 Nov 2024 08:30:40 -0500 Subject: [PATCH 046/315] adding beacon --- salt/_beacons/add_virtual_node_beacon.py | 113 ++++++++++++ salt/_modules/qcow2.py | 60 ++++++- .../tools/sbin/so-kvm-modify-hardware | 91 +++++++--- salt/manager/tools/sbin/so-salt-cloud | 162 ++++++++++++++++-- salt/salt/minion.sls | 5 + .../dynamic_annotations/hypervisor/add_node | 2 +- 6 files changed, 389 insertions(+), 44 deletions(-) create mode 100644 salt/_beacons/add_virtual_node_beacon.py diff --git a/salt/_beacons/add_virtual_node_beacon.py b/salt/_beacons/add_virtual_node_beacon.py new file mode 100644 index 000000000..6cbd3574c --- /dev/null +++ b/salt/_beacons/add_virtual_node_beacon.py @@ -0,0 +1,113 @@ +''' +Add Virtual Node Beacon + +This beacon monitors for creation or modification of files matching a specific pattern +and sends the contents of the files up to the Salt Master's event bus, including +the hypervisor and nodetype extracted from the file path. + +Configuration: + + beacons: + add_virtual_node_beacon: + - base_path: /path/to/files/* + +If base_path is not specified, it defaults to '/opt/so/saltstack/local/salt/hypervisor/hosts/*/add_*' +''' + +import os +import glob +import logging +import re + +log = logging.getLogger(__name__) + +__virtualname__ = 'add_virtual_node_beacon' +DEFAULT_BASE_PATH = '/opt/so/saltstack/local/salt/hypervisor/hosts/*/add_*' + +def __virtual__(): + ''' + Return the virtual name of the beacon. + ''' + return __virtualname__ + +def validate(config): + ''' + Validate the beacon configuration. + + Args: + config (list): Configuration of the beacon. + + Returns: + tuple: A tuple of (bool, str) indicating success and message. + ''' + if not isinstance(config, list): + return False, 'Configuration for add_virtual_node_beacon must be a list of dictionaries' + for item in config: + if not isinstance(item, dict): + return False, 'Each item in configuration must be a dictionary' + if 'base_path' in item and not isinstance(item['base_path'], str): + return False, 'base_path must be a string' + return True, 'Valid beacon configuration' + +def beacon(config): + ''' + Monitor for creation or modification of files and send events. + + Args: + config (list): Configuration of the beacon. + + Returns: + list: A list of events to send to the Salt Master. + ''' + if 'add_virtual_node_beacon' not in __context__: + __context__['add_virtual_node_beacon'] = {} + + ret = [] + + for item in config: + base_path = item.get('base_path', DEFAULT_BASE_PATH) + file_list = glob.glob(base_path) + + log.debug('Starting add_virtual_node_beacon. Found %d files matching pattern %s', len(file_list), base_path) + + for file_path in file_list: + try: + mtime = os.path.getmtime(file_path) + prev_mtime = __context__['add_virtual_node_beacon'].get(file_path, 0) + if mtime > prev_mtime: + log.info('File %s is new or modified', file_path) + with open(file_path, 'r') as f: + contents = f.read() + + data = {} + # Parse the contents of the file + for line in contents.splitlines(): + if ':' in line: + key, value = line.split(':', 1) + data[key.strip()] = value.strip() + else: + log.warning('Line in file %s does not contain colon: %s', file_path, line) + + # Extract hypervisor and nodetype from the file path + match = re.match(r'^.*/hosts/(?P[^/]+)/add_(?P[^/]+)$', file_path) + if match: + data['hypervisor'] = match.group('hypervisor') + data['nodetype'] = match.group('nodetype') + else: + log.warning('Unable to extract hypervisor and nodetype from file path: %s', file_path) + data['hypervisor'] = None + data['nodetype'] = None + + event = {'tag': f'add_virtual_node/{os.path.basename(file_path)}', 'data': data} + ret.append(event) + __context__['add_virtual_node_beacon'][file_path] = mtime + else: + log.debug('File %s has not been modified since last check', file_path) + except FileNotFoundError: + log.warning('File not found: %s', file_path) + except PermissionError: + log.error('Permission denied when accessing file: %s', file_path) + except Exception as e: + log.error('Error processing file %s: %s', file_path, str(e)) + + return ret diff --git a/salt/_modules/qcow2.py b/salt/_modules/qcow2.py index 48a90137b..0cbcd8707 100644 --- a/salt/_modules/qcow2.py +++ b/salt/_modules/qcow2.py @@ -1,10 +1,5 @@ #!py -# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one -# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at -# https://securityonion.net/license; you may not use this file except in compliance with the -# Elastic License 2.0. - import logging import subprocess import shlex @@ -71,3 +66,58 @@ def modify_network_config(image, interface, mode, ip4=None, gw4=None, dns4=None, except Exception as e: log.error('qcow2 module: An error occurred while executing the script: {}'.format(e)) raise + +def modify_hardware_config(vm_name, cpu=None, memory=None, pci=None, start=False): + ''' + Wrapper function to call so-kvm-modify-hardware + + :param vm_name: Name of the virtual machine to modify. + :param cpu: Number of virtual CPUs to assign. + :param memory: Amount of memory to assign in MiB. + :param pci: PCI hardware ID to passthrough to the VM (e.g., '0000:00:1f.2'). + :param start: Boolean flag to start the VM after modification. + + :return: A dictionary with the result of the script execution. + + CLI Example: + + .. code-block:: bash + + salt '*' qcow2.modify_hardware_config vm_name='my_vm' cpu=4 memory=8192 pci='0000:00:1f.2' start=True + + ''' + + cmd = ['/usr/sbin/so-kvm-modify-hardware', '-v', vm_name] + + if cpu is not None: + if isinstance(cpu, int) and cpu > 0: + cmd.extend(['-c', str(cpu)]) + else: + raise ValueError('cpu must be a positive integer.') + if memory is not None: + if isinstance(memory, int) and memory > 0: + cmd.extend(['-m', str(memory)]) + else: + raise ValueError('memory must be a positive integer.') + if pci: + cmd.extend(['-p', pci]) + if start: + cmd.append('-s') + + log.info('qcow2 module: Executing command: {}'.format(' '.join(shlex.quote(arg) for arg in cmd))) + + try: + result = subprocess.run(cmd, capture_output=True, text=True, check=False) + ret = { + 'retcode': result.returncode, + 'stdout': result.stdout, + 'stderr': result.stderr + } + if result.returncode != 0: + log.error('qcow2 module: Script execution failed with return code {}: {}'.format(result.returncode, result.stderr)) + else: + log.info('qcow2 module: Script executed successfully.') + return ret + except Exception as e: + log.error('qcow2 module: An error occurred while executing the script: {}'.format(e)) + raise diff --git a/salt/hypervisor/tools/sbin/so-kvm-modify-hardware b/salt/hypervisor/tools/sbin/so-kvm-modify-hardware index 4191373c4..b6e2ea281 100644 --- a/salt/hypervisor/tools/sbin/so-kvm-modify-hardware +++ b/salt/hypervisor/tools/sbin/so-kvm-modify-hardware @@ -8,11 +8,48 @@ """ Script to modify hardware parameters of a KVM virtual machine. -Usage: - python so-kvm-modify-hardware.py -v [-c ] [-m ] [-p ] [-s] +**Usage:** + python so-kvm-modify-hardware.py -v [-c ] [-m ] [-p ] [-p ...] [-s] + +**Options:** + -v, --vm Name of the virtual machine to modify. + -c, --cpu Number of virtual CPUs to assign. + -m, --memory Amount of memory to assign in MiB. + -p, --pci PCI hardware ID(s) to passthrough to the VM (e.g., 0000:00:1f.2). Can be specified multiple times. + -s, --start Start the VM after modification. + +**Examples:** + +1. **Modify VM with Multiple PCI Devices:** + + ```bash + python so-kvm-modify-hardware.py -v my_vm -c 4 -m 8192 -p 0000:00:1f.2 -p 0000:00:1f.3 -s + ``` + + This command modifies the VM named `my_vm`, setting the CPU count to 4, memory to 8192 MiB, and adds two PCI devices for passthrough (`0000:00:1f.2` and `0000:00:1f.3`). The VM is then started after modification due to the `-s` flag. + +2. **Modify VM with Single PCI Device:** + + ```bash + python so-kvm-modify-hardware.py -v my_vm -p 0000:00:1f.2 + ``` + + This command adds a single PCI device passthrough to the VM named `my_vm`. + +3. **Modify VM Without Starting It:** + + ```bash + python so-kvm-modify-hardware.py -v my_vm -c 2 -m 4096 + ``` + + This command sets the CPU count and memory for `my_vm` but does not start it afterward. + +**Notes:** + +- The `-p` or `--pci` option can be specified multiple times to pass through multiple PCI devices to the VM. +- The PCI hardware IDs should be in the format `0000:00:1f.2`. +- If the `-s` or `--start` flag is not provided, the VM will remain stopped after modification. -Example: - python so-kvm-modify-hardware.py -v my_vm -c 4 -m 8192 -p 0000:00:1f.2 -s """ import argparse @@ -28,12 +65,12 @@ def parse_arguments(): parser.add_argument('-v', '--vm', required=True, help='Name of the virtual machine to modify.') parser.add_argument('-c', '--cpu', type=int, help='Number of virtual CPUs to assign.') parser.add_argument('-m', '--memory', type=int, help='Amount of memory to assign in MiB.') - parser.add_argument('-p', '--pci', help='PCI hardware ID to passthrough to the VM (e.g., 0000:00:1f.2).') + parser.add_argument('-p', '--pci', action='append', help='PCI hardware ID(s) to passthrough to the VM (e.g., 0000:00:1f.2). Can be specified multiple times.') parser.add_argument('-s', '--start', action='store_true', help='Start the VM after modification.') args = parser.parse_args() return args -def modify_vm(dom, cpu_count, memory_amount, pci_id, logger): +def modify_vm(dom, cpu_count, memory_amount, pci_ids, logger): try: # Get the XML description of the VM xml_desc = dom.XMLDesc() @@ -61,26 +98,28 @@ def modify_vm(dom, cpu_count, memory_amount, pci_id, logger): logger.error("Could not find elements in XML.") sys.exit(1) - # Add PCI device passthrough - if pci_id is not None: + # Add PCI device passthrough(s) + if pci_ids: devices_elem = root.find('./devices') if devices_elem is not None: - hostdev_elem = ET.SubElement(devices_elem, 'hostdev', attrib={ - 'mode': 'subsystem', - 'type': 'pci', - 'managed': 'yes' - }) - source_elem = ET.SubElement(hostdev_elem, 'source') - domain_id, bus_slot_func = pci_id.split(':') - bus_slot, function = bus_slot_func.split('.') - address_attrs = { - 'domain': f'0x{domain_id}', - 'bus': f'0x{bus_slot}', - 'slot': f'0x{bus_slot}', - 'function': f'0x{function}' - } - ET.SubElement(source_elem, 'address', attrib=address_attrs) - logger.info(f"Added PCI device passthrough for {pci_id}.") + for pci_id in pci_ids: + hostdev_elem = ET.SubElement(devices_elem, 'hostdev', attrib={ + 'mode': 'subsystem', + 'type': 'pci', + 'managed': 'yes' + }) + source_elem = ET.SubElement(hostdev_elem, 'source') + domain_id, bus_slot_func = pci_id.split(':', 1) + bus_slot, function = bus_slot_func.split('.') + bus, slot = bus_slot[:2], bus_slot[2:] + address_attrs = { + 'domain': f'0x{domain_id}', + 'bus': f'0x{bus}', + 'slot': f'0x{slot}', + 'function': f'0x{function}' + } + ET.SubElement(source_elem, 'address', attrib=address_attrs) + logger.info(f"Added PCI device passthrough for {pci_id}.") else: logger.error("Could not find element in XML.") sys.exit(1) @@ -115,7 +154,7 @@ def main(): vm_name = args.vm cpu_count = args.cpu memory_amount = args.memory - pci_id = args.pci + pci_ids = args.pci # This will be a list or None start_vm_flag = args.start # Connect to libvirt @@ -129,7 +168,7 @@ def main(): dom = stop_vm(conn, vm_name, logger) # Modify VM XML - new_xml_desc = modify_vm(dom, cpu_count, memory_amount, pci_id, logger) + new_xml_desc = modify_vm(dom, cpu_count, memory_amount, pci_ids, logger) # Redefine VM redefine_vm(conn, new_xml_desc, logger) diff --git a/salt/manager/tools/sbin/so-salt-cloud b/salt/manager/tools/sbin/so-salt-cloud index 600d7bb8e..2691ea382 100644 --- a/salt/manager/tools/sbin/so-salt-cloud +++ b/salt/manager/tools/sbin/so-salt-cloud @@ -6,15 +6,119 @@ # Elastic License 2.0. """ -Script to assist with salt-cloud VM provisioning. This is only intended to work with a libvirt salt-cloud provider. +Script to assist with salt-cloud VM provisioning. This is intended to work with a libvirt salt-cloud provider. -Usage: - python so-salt-cloud -p (--dhcp4 | --static4 --ip4 --gw4 ) [--dns4 ] [--search4 ] +**Usage:** + python so-salt-cloud -p (--dhcp4 | --static4 --ip4 --gw4 ) + [-c ] [-m ] [-P ] [-P ...] [--dns4 ] [--search4 ] -Examples: - python so-salt-cloud -p core-hype1 hostname_nodetype --static4 --ip4 192.168.1.10/24 --gw4 192.168.1.1 --dns4 192.168.1.1,192.168.1.2 --search4 example.local +**Options:** + -p, --profile The cloud profile to build the VM from. + The name of the VM. + --dhcp4 Configure interface for DHCP (IPv4). + --static4 Configure interface for static IPv4 settings. + --ip4 IPv4 address (e.g., 192.168.1.10/24). Required for static IPv4 configuration. + --gw4 IPv4 gateway (e.g., 192.168.1.1). Required for static IPv4 configuration. + --dns4 Comma-separated list of IPv4 DNS servers (e.g., 8.8.8.8,8.8.4.4). + --search4 DNS search domain for IPv4. + -c, --cpu Number of virtual CPUs to assign. + -m, --memory Amount of memory to assign in MiB. + -P, --pci PCI hardware ID(s) to passthrough to the VM (e.g., 0000:00:1f.2). Can be specified multiple times. + +**Examples:** + +1. **Static IP Configuration with Multiple PCI Devices:** + + ```bash + python so-salt-cloud -p core-hype1 vm1_sensor --static4 --ip4 192.168.1.10/24 --gw4 192.168.1.1 \ + --dns4 192.168.1.1,192.168.1.2 --search4 example.local -c 4 -m 8192 -P 0000:00:1f.2 -P 0000:00:1f.3 + ``` + + This command provisions a VM named `vm1_sensor` using the `core-hype1` profile with the following settings: + + - Static IPv4 configuration: + - IP Address: `192.168.1.10/24` + - Gateway: `192.168.1.1` + - DNS Servers: `192.168.1.1`, `192.168.1.2` + - DNS Search Domain: `example.local` + - Hardware Configuration: + - CPUs: `4` + - Memory: `8192` MiB + - PCI Device Passthrough: `0000:00:1f.2`, `0000:00:1f.3` + +2. **DHCP Configuration with Default Hardware Settings:** + + ```bash + python so-salt-cloud -p core-hype1 vm2_master --dhcp4 + ``` + + This command provisions a VM named `vm2_master` using the `core-hype1` profile with DHCP for network configuration and default hardware settings. + +3. **Static IP Configuration without Hardware Specifications:** + + ```bash + python so-salt-cloud -p core-hype1 vm3_search --static4 --ip4 192.168.1.20/24 --gw4 192.168.1.1 + ``` + + This command provisions a VM named `vm3_search` with a static IP configuration and default hardware settings. + +4. **DHCP Configuration with Custom Hardware Specifications and Multiple PCI Devices:** + + ```bash + python so-salt-cloud -p core-hype1 vm4_node --dhcp4 -c 8 -m 16384 -P 0000:00:1f.4 -P 0000:00:1f.5 + ``` + + This command provisions a VM named `vm4_node` using DHCP for network configuration and custom hardware settings: + + - CPUs: `8` + - Memory: `16384` MiB + - PCI Device Passthrough: `0000:00:1f.4`, `0000:00:1f.5` + +**Notes:** + +- When using `--static4`, both `--ip4` and `--gw4` options are required. +- The script assumes the cloud profile name follows the format `basedomain-hypervisorname`. +- Hardware parameters (`-c`, `-m`, `-P`) are optional. If not provided, default values from the profile will be used. +- The `-P` or `--pci` option can be specified multiple times to pass through multiple PCI devices to the VM. +- The `vm_name` should include the role of the VM after an underscore (e.g., `hostname_role`), as the script uses this to determine the VM's role for firewall configuration. + +**Description:** + +The `so-salt-cloud` script automates the provisioning of virtual machines using SaltStack's `salt-cloud` utility. It performs the following steps: + +1. **Network Configuration:** + + - Modifies the network settings of the base QCOW2 image before provisioning. + - Supports both DHCP and static IPv4 configurations. + - Uses the `qcow2.modify_network_config` module via SaltStack to apply these settings on the target hypervisor. + +2. **VM Provisioning:** + + - Calls `salt-cloud` to provision the VM using the specified profile and VM name. + - The VM is provisioned but not started immediately to allow for hardware configuration. + +3. **Hardware Configuration:** + + - Modifies the hardware settings of the newly defined VM. + - Supports specifying multiple PCI devices for passthrough. + - Uses the `qcow2.modify_hardware_config` module via SaltStack to adjust CPU count, memory allocation, and PCI device passthrough. + - Starts the VM after hardware modifications. + +4. **Firewall Configuration:** + + - Monitors the output of `salt-cloud` to extract the VM's IP address. + - Calls the `so-firewall-minion` script to apply firewall rules based on the VM's role. + +**Exit Codes:** + +- `0`: Success +- Non-zero: An error occurred during execution. + +**Logging:** + +- Logs are written to `/opt/so/log/salt/so-salt-cloud.log`. +- Both file and console logging are enabled for real-time monitoring. - python so-salt-cloud -p core-hype1 hostname_nodetype --dhcp4 """ import argparse @@ -23,11 +127,12 @@ import re import sys import threading import salt.client - -local = salt.client.LocalClient() - import logging +# Initialize Salt local client +local = salt.client.LocalClient() + +# Set up logging logger = logging.getLogger(__name__) logger.setLevel(logging.INFO) @@ -77,7 +182,7 @@ def call_salt_cloud(profile, vm_name): ip_search_string = '[INFO ] Address =' ip_search_pattern = re.compile(re.escape(ip_search_string)) - # continuously read the output from salt-cloud + # Continuously read the output from salt-cloud while True: # Read stdout line by line line = process.stdout.readline() @@ -95,7 +200,7 @@ def call_salt_cloud(profile, vm_name): else: logger.error("No IP address found.") else: - # check if salt-cloud has terminated + # Check if salt-cloud has terminated if process.poll() is not None: break @@ -105,7 +210,29 @@ def call_salt_cloud(profile, vm_name): except Exception as e: logger.error(f"An error occurred while calling salt-cloud: {e}") -# This function requires the cloud profile to be in the form: basedomain_hypervisorhostname. The profile name will be used to target the hypervisor. +def run_qcow2_modify_hardware_config(profile, vm_name, cpu=None, memory=None, pci_list=None, start=False): + hv_name = profile.split('-')[1] + target = hv_name + "_*" + + try: + args_list = [ + 'vm_name=' + vm_name, + 'cpu=' + str(cpu) if cpu else '', + 'memory=' + str(memory) if memory else '', + 'start=' + str(start) + ] + + # Add PCI devices if provided + if pci_list: + # Join the list of PCI IDs into a comma-separated string + pci_devices = ','.join(pci_list) + args_list.append('pci=' + pci_devices) + + r = local.cmd(target, 'qcow2.modify_hardware_config', args_list) + logger.info(f'qcow2.modify_hardware_config: {r}') + except Exception as e: + logger.error(f"An error occurred while running qcow2.modify_hardware_config: {e}") + def run_qcow2_modify_network_config(profile, mode, ip=None, gateway=None, dns=None, search_domain=None): hv_name = profile.split('-')[1] target = hv_name + "_*" @@ -130,13 +257,18 @@ def parse_arguments(): parser = argparse.ArgumentParser(description="Call salt-cloud and pass the profile and VM name to it.") parser.add_argument('-p', '--profile', type=str, required=True, help="The cloud profile to build the VM from.") parser.add_argument('vm_name', type=str, help="The name of the VM.") + group = parser.add_mutually_exclusive_group(required=True) group.add_argument("--dhcp4", action="store_true", help="Configure interface for DHCP (IPv4).") group.add_argument("--static4", action="store_true", help="Configure interface for static IPv4 settings.") + parser.add_argument("--ip4", help="IPv4 address (e.g., 192.168.1.10/24). Required for static IPv4 configuration.") parser.add_argument("--gw4", help="IPv4 gateway (e.g., 192.168.1.1). Required for static IPv4 configuration.") parser.add_argument("--dns4", help="Comma-separated list of IPv4 DNS servers (e.g., 8.8.8.8,8.8.4.4).") parser.add_argument("--search4", help="DNS search domain for IPv4.") + parser.add_argument('-c', '--cpu', type=int, help='Number of virtual CPUs to assign.') + parser.add_argument('-m', '--memory', type=int, help='Amount of memory to assign in MiB.') + parser.add_argument('-P', '--pci', action='append', help='PCI hardware ID(s) to passthrough to the VM (e.g., 0000:00:1f.2). Can be specified multiple times.') args = parser.parse_args() @@ -156,9 +288,15 @@ def main(): else: mode = "dhcp4" # Default to DHCP if not specified + # Step 1: Modify network configuration run_qcow2_modify_network_config(args.profile, mode, args.ip4, args.gw4, args.dns4, args.search4) + + # Step 2: Provision the VM (without starting it) call_salt_cloud(args.profile, args.vm_name) + # Step 3: Modify hardware configuration + run_qcow2_modify_hardware_config(args.profile, args.vm_name, cpu=args.cpu, memory=args.memory, pci_list=args.pci, start=True) + except KeyboardInterrupt: logger.error("so-salt-cloud: Operation cancelled by user.") sys.exit(1) diff --git a/salt/salt/minion.sls b/salt/salt/minion.sls index a5953e8e1..0d995e96c 100644 --- a/salt/salt/minion.sls +++ b/salt/salt/minion.sls @@ -70,6 +70,11 @@ enable_startup_states: - regex: '^startup_states: highstate$' - unless: pgrep so-setup +# manager with hypervisors with need this beacon added to the minion config +#beacons: +# add_virtual_node_beacon: +# - base_path: /opt/so/saltstack/local/salt/hypervisor/hosts/*/add_* + # prior to 2.4.30 this managed file would restart the salt-minion service when updated # since this file is currently only adding a sleep timer on service start # it is not required to restart the service diff --git a/salt/soc/dynamic_annotations/hypervisor/add_node b/salt/soc/dynamic_annotations/hypervisor/add_node index 498db1460..ecbde7b41 100644 --- a/salt/soc/dynamic_annotations/hypervisor/add_node +++ b/salt/soc/dynamic_annotations/hypervisor/add_node @@ -3,7 +3,7 @@ network_mode: ip4: gw4: dns4: -sarch4: +search4: cpu: memory: disk: From a0a18973d8d0dfd214dc4fa16fb93e8f1c677db3 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Mon, 9 Dec 2024 15:29:51 -0500 Subject: [PATCH 047/315] add new salt bootstrap --- salt/salt/scripts/bootstrap-salt.sh | 4188 ++++++++------------------- 1 file changed, 1223 insertions(+), 2965 deletions(-) diff --git a/salt/salt/scripts/bootstrap-salt.sh b/salt/salt/scripts/bootstrap-salt.sh index a016524e6..4e65008dc 100644 --- a/salt/salt/scripts/bootstrap-salt.sh +++ b/salt/salt/scripts/bootstrap-salt.sh @@ -1,9 +1,12 @@ -#!/bin/sh - +#!/bin/sh # WARNING: Changes to this file in the salt repo will be overwritten! # Please submit pull requests against the salt-bootstrap repo: # https://github.com/saltstack/salt-bootstrap - +# shellcheck disable=SC2317 +# shellcheck disable=SC2086 +# shellcheck disable=SC2329 +# #====================================================================================================================== # vim: softtabstop=4 shiftwidth=4 expandtab fenc=utf-8 spell spelllang=en cc=120 #====================================================================================================================== @@ -14,7 +17,7 @@ # # BUGS: https://github.com/saltstack/salt-bootstrap/issues # -# COPYRIGHT: (c) 2012-2022 by the SaltStack Team, see AUTHORS.rst for more +# COPYRIGHT: (c) 2012-2024 by the SaltStack Team, see AUTHORS.rst for more # details. # # LICENSE: Apache 2.0 @@ -23,7 +26,7 @@ #====================================================================================================================== set -o nounset # Treat unset variables as an error -__ScriptVersion="2023.08.03" +__ScriptVersion="2024.11.07" __ScriptName="bootstrap-salt.sh" __ScriptFullName="$0" @@ -121,16 +124,35 @@ __check_command_exists() { command -v "$1" > /dev/null 2>&1 } +#--- FUNCTION ------------------------------------------------------------------------------------------------------- +# NAME: __check_services_systemd_functional +# DESCRIPTION: Set _SYSTEMD_FUNCTIONAL = BS_TRUE or BS_FALSE case where systemd is functional (for example: container may not have systemd) +#---------------------------------------------------------------------------------------------------------------------- +__check_services_systemd_functional() { + + # check if systemd is functional, having systemctl present is insufficient + + if [ "$_SYSTEMD_FUNCTIONAL" -eq $BS_FALSE ]; then + # already determined systemd is not functional, default is 1 + return + fi + + if __check_command_exists systemctl; then + # shellcheck disable=SC2034 + _SYSTEMD_HELP="$(systemctl --help)" + else + _SYSTEMD_FUNCTIONAL=$BS_FALSE + echoerror "systemctl: command not found, assume systemd not implemented, _SYSTEMD_FUNCTIONAL $_SYSTEMD_FUNCTIONAL" + fi +} # ---------- end of function __check_services_systemd_functional ---------- + #--- FUNCTION ------------------------------------------------------------------------------------------------------- # NAME: __check_pip_allowed # DESCRIPTION: Simple function to let the users know that -P needs to be used. #---------------------------------------------------------------------------------------------------------------------- __check_pip_allowed() { - if [ $# -eq 1 ]; then - _PIP_ALLOWED_ERROR_MSG=$1 - else - _PIP_ALLOWED_ERROR_MSG="pip based installations were not allowed. Retry using '-P'" - fi + + _PIP_ALLOWED_ERROR_MSG="pip based installations were not allowed. Retry using '-P'" if [ "$_PIP_ALLOWED" -eq $BS_FALSE ]; then echoerror "$_PIP_ALLOWED_ERROR_MSG" @@ -228,6 +250,7 @@ _TEMP_KEYS_DIR="null" _SLEEP="${__DEFAULT_SLEEP}" _INSTALL_MASTER=$BS_FALSE _INSTALL_SYNDIC=$BS_FALSE +_INSTALL_SALT_API=$BS_FALSE _INSTALL_MINION=$BS_TRUE _INSTALL_CLOUD=$BS_FALSE _VIRTUALENV_DIR=${BS_VIRTUALENV_DIR:-"null"} @@ -266,19 +289,16 @@ _CUSTOM_REPO_URL="null" _CUSTOM_MASTER_CONFIG="null" _CUSTOM_MINION_CONFIG="null" _QUIET_GIT_INSTALLATION=$BS_FALSE -_REPO_URL="repo.saltproject.io" -_ONEDIR_DIR="salt" -_ONEDIR_NIGHTLY_DIR="salt-dev/${_ONEDIR_DIR}" +_REPO_URL="packages.broadcom.com/artifactory" _PY_EXE="python3" -_INSTALL_PY="$BS_FALSE" -_TORNADO_MAX_PY3_VERSION="5.0" -_POST_NEON_INSTALL=$BS_FALSE _MINIMUM_PIP_VERSION="9.0.1" -_MINIMUM_SETUPTOOLS_VERSION="9.1" -_POST_NEON_PIP_INSTALL_ARGS="--prefix=/usr" +_MINIMUM_SETUPTOOLS_VERSION="65.6.3" +_MAXIMUM_SETUPTOOLS_VERSION="69.0" +_PIP_INSTALL_ARGS="--prefix=/usr" _PIP_DOWNLOAD_ARGS="" _QUICK_START="$BS_FALSE" _AUTO_ACCEPT_MINION_KEYS="$BS_FALSE" +_SYSTEMD_FUNCTIONAL=$BS_TRUE # Defaults for install arguments ITYPE="stable" @@ -297,9 +317,9 @@ __usage() { - stable Install latest stable release. This is the default install type - stable [branch] Install latest version on a branch. Only supported - for packages available at repo.saltproject.io + for packages available at packages.broadcom.com - stable [version] Install a specific version. Only supported for - packages available at repo.saltproject.io + packages available at packages.broadcom.com To pin a 3xxx minor version, specify it as 3xxx.0 - testing RHEL-family specific: configure EPEL testing repo - git Install from the head of the master branch @@ -307,17 +327,11 @@ __usage() { commit) - onedir Install latest onedir release. - onedir [version] Install a specific version. Only supported for - onedir packages available at repo.saltproject.io + onedir packages available at packages.broadcom.com - onedir_rc Install latest onedir RC release. - onedir_rc [version] Install a specific version. Only supported for - onedir RC packages available at repo.saltproject.io - - old-stable Install latest old stable release. - - old-stable [branch] Install latest version on a branch. Only supported - for packages available at repo.saltproject.io - - old-stable [version] Install a specific version. Only supported for - packages available at repo.saltproject.io - To pin a 3xxx minor version, specify it as 3xxx.0 + onedir RC packages available at packages.broadcom.com Examples: - ${__ScriptName} @@ -326,16 +340,15 @@ __usage() { - ${__ScriptName} stable 3006.1 - ${__ScriptName} testing - ${__ScriptName} git - - ${__ScriptName} git 2017.7 - - ${__ScriptName} git v2017.7.2 + - ${__ScriptName} git 3006.7 + - ${__ScriptName} git v3006.8 + - ${__ScriptName} git 3007.1 + - ${__ScriptName} git v3007.1 - ${__ScriptName} git 06f249901a2e2f1ed310d58ea3921a129f214358 - ${__ScriptName} onedir - ${__ScriptName} onedir 3006 - ${__ScriptName} onedir_rc - - ${__ScriptName} onedir_rc 3006 - - ${__ScriptName} old-stable - - ${__ScriptName} old-stable 3005 - - ${__ScriptName} old-stable 3005.1 + - ${__ScriptName} onedir_rc 3008 Options: @@ -349,7 +362,7 @@ __usage() { step. -c Temporary configuration directory -C Only run the configuration function. Implies -F (forced overwrite). - To overwrite Master or Syndic configs, -M or -S, respectively, must + To overwrite Master, Syndic or Api configs, -M,-S or -W, respectively, must also be specified. Salt installation will be ommitted, but some of the dependencies could be installed to write configuration with -j or -J. -d Disables checking if Salt services are enabled to start on system boot. @@ -401,8 +414,8 @@ __usage() { And automatically accept the minion key. -R Specify a custom repository URL. Assumes the custom repository URL points to a repository that mirrors Salt packages located at - repo.saltproject.io. The option passed with -R replaces the - "repo.saltproject.io". If -R is passed, -r is also set. Currently only + packages.broadcom.com. The option passed with -R replaces the + "packages.broadcom.com". If -R is passed, -r is also set. Currently only works on CentOS/RHEL and Debian based distributions and macOS. -s Sleep time used when waiting for daemons to start, restart and when checking for the services running. Default: ${__DEFAULT_SLEEP} @@ -414,23 +427,15 @@ __usage() { -v Display script version -V Install Salt into virtualenv (only available for Ubuntu based distributions) - -x Changes the Python version used to install Salt. - For CentOS 6 git installations python2.7 is supported. - Fedora git installation, CentOS 7, Ubuntu 18.04 support python3. + -W Also install salt-api + -x Changes the Python version used to install Salt (default: Python 3). + Python 2.7 is no longer supported. -X Do not start daemons after installation - -y Installs a different python version on host. Currently this has only been - tested with CentOS 6 and is considered experimental. This will install the - ius repo on the box if disable repo is false. This must be used in conjunction - with -x . For example: - sh bootstrap.sh -P -y -x python2.7 git v2017.7.2 - The above will install python27 and install the git version of salt using the - python2.7 executable. This only works for git and pip installations. EOT } # ---------- end of function __usage ---------- - -while getopts ':hvnDc:g:Gyx:k:s:MSNXCPFUKIA:i:Lp:dH:bflV:J:j:rR:aqQ' opt +while getopts ':hvnDc:g:Gx:k:s:MSWNXCPFUKIA:i:Lp:dH:bflV:J:j:rR:aqQ' opt do case "${opt}" in @@ -450,6 +455,7 @@ do s ) _SLEEP=$OPTARG ;; M ) _INSTALL_MASTER=$BS_TRUE ;; S ) _INSTALL_SYNDIC=$BS_TRUE ;; + W ) _INSTALL_SALT_API=$BS_TRUE ;; N ) _INSTALL_MINION=$BS_FALSE ;; X ) _START_DAEMONS=$BS_FALSE ;; C ) _CONFIG_ONLY=$BS_TRUE ;; @@ -476,7 +482,6 @@ do q ) _QUIET_GIT_INSTALLATION=$BS_TRUE ;; Q ) _QUICK_START=$BS_TRUE ;; x ) _PY_EXE="$OPTARG" ;; - y ) _INSTALL_PY="$BS_TRUE" ;; \?) echo echoerror "Option does not exist : $OPTARG" @@ -488,7 +493,6 @@ do done shift $((OPTIND-1)) - # Define our logging file and pipe paths LOGFILE="/tmp/$( echo "$__ScriptName" | sed s/.sh/.log/g )" LOGPIPE="/tmp/$( echo "$__ScriptName" | sed s/.sh/.logpipe/g )" @@ -596,7 +600,15 @@ fi echoinfo "Running version: ${__ScriptVersion}" echoinfo "Executed by: ${CALLER}" echoinfo "Command line: '${__ScriptFullName} ${__ScriptArgs}'" -echowarn "Running the unstable version of ${__ScriptName}" + +# Defaults +STABLE_REV="latest" +ONEDIR_REV="latest" +_ONEDIR_REV="latest" +YUM_REPO_FILE="/etc/yum.repos.d/salt.repo" + +# check if systemd is functional +__check_services_systemd_functional # Define installation type if [ "$#" -gt 0 ];then @@ -606,17 +618,11 @@ if [ "$#" -gt 0 ];then fi # Check installation type -if [ "$(echo "$ITYPE" | grep -E '(stable|testing|git|onedir|onedir_rc|old-stable)')" = "" ]; then +if [ "$(echo "$ITYPE" | grep -E '(stable|testing|git|onedir|onedir_rc)')" = "" ]; then echoerror "Installation type \"$ITYPE\" is not known..." exit 1 fi -# Due to our modifications to install_centos_onedir it is easiest to just lock down to only allowing stable install -if [ "$(echo "$ITYPE" | grep stable)" = "" ]; then - echoerror "This script has been modified to only support stable installation type. Installation type \"$ITYPE\" is not allowed..." - exit 1 -fi - # If doing a git install, check what branch/tag/sha will be checked out if [ "$ITYPE" = "git" ]; then if [ "$#" -eq 0 ];then @@ -632,45 +638,25 @@ if [ "$ITYPE" = "git" ]; then # If doing stable install, check if version specified elif [ "$ITYPE" = "stable" ]; then if [ "$#" -eq 0 ];then + STABLE_REV="latest" ONEDIR_REV="latest" _ONEDIR_REV="latest" ITYPE="onedir" else - if [ "$(echo "$1" | grep -E '^(nightly|latest|3005|3006)$')" != "" ]; then + if [ "$(echo "$1" | grep -E '^(latest|3006|3007)$')" != "" ]; then + STABLE_REV="$1" ONEDIR_REV="$1" _ONEDIR_REV="$1" ITYPE="onedir" shift elif [ "$(echo "$1" | grep -E '^([3-9][0-5]{2}[5-9](\.[0-9]*)?)')" != "" ]; then - ONEDIR_REV="minor/$1" + STABLE_REV="$1" + ONEDIR_REV="$1" _ONEDIR_REV="$1" ITYPE="onedir" shift else - echo "Unknown stable version: $1 (valid: 3005, 3006, latest)" - exit 1 - fi - fi - -# If doing old-stable install, check if version specified -elif [ "$ITYPE" = "old-stable" ]; then - if [ "$#" -eq 0 ];then - ITYPE="stable" - else - if [ "$(echo "$1" | grep -E '^(3003|3004|3005)$')" != "" ]; then - STABLE_REV="$1" - ITYPE="stable" - shift - elif [ "$(echo "$1" | grep -E '^([3-9][0-5]{3}(\.[0-9]*)?)$')" != "" ]; then - # Handle the 3xxx.0 version as 3xxx archive (pin to minor) and strip the fake ".0" suffix - ITYPE="stable" - STABLE_REV=$(echo "$1" | sed -E 's/^([3-9][0-9]{3})\.0$/\1/') - if [ "$(uname)" != "Darwin" ]; then - STABLE_REV="archive/$STABLE_REV" - fi - shift - else - echo "Unknown old stable version: $1 (valid: 3003, 3004, 3005)" + echo "Unknown stable version: $1 (valid: 3006, 3007, latest), versions older than 3006 are not available" exit 1 fi fi @@ -678,52 +664,54 @@ elif [ "$ITYPE" = "old-stable" ]; then elif [ "$ITYPE" = "onedir" ]; then if [ "$#" -eq 0 ];then ONEDIR_REV="latest" + STABLE_REV="latest" else - if [ "$(echo "$1" | grep -E '^(nightly|latest|3005|3006)$')" != "" ]; then + if [ "$(echo "$1" | grep -E '^(latest|3006|3007)$')" != "" ]; then ONEDIR_REV="$1" - shift - elif [ "$(echo "$1" | grep -E '^(3005(\.[0-9]*)?)')" != "" ]; then - # Handle the 3005.0 version as 3005 archive (pin to minor) and strip the fake ".0" suffix - ONEDIR_REV=$(echo "$1" | sed -E 's/^(3005)\.0$/\1/') - ONEDIR_REV="minor/$ONEDIR_REV" + STABLE_REV="$1" shift elif [ "$(echo "$1" | grep -E '^([3-9][0-9]{3}(\.[0-9]*)?)')" != "" ]; then - ONEDIR_REV="minor/$1" + ONEDIR_REV="$1" + STABLE_REV="$1" shift else - echo "Unknown onedir version: $1 (valid: 3005, 3006, latest, nightly.)" + echo "Unknown onedir version: $1 (valid: 3006, 3007, latest), versions older than 3006 are not available" exit 1 fi fi elif [ "$ITYPE" = "onedir_rc" ]; then - # Change the _ONEDIR_DIR to be the location for the RC packages - _ONEDIR_DIR="salt_rc/salt" + echoerror "RC Releases are not supported at this time" - # Change ITYPE to onedir so we use the regular onedir functions - ITYPE="onedir" - - if [ "$#" -eq 0 ];then - ONEDIR_REV="latest" - else - if [ "$(echo "$1" | grep -E '^(latest)$')" != "" ]; then - ONEDIR_REV="$1" - shift - elif [ "$(echo "$1" | grep -E '^([3-9][0-9]{3}?rc[0-9]-[0-9]$)')" != "" ]; then - # Handle the 3xxx.0 version as 3xxx archive (pin to minor) and strip the fake ".0" suffix - #ONEDIR_REV=$(echo "$1" | sed -E 's/^([3-9][0-9]{3})\.0$/\1/') - ONEDIR_REV="minor/$1" - shift - elif [ "$(echo "$1" | grep -E '^([3-9][0-9]{3}\.[0-9]?rc[0-9]$)')" != "" ]; then - # Handle the 3xxx.0 version as 3xxx archive (pin to minor) and strip the fake ".0" suffix - #ONEDIR_REV=$(echo "$1" | sed -E 's/^([3-9][0-9]{3})\.0$/\1/') - ONEDIR_REV="minor/$1" - shift - else - echo "Unknown onedir_rc version: $1 (valid: 3005-1, latest.)" - exit 1 - fi - fi +## # Change the _ONEDIR_DIR to be the location for the RC packages +## _ONEDIR_DIR="salt_rc/salt" +## +## # Change ITYPE to onedir so we use the regular onedir functions +## ITYPE="onedir" +## +## if [ "$#" -eq 0 ];then +## ONEDIR_REV="latest" +## else +## if [ "$(echo "$1" | grep -E '^(latest)$')" != "" ]; then +## ONEDIR_REV="$1" +## shift +## elif [ "$(echo "$1" | grep -E '^([3-9][0-9]{3}?rc[0-9]-[0-9]$)')" != "" ]; then +## # Handle the 3xxx.0 version as 3xxx archive (pin to minor) and strip the fake ".0" suffix +## #ONEDIR_REV=$(echo "$1" | sed -E 's/^([3-9][0-9]{3})\.0$/\1/') +## ## ONEDIR_REV="minor/$1" don't have minor directory anymore +## ONEDIR_REV="$1" +## shift +## elif [ "$(echo "$1" | grep -E '^([3-9][0-9]{3}\.[0-9]?rc[0-9]$)')" != "" ]; then +## # Handle the 3xxx.0 version as 3xxx archive (pin to minor) and strip the fake ".0" suffix +## #ONEDIR_REV=$(echo "$1" | sed -E 's/^([3-9][0-9]{3})\.0$/\1/') +## ## ONEDIR_REV="minor/$1" don't have minor directory anymore +## ONEDIR_REV="$1" +## shift +## else +## echo "Unknown onedir_rc version: $1 (valid: 3006-8, 3007-1, latest)" +## exit 1 +## fi +## fi fi # Doing a quick start, so install master @@ -773,7 +761,7 @@ if [ "$($whoami)" != "root" ]; then fi # Check that we're actually installing one of minion/master/syndic -if [ "$_INSTALL_MINION" -eq $BS_FALSE ] && [ "$_INSTALL_MASTER" -eq $BS_FALSE ] && [ "$_INSTALL_SYNDIC" -eq $BS_FALSE ] && [ "$_CONFIG_ONLY" -eq $BS_FALSE ]; then +if [ "$_INSTALL_MINION" -eq $BS_FALSE ] && [ "$_INSTALL_MASTER" -eq $BS_FALSE ] && [ "$_INSTALL_SYNDIC" -eq $BS_FALSE ] && [ "$_INSTALL_SALT_API" -eq $BS_FALSE ] && [ "$_CONFIG_ONLY" -eq $BS_FALSE ]; then echowarn "Nothing to install or configure" exit 1 fi @@ -806,6 +794,12 @@ if [ "$_CUSTOM_MINION_CONFIG" != "null" ]; then fi fi + +# Default to Python 3, no longer support for Python 2 +PY_PKG_VER=3 +_PY_PKG_VER="python3" +_PY_MAJOR_VERSION="3" + # Check if we're installing via a different Python executable and set major version variables if [ -n "$_PY_EXE" ]; then if [ "$(uname)" = "Darwin" ]; then @@ -814,19 +808,21 @@ if [ -n "$_PY_EXE" ]; then _PY_PKG_VER=$(echo "$_PY_EXE" | sed -E "s/\\.//g") fi - _PY_MAJOR_VERSION=$(echo "$_PY_PKG_VER" | cut -c 7) - if [ "$_PY_MAJOR_VERSION" != 3 ] && [ "$_PY_MAJOR_VERSION" != 2 ]; then - echoerror "Detected -x option, but Python major version is not 2 or 3." - echoerror "The -x option must be passed as python2, python27, or python2.7 (or use the Python '3' versions of examples)." + TEST_PY_MAJOR_VERSION=$(echo "$_PY_PKG_VER" | cut -c 7) + if [ "$TEST_PY_MAJOR_VERSION" -eq 2 ]; then + echoerror "Python 2 is no longer supported, only Python 3" + return 1 + fi + + if [ "$TEST_PY_MAJOR_VERSION" != 3 ]; then + echoerror "Detected -x option, but Python major version is not 3." + echoerror "The -x option must be passed as python3, python38, or python3.8 (use the Python '3' versions of examples)." exit 1 fi if [ "$_PY_EXE" != "python3" ]; then echoinfo "Detected -x option. Using $_PY_EXE to install Salt." fi -else - _PY_PKG_VER="" - _PY_MAJOR_VERSION="" fi # If the configuration directory or archive does not exist, error out @@ -843,7 +839,7 @@ fi # -a and -V only work from git if [ "$ITYPE" != "git" ]; then - if [ $_PIP_ALL -eq $BS_TRUE ]; then + if [ "$_PIP_ALL" -eq $BS_TRUE ]; then echoerror "Pip installing all python packages with -a is only possible when installing Salt via git" exit 1 fi @@ -853,7 +849,7 @@ if [ "$ITYPE" != "git" ]; then fi fi -# Set the _REPO_URL value based on if -R was passed or not. Defaults to repo.saltproject.io. +# Set the _REPO_URL value based on if -R was passed or not. Defaults to packages.broadcom.com if [ "$_CUSTOM_REPO_URL" != "null" ]; then _REPO_URL="$_CUSTOM_REPO_URL" @@ -938,6 +934,7 @@ __fetch_url() { # DESCRIPTION: Retrieves a URL, verifies its content and writes it to standard output #---------------------------------------------------------------------------------------------------------------------- __fetch_verify() { + fetch_verify_url="$1" fetch_verify_sum="$2" fetch_verify_size="$3" @@ -959,6 +956,7 @@ __fetch_verify() { # DESCRIPTION: Checks if a URL exists #---------------------------------------------------------------------------------------------------------------------- __check_url_exists() { + _URL="$1" if curl --output /dev/null --silent --fail "${_URL}"; then return 0 @@ -1035,17 +1033,12 @@ __derive_debian_numeric_version() { INPUT_VERSION="$(cat /etc/debian_version)" fi if [ -z "$NUMERIC_VERSION" ]; then - if [ "$INPUT_VERSION" = "wheezy/sid" ]; then - # I've found an EC2 wheezy image which did not tell its version - NUMERIC_VERSION=$(__parse_version_string "7.0") - elif [ "$INPUT_VERSION" = "jessie/sid" ]; then - NUMERIC_VERSION=$(__parse_version_string "8.0") - elif [ "$INPUT_VERSION" = "stretch/sid" ]; then - NUMERIC_VERSION=$(__parse_version_string "9.0") - elif [ "$INPUT_VERSION" = "buster/sid" ]; then - NUMERIC_VERSION=$(__parse_version_string "10.0") - elif [ "$INPUT_VERSION" = "bullseye/sid" ]; then + if [ "$INPUT_VERSION" = "bullseye/sid" ]; then NUMERIC_VERSION=$(__parse_version_string "11.0") + elif [ "$INPUT_VERSION" = "bookworm/sid" ]; then + NUMERIC_VERSION=$(__parse_version_string "12.0") + elif [ "$INPUT_VERSION" = "trixie/sid" ]; then + NUMERIC_VERSION=$(__parse_version_string "13.0") else echowarn "Unable to parse the Debian Version (codename: '$INPUT_VERSION')" fi @@ -1129,6 +1122,7 @@ __gather_linux_system_info() { DISTRO_VERSION="" # Let's test if the lsb_release binary is available + # shellcheck disable=SC2327,SC2328 rv=$(lsb_release >/dev/null 2>&1) # shellcheck disable=SC2181 @@ -1186,7 +1180,7 @@ __gather_linux_system_info() { # We already have the distribution name and version return fi - # shellcheck disable=SC2035,SC2086 + # shellcheck disable=SC2035,SC2086,SC2269 for rsource in $(__sort_release_files "$( cd /etc && /bin/ls *[_-]release *[_-]version 2>/dev/null | env -i sort | \ sed -e '/^redhat-release$/d' -e '/^lsb-release$/d'; \ @@ -1288,127 +1282,6 @@ __gather_linux_system_info() { } -#--- FUNCTION ------------------------------------------------------------------------------------------------------- -# NAME: __install_python() -# DESCRIPTION: Install a different version of python on a host. Currently this has only been tested on CentOS 6 and -# is considered experimental. -#---------------------------------------------------------------------------------------------------------------------- -__install_python() { - if [ "$_PY_EXE" = "" ]; then - echoerror "Must specify -x with -y to install a specific python version" - exit 1 - fi - - __PACKAGES="$_PY_PKG_VER" - - if [ ${_DISABLE_REPOS} -eq ${BS_FALSE} ]; then - echoinfo "Attempting to install a repo to help provide a separate python package" - echoinfo "$DISTRO_NAME_L" - case "$DISTRO_NAME_L" in - "red_hat"|"centos") - __PYTHON_REPO_URL="https://repo.ius.io/ius-release-el${DISTRO_MAJOR_VERSION}.rpm" - ;; - *) - echoerror "Installing a repo to provide a python package is only supported on Redhat/CentOS. - If a repo is already available, please try running script with -r." - exit 1 - ;; - esac - - echoinfo "Installing IUS repo" - __yum_install_noinput "${__PYTHON_REPO_URL}" || return 1 - fi - - echoinfo "Installing ${__PACKAGES}" - __yum_install_noinput "${__PACKAGES}" || return 1 -} - - -#--- FUNCTION ------------------------------------------------------------------------------------------------------- -# NAME: __gather_sunos_system_info -# DESCRIPTION: Discover SunOS system info -#---------------------------------------------------------------------------------------------------------------------- -__gather_sunos_system_info() { - if [ -f /sbin/uname ]; then - DISTRO_VERSION=$(/sbin/uname -X | awk '/[kK][eE][rR][nN][eE][lL][iI][dD]/ { print $3 }') - fi - - DISTRO_NAME="" - if [ -f /etc/release ]; then - while read -r line; do - [ "${DISTRO_NAME}" != "" ] && break - case "$line" in - *OpenIndiana*oi_[0-9]*) - DISTRO_NAME="OpenIndiana" - DISTRO_VERSION=$(echo "$line" | sed -nE "s/OpenIndiana(.*)oi_([[:digit:]]+)(.*)/\\2/p") - break - ;; - *OpenSolaris*snv_[0-9]*) - DISTRO_NAME="OpenSolaris" - DISTRO_VERSION=$(echo "$line" | sed -nE "s/OpenSolaris(.*)snv_([[:digit:]]+)(.*)/\\2/p") - break - ;; - *Oracle*Solaris*[0-9]*) - DISTRO_NAME="Oracle Solaris" - DISTRO_VERSION=$(echo "$line" | sed -nE "s/(Oracle Solaris) ([[:digit:]]+)(.*)/\\2/p") - break - ;; - *Solaris*) - DISTRO_NAME="Solaris" - # Let's make sure we not actually on a Joyent's SmartOS VM since some releases - # don't have SmartOS in `/etc/release`, only `Solaris` - if uname -v | grep joyent >/dev/null 2>&1; then - DISTRO_NAME="SmartOS" - fi - break - ;; - *NexentaCore*) - DISTRO_NAME="Nexenta Core" - break - ;; - *SmartOS*) - DISTRO_NAME="SmartOS" - break - ;; - *OmniOS*) - DISTRO_NAME="OmniOS" - DISTRO_VERSION=$(echo "$line" | awk '{print $3}') - _SIMPLIFY_VERSION=$BS_FALSE - break - ;; - esac - done < /etc/release - fi - - if [ "${DISTRO_NAME}" = "" ]; then - DISTRO_NAME="Solaris" - DISTRO_VERSION=$( - echo "${OS_VERSION}" | - sed -e 's;^4\.;1.;' \ - -e 's;^5\.\([0-6]\)[^0-9]*$;2.\1;' \ - -e 's;^5\.\([0-9][0-9]*\).*;\1;' - ) - fi - - if [ "${DISTRO_NAME}" = "SmartOS" ]; then - VIRTUAL_TYPE="smartmachine" - if [ "$(zonename)" = "global" ]; then - VIRTUAL_TYPE="global" - fi - fi -} - - -#--- FUNCTION ------------------------------------------------------------------------------------------------------- -# NAME: __gather_bsd_system_info -# DESCRIPTION: Discover OpenBSD, NetBSD and FreeBSD systems information -#---------------------------------------------------------------------------------------------------------------------- -__gather_bsd_system_info() { - DISTRO_NAME=${OS_NAME} - DISTRO_VERSION=$(echo "${OS_VERSION}" | sed -e 's;[()];;' -e 's/-.*$//') -} - - #--- FUNCTION ------------------------------------------------------------------------------------------------------- # NAME: __gather_osx_system_info # DESCRIPTION: Discover MacOS X @@ -1428,12 +1301,6 @@ __gather_system_info() { linux ) __gather_linux_system_info ;; - sunos ) - __gather_sunos_system_info - ;; - openbsd|freebsd|netbsd ) - __gather_bsd_system_info - ;; darwin ) __gather_osx_system_info ;; @@ -1454,21 +1321,23 @@ __gather_system_info() { #---------------------------------------------------------------------------------------------------------------------- # shellcheck disable=SC2034 __ubuntu_derivatives_translation() { - UBUNTU_DERIVATIVES="(trisquel|linuxmint|linaro|elementary_os|neon|pop)" + UBUNTU_DERIVATIVES="(trisquel|linuxmint|elementary_os|pop|neon)" # Mappings - trisquel_6_ubuntu_base="12.04" - linuxmint_13_ubuntu_base="12.04" - linuxmint_17_ubuntu_base="14.04" - linuxmint_18_ubuntu_base="16.04" - linuxmint_19_ubuntu_base="18.04" - linuxmint_20_ubuntu_base="20.04" - linaro_12_ubuntu_base="12.04" - elementary_os_02_ubuntu_base="12.04" - neon_16_ubuntu_base="16.04" - neon_18_ubuntu_base="18.04" + trisquel_10_ubuntu_base="20.04" + trisquel_11_ubuntu_base="22.04" + trisquel_12_ubuntu_base="24.04" neon_20_ubuntu_base="20.04" neon_22_ubuntu_base="22.04" + neon_24_ubuntu_base="24.04" + linuxmint_20_ubuntu_base="20.04" + linuxmint_21_ubuntu_base="22.04" + linuxmint_22_ubuntu_base="24.04" + elementary_os_06_ubuntu_base="20.04" + elementary_os_07_ubuntu_base="22.04" + elementary_os_08_ubuntu_base="24.04" + pop_20_ubuntu_base="22.04" pop_22_ubuntu_base="22.04" + pop_24_ubuntu_base="24.04" # Translate Ubuntu derivatives to their base Ubuntu version match=$(echo "$DISTRO_NAME_L" | grep -E ${UBUNTU_DERIVATIVES}) @@ -1511,42 +1380,24 @@ __check_dpkg_architecture() { return 1 fi - __REPO_ARCH="$DPKG_ARCHITECTURE" - __REPO_ARCH_DEB='deb [signed-by=/usr/share/keyrings/salt-archive-keyring.gpg]' __return_code=0 case $DPKG_ARCHITECTURE in "i386") - error_msg="$_REPO_URL likely doesn't have all required 32-bit packages for $DISTRO_NAME $DISTRO_MAJOR_VERSION." + error_msg="$_REPO_URL likely doesn't have required 32-bit packages for $DISTRO_NAME $DISTRO_MAJOR_VERSION." # amd64 is just a part of repository URI, 32-bit pkgs are hosted under the same location - __REPO_ARCH="amd64" + __return_code=1 ;; "amd64") error_msg="" ;; "arm64") - if [ "$_CUSTOM_REPO_URL" != "null" ]; then - warn_msg="Support for arm64 is experimental, make sure the custom repository used has the expected structure and contents." - else - # Saltstack official repository has arm64 metadata beginning with Debian 11, - # use amd64 repositories on arm64 for anything older, since all pkgs are arch-independent - if [ "$DISTRO_NAME_L" = "debian" ] && [ "$DISTRO_MAJOR_VERSION" -lt 11 ]; then - __REPO_ARCH="amd64" - else - __REPO_ARCH="arm64" - fi - __REPO_ARCH_DEB="deb [signed-by=/usr/share/keyrings/salt-archive-keyring.gpg arch=$__REPO_ARCH]" - warn_msg="Support for arm64 packages is experimental and might rely on architecture-independent packages from the amd64 repository." - fi + # Saltstack official repository has full arm64 support since 3006 error_msg="" ;; "armhf") - if [ "$DISTRO_NAME_L" = "ubuntu" ] || [ "$DISTRO_MAJOR_VERSION" -lt 8 ]; then - error_msg="Support for armhf packages at $_REPO_URL is limited to Debian/Raspbian 8 platforms." - __return_code=1 - else - error_msg="" - fi + error_msg="$_REPO_URL doesn't have packages for your system architecture: $DPKG_ARCHITECTURE." + __return_code=1 ;; *) error_msg="$_REPO_URL doesn't have packages for your system architecture: $DPKG_ARCHITECTURE." @@ -1562,10 +1413,10 @@ __check_dpkg_architecture() { if [ "${error_msg}" != "" ]; then echoerror "${error_msg}" if [ "$ITYPE" != "git" ]; then - echoerror "You can try git installation mode, i.e.: sh ${__ScriptName} git v2017.7.2." + echoerror "You can try git installation mode, i.e.: sh ${__ScriptName} git v3006.6." echoerror "It may be necessary to use git installation mode with pip and disable the SaltStack apt repository." echoerror "For example:" - echoerror " sh ${__ScriptName} -r -P git v2017.7.2" + echoerror " sh ${__ScriptName} -r -P git v3006.6" fi fi @@ -1617,8 +1468,14 @@ __ubuntu_codename_translation() { "22") DISTRO_CODENAME="jammy" ;; + "23") + DISTRO_CODENAME="lunar" + ;; + "24") + DISTRO_CODENAME="noble" + ;; *) - DISTRO_CODENAME="trusty" + DISTRO_CODENAME="noble" ;; esac } @@ -1637,20 +1494,21 @@ __debian_derivatives_translation() { DEBIAN_DERIVATIVES="(cumulus|devuan|kali|linuxmint|raspbian|bunsenlabs|turnkey)" # Mappings - cumulus_2_debian_base="7.0" - cumulus_3_debian_base="8.0" - cumulus_4_debian_base="10.0" - devuan_1_debian_base="8.0" - devuan_2_debian_base="9.0" + cumulus_5_debian_base="11.0" + cumulus_6_debian_base="12.0" + devuan_4_debian_base="11.0" + devuan_5_debian_base="12.0" kali_1_debian_base="7.0" kali_2021_debian_base="10.0" - linuxmint_1_debian_base="8.0" - raspbian_8_debian_base="8.0" - raspbian_9_debian_base="9.0" - raspbian_10_debian_base="10.0" + linuxmint_4_debian_base="11.0" + linuxmint_5_debian_base="12.0" raspbian_11_debian_base="11.0" + raspbian_12_debian_base="12.0" bunsenlabs_9_debian_base="9.0" - turnkey_9_debian_base="9.0" + bunsenlabs_11_debian_base="11.0" + bunsenlabs_12_debian_base="12.0" + turnkey_11_debian_base="11.0" + turnkey_12_debian_base="12.0" # Translate Debian derivatives to their base Debian version match=$(echo "$DISTRO_NAME_L" | grep -E ${DEBIAN_DERIVATIVES}) @@ -1718,14 +1576,9 @@ __debian_codename_translation() { ;; "12") DISTRO_CODENAME="bookworm" - # FIXME - TEMPORARY - # use bullseye packages until bookworm packages are available - DISTRO_CODENAME="bullseye" - DISTRO_MAJOR_VERSION=11 - rv=11 ;; *) - DISTRO_CODENAME="stretch" + DISTRO_CODENAME="bookworm" ;; esac } @@ -1738,8 +1591,8 @@ __debian_codename_translation() { __check_end_of_life_versions() { case "${DISTRO_NAME_L}" in debian) - # Debian versions below 9 are not supported - if [ "$DISTRO_MAJOR_VERSION" -lt 9 ]; then + # Debian versions below 11 are not supported + if [ "$DISTRO_MAJOR_VERSION" -lt 11 ]; then echoerror "End of life distributions are not supported." echoerror "Please consider upgrading to the next stable. See:" echoerror " https://wiki.debian.org/DebianReleases" @@ -1750,18 +1603,18 @@ __check_end_of_life_versions() { ubuntu) # Ubuntu versions not supported # - # < 16.04 - # = 16.10 - # = 17.04, 17.10 - # = 18.10 - # = 19.04, 19.10 + # < 20.04 # = 20.10 - if [ "$DISTRO_MAJOR_VERSION" -lt 16 ] || \ - [ "$DISTRO_MAJOR_VERSION" -eq 17 ] || \ - [ "$DISTRO_MAJOR_VERSION" -eq 19 ] || \ - { [ "$DISTRO_MAJOR_VERSION" -eq 16 ] && [ "$DISTRO_MINOR_VERSION" -eq 10 ]; } || \ - { [ "$DISTRO_MAJOR_VERSION" -eq 18 ] && [ "$DISTRO_MINOR_VERSION" -eq 10 ]; } || \ - { [ "$DISTRO_MAJOR_VERSION" -eq 20 ] && [ "$DISTRO_MINOR_VERSION" -eq 10 ]; }; then + # = 21.04, 21.10 + # = 22.10 + # = 23.04, 23.10 + if [ "$DISTRO_MAJOR_VERSION" -lt 20 ] || \ + { [ "$DISTRO_MAJOR_VERSION" -eq 20 ] && [ "$DISTRO_MINOR_VERSION" -eq 10 ]; } || \ + { [ "$DISTRO_MAJOR_VERSION" -eq 21 ] && [ "$DISTRO_MINOR_VERSION" -eq 04 ]; } || \ + { [ "$DISTRO_MAJOR_VERSION" -eq 21 ] && [ "$DISTRO_MINOR_VERSION" -eq 10 ]; } || \ + { [ "$DISTRO_MAJOR_VERSION" -eq 22 ] && [ "$DISTRO_MINOR_VERSION" -eq 10 ]; } || \ + { [ "$DISTRO_MAJOR_VERSION" -eq 23 ] && [ "$DISTRO_MINOR_VERSION" -eq 04 ]; } || \ + { [ "$DISTRO_MAJOR_VERSION" -eq 23 ] && [ "$DISTRO_MINOR_VERSION" -eq 10 ]; }; then echoerror "End of life distributions are not supported." echoerror "Please consider upgrading to the next stable. See:" echoerror " https://wiki.ubuntu.com/Releases" @@ -1805,8 +1658,8 @@ __check_end_of_life_versions() { ;; fedora) - # Fedora lower than 33 are no longer supported - if [ "$DISTRO_MAJOR_VERSION" -lt 33 ]; then + # Fedora lower than 38 are no longer supported + if [ "$DISTRO_MAJOR_VERSION" -lt 39 ]; then echoerror "End of life distributions are not supported." echoerror "Please consider upgrading to the next stable. See:" echoerror " https://fedoraproject.org/wiki/Releases" @@ -1815,8 +1668,8 @@ __check_end_of_life_versions() { ;; centos) - # CentOS versions lower than 7 are no longer supported - if [ "$DISTRO_MAJOR_VERSION" -lt 7 ]; then + # CentOS versions lower than 8 are no longer supported + if [ "$DISTRO_MAJOR_VERSION" -lt 8 ]; then echoerror "End of life distributions are not supported." echoerror "Please consider upgrading to the next stable. See:" echoerror " http://wiki.centos.org/Download" @@ -1825,8 +1678,8 @@ __check_end_of_life_versions() { ;; red_hat*linux) - # Red Hat (Enterprise) Linux versions lower than 7 are no longer supported - if [ "$DISTRO_MAJOR_VERSION" -lt 7 ]; then + # Red Hat (Enterprise) Linux versions lower than 8 are no longer supported + if [ "$DISTRO_MAJOR_VERSION" -lt 8 ]; then echoerror "End of life distributions are not supported." echoerror "Please consider upgrading to the next stable. See:" echoerror " https://access.redhat.com/support/policy/updates/errata/" @@ -1835,8 +1688,8 @@ __check_end_of_life_versions() { ;; oracle*linux) - # Oracle Linux versions lower than 7 are no longer supported - if [ "$DISTRO_MAJOR_VERSION" -lt 7 ]; then + # Oracle Linux versions lower than 8 are no longer supported + if [ "$DISTRO_MAJOR_VERSION" -lt 8 ]; then echoerror "End of life distributions are not supported." echoerror "Please consider upgrading to the next stable. See:" echoerror " http://www.oracle.com/us/support/library/elsp-lifetime-069338.pdf" @@ -1845,8 +1698,8 @@ __check_end_of_life_versions() { ;; scientific*linux) - # Scientific Linux versions lower than 7 are no longer supported - if [ "$DISTRO_MAJOR_VERSION" -lt 7 ]; then + # Scientific Linux versions lower than 8 are no longer supported + if [ "$DISTRO_MAJOR_VERSION" -lt 8 ]; then echoerror "End of life distributions are not supported." echoerror "Please consider upgrading to the next stable. See:" echoerror " https://www.scientificlinux.org/downloads/sl-versions/" @@ -1855,8 +1708,8 @@ __check_end_of_life_versions() { ;; cloud*linux) - # Cloud Linux versions lower than 7 are no longer supported - if [ "$DISTRO_MAJOR_VERSION" -lt 7 ]; then + # Cloud Linux versions lower than 8 are no longer supported + if [ "$DISTRO_MAJOR_VERSION" -lt 8 ]; then echoerror "End of life distributions are not supported." echoerror "Please consider upgrading to the next stable. See:" echoerror " https://docs.cloudlinux.com/index.html?cloudlinux_life-cycle.html" @@ -1875,20 +1728,11 @@ __check_end_of_life_versions() { fi ;; - freebsd) - # FreeBSD versions lower than 11 are EOL - if [ "$DISTRO_MAJOR_VERSION" -lt 11 ]; then - echoerror "Versions lower than FreeBSD 11 are EOL and no longer supported." - exit 1 - fi - ;; - *) ;; esac } - __gather_system_info echo @@ -1963,8 +1807,16 @@ if [ "$_INSTALL_SYNDIC" -eq $BS_TRUE ]; then fi fi +if [ "$_INSTALL_SALT_API" -eq $BS_TRUE ]; then + if [ "$_CONFIG_ONLY" -eq $BS_FALSE ]; then + echoinfo "Installing salt api" + else + echoinfo "Configuring salt api" + fi +fi + if [ "$_INSTALL_CLOUD" -eq $BS_TRUE ] && [ "$_CONFIG_ONLY" -eq $BS_FALSE ]; then - echoinfo "Installing salt-cloud and required python-libcloud package" + echoinfo "Installing salt-cloud and required python3-libcloud package" fi if [ $_START_DAEMONS -eq $BS_FALSE ]; then @@ -2008,16 +1860,14 @@ fi if [ "$ITYPE" = "git" ]; then if [ "${GIT_REV}" = "master" ]; then - _POST_NEON_INSTALL=$BS_TRUE __TAG_REGEX_MATCH="MATCH" else case ${OS_NAME_L} in - openbsd|freebsd|netbsd|darwin ) + darwin ) __NEW_VS_TAG_REGEX_MATCH=$(echo "${GIT_REV}" | sed -E 's/^(v?3[0-9]{3}(\.[0-9]{1,2})?).*$/MATCH/') if [ "$__NEW_VS_TAG_REGEX_MATCH" = "MATCH" ]; then - _POST_NEON_INSTALL=$BS_TRUE __TAG_REGEX_MATCH="${__NEW_VS_TAG_REGEX_MATCH}" - echodebug "Post Neon Tag Regex Match On: ${GIT_REV}" + echodebug "Tag Regex Match On: ${GIT_REV}" else __TAG_REGEX_MATCH=$(echo "${GIT_REV}" | sed -E 's/^(v?[0-9]{1,4}\.[0-9]{1,2})(\.[0-9]{1,2})?.*$/MATCH/') echodebug "Pre Neon Tag Regex Match On: ${GIT_REV}" @@ -2026,9 +1876,8 @@ if [ "$ITYPE" = "git" ]; then * ) __NEW_VS_TAG_REGEX_MATCH=$(echo "${GIT_REV}" | sed 's/^.*\(v\?3[[:digit:]]\{3\}\(\.[[:digit:]]\{1,2\}\)\?\).*$/MATCH/') if [ "$__NEW_VS_TAG_REGEX_MATCH" = "MATCH" ]; then - _POST_NEON_INSTALL=$BS_TRUE __TAG_REGEX_MATCH="${__NEW_VS_TAG_REGEX_MATCH}" - echodebug "Post Neon Tag Regex Match On: ${GIT_REV}" + echodebug "Tag Regex Match On: ${GIT_REV}" else __TAG_REGEX_MATCH=$(echo "${GIT_REV}" | sed 's/^.*\(v\?[[:digit:]]\{1,4\}\.[[:digit:]]\{1,2\}\)\(\.[[:digit:]]\{1,2\}\)\?.*$/MATCH/') echodebug "Pre Neon Tag Regex Match On: ${GIT_REV}" @@ -2037,18 +1886,16 @@ if [ "$ITYPE" = "git" ]; then esac fi - if [ "$_POST_NEON_INSTALL" -eq $BS_TRUE ]; then - echo - echowarn "Post Neon git based installations will always install salt" - echowarn "and its dependencies using pip which will be upgraded to" - echowarn "at least v${_MINIMUM_PIP_VERSION}, and, in case the setuptools version is also" - echowarn "too old, it will be upgraded to at least v${_MINIMUM_SETUPTOOLS_VERSION}" - echo - echowarn "You have 10 seconds to cancel and stop the bootstrap process..." - echo - sleep 10 - _PIP_ALLOWED=$BS_TRUE - fi + echo + echowarn "git based installations will always install salt" + echowarn "and its dependencies using pip which will be upgraded to" + echowarn "at least v${_MINIMUM_PIP_VERSION}, and, in case the setuptools version is also" + echowarn "too old, it will be upgraded to at least v${_MINIMUM_SETUPTOOLS_VERSION} and less than v${_MAXIMUM_SETUPTOOLS_VERSION}" + echo + echowarn "You have 10 seconds to cancel and stop the bootstrap process..." + echo + sleep 10 + _PIP_ALLOWED=$BS_TRUE fi @@ -2080,12 +1927,17 @@ __wait_for_apt(){ # Timeout set at 15 minutes WAIT_TIMEOUT=900 + ## see if sync'ing the clocks helps + if [ -f /usr/sbin/hwclock ]; then + /usr/sbin/hwclock -s + fi + # Run our passed in apt command "${@}" 2>"$APT_ERR" APT_RETURN=$? # Make sure we're not waiting on a lock - while [ $APT_RETURN -ne 0 ] && grep -q '^E: Could not get lock' "$APT_ERR"; do + while [ "$APT_RETURN" -ne 0 ] && grep -q '^E: Could not get lock' "$APT_ERR"; do echoinfo "Aware of the lock. Patiently waiting $WAIT_TIMEOUT more seconds..." sleep 1 WAIT_TIMEOUT=$((WAIT_TIMEOUT - 1)) @@ -2109,6 +1961,7 @@ __wait_for_apt(){ # PARAMETERS: packages #---------------------------------------------------------------------------------------------------------------------- __apt_get_install_noinput() { + __wait_for_apt apt-get install -y -o DPkg::Options::=--force-confold "${@}"; return $? } # ---------- end of function __apt_get_install_noinput ---------- @@ -2118,6 +1971,7 @@ __apt_get_install_noinput() { # DESCRIPTION: (DRY) apt-get upgrade with noinput options #---------------------------------------------------------------------------------------------------------------------- __apt_get_upgrade_noinput() { + __wait_for_apt apt-get upgrade -y -o DPkg::Options::=--force-confold; return $? } # ---------- end of function __apt_get_upgrade_noinput ---------- @@ -2148,12 +2002,14 @@ __temp_gpg_pub() { # PARAMETERS: url #---------------------------------------------------------------------------------------------------------------------- __apt_key_fetch() { + + url=$1 tempfile="$(__temp_gpg_pub)" - __fetch_url "$tempfile" "$url" || return 1 - cp -f "$tempfile" /usr/share/keyrings/salt-archive-keyring.gpg && chmod 644 /usr/share/keyrings/salt-archive-keyring.gpg || return 1 + mkdir -p /etc/apt/keyrings + cp -f "$tempfile" /etc/apt/keyrings/salt-archive-keyring.pgp && chmod 644 /etc/apt/keyrings/salt-archive-keyring.pgp || return 1 rm -f "$tempfile" return 0 @@ -2166,6 +2022,7 @@ __apt_key_fetch() { # PARAMETERS: url #---------------------------------------------------------------------------------------------------------------------- __rpm_import_gpg() { + url=$1 tempfile="$(__temp_gpg_pub)" @@ -2290,10 +2147,15 @@ __git_clone_and_checkout() { if [ "$(git clone 2>&1 | grep 'single-branch')" != "" ]; then # The "--single-branch" option is supported, attempt shallow cloning echoinfo "Attempting to shallow clone $GIT_REV from Salt's repository ${_SALT_REPO_URL}" - if git clone --depth 1 --branch "$GIT_REV" "$_SALT_REPO_URL" "$__SALT_CHECKOUT_REPONAME"; then + ## Shallow cloning is resulting in the wrong version of Salt, even with a depth of 5 + ## getting 3007.0+0na.246d066 when it should be 3007.1+410.g246d066457, disabling for now + ## if git clone --depth 1 --branch "$GIT_REV" "$_SALT_REPO_URL" "$__SALT_CHECKOUT_REPONAME"; then + echodebug "git command, git clone --branch $GIT_REV $_SALT_REPO_URL $__SALT_CHECKOUT_REPONAME" + if git clone --branch "$GIT_REV" "$_SALT_REPO_URL" "$__SALT_CHECKOUT_REPONAME"; then # shellcheck disable=SC2164 cd "${_SALT_GIT_CHECKOUT_DIR}" __SHALLOW_CLONE=$BS_TRUE + echoinfo "shallow path (disabled shallow) git cloned $GIT_REV, version $(python3 salt/version.py)" else # Shallow clone above failed(missing upstream tags???), let's resume the old behaviour. echowarn "Failed to shallow clone." @@ -2307,10 +2169,13 @@ __git_clone_and_checkout() { fi if [ "$__SHALLOW_CLONE" -eq $BS_FALSE ]; then + echodebug "shallow clone false, BS_FALSE $BS_FALSE, git clone $_SALT_REPO_URL $__SALT_CHECKOUT_REPONAME" git clone "$_SALT_REPO_URL" "$__SALT_CHECKOUT_REPONAME" || return 1 # shellcheck disable=SC2164 cd "${_SALT_GIT_CHECKOUT_DIR}" + echoinfo "git cloned $GIT_REV, version $(python3 salt/version.py)" + if ! echo "$_SALT_REPO_URL" | grep -q -F -w "${_SALTSTACK_REPO_URL#*://}"; then # We need to add the saltstack repository as a remote and fetch tags for proper versioning echoinfo "Adding SaltStack's Salt repository as a remote" @@ -2403,7 +2268,7 @@ __movefile() { exit 1 fi - if [ $_KEEP_TEMP_FILES -eq $BS_TRUE ]; then + if [ "$_KEEP_TEMP_FILES" -eq $BS_TRUE ]; then # We're being told not to move files, instead copy them so we can keep # them around echodebug "Since BS_KEEP_TEMP_FILES=1 we're copying files instead of moving them" @@ -2520,14 +2385,17 @@ __overwriteconfig() { if [ -n "$_PY_EXE" ]; then good_python="$_PY_EXE" # If python does not have yaml installed we're on Arch and should use python2 + # but no more support, hence error out elif python -c "import yaml" 2> /dev/null; then - good_python=python + good_python=python # assume python is python 3 on Arch else - good_python=python2 + ## good_python=python2 + echoerror "Python 2 is no longer supported, only Python 3" + return 1 fi # Convert json string to a yaml string and write it to config file. Output is dumped into tempfile. - "$good_python" -c "import json; import yaml; jsn=json.loads('$json'); yml=yaml.safe_dump(jsn, line_break='\\n', default_flow_style=False); config_file=open('$target', 'w'); config_file.write(yml); config_file.close();" 2>$tempfile + "$good_python" -c "import json; import yaml; jsn=json.loads('$json'); yml=yaml.safe_dump(jsn, line_break='\\n', default_flow_style=False, sort_keys=False); config_file=open('$target', 'w'); config_file.write(yml); config_file.close();" 2>"$tempfile" # No python errors output to the tempfile if [ ! -s "$tempfile" ]; then @@ -2552,6 +2420,7 @@ __overwriteconfig() { # PARAMETERS: servicename #---------------------------------------------------------------------------------------------------------------------- __check_services_systemd() { + if [ $# -eq 0 ]; then echoerror "You need to pass a service name to check!" exit 1 @@ -2559,6 +2428,21 @@ __check_services_systemd() { echoerror "You need to pass a service name to check as the single argument to the function" fi + # check if systemd is functional, having systemctl present is insufficient + + if [ "$_SYSTEMD_FUNCTIONAL" -eq $BS_FALSE ]; then + # already determined systemd is not functional, default is 1 + return 1 + fi + + _SYSTEMD_ACTIVE=$(/bin/systemctl daemon-reload 2>&1 | grep 'System has not been booted with systemd') + echodebug "__check_services_systemd _SYSTEMD_ACTIVE result ,$_SYSTEMD_ACTIVE," + if [ "$_SYSTEMD_ACTIVE" != "" ]; then + _SYSTEMD_FUNCTIONAL=$BS_FALSE + echodebug "systemd is not functional, despite systemctl being present, setting _SYSTEMD_FUNCTIONAL false, $_SYSTEMD_FUNCTIONAL" + return 1 + fi + servicename=$1 echodebug "Checking if service ${servicename} is enabled" @@ -2578,6 +2462,7 @@ __check_services_systemd() { # PARAMETERS: servicename #---------------------------------------------------------------------------------------------------------------------- __check_services_upstart() { + if [ $# -eq 0 ]; then echoerror "You need to pass a service name to check!" exit 1 @@ -2605,6 +2490,7 @@ __check_services_upstart() { # PARAMETERS: servicename #---------------------------------------------------------------------------------------------------------------------- __check_services_sysvinit() { + if [ $# -eq 0 ]; then echoerror "You need to pass a service name to check!" exit 1 @@ -2631,6 +2517,7 @@ __check_services_sysvinit() { # PARAMETERS: servicename #---------------------------------------------------------------------------------------------------------------------- __check_services_debian() { + if [ $# -eq 0 ]; then echoerror "You need to pass a service name to check!" exit 1 @@ -2652,38 +2539,13 @@ __check_services_debian() { } # ---------- end of function __check_services_debian ---------- -#--- FUNCTION ------------------------------------------------------------------------------------------------------- -# NAME: __check_services_openbsd -# DESCRIPTION: Return 0 or 1 in case the service is enabled or not -# PARAMETERS: servicename -#---------------------------------------------------------------------------------------------------------------------- -__check_services_openbsd() { - if [ $# -eq 0 ]; then - echoerror "You need to pass a service name to check!" - exit 1 - elif [ $# -ne 1 ]; then - echoerror "You need to pass a service name to check as the single argument to the function" - fi - - servicename=$1 - echodebug "Checking if service ${servicename} is enabled" - - # shellcheck disable=SC2086,SC2046,SC2144 - if rcctl get ${servicename} status; then - echodebug "Service ${servicename} is enabled" - return 0 - else - echodebug "Service ${servicename} is NOT enabled" - return 1 - fi -} # ---------- end of function __check_services_openbsd ---------- - #--- FUNCTION ------------------------------------------------------------------------------------------------------- # NAME: __check_services_openrc # DESCRIPTION: Return 0 or 1 in case the service is enabled or not # PARAMETERS: servicename #---------------------------------------------------------------------------------------------------------------------- __check_services_openrc() { + if [ $# -eq 0 ]; then echoerror "You need to pass a service name to check!" exit 1 @@ -2710,9 +2572,10 @@ __check_services_openrc() { # DESCRIPTION: Return 0 or 1 depending on successful creation of virtualenv #---------------------------------------------------------------------------------------------------------------------- __create_virtualenv() { + if [ ! -d "$_VIRTUALENV_DIR" ]; then echoinfo "Creating virtualenv ${_VIRTUALENV_DIR}" - if [ $_PIP_ALL -eq $BS_TRUE ]; then + if [ "$_PIP_ALL" -eq $BS_TRUE ]; then virtualenv --no-site-packages "${_VIRTUALENV_DIR}" || return 1 else virtualenv --system-site-packages "${_VIRTUALENV_DIR}" || return 1 @@ -2727,6 +2590,7 @@ __create_virtualenv() { # DESCRIPTION: Return 0 or 1 depending on successful activation of virtualenv #---------------------------------------------------------------------------------------------------------------------- __activate_virtualenv() { + set +o nounset # Is virtualenv empty if [ -z "$_VIRTUALENV_DIR" ]; then @@ -2753,7 +2617,7 @@ __install_pip_pkgs() { _pip_cmd="${_py_exe} -m pip" if [ "${_py_exe}" = "" ]; then - _py_exe='python' + _py_exe='python3' fi __check_pip_allowed @@ -2781,17 +2645,6 @@ __install_pip_pkgs() { ${_pip_cmd} install ${_pip_pkgs} || return 1 } -#--- FUNCTION ------------------------------------------------------------------------------------------------------- -# NAME: __install_tornado_pip -# PARAMETERS: python executable -# DESCRIPTION: Return 0 or 1 if successfully able to install tornado<5.0 -#---------------------------------------------------------------------------------------------------------------------- -__install_tornado_pip() { - # OS needs tornado <5.0 from pip - __check_pip_allowed "You need to allow pip based installations (-P) for Tornado <5.0 in order to install Salt on Python 3" - ## install pip if its not installed and install tornado - __install_pip_pkgs "tornado<5.0" "${1}" || return 1 -} #--- FUNCTION ------------------------------------------------------------------------------------------------------- # NAME: __install_pip_deps @@ -2829,19 +2682,20 @@ __install_pip_deps() { } # ---------- end of function __install_pip_deps ---------- #--- FUNCTION ------------------------------------------------------------------------------------------------------- -# NAME: __install_salt_from_repo_post_neon +# NAME: __install_salt_from_repo # DESCRIPTION: Return 0 or 1 if successfully able to install. Can provide a different python version to # install pip packages with. If $py_exe is not specified it will use the default python version. # PARAMETERS: py_exe #---------------------------------------------------------------------------------------------------------------------- -__install_salt_from_repo_post_neon() { +__install_salt_from_repo() { + _py_exe="$1" if [ "${_py_exe}" = "" ]; then - _py_exe='python' + _py_exe="python3" fi - echodebug "__install_salt_from_repo_post_neon py_exe=$_py_exe" + echodebug "__install_salt_from_repo py_exe=$_py_exe" _py_version=$(${_py_exe} -c "import sys; print('{0}.{1}'.format(*sys.version_info))") _pip_cmd="pip${_py_version}" @@ -2879,14 +2733,9 @@ except ImportError: EOM ) if ! ${_py_exe} -c "$CHECK_PIP_VERSION_SCRIPT"; then - # Upgrade pip to at least 1.2 which is when we can start using "python -m pip" - if [ "${_py_version}" = "3.5" ]; then - echodebug "Running '${_pip_cmd} install ${_POST_NEON_PIP_INSTALL_ARGS} pip>=${_MINIMUM_PIP_VERSION},<21.0'" - ${_pip_cmd} install ${_POST_NEON_PIP_INSTALL_ARGS} -v "pip>=${_MINIMUM_PIP_VERSION},<21.0" - else - echodebug "Running '${_pip_cmd} install ${_POST_NEON_PIP_INSTALL_ARGS} pip>=${_MINIMUM_PIP_VERSION}'" - ${_pip_cmd} install ${_POST_NEON_PIP_INSTALL_ARGS} -v "pip>=${_MINIMUM_PIP_VERSION}" - fi + # Upgrade pip to at least 1.2 which is when we can start using "python3 -m pip" + echodebug "Running '${_pip_cmd} install ${_PIP_INSTALL_ARGS} pip>=${_MINIMUM_PIP_VERSION}'" + ${_pip_cmd} install ${_PIP_INSTALL_ARGS} -v "pip>=${_MINIMUM_PIP_VERSION}" sleep 1 echodebug "PATH: ${PATH}" _pip_cmd="pip${_py_version}" @@ -2905,26 +2754,43 @@ EOM echodebug "Installed pip version: $(${_pip_cmd} --version)" fi - _setuptools_dep="setuptools>=${_MINIMUM_SETUPTOOLS_VERSION}" - if [ "$_PY_MAJOR_VERSION" -eq 2 ]; then - # We also lock setuptools to <45 which is the latest release to support both py2 and py3 - _setuptools_dep="${_setuptools_dep},<45" + _setuptools_dep="setuptools>=${_MINIMUM_SETUPTOOLS_VERSION},<${_MAXIMUM_SETUPTOOLS_VERSION}" + if [ "$_PY_MAJOR_VERSION" -ne 3 ]; then + echoerror "Python version is no longer supported, only Python 3" + return 1 fi - echodebug "Running '${_pip_cmd} install wheel ${_setuptools_dep}'" - ${_pip_cmd} install --upgrade ${_POST_NEON_PIP_INSTALL_ARGS} wheel "${_setuptools_dep}" + _USE_BREAK_SYSTEM_PACKAGES="" + # shellcheck disable=SC2086,SC2090 + if { [ ${DISTRO_NAME_L} = "ubuntu" ] && [ "$DISTRO_MAJOR_VERSION" -ge 24 ]; } || \ + [ ${DISTRO_NAME_L} = "debian" ] && [ "$DISTRO_MAJOR_VERSION" -ge 12 ]; then + _USE_BREAK_SYSTEM_PACKAGES="--break-system-packages" + echodebug "OS is greater than / equal Debian 12 or Ubuntu 24.04, using ${_USE_BREAK_SYSTEM_PACKAGES}" + fi - echoinfo "Installing salt using ${_py_exe}" + echodebug "Running '${_pip_cmd} install ${_USE_BREAK_SYSTEM_PACKAGES} --upgrade ${_PIP_INSTALL_ARGS} wheel ${_setuptools_dep}" + ${_pip_cmd} install ${_USE_BREAK_SYSTEM_PACKAGES} --upgrade ${_PIP_INSTALL_ARGS} wheel "${_setuptools_dep}" + + echoinfo "Installing salt using ${_py_exe}, $(${_py_exe} --version)" cd "${_SALT_GIT_CHECKOUT_DIR}" || return 1 - mkdir /tmp/git/deps + mkdir -p /tmp/git/deps + echodebug "Created directory /tmp/git/deps" + echodebug "Installing Salt dependencies for Salt version $(python3 salt/version.py)" + + if [ ${DISTRO_NAME_L} = "ubuntu" ] && [ "$DISTRO_MAJOR_VERSION" -eq 22 ]; then + echodebug "Ubuntu 22.04 has problem with base.txt requirements file, not parsing sys_platform == 'win32', upgrading from default pip works" + echodebug "${_pip_cmd} install ${_USE_BREAK_SYSTEM_PACKAGES} --upgrade pip" + ${_pip_cmd} install ${_USE_BREAK_SYSTEM_PACKAGES} --upgrade pip || (echo "Failed to upgrade pip" && return 1) + fi + echoinfo "Downloading Salt Dependencies from PyPi" echodebug "Running '${_pip_cmd} download -d /tmp/git/deps ${_PIP_DOWNLOAD_ARGS} .'" ${_pip_cmd} download -d /tmp/git/deps ${_PIP_DOWNLOAD_ARGS} . || (echo "Failed to download salt dependencies" && return 1) echoinfo "Installing Downloaded Salt Dependencies" - echodebug "Running '${_pip_cmd} install --ignore-installed ${_POST_NEON_PIP_INSTALL_ARGS} /tmp/git/deps/*'" - ${_pip_cmd} install --ignore-installed ${_POST_NEON_PIP_INSTALL_ARGS} /tmp/git/deps/* || return 1 + echodebug "Running '${_pip_cmd} install ${_USE_BREAK_SYSTEM_PACKAGES} --ignore-installed ${_PIP_INSTALL_ARGS} /tmp/git/deps/*'" + ${_pip_cmd} install ${_USE_BREAK_SYSTEM_PACKAGES} --ignore-installed ${_PIP_INSTALL_ARGS} /tmp/git/deps/* || return 1 rm -f /tmp/git/deps/* echoinfo "Building Salt Python Wheel" @@ -2934,16 +2800,27 @@ EOM fi echodebug "Running '${_py_exe} setup.py --salt-config-dir=$_SALT_ETC_DIR --salt-cache-dir=${_SALT_CACHE_DIR} ${SETUP_PY_INSTALL_ARGS} bdist_wheel'" - ${_py_exe} setup.py --salt-config-dir="$_SALT_ETC_DIR" --salt-cache-dir="${_SALT_CACHE_DIR}" ${SETUP_PY_INSTALL_ARGS} bdist_wheel || return 1 + ${_py_exe} setup.py --salt-config-dir="$_SALT_ETC_DIR" --salt-cache-dir="${_SALT_CACHE_DIR} ${SETUP_PY_INSTALL_ARGS}" bdist_wheel || return 1 mv dist/salt*.whl /tmp/git/deps/ || return 1 cd "${__SALT_GIT_CHECKOUT_PARENT_DIR}" || return 1 echoinfo "Installing Built Salt Wheel" - ${_pip_cmd} uninstall --yes salt 2>/dev/null || true - echodebug "Running '${_pip_cmd} install --no-deps --force-reinstall ${_POST_NEON_PIP_INSTALL_ARGS} /tmp/git/deps/salt*.whl'" - ${_pip_cmd} install --no-deps --force-reinstall \ - ${_POST_NEON_PIP_INSTALL_ARGS} \ + ${_pip_cmd} uninstall --yes ${_USE_BREAK_SYSTEM_PACKAGES} salt 2>/dev/null || true + + # Hack for getting current Arch working with git-master + if [ "${DISTRO_NAME}" = "Arch Linux" ]; then + _arch_dep="cryptography==42.0.7" # debug matching current Arch version of python-cryptography + echodebug "Running '${_pip_cmd} install --force-reinstall --break-system-packages ${_arch_dep}'" + ${_pip_cmd} install --force-reinstall --break-system-packages "${_arch_dep}" + fi + + echodebug "Running '${_pip_cmd} install ${_USE_BREAK_SYSTEM_PACKAGES} --no-deps --force-reinstall ${_PIP_INSTALL_ARGS} /tmp/git/deps/salt*.whl'" + + echodebug "Running ${_pip_cmd} install ${_USE_BREAK_SYSTEM_PACKAGES} --no-deps --force-reinstall ${_PIP_INSTALL_ARGS} --global-option=--salt-config-dir=$_SALT_ETC_DIR --salt-cache-dir=${_SALT_CACHE_DIR} ${SETUP_PY_INSTALL_ARGS} /tmp/git/deps/salt*.whl" + + ${_pip_cmd} install ${_USE_BREAK_SYSTEM_PACKAGES} --no-deps --force-reinstall \ + ${_PIP_INSTALL_ARGS} \ --global-option="--salt-config-dir=$_SALT_ETC_DIR --salt-cache-dir=${_SALT_CACHE_DIR} ${SETUP_PY_INSTALL_ARGS}" \ /tmp/git/deps/salt*.whl || return 1 @@ -2966,21 +2843,16 @@ EOM return 1 fi return 0 -} # ---------- end of function __install_salt_from_repo_post_neon ---------- +} # ---------- end of function __install_salt_from_repo ---------- -if [ "${_POST_NEON_INSTALL}" -eq $BS_FALSE ]; then - if [ "x${_PY_MAJOR_VERSION}" = "x" ]; then - # Default to python 2 for pre Neon installs - _PY_MAJOR_VERSION=2 - fi -else - if [ "x${_PY_MAJOR_VERSION}" = "x" ]; then - # Default to python 3 for post Neon install - _PY_MAJOR_VERSION=3 - fi +# shellcheck disable=SC2268 +if [ "x${_PY_MAJOR_VERSION}" = "x" ]; then + # Default to python 3 for install + _PY_MAJOR_VERSION=3 fi + ####################################################################################################################### # # Distribution install functions @@ -3064,6 +2936,7 @@ fi # Ubuntu Install Functions # __enable_universe_repository() { + if [ "$(grep -R universe /etc/apt/sources.list /etc/apt/sources.list.d/ | grep -v '#')" != "" ]; then # The universe repository is already enabled return 0 @@ -3078,15 +2951,13 @@ __enable_universe_repository() { __install_saltstack_ubuntu_repository() { # Workaround for latest non-LTS Ubuntu + echodebug "__install_saltstack_ubuntu_repository() entry" + if { [ "$DISTRO_MAJOR_VERSION" -eq 20 ] && [ "$DISTRO_MINOR_VERSION" -eq 10 ]; } || \ - # remove 22 version when salt packages for 22.04 are available - [ "$DISTRO_MAJOR_VERSION" -eq 21 ] || [ "$DISTRO_MAJOR_VERSION" -eq 22 ]; then + { [ "$DISTRO_MAJOR_VERSION" -eq 22 ] && [ "$DISTRO_MINOR_VERSION" -eq 10 ]; } || \ + { [ "$DISTRO_MAJOR_VERSION" -eq 24 ] && [ "$DISTRO_MINOR_VERSION" -eq 10 ]; } || \ + [ "$DISTRO_MAJOR_VERSION" -eq 21 ] || [ "$DISTRO_MAJOR_VERSION" -eq 23 ] || [ "$DISTRO_MAJOR_VERSION" -eq 25 ]; then echowarn "Non-LTS Ubuntu detected, but stable packages requested. Trying packages for previous LTS release. You may experience problems." - UBUNTU_VERSION=20.04 - UBUNTU_CODENAME="focal" - else - UBUNTU_VERSION=${DISTRO_VERSION} - UBUNTU_CODENAME=${DISTRO_CODENAME} fi # Install downloader backend for GPG keys fetching @@ -3102,33 +2973,48 @@ __install_saltstack_ubuntu_repository() { __PACKAGES="${__PACKAGES} apt-transport-https ca-certificates" fi + ## include hwclock if not part of base OS (23.10 and up) + if [ ! -f /usr/sbin/hwclock ]; then + __PACKAGES="${__PACKAGES} util-linux-extra" + fi + # shellcheck disable=SC2086,SC2090 __apt_get_install_noinput ${__PACKAGES} || return 1 - __PY_VERSION_REPO="apt" - if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -eq 3 ]; then - __PY_VERSION_REPO="py3" + if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -ne 3 ]; then + echoerror "Python version is not supported, only Python 3" + return 1 fi # SaltStack's stable Ubuntu repository: - SALTSTACK_UBUNTU_URL="${HTTP_VAL}://${_REPO_URL}/${__PY_VERSION_REPO}/ubuntu/${UBUNTU_VERSION}/${__REPO_ARCH}/${STABLE_REV}" - echo "$__REPO_ARCH_DEB $SALTSTACK_UBUNTU_URL $UBUNTU_CODENAME main" > /etc/apt/sources.list.d/salt.list - - __apt_key_fetch "$SALTSTACK_UBUNTU_URL/salt-archive-keyring.gpg" || return 1 - + __fetch_url "/etc/apt/sources.list.d/salt.sources" "https://github.com/saltstack/salt-install-guide/releases/latest/download/salt.sources" + __apt_key_fetch "${HTTP_VAL}://${_REPO_URL}/api/security/keypair/SaltProjectKey/public" || return 1 __wait_for_apt apt-get update || return 1 + + if [ "$STABLE_REV" != "latest" ]; then + # latest is default + STABLE_REV_MAJOR=$(echo "$STABLE_REV" | cut -d '.' -f 1) + if [ "$STABLE_REV_MAJOR" -eq "3006" ]; then + echo "Package: salt-*" > /etc/apt/preferences.d/salt-pin-1001 + echo "Pin: version 3006.*" >> /etc/apt/preferences.d/salt-pin-1001 + echo "Pin-Priority: 1001" >> /etc/apt/preferences.d/salt-pin-1001 + elif [ "$STABLE_REV_MAJOR" -eq "3007" ]; then + echo "Package: salt-*" > /etc/apt/preferences.d/salt-pin-1001 + echo "Pin: version 3007.*" >> /etc/apt/preferences.d/salt-pin-1001 + echo "Pin-Priority: 1001" >> /etc/apt/preferences.d/salt-pin-1001 + fi + fi + } __install_saltstack_ubuntu_onedir_repository() { + + echodebug "__install_saltstack_ubuntu_onedir_repository() entry" # Workaround for latest non-LTS Ubuntu if { [ "$DISTRO_MAJOR_VERSION" -eq 20 ] && [ "$DISTRO_MINOR_VERSION" -eq 10 ]; } || \ - [ "$DISTRO_MAJOR_VERSION" -eq 21 ]; then + { [ "$DISTRO_MAJOR_VERSION" -eq 22 ] && [ "$DISTRO_MINOR_VERSION" -eq 10 ]; } || \ + [ "$DISTRO_MAJOR_VERSION" -eq 21 ] || [ "$DISTRO_MAJOR_VERSION" -eq 23 ] || [ "$DISTRO_MAJOR_VERSION" -eq 25 ]; then echowarn "Non-LTS Ubuntu detected, but stable packages requested. Trying packages for previous LTS release. You may experience problems." - UBUNTU_VERSION=20.04 - UBUNTU_CODENAME="focal" - else - UBUNTU_VERSION=${DISTRO_VERSION} - UBUNTU_CODENAME=${DISTRO_CODENAME} fi # Install downloader backend for GPG keys fetching @@ -3144,35 +3030,38 @@ __install_saltstack_ubuntu_onedir_repository() { __PACKAGES="${__PACKAGES} apt-transport-https ca-certificates" fi + ## include hwclock if not part of base OS (23.10 and up) + if [ ! -f /usr/sbin/hwclock ]; then + __PACKAGES="${__PACKAGES} util-linux-extra" + fi + # shellcheck disable=SC2086,SC2090 __apt_get_install_noinput ${__PACKAGES} || return 1 - __PY_VERSION_REPO="apt" - if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -eq 3 ]; then - __PY_VERSION_REPO="py3" - fi - # SaltStack's stable Ubuntu repository: - SALTSTACK_UBUNTU_URL="${HTTP_VAL}://${_REPO_URL}/${_ONEDIR_DIR}/${__PY_VERSION_REPO}/ubuntu/${UBUNTU_VERSION}/${__REPO_ARCH}/${ONEDIR_REV}/" - if [ "${ONEDIR_REV}" = "nightly" ] ; then - SALTSTACK_UBUNTU_URL="${HTTP_VAL}://${_REPO_URL}/${_ONEDIR_NIGHTLY_DIR}/${__PY_VERSION_REPO}/ubuntu/${UBUNTU_VERSION}/${__REPO_ARCH}/" - fi - echo "$__REPO_ARCH_DEB $SALTSTACK_UBUNTU_URL $UBUNTU_CODENAME main" > /etc/apt/sources.list.d/salt.list - - if [ "$(echo "${ONEDIR_REV}" | grep -E '(3004|3005)')" != "" ]; then - __apt_key_fetch "${SALTSTACK_UBUNTU_URL}salt-archive-keyring.gpg" || return 1 - elif [ "$(echo "${ONEDIR_REV}" | grep -E '(latest|nightly)')" != "" ]; then - __apt_key_fetch "${SALTSTACK_UBUNTU_URL}salt-archive-keyring.gpg" || \ - __apt_key_fetch "${SALTSTACK_UBUNTU_URL}SALT-PROJECT-GPG-PUBKEY-2023.gpg" || return 1 - else - __apt_key_fetch "${SALTSTACK_UBUNTU_URL}SALT-PROJECT-GPG-PUBKEY-2023.gpg" || return 1 - fi - + __fetch_url "/etc/apt/sources.list.d/salt.sources" "https://github.com/saltstack/salt-install-guide/releases/latest/download/salt.sources" + __apt_key_fetch "${HTTP_VAL}://${_REPO_URL}/api/security/keypair/SaltProjectKey/public" || return 1 __wait_for_apt apt-get update || return 1 + + if [ "$ONEDIR_REV" != "latest" ]; then + # latest is default + ONEDIR_REV_MAJOR=$(echo "$ONEDIR_REV" | cut -d '.' -f 1) + if [ "$ONEDIR_REV_MAJOR" -eq "3006" ]; then + echo "Package: salt-*" > /etc/apt/preferences.d/salt-pin-1001 + echo "Pin: version 3006.*" >> /etc/apt/preferences.d/salt-pin-1001 + echo "Pin-Priority: 1001" >> /etc/apt/preferences.d/salt-pin-1001 + elif [ "$ONEDIR_REV_MAJOR" -eq "3007" ]; then + echo "Package: salt-*" > /etc/apt/preferences.d/salt-pin-1001 + echo "Pin: version 3007.*" >> /etc/apt/preferences.d/salt-pin-1001 + echo "Pin-Priority: 1001" >> /etc/apt/preferences.d/salt-pin-1001 + fi + fi } install_ubuntu_deps() { - if [ $_DISABLE_REPOS -eq $BS_FALSE ]; then + + echodebug "install_ubuntu_deps() entry" + if [ "$_DISABLE_REPOS" -eq $BS_FALSE ]; then # Install add-apt-repository if ! __check_command_exists add-apt-repository; then __apt_get_install_noinput software-properties-common || return 1 @@ -3185,24 +3074,19 @@ install_ubuntu_deps() { __PACKAGES='' - if [ "$DISTRO_MAJOR_VERSION" -lt 16 ]; then - # Minimal systems might not have upstart installed, install it - __PACKAGES="upstart" + if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -ne 3 ]; then + echoerror "Python version is no longer supported, only Python 3" + return 1 fi - if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -eq 3 ]; then - PY_PKG_VER=3 - else - PY_PKG_VER="" - fi - - if [ "$DISTRO_MAJOR_VERSION" -ge 16 ] && [ -z "$_PY_EXE" ]; then - __PACKAGES="${__PACKAGES} python2.7" + if [ "$DISTRO_MAJOR_VERSION" -ge 20 ] && [ -z "$_PY_EXE" ]; then + __PACKAGES="${__PACKAGES} python${PY_PKG_VER}" fi if [ "$_VIRTUALENV_DIR" != "null" ]; then - __PACKAGES="${__PACKAGES} python-virtualenv" + __PACKAGES="${__PACKAGES} python${PY_PKG_VER}-virtualenv" fi + # Need python-apt for managing packages via Salt __PACKAGES="${__PACKAGES} python${PY_PKG_VER}-apt" @@ -3215,6 +3099,11 @@ install_ubuntu_deps() { # Additionally install procps and pciutils which allows for Docker bootstraps. See 366#issuecomment-39666813 __PACKAGES="${__PACKAGES} procps pciutils" + ## include hwclock if not part of base OS (23.10 and up) + if [ ! -f /usr/sbin/hwclock ]; then + __PACKAGES="${__PACKAGES} util-linux-extra" + fi + # shellcheck disable=SC2086,SC2090 __apt_get_install_noinput ${__PACKAGES} || return 1 @@ -3228,14 +3117,10 @@ install_ubuntu_deps() { } install_ubuntu_stable_deps() { - if [ "${_SLEEP}" -eq "${__DEFAULT_SLEEP}" ] && [ "$DISTRO_MAJOR_VERSION" -lt 16 ]; then - # The user did not pass a custom sleep value as an argument, let's increase the default value - echodebug "On Ubuntu systems we increase the default sleep value to 10." - echodebug "See https://github.com/saltstack/salt/issues/12248 for more info." - _SLEEP=10 - fi - if [ $_START_DAEMONS -eq $BS_FALSE ]; then + echodebug "install_ubuntu_stable_deps() entry" + + if [ "$_START_DAEMONS" -eq $BS_FALSE ]; then echowarn "Not starting daemons on Debian based distributions is not working mostly because starting them is the default behaviour." fi @@ -3246,7 +3131,8 @@ install_ubuntu_stable_deps() { if [ "${_UPGRADE_SYS}" -eq $BS_TRUE ]; then if [ "${_INSECURE_DL}" -eq $BS_TRUE ]; then - if [ "$DISTRO_MAJOR_VERSION" -ge 20 ] || [ "$DISTRO_MAJOR_VERSION" -ge 21 ] || [ "$DISTRO_MAJOR_VERSION" -ge 22 ]; then + ## apt-key is deprecated + if [ "$DISTRO_MAJOR_VERSION" -ge 20 ]; then __apt_get_install_noinput --allow-unauthenticated debian-archive-keyring && apt-get update || return 1 else __apt_get_install_noinput --allow-unauthenticated debian-archive-keyring && @@ -3266,6 +3152,9 @@ install_ubuntu_stable_deps() { } install_ubuntu_git_deps() { + + echodebug "install_ubuntu_git_deps() entry" + __wait_for_apt apt-get update || return 1 if ! __check_command_exists git; then @@ -3278,65 +3167,27 @@ install_ubuntu_git_deps() { __git_clone_and_checkout || return 1 - if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -eq 3 ]; then - PY_PKG_VER=3 - else - PY_PKG_VER="" + if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -ne 3 ]; then + echoerror "Python version is no longer supported, only Python 3" + return 1 fi - if [ "${_POST_NEON_INSTALL}" -eq $BS_FALSE ]; then - - __PACKAGES="" - - # See how we are installing packages - if [ "${_PIP_ALL}" -eq $BS_TRUE ]; then - __PACKAGES="${__PACKAGES} python-dev swig libssl-dev libzmq3 libzmq3-dev" - - if ! __check_command_exists pip; then - __PACKAGES="${__PACKAGES} python-setuptools python-pip" - fi - - # Get just the apt packages that are required to build all the pythons - # shellcheck disable=SC2086 - __apt_get_install_noinput ${__PACKAGES} || return 1 - # Install the pythons from requirements (only zmq for now) - __install_pip_deps "${_SALT_GIT_CHECKOUT_DIR}/requirements/zeromq.txt" || return 1 - else - install_ubuntu_stable_deps || return 1 - - if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -eq 3 ]; then - __PACKAGES="${__PACKAGES} python3-setuptools" - else - # There is no m2crypto package for Py3 at this time - only install for Py2 - __PACKAGES="${__PACKAGES} python-m2crypto" - fi - - __PACKAGES="${__PACKAGES} python${PY_PKG_VER}-crypto python${PY_PKG_VER}-jinja2" - __PACKAGES="${__PACKAGES} python${PY_PKG_VER}-msgpack python${PY_PKG_VER}-requests" - __PACKAGES="${__PACKAGES} python${PY_PKG_VER}-tornado python${PY_PKG_VER}-yaml" - __PACKAGES="${__PACKAGES} python${PY_PKG_VER}-zmq" - __PACKAGES="${__PACKAGES} python-concurrent.futures" - - if [ "$_INSTALL_CLOUD" -eq $BS_TRUE ]; then - # Install python-libcloud if asked to - __PACKAGES="${__PACKAGES} python${PY_PKG_VER}-libcloud" - fi - - # shellcheck disable=SC2086 - __apt_get_install_noinput ${__PACKAGES} || return 1 - fi - else - __PACKAGES="python${PY_PKG_VER}-dev python${PY_PKG_VER}-pip python${PY_PKG_VER}-setuptools gcc" - if [ "$DISTRO_MAJOR_VERSION" -ge 22 ]; then - __PACKAGES="${__PACKAGES} g++" - fi - # shellcheck disable=SC2086 - __apt_get_install_noinput ${__PACKAGES} || return 1 + __PACKAGES="python${PY_PKG_VER}-dev python${PY_PKG_VER}-pip python${PY_PKG_VER}-setuptools gcc" + if [ "$DISTRO_MAJOR_VERSION" -ge 22 ]; then + __PACKAGES="${__PACKAGES} g++" fi + ## include hwclock if not part of base OS (23.10 and up) + if [ ! -f /usr/sbin/hwclock ]; then + __PACKAGES="${__PACKAGES} util-linux-extra" + fi + + # shellcheck disable=SC2086 + __apt_get_install_noinput ${__PACKAGES} || return 1 + # Let's trigger config_salt() if [ "$_TEMP_CONFIG_DIR" = "null" ]; then - _TEMP_CONFIG_DIR="${_SALT_GIT_CHECKOUT_DIR}/conf/" + _TEMP_CONFIG_DIR="${_SALT_GIT_CHECKOUT_DIR}/conf" CONFIG_SALT_FUNC="config_salt" fi @@ -3344,14 +3195,8 @@ install_ubuntu_git_deps() { } install_ubuntu_onedir_deps() { - if [ "${_SLEEP}" -eq "${__DEFAULT_SLEEP}" ] && [ "$DISTRO_MAJOR_VERSION" -lt 16 ]; then - # The user did not pass a custom sleep value as an argument, let's increase the default value - echodebug "On Ubuntu systems we increase the default sleep value to 10." - echodebug "See https://github.com/saltstack/salt/issues/12248 for more info." - _SLEEP=10 - fi - if [ $_START_DAEMONS -eq $BS_FALSE ]; then + if [ "$_START_DAEMONS" -eq $BS_FALSE ]; then echowarn "Not starting daemons on Debian based distributions is not working mostly because starting them is the default behaviour." fi @@ -3362,7 +3207,8 @@ install_ubuntu_onedir_deps() { if [ "${_UPGRADE_SYS}" -eq $BS_TRUE ]; then if [ "${_INSECURE_DL}" -eq $BS_TRUE ]; then - if [ "$DISTRO_MAJOR_VERSION" -ge 20 ] || [ "$DISTRO_MAJOR_VERSION" -ge 21 ]; then + ## apt-key is deprecated + if [ "$DISTRO_MAJOR_VERSION" -ge 20 ]; then __apt_get_install_noinput --allow-unauthenticated debian-archive-keyring && apt-get update || return 1 else __apt_get_install_noinput --allow-unauthenticated debian-archive-keyring && @@ -3382,6 +3228,7 @@ install_ubuntu_onedir_deps() { } install_ubuntu_stable() { + __PACKAGES="" if [ "$_INSTALL_CLOUD" -eq $BS_TRUE ];then @@ -3397,6 +3244,10 @@ install_ubuntu_stable() { __PACKAGES="${__PACKAGES} salt-syndic" fi + if [ "$_INSTALL_SALT_API" -eq $BS_TRUE ]; then + __PACKAGES="${__PACKAGES} salt-api" + fi + # shellcheck disable=SC2086 __apt_get_install_noinput ${__PACKAGES} || return 1 @@ -3404,6 +3255,7 @@ install_ubuntu_stable() { } install_ubuntu_git() { + # Activate virtualenv before install if [ "${_VIRTUALENV_DIR}" != "null" ]; then __activate_virtualenv || return 1 @@ -3412,43 +3264,28 @@ install_ubuntu_git() { if [ -n "$_PY_EXE" ]; then _PYEXE=${_PY_EXE} else - _PYEXE=python2.7 + echoerror "Python 2 is no longer supported, only Python 3" + return 1 fi - if [ "${_POST_NEON_INSTALL}" -eq $BS_TRUE ]; then - # We can use --prefix on debian based ditributions - if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -eq 3 ]; then - _POST_NEON_PIP_INSTALL_ARGS="--target=/usr/lib/python3/dist-packages --install-option=--install-scripts=/usr/bin" - else - _POST_NEON_PIP_INSTALL_ARGS="--target=/usr/lib/python2.7/dist-packages --install-option=--install-scripts=/usr/bin" - fi - _POST_NEON_PIP_INSTALL_ARGS="" - __install_salt_from_repo_post_neon "${_PY_EXE}" || return 1 - cd "${_SALT_GIT_CHECKOUT_DIR}" || return 1 + _PIP_INSTALL_ARGS="" + __install_salt_from_repo "${_PY_EXE}" || return 1 + cd "${_SALT_GIT_CHECKOUT_DIR}" || return 1 - # Account for new path for services files in later releases - if [ -d "pkg/common" ]; then - _SERVICE_DIR="pkg/common" - else - _SERVICE_DIR="pkg" - fi - - sed -i 's:/usr/bin:/usr/local/bin:g' ${_SERVICE_DIR}/*.service - return 0 - fi - - if [ -f "${_SALT_GIT_CHECKOUT_DIR}/salt/syspaths.py" ]; then - # shellcheck disable=SC2086 - "${_PYEXE}" setup.py --salt-config-dir="$_SALT_ETC_DIR" --salt-cache-dir="${_SALT_CACHE_DIR}" ${SETUP_PY_INSTALL_ARGS} install --install-layout=deb || return 1 + # Account for new path for services files in later releases + if [ -d "pkg/common" ]; then + _SERVICE_DIR="pkg/common" else - # shellcheck disable=SC2086 - "${_PYEXE}" setup.py ${SETUP_PY_INSTALL_ARGS} install --install-layout=deb || return 1 + _SERVICE_DIR="pkg" fi + sed -i 's:/usr/bin:/usr/local/bin:g' "${_SERVICE_DIR}"/*.service return 0 + } install_ubuntu_onedir() { + __PACKAGES="" if [ "$_INSTALL_CLOUD" -eq $BS_TRUE ];then @@ -3464,6 +3301,10 @@ install_ubuntu_onedir() { __PACKAGES="${__PACKAGES} salt-syndic" fi + if [ "$_INSTALL_SALT_API" -eq $BS_TRUE ]; then + __PACKAGES="${__PACKAGES} salt-api" + fi + # shellcheck disable=SC2086 __apt_get_install_noinput ${__PACKAGES} || return 1 @@ -3471,6 +3312,7 @@ install_ubuntu_onedir() { } install_ubuntu_stable_post() { + for fname in api master minion syndic; do # Skip salt-api since the service should be opt-in and not necessarily started on boot [ $fname = "api" ] && continue @@ -3480,7 +3322,8 @@ install_ubuntu_stable_post() { [ $fname = "master" ] && [ "$_INSTALL_MASTER" -eq $BS_FALSE ] && continue [ $fname = "syndic" ] && [ "$_INSTALL_SYNDIC" -eq $BS_FALSE ] && continue - if [ -f /bin/systemctl ]; then + ## if [ -f /bin/systemctl ]; then + if [ "$_SYSTEMD_FUNCTIONAL" -eq $BS_TRUE ]; then # Using systemd /bin/systemctl is-enabled salt-$fname.service > /dev/null 2>&1 || ( /bin/systemctl preset salt-$fname.service > /dev/null 2>&1 && @@ -3497,6 +3340,7 @@ install_ubuntu_stable_post() { } install_ubuntu_git_post() { + for fname in api master minion syndic; do # Skip if not meant to be installed [ $fname = "api" ] && \ @@ -3512,7 +3356,7 @@ install_ubuntu_git_post() { _SERVICE_DIR="${_SALT_GIT_CHECKOUT_DIR}/pkg" fi - if [ -f /bin/systemctl ] && [ "$DISTRO_MAJOR_VERSION" -ge 16 ]; then + if [ "$_SYSTEMD_FUNCTIONAL" -eq $BS_TRUE ] && [ "$DISTRO_MAJOR_VERSION" -ge 16 ]; then __copyfile "${_SERVICE_DIR}/salt-${fname}.service" "/lib/systemd/system/salt-${fname}.service" # Skip salt-api since the service should be opt-in and not necessarily started on boot @@ -3521,21 +3365,6 @@ install_ubuntu_git_post() { systemctl is-enabled salt-$fname.service || (systemctl preset salt-$fname.service && systemctl enable salt-$fname.service) sleep 1 systemctl daemon-reload - elif [ -f /sbin/initctl ]; then - _upstart_conf="/etc/init/salt-$fname.conf" - # We have upstart support - echodebug "There's upstart support" - if [ ! -f $_upstart_conf ]; then - # upstart does not know about our service, let's copy the proper file - echowarn "Upstart does not appear to know about salt-$fname" - echodebug "Copying ${_SERVICE_DIR}/salt-$fname.upstart to $_upstart_conf" - __copyfile "${_SERVICE_DIR}/salt-${fname}.upstart" "$_upstart_conf" - # Set service to know about virtualenv - if [ "${_VIRTUALENV_DIR}" != "null" ]; then - echo "SALT_USE_VIRTUALENV=${_VIRTUALENV_DIR}" > /etc/default/salt-${fname} - fi - /sbin/initctl reload-configuration || return 1 - fi # No upstart support in Ubuntu!? elif [ -f "${_SALT_GIT_CHECKOUT_DIR}/pkg/salt-${fname}.init" ]; then echodebug "There's NO upstart support!?" @@ -3548,7 +3377,7 @@ install_ubuntu_git_post() { update-rc.d salt-$fname defaults else - echoerror "Neither upstart nor init.d was setup for salt-$fname" + echoerror "No init.d was setup for salt-$fname" fi done @@ -3556,13 +3385,12 @@ install_ubuntu_git_post() { } install_ubuntu_restart_daemons() { - [ $_START_DAEMONS -eq $BS_FALSE ] && return - # Ensure upstart configs / systemd units are loaded - if [ -f /bin/systemctl ] && [ "$DISTRO_MAJOR_VERSION" -ge 16 ]; then + [ "$_START_DAEMONS" -eq $BS_FALSE ] && return + + # Ensure systemd units are loaded + if [ "$_SYSTEMD_FUNCTIONAL" -eq $BS_TRUE ] && [ "$DISTRO_MAJOR_VERSION" -ge 16 ]; then systemctl daemon-reload - elif [ -f /sbin/initctl ]; then - /sbin/initctl reload-configuration fi for fname in api master minion syndic; do @@ -3574,7 +3402,7 @@ install_ubuntu_restart_daemons() { [ $fname = "minion" ] && [ "$_INSTALL_MINION" -eq $BS_FALSE ] && continue [ $fname = "syndic" ] && [ "$_INSTALL_SYNDIC" -eq $BS_FALSE ] && continue - if [ -f /bin/systemctl ] && [ "$DISTRO_MAJOR_VERSION" -ge 16 ]; then + if [ "$_SYSTEMD_FUNCTIONAL" -eq $BS_TRUE ] && [ "$DISTRO_MAJOR_VERSION" -ge 16 ]; then echodebug "There's systemd support while checking salt-$fname" systemctl stop salt-$fname > /dev/null 2>&1 systemctl start salt-$fname.service && continue @@ -3586,18 +3414,6 @@ install_ubuntu_restart_daemons() { fi fi - if [ -f /sbin/initctl ]; then - echodebug "There's upstart support while checking salt-$fname" - - if status salt-$fname 2>/dev/null | grep -q running; then - stop salt-$fname || (echodebug "Failed to stop salt-$fname" && return 1) - fi - - start salt-$fname && continue - # We failed to start the service, let's test the SysV code below - echodebug "Failed to start salt-$fname using Upstart" - fi - if [ ! -f /etc/init.d/salt-$fname ]; then echoerror "No init.d support for salt-$fname was found" return 1 @@ -3611,6 +3427,7 @@ install_ubuntu_restart_daemons() { } install_ubuntu_check_services() { + for fname in api master minion syndic; do # Skip salt-api since the service should be opt-in and not necessarily started on boot [ $fname = "api" ] && continue @@ -3620,10 +3437,8 @@ install_ubuntu_check_services() { [ $fname = "master" ] && [ "$_INSTALL_MASTER" -eq $BS_FALSE ] && continue [ $fname = "syndic" ] && [ "$_INSTALL_SYNDIC" -eq $BS_FALSE ] && continue - if [ -f /bin/systemctl ] && [ "$DISTRO_MAJOR_VERSION" -ge 16 ]; then + if [ "$_SYSTEMD_FUNCTIONAL" -eq $BS_TRUE ] && [ "$DISTRO_MAJOR_VERSION" -ge 16 ]; then __check_services_systemd salt-$fname || return 1 - elif [ -f /sbin/initctl ] && [ -f /etc/init/salt-${fname}.conf ]; then - __check_services_upstart salt-$fname || return 1 elif [ -f /etc/init.d/salt-$fname ]; then __check_services_debian salt-$fname || return 1 fi @@ -3641,12 +3456,12 @@ install_ubuntu_check_services() { # Debian Install Functions # __install_saltstack_debian_repository() { - DEBIAN_RELEASE="$DISTRO_MAJOR_VERSION" - DEBIAN_CODENAME="$DISTRO_CODENAME" - __PY_VERSION_REPO="apt" - if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -eq 3 ]; then - __PY_VERSION_REPO="py3" + echodebug "__install_saltstack_debian_repository() entry" + + if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -ne 3 ]; then + echoerror "Python version is no longer supported, only Python 3" + return 1 fi # Install downloader backend for GPG keys fetching @@ -3665,22 +3480,37 @@ __install_saltstack_debian_repository() { # shellcheck disable=SC2086,SC2090 __apt_get_install_noinput ${__PACKAGES} || return 1 - # amd64 is just a part of repository URI, 32-bit pkgs are hosted under the same location - SALTSTACK_DEBIAN_URL="${HTTP_VAL}://${_REPO_URL}/${__PY_VERSION_REPO}/debian/${DEBIAN_RELEASE}/${__REPO_ARCH}/${STABLE_REV}" - echo "$__REPO_ARCH_DEB $SALTSTACK_DEBIAN_URL $DEBIAN_CODENAME main" > "/etc/apt/sources.list.d/salt.list" - - __apt_key_fetch "$SALTSTACK_DEBIAN_URL/salt-archive-keyring.gpg" || return 1 + ## SALTSTACK_DEBIAN_URL="${HTTP_VAL}://${_REPO_URL}/${_ONEDIR_DIR}/${__PY_VERSION_REPO}/debian/${DEBIAN_RELEASE}/${__REPO_ARCH}/${STABLE_REV}" + ## echo "$__REPO_ARCH_DEB $SALTSTACK_DEBIAN_URL $DEBIAN_CODENAME main" > "/etc/apt/sources.list.d/salt.list" + ## __apt_key_fetch "$SALTSTACK_DEBIAN_URL/SALT-PROJECT-GPG-PUBKEY-2023.gpg" || return 1 + ## __wait_for_apt apt-get update || return 1 + __fetch_url "/etc/apt/sources.list.d/salt.sources" "https://github.com/saltstack/salt-install-guide/releases/latest/download/salt.sources" + __apt_key_fetch "${HTTP_VAL}://${_REPO_URL}/api/security/keypair/SaltProjectKey/public" || return 1 __wait_for_apt apt-get update || return 1 + + if [ "$STABLE_REV" != "latest" ]; then + # latest is default + STABLE_REV_MAJOR=$(echo "$STABLE_REV" | cut -d '.' -f 1) + if [ "$STABLE_REV_MAJOR" -eq "3006" ]; then + echo "Package: salt-*" > /etc/apt/preferences.d/salt-pin-1001 + echo "Pin: version 3006.*" >> /etc/apt/preferences.d/salt-pin-1001 + echo "Pin-Priority: 1001" >> /etc/apt/preferences.d/salt-pin-1001 + elif [ "$STABLE_REV_MAJOR" -eq "3007" ]; then + echo "Package: salt-*" > /etc/apt/preferences.d/salt-pin-1001 + echo "Pin: version 3007.*" >> /etc/apt/preferences.d/salt-pin-1001 + echo "Pin-Priority: 1001" >> /etc/apt/preferences.d/salt-pin-1001 + fi + fi } __install_saltstack_debian_onedir_repository() { - DEBIAN_RELEASE="$DISTRO_MAJOR_VERSION" - DEBIAN_CODENAME="$DISTRO_CODENAME" - __PY_VERSION_REPO="apt" - if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -eq 3 ]; then - __PY_VERSION_REPO="py3" + echodebug "__install_saltstack_debian_onedir_repository() entry" + + if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -ne 3 ]; then + echoerror "Python version is no longer supported, only Python 3" + return 1 fi # Install downloader backend for GPG keys fetching @@ -3699,80 +3529,30 @@ __install_saltstack_debian_onedir_repository() { # shellcheck disable=SC2086,SC2090 __apt_get_install_noinput ${__PACKAGES} || return 1 - # amd64 is just a part of repository URI, 32-bit pkgs are hosted under the same location - SALTSTACK_DEBIAN_URL="${HTTP_VAL}://${_REPO_URL}/${_ONEDIR_DIR}/${__PY_VERSION_REPO}/debian/${DEBIAN_RELEASE}/${__REPO_ARCH}/${ONEDIR_REV}/" - if [ "${ONEDIR_REV}" = "nightly" ] ; then - SALTSTACK_DEBIAN_URL="${HTTP_VAL}://${_REPO_URL}/${_ONEDIR_NIGHTLY_DIR}/${__PY_VERSION_REPO}/debian/${DEBIAN_RELEASE}/${__REPO_ARCH}/" - fi - echo "$__REPO_ARCH_DEB $SALTSTACK_DEBIAN_URL $DEBIAN_CODENAME main" > "/etc/apt/sources.list.d/salt.list" - - if [ "$(echo "${ONEDIR_REV}" | grep -E '(3004|3005)')" != "" ]; then - __apt_key_fetch "${SALTSTACK_DEBIAN_URL}salt-archive-keyring.gpg" || return 1 - elif [ "$(echo "${ONEDIR_REV}" | grep -E '(latest|nightly)')" != "" ]; then - __apt_key_fetch "${SALTSTACK_DEBIAN_URL}salt-archive-keyring.gpg" || \ - __apt_key_fetch "${SALTSTACK_DEBIAN_URL}SALT-PROJECT-GPG-PUBKEY-2023.gpg" || return 1 - else - __apt_key_fetch "${SALTSTACK_DEBIAN_URL}SALT-PROJECT-GPG-PUBKEY-2023.gpg" || return 1 - fi - - __wait_for_apt apt-get update || return 1 -} - -install_debian_deps() { - if [ $_START_DAEMONS -eq $BS_FALSE ]; then - echowarn "Not starting daemons on Debian based distributions is not working mostly because starting them is the default behaviour." - fi - - # No user interaction, libc6 restart services for example - export DEBIAN_FRONTEND=noninteractive - + __fetch_url "/etc/apt/sources.list.d/salt.sources" "https://github.com/saltstack/salt-install-guide/releases/latest/download/salt.sources" + __apt_key_fetch "${HTTP_VAL}://${_REPO_URL}/api/security/keypair/SaltProjectKey/public" || return 1 __wait_for_apt apt-get update || return 1 - if [ "${_UPGRADE_SYS}" -eq $BS_TRUE ]; then - # Try to update GPG keys first if allowed - if [ "${_INSECURE_DL}" -eq $BS_TRUE ]; then - if [ "$DISTRO_MAJOR_VERSION" -ge 10 ]; then - __apt_get_install_noinput --allow-unauthenticated debian-archive-keyring && apt-get update || return 1 - else - __apt_get_install_noinput --allow-unauthenticated debian-archive-keyring && - apt-key update && apt-get update || return 1 - fi + if [ "$ONEDIR_REV" != "latest" ]; then + # latest is default + ONEDIR_REV_MAJOR=$(echo "$ONEDIR_REV" | cut -d '.' -f 1) + if [ "$ONEDIR_REV_MAJOR" -eq "3006" ]; then + echo "Package: salt-*" > /etc/apt/preferences.d/salt-pin-1001 + echo "Pin: version 3006.*" >> /etc/apt/preferences.d/salt-pin-1001 + echo "Pin-Priority: 1001" >> /etc/apt/preferences.d/salt-pin-1001 + elif [ "$ONEDIR_REV_MAJOR" -eq "3007" ]; then + echo "Package: salt-*" > /etc/apt/preferences.d/salt-pin-1001 + echo "Pin: version 3007.*" >> /etc/apt/preferences.d/salt-pin-1001 + echo "Pin-Priority: 1001" >> /etc/apt/preferences.d/salt-pin-1001 fi - - __apt_get_upgrade_noinput || return 1 fi - - if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -eq 3 ]; then - PY_PKG_VER=3 - else - PY_PKG_VER="" - fi - - # Additionally install procps and pciutils which allows for Docker bootstraps. See 366#issuecomment-39666813 - __PACKAGES='procps pciutils' - - # YAML module is used for generating custom master/minion configs - __PACKAGES="${__PACKAGES} python${PY_PKG_VER}-yaml" - - # shellcheck disable=SC2086 - __apt_get_install_noinput ${__PACKAGES} || return 1 - - if [ "$_DISABLE_REPOS" -eq "$BS_FALSE" ] || [ "$_CUSTOM_REPO_URL" != "null" ]; then - __check_dpkg_architecture || return 1 - __install_saltstack_debian_repository || return 1 - fi - - if [ "${_EXTRA_PACKAGES}" != "" ]; then - echoinfo "Installing the following extra packages as requested: ${_EXTRA_PACKAGES}" - # shellcheck disable=SC2086 - __apt_get_install_noinput ${_EXTRA_PACKAGES} || return 1 - fi - - return 0 } install_debian_onedir_deps() { - if [ $_START_DAEMONS -eq $BS_FALSE ]; then + + echodebug "install_debian_onedir_git_deps() entry" + + if [ "$_START_DAEMONS" -eq $BS_FALSE ]; then echowarn "Not starting daemons on Debian based distributions is not working mostly because starting them is the default behaviour." fi @@ -3795,10 +3575,9 @@ install_debian_onedir_deps() { __apt_get_upgrade_noinput || return 1 fi - if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -eq 3 ]; then - PY_PKG_VER=3 - else - PY_PKG_VER="" + if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -ne 3 ]; then + echoerror "Python version is no longer supported, only Python 3" + return 1 fi # Additionally install procps and pciutils which allows for Docker bootstraps. See 366#issuecomment-39666813 @@ -3824,75 +3603,14 @@ install_debian_onedir_deps() { return 0 } -install_debian_git_pre() { - if ! __check_command_exists git; then - __apt_get_install_noinput git || return 1 - fi - - if [ "$_INSECURE_DL" -eq $BS_FALSE ] && [ "${_SALT_REPO_URL%%://*}" = "https" ]; then - __apt_get_install_noinput ca-certificates - fi - - __git_clone_and_checkout || return 1 - - # Let's trigger config_salt() - if [ "$_TEMP_CONFIG_DIR" = "null" ]; then - _TEMP_CONFIG_DIR="${_SALT_GIT_CHECKOUT_DIR}/conf/" - CONFIG_SALT_FUNC="config_salt" - fi -} - install_debian_git_deps() { - install_debian_deps || return 1 - install_debian_git_pre || return 1 - if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -eq 3 ]; then - PY_PKG_VER=3 - else - PY_PKG_VER="" - fi + echodebug "install_debian_git_deps() entry" - if [ "${_POST_NEON_INSTALL}" -eq $BS_FALSE ]; then - __PACKAGES="libzmq3 libzmq3-dev lsb-release python-apt python-backports.ssl-match-hostname" - __PACKAGES="${__PACKAGES} python-crypto python-jinja2 python-msgpack python-m2crypto" - __PACKAGES="${__PACKAGES} python-requests python-tornado python-yaml python-zmq" - - if [ "$_INSTALL_CLOUD" -eq $BS_TRUE ]; then - # Install python-libcloud if asked to - __PACKAGES="${__PACKAGES} python-libcloud" - fi - - # shellcheck disable=SC2086 - __apt_get_install_noinput ${__PACKAGES} || return 1 - else - __PACKAGES="python${PY_PKG_VER}-dev python${PY_PKG_VER}-pip python${PY_PKG_VER}-setuptools gcc" - echodebug "install_debian_git_deps() Installing ${__PACKAGES}" - # shellcheck disable=SC2086 - __apt_get_install_noinput ${__PACKAGES} || return 1 - fi - - return 0 -} - -install_debian_7_git_deps() { - install_debian_deps || return 1 - install_debian_git_deps || return 1 - - return 0 -} - -install_debian_8_git_deps() { - - if [ "${_POST_NEON_INSTALL}" -eq $BS_TRUE ]; then - echodebug "CALLING install_debian_git_deps" - install_debian_git_deps || return 1 - return 0 - fi - - install_debian_deps || return 1 + __wait_for_apt apt-get update || return 1 if ! __check_command_exists git; then - __apt_get_install_noinput git || return 1 + __apt_get_install_noinput git-core || return 1 fi if [ "$_INSECURE_DL" -eq $BS_FALSE ] && [ "${_SALT_REPO_URL%%://*}" = "https" ]; then @@ -3901,124 +3619,28 @@ install_debian_8_git_deps() { __git_clone_and_checkout || return 1 - __PACKAGES="libzmq3 libzmq3-dev lsb-release python-apt python-crypto python-jinja2" - __PACKAGES="${__PACKAGES} python-m2crypto python-msgpack python-requests python-systemd" - __PACKAGES="${__PACKAGES} python-yaml python-zmq python-concurrent.futures" - - if [ "$_INSTALL_CLOUD" -eq $BS_TRUE ]; then - # Install python-libcloud if asked to - __PACKAGES="${__PACKAGES} python-libcloud" + if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -ne 3 ]; then + echoerror "Python version is no longer supported, only Python 3" + return 1 fi - __PIP_PACKAGES='' - if (__check_pip_allowed >/dev/null 2>&1); then - __PIP_PACKAGES='tornado<5.0' - # Install development environment for building tornado Python module - __PACKAGES="${__PACKAGES} build-essential python-dev" - - if ! __check_command_exists pip; then - __PACKAGES="${__PACKAGES} python-pip" - fi - # Attempt to configure backports repo on non-x86_64 system - elif [ $_DISABLE_REPOS -eq $BS_FALSE ] && [ "$DPKG_ARCHITECTURE" != "amd64" ]; then - # Check if Debian Backports repo already configured - if ! apt-cache policy | grep -q 'Debian Backports'; then - echo 'deb http://httpredir.debian.org/debian jessie-backports main' > \ - /etc/apt/sources.list.d/backports.list - fi - - __wait_for_apt apt-get update || return 1 - - # python-tornado package should be installed from backports repo - __PACKAGES="${__PACKAGES} python-backports.ssl-match-hostname python-tornado/jessie-backports" - else - __PACKAGES="${__PACKAGES} python-backports.ssl-match-hostname python-tornado" - fi + __PACKAGES="python${PY_PKG_VER}-dev python${PY_PKG_VER}-pip python${PY_PKG_VER}-setuptools gcc" + echodebug "install_debian_git_deps() Installing ${__PACKAGES}" # shellcheck disable=SC2086 __apt_get_install_noinput ${__PACKAGES} || return 1 - if [ "${__PIP_PACKAGES}" != "" ]; then - # shellcheck disable=SC2086,SC2090 - pip install -U ${__PIP_PACKAGES} || return 1 - fi - # Let's trigger config_salt() if [ "$_TEMP_CONFIG_DIR" = "null" ]; then - _TEMP_CONFIG_DIR="${_SALT_GIT_CHECKOUT_DIR}/conf/" + _TEMP_CONFIG_DIR="${_SALT_GIT_CHECKOUT_DIR}/conf" CONFIG_SALT_FUNC="config_salt" fi return 0 } -install_debian_9_git_deps() { - - if [ "${_POST_NEON_INSTALL}" -eq $BS_TRUE ]; then - install_debian_git_deps || return 1 - return 0 - fi - - install_debian_deps || return 1 - install_debian_git_pre || return 1 - - __PACKAGES="libzmq5 lsb-release" - - if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -eq 3 ]; then - PY_PKG_VER=3 - else - PY_PKG_VER="" - - # These packages are PY2-ONLY - __PACKAGES="${__PACKAGES} python-backports-abc python-m2crypto python-concurrent.futures" - fi - - __PACKAGES="${__PACKAGES} python${PY_PKG_VER}-apt python${PY_PKG_VER}-crypto python${PY_PKG_VER}-jinja2" - __PACKAGES="${__PACKAGES} python${PY_PKG_VER}-msgpack python${PY_PKG_VER}-requests python${PY_PKG_VER}-systemd" - __PACKAGES="${__PACKAGES} python${PY_PKG_VER}-tornado python${PY_PKG_VER}-yaml python${PY_PKG_VER}-zmq" - - if [ "$_INSTALL_CLOUD" -eq $BS_TRUE ]; then - # Install python-libcloud if asked to - __PACKAGES="${__PACKAGES} python${PY_PKG_VER}-libcloud" - fi - - # shellcheck disable=SC2086 - __apt_get_install_noinput ${__PACKAGES} || return 1 - - return 0 -} - -install_debian_10_git_deps() { - - if [ "${_POST_NEON_INSTALL}" -eq $BS_TRUE ]; then - install_debian_git_deps || return 1 - return 0 - fi - - install_debian_deps || return 1 - install_debian_git_pre || return 1 - - if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -eq 3 ]; then - _py=${_PY_EXE} - PY_PKG_VER=3 - __PACKAGES="python${PY_PKG_VER}-distutils" - else - _py="python" - PY_PKG_VER="" - __PACKAGES="" - fi - - __install_tornado_pip ${_py}|| return 1 - __PACKAGES="${__PACKAGES} python${PY_PKG_VER}-msgpack python${PY_PKG_VER}-jinja2" - __PACKAGES="${__PACKAGES} python${PY_PKG_VER}-tornado python${PY_PKG_VER}-yaml python${PY_PKG_VER}-zmq" - - # shellcheck disable=SC2086 - __apt_get_install_noinput ${__PACKAGES} || return 1 - - return 0 -} - install_debian_stable() { + __PACKAGES="" if [ "$_INSTALL_CLOUD" -eq $BS_TRUE ];then @@ -4034,81 +3656,70 @@ install_debian_stable() { __PACKAGES="${__PACKAGES} salt-syndic" fi + if [ "$_INSTALL_SALT_API" -eq $BS_TRUE ]; then + __PACKAGES="${__PACKAGES} salt-api" + fi + # shellcheck disable=SC2086 __apt_get_install_noinput ${__PACKAGES} || return 1 return 0 } -install_debian_7_stable() { - install_debian_stable || return 1 +install_debian_11_git_deps() { + + install_debian_git_deps || return 1 return 0 } -install_debian_8_stable() { - install_debian_stable || return 1 - return 0 -} +install_debian_12_git_deps() { -install_debian_9_stable() { - install_debian_stable || return 1 + install_debian_git_deps || return 1 return 0 } install_debian_git() { + if [ -n "$_PY_EXE" ]; then _PYEXE=${_PY_EXE} else - _PYEXE=python + ## _PYEXE=python + echoerror "Python 2 is no longer supported, only Py3 packages" + return 1 fi - if [ "${_POST_NEON_INSTALL}" -eq $BS_TRUE ]; then - # We can use --prefix on debian based ditributions - if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -eq 3 ]; then - _POST_NEON_PIP_INSTALL_ARGS="--target=/usr/lib/python3/dist-packages --install-option=--install-scripts=/usr/bin" - else - _POST_NEON_PIP_INSTALL_ARGS="--target=/usr/lib/python2.7/dist-packages --install-option=--install-scripts=/usr/bin" - fi - _POST_NEON_PIP_INSTALL_ARGS="" - __install_salt_from_repo_post_neon "${_PY_EXE}" || return 1 - cd "${_SALT_GIT_CHECKOUT_DIR}" || return 1 + # We can use --prefix on debian based ditributions - # Account for new path for services files in later releases - if [ -d "pkg/common" ]; then - _SERVICE_DIR="pkg/common" - else - _SERVICE_DIR="pkg" - fi + _PIP_INSTALL_ARGS="" - sed -i 's:/usr/bin:/usr/local/bin:g' ${_SERVICE_DIR}/*.service - return 0 - fi + __install_salt_from_repo "${_PY_EXE}" || return 1 + cd "${_SALT_GIT_CHECKOUT_DIR}" || return 1 - if [ -f "${_SALT_GIT_CHECKOUT_DIR}/salt/syspaths.py" ]; then - # shellcheck disable=SC2086 - "${_PYEXE}" setup.py --salt-config-dir="$_SALT_ETC_DIR" --salt-cache-dir="${_SALT_CACHE_DIR}" ${SETUP_PY_INSTALL_ARGS} install --install-layout=deb || return 1 + # Account for new path for services files in later releases + if [ -d "pkg/common" ]; then + _SERVICE_DIR="pkg/common" else - # shellcheck disable=SC2086 - "${_PYEXE}" setup.py ${SETUP_PY_INSTALL_ARGS} install --install-layout=deb || return 1 + _SERVICE_DIR="pkg" fi + + sed -i 's:/usr/bin:/usr/local/bin:g' "${_SERVICE_DIR}"/*.service + return 0 } -install_debian_7_git() { +install_debian_11_git() { + install_debian_git || return 1 return 0 } -install_debian_8_git() { - install_debian_git || return 1 - return 0 -} +install_debian_12_git() { -install_debian_9_git() { install_debian_git || return 1 return 0 } install_debian_onedir() { + __PACKAGES="" if [ "$_INSTALL_CLOUD" -eq $BS_TRUE ];then @@ -4124,6 +3735,10 @@ install_debian_onedir() { __PACKAGES="${__PACKAGES} salt-syndic" fi + if [ "$_INSTALL_SALT_API" -eq $BS_TRUE ]; then + __PACKAGES="${__PACKAGES} salt-api" + fi + # shellcheck disable=SC2086 __apt_get_install_noinput ${__PACKAGES} || return 1 @@ -4131,6 +3746,7 @@ install_debian_onedir() { } install_debian_git_post() { + for fname in api master minion syndic; do # Skip if not meant to be installed [ "$fname" = "api" ] && \ @@ -4147,7 +3763,7 @@ install_debian_git_post() { fi # Configure SystemD for Debian 8 "Jessie" and later - if [ -f /bin/systemctl ]; then + if [ "$_SYSTEMD_FUNCTIONAL" -eq $BS_TRUE ]; then if [ ! -f /lib/systemd/system/salt-${fname}.service ] || \ { [ -f /lib/systemd/system/salt-${fname}.service ] && [ $_FORCE_OVERWRITE -eq $BS_TRUE ]; }; then if [ -f "${_SERVICE_DIR}/salt-${fname}.service" ]; then @@ -4165,29 +3781,12 @@ install_debian_git_post() { /bin/systemctl enable "salt-${fname}.service" SYSTEMD_RELOAD=$BS_TRUE - - # Install initscripts for Debian 7 "Wheezy" - elif [ ! -f "/etc/init.d/salt-$fname" ] || \ - { [ -f "/etc/init.d/salt-$fname" ] && [ "$_FORCE_OVERWRITE" -eq $BS_TRUE ]; }; then - __copyfile "${_SALT_GIT_CHECKOUT_DIR}/pkg/deb/salt-${fname}.init" "/etc/init.d/salt-${fname}" - __copyfile "${_SALT_GIT_CHECKOUT_DIR}/pkg/deb/salt-${fname}.environment" "/etc/default/salt-${fname}" - - if [ ! -f "/etc/init.d/salt-${fname}" ]; then - echowarn "The init script for salt-${fname} was not found, skipping it..." - continue - fi - - chmod +x "/etc/init.d/salt-${fname}" - - # Skip salt-api since the service should be opt-in and not necessarily started on boot - [ "$fname" = "api" ] && continue - - update-rc.d "salt-${fname}" defaults fi done } install_debian_2021_post() { + # Kali 2021 (debian derivative) disables all network services by default # Using archlinux post function to enable salt systemd services install_arch_linux_post || return 1 @@ -4195,6 +3794,7 @@ install_debian_2021_post() { } install_debian_restart_daemons() { + [ "$_START_DAEMONS" -eq $BS_FALSE ] && return 0 for fname in api master minion syndic; do @@ -4206,8 +3806,8 @@ install_debian_restart_daemons() { [ $fname = "minion" ] && [ "$_INSTALL_MINION" -eq $BS_FALSE ] && continue [ $fname = "syndic" ] && [ "$_INSTALL_SYNDIC" -eq $BS_FALSE ] && continue - if [ -f /bin/systemctl ]; then - # Debian 8 uses systemd + if [ "$_SYSTEMD_FUNCTIONAL" -eq $BS_TRUE ]; then + # Debian 8 and above uses systemd /bin/systemctl stop salt-$fname > /dev/null 2>&1 /bin/systemctl start salt-$fname.service && continue if [ "$_ECHO_DEBUG" -eq $BS_TRUE ]; then @@ -4223,6 +3823,7 @@ install_debian_restart_daemons() { } install_debian_check_services() { + for fname in api master minion syndic; do # Skip salt-api since the service should be opt-in and not necessarily started on boot [ $fname = "api" ] && continue @@ -4232,7 +3833,7 @@ install_debian_check_services() { [ $fname = "minion" ] && [ "$_INSTALL_MINION" -eq $BS_FALSE ] && continue [ $fname = "syndic" ] && [ "$_INSTALL_SYNDIC" -eq $BS_FALSE ] && continue - if [ -f /bin/systemctl ]; then + if [ "$_SYSTEMD_FUNCTIONAL" -eq $BS_TRUE ]; then __check_services_systemd salt-$fname || return 1 elif [ -f /etc/init.d/salt-$fname ]; then __check_services_debian salt-$fname || return 1 @@ -4251,54 +3852,55 @@ install_debian_check_services() { # __install_saltstack_fedora_onedir_repository() { - if [ "$ITYPE" = "stable" ]; then - REPO_REV="$ONEDIR_REV" - else - REPO_REV="latest" + + if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -ne 3 ]; then + echoerror "Python version is no longer supported, only Python 3" + return 1 fi - __PY_VERSION_REPO="yum" - if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -eq 3 ]; then - __PY_VERSION_REPO="py3" - fi - - GPG_KEY="SALT-PROJECT-GPG-PUBKEY-2023.pub" - - REPO_FILE="/etc/yum.repos.d/salt.repo" - - if [ ! -s "$REPO_FILE" ] || [ "$_FORCE_OVERWRITE" -eq $BS_TRUE ]; then - FETCH_URL="${HTTP_VAL}://${_REPO_URL}/${_ONEDIR_DIR}/${__PY_VERSION_REPO}/fedora/${DISTRO_MAJOR_VERSION}/${CPU_ARCH_L}/${ONEDIR_REV}" - if [ "${ONEDIR_REV}" = "nightly" ] ; then - FETCH_URL="${HTTP_VAL}://${_REPO_URL}/${_ONEDIR_NIGHTLY_DIR}/${__PY_VERSION_REPO}/fedora/${DISTRO_MAJOR_VERSION}/${CPU_ARCH_L}/" + if [ ! -s "$YUM_REPO_FILE" ] || [ "$_FORCE_OVERWRITE" -eq $BS_TRUE ]; then + FETCH_URL="https://github.com/saltstack/salt-install-guide/releases/latest/download/salt.repo" + __fetch_url "${YUM_REPO_FILE}" "${FETCH_URL}" + if [ "$ONEDIR_REV" != "latest" ]; then + # 3006.x is default + REPO_REV_MAJOR=$(echo "$ONEDIR_REV" | cut -d '.' -f 1) + if [ "$REPO_REV_MAJOR" -eq "3007" ]; then + # Enable the Salt 3007 STS repo + dnf config-manager --set-disable salt-repo-* + dnf config-manager --set-enabled salt-repo-3007-sts + fi + else + # Enable the Salt LATEST repo + dnf config-manager --set-disable salt-repo-* + dnf config-manager --set-enabled salt-repo-latest fi + dnf clean expire-cache || return 1 - __fetch_url "${REPO_FILE}" "${FETCH_URL}.repo" - - __rpm_import_gpg "${FETCH_URL}/${GPG_KEY}" || return 1 - - yum clean metadata || return 1 - elif [ "$REPO_REV" != "latest" ]; then + elif [ "$ONEDIR_REV" != "latest" ]; then echowarn "salt.repo already exists, ignoring salt version argument." - echowarn "Use -F (forced overwrite) to install $REPO_REV." + echowarn "Use -F (forced overwrite) to install $ONEDIR_REV." fi return 0 } install_fedora_deps() { + if [ "$_UPGRADE_SYS" -eq $BS_TRUE ]; then dnf -y update || return 1 fi __PACKAGES="${__PACKAGES:=}" - if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -lt 3 ]; then - echoerror "There are no Python 2 stable packages for Fedora, only Py3 packages" + if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -ne 3 ]; then + echoerror "Python version is no longer supported, only Python 3" return 1 fi # Salt on Fedora is Py3 PY_PKG_VER=3 + ## find no dnf-utils in Fedora packaging archives and yum-utils EL7 and F30, none after + ## but find it on 8 and 9 Centos Stream __PACKAGES="${__PACKAGES} dnf-utils libyaml procps-ng python${PY_PKG_VER}-crypto python${PY_PKG_VER}-jinja2" __PACKAGES="${__PACKAGES} python${PY_PKG_VER}-msgpack python${PY_PKG_VER}-requests python${PY_PKG_VER}-zmq" __PACKAGES="${__PACKAGES} python${PY_PKG_VER}-pip python${PY_PKG_VER}-m2crypto python${PY_PKG_VER}-pyyaml" @@ -4313,84 +3915,11 @@ install_fedora_deps() { return 0 } -install_fedora_stable() { - if [ "$STABLE_REV" = "latest" ]; then - __SALT_VERSION="" - else - __SALT_VERSION="$(dnf list --showduplicates salt | grep "$STABLE_REV" | head -n 1 | awk '{print $2}')" - if [ "x${__SALT_VERSION}" = "x" ]; then - echoerror "Could not find a stable install for Salt ${STABLE_REV}" - exit 1 - fi - echoinfo "Installing Stable Package Version ${__SALT_VERSION}" - __SALT_VERSION="-${__SALT_VERSION}" - fi - __PACKAGES="" - - if [ "$_INSTALL_CLOUD" -eq $BS_TRUE ];then - __PACKAGES="${__PACKAGES} salt-cloud${__SALT_VERSION}" - fi - if [ "$_INSTALL_MASTER" -eq $BS_TRUE ]; then - __PACKAGES="${__PACKAGES} salt-master${__SALT_VERSION}" - fi - if [ "$_INSTALL_MINION" -eq $BS_TRUE ]; then - __PACKAGES="${__PACKAGES} salt-minion${__SALT_VERSION}" - fi - if [ "$_INSTALL_SYNDIC" -eq $BS_TRUE ]; then - __PACKAGES="${__PACKAGES} salt-syndic${__SALT_VERSION}" - fi - - # shellcheck disable=SC2086 - __dnf_install_noinput ${__PACKAGES} || return 1 - - __python="python3" - if ! __check_command_exists python3; then - echoerror "Could not find a python3 binary?!" - return 1 - fi - - if [ "${_POST_NEON_INSTALL}" -eq $BS_FALSE ]; then - __check_pip_allowed "You need to allow pip based installations (-P) for Tornado <5.0 in order to install Salt" - __installed_tornado_rpm=$(rpm -qa | grep python${PY_PKG_VER}-tornado) - if [ -n "${__installed_tornado_rpm}" ]; then - echodebug "Removing system package ${__installed_tornado_rpm}" - rpm -e --nodeps "${__installed_tornado_rpm}" || return 1 - fi - __get_site_packages_dir_code=$(cat << EOM -import site -print([d for d in site.getsitepackages() if d.startswith('/usr/lib/python')][0]) -EOM -) - __target_path=$(${__python} -c "${__get_site_packages_dir_code}") - echodebug "Running '${__python}' -m pip install --target ${__target_path} 'tornado<5.0'" - "${__python}" -m pip install --target "${__target_path}" "tornado<5" || return 1 - fi - - return 0 -} - -install_fedora_stable_post() { - for fname in api master minion syndic; do - # Skip salt-api since the service should be opt-in and not necessarily started on boot - [ $fname = "api" ] && continue - - # Skip if not meant to be installed - [ $fname = "master" ] && [ "$_INSTALL_MASTER" -eq $BS_FALSE ] && continue - [ $fname = "minion" ] && [ "$_INSTALL_MINION" -eq $BS_FALSE ] && continue - [ $fname = "syndic" ] && [ "$_INSTALL_SYNDIC" -eq $BS_FALSE ] && continue - - systemctl is-enabled salt-$fname.service || (systemctl preset salt-$fname.service && systemctl enable salt-$fname.service) - sleep 1 - systemctl daemon-reload - done -} - install_fedora_git_deps() { - if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -eq 3 ]; then - # Packages are named python3- - PY_PKG_VER=3 - else - PY_PKG_VER=2 + + if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -ne 3 ]; then + echoerror "Python version is no longer supported, only Python 3" + return 1 fi __PACKAGES="" @@ -4409,79 +3938,40 @@ install_fedora_git_deps() { __git_clone_and_checkout || return 1 - if [ "${_POST_NEON_INSTALL}" -eq $BS_FALSE ]; then - - if [ "$_INSECURE_DL" -eq $BS_FALSE ] && [ "${_SALT_REPO_URL%%://*}" = "https" ]; then - __PACKAGES="${__PACKAGES} ca-certificates" - fi - if [ "$_INSTALL_CLOUD" -eq $BS_TRUE ]; then - __PACKAGES="${__PACKAGES} python${PY_PKG_VER}-libcloud python${PY_PKG_VER}-netaddr" - fi - - install_fedora_deps || return 1 - - if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -eq 3 ]; then - if __check_command_exists python3; then - __python="python3" - fi - elif [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -eq 2 ]; then - if __check_command_exists python2; then - __python="python2" - fi - else - if ! __check_command_exists python; then - echoerror "Unable to find a python binary?!" - return 1 - fi - # Let's hope it's the right one - __python="python" - fi - - grep tornado "${_SALT_GIT_CHECKOUT_DIR}/requirements/base.txt" | while IFS=' - ' read -r dep; do - echodebug "Running '${__python}' -m pip install '${dep}'" - "${__python}" -m pip install "${dep}" || return 1 - done - else - __PACKAGES="python${PY_PKG_VER}-devel python${PY_PKG_VER}-pip python${PY_PKG_VER}-setuptools gcc" - if [ "${DISTRO_VERSION}" -ge 35 ]; then - __PACKAGES="${__PACKAGES} gcc-c++" - fi - # shellcheck disable=SC2086 - __dnf_install_noinput ${__PACKAGES} || return 1 - fi + __PACKAGES="python${PY_PKG_VER}-devel python${PY_PKG_VER}-pip python${PY_PKG_VER}-setuptools gcc gcc-c++" + # shellcheck disable=SC2086 + __dnf_install_noinput ${__PACKAGES} || return 1 # Let's trigger config_salt() if [ "$_TEMP_CONFIG_DIR" = "null" ]; then - _TEMP_CONFIG_DIR="${_SALT_GIT_CHECKOUT_DIR}/conf/" + _TEMP_CONFIG_DIR="${_SALT_GIT_CHECKOUT_DIR}/conf" CONFIG_SALT_FUNC="config_salt" fi + _fedora_dep="contextvars" + echodebug "Running '${_PY_EXE} -m pip install --upgrade ${_fedora_dep}'" + ${_PY_EXE} -m pip install --upgrade "${_fedora_dep}" + return 0 } install_fedora_git() { + if [ "${_PY_EXE}" != "" ]; then _PYEXE=${_PY_EXE} echoinfo "Using the following python version: ${_PY_EXE} to install salt" else - _PYEXE='python2' + echoerror "Python 2 is no longer supported, only Py3 packages" + return 1 fi - if [ "${_POST_NEON_INSTALL}" -eq $BS_TRUE ]; then - __install_salt_from_repo_post_neon "${_PY_EXE}" || return 1 - return 0 - fi - - if [ -f "${_SALT_GIT_CHECKOUT_DIR}/salt/syspaths.py" ]; then - ${_PYEXE} setup.py --salt-config-dir="$_SALT_ETC_DIR" --salt-cache-dir="${_SALT_CACHE_DIR}" ${SETUP_PY_INSTALL_ARGS} install --prefix=/usr || return 1 - else - ${_PYEXE} setup.py ${SETUP_PY_INSTALL_ARGS} install --prefix=/usr || return 1 - fi + __install_salt_from_repo "${_PY_EXE}" || return 1 return 0 + } install_fedora_git_post() { + for fname in api master minion syndic; do # Skip if not meant to be installed [ $fname = "api" ] && \ @@ -4509,10 +3999,12 @@ install_fedora_git_post() { systemctl is-enabled salt-$fname.service || (systemctl preset salt-$fname.service && systemctl enable salt-$fname.service) sleep 1 systemctl daemon-reload + done } install_fedora_restart_daemons() { + [ $_START_DAEMONS -eq $BS_FALSE ] && return for fname in api master minion syndic; do @@ -4535,6 +4027,7 @@ install_fedora_restart_daemons() { } install_fedora_check_services() { + for fname in api master minion syndic; do # Skip salt-api since the service should be opt-in and not necessarily started on boot [ $fname = "api" ] && continue @@ -4567,19 +4060,13 @@ install_fedora_onedir_deps() { fi # If -R was passed, we need to configure custom repo url with rsync-ed packages - # Which is still handled in __install_saltstack_rhel_repository. This call has + # Which is still handled in __install_saltstack_rhel_onedir_repository. This call has # its own check in case -r was passed without -R. if [ "$_CUSTOM_REPO_URL" != "null" ]; then __install_saltstack_fedora_onedir_repository || return 1 fi - if [ "$DISTRO_MAJOR_VERSION" -ge 8 ]; then - __PACKAGES="dnf-utils chkconfig" - else - __PACKAGES="yum-utils chkconfig" - fi - - __PACKAGES="${__PACKAGES} procps" + __PACKAGES="dnf-utils chkconfig procps-ng" # shellcheck disable=SC2086 __yum_install_noinput ${__PACKAGES} || return 1 @@ -4596,6 +4083,7 @@ install_fedora_onedir_deps() { install_fedora_onedir() { + STABLE_REV=$ONEDIR_REV #install_fedora_stable || return 1 @@ -4614,6 +4102,10 @@ install_fedora_onedir() { __PACKAGES="${__PACKAGES} salt-syndic" fi + if [ "$_INSTALL_SALT_API" -eq $BS_TRUE ]; then + __PACKAGES="${__PACKAGES} salt-api" + fi + # shellcheck disable=SC2086 __yum_install_noinput ${__PACKAGES} || return 1 @@ -4621,11 +4113,26 @@ install_fedora_onedir() { } install_fedora_onedir_post() { + STABLE_REV=$ONEDIR_REV - install_fedora_stable_post || return 1 + + for fname in api master minion syndic; do + # Skip salt-api since the service should be opt-in and not necessarily started on boot + [ $fname = "api" ] && continue + + # Skip if not meant to be installed + [ $fname = "master" ] && [ "$_INSTALL_MASTER" -eq $BS_FALSE ] && continue + [ $fname = "minion" ] && [ "$_INSTALL_MINION" -eq $BS_FALSE ] && continue + [ $fname = "syndic" ] && [ "$_INSTALL_SYNDIC" -eq $BS_FALSE ] && continue + + systemctl is-enabled salt-$fname.service || (systemctl preset salt-$fname.service && systemctl enable salt-$fname.service) + sleep 1 + systemctl daemon-reload + done return 0 } + # # Ended Fedora Install Functions # @@ -4635,133 +4142,40 @@ install_fedora_onedir_post() { # # CentOS Install Functions # -__install_saltstack_rhel_repository() { - if [ "${DISTRO_MAJOR_VERSION}" -ge 9 ]; then - echoerror "Old stable repository unavailable on RH variants greater than or equal to 9" - echoerror "Use the stable install type." - exit 1 - fi - - if [ "$ITYPE" = "stable" ]; then - repo_rev="$STABLE_REV" - else - repo_rev="latest" - fi - - __PY_VERSION_REPO="yum" - if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -eq 3 ]; then - __PY_VERSION_REPO="py3" - fi - - # Avoid using '$releasever' variable for yum. - # Instead, this should work correctly on all RHEL variants. - base_url="${HTTP_VAL}://${_REPO_URL}/${__PY_VERSION_REPO}/redhat/${DISTRO_MAJOR_VERSION}/\$basearch/${repo_rev}/" - if [ "${DISTRO_MAJOR_VERSION}" -eq 7 ]; then - gpg_key="SALTSTACK-GPG-KEY.pub base/RPM-GPG-KEY-CentOS-7" - elif [ "${DISTRO_MAJOR_VERSION}" -ge 9 ]; then - gpg_key="SALTSTACK-GPG-KEY2.pub" - else - gpg_key="SALTSTACK-GPG-KEY.pub" - fi - - gpg_key_urls="" - for key in $gpg_key; do - gpg_key_urls=$(printf "${base_url}${key},%s" "$gpg_key_urls") - done - - repo_file="/etc/yum.repos.d/salt.repo" - - if [ ! -s "$repo_file" ] || [ "$_FORCE_OVERWRITE" -eq $BS_TRUE ]; then - cat <<_eof > "$repo_file" -[saltstack] -name=SaltStack ${repo_rev} Release Channel for RHEL/CentOS \$releasever -baseurl=${base_url} -skip_if_unavailable=True -gpgcheck=1 -gpgkey=${gpg_key_urls} -enabled=1 -enabled_metadata=1 -_eof - - fetch_url="${HTTP_VAL}://${_REPO_URL}/${__PY_VERSION_REPO}/redhat/${DISTRO_MAJOR_VERSION}/${CPU_ARCH_L}/${repo_rev}/" - for key in $gpg_key; do - __rpm_import_gpg "${fetch_url}${key}" || return 1 - done - - yum clean metadata || return 1 - elif [ "$repo_rev" != "latest" ]; then - echowarn "salt.repo already exists, ignoring salt version argument." - echowarn "Use -F (forced overwrite) to install $repo_rev." - fi - - return 0 -} - __install_saltstack_rhel_onedir_repository() { - if [ "$ITYPE" = "stable" ]; then - repo_rev="$ONEDIR_REV" - else - repo_rev="latest" + + if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -ne 3 ]; then + echoerror "Python version is no longer supported, only Python 3" + return 1 fi - __PY_VERSION_REPO="yum" - if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -eq 3 ]; then - __PY_VERSION_REPO="py3" - fi - - # Avoid using '$releasever' variable for yum. - # Instead, this should work correctly on all RHEL variants. - base_url="${HTTP_VAL}://${_REPO_URL}/${_ONEDIR_DIR}/${__PY_VERSION_REPO}/redhat/${DISTRO_MAJOR_VERSION}/\$basearch/${ONEDIR_REV}/" - if [ "${ONEDIR_REV}" = "nightly" ] ; then - base_url="${HTTP_VAL}://${_REPO_URL}/${_ONEDIR_NIGHTLY_DIR}/${__PY_VERSION_REPO}/redhat/${DISTRO_MAJOR_VERSION}/\$basearch/" - fi - if [ "$(echo "${ONEDIR_REV}" | grep -E '(3004|3005)')" != "" ] || [ "${ONEDIR_REV}" = "nightly" ]; then - if [ "${DISTRO_MAJOR_VERSION}" -eq 9 ]; then - gpg_key="SALTSTACK-GPG-KEY2.pub" - else - gpg_key="SALTSTACK-GPG-KEY.pub" - fi - else - gpg_key="SALT-PROJECT-GPG-PUBKEY-2023.pub" - fi - - gpg_key_urls="" - for key in $gpg_key; do - gpg_key_urls=$(printf "${base_url}${key},%s" "$gpg_key_urls") - done - - repo_file="/etc/yum.repos.d/salt.repo" - - if [ ! -s "$repo_file" ] || [ "$_FORCE_OVERWRITE" -eq $BS_TRUE ]; then - cat <<_eof > "$repo_file" -[saltstack] -name=SaltStack ${repo_rev} Release Channel for RHEL/CentOS \$releasever -baseurl=${base_url} -skip_if_unavailable=True -gpgcheck=1 -gpgkey=${gpg_key_urls} -enabled=1 -enabled_metadata=1 -_eof - - fetch_url="${HTTP_VAL}://${_REPO_URL}/${_ONEDIR_DIR}/${__PY_VERSION_REPO}/redhat/${DISTRO_MAJOR_VERSION}/${CPU_ARCH_L}/${ONEDIR_REV}/" - if [ "${ONEDIR_REV}" = "nightly" ] ; then - fetch_url="${HTTP_VAL}://${_REPO_URL}/${_ONEDIR_NIGHTLY_DIR}/${__PY_VERSION_REPO}/redhat/${DISTRO_MAJOR_VERSION}/${CPU_ARCH_L}/" + if [ ! -s "$YUM_REPO_FILE" ] || [ "$_FORCE_OVERWRITE" -eq $BS_TRUE ]; then + FETCH_URL="https://github.com/saltstack/salt-install-guide/releases/latest/download/salt.repo" + __fetch_url "${YUM_REPO_FILE}" "${FETCH_URL}" + if [ "$ONEDIR_REV" != "latest" ]; then + # 3006.x is default + REPO_REV_MAJOR=$(echo "$ONEDIR_REV" | cut -d '.' -f 1) + if [ "$REPO_REV_MAJOR" -eq "3007" ]; then + # Enable the Salt 3007 STS repo + dnf config-manager --set-disable salt-repo-* + dnf config-manager --set-enabled salt-repo-3007-sts + fi + else + # Enable the Salt LATEST repo + dnf config-manager --set-disable salt-repo-* + dnf config-manager --set-enabled salt-repo-latest fi - for key in $gpg_key; do - __rpm_import_gpg "${fetch_url}${key}" || return 1 - done - - yum clean metadata || return 1 - elif [ "$repo_rev" != "latest" ]; then + dnf clean expire-cache || return 1 + elif [ "$ONEDIR_REV" != "latest" ]; then echowarn "salt.repo already exists, ignoring salt version argument." - echowarn "Use -F (forced overwrite) to install $repo_rev." + echowarn "Use -F (forced overwrite) to install $ONEDIR_REV." fi return 0 } install_centos_stable_deps() { + if [ "$_UPGRADE_SYS" -eq $BS_TRUE ]; then yum -y update || return 1 fi @@ -4773,48 +4187,18 @@ install_centos_stable_deps() { fi if [ "$_DISABLE_REPOS" -eq "$BS_FALSE" ]; then - __install_saltstack_rhel_repository || return 1 + echoerror "old-stable packages are no longer supported and are End-Of-Life." + return 1 fi # If -R was passed, we need to configure custom repo url with rsync-ed packages - # Which is still handled in __install_saltstack_rhel_repository. This call has + # Which is still handled in __install_saltstack_rhel_onedir_repository. This call has # its own check in case -r was passed without -R. if [ "$_CUSTOM_REPO_URL" != "null" ]; then - __install_saltstack_rhel_repository || return 1 + __install_saltstack_rhel_onedir_repository || return 1 fi - if [ "$DISTRO_MAJOR_VERSION" -ge 8 ]; then - __PACKAGES="dnf-utils chkconfig" - else - __PACKAGES="yum-utils chkconfig" - fi - - if [ "${_POST_NEON_INSTALL}" -eq $BS_FALSE ]; then - if [ "$DISTRO_MAJOR_VERSION" -ge 8 ]; then - # YAML module is used for generating custom master/minion configs - if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -eq 3 ]; then - __PACKAGES="${__PACKAGES} python3-pyyaml python3-setuptools" - else - __PACKAGES="${__PACKAGES} python2-pyyaml" - fi - elif [ "$DISTRO_MAJOR_VERSION" -eq 7 ]; then - # YAML module is used for generating custom master/minion configs - if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -eq 3 ]; then - __PACKAGES="${__PACKAGES} python36-PyYAML python36-setuptools" - else - __PACKAGES="${__PACKAGES} PyYAML" - fi - else - # YAML module is used for generating custom master/minion configs - if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -eq 3 ]; then - __PACKAGES="${__PACKAGES} python34-PyYAML python34-setuptools" - else - __PACKAGES="${__PACKAGES} PyYAML" - fi - fi - fi - - __PACKAGES="${__PACKAGES} procps" + __PACKAGES="yum-utils chkconfig procps-ng findutils" # shellcheck disable=SC2086 __yum_install_noinput ${__PACKAGES} || return 1 @@ -4825,11 +4209,11 @@ install_centos_stable_deps() { __yum_install_noinput ${_EXTRA_PACKAGES} || return 1 fi - return 0 } install_centos_stable() { + __PACKAGES="" if [ "$_INSTALL_CLOUD" -eq $BS_TRUE ];then @@ -4845,6 +4229,10 @@ install_centos_stable() { __PACKAGES="${__PACKAGES} salt-syndic" fi + if [ "$_INSTALL_SALT_API" -eq $BS_TRUE ]; then + __PACKAGES="${__PACKAGES} salt-api" + fi + # shellcheck disable=SC2086 __yum_install_noinput ${__PACKAGES} || return 1 @@ -4859,6 +4247,7 @@ install_centos_stable() { } install_centos_stable_post() { + SYSTEMD_RELOAD=$BS_FALSE for fname in api master minion syndic; do @@ -4870,7 +4259,7 @@ install_centos_stable_post() { [ $fname = "minion" ] && [ "$_INSTALL_MINION" -eq $BS_FALSE ] && continue [ $fname = "syndic" ] && [ "$_INSTALL_SYNDIC" -eq $BS_FALSE ] && continue - if [ -f /bin/systemctl ]; then + if [ "$_SYSTEMD_FUNCTIONAL" -eq $BS_TRUE ]; then /bin/systemctl is-enabled salt-${fname}.service > /dev/null 2>&1 || ( /bin/systemctl preset salt-${fname}.service > /dev/null 2>&1 && /bin/systemctl enable salt-${fname}.service > /dev/null 2>&1 @@ -4890,14 +4279,14 @@ install_centos_stable_post() { } install_centos_git_deps() { + # First try stable deps then fall back to onedir deps if that one fails # if we're installing on a Red Hat based host that doesn't have the classic # package repos available. # Set ONEDIR_REV to STABLE_REV in case we # end up calling install_centos_onedir_deps ONEDIR_REV=${STABLE_REV} - install_centos_onedir_deps || \ - return 1 + install_centos_onedir_deps || return 1 if [ "$_INSECURE_DL" -eq $BS_FALSE ] && [ "${_SALT_REPO_URL%%://*}" = "https" ]; then __yum_install_noinput ca-certificates || return 1 @@ -4912,111 +4301,23 @@ install_centos_git_deps() { __PACKAGES="" if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -eq 3 ]; then - if [ "$DISTRO_MAJOR_VERSION" -ge 8 ]; then - # Packages are named python3- - PY_PKG_VER=3 - __PACKAGES="${__PACKAGES} python3" - else - # Packages are named python36- - PY_PKG_VER=36 - __PACKAGES="${__PACKAGES} python36" - fi + # Packages are named python3- + PY_PKG_VER=3 + __PACKAGES="${__PACKAGES} python3" else - PY_PKG_VER="" - if [ "$DISTRO_MAJOR_VERSION" -ge 8 ]; then - __PACKAGES="${__PACKAGES} python2" - elif [ "$DISTRO_MAJOR_VERSION" -eq 6 ]; then - PY_PKG_VER=27 - __PACKAGES="${__PACKAGES} python27" - else - __PACKAGES="${__PACKAGES} python" - fi + echoerror "Python 2 is no longer supported, only Python 3" + return 1 fi - if [ "${_POST_NEON_INSTALL}" -eq $BS_FALSE ]; then - _install_m2crypto_req=false - if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -eq 3 ]; then - _py=${_PY_EXE} - if [ "$DISTRO_MAJOR_VERSION" -gt 6 ]; then - _install_m2crypto_req=true - fi - else - if [ "$DISTRO_MAJOR_VERSION" -eq 6 ]; then - _install_m2crypto_req=true - fi - _py="python" + __PACKAGES="${__PACKAGES} python${PY_PKG_VER}-devel python${PY_PKG_VER}-pip python${PY_PKG_VER}-setuptools gcc" - # Only Py2 needs python-futures - __PACKAGES="${__PACKAGES} python-futures" + # shellcheck disable=SC2086 + __yum_install_noinput ${__PACKAGES} || return 1 - # There is no systemd-python3 package as of this writing - if [ "$DISTRO_MAJOR_VERSION" -ge 7 ]; then - __PACKAGES="${__PACKAGES} systemd-python" - fi - fi - - if [ "$DISTRO_MAJOR_VERSION" -ge 8 ]; then - __install_tornado_pip ${_py} || return 1 - __PACKAGES="${__PACKAGES} python3-m2crypto" - else - __PACKAGES="${__PACKAGES} m2crypto python${PY_PKG_VER}-crypto" - fi - - __PACKAGES="${__PACKAGES} python${PY_PKG_VER}-jinja2" - __PACKAGES="${__PACKAGES} python${PY_PKG_VER}-msgpack python${PY_PKG_VER}-requests" - __PACKAGES="${__PACKAGES} python${PY_PKG_VER}-tornado python${PY_PKG_VER}-zmq" - - if [ "$_INSTALL_CLOUD" -eq $BS_TRUE ]; then - __PACKAGES="${__PACKAGES} python${PY_PKG_VER}-libcloud" - fi - - if [ "${_INSTALL_PY}" -eq "${BS_TRUE}" ]; then - # Install Python if "-y" was passed in. - __install_python || return 1 - fi - - if [ "${_PY_EXE}" != "" ] && [ "$_PIP_ALLOWED" -eq "$BS_TRUE" ]; then - # If "-x" is defined, install dependencies with pip based on the Python version given. - _PIP_PACKAGES="m2crypto!=0.33.0 jinja2 msgpack-python pycrypto PyYAML tornado<5.0 zmq futures>=2.0" - - # install swig and openssl on cent6 - if $_install_m2crypto_req; then - __yum_install_noinput openssl-devel swig || return 1 - fi - - if [ -f "${_SALT_GIT_CHECKOUT_DIR}/requirements/base.txt" ]; then - # Filter out any commented lines from the requirements file - _REQ_LINES="$(grep '^[^#]' "${_SALT_GIT_CHECKOUT_DIR}/requirements/base.txt")" - for SINGLE_PACKAGE in ${_PIP_PACKAGES}; do - __REQUIRED_VERSION="$(grep "${SINGLE_PACKAGE}" "${_REQ_LINES}")" - if [ "${__REQUIRED_VERSION}" != "" ]; then - _PIP_PACKAGES=$(echo "$_PIP_PACKAGES" | sed "s/${SINGLE_PACKAGE}/${__REQUIRED_VERSION}/") - fi - done - fi - - if [ "$_INSTALL_CLOUD" -eq "${BS_TRUE}" ]; then - _PIP_PACKAGES="${_PIP_PACKAGES} apache-libcloud" - fi - - __install_pip_pkgs "${_PIP_PACKAGES}" "${_PY_EXE}" || return 1 - else - # shellcheck disable=SC2086 - __yum_install_noinput ${__PACKAGES} || return 1 - fi - else - if [ "${_INSTALL_PY}" -eq "${BS_TRUE}" ] && [ "$DISTRO_MAJOR_VERSION" -lt 8 ]; then - # Install Python if "-y" was passed in. - __install_python || return 1 - fi - __PACKAGES="${__PACKAGES} python${PY_PKG_VER}-devel python${PY_PKG_VER}-pip python${PY_PKG_VER}-setuptools gcc" - # shellcheck disable=SC2086 - __yum_install_noinput ${__PACKAGES} || return 1 - fi # Let's trigger config_salt() if [ "$_TEMP_CONFIG_DIR" = "null" ]; then - _TEMP_CONFIG_DIR="${_SALT_GIT_CHECKOUT_DIR}/conf/" + _TEMP_CONFIG_DIR="${_SALT_GIT_CHECKOUT_DIR}/conf" CONFIG_SALT_FUNC="config_salt" fi @@ -5024,29 +4325,23 @@ install_centos_git_deps() { } install_centos_git() { + if [ "${_PY_EXE}" != "" ]; then _PYEXE=${_PY_EXE} echoinfo "Using the following python version: ${_PY_EXE} to install salt" else - _PYEXE='python2' + echoerror "Python 2 is no longer supported, only Python 3" + return 1 fi echodebug "_PY_EXE: $_PY_EXE" - if [ "${_POST_NEON_INSTALL}" -eq $BS_TRUE ]; then - __install_salt_from_repo_post_neon "${_PY_EXE}" || return 1 - return 0 - fi - - if [ -f "${_SALT_GIT_CHECKOUT_DIR}/salt/syspaths.py" ]; then - $_PYEXE setup.py --salt-config-dir="$_SALT_ETC_DIR" --salt-cache-dir="${_SALT_CACHE_DIR}" ${SETUP_PY_INSTALL_ARGS} install --prefix=/usr || return 1 - else - $_PYEXE setup.py ${SETUP_PY_INSTALL_ARGS} install --prefix=/usr || return 1 - fi + __install_salt_from_repo "${_PY_EXE}" || return 1 return 0 } install_centos_git_post() { + SYSTEMD_RELOAD=$BS_FALSE for fname in api master minion syndic; do @@ -5063,7 +4358,8 @@ install_centos_git_post() { else _SERVICE_FILE="${_SALT_GIT_CHECKOUT_DIR}/pkg/rpm/salt-${fname}.service" fi - if [ -f /bin/systemctl ]; then + + if [ "$_SYSTEMD_FUNCTIONAL" -eq $BS_TRUE ]; then if [ ! -f "/usr/lib/systemd/system/salt-${fname}.service" ] || \ { [ -f "/usr/lib/systemd/system/salt-${fname}.service" ] && [ "$_FORCE_OVERWRITE" -eq $BS_TRUE ]; }; then __copyfile "${_SERVICE_FILE}" /usr/lib/systemd/system @@ -5087,7 +4383,8 @@ install_centos_git_post() { } install_centos_onedir_deps() { - if [ "$_UPGRADE_SYS" -eq $BS_TRUE ]; then + + if [ "$_UPGRADE_SYS" -eq "$BS_TRUE" ]; then yum -y update || return 1 fi @@ -5102,19 +4399,13 @@ install_centos_onedir_deps() { fi # If -R was passed, we need to configure custom repo url with rsync-ed packages - # Which is still handled in __install_saltstack_rhel_repository. This call has - # its own check in case -r was passed without -R. + # Which was still handled in __install_saltstack_rhel_repository, which was for old-stable which + # is removed since End-Of-Life. This call has its own check in case -r was passed without -R. if [ "$_CUSTOM_REPO_URL" != "null" ]; then __install_saltstack_rhel_onedir_repository || return 1 fi - if [ "$DISTRO_MAJOR_VERSION" -ge 8 ]; then - __PACKAGES="dnf-utils chkconfig" - else - __PACKAGES="yum-utils chkconfig" - fi - - __PACKAGES="${__PACKAGES} procps" + __PACKAGES="yum-utils chkconfig procps-ng findutils" # shellcheck disable=SC2086 __yum_install_noinput ${__PACKAGES} || return 1 @@ -5125,48 +4416,39 @@ install_centos_onedir_deps() { __yum_install_noinput ${_EXTRA_PACKAGES} || return 1 fi - return 0 } -# This function has been modified to allow for specific versions to be installed -# when not using the salt repo install_centos_onedir() { + yum clean metadata + yum makecache + __PACKAGES="" - local cloud='salt-cloud' - local master='salt-master' - local minion='salt-minion' - local syndic='salt-syndic' - local ver="$_ONEDIR_REV" - - if [ ! -z $ver ]; then - cloud+="-$ver" - master+="-$ver" - minion+="-$ver" - syndic+="-$ver" - fi - if [ "$_INSTALL_CLOUD" -eq $BS_TRUE ];then - __PACKAGES="${__PACKAGES} $cloud" + __PACKAGES="${__PACKAGES} salt-cloud-${STABLE_REV}" fi if [ "$_INSTALL_MASTER" -eq $BS_TRUE ];then - __PACKAGES="${__PACKAGES} $master" + __PACKAGES="${__PACKAGES} salt-master-${STABLE_REV}" fi if [ "$_INSTALL_MINION" -eq $BS_TRUE ]; then - __PACKAGES="${__PACKAGES} $minion" + __PACKAGES="${__PACKAGES} salt-minion-${STABLE_REV}" fi if [ "$_INSTALL_SYNDIC" -eq $BS_TRUE ];then - __PACKAGES="${__PACKAGES} $syndic" + __PACKAGES="${__PACKAGES} salt-syndic-${STABLE_REV}" + fi + + if [ "$_INSTALL_SALT_API" -eq $BS_TRUE ]; then + __PACKAGES="${__PACKAGES} salt-api-${STABLE_REV}" fi # shellcheck disable=SC2086 __yum_install_noinput ${__PACKAGES} || return 1 - return 0 } install_centos_onedir_post() { + SYSTEMD_RELOAD=$BS_FALSE for fname in api master minion syndic; do @@ -5178,7 +4460,7 @@ install_centos_onedir_post() { [ $fname = "minion" ] && [ "$_INSTALL_MINION" -eq $BS_FALSE ] && continue [ $fname = "syndic" ] && [ "$_INSTALL_SYNDIC" -eq $BS_FALSE ] && continue - if [ -f /bin/systemctl ]; then + if [ "$_SYSTEMD_FUNCTIONAL" -eq $BS_TRUE ]; then /bin/systemctl is-enabled salt-${fname}.service > /dev/null 2>&1 || ( /bin/systemctl preset salt-${fname}.service > /dev/null 2>&1 && /bin/systemctl enable salt-${fname}.service > /dev/null 2>&1 @@ -5198,7 +4480,8 @@ install_centos_onedir_post() { } install_centos_restart_daemons() { - [ $_START_DAEMONS -eq $BS_FALSE ] && return + + [ "$_START_DAEMONS" -eq $BS_FALSE ] && return for fname in api master minion syndic; do # Skip salt-api since the service should be opt-in and not necessarily started on boot @@ -5209,26 +4492,11 @@ install_centos_restart_daemons() { [ $fname = "minion" ] && [ "$_INSTALL_MINION" -eq $BS_FALSE ] && continue [ $fname = "syndic" ] && [ "$_INSTALL_SYNDIC" -eq $BS_FALSE ] && continue - if [ -f /sbin/initctl ] && [ -f /etc/init/salt-${fname}.conf ]; then - # We have upstart support and upstart knows about our service - if ! /sbin/initctl status salt-$fname > /dev/null 2>&1; then - # Everything is in place and upstart gave us an error code? Fail! - return 1 - fi - - # upstart knows about this service. - # Let's try to stop it, and then start it - /sbin/initctl stop salt-$fname > /dev/null 2>&1 - # Restart service - if ! /sbin/initctl start salt-$fname > /dev/null 2>&1; then - # Failed the restart?! - return 1 - fi - elif [ -f /etc/init.d/salt-$fname ]; then + if [ -f /etc/init.d/salt-$fname ]; then # Disable stdin to fix shell session hang on killing tee pipe service salt-$fname stop < /dev/null > /dev/null 2>&1 service salt-$fname start < /dev/null - elif [ -f /usr/bin/systemctl ]; then + elif [ "$_SYSTEMD_FUNCTIONAL" -eq $BS_TRUE ]; then # CentOS 7 uses systemd /usr/bin/systemctl stop salt-$fname > /dev/null 2>&1 /usr/bin/systemctl start salt-$fname.service && continue @@ -5242,21 +4510,25 @@ install_centos_restart_daemons() { } install_centos_testing_deps() { + install_centos_stable_deps || return 1 return 0 } install_centos_testing() { + install_centos_stable || return 1 return 0 } install_centos_testing_post() { + install_centos_stable_post || return 1 return 0 } install_centos_check_services() { + for fname in api master minion syndic; do # Skip salt-api since the service should be opt-in and not necessarily started on boot [ $fname = "api" ] && continue @@ -5266,12 +4538,10 @@ install_centos_check_services() { [ $fname = "master" ] && [ "$_INSTALL_MASTER" -eq $BS_FALSE ] && continue [ $fname = "syndic" ] && [ "$_INSTALL_SYNDIC" -eq $BS_FALSE ] && continue - if [ -f /sbin/initctl ] && [ -f /etc/init/salt-${fname}.conf ]; then - __check_services_upstart salt-$fname || return 1 - elif [ -f /etc/init.d/salt-$fname ]; then - __check_services_sysvinit salt-$fname || return 1 - elif [ -f /usr/bin/systemctl ]; then - __check_services_systemd salt-$fname || return 1 + if [ -f "/etc/init.d/salt-$fname" ]; then + __check_services_sysvinit "salt-$fname" || return 1 + elif [ "$_SYSTEMD_FUNCTIONAL" -eq $BS_TRUE ]; then + __check_services_systemd "salt-$fname" || return 1 fi done @@ -5287,286 +4557,343 @@ install_centos_check_services() { # RedHat Install Functions # install_red_hat_linux_stable_deps() { + install_centos_stable_deps || return 1 return 0 } install_red_hat_linux_git_deps() { + install_centos_git_deps || return 1 return 0 } install_red_hat_linux_onedir_deps() { + install_centos_onedir_deps || return 1 return 0 } install_red_hat_enterprise_stable_deps() { + install_red_hat_linux_stable_deps || return 1 return 0 } install_red_hat_enterprise_git_deps() { + install_red_hat_linux_git_deps || return 1 return 0 } install_red_hat_enterprise_onedir_deps() { + install_red_hat_linux_onedir_deps || return 1 return 0 } install_red_hat_enterprise_linux_stable_deps() { + install_red_hat_linux_stable_deps || return 1 return 0 } install_red_hat_enterprise_linux_git_deps() { + install_red_hat_linux_git_deps || return 1 return 0 } install_red_hat_enterprise_linux_onedir_deps() { + install_red_hat_linux_onedir_deps || return 1 return 0 } install_red_hat_enterprise_server_stable_deps() { + install_red_hat_linux_stable_deps || return 1 return 0 } install_red_hat_enterprise_server_git_deps() { + install_red_hat_linux_git_deps || return 1 return 0 } install_red_hat_enterprise_server_onedir_deps() { + install_red_hat_linux_onedir_deps || return 1 return 0 } install_red_hat_enterprise_workstation_stable_deps() { + install_red_hat_linux_stable_deps || return 1 return 0 } install_red_hat_enterprise_workstation_git_deps() { + install_red_hat_linux_git_deps || return 1 return 0 } install_red_hat_enterprise_workstation_onedir_deps() { + install_red_hat_linux_timat_deps || return 1 return 0 } install_red_hat_linux_stable() { + install_centos_stable || return 1 return 0 } install_red_hat_linux_git() { + install_centos_git || return 1 return 0 } install_red_hat_linux_onedir() { + install_centos_onedir || return 1 return 0 } install_red_hat_enterprise_stable() { + install_red_hat_linux_stable || return 1 return 0 } install_red_hat_enterprise_git() { + install_red_hat_linux_git || return 1 return 0 } install_red_hat_enterprise_onedir() { + install_red_hat_linux_onedir || return 1 return 0 } install_red_hat_enterprise_linux_stable() { + install_red_hat_linux_stable || return 1 return 0 } install_red_hat_enterprise_linux_git() { + install_red_hat_linux_git || return 1 return 0 } install_red_hat_enterprise_linux_onedir() { + install_red_hat_linux_onedir || return 1 return 0 } install_red_hat_enterprise_server_stable() { + install_red_hat_linux_stable || return 1 return 0 } install_red_hat_enterprise_server_git() { + install_red_hat_linux_git || return 1 return 0 } install_red_hat_enterprise_server_onedir() { + install_red_hat_linux_onedir || return 1 return 0 } install_red_hat_enterprise_workstation_stable() { + install_red_hat_linux_stable || return 1 return 0 } install_red_hat_enterprise_workstation_git() { + install_red_hat_linux_git || return 1 return 0 } install_red_hat_enterprise_workstation_onedir() { + install_red_hat_linux_onedir || return 1 return 0 } install_red_hat_linux_stable_post() { + install_centos_stable_post || return 1 return 0 } install_red_hat_linux_restart_daemons() { + install_centos_restart_daemons || return 1 return 0 } install_red_hat_linux_git_post() { + install_centos_git_post || return 1 return 0 } install_red_hat_enterprise_stable_post() { + install_red_hat_linux_stable_post || return 1 return 0 } install_red_hat_enterprise_restart_daemons() { + install_red_hat_linux_restart_daemons || return 1 return 0 } install_red_hat_enterprise_git_post() { + install_red_hat_linux_git_post || return 1 return 0 } install_red_hat_enterprise_linux_stable_post() { + install_red_hat_linux_stable_post || return 1 return 0 } install_red_hat_enterprise_linux_restart_daemons() { + install_red_hat_linux_restart_daemons || return 1 return 0 } install_red_hat_enterprise_linux_git_post() { + install_red_hat_linux_git_post || return 1 return 0 } install_red_hat_enterprise_server_stable_post() { + install_red_hat_linux_stable_post || return 1 return 0 } install_red_hat_enterprise_server_restart_daemons() { + install_red_hat_linux_restart_daemons || return 1 return 0 } install_red_hat_enterprise_server_git_post() { + install_red_hat_linux_git_post || return 1 return 0 } install_red_hat_enterprise_workstation_stable_post() { + install_red_hat_linux_stable_post || return 1 return 0 } install_red_hat_enterprise_workstation_restart_daemons() { + install_red_hat_linux_restart_daemons || return 1 return 0 } install_red_hat_enterprise_workstation_git_post() { + install_red_hat_linux_git_post || return 1 return 0 } install_red_hat_linux_testing_deps() { + install_centos_testing_deps || return 1 return 0 } install_red_hat_linux_testing() { + install_centos_testing || return 1 return 0 } install_red_hat_linux_testing_post() { + install_centos_testing_post || return 1 return 0 } install_red_hat_enterprise_testing_deps() { + install_centos_testing_deps || return 1 return 0 } install_red_hat_enterprise_testing() { + install_centos_testing || return 1 return 0 } install_red_hat_enterprise_testing_post() { + install_centos_testing_post || return 1 return 0 } install_red_hat_enterprise_server_testing_deps() { + install_centos_testing_deps || return 1 return 0 } install_red_hat_enterprise_server_testing() { + install_centos_testing || return 1 return 0 } install_red_hat_enterprise_server_testing_post() { + install_centos_testing_post || return 1 return 0 } install_red_hat_enterprise_workstation_testing_deps() { + install_centos_testing_deps || return 1 return 0 } install_red_hat_enterprise_workstation_testing() { + install_centos_testing || return 1 return 0 } install_red_hat_enterprise_workstation_testing_post() { + install_centos_testing_post || return 1 return 0 } @@ -5580,11 +4907,13 @@ install_red_hat_enterprise_workstation_testing_post() { # Oracle Linux Install Functions # install_oracle_linux_stable_deps() { + # Install Oracle's EPEL. - if [ ${_EPEL_REPOS_INSTALLED} -eq $BS_FALSE ]; then + if [ "${_EPEL_REPOS_INSTALLED}" -eq $BS_FALSE ]; then _EPEL_REPO=oracle-epel-release-el${DISTRO_MAJOR_VERSION} if ! rpm -q "${_EPEL_REPO}" > /dev/null; then - __yum_install_noinput "${_EPEL_REPO}" + # shellcheck disable=SC2086 + __yum_install_noinput ${_EPEL_REPO} fi _EPEL_REPOS_INSTALLED=$BS_TRUE fi @@ -5969,6 +5298,7 @@ install_cloud_linux_check_services() { # Alpine Linux Install Functions # install_alpine_linux_stable_deps() { + _PIP_INSTALL_ARGS="" if ! grep -q '^[^#].\+alpine/.\+/community' /etc/apk/repositories; then # Add community repository entry based on the "main" repo URL __REPO=$(grep '^[^#].\+alpine/.\+/main\>' /etc/apk/repositories) @@ -5987,6 +5317,7 @@ install_alpine_linux_stable_deps() { } install_alpine_linux_git_deps() { + _PIP_INSTALL_ARGS="" install_alpine_linux_stable_deps || return 1 if ! __check_command_exists git; then @@ -5995,33 +5326,14 @@ install_alpine_linux_git_deps() { __git_clone_and_checkout || return 1 - if [ "${_POST_NEON_INSTALL}" -eq $BS_FALSE ]; then - apk -U add python2 py-virtualenv py2-crypto py2-m2crypto py2-setuptools \ - py2-jinja2 py2-yaml py2-markupsafe py2-msgpack py2-psutil \ - py2-zmq zeromq py2-requests || return 1 - - if [ -f "${_SALT_GIT_CHECKOUT_DIR}/requirements/base.txt" ]; then - # We're on the master branch, install whichever tornado is on the requirements file - __REQUIRED_TORNADO="$(grep tornado "${_SALT_GIT_CHECKOUT_DIR}/requirements/base.txt")" - if [ "${__REQUIRED_TORNADO}" != "" ]; then - apk -U add py2-tornado || return 1 - fi - fi - else - apk -U add python3 python3-dev py3-pip py3-setuptools g++ linux-headers zeromq-dev openrc || return 1 - _PY_EXE=python3 - return 0 - fi - - # Let's trigger config_salt() - if [ "$_TEMP_CONFIG_DIR" = "null" ]; then - _TEMP_CONFIG_DIR="${_SALT_GIT_CHECKOUT_DIR}/conf/" - CONFIG_SALT_FUNC="config_salt" - fi + apk -U add python3 python3-dev py3-pip py3-setuptools g++ linux-headers zeromq-dev openrc || return 1 + _PY_EXE=python3 + return 0 } install_alpine_linux_stable() { __PACKAGES="salt" + _PIP_INSTALL_ARGS="" if [ "$_INSTALL_CLOUD" -eq $BS_TRUE ];then __PACKAGES="${__PACKAGES} salt-cloud" @@ -6036,26 +5348,23 @@ install_alpine_linux_stable() { __PACKAGES="${__PACKAGES} salt-syndic" fi + if [ "$_INSTALL_SALT_API" -eq $BS_TRUE ]; then + __PACKAGES="${__PACKAGES} salt-api" + fi + # shellcheck disable=SC2086 - apk -U add ${__PACKAGES} || return 1 + apk -U add "${__PACKAGES}" || return 1 return 0 } install_alpine_linux_git() { - - if [ "${_POST_NEON_INSTALL}" -eq $BS_TRUE ]; then - __install_salt_from_repo_post_neon "${_PY_EXE}" || return 1 - return 0 - fi - - if [ -f "${_SALT_GIT_CHECKOUT_DIR}/salt/syspaths.py" ]; then - python2 setup.py --salt-config-dir="$_SALT_ETC_DIR" --salt-cache-dir="${_SALT_CACHE_DIR}" ${SETUP_PY_INSTALL_ARGS} install || return 1 - else - python2 setup.py ${SETUP_PY_INSTALL_ARGS} install || return 1 - fi + _PIP_INSTALL_ARGS="" + __install_salt_from_repo "${_PY_EXE}" || return 1 + return 0 } install_alpine_linux_post() { + _PIP_INSTALL_ARGS="" for fname in api master minion syndic; do # Skip if not meant to be installed [ $fname = "api" ] && \ @@ -6085,6 +5394,7 @@ install_alpine_linux_post() { } install_alpine_linux_restart_daemons() { + _PIP_INSTALL_ARGS="" [ "${_START_DAEMONS}" -eq $BS_FALSE ] && return for fname in api master minion syndic; do @@ -6103,6 +5413,7 @@ install_alpine_linux_restart_daemons() { } install_alpine_linux_check_services() { + _PIP_INSTALL_ARGS="" for fname in api master minion syndic; do # Skip salt-api since the service should be opt-in and not necessarily started on boot [ $fname = "api" ] && continue @@ -6119,6 +5430,7 @@ install_alpine_linux_check_services() { } daemons_running_alpine_linux() { + _PIP_INSTALL_ARGS="" [ "${_START_DAEMONS}" -eq $BS_FALSE ] && return FAILED_DAEMONS=0 @@ -6152,167 +5464,21 @@ daemons_running_alpine_linux() { # Amazon Linux AMI Install Functions # -install_amazon_linux_ami_deps() { - # Shim to figure out if we're using old (rhel) or new (aws) rpms. - _USEAWS=$BS_FALSE - pkg_append="python" - - if [ "$ITYPE" = "stable" ]; then - repo_rev="$STABLE_REV" - else - repo_rev="latest" - fi - - if echo $repo_rev | grep -E -q '^archive'; then - year=$(echo "$repo_rev" | cut -d '/' -f 2 | cut -c1-4) - else - year=$(echo "$repo_rev" | cut -c1-4) - fi - - if echo "$repo_rev" | grep -E -q '^(latest|2016\.11)$' || \ - [ "$year" -gt 2016 ]; then - _USEAWS=$BS_TRUE - pkg_append="python27" - fi - - # We need to install yum-utils before doing anything else when installing on - # Amazon Linux ECS-optimized images. See issue #974. - __yum_install_noinput yum-utils - - # Do upgrade early - if [ "$_UPGRADE_SYS" -eq $BS_TRUE ]; then - yum -y update || return 1 - fi - - if [ $_DISABLE_REPOS -eq $BS_FALSE ] || [ "$_CUSTOM_REPO_URL" != "null" ]; then - __REPO_FILENAME="salt.repo" - - # Set a few vars to make life easier. - if [ $_USEAWS -eq $BS_TRUE ]; then - base_url="$HTTP_VAL://${_REPO_URL}/yum/amazon/latest/\$basearch/$repo_rev/" - gpg_key="${base_url}SALTSTACK-GPG-KEY.pub" - repo_name="SaltStack repo for Amazon Linux" - else - base_url="$HTTP_VAL://${_REPO_URL}/yum/redhat/6/\$basearch/$repo_rev/" - gpg_key="${base_url}SALTSTACK-GPG-KEY.pub" - repo_name="SaltStack repo for RHEL/CentOS 6" - fi - - # This should prob be refactored to use __install_saltstack_rhel_repository() - # With args passed in to do the right thing. Reformatted to be more like the - # amazon linux yum file. - if [ ! -s "/etc/yum.repos.d/${__REPO_FILENAME}" ]; then - cat <<_eof > "/etc/yum.repos.d/${__REPO_FILENAME}" -[saltstack-repo] -name=$repo_name -failovermethod=priority -priority=10 -gpgcheck=1 -gpgkey=$gpg_key -baseurl=$base_url -_eof - fi - - fi - - if [ "${_POST_NEON_INSTALL}" -eq $BS_FALSE ]; then - # Package python-ordereddict-1.1-2.el6.noarch is obsoleted by python26-2.6.9-2.88.amzn1.x86_64 - # which is already installed - __PACKAGES="m2crypto ${pkg_append}-crypto ${pkg_append}-jinja2 ${pkg_append}-PyYAML" - __PACKAGES="${__PACKAGES} ${pkg_append}-msgpack ${pkg_append}-requests ${pkg_append}-zmq" - __PACKAGES="${__PACKAGES} ${pkg_append}-futures" - # shellcheck disable=SC2086 - __yum_install_noinput ${__PACKAGES} || return 1 - fi - - if [ "${_EXTRA_PACKAGES}" != "" ]; then - echoinfo "Installing the following extra packages as requested: ${_EXTRA_PACKAGES}" - # shellcheck disable=SC2086 - __yum_install_noinput ${_EXTRA_PACKAGES} || return 1 - fi -} - -install_amazon_linux_ami_git_deps() { - if [ "$_INSECURE_DL" -eq $BS_FALSE ] && [ "${_SALT_REPO_URL%%://*}" = "https" ]; then - yum -y install ca-certificates || return 1 - fi - - PIP_EXE='pip' - if __check_command_exists python2.7; then - if ! __check_command_exists pip2.7; then - if ! __check_command_exists easy_install-2.7; then - __yum_install_noinput python27-setuptools - fi - /usr/bin/easy_install-2.7 pip || return 1 - fi - PIP_EXE='/usr/local/bin/pip2.7' - _PY_EXE='python2.7' - fi - - install_amazon_linux_ami_deps || return 1 - - if ! __check_command_exists git; then - __yum_install_noinput git || return 1 - fi - - __git_clone_and_checkout || return 1 - - if [ "${_POST_NEON_INSTALL}" -eq $BS_FALSE ]; then - __PACKAGES="" - __PIP_PACKAGES="" - - if [ "$_INSTALL_CLOUD" -eq $BS_TRUE ]; then - __check_pip_allowed "You need to allow pip based installations (-P) in order to install apache-libcloud" - __PACKAGES="${__PACKAGES} python27-pip" - __PIP_PACKAGES="${__PIP_PACKAGES} apache-libcloud>=$_LIBCLOUD_MIN_VERSION" - fi - - if [ -f "${_SALT_GIT_CHECKOUT_DIR}/requirements/base.txt" ]; then - # We're on the master branch, install whichever tornado is on the requirements file - __REQUIRED_TORNADO="$(grep tornado "${_SALT_GIT_CHECKOUT_DIR}/requirements/base.txt")" - if [ "${__REQUIRED_TORNADO}" != "" ]; then - __PACKAGES="${__PACKAGES} ${pkg_append}-tornado" - fi - fi - - if [ "${__PACKAGES}" != "" ]; then - # shellcheck disable=SC2086 - __yum_install_noinput ${__PACKAGES} || return 1 - fi - - if [ "${__PIP_PACKAGES}" != "" ]; then - # shellcheck disable=SC2086 - ${PIP_EXE} install ${__PIP_PACKAGES} || return 1 - fi - else - __PACKAGES="python27-pip python27-setuptools python27-devel gcc" - # shellcheck disable=SC2086 - __yum_install_noinput ${__PACKAGES} || return 1 - fi - - # Let's trigger config_salt() - if [ "$_TEMP_CONFIG_DIR" = "null" ]; then - _TEMP_CONFIG_DIR="${_SALT_GIT_CHECKOUT_DIR}/conf/" - CONFIG_SALT_FUNC="config_salt" - fi - - return 0 -} - +# Support for Amazon Linux 2 install_amazon_linux_ami_2_git_deps() { if [ "$_INSECURE_DL" -eq $BS_FALSE ] && [ "${_SALT_REPO_URL%%://*}" = "https" ]; then yum -y install ca-certificates || return 1 fi + if [ "$_PY_MAJOR_VERSION" -eq 2 ]; then + echoerror "Python 2 is no longer supported, only Python 3" + return 1 + fi + install_amazon_linux_ami_2_deps || return 1 - if [ "$_PY_MAJOR_VERSION" -eq 2 ]; then - PY_PKG_VER=2 - PIP_EXE='/bin/pip' - else - PY_PKG_VER=3 - PIP_EXE='/bin/pip3' - fi + PY_PKG_VER=3 + PIP_EXE='/bin/pip3' __PACKAGES="python${PY_PKG_VER}-pip" if ! __check_command_exists "${PIP_EXE}"; then @@ -6326,61 +5492,14 @@ install_amazon_linux_ami_2_git_deps() { __git_clone_and_checkout || return 1 - if [ "${_POST_NEON_INSTALL}" -eq $BS_FALSE ]; then + __PACKAGES="python${PY_PKG_VER}-pip python${PY_PKG_VER}-setuptools python${PY_PKG_VER}-devel gcc" - __PACKAGES="" - __PIP_PACKAGES="" - - if [ "$_INSTALL_CLOUD" -eq "$BS_TRUE" ]; then - __check_pip_allowed "You need to allow pip based installations (-P) in order to install apache-libcloud" - if [ "$PARSED_VERSION" -eq "2" ]; then - if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -eq "3" ]; then - __PACKAGES="${__PACKAGES} python3-pip" - __PIP_PACKAGES="${__PIP_PACKAGES} tornado<$_TORNADO_MAX_PY3_VERSION" - else - __PACKAGES="${__PACKAGES} python2-pip" - fi - else - __PACKAGES="${__PACKAGES} python27-pip" - fi - __PIP_PACKAGES="${__PIP_PACKAGES} apache-libcloud>=$_LIBCLOUD_MIN_VERSION" - fi - - if [ -f "${_SALT_GIT_CHECKOUT_DIR}/requirements/base.txt" ]; then - # We're on the master branch, install whichever tornado is on the requirements file - __REQUIRED_TORNADO="$(grep tornado "${_SALT_GIT_CHECKOUT_DIR}/requirements/base.txt")" - if [ "${__REQUIRED_TORNADO}" != "" ]; then - if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -eq "3" ]; then - __PIP_PACKAGES="${__PIP_PACKAGES} tornado<$_TORNADO_MAX_PY3_VERSION" - else - __PACKAGES="${__PACKAGES} ${pkg_append}${PY_PKG_VER}-tornado" - fi - fi - fi - - if [ "${__PIP_PACKAGES}" != "" ]; then - __check_pip_allowed "You need to allow pip based installations (-P) in order to install ${__PIP_PACKAGES}" - __PACKAGES="${__PACKAGES} python${PY_PKG_VER}-pip" - fi - - if [ "${__PACKAGES}" != "" ]; then - # shellcheck disable=SC2086 - __yum_install_noinput ${__PACKAGES} || return 1 - fi - - if [ "${__PIP_PACKAGES}" != "" ]; then - # shellcheck disable=SC2086 - ${PIP_EXE} install ${__PIP_PACKAGES} || return 1 - fi - else - __PACKAGES="python${PY_PKG_VER}-pip python${PY_PKG_VER}-setuptools python${PY_PKG_VER}-devel gcc" - # shellcheck disable=SC2086 - __yum_install_noinput ${__PACKAGES} || return 1 - fi + # shellcheck disable=SC2086 + __yum_install_noinput ${__PACKAGES} || return 1 # Let's trigger config_salt() if [ "$_TEMP_CONFIG_DIR" = "null" ]; then - _TEMP_CONFIG_DIR="${_SALT_GIT_CHECKOUT_DIR}/conf/" + _TEMP_CONFIG_DIR="${_SALT_GIT_CHECKOUT_DIR}/conf" CONFIG_SALT_FUNC="config_salt" fi @@ -6388,26 +5507,9 @@ install_amazon_linux_ami_2_git_deps() { } install_amazon_linux_ami_2_deps() { - # Shim to figure out if we're using old (rhel) or new (aws) rpms. - _USEAWS=$BS_FALSE - pkg_append="python" - - if [ "$ITYPE" = "stable" ]; then - repo_rev="$STABLE_REV" - else - repo_rev="latest" - fi - - if echo $repo_rev | grep -E -q '^archive'; then - year=$(echo "$repo_rev" | cut -d '/' -f 2 | cut -c1-4) - else - year=$(echo "$repo_rev" | cut -c1-4) - fi - - if echo "$repo_rev" | grep -E -q '^(latest|2016\.11)$' || \ - [ "$year" -gt 2016 ]; then - _USEAWS=$BS_TRUE - pkg_append="python" + if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -ne 3 ]; then + echoerror "Python version is no longer supported, only Python 3" + return 1 fi # We need to install yum-utils before doing anything else when installing on @@ -6420,56 +5522,24 @@ install_amazon_linux_ami_2_deps() { fi if [ $_DISABLE_REPOS -eq $BS_FALSE ] || [ "$_CUSTOM_REPO_URL" != "null" ]; then - __REPO_FILENAME="salt.repo" - __PY_VERSION_REPO="yum" - PY_PKG_VER="" - repo_label="saltstack-repo" - repo_name="SaltStack repo for Amazon Linux 2" - if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -eq 3 ]; then - __REPO_FILENAME="salt.repo" - __PY_VERSION_REPO="py3" - PY_PKG_VER=3 - repo_label="saltstack-py3-repo" - repo_name="SaltStack Python 3 repo for Amazon Linux 2" + if [ ! -s "${YUM_REPO_FILE}" ]; then + FETCH_URL="https://github.com/saltstack/salt-install-guide/releases/latest/download/salt.repo" + __fetch_url "${YUM_REPO_FILE}" "${FETCH_URL}" + if [ "$STABLE_REV" != "latest" ]; then + # 3006.x is default + REPO_REV_MAJOR=$(echo "$STABLE_REV" | cut -d '.' -f 1) + if [ "$REPO_REV_MAJOR" -eq "3007" ]; then + # Enable the Salt 3007 STS repo + dnf config-manager --set-disable salt-repo-* + dnf config-manager --set-enabled salt-repo-3007-sts + fi + else + # Enable the Salt LATEST repo + dnf config-manager --set-disable salt-repo-* + dnf config-manager --set-enabled salt-repo-latest + fi + dnf clean expire-cache || return 1 fi - - base_url="$HTTP_VAL://${_REPO_URL}/${__PY_VERSION_REPO}/amazon/2/\$basearch/$repo_rev/" - gpg_key="${base_url}SALTSTACK-GPG-KEY.pub,${base_url}base/RPM-GPG-KEY-CentOS-7" - if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -eq 3 ]; then - gpg_key="${base_url}SALTSTACK-GPG-KEY.pub" - fi - - # This should prob be refactored to use __install_saltstack_rhel_repository() - # With args passed in to do the right thing. Reformatted to be more like the - # amazon linux yum file. - if [ ! -s "/etc/yum.repos.d/${__REPO_FILENAME}" ]; then - cat <<_eof > "/etc/yum.repos.d/${__REPO_FILENAME}" -[$repo_label] -name=$repo_name -failovermethod=priority -priority=10 -gpgcheck=1 -gpgkey=$gpg_key -baseurl=$base_url -_eof - fi - - fi - - if [ "${_POST_NEON_INSTALL}" -eq $BS_FALSE ]; then - # Package python-ordereddict-1.1-2.el6.noarch is obsoleted by python26-2.6.9-2.88.amzn1.x86_64 - # which is already installed - if [ -n "${PY_PKG_VER}" ] && [ "${PY_PKG_VER}" -eq 3 ]; then - __PACKAGES="${pkg_append}${PY_PKG_VER}-m2crypto ${pkg_append}${PY_PKG_VER}-pyyaml" - else - __PACKAGES="m2crypto PyYAML ${pkg_append}-futures" - fi - - __PACKAGES="${__PACKAGES} ${pkg_append}${PY_PKG_VER}-crypto ${pkg_append}${PY_PKG_VER}-jinja2 procps-ng" - __PACKAGES="${__PACKAGES} ${pkg_append}${PY_PKG_VER}-msgpack ${pkg_append}${PY_PKG_VER}-requests ${pkg_append}${PY_PKG_VER}-zmq" - - # shellcheck disable=SC2086 - __yum_install_noinput ${__PACKAGES} || return 1 fi if [ "${_EXTRA_PACKAGES}" != "" ]; then @@ -6480,20 +5550,9 @@ _eof } install_amazon_linux_ami_2_onedir_deps() { - # Shim to figure out if we're using old (rhel) or new (aws) rpms. - _USEAWS=$BS_FALSE - pkg_append="python" - - if [ "$ITYPE" = "onedir" ]; then - repo_rev="$ONEDIR_REV" - else - repo_rev="latest" - fi - - if echo $repo_rev | grep -E -q '^archive'; then - year=$(echo "$repo_rev" | cut -d '/' -f 2 | cut -c1-4) - else - year=$(echo "$repo_rev" | cut -c1-4) + if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -ne 3 ]; then + echoerror "Python version is no longer supported, only Python 3" + return 1 fi # We need to install yum-utils before doing anything else when installing on @@ -6506,64 +5565,24 @@ install_amazon_linux_ami_2_onedir_deps() { fi if [ $_DISABLE_REPOS -eq $BS_FALSE ] || [ "$_CUSTOM_REPO_URL" != "null" ]; then - __REPO_FILENAME="salt.repo" - __PY_VERSION_REPO="yum" - PY_PKG_VER="" - repo_label="saltstack-repo" - repo_name="SaltStack repo for Amazon Linux 2" - if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -eq 3 ]; then - __REPO_FILENAME="salt.repo" - __PY_VERSION_REPO="py3" - PY_PKG_VER=3 - repo_label="saltstack-py3-repo" - repo_name="SaltStack Python 3 repo for Amazon Linux 2" + if [ ! -s "${YUM_REPO_FILE}" ]; then + FETCH_URL="https://github.com/saltstack/salt-install-guide/releases/latest/download/salt.repo" + __fetch_url "${YUM_REPO_FILE}" "${FETCH_URL}" + if [ "$ONEDIR_REV" != "latest" ]; then + # 3006.x is default + REPO_REV_MAJOR=$(echo "$ONEDIR_REV" | cut -d '.' -f 1) + if [ "$REPO_REV_MAJOR" -eq "3007" ]; then + # Enable the Salt 3007 STS repo + dnf config-manager --set-disable salt-repo-* + dnf config-manager --set-enabled salt-repo-3007-sts + fi + else + # Enable the Salt LATEST repo + dnf config-manager --set-disable salt-repo-* + dnf config-manager --set-enabled salt-repo-latest + fi + dnf clean expire-cache || return 1 fi - - base_url="$HTTP_VAL://${_REPO_URL}/${_ONEDIR_DIR}/${__PY_VERSION_REPO}/amazon/2/\$basearch/$repo_rev/" - if [ "${ONEDIR_REV}" = "nightly" ] ; then - base_url="$HTTP_VAL://${_REPO_URL}/${_ONEDIR_NIGHTLY_DIR}/${__PY_VERSION_REPO}/amazon/2/\$basearch/" - fi - - if [ "$(echo "${ONEDIR_REV}" | grep -E '(3004|3005)')" != "" ] || [ "${ONEDIR_REV}" = "nightly" ]; then - gpg_key="${base_url}SALTSTACK-GPG-KEY.pub,${base_url}base/RPM-GPG-KEY-CentOS-7" - if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -eq 3 ]; then - gpg_key="${base_url}SALTSTACK-GPG-KEY.pub" - fi - else - gpg_key="${base_url}SALT-PROJECT-GPG-PUBKEY-2023.pub" - fi - - # This should prob be refactored to use __install_saltstack_rhel_repository() - # With args passed in to do the right thing. Reformatted to be more like the - # amazon linux yum file. - if [ ! -s "/etc/yum.repos.d/${__REPO_FILENAME}" ]; then - cat <<_eof > "/etc/yum.repos.d/${__REPO_FILENAME}" -[$repo_label] -name=$repo_name -failovermethod=priority -priority=10 -gpgcheck=1 -gpgkey=$gpg_key -baseurl=$base_url -_eof - fi - - fi - - if [ "${_POST_NEON_INSTALL}" -eq $BS_FALSE ]; then - # Package python-ordereddict-1.1-2.el6.noarch is obsoleted by python26-2.6.9-2.88.amzn1.x86_64 - # which is already installed - if [ -n "${PY_PKG_VER}" ] && [ "${PY_PKG_VER}" -eq 3 ]; then - __PACKAGES="${pkg_append}${PY_PKG_VER}-m2crypto ${pkg_append}${PY_PKG_VER}-pyyaml" - else - __PACKAGES="m2crypto PyYAML ${pkg_append}-futures" - fi - - __PACKAGES="${__PACKAGES} ${pkg_append}${PY_PKG_VER}-crypto ${pkg_append}${PY_PKG_VER}-jinja2 procps-ng" - __PACKAGES="${__PACKAGES} ${pkg_append}${PY_PKG_VER}-msgpack ${pkg_append}${PY_PKG_VER}-requests ${pkg_append}${PY_PKG_VER}-zmq" - - # shellcheck disable=SC2086 - __yum_install_noinput ${__PACKAGES} || return 1 fi if [ "${_EXTRA_PACKAGES}" != "" ]; then @@ -6573,41 +5592,6 @@ _eof fi } -install_amazon_linux_ami_stable() { - install_centos_stable || return 1 - return 0 -} - -install_amazon_linux_ami_stable_post() { - install_centos_stable_post || return 1 - return 0 -} - -install_amazon_linux_ami_restart_daemons() { - install_centos_restart_daemons || return 1 - return 0 -} - -install_amazon_linux_ami_git() { - install_centos_git || return 1 - return 0 -} - -install_amazon_linux_ami_git_post() { - install_centos_git_post || return 1 - return 0 -} - -install_amazon_linux_ami_testing() { - install_centos_testing || return 1 - return 0 -} - -install_amazon_linux_ami_testing_post() { - install_centos_testing_post || return 1 - return 0 -} - install_amazon_linux_ami_2_stable() { install_centos_stable || return 1 return 0 @@ -6658,6 +5642,133 @@ install_amazon_linux_ami_2_onedir_post() { return 0 } +# Support for Amazon Linux 2023 +# the following code needs adjustment to allow for 2023, 2024, 2025, etc - 2023 for now +install_amazon_linux_ami_2023_git_deps() { + if [ "$_INSECURE_DL" -eq $BS_FALSE ] && [ "${_SALT_REPO_URL%%://*}" = "https" ]; then + yum -y install ca-certificates || return 1 + fi + + install_amazon_linux_ami_2023_onedir_deps || return 1 + + PY_PKG_VER=3 + PIP_EXE='/bin/pip3' + __PACKAGES="python${PY_PKG_VER}-pip" + + if ! __check_command_exists "${PIP_EXE}"; then + # shellcheck disable=SC2086 + __yum_install_noinput ${__PACKAGES} || return 1 + fi + + if ! __check_command_exists git; then + __yum_install_noinput git || return 1 + fi + + __git_clone_and_checkout || return 1 + + __PACKAGES="python${PY_PKG_VER}-pip python${PY_PKG_VER}-setuptools python${PY_PKG_VER}-devel gcc" + + # shellcheck disable=SC2086 + __yum_install_noinput ${__PACKAGES} || return 1 + + # Let's trigger config_salt() + if [ "$_TEMP_CONFIG_DIR" = "null" ]; then + _TEMP_CONFIG_DIR="${_SALT_GIT_CHECKOUT_DIR}/conf" + CONFIG_SALT_FUNC="config_salt" + fi + + return 0 +} + +install_amazon_linux_ami_2023_onedir_deps() { + + # We need to install yum-utils before doing anything else when installing on + # Amazon Linux ECS-optimized images. See issue #974. + __yum_install_noinput yum-utils + + # Do upgrade early + if [ "$_UPGRADE_SYS" -eq $BS_TRUE ]; then + yum -y update || return 1 + fi + + if [ $_DISABLE_REPOS -eq $BS_FALSE ] || [ "$_CUSTOM_REPO_URL" != "null" ]; then + if [ ! -s "${YUM_REPO_FILE}" ]; then + FETCH_URL="https://github.com/saltstack/salt-install-guide/releases/latest/download/salt.repo" + __fetch_url "${YUM_REPO_FILE}" "${FETCH_URL}" + if [ "$ONEDIR_REV" != "latest" ]; then + # 3006.x is default + REPO_REV_MAJOR=$(echo "$ONEDIR_REV" | cut -d '.' -f 1) + if [ "$REPO_REV_MAJOR" -eq "3007" ]; then + # Enable the Salt 3007 STS repo + dnf config-manager --set-disable salt-repo-* + dnf config-manager --set-enabled salt-repo-3007-sts + fi + else + # Enable the Salt LATEST repo + dnf config-manager --set-disable salt-repo-* + dnf config-manager --set-enabled salt-repo-latest + fi + dnf clean expire-cache || return 1 + fi + fi + + if [ "${_EXTRA_PACKAGES}" != "" ]; then + echoinfo "Installing the following extra packages as requested: ${_EXTRA_PACKAGES}" + # shellcheck disable=SC2086 + __yum_install_noinput ${_EXTRA_PACKAGES} || return 1 + fi +} + +install_amazon_linux_ami_2023_stable() { + install_centos_stable || return 1 + return 0 +} + +install_amazon_linux_ami_2023_stable_post() { + install_centos_stable_post || return 1 + return 0 +} + +install_amazon_linux_ami_2023_restart_daemons() { + install_centos_restart_daemons || return 1 + return 0 +} + +install_amazon_linux_ami_2023_git() { + install_centos_git || return 1 + return 0 +} + +install_amazon_linux_ami_2023_git_post() { + install_centos_git_post || return 1 + return 0 +} + +install_amazon_linux_ami_2023_testing() { + install_centos_testing || return 1 + return 0 +} + +install_amazon_linux_ami_2023_testing_post() { + install_centos_testing_post || return 1 + return 0 +} + +install_amazon_linux_ami_2023_check_services() { + install_centos_check_services || return 1 + return 0 +} + +install_amazon_linux_ami_2023_onedir() { + install_centos_stable || return 1 + return 0 +} + +install_amazon_linux_ami_2023_onedir_post() { + install_centos_stable_post || return 1 + return 0 +} + # # Ended Amazon Linux AMI Install Functions # @@ -6685,7 +5796,8 @@ install_arch_linux_stable_deps() { fi if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -eq 2 ]; then - PY_PKG_VER=2 + echoerror "Python 2 is no longer supported, only Python 3" + return 1 else PY_PKG_VER="" fi @@ -6693,6 +5805,7 @@ install_arch_linux_stable_deps() { # YAML module is used for generating custom master/minion configs # shellcheck disable=SC2086 pacman -Su --noconfirm --needed python${PY_PKG_VER}-yaml + pacman -Su --noconfirm --needed python${PY_PKG_VER}-tornado if [ "$_INSTALL_CLOUD" -eq $BS_TRUE ]; then # shellcheck disable=SC2086 @@ -6716,33 +5829,21 @@ install_arch_linux_git_deps() { __git_clone_and_checkout || return 1 - if [ "${_POST_NEON_INSTALL}" -eq $BS_FALSE ]; then - pacman -R --noconfirm python2-distribute - pacman -Su --noconfirm --needed python2-crypto python2-setuptools python2-jinja \ - python2-m2crypto python2-markupsafe python2-msgpack python2-psutil \ - python2-pyzmq zeromq python2-requests python2-systemd || return 1 - - if [ -f "${_SALT_GIT_CHECKOUT_DIR}/requirements/base.txt" ]; then - # We're on the master branch, install whichever tornado is on the requirements file - __REQUIRED_TORNADO="$(grep tornado "${_SALT_GIT_CHECKOUT_DIR}/requirements/base.txt")" - if [ "${__REQUIRED_TORNADO}" != "" ]; then - pacman -Su --noconfirm --needed python2-tornado - fi - fi + if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -eq 2 ]; then + echoerror "Python 2 is no longer supported, only Python 3" + return 1 else - if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -eq 2 ]; then - PY_PKG_VER=2 - else - PY_PKG_VER="" - fi - __PACKAGES="python${PY_PKG_VER}-pip python${PY_PKG_VER}-setuptools gcc" - # shellcheck disable=SC2086 - pacman -Su --noconfirm --needed ${__PACKAGES} + PY_PKG_VER="" fi + __PACKAGES="python${PY_PKG_VER}-pip python${PY_PKG_VER}-setuptools gcc" + + # shellcheck disable=SC2086 + pacman -Su --noconfirm --needed ${__PACKAGES} + # Let's trigger config_salt() if [ "$_TEMP_CONFIG_DIR" = "null" ]; then - _TEMP_CONFIG_DIR="${_SALT_GIT_CHECKOUT_DIR}/conf/" + _TEMP_CONFIG_DIR="${_SALT_GIT_CHECKOUT_DIR}/conf" CONFIG_SALT_FUNC="config_salt" fi @@ -6770,19 +5871,16 @@ install_arch_linux_stable() { } install_arch_linux_git() { + if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -eq 2 ]; then + echoerror "Python 2 is no longer supported, only Python 3" + return 1 + fi - _POST_NEON_PIP_INSTALL_ARGS="${_POST_NEON_PIP_INSTALL_ARGS} --use-pep517" + _PIP_INSTALL_ARGS="${_PIP_INSTALL_ARGS} --use-pep517" _PIP_DOWNLOAD_ARGS="${_PIP_DOWNLOAD_ARGS} --use-pep517" - if [ "${_POST_NEON_INSTALL}" -eq $BS_TRUE ]; then - __install_salt_from_repo_post_neon "${_PY_EXE}" || return 1 - return 0 - fi - if [ -f "${_SALT_GIT_CHECKOUT_DIR}/salt/syspaths.py" ]; then - python2 setup.py --salt-config-dir="$_SALT_ETC_DIR" --salt-cache-dir="${_SALT_CACHE_DIR}" ${SETUP_PY_INSTALL_ARGS} install || return 1 - else - python2 setup.py ${SETUP_PY_INSTALL_ARGS} install || return 1 - fi + __install_salt_from_repo "${_PY_EXE}" || return 1 + return 0 } @@ -6806,7 +5904,7 @@ install_arch_linux_post() { # Skip salt-api since the service should be opt-in and not necessarily started on boot [ $fname = "api" ] && continue - if [ -f /usr/bin/systemctl ]; then + if [ "$_SYSTEMD_FUNCTIONAL" -eq $BS_TRUE ]; then # Using systemd /usr/bin/systemctl is-enabled salt-$fname.service > /dev/null 2>&1 || ( /usr/bin/systemctl preset salt-$fname.service > /dev/null 2>&1 && @@ -6837,7 +5935,7 @@ install_arch_linux_git_post() { _SERVICE_DIR="${_SALT_GIT_CHECKOUT_DIR}/pkg/rpm" fi - if [ -f /usr/bin/systemctl ]; then + if [ "$_SYSTEMD_FUNCTIONAL" -eq $BS_TRUE ]; then __copyfile "${_SERVICE_DIR}/salt-${fname}.service" "/lib/systemd/system/salt-${fname}.service" # Skip salt-api since the service should be opt-in and not necessarily started on boot @@ -6859,7 +5957,7 @@ install_arch_linux_git_post() { } install_arch_linux_restart_daemons() { - [ $_START_DAEMONS -eq $BS_FALSE ] && return + [ "$_START_DAEMONS" -eq $BS_FALSE ] && return for fname in api master minion syndic; do # Skip salt-api since the service should be opt-in and not necessarily started on boot @@ -6870,7 +5968,7 @@ install_arch_linux_restart_daemons() { [ $fname = "minion" ] && [ "$_INSTALL_MINION" -eq $BS_FALSE ] && continue [ $fname = "syndic" ] && [ "$_INSTALL_SYNDIC" -eq $BS_FALSE ] && continue - if [ -f /usr/bin/systemctl ]; then + if [ "$_SYSTEMD_FUNCTIONAL" -eq $BS_TRUE ]; then /usr/bin/systemctl stop salt-$fname.service > /dev/null 2>&1 /usr/bin/systemctl start salt-$fname.service && continue echodebug "Failed to start salt-$fname using systemd" @@ -6886,7 +5984,7 @@ install_arch_linux_restart_daemons() { } install_arch_check_services() { - if [ ! -f /usr/bin/systemctl ]; then + if [ "$_SYSTEMD_FUNCTIONAL" -eq $BS_TRUE ]; then # Not running systemd!? Don't check! return 0 fi @@ -6928,57 +6026,91 @@ install_arch_linux_onedir_post() { # __install_saltstack_photon_onedir_repository() { - if [ "$ITYPE" = "stable" ]; then - REPO_REV="$ONEDIR_REV" - else - REPO_REV="latest" + echodebug "__install_saltstack_photon_onedir_repository() entry" + + if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -ne 3 ]; then + echoerror "Python version is no longer supported, only Python 3" + return 1 fi - __PY_VERSION_REPO="yum" - if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -eq 3 ]; then - __PY_VERSION_REPO="py3" - fi - - REPO_FILE="/etc/yum.repos.d/salt.repo" - - if [ ! -s "$REPO_FILE" ] || [ "$_FORCE_OVERWRITE" -eq $BS_TRUE ]; then - FETCH_URL="${HTTP_VAL}://${_REPO_URL}/${_ONEDIR_DIR}/${__PY_VERSION_REPO}/photon/${DISTRO_MAJOR_VERSION}/${CPU_ARCH_L}/${ONEDIR_REV}" - if [ "${ONEDIR_REV}" = "nightly" ] ; then - FETCH_URL="${HTTP_VAL}://${_REPO_URL}/${_ONEDIR_NIGHTLY_DIR}/${__PY_VERSION_REPO}/photon/${DISTRO_MAJOR_VERSION}/${CPU_ARCH_L}/" + if [ ! -s "$YUM_REPO_FILE" ] || [ "$_FORCE_OVERWRITE" -eq $BS_TRUE ]; then + ## Photon tdnf doesn't support config-manager + ## FETCH_URL="https://github.com/saltstack/salt-install-guide/releases/latest/download/salt.repo" + ## __fetch_url "${YUM_REPO_FILE}" "${FETCH_URL}" + # shellcheck disable=SC2129 + if [ "$ONEDIR_REV" != "latest" ]; then + # 3006.x is default + REPO_REV_MAJOR=$(echo "$ONEDIR_REV" | cut -d '.' -f 1) + if [ "$REPO_REV_MAJOR" -eq "3007" ]; then + # Enable the Salt 3007 STS repo + ## tdnf config-manager --set-disable salt-repo-* + ## tdnf config-manager --set-enabled salt-repo-3007-sts + echo "[salt-repo-3007-sts]" > "${YUM_REPO_FILE}" + echo "name=Salt Repo for Salt v3007 STS" >> "${YUM_REPO_FILE}" + echo "baseurl=https://packages.broadcom.com/artifactory/saltproject-rpm/" >> "${YUM_REPO_FILE}" + echo "skip_if_unavailable=True" >> "${YUM_REPO_FILE}" + echo "priority=10" >> "${YUM_REPO_FILE}" + echo "enabled=1" >> "${YUM_REPO_FILE}" + echo "enabled_metadata=1" >> "${YUM_REPO_FILE}" + echo "gpgcheck=1" >> "${YUM_REPO_FILE}" + echo "exclude=*3006* *3008* *3009* *3010*" >> "${YUM_REPO_FILE}" + echo "gpgkey=https://packages.broadcom.com/artifactory/api/security/keypair/SaltProjectKey/public" >> "${YUM_REPO_FILE}" + else + # Salt 3006 repo + echo "[salt-repo-3006-lts]" > "${YUM_REPO_FILE}" + echo "name=Salt Repo for Salt v3006 LTS" >> "${YUM_REPO_FILE}" + echo "baseurl=https://packages.broadcom.com/artifactory/saltproject-rpm/" >> "${YUM_REPO_FILE}" + echo "skip_if_unavailable=True" >> "${YUM_REPO_FILE}" + echo "priority=10" >> "${YUM_REPO_FILE}" + echo "enabled=1" >> "${YUM_REPO_FILE}" + echo "enabled_metadata=1" >> "${YUM_REPO_FILE}" + echo "gpgcheck=1" >> "${YUM_REPO_FILE}" + echo "exclude=*3007* *3008* *3009* *3010*" >> "${YUM_REPO_FILE}" + echo "gpgkey=https://packages.broadcom.com/artifactory/api/security/keypair/SaltProjectKey/public" >> "${YUM_REPO_FILE}" + fi + else + # Enable the Salt LATEST repo + ## tdnf config-manager --set-disable salt-repo-* + ## tdnf config-manager --set-enabled salt-repo-latest + echo "[salt-repo-latest]" > "${YUM_REPO_FILE}" + echo "name=Salt Repo for Salt LATEST release" >> "${YUM_REPO_FILE}" + echo "baseurl=https://packages.broadcom.com/artifactory/saltproject-rpm/" >> "${YUM_REPO_FILE}" + echo "skip_if_unavailable=True" >> "${YUM_REPO_FILE}" + echo "priority=10" >> "${YUM_REPO_FILE}" + echo "enabled=1" >> "${YUM_REPO_FILE}" + echo "enabled_metadata=1" >> "${YUM_REPO_FILE}" + echo "gpgcheck=1" >> "${YUM_REPO_FILE}" + echo "gpgkey=https://packages.broadcom.com/artifactory/api/security/keypair/SaltProjectKey/public" >> "${YUM_REPO_FILE}" fi - - __fetch_url "${REPO_FILE}" "${FETCH_URL}.repo" - - GPG_KEY="SALT-PROJECT-GPG-PUBKEY-2023.pub" - - __rpm_import_gpg "${FETCH_URL}/${GPG_KEY}" || return 1 - tdnf makecache || return 1 - elif [ "$REPO_REV" != "latest" ]; then + elif [ "$ONEDIR_REV" != "latest" ]; then echowarn "salt.repo already exists, ignoring salt version argument." - echowarn "Use -F (forced overwrite) to install $REPO_REV." + echowarn "Use -F (forced overwrite) to install $ONEDIR_REV." fi return 0 } install_photon_deps() { + echodebug "install_photon_deps() entry" + + if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -ne 3 ]; then + echoerror "Python version is no longer supported, only Python 3" + return 1 + fi + if [ "$_UPGRADE_SYS" -eq $BS_TRUE ]; then tdnf -y update || return 1 fi __PACKAGES="${__PACKAGES:=}" - if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -lt 3 ]; then - echoerror "There are no Python 2 stable packages for Fedora, only Py3 packages" - return 1 - fi - PY_PKG_VER=3 __PACKAGES="${__PACKAGES} libyaml procps-ng python${PY_PKG_VER}-crypto python${PY_PKG_VER}-jinja2" __PACKAGES="${__PACKAGES} python${PY_PKG_VER}-msgpack python${PY_PKG_VER}-requests python${PY_PKG_VER}-zmq" __PACKAGES="${__PACKAGES} python${PY_PKG_VER}-pip python${PY_PKG_VER}-m2crypto python${PY_PKG_VER}-pyyaml" __PACKAGES="${__PACKAGES} python${PY_PKG_VER}-systemd" + if [ "${_EXTRA_PACKAGES}" != "" ]; then echoinfo "Installing the following extra packages as requested: ${_EXTRA_PACKAGES}" fi @@ -6990,6 +6122,8 @@ install_photon_deps() { } install_photon_stable_post() { + echodebug "install_photon_stable_post() entry" + for fname in api master minion syndic; do # Skip salt-api since the service should be opt-in and not necessarily started on boot [ $fname = "api" ] && continue @@ -7006,17 +6140,21 @@ install_photon_stable_post() { } install_photon_git_deps() { - if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -eq 3 ]; then - # Packages are named python3- - PY_PKG_VER=3 - else - PY_PKG_VER=2 + echodebug "install_photon_git_deps() entry" + + if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -ne 3 ]; then + echoerror "Python version is no longer supported, only Python 3" + return 1 fi + # Packages are named python3- + PY_PKG_VER=3 + __PACKAGES="" if ! __check_command_exists ps; then __PACKAGES="${__PACKAGES} procps-ng" fi + if ! __check_command_exists git; then __PACKAGES="${__PACKAGES} git" fi @@ -7029,55 +6167,28 @@ install_photon_git_deps() { __git_clone_and_checkout || return 1 - if [ "${_POST_NEON_INSTALL}" -eq $BS_FALSE ]; then + __PACKAGES="python${PY_PKG_VER}-devel python${PY_PKG_VER}-pip python${PY_PKG_VER}-setuptools gcc glibc-devel linux-devel.x86_64 cython${PY_PKG_VER}" - if [ "$_INSECURE_DL" -eq $BS_FALSE ] && [ "${_SALT_REPO_URL%%://*}" = "https" ]; then - __PACKAGES="${__PACKAGES} ca-certificates" - fi - if [ "$_INSTALL_CLOUD" -eq $BS_TRUE ]; then - __PACKAGES="${__PACKAGES} python${PY_PKG_VER}-libcloud python${PY_PKG_VER}-netaddr" - fi + echodebug "install_photon_git_deps() distro major version, ${DISTRO_MAJOR_VERSION}" - install_photon_deps || return 1 - - if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -eq 3 ]; then - if __check_command_exists python3; then - __python="python3" - fi - elif [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -eq 2 ]; then - if __check_command_exists python2; then - __python="python2" - fi - else - if ! __check_command_exists python; then - echoerror "Unable to find a python binary?!" - return 1 - fi - # Let's hope it's the right one - __python="python" - fi - - grep tornado "${_SALT_GIT_CHECKOUT_DIR}/requirements/base.txt" | while IFS=' - ' read -r dep; do - echodebug "Running '${__python}' -m pip install '${dep}'" - "${__python}" -m pip install "${dep}" || return 1 - done - else - __PACKAGES="python${PY_PKG_VER}-devel python${PY_PKG_VER}-pip python${PY_PKG_VER}-setuptools gcc glibc-devel linux-devel.x86_64" - # shellcheck disable=SC2086 - __tdnf_install_noinput ${__PACKAGES} || return 1 + ## Photon 5 container is missing systemd on default installation + if [ "${DISTRO_MAJOR_VERSION}" -lt 5 ]; then + __PACKAGES="${__PACKAGES} python${PY_PKG_VER}-tornado" fi + # shellcheck disable=SC2086 + __tdnf_install_noinput ${__PACKAGES} || return 1 + if [ "${DISTRO_MAJOR_VERSION}" -gt 3 ]; then # Need newer version of setuptools on Photon - _setuptools_dep="setuptools>=${_MINIMUM_SETUPTOOLS_VERSION}" - echodebug "Running '${_PY_EXE} -m pip --upgrade install ${_setuptools_dep}'" + _setuptools_dep="setuptools>=${_MINIMUM_SETUPTOOLS_VERSION},<${_MAXIMUM_SETUPTOOLS_VERSION}" + echodebug "Running '${_PY_EXE} -m pip install --upgrade ${_setuptools_dep}'" ${_PY_EXE} -m pip install --upgrade "${_setuptools_dep}" fi # Let's trigger config_salt() if [ "$_TEMP_CONFIG_DIR" = "null" ]; then - _TEMP_CONFIG_DIR="${_SALT_GIT_CHECKOUT_DIR}/conf/" + _TEMP_CONFIG_DIR="${_SALT_GIT_CHECKOUT_DIR}/conf" CONFIG_SALT_FUNC="config_salt" fi @@ -7085,11 +6196,14 @@ install_photon_git_deps() { } install_photon_git() { + echodebug "install_photon_git() entry" + if [ "${_PY_EXE}" != "" ]; then _PYEXE=${_PY_EXE} echoinfo "Using the following python version: ${_PY_EXE} to install salt" else - _PYEXE='python2' + echoerror "Python 2 is no longer supported, only Python 3" + return 1 fi if [ -f "${_SALT_GIT_CHECKOUT_DIR}/salt/syspaths.py" ]; then @@ -7101,6 +6215,8 @@ install_photon_git() { } install_photon_git_post() { + echodebug "install_photon_git_post() entry" + for fname in api master minion syndic; do # Skip if not meant to be installed [ $fname = "api" ] && \ @@ -7132,7 +6248,9 @@ install_photon_git_post() { } install_photon_restart_daemons() { - [ $_START_DAEMONS -eq $BS_FALSE ] && return + [ "$_START_DAEMONS" -eq $BS_FALSE ] && return + echodebug "install_photon_restart_daemons() entry" + for fname in api master minion syndic; do # Skip salt-api since the service should be opt-in and not necessarily started on boot @@ -7154,6 +6272,8 @@ install_photon_restart_daemons() { } install_photon_check_services() { + echodebug "install_photon_check_services() entry" + for fname in api master minion syndic; do # Skip salt-api since the service should be opt-in and not necessarily started on boot [ $fname = "api" ] && continue @@ -7170,6 +6290,8 @@ install_photon_check_services() { } install_photon_onedir_deps() { + echodebug "install_photon_onedir_deps() entry" + if [ "$_UPGRADE_SYS" -eq $BS_TRUE ]; then tdnf -y update || return 1 @@ -7186,8 +6308,8 @@ install_photon_onedir_deps() { fi # If -R was passed, we need to configure custom repo url with rsync-ed packages - # Which is still handled in __install_saltstack_rhel_repository. This call has - # its own check in case -r was passed without -R. + # Which was handled in __install_saltstack_rhel_repository buu that hanlded old-stable which is for + # releases which are End-Of-Life. This call has its own check in case -r was passed without -R. if [ "$_CUSTOM_REPO_URL" != "null" ]; then __install_saltstack_photon_onedir_repository || return 1 fi @@ -7209,6 +6331,8 @@ install_photon_onedir_deps() { install_photon_onedir() { + echodebug "install_photon_onedir() entry" + STABLE_REV=$ONEDIR_REV __PACKAGES="" @@ -7226,6 +6350,10 @@ install_photon_onedir() { __PACKAGES="${__PACKAGES} salt-syndic" fi + if [ "$_INSTALL_SALT_API" -eq $BS_TRUE ]; then + __PACKAGES="${__PACKAGES} salt-api" + fi + # shellcheck disable=SC2086 __tdnf_install_noinput ${__PACKAGES} || return 1 @@ -7243,526 +6371,6 @@ install_photon_onedir_post() { # ####################################################################################################################### -####################################################################################################################### -# -# FreeBSD Install Functions -# - -# Using a separate conf step to head for idempotent install... -__configure_freebsd_pkg_details() { - _SALT_ETC_DIR="/usr/local/etc/salt" - _PKI_DIR=${_SALT_ETC_DIR}/pki - _POST_NEON_PIP_INSTALL_ARGS="--prefix=/usr/local" -} - -install_freebsd_deps() { - __configure_freebsd_pkg_details - pkg install -y pkg -} - -install_freebsd_git_deps() { - install_freebsd_deps || return 1 - - if ! __check_command_exists git; then - /usr/local/sbin/pkg install -y git || return 1 - fi - __git_clone_and_checkout || return 1 - - if [ "${_POST_NEON_INSTALL}" -eq $BS_FALSE ]; then - - SALT_DEPENDENCIES=$(/usr/local/sbin/pkg rquery %dn py39-salt) - # shellcheck disable=SC2086 - /usr/local/sbin/pkg install -y ${SALT_DEPENDENCIES} python || return 1 - - /usr/local/sbin/pkg install -y py39-requests || return 1 - /usr/local/sbin/pkg install -y py39-tornado4 || return 1 - - else - /usr/local/sbin/pkg install -y python py39-pip py39-setuptools libzmq4 libunwind || return 1 - fi - - echodebug "Adapting paths to FreeBSD" - # The list of files was taken from Salt's BSD port Makefile - for file in doc/man/salt-key.1 doc/man/salt-cp.1 doc/man/salt-minion.1 \ - doc/man/salt-syndic.1 doc/man/salt-master.1 doc/man/salt-run.1 \ - doc/man/salt.7 doc/man/salt.1 doc/man/salt-call.1; do - [ ! -f $file ] && continue - echodebug "Patching ${file}" - sed -in -e "s|/etc/salt|${_SALT_ETC_DIR}|" \ - -e "s|/srv/salt|${_SALT_ETC_DIR}/states|" \ - -e "s|/srv/pillar|${_SALT_ETC_DIR}/pillar|" ${file} - done - if [ ! -f salt/syspaths.py ]; then - # We still can't provide the system paths, salt 0.16.x - # Let's patch salt's source and adapt paths to what's expected on FreeBSD - echodebug "Replacing occurrences of '/etc/salt' with ${_SALT_ETC_DIR}" - # The list of files was taken from Salt's BSD port Makefile - for file in conf/minion conf/master salt/config.py salt/client.py \ - salt/modules/mysql.py salt/utils/parsers.py salt/modules/tls.py \ - salt/modules/postgres.py salt/utils/migrations.py; do - [ ! -f $file ] && continue - echodebug "Patching ${file}" - sed -in -e "s|/etc/salt|${_SALT_ETC_DIR}|" \ - -e "s|/srv/salt|${_SALT_ETC_DIR}/states|" \ - -e "s|/srv/pillar|${_SALT_ETC_DIR}/pillar|" ${file} - done - fi - echodebug "Finished patching" - - # Let's trigger config_salt() - if [ "$_TEMP_CONFIG_DIR" = "null" ]; then - _TEMP_CONFIG_DIR="${_SALT_GIT_CHECKOUT_DIR}/conf/" - CONFIG_SALT_FUNC="config_salt" - - fi - - return 0 -} - -install_freebsd_stable() { -# -# installing latest version of salt from FreeBSD CURRENT ports repo -# - # shellcheck disable=SC2086 - /usr/local/sbin/pkg install -y py39-salt || return 1 - - return 0 -} - -install_freebsd_git() { - - # /usr/local/bin/python3 in FreeBSD is a symlink to /usr/local/bin/python3.7 - __PYTHON_PATH=$(readlink -f "$(command -v python3)") - __ESCAPED_PYTHON_PATH=$(echo "${__PYTHON_PATH}" | sed 's/\//\\\//g') - - if [ "${_POST_NEON_INSTALL}" -eq $BS_TRUE ]; then - __install_salt_from_repo_post_neon "${__PYTHON_PATH}" || return 1 - for script in salt_api salt_master salt_minion salt_proxy salt_syndic; do - __fetch_url "/usr/local/etc/rc.d/${script}" "https://raw.githubusercontent.com/freebsd/freebsd-ports/master/sysutils/py-salt/files/${script}.in" || return 1 - sed -i '' 's/%%PREFIX%%/\/usr\/local/g' /usr/local/etc/rc.d/${script} - sed -i '' "s/%%PYTHON_CMD%%/${__ESCAPED_PYTHON_PATH}/g" /usr/local/etc/rc.d/${script} - chmod +x /usr/local/etc/rc.d/${script} || return 1 - done - - return 0 - fi - - # Install from git - if [ ! -f salt/syspaths.py ]; then - # We still can't provide the system paths, salt 0.16.x - ${__PYTHON_PATH} setup.py ${SETUP_PY_INSTALL_ARGS} install || return 1 - else - ${__PYTHON_PATH} setup.py \ - --salt-root-dir=/ \ - --salt-config-dir="${_SALT_ETC_DIR}" \ - --salt-cache-dir="${_SALT_CACHE_DIR}" \ - --salt-sock-dir=/var/run/salt \ - --salt-srv-root-dir="${_SALT_ETC_DIR}" \ - --salt-base-file-roots-dir="${_SALT_ETC_DIR}/states" \ - --salt-base-pillar-roots-dir="${_SALT_ETC_DIR}/pillar" \ - --salt-base-master-roots-dir="${_SALT_ETC_DIR}/salt-master" \ - --salt-logs-dir=/var/log/salt \ - --salt-pidfile-dir=/var/run \ - ${SETUP_PY_INSTALL_ARGS} install \ - || return 1 - fi - - for script in salt_api salt_master salt_minion salt_proxy salt_syndic; do - __fetch_url "/usr/local/etc/rc.d/${script}" "https://raw.githubusercontent.com/freebsd/freebsd-ports/master/sysutils/py-salt/files/${script}.in" || return 1 - sed -i '' 's/%%PREFIX%%/\/usr\/local/g' /usr/local/etc/rc.d/${script} - sed -i '' "s/%%PYTHON_CMD%%/${__ESCAPED_PYTHON_PATH}/g" /usr/local/etc/rc.d/${script} - chmod +x /usr/local/etc/rc.d/${script} || return 1 - done - - # And we're good to go - return 0 -} - -install_freebsd_stable_post() { - for fname in api master minion syndic; do - # Skip salt-api since the service should be opt-in and not necessarily started on boot - [ $fname = "api" ] && continue - - # Skip if not meant to be installed - [ $fname = "minion" ] && [ "$_INSTALL_MINION" -eq $BS_FALSE ] && continue - [ $fname = "master" ] && [ "$_INSTALL_MASTER" -eq $BS_FALSE ] && continue - [ $fname = "syndic" ] && [ "$_INSTALL_SYNDIC" -eq $BS_FALSE ] && continue - - enable_string="salt_${fname}_enable=YES" - grep "$enable_string" /etc/rc.conf >/dev/null 2>&1 - [ $? -eq 1 ] && sysrc $enable_string - - done -} - -install_freebsd_git_post() { - install_freebsd_stable_post || return 1 - return 0 -} - -install_freebsd_restart_daemons() { - [ $_START_DAEMONS -eq $BS_FALSE ] && return - - for fname in api master minion syndic; do - # Skip salt-api since the service should be opt-in and not necessarily started on boot - [ $fname = "api" ] && continue - - # Skip if not meant to be installed - [ $fname = "master" ] && [ "$_INSTALL_MASTER" -eq $BS_FALSE ] && continue - [ $fname = "minion" ] && [ "$_INSTALL_MINION" -eq $BS_FALSE ] && continue - [ $fname = "syndic" ] && [ "$_INSTALL_SYNDIC" -eq $BS_FALSE ] && continue - - service salt_$fname stop > /dev/null 2>&1 - service salt_$fname start - done -} - -install_freebsd_onedir() { -# -# call install_freebsd_stable -# - install_freebsd_stable || return 1 - - return 0 -} -# -# Ended FreeBSD Install Functions -# -####################################################################################################################### - -####################################################################################################################### -# -# OpenBSD Install Functions -# - -install_openbsd_deps() { - if [ $_DISABLE_REPOS -eq $BS_FALSE ]; then - OPENBSD_REPO='https://cdn.openbsd.org/pub/OpenBSD' - echoinfo "setting package repository to $OPENBSD_REPO" - echo "${OPENBSD_REPO}" >/etc/installurl || return 1 - fi - - if [ "${_EXTRA_PACKAGES}" != "" ]; then - echoinfo "Installing the following extra packages as requested: ${_EXTRA_PACKAGES}" - # shellcheck disable=SC2086 - pkg_add -I -v ${_EXTRA_PACKAGES} || return 1 - fi - return 0 -} - -install_openbsd_git_deps() { - install_openbsd_deps || return 1 - - if ! __check_command_exists git; then - pkg_add -I -v git || return 1 - fi - __git_clone_and_checkout || return 1 - - if [ "${_POST_NEON_INSTALL}" -eq $BS_TRUE ]; then - pkg_add -I -v py3-pip py3-setuptools - fi - - # - # Let's trigger config_salt() - # - if [ "$_TEMP_CONFIG_DIR" = "null" ]; then - _TEMP_CONFIG_DIR="${_SALT_GIT_CHECKOUT_DIR}/conf/" - CONFIG_SALT_FUNC="config_salt" - fi - - return 0 -} - -install_openbsd_git() { - # - # Install from git - # - if [ "${_POST_NEON_INSTALL}" -eq $BS_TRUE ]; then - __install_salt_from_repo_post_neon "${_PY_EXE}" || return 1 - return 0 - fi - - if [ ! -f salt/syspaths.py ]; then - # We still can't provide the system paths, salt 0.16.x - /usr/local/bin/python2.7 setup.py ${SETUP_PY_INSTALL_ARGS} install || return 1 - fi - return 0 -} - -install_openbsd_stable() { - pkg_add -r -I -v salt || return 1 - return 0 -} - -install_openbsd_post() { - for fname in api master minion syndic; do - [ $fname = "api" ] && continue - [ $fname = "minion" ] && [ "$_INSTALL_MINION" -eq $BS_FALSE ] && continue - [ $fname = "master" ] && [ "$_INSTALL_MASTER" -eq $BS_FALSE ] && continue - [ $fname = "syndic" ] && [ "$_INSTALL_SYNDIC" -eq $BS_FALSE ] && continue - - rcctl enable salt_$fname - done - - return 0 -} - -install_openbsd_check_services() { - for fname in api master minion syndic; do - # Skip salt-api since the service should be opt-in and not necessarily started on boot - [ $fname = "api" ] && continue - - # Skip if not meant to be installed - [ $fname = "master" ] && [ "$_INSTALL_MASTER" -eq $BS_FALSE ] && continue - [ $fname = "minion" ] && [ "$_INSTALL_MINION" -eq $BS_FALSE ] && continue - [ $fname = "syndic" ] && continue - - if [ -f /etc/rc.d/salt_${fname} ]; then - __check_services_openbsd salt_${fname} || return 1 - fi - done - - return 0 -} - -install_openbsd_restart_daemons() { - [ $_START_DAEMONS -eq $BS_FALSE ] && return - - for fname in api master minion syndic; do - # Skip salt-api since the service should be opt-in and not necessarily started on boot - [ $fname = "api" ] && continue - - # Skip if not meant to be installed - [ $fname = "master" ] && [ "$_INSTALL_MASTER" -eq $BS_FALSE ] && continue - [ $fname = "minion" ] && [ "$_INSTALL_MINION" -eq $BS_FALSE ] && continue - [ $fname = "syndic" ] && [ "$_INSTALL_SYNDIC" -eq $BS_FALSE ] && continue - - rcctl restart salt_${fname} - done - - return 0 -} - -install_openbsd_onedir() { -# -# Call install_openbsd_stable -# - install_openbsd_stable || return 1 - - return 0 -} -# -# Ended OpenBSD Install Functions -# -####################################################################################################################### - -####################################################################################################################### -# -# SmartOS Install Functions -# -install_smartos_deps() { - smartos_deps="$(pkgin show-deps salt | grep '^\s' | grep -v '\snot' | xargs) py27-m2crypto" - pkgin -y install "${smartos_deps}" || return 1 - - # Set _SALT_ETC_DIR to SmartOS default if they didn't specify - _SALT_ETC_DIR=${BS_SALT_ETC_DIR:-/opt/local/etc/salt} - # We also need to redefine the PKI directory - _PKI_DIR=${_SALT_ETC_DIR}/pki - - # Let's trigger config_salt() - if [ "$_TEMP_CONFIG_DIR" = "null" ]; then - # Let's set the configuration directory to /tmp - _TEMP_CONFIG_DIR="/tmp" - CONFIG_SALT_FUNC="config_salt" - - # Let's download, since they were not provided, the default configuration files - if [ ! -f "$_SALT_ETC_DIR/minion" ] && [ ! -f "$_TEMP_CONFIG_DIR/minion" ]; then - # shellcheck disable=SC2086 - curl $_CURL_ARGS -s -o "$_TEMP_CONFIG_DIR/minion" -L \ - https://raw.githubusercontent.com/saltstack/salt/master/conf/minion || return 1 - fi - if [ ! -f "$_SALT_ETC_DIR/master" ] && [ ! -f $_TEMP_CONFIG_DIR/master ]; then - # shellcheck disable=SC2086 - curl $_CURL_ARGS -s -o "$_TEMP_CONFIG_DIR/master" -L \ - https://raw.githubusercontent.com/saltstack/salt/master/conf/master || return 1 - fi - fi - - if [ "$_INSTALL_CLOUD" -eq $BS_TRUE ]; then - pkgin -y install py27-apache-libcloud || return 1 - fi - - if [ "${_EXTRA_PACKAGES}" != "" ]; then - echoinfo "Installing the following extra packages as requested: ${_EXTRA_PACKAGES}" - # shellcheck disable=SC2086 - pkgin -y install ${_EXTRA_PACKAGES} || return 1 - fi - - return 0 -} - -install_smartos_git_deps() { - install_smartos_deps || return 1 - - if ! __check_command_exists git; then - pkgin -y install git || return 1 - fi - - __git_clone_and_checkout || return 1 - - if [ "${_POST_NEON_INSTALL}" -eq $BS_FALSE ]; then - - if [ -f "${_SALT_GIT_CHECKOUT_DIR}/requirements/base.txt" ]; then - # Install whichever tornado is in the requirements file - __REQUIRED_TORNADO="$(grep tornado "${_SALT_GIT_CHECKOUT_DIR}/requirements/base.txt")" - __check_pip_allowed "You need to allow pip based installations (-P) in order to install the python package '${__REQUIRED_TORNADO}'" - - # Install whichever futures is in the requirements file - __REQUIRED_FUTURES="$(grep futures "${_SALT_GIT_CHECKOUT_DIR}/requirements/base.txt")" - __check_pip_allowed "You need to allow pip based installations (-P) in order to install the python package '${__REQUIRED_FUTURES}'" - - if [ "${__REQUIRED_TORNADO}" != "" ]; then - if ! __check_command_exists pip; then - pkgin -y install py27-pip - fi - pip install -U "${__REQUIRED_TORNADO}" - fi - - if [ "${__REQUIRED_FUTURES}" != "" ]; then - if ! __check_command_exists pip; then - pkgin -y install py27-pip - fi - pip install -U "${__REQUIRED_FUTURES}" - fi - fi - else - if ! __check_command_exists pip; then - pkgin -y install py27-pip - fi - pkgin -y install py27-setuptools - fi - - # Let's trigger config_salt() - if [ "$_TEMP_CONFIG_DIR" = "null" ]; then - _TEMP_CONFIG_DIR="${_SALT_GIT_CHECKOUT_DIR}/conf/" - CONFIG_SALT_FUNC="config_salt" - fi - - return 0 -} - -install_smartos_stable() { - pkgin -y install salt || return 1 - return 0 -} - -install_smartos_git() { - - if [ "${_POST_NEON_INSTALL}" -eq $BS_TRUE ]; then - __install_salt_from_repo_post_neon "${_PY_EXE}" || return 1 - return 0 - fi - - # Use setuptools in order to also install dependencies - # lets force our config path on the setup for now, since salt/syspaths.py only got fixed in 2015.5.0 - USE_SETUPTOOLS=1 /opt/local/bin/python setup.py --salt-config-dir="$_SALT_ETC_DIR" --salt-cache-dir="${_SALT_CACHE_DIR}" ${SETUP_PY_INSTALL_ARGS} install || return 1 - return 0 -} - -install_smartos_post() { - smf_dir="/opt/custom/smf" - - # Install manifest files if needed. - for fname in api master minion syndic; do - # Skip if not meant to be installed - [ $fname = "api" ] && \ - ([ "$_INSTALL_MASTER" -eq $BS_FALSE ] || ! __check_command_exists "salt-${fname}") && continue - [ $fname = "master" ] && [ "$_INSTALL_MASTER" -eq $BS_FALSE ] && continue - [ $fname = "minion" ] && [ "$_INSTALL_MINION" -eq $BS_FALSE ] && continue - [ $fname = "syndic" ] && [ "$_INSTALL_SYNDIC" -eq $BS_FALSE ] && continue - - svcs network/salt-$fname > /dev/null 2>&1 - if [ $? -eq 1 ]; then - if [ ! -f "$_TEMP_CONFIG_DIR/salt-$fname.xml" ]; then - # shellcheck disable=SC2086 - curl $_CURL_ARGS -s -o "$_TEMP_CONFIG_DIR/salt-$fname.xml" -L \ - "https://raw.githubusercontent.com/saltstack/salt/master/pkg/smartos/salt-$fname.xml" - fi - svccfg import "$_TEMP_CONFIG_DIR/salt-$fname.xml" - if [ "${VIRTUAL_TYPE}" = "global" ]; then - if [ ! -d "$smf_dir" ]; then - mkdir -p "$smf_dir" || return 1 - fi - if [ ! -f "$smf_dir/salt-$fname.xml" ]; then - __copyfile "$_TEMP_CONFIG_DIR/salt-$fname.xml" "$smf_dir/" || return 1 - fi - fi - fi - done - - return 0 -} - -install_smartos_git_post() { - smf_dir="/opt/custom/smf" - - # Install manifest files if needed. - for fname in api master minion syndic; do - # Skip if not meant to be installed - [ $fname = "api" ] && \ - ([ "$_INSTALL_MASTER" -eq $BS_FALSE ] || ! __check_command_exists "salt-${fname}") && continue - [ $fname = "master" ] && [ "$_INSTALL_MASTER" -eq $BS_FALSE ] && continue - [ $fname = "minion" ] && [ "$_INSTALL_MINION" -eq $BS_FALSE ] && continue - [ $fname = "syndic" ] && [ "$_INSTALL_SYNDIC" -eq $BS_FALSE ] && continue - - svcs "network/salt-$fname" > /dev/null 2>&1 - if [ $? -eq 1 ]; then - svccfg import "${_SALT_GIT_CHECKOUT_DIR}/pkg/smartos/salt-$fname.xml" - if [ "${VIRTUAL_TYPE}" = "global" ]; then - if [ ! -d $smf_dir ]; then - mkdir -p "$smf_dir" - fi - if [ ! -f "$smf_dir/salt-$fname.xml" ]; then - __copyfile "${_SALT_GIT_CHECKOUT_DIR}/pkg/smartos/salt-$fname.xml" "$smf_dir/" - fi - fi - fi - done - - return 0 -} - -install_smartos_restart_daemons() { - [ $_START_DAEMONS -eq $BS_FALSE ] && return - - for fname in api master minion syndic; do - # Skip salt-api since the service should be opt-in and not necessarily started on boot - [ $fname = "api" ] && continue - - # Skip if not meant to be installed - [ $fname = "master" ] && [ "$_INSTALL_MASTER" -eq $BS_FALSE ] && continue - [ $fname = "minion" ] && [ "$_INSTALL_MINION" -eq $BS_FALSE ] && continue - [ $fname = "syndic" ] && [ "$_INSTALL_SYNDIC" -eq $BS_FALSE ] && continue - - # Stop if running && Start service - svcadm disable salt-$fname > /dev/null 2>&1 - svcadm enable salt-$fname - done - - return 0 -} -install_smartos_onedir() { -# -# call install_smartos_stable -# - install_smartos_stable || return 1 - - return 0 -} -# -# Ended SmartOS Install Functions -# -####################################################################################################################### ####################################################################################################################### # @@ -7844,7 +6452,7 @@ __zypper_install() { __opensuse_prep_install() { # DRY function for common installation preparatory steps for SUSE - if [ $_DISABLE_REPOS -eq $BS_FALSE ]; then + if [ "$_DISABLE_REPOS" -eq $BS_FALSE ]; then # Is the repository already known __set_suse_pkg_repo # Check zypper repos and refresh if necessary @@ -7876,7 +6484,7 @@ install_opensuse_stable_deps() { # YAML module is used for generating custom master/minion configs # requests is still used by many salt modules # Salt needs python-zypp installed in order to use the zypper module - __PACKAGES="python-PyYAML python-requests python-zypp" + __PACKAGES="python${PY_PKG_VER}-PyYAML python${PY_PKG_VER}-requests python${PY_PKG_VER}-zypp" # shellcheck disable=SC2086 __zypper_install ${__PACKAGES} || return 1 @@ -7903,27 +6511,11 @@ install_opensuse_git_deps() { __git_clone_and_checkout || return 1 - if [ "${_POST_NEON_INSTALL}" -eq $BS_FALSE ]; then - __zypper_install patch || return 1 - - __PACKAGES="libzmq5 python-Jinja2 python-m2crypto python-msgpack-python python-pycrypto python-pyzmq python-xml python-futures" - - if [ -f "${_SALT_GIT_CHECKOUT_DIR}/requirements/base.txt" ]; then - # We're on the master branch, install whichever tornado is on the requirements file - __REQUIRED_TORNADO="$(grep tornado "${_SALT_GIT_CHECKOUT_DIR}/requirements/base.txt")" - if [ "${__REQUIRED_TORNADO}" != "" ]; then - __PACKAGES="${__PACKAGES} python-tornado" - fi - fi - - if [ "$_INSTALL_CLOUD" -eq $BS_TRUE ]; then - __PACKAGES="${__PACKAGES} python-apache-libcloud" - fi # Check for Tumbleweed - elif [ "${DISTRO_MAJOR_VERSION}" -ge 20210101 ]; then + if [ "${DISTRO_MAJOR_VERSION}" -ge 20210101 ]; then __PACKAGES="python3-pip gcc-c++ python3-pyzmq-devel" else - __PACKAGES="python-pip python-setuptools gcc" + __PACKAGES="python3-pip python3-setuptools gcc" fi # shellcheck disable=SC2086 @@ -7931,7 +6523,7 @@ install_opensuse_git_deps() { # Let's trigger config_salt() if [ "$_TEMP_CONFIG_DIR" = "null" ]; then - _TEMP_CONFIG_DIR="${_SALT_GIT_CHECKOUT_DIR}/conf/" + _TEMP_CONFIG_DIR="${_SALT_GIT_CHECKOUT_DIR}/conf" CONFIG_SALT_FUNC="config_salt" fi @@ -7958,6 +6550,10 @@ install_opensuse_stable() { __PACKAGES="${__PACKAGES} salt-syndic" fi + if [ "$_INSTALL_SALT_API" -eq $BS_TRUE ]; then + __PACKAGES="${__PACKAGES} salt-api" + fi + # shellcheck disable=SC2086 __zypper_install $__PACKAGES || return 1 @@ -7965,12 +6561,7 @@ install_opensuse_stable() { } install_opensuse_git() { - if [ "${_POST_NEON_INSTALL}" -eq $BS_TRUE ]; then - __install_salt_from_repo_post_neon "${_PY_EXE}" || return 1 - return 0 - fi - - python setup.py ${SETUP_PY_INSTALL_ARGS} install --prefix=/usr || return 1 + __install_salt_from_repo "${_PY_EXE}" || return 1 return 0 } @@ -7988,7 +6579,7 @@ install_opensuse_stable_post() { [ $fname = "minion" ] && [ "$_INSTALL_MINION" -eq $BS_FALSE ] && continue [ $fname = "syndic" ] && [ "$_INSTALL_SYNDIC" -eq $BS_FALSE ] && continue - if [ -f /bin/systemctl ] || [ -f /usr/bin/systemctl ]; then + if [ "$_SYSTEMD_FUNCTIONAL" -eq $BS_TRUE ]; then systemctl is-enabled salt-$fname.service || (systemctl preset salt-$fname.service && systemctl enable salt-$fname.service) sleep 1 systemctl daemon-reload @@ -8011,7 +6602,7 @@ install_opensuse_git_post() { [ $fname = "minion" ] && [ "$_INSTALL_MINION" -eq $BS_FALSE ] && continue [ $fname = "syndic" ] && [ "$_INSTALL_SYNDIC" -eq $BS_FALSE ] && continue - if command -v systemctl; then + if [ "$_SYSTEMD_FUNCTIONAL" -eq $BS_TRUE ]; then use_usr_lib=$BS_FALSE if [ "${DISTRO_MAJOR_VERSION}" -ge 15 ]; then @@ -8052,7 +6643,7 @@ install_opensuse_onedir_post() { } install_opensuse_restart_daemons() { - [ $_START_DAEMONS -eq $BS_FALSE ] && return + [ "$_START_DAEMONS" -eq $BS_FALSE ] && return for fname in api master minion syndic; do # Skip salt-api since the service should be opt-in and not necessarily started on boot @@ -8063,7 +6654,7 @@ install_opensuse_restart_daemons() { [ $fname = "minion" ] && [ "$_INSTALL_MINION" -eq $BS_FALSE ] && continue [ $fname = "syndic" ] && [ "$_INSTALL_SYNDIC" -eq $BS_FALSE ] && continue - if [ -f /bin/systemctl ]; then + if [ "$_SYSTEMD_FUNCTIONAL" -eq $BS_TRUE ]; then systemctl stop salt-$fname > /dev/null 2>&1 systemctl start salt-$fname.service && continue echodebug "Failed to start salt-$fname using systemd" @@ -8079,7 +6670,7 @@ install_opensuse_restart_daemons() { } install_opensuse_check_services() { - if [ ! -f /bin/systemctl ]; then + if [ "$_SYSTEMD_FUNCTIONAL" -eq $BS_TRUE ]; then # Not running systemd!? Don't check! return 0 fi @@ -8113,11 +6704,10 @@ install_opensuse_15_stable_deps() { # SUSE only packages Salt for Python 3 on Leap 15 # Py3 is the default bootstrap install for Leap 15 - # However, git installs might specify "-x python2" - if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -eq 2 ]; then - PY_PKG_VER=2 - else - PY_PKG_VER=3 + # However, git installs that specify "-x python2" are disallowed + if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -ne 3 ]; then + echoerror "Python version is no longer supported, only Python 3" + return 1 fi # YAML module is used for generating custom master/minion configs @@ -8145,47 +6735,20 @@ install_opensuse_15_git_deps() { __git_clone_and_checkout || return 1 - if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -eq 2 ]; then - PY_PKG_VER=2 - else - PY_PKG_VER=3 + if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -ne 3 ]; then + echoerror "Python version is no longer supported, only Python 3" + return 1 fi - __PACKAGES="python${PY_PKG_VER}-xml" - - if [ "${_POST_NEON_INSTALL}" -eq $BS_FALSE ]; then - - # Py3 is the default bootstrap install for Leap 15 - # However, git installs might specify "-x python2" - if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -eq 2 ]; then - # This is required by some of the python2 packages below - __PACKAGES="${__PACKAGES} libpython2_7-1_0 python2-futures python-ipaddress" - fi - - __PACKAGES="${__PACKAGES} libzmq5 python${PY_PKG_VER}-Jinja2 python${PY_PKG_VER}-msgpack" - __PACKAGES="${__PACKAGES} python${PY_PKG_VER}-pycrypto python${PY_PKG_VER}-pyzmq" - - if [ -f "${_SALT_GIT_CHECKOUT_DIR}/requirements/base.txt" ]; then - # We're on the master branch, install whichever tornado is on the requirements file - __REQUIRED_TORNADO="$(grep tornado "${_SALT_GIT_CHECKOUT_DIR}/requirements/base.txt")" - if [ "${__REQUIRED_TORNADO}" != "" ]; then - __PACKAGES="${__PACKAGES} python${PY_PKG_VER}-tornado" - fi - fi - - if [ "$_INSTALL_CLOUD" -eq $BS_TRUE ]; then - __PACKAGES="${__PACKAGES} python${PY_PKG_VER}-apache-libcloud" - fi - else - __PACKAGES="${__PACKAGES} python${PY_PKG_VER}-devel python${PY_PKG_VER}-pip python${PY_PKG_VER}-setuptools gcc" - fi + PY_PKG_VER=3 + __PACKAGES="python${PY_PKG_VER}-xml python${PY_PKG_VER}-devel python${PY_PKG_VER}-pip python${PY_PKG_VER}-setuptools gcc" # shellcheck disable=SC2086 __zypper_install ${__PACKAGES} || return 1 # Let's trigger config_salt() if [ "$_TEMP_CONFIG_DIR" = "null" ]; then - _TEMP_CONFIG_DIR="${_SALT_GIT_CHECKOUT_DIR}/conf/" + _TEMP_CONFIG_DIR="${_SALT_GIT_CHECKOUT_DIR}/conf" CONFIG_SALT_FUNC="config_salt" fi @@ -8196,17 +6759,12 @@ install_opensuse_15_git() { # Py3 is the default bootstrap install for Leap 15 if [ -n "$_PY_EXE" ]; then - _PYEXE=${_PY_EXE} + _PYEXE="${_PY_EXE}" else _PYEXE=python3 fi - if [ "${_POST_NEON_INSTALL}" -eq $BS_TRUE ]; then - __install_salt_from_repo_post_neon "${_PY_EXE}" || return 1 - return 0 - fi - - ${_PYEXE} setup.py ${SETUP_PY_INSTALL_ARGS} install --prefix=/usr || return 1 + __install_salt_from_repo "${_PY_EXE}" || return 1 return 0 } @@ -8291,266 +6849,6 @@ install_suse_15_restart_daemons() { # ####################################################################################################################### -####################################################################################################################### -# -# SUSE Enterprise 12 -# - -install_suse_12_stable_deps() { - __opensuse_prep_install || return 1 - - # YAML module is used for generating custom master/minion configs - # requests is still used by many salt modules - # Salt needs python-zypp installed in order to use the zypper module - __PACKAGES="python-PyYAML python-requests python-zypp" - - if [ "$_INSTALL_CLOUD" -eq $BS_TRUE ]; then - __PACKAGES="${__PACKAGES} python-apache-libcloud" - fi - - # shellcheck disable=SC2086,SC2090 - __zypper_install ${__PACKAGES} || return 1 - - # SLES 11 SP3 ships with both python-M2Crypto-0.22.* and python-m2crypto-0.21 and we will be asked which - # we want to install, even with --non-interactive. - # Let's try to install the higher version first and then the lower one in case of failure - __zypper_install 'python-M2Crypto>=0.22' || __zypper_install 'python-M2Crypto>=0.21' || return 1 - - if [ "${_EXTRA_PACKAGES}" != "" ]; then - echoinfo "Installing the following extra packages as requested: ${_EXTRA_PACKAGES}" - # shellcheck disable=SC2086 - __zypper_install ${_EXTRA_PACKAGES} || return 1 - fi - - return 0 -} - -install_suse_12_git_deps() { - install_suse_12_stable_deps || return 1 - - if ! __check_command_exists git; then - __zypper_install git-core || return 1 - fi - - __git_clone_and_checkout || return 1 - - __PACKAGES="" - # shellcheck disable=SC2089 - __PACKAGES="${__PACKAGES} libzmq4 python-Jinja2 python-msgpack-python python-pycrypto" - __PACKAGES="${__PACKAGES} python-pyzmq python-xml" - - if [ -f "${_SALT_GIT_CHECKOUT_DIR}/requirements/base.txt" ]; then - # We're on the master branch, install whichever tornado is on the requirements file - __REQUIRED_TORNADO="$(grep tornado "${_SALT_GIT_CHECKOUT_DIR}/requirements/base.txt")" - if [ "${__REQUIRED_TORNADO}" != "" ]; then - __PACKAGES="${__PACKAGES} python-tornado" - fi - fi - - if [ "$_INSTALL_CLOUD" -eq $BS_TRUE ]; then - __PACKAGES="${__PACKAGES} python-apache-libcloud" - fi - - # shellcheck disable=SC2086 - __zypper_install ${__PACKAGES} || return 1 - - # Let's trigger config_salt() - if [ "$_TEMP_CONFIG_DIR" = "null" ]; then - _TEMP_CONFIG_DIR="${_SALT_GIT_CHECKOUT_DIR}/conf/" - CONFIG_SALT_FUNC="config_salt" - fi - - return 0 -} - -install_suse_12_onedir_deps() { - install_suse_12_stable_deps || return 1 - return 0 -} - -install_suse_12_stable() { - install_opensuse_stable || return 1 - return 0 -} - -install_suse_12_git() { - install_opensuse_git || return 1 - return 0 -} - -install_suse_12_onedir() { - install_opensuse_stable || return 1 - return 0 -} - -install_suse_12_stable_post() { - install_opensuse_stable_post || return 1 - return 0 -} - -install_suse_12_git_post() { - install_opensuse_git_post || return 1 - return 0 -} - -install_suse_12_onedir_post() { - install_opensuse_stable_post || return 1 - return 0 -} - -install_suse_12_restart_daemons() { - install_opensuse_restart_daemons || return 1 - return 0 -} - -# -# End of SUSE Enterprise 12 -# -####################################################################################################################### - -####################################################################################################################### -# -# SUSE Enterprise 11 -# - -install_suse_11_stable_deps() { - __opensuse_prep_install || return 1 - - # YAML module is used for generating custom master/minion configs - __PACKAGES="python-PyYAML" - - # shellcheck disable=SC2086,SC2090 - __zypper_install ${__PACKAGES} || return 1 - - # SLES 11 SP3 ships with both python-M2Crypto-0.22.* and python-m2crypto-0.21 and we will be asked which - # we want to install, even with --non-interactive. - # Let's try to install the higher version first and then the lower one in case of failure - __zypper_install 'python-M2Crypto>=0.22' || __zypper_install 'python-M2Crypto>=0.21' || return 1 - - if [ "${_EXTRA_PACKAGES}" != "" ]; then - echoinfo "Installing the following extra packages as requested: ${_EXTRA_PACKAGES}" - # shellcheck disable=SC2086 - __zypper_install ${_EXTRA_PACKAGES} || return 1 - fi - - return 0 -} - -install_suse_11_git_deps() { - install_suse_11_stable_deps || return 1 - - if ! __check_command_exists git; then - __zypper_install git || return 1 - fi - - __git_clone_and_checkout || return 1 - - __PACKAGES="" - # shellcheck disable=SC2089 - __PACKAGES="${__PACKAGES} libzmq4 python-Jinja2 python-msgpack-python python-pycrypto" - __PACKAGES="${__PACKAGES} python-pyzmq python-xml python-zypp" - - if [ -f "${_SALT_GIT_CHECKOUT_DIR}/requirements/base.txt" ]; then - # We're on the master branch, install whichever tornado is on the requirements file - __REQUIRED_TORNADO="$(grep tornado "${_SALT_GIT_CHECKOUT_DIR}/requirements/base.txt")" - if [ "${__REQUIRED_TORNADO}" != "" ]; then - __PACKAGES="${__PACKAGES} python-tornado" - fi - fi - - if [ "$_INSTALL_CLOUD" -eq $BS_TRUE ]; then - __PACKAGES="${__PACKAGES} python-apache-libcloud" - fi - - # shellcheck disable=SC2086 - __zypper_install ${__PACKAGES} || return 1 - - # Let's trigger config_salt() - if [ "$_TEMP_CONFIG_DIR" = "null" ]; then - _TEMP_CONFIG_DIR="${_SALT_GIT_CHECKOUT_DIR}/conf/" - CONFIG_SALT_FUNC="config_salt" - fi - - return 0 -} - -install_suse_11_onedir_deps() { - install_suse_11_stable_deps || return 1 - return 0 -} - -install_suse_11_stable() { - install_opensuse_stable || return 1 - return 0 -} - -install_suse_11_git() { - install_opensuse_git || return 1 - return 0 -} - -install_suse_11_onedir() { - install_opensuse_stable || return 1 - return 0 -} - -install_suse_11_stable_post() { - install_opensuse_stable_post || return 1 - return 0 -} - -install_suse_11_git_post() { - install_opensuse_git_post || return 1 - return 0 -} - -install_suse_11_onedir_post() { - install_opensuse_stable_post || return 1 - return 0 -} - -install_suse_11_restart_daemons() { - install_opensuse_restart_daemons || return 1 - return 0 -} - - -# -# End of SUSE Enterprise 11 -# -####################################################################################################################### - -####################################################################################################################### -# -# SUSE Enterprise General Functions -# - -# Used for both SLE 11 and 12 -install_suse_check_services() { - if [ ! -f /bin/systemctl ]; then - # Not running systemd!? Don't check! - return 0 - fi - - for fname in api master minion syndic; do - # Skip salt-api since the service should be opt-in and not necessarily started on boot - [ $fname = "api" ] && continue - - # Skip if not meant to be installed - [ $fname = "master" ] && [ "$_INSTALL_MASTER" -eq $BS_FALSE ] && continue - [ $fname = "minion" ] && [ "$_INSTALL_MINION" -eq $BS_FALSE ] && continue - [ $fname = "syndic" ] && [ "$_INSTALL_SYNDIC" -eq $BS_FALSE ] && continue - - __check_services_systemd salt-$fname || return 1 - done - - return 0 -} - -# -# End of SUSE Enterprise General Functions -# -####################################################################################################################### ####################################################################################################################### # @@ -8608,9 +6906,15 @@ __gentoo_pre_dep() { mkdir /etc/portage fi - # Enable Python 3.7 target for Salt Neon using GIT - if [ "${ITYPE}" = "git" ] && [ "${GIT_REV}" = "v3000" ]; then - EXTRA_PYTHON_TARGET=python3_7 + # Enable Python 3.10 target for Salt 3006 or later, otherwise 3.7 as previously, using GIT + if [ "${ITYPE}" = "git" ]; then + GIT_REV_MAJOR=$(echo "${GIT_REV}" | awk -F "." '{print $1}') + if [ "${GIT_REV_MAJOR}" = "v3006" ] || [ "${GIT_REV_MAJOR}" = "v3007" ]; then + EXTRA_PYTHON_TARGET=python3_10 + else + # assume pre-3006, so leave it as Python 3.7 + EXTRA_PYTHON_TARGET=python3_7 + fi fi if [ -n "${EXTRA_PYTHON_TARGET:-}" ]; then @@ -8626,7 +6930,6 @@ __gentoo_post_dep() { echoinfo "Installing the following extra packages as requested: ${_EXTRA_PACKAGES}" # shellcheck disable=SC2086 __autounmask ${_EXTRA_PACKAGES} || return 1 - # shellcheck disable=SC2086 __emerge ${_EXTRA_PACKAGES} || return 1 fi @@ -8670,27 +6973,6 @@ install_gentoo_git_deps() { GENTOO_GIT_PACKAGES="${GENTOO_GIT_PACKAGES:-} dev-vcs/git" fi - # Salt <3000 does not automatically install dependencies. It has to be done manually. - if [ "${_POST_NEON_INSTALL}" -eq $BS_FALSE ]; then - GENTOO_GIT_PACKAGES="${GENTOO_GIT_PACKAGES:-} - sys-apps/pciutils - dev-python/pyyaml - dev-python/pyzmq - dev-python/libnacl - dev-python/pycryptodome - dev-python/py - dev-python/requests - /etc/paths.d/salt fi @@ -9159,17 +7404,20 @@ install_macosx_stable_post() { } install_macosx_onedir_post() { + install_macosx_stable_post || return 1 return 0 } install_macosx_git_post() { + install_macosx_stable_post || return 1 return 0 } install_macosx_restart_daemons() { - [ $_START_DAEMONS -eq $BS_FALSE ] && return + + [ "$_START_DAEMONS" -eq $BS_FALSE ] && return if [ "$_INSTALL_MINION" -eq $BS_TRUE ]; then /bin/launchctl unload -w /Library/LaunchDaemons/com.saltstack.salt.minion.plist || return 1 @@ -9194,6 +7442,7 @@ install_macosx_restart_daemons() { # the -c options is passed. # config_salt() { + # If the configuration directory is not passed, return [ "$_TEMP_CONFIG_DIR" = "null" ] && return @@ -9237,7 +7486,7 @@ config_salt() { # Check if a minion config file already exists and move to .bak if needed if [ -f "$_SALT_ETC_DIR/minion" ] && [ "$CREATE_BAK" -eq "$BS_TRUE" ]; then - __movefile "$_SALT_ETC_DIR/minion" "$_SALT_ETC_DIR/minion.bak" $BS_TRUE || return 1 + __movefile "$_SALT_ETC_DIR/minion" "$_SALT_ETC_DIR/minion.bak" "$BS_TRUE" || return 1 CONFIGURED_ANYTHING=$BS_TRUE fi @@ -9280,8 +7529,11 @@ config_salt() { if [ "$_INSTALL_SYNDIC" -eq $BS_TRUE ] && [ "$_CONFIG_ONLY" -eq $BS_TRUE ]; then OVERWRITE_MASTER_CONFIGS=$BS_TRUE fi + if [ "$_INSTALL_SALT_API" -eq $BS_TRUE ] && [ "$_CONFIG_ONLY" -eq $BS_TRUE ]; then + OVERWRITE_MASTER_CONFIGS=$BS_TRUE + fi - if [ "$_INSTALL_MASTER" -eq $BS_TRUE ] || [ "$_INSTALL_SYNDIC" -eq $BS_TRUE ] || [ "$OVERWRITE_MASTER_CONFIGS" -eq $BS_TRUE ] || [ "$_CUSTOM_MASTER_CONFIG" != "null" ]; then + if [ "$_INSTALL_MASTER" -eq $BS_TRUE ] || [ "$_INSTALL_SYNDIC" -eq $BS_TRUE ] || [ "$_INSTALL_SALT_API" -eq $BS_TRUE ] || [ "$OVERWRITE_MASTER_CONFIGS" -eq $BS_TRUE ] || [ "$_CUSTOM_MASTER_CONFIG" != "null" ]; then # Create the PKI directory [ -d "$_PKI_DIR/master" ] || (mkdir -p "$_PKI_DIR/master" && chmod 700 "$_PKI_DIR/master") || return 1 @@ -9290,7 +7542,7 @@ config_salt() { # Check if a master config file already exists and move to .bak if needed if [ -f "$_SALT_ETC_DIR/master" ] && [ "$CREATE_BAK" -eq "$BS_TRUE" ]; then - __movefile "$_SALT_ETC_DIR/master" "$_SALT_ETC_DIR/master.bak" $BS_TRUE || return 1 + __movefile "$_SALT_ETC_DIR/master" "$_SALT_ETC_DIR/master.bak" "$BS_TRUE" || return 1 CONFIGURED_ANYTHING=$BS_TRUE fi @@ -9304,7 +7556,7 @@ config_salt() { CONFIGURED_ANYTHING=$BS_TRUE fi - # Copy the master's keys if found + # Copy the masters keys if found if [ -f "$_TEMP_CONFIG_DIR/master.pem" ]; then __movefile "$_TEMP_CONFIG_DIR/master.pem" "$_PKI_DIR/master/" || return 1 chmod 400 "$_PKI_DIR/master/master.pem" || return 1 @@ -9334,7 +7586,7 @@ config_salt() { done fi - if [ "$_CONFIG_ONLY" -eq $BS_TRUE ] && [ $CONFIGURED_ANYTHING -eq $BS_FALSE ]; then + if [ "$_CONFIG_ONLY" -eq $BS_TRUE ] && [ "$CONFIGURED_ANYTHING" -eq $BS_FALSE ]; then echowarn "No configuration or keys were copied over. No configuration was done!" exit 0 fi @@ -9352,6 +7604,7 @@ config_salt() { # as long as the -k option is passed. # preseed_master() { + # Create the PKI directory if [ "$(find "$_TEMP_KEYS_DIR" -maxdepth 1 -type f | wc -l)" -lt 1 ]; then @@ -9386,6 +7639,7 @@ preseed_master() { # This function checks if all of the installed daemons are running or not. # daemons_running_onedir() { + [ "$_START_DAEMONS" -eq $BS_FALSE ] && return 0 FAILED_DAEMONS=0 @@ -9423,6 +7677,7 @@ daemons_running_onedir() { # This function checks if all of the installed daemons are running or not. # daemons_running() { + [ "$_START_DAEMONS" -eq $BS_FALSE ] && return 0 FAILED_DAEMONS=0 @@ -9437,7 +7692,7 @@ daemons_running() { # shellcheck disable=SC2009 if [ "${DISTRO_NAME}" = "SmartOS" ]; then - if [ "$(svcs -Ho STA salt-$fname)" != "ON" ]; then + if [ "$(svcs -Ho STA "salt-$fname")" != "ON" ]; then echoerror "salt-$fname was not found running" FAILED_DAEMONS=$((FAILED_DAEMONS + 1)) fi @@ -9447,7 +7702,7 @@ daemons_running() { fi done - return $FAILED_DAEMONS + return ${FAILED_DAEMONS} } # # Ended daemons running check function @@ -9470,9 +7725,10 @@ if [ ${_NO_DEPS} -eq $BS_FALSE ]; then fi DEPS_INSTALL_FUNC="null" -for FUNC_NAME in $(__strip_duplicates "$DEP_FUNC_NAMES"); do - if __function_defined "$FUNC_NAME"; then - DEPS_INSTALL_FUNC="$FUNC_NAME" +# shellcheck disable=SC2086 +for FUNC_NAME in $(__strip_duplicates ${DEP_FUNC_NAMES}); do + if __function_defined ${FUNC_NAME}; then + DEPS_INSTALL_FUNC=${FUNC_NAME} break fi done @@ -9582,7 +7838,7 @@ for FUNC_NAME in $(__strip_duplicates "$DAEMONS_RUNNING_FUNC_NAMES"); do done echodebug "DAEMONS_RUNNING_FUNC=${DAEMONS_RUNNING_FUNC}" -# Let's get the check services function +# Lets get the check services function if [ ${_DISABLE_SALT_CHECKS} -eq $BS_FALSE ]; then CHECK_SERVICES_FUNC_NAMES="install_${DISTRO_NAME_L}${PREFIXED_DISTRO_MAJOR_VERSION}_${ITYPE}_check_services" CHECK_SERVICES_FUNC_NAMES="$CHECK_SERVICES_FUNC_NAMES install_${DISTRO_NAME_L}${PREFIXED_DISTRO_MAJOR_VERSION}${PREFIXED_DISTRO_MINOR_VERSION}_${ITYPE}_check_services" @@ -9615,7 +7871,7 @@ fi # Install dependencies -if [ ${_NO_DEPS} -eq $BS_FALSE ] && [ $_CONFIG_ONLY -eq $BS_FALSE ]; then +if [ "${_NO_DEPS}" -eq $BS_FALSE ] && [ "$_CONFIG_ONLY" -eq $BS_FALSE ]; then # Only execute function is not in config mode only echoinfo "Running ${DEPS_INSTALL_FUNC}()" if ! ${DEPS_INSTALL_FUNC}; then @@ -9639,7 +7895,7 @@ if [ "$_CUSTOM_MASTER_CONFIG" != "null" ] || [ "$_CUSTOM_MINION_CONFIG" != "null _TEMP_CONFIG_DIR="$_SALT_ETC_DIR" fi - if [ ${_NO_DEPS} -eq $BS_FALSE ] && [ $_CONFIG_ONLY -eq $BS_TRUE ]; then + if [ "${_NO_DEPS}" -eq $BS_FALSE ] && [ "$_CONFIG_ONLY" -eq $BS_TRUE ]; then # Execute function to satisfy dependencies for configuration step echoinfo "Running ${DEPS_INSTALL_FUNC}()" if ! ${DEPS_INSTALL_FUNC}; then @@ -9713,6 +7969,7 @@ fi if [ "$STARTDAEMONS_INSTALL_FUNC" != "null" ] && [ ${_START_DAEMONS} -eq $BS_TRUE ]; then echoinfo "Running ${STARTDAEMONS_INSTALL_FUNC}()" echodebug "Waiting ${_SLEEP} seconds for processes to settle before checking for them" + # shellcheck disable=SC2086 sleep ${_SLEEP} if ! ${STARTDAEMONS_INSTALL_FUNC}; then echoerror "Failed to run ${STARTDAEMONS_INSTALL_FUNC}()!!!" @@ -9724,6 +7981,7 @@ fi if [ "$DAEMONS_RUNNING_FUNC" != "null" ] && [ ${_START_DAEMONS} -eq $BS_TRUE ]; then echoinfo "Running ${DAEMONS_RUNNING_FUNC}()" echodebug "Waiting ${_SLEEP} seconds for processes to settle before checking for them" + # shellcheck disable=SC2086 sleep ${_SLEEP} # Sleep a little bit to let daemons start if ! ${DAEMONS_RUNNING_FUNC}; then echoerror "Failed to run ${DAEMONS_RUNNING_FUNC}()!!!" @@ -9746,7 +8004,7 @@ if [ "$DAEMONS_RUNNING_FUNC" != "null" ] && [ ${_START_DAEMONS} -eq $BS_TRUE ]; echodebug "Running salt-$fname by hand outputs: $(nohup salt-$fname -l debug)" - [ ! -f /var/log/salt/$fname ] && echodebug "/var/log/salt/$fname does not exist. Can't cat its contents!" && continue + [ ! -f "/var/log/salt/$fname" ] && echodebug "/var/log/salt/$fname does not exist. Can't cat its contents!" && continue echodebug "DAEMON LOGS for $fname:" echodebug "$(cat /var/log/salt/$fname)" From 61a1fbde6e4b1b143a2e167e6bd90d76b8466f88 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Mon, 9 Dec 2024 15:30:48 -0500 Subject: [PATCH 048/315] create hypervisor pillars in setup --- setup/so-functions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup/so-functions b/setup/so-functions index 59408a69c..b2cdd56ee 100755 --- a/setup/so-functions +++ b/setup/so-functions @@ -1439,7 +1439,7 @@ make_some_dirs() { mkdir -p $local_salt_dir/salt/firewall/portgroups mkdir -p $local_salt_dir/salt/firewall/ports - for THEDIR in bpf pcap elasticsearch ntp firewall redis backup influxdb strelka sensoroni soc docker zeek suricata nginx telegraf logstash soc manager kratos idstools idh elastalert stig global kafka versionlock; do + for THEDIR in bpf pcap elasticsearch ntp firewall redis backup influxdb strelka sensoroni soc docker zeek suricata nginx telegraf logstash soc manager kratos idstools idh elastalert stig global kafka versionlock hypervisor; do mkdir -p $local_salt_dir/pillar/$THEDIR touch $local_salt_dir/pillar/$THEDIR/adv_$THEDIR.sls touch $local_salt_dir/pillar/$THEDIR/soc_$THEDIR.sls From 7eaa8d54dc75d22a271dcdd9a42c4f71e78a8ae0 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Mon, 9 Dec 2024 15:35:07 -0500 Subject: [PATCH 049/315] git ignore dirs --- .gitignore | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 7f446a041..1830698b0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ - # Created by https://www.gitignore.io/api/macos,windows # Edit at https://www.gitignore.io/?templates=macos,windows @@ -67,4 +66,10 @@ __pycache__ # Analyzer dev/test config files *_dev.yaml -site-packages \ No newline at end of file +site-packages + +# Project Scope Directory +.projectScope/ + +# vscode settings +.vscode/ From a84a32c075059ffaace45a6c407cf67e492ce804 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Tue, 10 Dec 2024 16:24:18 -0500 Subject: [PATCH 050/315] increase whiptail by 1 --- setup/so-whiptail | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup/so-whiptail b/setup/so-whiptail index b25682acd..2ea5dd38b 100755 --- a/setup/so-whiptail +++ b/setup/so-whiptail @@ -674,7 +674,7 @@ whiptail_install_type_dist_existing() { Note: Heavy nodes (HEAVYNODE) are NOT recommended for most users. EOM - install_type=$(whiptail --title "$whiptail_title" --menu "$node_msg" 19 75 6 \ + install_type=$(whiptail --title "$whiptail_title" --menu "$node_msg" 19 75 7 \ "SENSOR" "Create a forward only sensor " \ "SEARCHNODE" "Add a search node with parsing " \ "FLEET" "Dedicated Elastic Fleet Node " \ From e779d180f932033a4a4d42d18fb43a6c03be618e Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Fri, 13 Dec 2024 16:03:17 -0500 Subject: [PATCH 051/315] work around libvirt issue. add raid scripts --- salt/hypervisor/raid.sh | 19 ++ salt/hypervisor/raid2.sh | 187 ++++++++++++++++++++ salt/libvirt/64962/init.sls | 9 + salt/libvirt/64962/scripts/fix-salt-ldap.py | 75 ++++++++ salt/libvirt/init.sls | 1 + 5 files changed, 291 insertions(+) create mode 100644 salt/hypervisor/raid.sh create mode 100644 salt/hypervisor/raid2.sh create mode 100644 salt/libvirt/64962/init.sls create mode 100644 salt/libvirt/64962/scripts/fix-salt-ldap.py diff --git a/salt/hypervisor/raid.sh b/salt/hypervisor/raid.sh new file mode 100644 index 000000000..031e4c522 --- /dev/null +++ b/salt/hypervisor/raid.sh @@ -0,0 +1,19 @@ +# quick script to create raid +parted -s /dev/nvme0n1 rm 1 +parted -s /dev/nvme0n1 mklabel gpt +parted -s /dev/nvme0n1 mkpart primary xfs 0% 100% +parted -s /dev/nvme0n1 set 1 raid on +parted -s /dev/nvme1n1 rm 1 +parted -s /dev/nvme1n1 mklabel gpt +parted -s /dev/nvme1n1 mkpart primary xfs 0% 100% +parted -s /dev/nvme1n1 set 1 raid on +yes | mdadm --create /dev/md0 --level=1 --raid-devices=2 /dev/nvme0n1p1 /dev/nvme1n1p1 + +mkfs -t xfs -f /dev/md0 +echo "Create NSM mount point" +mkdir -p /nsm +echo "Add mount to fstab" +echo "/dev/md0 /nsm xfs defaults,nofail 0 0" >> /etc/fstab +echo "Mounting /nsm" +mount -a +mdadm --detail --scan --verbose >> /etc/mdadm.conf diff --git a/salt/hypervisor/raid2.sh b/salt/hypervisor/raid2.sh new file mode 100644 index 000000000..83e1970df --- /dev/null +++ b/salt/hypervisor/raid2.sh @@ -0,0 +1,187 @@ +#!/bin/bash + +# Exit on any error +set -e + +# Function to log messages +log() { + echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" +} + +# Function to check if running as root +check_root() { + if [ "$EUID" -ne 0 ]; then + log "Error: Please run as root" + exit 1 + fi +} + +# Function to check if RAID is already set up +check_existing_raid() { + if [ -e "/dev/md0" ]; then + if mdadm --detail /dev/md0 &>/dev/null; then + local raid_state=$(mdadm --detail /dev/md0 | grep "State" | awk '{print $3}') + local mount_point="/nsm" + + log "Found existing RAID array /dev/md0 (State: $raid_state)" + + if mountpoint -q "$mount_point"; then + log "RAID is already mounted at $mount_point" + log "Current RAID details:" + mdadm --detail /dev/md0 + + # Check if resyncing + if grep -q "resync" /proc/mdstat; then + log "RAID is currently resyncing:" + grep resync /proc/mdstat + log "You can monitor progress with: watch -n 60 cat /proc/mdstat" + else + log "RAID is fully synced and operational" + fi + + # Show disk usage + log "Current disk usage:" + df -h "$mount_point" + + exit 0 + fi + fi + fi + + # Check if any of the target devices are in use + for device in "/dev/nvme0n1" "/dev/nvme1n1"; do + if lsblk -o NAME,MOUNTPOINT "$device" | grep -q "nsm"; then + log "Error: $device is already mounted at /nsm" + exit 1 + fi + + if mdadm --examine "$device" &>/dev/null || mdadm --examine "${device}p1" &>/dev/null; then + log "Error: $device appears to be part of an existing RAID array" + log "To reuse this device, you must first:" + log "1. Unmount any filesystems" + log "2. Stop the RAID array: mdadm --stop /dev/md0" + log "3. Zero the superblock: mdadm --zero-superblock ${device}p1" + exit 1 + fi + done +} + +# Function to ensure devices are not in use +ensure_devices_free() { + local device=$1 + + log "Cleaning up device $device" + + # Kill any processes using the device + fuser -k "${device}"* 2>/dev/null || true + + # Force unmount any partitions + for part in "${device}"*; do + if mount | grep -q "$part"; then + umount -f "$part" 2>/dev/null || true + fi + done + + # Stop any MD arrays using this device + for md in $(ls /dev/md* 2>/dev/null || true); do + if mdadm --detail "$md" 2>/dev/null | grep -q "$device"; then + mdadm --stop "$md" 2>/dev/null || true + fi + done + + # Clear MD superblock + mdadm --zero-superblock "${device}"* 2>/dev/null || true + + # Remove LVM PV if exists + pvremove -ff -y "$device" 2>/dev/null || true + + # Clear all signatures + wipefs -af "$device" 2>/dev/null || true + + # Delete partition table + dd if=/dev/zero of="$device" bs=512 count=2048 2>/dev/null || true + dd if=/dev/zero of="$device" bs=512 seek=$(( $(blockdev --getsz "$device") - 2048 )) count=2048 2>/dev/null || true + + # Force kernel to reread + blockdev --rereadpt "$device" 2>/dev/null || true + partprobe -s "$device" 2>/dev/null || true + sleep 2 +} + +# Main script +main() { + log "Starting RAID setup script" + + # Check if running as root + check_root + + # Check for existing RAID setup + check_existing_raid + + # Clean up any existing MD arrays + log "Cleaning up existing MD arrays" + mdadm --stop --scan 2>/dev/null || true + + # Clear mdadm configuration + log "Clearing mdadm configuration" + echo "DEVICE partitions" > /etc/mdadm.conf + + # Clean and prepare devices + for device in "/dev/nvme0n1" "/dev/nvme1n1"; do + ensure_devices_free "$device" + + log "Creating new partition table on $device" + sgdisk -Z "$device" + sgdisk -o "$device" + + log "Creating RAID partition" + sgdisk -n 1:0:0 -t 1:fd00 "$device" + + partprobe "$device" + udevadm settle + sleep 5 + done + + log "Final verification of partition availability" + if ! [ -b "/dev/nvme0n1p1" ] || ! [ -b "/dev/nvme1n1p1" ]; then + log "Error: Partitions not available after creation" + exit 1 + fi + + log "Creating RAID array" + mdadm --create /dev/md0 --level=1 --raid-devices=2 \ + --metadata=1.2 \ + /dev/nvme0n1p1 /dev/nvme1n1p1 \ + --force --run + + log "Creating XFS filesystem" + mkfs.xfs -f /dev/md0 + + log "Creating mount point" + mkdir -p /nsm + + log "Updating fstab" + sed -i '/\/dev\/md0/d' /etc/fstab + echo "/dev/md0 /nsm xfs defaults,nofail 0 0" >> /etc/fstab + + log "Reloading systemd daemon" + systemctl daemon-reload + + log "Mounting filesystem" + mount -a + + log "Saving RAID configuration" + mdadm --detail --scan > /etc/mdadm.conf + + log "RAID setup complete" + log "RAID array details:" + mdadm --detail /dev/md0 + + if grep -q "resync" /proc/mdstat; then + log "RAID is currently resyncing. You can monitor progress with:" + log "watch -n 60 cat /proc/mdstat" + fi +} + +# Run main function +main "$@" diff --git a/salt/libvirt/64962/init.sls b/salt/libvirt/64962/init.sls new file mode 100644 index 000000000..81eedb09b --- /dev/null +++ b/salt/libvirt/64962/init.sls @@ -0,0 +1,9 @@ +python3_lief: + pkg.installed: + - name: securityonion-python3-lief + +fix-salt-ldap: + cmd.script: + - source: salt://libvirt/64962/scripts/fix-salt-ldap.py + - require: + - pkg: python3_lief diff --git a/salt/libvirt/64962/scripts/fix-salt-ldap.py b/salt/libvirt/64962/scripts/fix-salt-ldap.py new file mode 100644 index 000000000..56fcce8aa --- /dev/null +++ b/salt/libvirt/64962/scripts/fix-salt-ldap.py @@ -0,0 +1,75 @@ +#!/usr/bin/env python3 + +import datetime +import grp +import os +import pathlib +import pwd +import shutil +## +import dbus # dnf -y install python3-dbus +## +import lief # https://pypi.org/project/lief/ + +# https://github.com/saltstack/salt/issues/64962 + +salt_root = pathlib.Path('/opt/saltstack') +src_lib = pathlib.Path('/lib64/libldap.so.2') +dst_lib = salt_root.joinpath('salt', 'lib', 'libldap.so.2') + +uname = 'salt' +gname = 'salt' + +lib = lief.parse(str(src_lib)) +sym = next(i for i in lib.imported_symbols if i.name == 'EVP_md2') +if sym: + # Get the Salt services from DBus. + sysbus = dbus.SystemBus() + sysd = sysbus.get_object('org.freedesktop.systemd1', '/org/freedesktop/systemd1') + mgr = dbus.Interface(sysd, 'org.freedesktop.systemd1.Manager') + svcs = [] + for i in mgr.ListUnits(): + # first element is unit name. + if not str(i[0]).startswith('salt-'): + continue + svc = sysbus.get_object('org.freedesktop.systemd1', object_path = mgr.GetUnit(str(i[0]))) + props = dbus.Interface(svc, dbus_interface = 'org.freedesktop.DBus.Properties') + state = props.Get('org.freedesktop.systemd1.Unit', 'ActiveState') + if str(state) == 'active': + svcs.append(i[0]) + # Get the user/group + u = pwd.getpwnam(uname) + g = grp.getgrnam(gname) + # Modify + print('Modifications necessary.') + if svcs: + # Stop the services first. + for sn in svcs: + mgr.StopUnit(sn, 'replace') + if dst_lib.exists(): + # 3.10 deprecated .utcnow(). + #dst_lib_bak = pathlib.Path(str(dst_lib) + '.bak_{0}'.format(datetime.datetime.now(datetime.UTC).timestamp())) + dst_lib_bak = pathlib.Path(str(dst_lib) + '.bak_{0}'.format(datetime.datetime.utcnow().timestamp())) + os.rename(dst_lib, dst_lib_bak) + print('Destination file {0} exists; backed up to {1}.'.format(dst_lib, dst_lib_bak)) + lib.remove_dynamic_symbol(sym) + lib.write(str(dst_lib)) + os.chown(dst_lib, u.pw_uid, g.gr_gid) + os.chmod(dst_lib, src_lib.stat().st_mode) + # Before we restart services, we also want to remove any python caches. + for root, dirs, files in os.walk(salt_root): + for f in files: + if f.lower().endswith('.pyc'): + fpath = os.path.join(root, f) + os.remove(fpath) + print('Removed file {0}'.format(fpath)) + if '__pycache__' in dirs: + dpath = os.path.join(root, '__pycache__') + shutil.rmtree(dpath) + print('Removed directory {0}'.format(dpath)) + # And then start the units that were started before. + if svcs: + for sn in svcs: + mgr.RestartUnit(sn, 'replace') + +print('Done.') diff --git a/salt/libvirt/init.sls b/salt/libvirt/init.sls index 689ee278e..75e44dd86 100644 --- a/salt/libvirt/init.sls +++ b/salt/libvirt/init.sls @@ -6,6 +6,7 @@ {% from 'libvirt/map.jinja' import LIBVIRTMERGED %} include: + - libvirt.64962 - libvirt.packages - libvirt.ssh.users From 5e4f1fc27917ba279005240a9b0a9e90d1eef1a8 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Mon, 16 Dec 2024 10:23:14 -0500 Subject: [PATCH 052/315] only run fix ldap when lief installed --- salt/libvirt/64962/init.sls | 2 ++ 1 file changed, 2 insertions(+) diff --git a/salt/libvirt/64962/init.sls b/salt/libvirt/64962/init.sls index 81eedb09b..a6b13c3e5 100644 --- a/salt/libvirt/64962/init.sls +++ b/salt/libvirt/64962/init.sls @@ -7,3 +7,5 @@ fix-salt-ldap: - source: salt://libvirt/64962/scripts/fix-salt-ldap.py - require: - pkg: python3_lief + - onchanges: + - pkg: python3_lief From b24aa2f797a6c519728ff3b612cde704ce06d12f Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Thu, 19 Dec 2024 10:11:54 -0500 Subject: [PATCH 053/315] fix destroying virbr0 --- salt/libvirt/init.sls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/libvirt/init.sls b/salt/libvirt/init.sls index 75e44dd86..dae0ed2bd 100644 --- a/salt/libvirt/init.sls +++ b/salt/libvirt/init.sls @@ -84,7 +84,7 @@ disable_default_bridge: - require: - pkg: install_libvirt-client - onlyif: - - virsh net-info | grep default + - virsh net-list | grep default # this should only run during the first highstate after setup. it will transfer connection from mgmt to br0 down_original_mgmt_interface: From 7a8fd8c3e58e5f05ac56c103818162f7eff3b558 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Thu, 19 Dec 2024 10:12:29 -0500 Subject: [PATCH 054/315] handle salt-cloud package --- salt/salt/master.sls | 3 +++ salt/salt/minion.sls | 8 +++++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/salt/salt/master.sls b/salt/salt/master.sls index bfd458dc8..17e818503 100644 --- a/salt/salt/master.sls +++ b/salt/salt/master.sls @@ -8,6 +8,9 @@ include: - salt.minion +{% if salt['pillar.get']('hypervisor:nodes', {} ) %} + - salt.cloud +{% endif %} hold_salt_master_package: module.run: diff --git a/salt/salt/minion.sls b/salt/salt/minion.sls index 0d995e96c..9c8e2993b 100644 --- a/salt/salt/minion.sls +++ b/salt/salt/minion.sls @@ -37,13 +37,15 @@ install_salt_minion: {% endif %} {% if INSTALLEDSALTVERSION|string == SALTVERSION|string %} - +# only hold the package if it is already installed hold_salt_packages: pkg.held: - pkgs: -{% for package in SALTPACKAGES %} +{% for package in SALTPACKAGES %} +{% if salt['pkg.version'](package) %} - {{ package }}: {{SALTVERSION}}-0.* -{% endfor %} +{% endif %} +{% endfor %} remove_error_log_level_logfile: file.line: From f2bd735f516fe2f5fefe2bf6477087c12625e778 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Thu, 19 Dec 2024 10:13:05 -0500 Subject: [PATCH 055/315] another script to create raid --- salt/hypervisor/raid3.sh | 192 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 192 insertions(+) create mode 100644 salt/hypervisor/raid3.sh diff --git a/salt/hypervisor/raid3.sh b/salt/hypervisor/raid3.sh new file mode 100644 index 000000000..8e7d6c7ae --- /dev/null +++ b/salt/hypervisor/raid3.sh @@ -0,0 +1,192 @@ +#!/bin/bash + +# Exit on any error +set -e + +# Function to log messages +log() { + echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" +} + +# Function to check if running as root +check_root() { + if [ "$EUID" -ne 0 ]; then + log "Error: Please run as root" + exit 1 + fi +} + +# Function to perform thorough device cleanup +ensure_devices_free() { + local device=$1 + + log "Performing thorough cleanup of device $device" + + # Kill any processes using the device + fuser -k "${device}"* 2>/dev/null || true + + # Force unmount any partitions + for part in "${device}"*; do + if mount | grep -q "$part"; then + umount -f "$part" 2>/dev/null || true + fi + done + + # Stop any MD arrays using this device + for md in $(ls /dev/md* 2>/dev/null || true); do + if mdadm --detail "$md" 2>/dev/null | grep -q "$device"; then + log "Stopping MD array $md" + mdadm --stop "$md" 2>/dev/null || true + fi + done + + # Thorough RAID cleanup + log "Cleaning RAID metadata from $device" + mdadm --zero-superblock "$device" 2>/dev/null || true + if [ -e "${device}p1" ]; then + mdadm --zero-superblock "${device}p1" 2>/dev/null || true + fi + + # Remove LVM PV if exists + pvremove -ff -y "$device" 2>/dev/null || true + + # Clear all signatures + log "Wiping all signatures from $device" + wipefs -a "$device" 2>/dev/null || true + + # Clear partition table + log "Clearing partition table on $device" + sgdisk -Z "$device" 2>/dev/null || true + + # Force kernel to reread + log "Forcing kernel to reread partition table" + partprobe "$device" 2>/dev/null || true + sleep 2 +} + +# Function to check if RAID is already set up +check_existing_raid() { + # Clear existing mdadm configuration first + log "Initializing clean mdadm configuration" + echo "DEVICE partitions" > /etc/mdadm.conf + + if [ -e "/dev/md0" ]; then + if mdadm --detail /dev/md0 &>/dev/null; then + local raid_state=$(mdadm --detail /dev/md0 | grep "State" | awk '{print $3}') + local mount_point="/nsm" + + log "Found existing RAID array /dev/md0 (State: $raid_state)" + + if mountpoint -q "$mount_point"; then + log "RAID is already mounted at $mount_point" + log "Current RAID details:" + mdadm --detail /dev/md0 + + # Check if resyncing + if grep -q "resync" /proc/mdstat; then + log "RAID is currently resyncing:" + grep resync /proc/mdstat + log "You can monitor progress with: watch -n 60 cat /proc/mdstat" + else + log "RAID is fully synced and operational" + fi + + # Show disk usage + log "Current disk usage:" + df -h "$mount_point" + + exit 0 + fi + fi + fi + + # Check if any MD arrays exist and try to clean them up + if [ -f /proc/mdstat ]; then + log "Checking for existing MD arrays" + if grep -q "md" /proc/mdstat; then + log "Found existing MD arrays, attempting cleanup" + for md in $(awk '/md/{print $1}' /proc/mdstat); do + log "Stopping array $md" + mdadm --stop "/dev/$md" 2>/dev/null || true + done + fi + fi + + # Check if any of the target devices are in use + for device in "/dev/nvme0n1" "/dev/nvme1n1"; do + if lsblk -o NAME,MOUNTPOINT "$device" | grep -q "nsm"; then + log "Error: $device is already mounted at /nsm" + exit 1 + fi + done +} + +# Main script +main() { + log "Starting RAID setup script" + + # Check if running as root + check_root + + # Check for existing RAID setup + check_existing_raid + + # Clean and prepare devices + for device in "/dev/nvme0n1" "/dev/nvme1n1"; do + ensure_devices_free "$device" + + log "Creating new partition table on $device" + sgdisk -Z "$device" + sgdisk -o "$device" + + log "Creating RAID partition" + sgdisk -n 1:0:0 -t 1:fd00 "$device" + + partprobe "$device" + udevadm settle + sleep 5 + done + + log "Final verification of partition availability" + if ! [ -b "/dev/nvme0n1p1" ] || ! [ -b "/dev/nvme1n1p1" ]; then + log "Error: Partitions not available after creation" + exit 1 + fi + + log "Creating RAID array" + mdadm --create /dev/md0 --level=1 --raid-devices=2 \ + --metadata=1.2 \ + /dev/nvme0n1p1 /dev/nvme1n1p1 \ + --force --run + + log "Creating XFS filesystem" + mkfs.xfs -f /dev/md0 + + log "Creating mount point" + mkdir -p /nsm + + log "Updating fstab" + sed -i '/\/dev\/md0/d' /etc/fstab + echo "/dev/md0 /nsm xfs defaults,nofail 0 0" >> /etc/fstab + + log "Reloading systemd daemon" + systemctl daemon-reload + + log "Mounting filesystem" + mount -a + + log "Saving RAID configuration" + mdadm --detail --scan > /etc/mdadm.conf + + log "RAID setup complete" + log "RAID array details:" + mdadm --detail /dev/md0 + + if grep -q "resync" /proc/mdstat; then + log "RAID is currently resyncing. You can monitor progress with:" + log "watch -n 60 cat /proc/mdstat" + fi +} + +# Run main function +main "$@" From 6f0161e9dae56c1dd8315ff31a17a3bb7ce30e9b Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Thu, 19 Dec 2024 17:36:48 -0500 Subject: [PATCH 056/315] script to create base domain --- salt/libvirt/scripts/createvm.sh | 153 +++++++++++++++++++++++++++++++ 1 file changed, 153 insertions(+) create mode 100644 salt/libvirt/scripts/createvm.sh diff --git a/salt/libvirt/scripts/createvm.sh b/salt/libvirt/scripts/createvm.sh new file mode 100644 index 000000000..e0b9c216d --- /dev/null +++ b/salt/libvirt/scripts/createvm.sh @@ -0,0 +1,153 @@ +#!/bin/bash + +# Exit on any error +set -e + +# Set variables and defaults +VM=${1:-"small-vm"} # VM name +IP=${2:-"192.168.1.10"} # IP address +GATEWAY=${3:-"192.168.1.1"} # Gateway +DNS=${4:-"192.168.1.1"} # Comma-separated list of DNS servers +MAC_ADDRESS="52:54:00:f2:c3:df" # Default MAC - will be overridden if found + +# Show usage if help is requested +if [[ "$1" == "-h" || "$1" == "--help" ]]; then + echo "Usage: $0 " + echo "Example: $0 myvm 192.168.1.50 192.168.1.1 8.8.8.8,8.8.4.4" + echo "All parameters are optional and will use defaults if not specified" + exit 0 +fi + +# Convert comma-separated DNS servers to yaml format +format_dns() { + local IFS=',' + local dns_list=($1) + local yaml="" + for dns in "${dns_list[@]}"; do + yaml="$yaml - $dns"$'\n' + done + echo "$yaml" +} + +DNS_YAML=$(format_dns "$DNS") + +# Set up directory structure +D=/root/create_vm/var/lib/libvirt/images +mkdir -vp $D/$VM +cd $D/$VM + +# Create cloud-init metadata +cat > meta-data << EOF +instance-id: ${VM} +local-hostname: ${VM} +EOF + +# Create network configuration +cat > network-config << EOF +version: 2 +ethernets: + eth0: + match: + macaddress: ${MAC_ADDRESS} + dhcp4: false + dhcp6: false + addresses: + - ${IP}/24 + routes: + - to: 0.0.0.0/0 + via: ${GATEWAY} + nameservers: + addresses: +$(format_dns "$DNS") +EOF + +# Generate password hash using: +# Create passwd hash +### python3 -c 'import crypt; print(crypt.crypt("YOUR_PASSWD_HERE", crypt.mksalt(crypt.METHOD_SHA512)))' +# Create ssh keypair +### ssh-keygen -t ed25519 -C "soqemussh" -f ~/.ssh/soqemussh + +# Create user-data with network configuration +cat > user-data << EOF +#cloud-config +preserve_hostname: False +hostname: ${VM} +fqdn: ${VM}.local + +users: + - default + - name: soqemussh + groups: ['wheel'] + shell: /bin/bash + sudo: ALL=(ALL) NOPASSWD:ALL + lock_passwd: false + passwd: $(echo '___YOUR_HASH_HERE___') + ssh-authorized-keys: + - ssh-ed25519 ___YOUR_PUB_KEY_HERE___ + +# Configure where output will go +output: + all: ">> /var/log/cloud-init.log" + +# configure interaction with ssh server +ssh_genkeytypes: ['ed25519', 'rsa'] + +# set timezone for VM +timezone: UTC + +# Don't preallocate the entire disk space +#resize_rootfs: true +#growpart: +# mode: auto +# devices: ['/'] + +# Install QEMU guest agent. Enable and start the service +packages: + - qemu-guest-agent + +runcmd: + - systemctl enable --now qemu-guest-agent + - systemctl enable --now serial-getty@ttyS0.service + - systemctl enable --now NetworkManager + - growpart /dev/vda 2 + - pvresize /dev/vda2 + - lvextend -l +100%FREE /dev/vg_main/lv_root + - xfs_growfs /dev/vg_main/lv_root +EOF + +# First, copy the base image +echo "Creating base VM image..." +cp -v /root/create_vm/OL9U5_x86_64-kvm-b253.qcow2 $VM.qcow2 + +# First resize the image to our desired size +echo "Resizing image..." +qemu-img resize $VM.qcow2 205G + +# Now compress it +echo "Compressing image..." +qemu-img convert -p -O qcow2 -c $VM.qcow2 $VM-compressed.qcow2 +mv -v $VM-compressed.qcow2 $VM.qcow2 + +# Create a cloud-init ISO with network config +echo "Creating cloud-init ISO..." +mkisofs -output $VM-cidata.iso -volid CIDATA -rock user-data meta-data network-config + +# Echo the configuration for verification +echo "Creating VM with the following network configuration:" +echo "VM Name: $VM" +echo "IP Address: $IP" +echo "Gateway: $GATEWAY" +echo "DNS Servers: $DNS" +echo "MAC Address: $MAC_ADDRESS" + +echo "Files have been created in $D/$VM" +echo +echo "To complete VM creation on the hypervisor, run:" +echo "virsh pool-create-as --name $VM --type dir --target $D/$VM" +echo "virt-install --import --name ${VM} \\" +echo " --memory 4096 --vcpus 4 --cpu host \\" +echo " --disk ${VM}.qcow2,format=qcow2,bus=virtio \\" +echo " --disk ${VM}-cidata.iso,device=cdrom \\" +echo " --network bridge=br0,model=virtio,mac=${MAC_ADDRESS} \\" +echo " --os-variant=ol9.5 \\" +echo " --noautoconsole" From 3c59858f70de8e953a3cdb4dcda07548c2ec4f57 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Fri, 20 Dec 2024 11:42:53 -0500 Subject: [PATCH 057/315] improvements to createvm --- salt/libvirt/scripts/createvm.sh | 91 ++++++++++++++++++++++---------- 1 file changed, 64 insertions(+), 27 deletions(-) diff --git a/salt/libvirt/scripts/createvm.sh b/salt/libvirt/scripts/createvm.sh index e0b9c216d..4a88ecb1f 100644 --- a/salt/libvirt/scripts/createvm.sh +++ b/salt/libvirt/scripts/createvm.sh @@ -1,23 +1,69 @@ #!/bin/bash +# Ensure /root/create_vm/var/lib/libvirt/images exists +# Place this script in /root/create_vm +# Download OL9U5_x86_64-kvm-b253.qcow2 from https://yum.oracle.com/oracle-linux-templates.html, place in /root/create_vm/ + +# These steps will be removed from the process to create the final image and is being used for development +# This is used for the user-data auth portion of cloud-init +# Create passwd hash: +# python3 -c 'import crypt; print(crypt.crypt("YOUR_PASSWD_HERE", crypt.mksalt(crypt.METHOD_SHA512)))' +# Create ssh keypair: +# ssh-keygen -t ed25519 -C "soqemussh" -f ~/.ssh/soqemussh + +# Run the script: createvm.sh coreol9Small 205G +# IP options may be removed for final version + +# After running the script, the following will be output: +#[root@jppvirtman create_vm]# ll var/lib/libvirt/images/coreol9Small/ +#total 610376 +#-rw-r--r--. 1 root root 380928 Dec 20 14:33 coreol9Small-cidata.iso +#-rw-r--r--. 1 root root 624623616 Dec 20 14:33 coreol9Small.qcow2 +#-rw-r--r--. 1 root root 55 Dec 20 14:32 meta-data +#-rw-r--r--. 1 root root 333 Dec 20 14:32 network-config +#-rw-r--r--. 1 root root 1047 Dec 20 14:32 user-data + +# These files are now scp to a hypervisor node +# Place the files in /var/lib/libvirt/images/coreol9Small (or whatever is the same as the vm name) +# Create your storage pool as instructed by the script. this is only needed if one doesn't already exist +# Run the virt-install command as instructed by the script + +# Could add the following to the final runcmd in the user-data to fill the disk to avoid the cons of thin provisioning the disk +# - dd if=/dev/zero of=/tmp/fill bs=1M || true +# - rm -f /tmp/fill + # Exit on any error set -e # Set variables and defaults VM=${1:-"small-vm"} # VM name -IP=${2:-"192.168.1.10"} # IP address -GATEWAY=${3:-"192.168.1.1"} # Gateway -DNS=${4:-"192.168.1.1"} # Comma-separated list of DNS servers +DISK_SIZE=${2:-"205G"} # Disk size with unit (default 205G) +IP=${3:-"192.168.1.10"} # IP address +GATEWAY=${4:-"192.168.1.1"} # Gateway +DNS=${5:-"192.168.1.1"} # Comma-separated list of DNS servers MAC_ADDRESS="52:54:00:f2:c3:df" # Default MAC - will be overridden if found # Show usage if help is requested if [[ "$1" == "-h" || "$1" == "--help" ]]; then - echo "Usage: $0 " - echo "Example: $0 myvm 192.168.1.50 192.168.1.1 8.8.8.8,8.8.4.4" + echo "Usage: $0 " + echo "Example: $0 myvm 100G 192.168.1.50 192.168.1.1 8.8.8.8,8.8.4.4" + echo "Parameters:" + echo " vm_name : Name of the VM (default: small-vm)" + echo " disk_size : Size of the disk with unit G/M (default: 205G)" + echo " ip : IP address (default: 192.168.1.10)" + echo " gateway : Gateway address (default: 192.168.1.1)" + echo " dns_servers: Comma-separated DNS servers (default: 192.168.1.1)" echo "All parameters are optional and will use defaults if not specified" exit 0 fi +# Validate disk size format +if ! [[ $DISK_SIZE =~ ^[0-9]+[GM]$ ]]; then + echo "Error: Disk size must be a number followed by G (gigabytes) or M (megabytes)" + echo "Example: 100G or 51200M" + exit 1 +fi + # Convert comma-separated DNS servers to yaml format format_dns() { local IFS=',' @@ -61,12 +107,6 @@ ethernets: $(format_dns "$DNS") EOF -# Generate password hash using: -# Create passwd hash -### python3 -c 'import crypt; print(crypt.crypt("YOUR_PASSWD_HERE", crypt.mksalt(crypt.METHOD_SHA512)))' -# Create ssh keypair -### ssh-keygen -t ed25519 -C "soqemussh" -f ~/.ssh/soqemussh - # Create user-data with network configuration cat > user-data << EOF #cloud-config @@ -83,7 +123,7 @@ users: lock_passwd: false passwd: $(echo '___YOUR_HASH_HERE___') ssh-authorized-keys: - - ssh-ed25519 ___YOUR_PUB_KEY_HERE___ + - ssh-ed25519 ___YOUR_PUB_KEY_HERE___ soqemussh # Configure where output will go output: @@ -95,12 +135,6 @@ ssh_genkeytypes: ['ed25519', 'rsa'] # set timezone for VM timezone: UTC -# Don't preallocate the entire disk space -#resize_rootfs: true -#growpart: -# mode: auto -# devices: ['/'] - # Install QEMU guest agent. Enable and start the service packages: - qemu-guest-agent @@ -115,26 +149,29 @@ runcmd: - xfs_growfs /dev/vg_main/lv_root EOF -# First, copy the base image +# First, copy the base image with progress echo "Creating base VM image..." -cp -v /root/create_vm/OL9U5_x86_64-kvm-b253.qcow2 $VM.qcow2 +rsync --progress /root/create_vm/OL9U5_x86_64-kvm-b253.qcow2 $VM.qcow2 -# First resize the image to our desired size -echo "Resizing image..." -qemu-img resize $VM.qcow2 205G +# Resize the image to specified size +echo "Resizing image to $DISK_SIZE..." +echo "Current image size: $(qemu-img info $VM.qcow2 | grep 'virtual size' | cut -d':' -f2 | cut -d'(' -f1 | tr -d ' ')" +qemu-img resize -f qcow2 $VM.qcow2 $DISK_SIZE +echo "New image size: $(qemu-img info $VM.qcow2 | grep 'virtual size' | cut -d':' -f2 | cut -d'(' -f1 | tr -d ' ')" -# Now compress it +# Now compress it with progress echo "Compressing image..." qemu-img convert -p -O qcow2 -c $VM.qcow2 $VM-compressed.qcow2 mv -v $VM-compressed.qcow2 $VM.qcow2 -# Create a cloud-init ISO with network config +# Create a cloud-init ISO with network config and progress indication echo "Creating cloud-init ISO..." -mkisofs -output $VM-cidata.iso -volid CIDATA -rock user-data meta-data network-config +mkisofs -output $VM-cidata.iso -volid CIDATA -rock -verbose user-data meta-data network-config # Echo the configuration for verification -echo "Creating VM with the following network configuration:" +echo "Creating VM with the following configuration:" echo "VM Name: $VM" +echo "Disk Size: $DISK_SIZE" echo "IP Address: $IP" echo "Gateway: $GATEWAY" echo "DNS Servers: $DNS" From 0197cdb33d7aa9b11f99e5aa940c31faa322205d Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Thu, 9 Jan 2025 16:12:33 -0500 Subject: [PATCH 058/315] fix bridge forwarding on hypervisors bridge --- salt/firewall/iptables.jinja | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/salt/firewall/iptables.jinja b/salt/firewall/iptables.jinja index 074663e15..48a0808e7 100644 --- a/salt/firewall/iptables.jinja +++ b/salt/firewall/iptables.jinja @@ -91,6 +91,10 @@ COMMIT -A INPUT -m conntrack --ctstate INVALID -j DROP -A INPUT -p icmp -j ACCEPT -A INPUT -j LOGGING +{% if GLOBALS.role in ['so-hypervisor', 'so-managerhyper'] -%} +-A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT +-A FORWARD -i br0 -o br0 -j ACCEPT +{%- endif %} -A FORWARD -j DOCKER-USER -A FORWARD -j DOCKER-ISOLATION-STAGE-1 -A FORWARD -o sobridge -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT From 6888682f92c328a31c6566faa7cfeabc56b1ce6b Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Thu, 9 Jan 2025 16:14:01 -0500 Subject: [PATCH 059/315] add comments for raid scripts --- salt/hypervisor/raid.sh | 1 + salt/hypervisor/raid3.sh | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/salt/hypervisor/raid.sh b/salt/hypervisor/raid.sh index 031e4c522..b4539ba05 100644 --- a/salt/hypervisor/raid.sh +++ b/salt/hypervisor/raid.sh @@ -1,4 +1,5 @@ # quick script to create raid +# this is an example of the base functions parted -s /dev/nvme0n1 rm 1 parted -s /dev/nvme0n1 mklabel gpt parted -s /dev/nvme0n1 mkpart primary xfs 0% 100% diff --git a/salt/hypervisor/raid3.sh b/salt/hypervisor/raid3.sh index 8e7d6c7ae..4e5bd6c7f 100644 --- a/salt/hypervisor/raid3.sh +++ b/salt/hypervisor/raid3.sh @@ -1,5 +1,13 @@ #!/bin/bash +#raid3.sh is a refinement of raid2.sh. raid2.sh was used to create the raid in testing +#More detailed logging +#More thorough RAID array cleanup +#Better organized cleanup procedures +#Simplified device wiping using more modern tools (sgdisk instead of dd) +#More robust handling of existing MD arrays +#The core RAID creation and mounting functionality remains the same between both scripts, but the second version has improved error handling and cleanup procedures. + # Exit on any error set -e From ecc5d64584e5f895adf36428c30be04e8564aedf Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Thu, 9 Jan 2025 16:14:57 -0500 Subject: [PATCH 060/315] move logge def to global --- salt/hypervisor/tools/sbin/so-qcow2-modify-network | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/salt/hypervisor/tools/sbin/so-qcow2-modify-network b/salt/hypervisor/tools/sbin/so-qcow2-modify-network index 8829d3223..7920985b4 100644 --- a/salt/hypervisor/tools/sbin/so-qcow2-modify-network +++ b/salt/hypervisor/tools/sbin/so-qcow2-modify-network @@ -28,6 +28,13 @@ import configparser from io import StringIO from so_logging_utils import setup_logging +# Set up logging using the so_logging_utils library +logger = setup_logging( + logger_name='so-qcow2-modify-network', + log_file_path='/opt/so/log/hypervisor/so-qcow2-modify-network.log', + log_level=logging.INFO, + format_str='%(asctime)s - %(levelname)s - %(message)s' +) NETWORK_CONFIG_DIR = "/etc/NetworkManager/system-connections" @@ -161,13 +168,6 @@ def parse_arguments(): return args def main(): - # Set up logging using the so_logging_utils library - logger = setup_logging( - logger_name='so-qcow2-modify-network', - log_file_path='/opt/so/log/hypervisor/so-qcow2-modify-network.log', - log_level=logging.INFO, - format_str='%(asctime)s - %(levelname)s - %(message)s' - ) try: args = parse_arguments() From 574d2994d1524a5420eebbaece1bf028d30a2b29 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Thu, 9 Jan 2025 16:16:59 -0500 Subject: [PATCH 061/315] use cmd.run instead of cmd.script to resolve issue 64962 --- salt/libvirt/64962/init.sls | 13 ++++++++++--- .../{fix-salt-ldap.py => so-fix-salt-ldap.py} | 4 ++-- 2 files changed, 12 insertions(+), 5 deletions(-) rename salt/libvirt/64962/scripts/{fix-salt-ldap.py => so-fix-salt-ldap.py} (96%) diff --git a/salt/libvirt/64962/init.sls b/salt/libvirt/64962/init.sls index a6b13c3e5..e20f24f2d 100644 --- a/salt/libvirt/64962/init.sls +++ b/salt/libvirt/64962/init.sls @@ -2,10 +2,17 @@ python3_lief: pkg.installed: - name: securityonion-python3-lief +so-fix-salt-ldap_script: + file.managed: + - name: /usr/sbin/so-fix-salt-ldap.py + - source: salt://libvirt/64962/scripts/so-fix-salt-ldap.py + - mode: 744 + fix-salt-ldap: - cmd.script: - - source: salt://libvirt/64962/scripts/fix-salt-ldap.py + cmd.run: + - name: /usr/sbin/so-fix-salt-ldap.py - require: - pkg: python3_lief + - file: so-fix-salt-ldap_script - onchanges: - - pkg: python3_lief + - file: so-fix-salt-ldap_script diff --git a/salt/libvirt/64962/scripts/fix-salt-ldap.py b/salt/libvirt/64962/scripts/so-fix-salt-ldap.py similarity index 96% rename from salt/libvirt/64962/scripts/fix-salt-ldap.py rename to salt/libvirt/64962/scripts/so-fix-salt-ldap.py index 56fcce8aa..919b50261 100644 --- a/salt/libvirt/64962/scripts/fix-salt-ldap.py +++ b/salt/libvirt/64962/scripts/so-fix-salt-ldap.py @@ -1,5 +1,7 @@ #!/usr/bin/env python3 +# this script comes from the user nf-brentsaner located here https://github.com/saltstack/salt/issues/64962 + import datetime import grp import os @@ -11,8 +13,6 @@ import dbus # dnf -y install python3-dbus ## import lief # https://pypi.org/project/lief/ -# https://github.com/saltstack/salt/issues/64962 - salt_root = pathlib.Path('/opt/saltstack') src_lib = pathlib.Path('/lib64/libldap.so.2') dst_lib = salt_root.joinpath('salt', 'lib', 'libldap.so.2') From ebbfcd169c17faad440931a1eaef68369a83d7a5 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Thu, 9 Jan 2025 16:17:50 -0500 Subject: [PATCH 062/315] add pkg required for so-qcow2-modify-network --- salt/libvirt/packages.sls | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/salt/libvirt/packages.sls b/salt/libvirt/packages.sls index c79f42dd8..4de30568a 100644 --- a/salt/libvirt/packages.sls +++ b/salt/libvirt/packages.sls @@ -28,6 +28,11 @@ install_xorriso: install_virt-install: pkg.installed: - name: virt-install + +# needed for for so-qcow2-modify-network - import guestfs +install_python3-libguestfs: + pkg.installed: + - name: python3-libguestfs ### libvirt_python_wheel: From d677dc51de4d39f6ba75fd795d0a13ef3aeb21b5 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Thu, 9 Jan 2025 16:19:23 -0500 Subject: [PATCH 063/315] add comment about reactors required by salt-master --- salt/salt/master.sls | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/salt/salt/master.sls b/salt/salt/master.sls index 17e818503..7e823f4e8 100644 --- a/salt/salt/master.sls +++ b/salt/salt/master.sls @@ -52,23 +52,21 @@ salt_master_service: - file: engines_config - order: last +{# # we need to managed adding the following to salt-master config if there are hypervisors -#reactor: +reactor: + - 'salt/auth/accept/*': + - salt://reactor/check_hypervisor.sls #- salt/cloud/*/creating': #- salt/cloud/*/requesting -# - 'salt/cloud/*/deploying': -# - /opt/so/saltstack/default/salt/reactor/createEmptyPillar.sls -## - 'salt/cloud/*/created': -## - /opt/so/saltstack/default/salt/reactor/setSalt.sls -## - /opt/so/saltstack/default/salt/reactor/setHostname.sls -## - /opt/so/saltstack/default/salt/reactor/sominion.sls -# - 'setup/so-minion': -# - /opt/so/saltstack/default/salt/reactor/sominion_setup.sls -# - /opt/so/saltstack/default/salt/reactor/virtUpdate.sls -# - 'salt/cloud/*/destroyed': -# - /opt/so/saltstack/default/salt/reactor/virtReleaseHardware.sls -# - /opt/so/saltstack/default/salt/reactor/deleteKey.sls - + - 'salt/cloud/*/deploying': + - /opt/so/saltstack/default/salt/reactor/createEmptyPillar.sls + - 'setup/so-minion': + - /opt/so/saltstack/default/salt/reactor/sominion_setup.sls + - 'salt/cloud/*/destroyed': + - /opt/so/saltstack/default/salt/reactor/virtReleaseHardware.sls + - /opt/so/saltstack/default/salt/reactor/deleteKey.sls +#} {% else %} From 2ba8a87c9db952459b337958df8a9d44e91b0f5a Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Thu, 9 Jan 2025 16:20:56 -0500 Subject: [PATCH 064/315] add directory where qcow2 images will be distributed from --- salt/libvirt/images/coreol9Small/README | 1 + salt/libvirt/images/init.sls | 6 ++++++ 2 files changed, 7 insertions(+) create mode 100644 salt/libvirt/images/coreol9Small/README create mode 100644 salt/libvirt/images/init.sls diff --git a/salt/libvirt/images/coreol9Small/README b/salt/libvirt/images/coreol9Small/README new file mode 100644 index 000000000..28d066458 --- /dev/null +++ b/salt/libvirt/images/coreol9Small/README @@ -0,0 +1 @@ +# The files in this directory (/opt/so/saltstack/local/salt/libvirt/images/coreol9Small) are generated by createvm.sh. They are then distributed to the hypervisors where a storage pool will be created then the image can be installed. diff --git a/salt/libvirt/images/init.sls b/salt/libvirt/images/init.sls new file mode 100644 index 000000000..605af2368 --- /dev/null +++ b/salt/libvirt/images/init.sls @@ -0,0 +1,6 @@ +# the source location will be /opt/so/saltstack/local/salt/libvirt/imaages/coreol9Small +# this will need to change to save the images to /nsm +baseimagefiles: + file.recurse: + - name: /var/lib/libvirt/images/coreol9Small/ + - source: salt://libvirt/images/coreol9Small/ From 3cac19d4987256de2458256b77b55c32e3ce61e3 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Thu, 9 Jan 2025 16:31:51 -0500 Subject: [PATCH 065/315] createvm script without setting network in base domain --- salt/libvirt/scripts/createvm2.sh | 144 ++++++++++++++++++++++++++++++ 1 file changed, 144 insertions(+) create mode 100644 salt/libvirt/scripts/createvm2.sh diff --git a/salt/libvirt/scripts/createvm2.sh b/salt/libvirt/scripts/createvm2.sh new file mode 100644 index 000000000..b2be0d5b4 --- /dev/null +++ b/salt/libvirt/scripts/createvm2.sh @@ -0,0 +1,144 @@ +#!/bin/bash + +# Ensure /root/create_vm/var/lib/libvirt/images exists +# Place this script in /root/create_vm +# Download OL9U5_x86_64-kvm-b253.qcow2 from https://yum.oracle.com/oracle-linux-templates.html, place in /root/create_vm/ + +# These steps will be removed from the process to create the final image and is being used for development +# This is used for the user-data auth portion of cloud-init +# Create passwd hash: +# python3 -c 'import crypt; print(crypt.crypt("YOUR_PASSWD_HERE", crypt.mksalt(crypt.METHOD_SHA512)))' +# Create ssh keypair: +# ssh-keygen -t ed25519 -C "soqemussh" -f ~/.ssh/soqemussh + +# Run the script: createbase.sh coreol9Small 20G +# After running the script, the following will be output: +#[root@jppvirtman create_vm]# ll var/lib/libvirt/images/coreol9Small/ +#total 610376 +#-rw-r--r--. 1 root root 380928 Dec 20 14:33 coreol9Small-cidata.iso +#-rw-r--r--. 1 root root 624623616 Dec 20 14:33 coreol9Small.qcow2 +#-rw-r--r--. 1 root root 55 Dec 20 14:32 meta-data +#-rw-r--r--. 1 root root 1047 Dec 20 14:32 user-data + +# These files are now scp to a hypervisor node +# Place the files in /var/lib/libvirt/images/coreol9Small (or whatever is the same as the vm name) +# Create your storage pool as instructed by the script if one doesn't already exist +# Run the virt-install command as instructed by the script + +# Exit on any error +set -e + +# Set variables and defaults +VM=${1:-"base-vm"} # VM name +DISK_SIZE=${2:-"220G"} # Disk size with unit (default 20G) + +# Show usage if help is requested +if [[ "$1" == "-h" || "$1" == "--help" ]]; then + echo "Usage: $0 " + echo "Example: $0 myvm 20G" + echo "Parameters:" + echo " vm_name : Name of the VM (default: base-vm)" + echo " disk_size : Size of the disk with unit G/M (default: 20G)" + echo "All parameters are optional and will use defaults if not specified" + exit 0 +fi + +# Validate disk size format +if ! [[ $DISK_SIZE =~ ^[0-9]+[GM]$ ]]; then + echo "Error: Disk size must be a number followed by G (gigabytes) or M (megabytes)" + echo "Example: 20G or 20480M" + exit 1 +fi + +# Set up directory structure +#D=/root/create_vm/var/lib/libvirt/images +D=/opt/so/saltstack/local/salt/libvirt/images +mkdir -vp $D/$VM +cd $D/$VM + +# Create cloud-init metadata +cat > meta-data << EOF +instance-id: ${VM} +local-hostname: ${VM} +EOF + +# Create user-data configuration +cat > user-data << EOF +#cloud-config +preserve_hostname: False +hostname: ${VM} +fqdn: ${VM}.local + +users: + - default + - name: soqemussh + groups: ['wheel'] + shell: /bin/bash + sudo: ALL=(ALL) NOPASSWD:ALL + lock_passwd: false + passwd: $(echo '___YOUR_HASH_HERE___') + ssh-authorized-keys: + - ssh-ed25519 ___YOUR_PUB_KEY_HERE___ soqemussh + +# Configure where output will go +output: + all: ">> /var/log/cloud-init.log" + +# configure interaction with ssh server +ssh_genkeytypes: ['ed25519', 'rsa'] + +# set timezone for VM +timezone: UTC + +# Install QEMU guest agent. Enable and start the service +packages: + - qemu-guest-agent + +runcmd: + - systemctl enable --now qemu-guest-agent + - systemctl enable --now serial-getty@ttyS0.service + - systemctl enable --now NetworkManager + - growpart /dev/vda 2 + - pvresize /dev/vda2 + - lvextend -l +100%FREE /dev/vg_main/lv_root + - xfs_growfs /dev/vg_main/lv_root + - touch /etc/cloud/cloud-init.disabled + - shutdown -P now +EOF + +# First, copy the base image with progress +echo "Creating base VM image..." +rsync --progress /root/create_vm/OL9U5_x86_64-kvm-b253.qcow2 $VM.qcow2 + +# Resize the image to specified size +echo "Resizing image to $DISK_SIZE..." +echo "Current image size: $(qemu-img info $VM.qcow2 | grep 'virtual size' | cut -d':' -f2 | cut -d'(' -f1 | tr -d ' ')" +qemu-img resize -f qcow2 $VM.qcow2 $DISK_SIZE +echo "New image size: $(qemu-img info $VM.qcow2 | grep 'virtual size' | cut -d':' -f2 | cut -d'(' -f1 | tr -d ' ')" + +# Now compress it with progress +echo "Compressing image..." +qemu-img convert -p -O qcow2 -c $VM.qcow2 $VM-compressed.qcow2 +mv -v $VM-compressed.qcow2 $VM.qcow2 + +# Create a cloud-init ISO with progress indication +echo "Creating cloud-init ISO..." +mkisofs -output $VM-cidata.iso -volid CIDATA -rock -verbose user-data meta-data + +# Echo the configuration for verification +echo "Creating VM with the following configuration:" +echo "VM Name: $VM" +echo "Disk Size: $DISK_SIZE" + +echo "Files have been created in $D/$VM" +echo +echo "To complete VM creation on the hypervisor, run:" +echo "virsh pool-create-as --name $VM --type dir --target $D/$VM" +echo "virt-install --name ${VM} \\" +echo " --memory 4096 --vcpus 4 --cpu host \\" +echo " --disk ${VM}.qcow2,format=qcow2,bus=virtio \\" +echo " --disk ${VM}-cidata.iso,device=cdrom \\" +echo " --network bridge=br0,model=virtio \\" +echo " --os-variant=ol9.5 \\" +echo " --import \\" +echo " --noautoconsole" From 776afa4a3638d8dfeb3ea6d8fa1bc2f8965c63c4 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Thu, 9 Jan 2025 16:32:41 -0500 Subject: [PATCH 066/315] setup items on manager when hypervisor joins the grid --- salt/manager/hypervisor/directories.sls | 11 +++++ salt/orch/setup_hypervisor.sls | 66 +++++++++++++++++++++++++ salt/reactor/check_hypervisor.sls | 6 +++ 3 files changed, 83 insertions(+) create mode 100644 salt/manager/hypervisor/directories.sls create mode 100644 salt/orch/setup_hypervisor.sls create mode 100644 salt/reactor/check_hypervisor.sls diff --git a/salt/manager/hypervisor/directories.sls b/salt/manager/hypervisor/directories.sls new file mode 100644 index 000000000..3f60492f6 --- /dev/null +++ b/salt/manager/hypervisor/directories.sls @@ -0,0 +1,11 @@ +{% set dirs = [ + '/nsm/libvirt/createvm' +] %} + +create_libvirt_dirs: + file.directory: + - names: {{ dirs }} + - makedirs: True + - mode: 755 + - user: root + - group: root diff --git a/salt/orch/setup_hypervisor.sls b/salt/orch/setup_hypervisor.sls new file mode 100644 index 000000000..a79e07ee5 --- /dev/null +++ b/salt/orch/setup_hypervisor.sls @@ -0,0 +1,66 @@ +{% set qcow2_url = 'https://yum.oracle.com/templates/OracleLinux/OL9/u5/x86_64/OL9U5_x86_64-kvm-b253.qcow2' %} +{% set expected_sha256 = '3b00bbbefc8e78dd28d9f538834fb9e2a03d5ccdc2cadf2ffd0036c0a8f02021' %} +{% set target_path = '/nsm/libvirt/createvm/OL9U5_x86_64-kvm-b253.qcow2' %} +{% set master_id = salt.local.opts.get('id') %} + +createvm_directories: + salt.state: + - tgt: {{ master_id }} + - sls: + - manager.hypervisor.directories + +check_qcow2_exists: + salt.function: + - name: file.file_exists + - tgt: {{ master_id }} + - arg: + - {{ target_path }} + - require: + - salt: createvm_directories + +download_qcow2: + salt.function: + - name: cmd.run + - tgt: {{ master_id }} + - arg: + - curl -L {{ qcow2_url }} -o {{ target_path }} + - onlyif: + - fun: file.file_exists + tgt: {{ master_id }} + arg: + - {{ target_path }} + expected: False + +verify_checksum: + salt.function: + - name: cmd.run_all + - tgt: {{ master_id }} + - arg: + - echo "{{ expected_sha256 }} {{ target_path }}" | sha256sum -c + - require: + - salt: download_qcow2 + - onlyif: + - fun: file.file_exists + tgt: {{ master_id }} + arg: + - {{ target_path }} + +handle_failed_verification: + salt.function: + - name: log.error + - tgt: {{ master_id }} + - arg: + - "Checksum verification failed for {{ target_path }}" + - onfail: + - salt: verify_checksum + +cleanup_failed_download: + salt.function: + - name: file.remove + - tgt: {{ master_id }} + - arg: + - {{ target_path }} + - onfail: + - salt: verify_checksum + - require: + - salt: verify_checksum diff --git a/salt/reactor/check_hypervisor.sls b/salt/reactor/check_hypervisor.sls new file mode 100644 index 000000000..b26b6d0dd --- /dev/null +++ b/salt/reactor/check_hypervisor.sls @@ -0,0 +1,6 @@ +{% if data['id'].endswith(('_hypervisor', '_managerhyper')) %} +check_and_trigger: + runner.state.orchestrate: + - args: + - mods: orch.setup_hypervisor +{% endif %} From 2e3c1adc63096db99e8cc8ec23ed241ab4bd721d Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Tue, 14 Jan 2025 16:20:21 -0500 Subject: [PATCH 067/315] runner to setup manager for first hypervisor --- salt/_runners/setup_hypervisor.py | 585 ++++++++++++++++++++++++ salt/manager/hypervisor/directories.sls | 11 - salt/orch/setup_hypervisor.sls | 66 --- salt/reactor/check_hypervisor.sls | 4 +- 4 files changed, 586 insertions(+), 80 deletions(-) create mode 100644 salt/_runners/setup_hypervisor.py delete mode 100644 salt/manager/hypervisor/directories.sls delete mode 100644 salt/orch/setup_hypervisor.sls diff --git a/salt/_runners/setup_hypervisor.py b/salt/_runners/setup_hypervisor.py new file mode 100644 index 000000000..e444b739a --- /dev/null +++ b/salt/_runners/setup_hypervisor.py @@ -0,0 +1,585 @@ +""" +This runner performs the initial setup required for hypervisor hosts in the environment. +It handles downloading the Oracle Linux KVM image, setting up SSH keys for secure +communication, and creating the initial VM. + +Functions: + setup_environment: Downloads image, sets up SSH keys, and creates initial VM + regenerate_ssh_keys: Regenerates SSH keys for remote access + create_vm: Creates a new VM with cloud-init configuration + +The runner is typically triggered automatically when a new hypervisor minion connects, +but can also be run manually if needed. + +CLI Examples: + + # Perform complete environment setup (creates VM named 'so-ol9' with 220G disk by default) + salt-run setup_hypervisor.setup_environment + + # Setup with custom VM name (uses default 220G disk) + salt-run setup_hypervisor.setup_environment myvm + + # Setup with custom VM name and disk size + salt-run setup_hypervisor.setup_environment myvm 300G + + # Regenerate SSH keys only + salt-run setup_hypervisor.regenerate_ssh_keys + + # Create additional VM with default disk size (220G) + salt-run setup_hypervisor.create_vm myvm2 + + # Create additional VM with custom disk size + salt-run setup_hypervisor.create_vm myvm3 300G +""" + +import hashlib +import logging +import os +import pwd +import requests +import salt.utils.files +import sys +import time +from cryptography.hazmat.primitives import serialization +from cryptography.hazmat.primitives.asymmetric import ed25519 + +# Configure logging +log = logging.getLogger(__name__) +log.setLevel(logging.DEBUG) + +# Ensure we have a stream handler +stream_handler = logging.StreamHandler(sys.stdout) +stream_handler.setLevel(logging.DEBUG) +formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') +stream_handler.setFormatter(formatter) +log.addHandler(stream_handler) + +def _check_file_exists(path): + """Check if a file exists and create its directory if needed.""" + if os.path.exists(path): + return True + os.makedirs(os.path.dirname(path), exist_ok=True) + return False + +def _validate_image_checksum(path, expected_sha256): + """ + Validate the checksum of an existing image file. + Returns: + bool: True if checksum matches, False otherwise + """ + sha256_hash = hashlib.sha256() + with salt.utils.files.fopen(path, 'rb') as f: + for chunk in iter(lambda: f.read(4096), b''): + sha256_hash.update(chunk) + + downloaded_sha256 = sha256_hash.hexdigest() + if downloaded_sha256 != expected_sha256: + log.error("VALIDATE: Checksum validation failed for %s - expected: %s, got: %s", + path, expected_sha256, downloaded_sha256) + return False + + log.info("VALIDATE: Checksum validation successful for %s", path) + return True + +# Constants +IMAGE_URL = "https://yum.oracle.com/templates/OracleLinux/OL9/u5/x86_64/OL9U5_x86_64-kvm-b253.qcow2" +IMAGE_SHA256 = "3b00bbbefc8e78dd28d9f538834fb9e2a03d5ccdc2cadf2ffd0036c0a8f02021" +IMAGE_PATH = "/nsm/libvirt/boot/OL9U5_x86_64-kvm-b253.qcow2" + +def _download_image(): + """ + Download and validate the Oracle Linux KVM image. + Returns: + bool: True if successful or file exists with valid checksum, False on error + """ + # Check if file already exists and validate checksum + if _check_file_exists(IMAGE_PATH): + if _validate_image_checksum(IMAGE_PATH, IMAGE_SHA256): + return True + else: + log.warning("DOWNLOAD: Existing image has invalid checksum, will re-download") + os.unlink(IMAGE_PATH) + + log.info("DOWNLOAD: Starting image download process") + + try: + # Download file + log.info("DOWNLOAD: Downloading Oracle Linux KVM image from %s to %s", IMAGE_URL, IMAGE_PATH) + response = requests.get(IMAGE_URL, stream=True) + response.raise_for_status() + + # Get total file size for progress tracking + total_size = int(response.headers.get('content-length', 0)) + downloaded_size = 0 + last_log_time = 0 + + # Save file with progress logging + with salt.utils.files.fopen(IMAGE_PATH, 'wb') as f: + for chunk in response.iter_content(chunk_size=8192): + f.write(chunk) + downloaded_size += len(chunk) + + # Log progress every second + current_time = time.time() + if current_time - last_log_time >= 1: + progress = (downloaded_size / total_size) * 100 if total_size > 0 else 0 + log.info("DOWNLOAD: Progress - %.1f%% (%d/%d bytes)", + progress, downloaded_size, total_size) + last_log_time = current_time + + # Validate downloaded file + if not _validate_image_checksum(IMAGE_PATH, IMAGE_SHA256): + os.unlink(IMAGE_PATH) + return False + + log.info("DOWNLOAD: Successfully downloaded and validated Oracle Linux KVM image") + return True + + except Exception as e: + log.error("DOWNLOAD: Error downloading hypervisor image: %s", str(e)) + if os.path.exists(IMAGE_PATH): + os.unlink(IMAGE_PATH) + return False + +def _check_ssh_keys_exist(): + """ + Check if SSH keys already exist. + Returns: + bool: True if both private and public keys exist, False otherwise + """ + key_dir = '/etc/ssh/auth_keys/soqemussh' + key_path = f'{key_dir}/id_ed25519' + pub_key_path = f'{key_path}.pub' + dest_dir = '/opt/so/saltstack/local/salt/libvirt/ssh/keys' + dest_path = os.path.join(dest_dir, os.path.basename(pub_key_path)) + + if os.path.exists(key_path) and os.path.exists(pub_key_path) and os.path.exists(dest_path): + log.info("SETUP_KEYS: SSH keys already exist") + return True + return False + +def _setup_ssh_keys(): + """ + Generate and set up SSH keys. + Returns: + bool: True if successful, False on error + """ + try: + key_dir = '/etc/ssh/auth_keys/soqemussh' + key_path = f'{key_dir}/id_ed25519' + pub_key_path = f'{key_path}.pub' + + # Check if keys already exist + if _check_ssh_keys_exist(): + return True + + # Create key directories if they don't exist and set permissions + log.info("SETUP_KEYS: Setting up SSH directory and keys") + parent_dir = os.path.dirname(key_dir) # /etc/ssh/auth_keys + os.makedirs(parent_dir, exist_ok=True) + os.chmod(parent_dir, 0o700) + + os.makedirs(key_dir, exist_ok=True) + os.chmod(key_dir, 0o700) + + # Generate new ed25519 key pair + log.info("SETUP_KEYS: Generating new SSH keys") + private_key = ed25519.Ed25519PrivateKey.generate() + public_key = private_key.public_key() + + # Serialize private key + private_bytes = private_key.private_bytes( + encoding=serialization.Encoding.PEM, + format=serialization.PrivateFormat.OpenSSH, + encryption_algorithm=serialization.NoEncryption() + ) + + # Serialize public key and format it as an OpenSSH public key + public_bytes = public_key.public_bytes( + encoding=serialization.Encoding.OpenSSH, + format=serialization.PublicFormat.OpenSSH + ) + public_bytes = public_bytes + b' soqemussh@salt-master\n' + + # Write the keys to files + with salt.utils.files.fopen(key_path, 'wb') as f: + f.write(private_bytes) + + with salt.utils.files.fopen(pub_key_path, 'wb') as f: + f.write(public_bytes) + + # Set proper permissions + os.chmod(key_path, 0o600) + os.chmod(pub_key_path, 0o644) + + log.info("SETUP_KEYS: SSH keys generated successfully") + + # Copy public key to saltstack directory + dest_dir = '/opt/so/saltstack/local/salt/libvirt/ssh/keys' + os.makedirs(dest_dir, exist_ok=True) + dest_path = os.path.join(dest_dir, os.path.basename(pub_key_path)) + + with salt.utils.files.fopen(pub_key_path, 'rb') as src: + with salt.utils.files.fopen(dest_path, 'wb') as dst: + dst.write(src.read()) + + log.info("SETUP_KEYS: Public key copied to %s", dest_dir) + return True + + except Exception as e: + log.error("SETUP_KEYS: Error setting up SSH keys: %s", str(e)) + return False + +def _check_vm_exists(vm_name: str) -> bool: + """ + Check if VM files already exist. + Returns: + bool: True if VM files exist, False otherwise + """ + base_dir = '/opt/so/saltstack/local/salt/libvirt/images' + vm_dir = f'{base_dir}/{vm_name}' + vm_image = os.path.join(vm_dir, f'{vm_name}.qcow2') + cidata_iso = os.path.join(vm_dir, f'{vm_name}-cidata.iso') + + required_files = [ + vm_image, + cidata_iso, + os.path.join(vm_dir, 'meta-data'), + os.path.join(vm_dir, 'user-data') + ] + + exists = all(os.path.exists(f) for f in required_files) + if exists: + log.info("MAIN: VM %s already exists", vm_name) + return exists + +def setup_environment(vm_name: str = 'so-ol9', disk_size: str = '220G'): + """ + Main entry point to set up the hypervisor environment. + This includes downloading the base image, generating SSH keys for remote access, + and creating the initial VM. + + Args: + vm_name (str, optional): Name of the VM to create as part of environment setup. + Defaults to 'so-ol9'. + disk_size (str, optional): Size of the VM disk with unit. + Defaults to '220G'. + + Returns: + dict: Dictionary containing setup status and VM creation results + """ + log.info("MAIN: Starting setup_environment in setup_hypervisor runner") + + # Check if environment is already set up + image_exists = _check_file_exists(IMAGE_PATH) + image_valid = image_exists and _validate_image_checksum(IMAGE_PATH, IMAGE_SHA256) + keys_exist = _check_ssh_keys_exist() + vm_exists = _check_vm_exists(vm_name) + + # Track if we need to create/recreate VM + create_vm_needed = False + + # Handle image setup if needed + if not image_valid: + log.info("MAIN: Starting image download/validation process") + if not _download_image(): + log.error("MAIN: Image download failed") + return { + 'success': False, + 'error': 'Image download failed', + 'vm_result': None + } + create_vm_needed = True + + # Handle SSH key setup if needed + if not keys_exist: + log.info("MAIN: Setting up SSH keys") + if not _setup_ssh_keys(): + log.error("MAIN: SSH key setup failed") + return { + 'success': False, + 'error': 'SSH key setup failed', + 'vm_result': None + } + create_vm_needed = True + + # Create/recreate VM if needed + if create_vm_needed or not vm_exists: + if vm_exists: + log.info("MAIN: Environment changes detected, recreating VM %s", vm_name) + else: + log.info("MAIN: Creating new VM %s", vm_name) + vm_result = create_vm(vm_name, disk_size) + else: + log.info("MAIN: No changes detected, using existing VM %s", vm_name) + vm_result = { + 'success': True, + 'vm_dir': f'/opt/so/saltstack/local/salt/libvirt/images/{vm_name}', + 'commands': [ + f"virsh pool-create-as --name {vm_name} --type dir --target /opt/so/saltstack/local/salt/libvirt/images/{vm_name}", + f"""virt-install --name {vm_name} \\ + --memory 4096 --vcpus 4 --cpu host \\ + --disk /opt/so/saltstack/local/salt/libvirt/images/{vm_name}/{vm_name}.qcow2,format=qcow2,bus=virtio \\ + --disk /opt/so/saltstack/local/salt/libvirt/images/{vm_name}/{vm_name}-cidata.iso,device=cdrom \\ + --network bridge=br0,model=virtio \\ + --os-variant=ol9.5 \\ + --import \\ + --noautoconsole""" + ] + } + + success = vm_result.get('success', False) + log.info("MAIN: Setup environment completed with status: %s", "SUCCESS" if success else "FAILED") + + return { + 'success': success, + 'error': vm_result.get('error') if not success else None, + 'vm_result': vm_result + } + +def create_vm(vm_name: str, disk_size: str = '220G'): + """ + Create a new VM with cloud-init configuration. + + Args: + vm_name (str): Name of the VM + disk_size (str): Size of the disk with unit (default: '220G') + + Returns: + dict: Dictionary containing success status and commands to run on hypervisor + """ + try: + # Input validation + if not isinstance(vm_name, str) or not vm_name: + log.error("CREATEVM: Invalid VM name") + return {'success': False, 'error': 'Invalid VM name'} + + if not vm_name.isalnum() and not all(c in '-_' for c in vm_name if not c.isalnum()): + log.error("CREATEVM: VM name must contain only alphanumeric characters, hyphens, or underscores") + return {'success': False, 'error': 'Invalid VM name format'} + + # Validate disk size format + if not isinstance(disk_size, str) or not disk_size.endswith(('G', 'M')): + log.error("CREATEVM: Invalid disk size format. Must end with G or M") + return {'success': False, 'error': 'Invalid disk size format'} + + try: + size_num = int(disk_size[:-1]) + if size_num <= 0: + raise ValueError + except ValueError: + log.error("CREATEVM: Invalid disk size number") + return {'success': False, 'error': 'Invalid disk size number'} + + # Ensure base image exists + if not os.path.exists(IMAGE_PATH): + log.error("CREATEVM: Base image not found at %s", IMAGE_PATH) + return {'success': False, 'error': 'Base image not found'} + + # Set up directory structure + base_dir = '/opt/so/saltstack/local/salt/libvirt/images' + vm_dir = f'{base_dir}/{vm_name}' + os.makedirs(vm_dir, exist_ok=True) + + # Read the SSH public key + pub_key_path = '/opt/so/saltstack/local/salt/libvirt/ssh/keys/id_ed25519.pub' + try: + with salt.utils.files.fopen(pub_key_path, 'r') as f: + ssh_pub_key = f.read().strip() + except Exception as e: + log.error("CREATEVM: Failed to read SSH public key: %s", str(e)) + return {'success': False, 'error': 'Failed to read SSH public key'} + + # Create meta-data + meta_data = f"""instance-id: {vm_name} +local-hostname: {vm_name} +""" + meta_data_path = os.path.join(vm_dir, 'meta-data') + with salt.utils.files.fopen(meta_data_path, 'w') as f: + f.write(meta_data) + + # Create user-data + user_data = f"""#cloud-config +preserve_hostname: False +hostname: {vm_name} +fqdn: {vm_name}.local + +users: + - default + - name: soqemussh + groups: ['wheel'] + shell: /bin/bash + sudo: ALL=(ALL) NOPASSWD:ALL + lock_passwd: false + passwd: $6$THWuTZMZhIVMGaaw$w9kozn7z7i0Y9LRVGZwN6mcZag4vMpE3hW6eCtKNHlFpL1XLcOdiIr29JyDxx3MLBXNedIqnqcj4psqCjv58d. + ssh-authorized-keys: + - {ssh_pub_key} + +# Configure where output will go +output: + all: ">> /var/log/cloud-init.log" + +# configure interaction with ssh server +ssh_genkeytypes: ['ed25519', 'rsa'] + +# set timezone for VM +timezone: UTC + +# Install QEMU guest agent. Enable and start the service +packages: + - qemu-guest-agent + +runcmd: + - systemctl enable --now qemu-guest-agent + - systemctl enable --now serial-getty@ttyS0.service + - systemctl enable --now NetworkManager + - growpart /dev/vda 2 + - pvresize /dev/vda2 + - lvextend -l +100%FREE /dev/vg_main/lv_root + - xfs_growfs /dev/vg_main/lv_root + - touch /etc/cloud/cloud-init.disabled + - shutdown -P now +""" + user_data_path = os.path.join(vm_dir, 'user-data') + with salt.utils.files.fopen(user_data_path, 'w') as f: + f.write(user_data) + + # Copy and resize base image + base_image = IMAGE_PATH + vm_image = os.path.join(vm_dir, f'{vm_name}.qcow2') + + # Copy base image with progress logging + import shutil + log.info("CREATEVM: Copying base image to %s", vm_image) + shutil.copy2(base_image, vm_image) + log.info("CREATEVM: Base image copy complete") + + # Get current image size + import subprocess + try: + result = subprocess.run(['qemu-img', 'info', '--output=json', vm_image], + check=True, capture_output=True, text=True) + import json + info = json.loads(result.stdout) + current_size = info.get('virtual-size', 0) + requested_size = int(disk_size[:-1]) * (1024**3 if disk_size.endswith('G') else 1024**2) + + # Only resize if requested size is larger + if requested_size > current_size: + log.info("CREATEVM: Resizing image to %s", disk_size) + try: + result = subprocess.run(['qemu-img', 'resize', '-f', 'qcow2', vm_image, disk_size], + check=True, capture_output=True, text=True) + log.info("CREATEVM: Image resize complete") + except subprocess.CalledProcessError as e: + log.error("CREATEVM: Failed to resize image: %s", e.stderr) + raise + else: + log.info("CREATEVM: Image already at or larger than requested size") + except subprocess.CalledProcessError as e: + log.error("CREATEVM: Failed to get image info: %s", e.stderr) + raise + except json.JSONDecodeError as e: + log.error("CREATEVM: Failed to parse image info: %s", str(e)) + raise + + # Compress image + temp_image = f"{vm_image}.temp" + log.info("CREATEVM: Compressing image") + + # Start compression in a subprocess + process = subprocess.Popen(['qemu-img', 'convert', '-O', 'qcow2', '-c', vm_image, temp_image], + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + + # Monitor progress by checking output file size + source_size = os.path.getsize(vm_image) + last_log_time = 0 + + while process.poll() is None: # While compression is running + current_time = time.time() + if current_time - last_log_time >= 1: # Log every second + if os.path.exists(temp_image): + compressed_size = os.path.getsize(temp_image) + progress = (compressed_size / source_size) * 100 + log.info("CREATEVM: Compression progress - %.1f%% (%d/%d bytes)", + progress, compressed_size, source_size) + last_log_time = current_time + + # Check if compression completed successfully + if process.returncode == 0: + os.replace(temp_image, vm_image) + log.info("CREATEVM: Image compression complete") + else: + error = process.stderr.read().decode('utf-8') + log.error("CREATEVM: Failed to compress image: %s", error) + if os.path.exists(temp_image): + os.unlink(temp_image) + raise subprocess.CalledProcessError(process.returncode, 'qemu-img convert', stderr=error) + + # Create cloud-init ISO + cidata_iso = os.path.join(vm_dir, f'{vm_name}-cidata.iso') + subprocess.run(['mkisofs', '-output', cidata_iso, '-volid', 'CIDATA', '-rock', + user_data_path, meta_data_path], + check=True, capture_output=True) + + # Generate commands for hypervisor + commands = [ + f"virsh pool-create-as --name {vm_name} --type dir --target {vm_dir}", + f"""virt-install --name {vm_name} \\ + --memory 4096 --vcpus 4 --cpu host \\ + --disk {vm_image},format=qcow2,bus=virtio \\ + --disk {cidata_iso},device=cdrom \\ + --network bridge=br0,model=virtio \\ + --os-variant=ol9.5 \\ + --import \\ + --noautoconsole""" + ] + + return { + 'success': True, + 'vm_dir': vm_dir, + 'commands': commands + } + + except Exception as e: + log.error("CREATEVM: Error creating VM: %s", str(e)) + return {'success': False, 'error': str(e)} + +def regenerate_ssh_keys(): + """ + Regenerate SSH keys. + Returns: + bool: True if successful, False on error + """ + log.info("MAIN: Starting SSH key regeneration") + try: + # Verify current state + if not _check_ssh_keys_exist(): + log.warning("MAIN: No existing SSH keys found to regenerate") + return _setup_ssh_keys() + + # Remove existing keys + key_dir = '/etc/ssh/auth_keys/soqemussh' + key_path = f'{key_dir}/id_ed25519' + pub_key_path = f'{key_path}.pub' + dest_dir = '/opt/so/saltstack/local/salt/libvirt/ssh/keys' + dest_path = os.path.join(dest_dir, os.path.basename(pub_key_path)) + + for path in [key_path, pub_key_path, dest_path]: + try: + os.unlink(path) + log.info("MAIN: Removed existing key: %s", path) + except FileNotFoundError: + log.warning("MAIN: Key file not found: %s", path) + + # Generate new keys + if _setup_ssh_keys(): + log.info("MAIN: SSH keys regenerated successfully") + return True + + log.error("MAIN: Failed to regenerate SSH keys") + return False + + except Exception as e: + log.error("MAIN: Error regenerating SSH keys: %s", str(e)) + return False diff --git a/salt/manager/hypervisor/directories.sls b/salt/manager/hypervisor/directories.sls deleted file mode 100644 index 3f60492f6..000000000 --- a/salt/manager/hypervisor/directories.sls +++ /dev/null @@ -1,11 +0,0 @@ -{% set dirs = [ - '/nsm/libvirt/createvm' -] %} - -create_libvirt_dirs: - file.directory: - - names: {{ dirs }} - - makedirs: True - - mode: 755 - - user: root - - group: root diff --git a/salt/orch/setup_hypervisor.sls b/salt/orch/setup_hypervisor.sls deleted file mode 100644 index a79e07ee5..000000000 --- a/salt/orch/setup_hypervisor.sls +++ /dev/null @@ -1,66 +0,0 @@ -{% set qcow2_url = 'https://yum.oracle.com/templates/OracleLinux/OL9/u5/x86_64/OL9U5_x86_64-kvm-b253.qcow2' %} -{% set expected_sha256 = '3b00bbbefc8e78dd28d9f538834fb9e2a03d5ccdc2cadf2ffd0036c0a8f02021' %} -{% set target_path = '/nsm/libvirt/createvm/OL9U5_x86_64-kvm-b253.qcow2' %} -{% set master_id = salt.local.opts.get('id') %} - -createvm_directories: - salt.state: - - tgt: {{ master_id }} - - sls: - - manager.hypervisor.directories - -check_qcow2_exists: - salt.function: - - name: file.file_exists - - tgt: {{ master_id }} - - arg: - - {{ target_path }} - - require: - - salt: createvm_directories - -download_qcow2: - salt.function: - - name: cmd.run - - tgt: {{ master_id }} - - arg: - - curl -L {{ qcow2_url }} -o {{ target_path }} - - onlyif: - - fun: file.file_exists - tgt: {{ master_id }} - arg: - - {{ target_path }} - expected: False - -verify_checksum: - salt.function: - - name: cmd.run_all - - tgt: {{ master_id }} - - arg: - - echo "{{ expected_sha256 }} {{ target_path }}" | sha256sum -c - - require: - - salt: download_qcow2 - - onlyif: - - fun: file.file_exists - tgt: {{ master_id }} - arg: - - {{ target_path }} - -handle_failed_verification: - salt.function: - - name: log.error - - tgt: {{ master_id }} - - arg: - - "Checksum verification failed for {{ target_path }}" - - onfail: - - salt: verify_checksum - -cleanup_failed_download: - salt.function: - - name: file.remove - - tgt: {{ master_id }} - - arg: - - {{ target_path }} - - onfail: - - salt: verify_checksum - - require: - - salt: verify_checksum diff --git a/salt/reactor/check_hypervisor.sls b/salt/reactor/check_hypervisor.sls index b26b6d0dd..fdf75453d 100644 --- a/salt/reactor/check_hypervisor.sls +++ b/salt/reactor/check_hypervisor.sls @@ -1,6 +1,4 @@ {% if data['id'].endswith(('_hypervisor', '_managerhyper')) %} check_and_trigger: - runner.state.orchestrate: - - args: - - mods: orch.setup_hypervisor + runner.setup_hypervisor.setup_environment: [] {% endif %} From 161e8a6c2199e082018ffd4809e63dc2152ca189 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Tue, 14 Jan 2025 16:21:17 -0500 Subject: [PATCH 068/315] ssh config for manager. dont need to create soqemussh user on manager --- salt/libvirt/ssh/files/config | 2 +- salt/libvirt/ssh/users.sls | 47 +++++++++-------------------------- 2 files changed, 13 insertions(+), 36 deletions(-) diff --git a/salt/libvirt/ssh/files/config b/salt/libvirt/ssh/files/config index 25af86b73..360d5c182 100644 --- a/salt/libvirt/ssh/files/config +++ b/salt/libvirt/ssh/files/config @@ -1,2 +1,2 @@ Host * - IdentityFile /home/soqemussh/.ssh/id_ed25519 + IdentityFile /etc/ssh/auth_keys/soqemussh/id_ed25519 diff --git a/salt/libvirt/ssh/users.sls b/salt/libvirt/ssh/users.sls index a893b9a7d..f0e30caec 100644 --- a/salt/libvirt/ssh/users.sls +++ b/salt/libvirt/ssh/users.sls @@ -5,44 +5,10 @@ {% from 'vars/globals.map.jinja' import GLOBALS %} -# used for qemu+ssh connection between manager and hypervisors -create_soqemussh_user: - user.present: - - name: soqemussh - - shell: /bin/bash - - home: /home/soqemussh -{% if not GLOBALS.is_manager %} - - groups: - - wheel - - qemu - - libvirt -{% endif %} + {% if GLOBALS.is_manager %} -create_local_libvirt_ssh_key_dir: - file.directory: - - name: /opt/so/saltstack/local/salt/libvirt/ssh/keys - - user: socore - - group: socore - - mode: 755 - - makedirs: True - -# generate the key pair and put the pub key in salt local files roots -generate_ssh_key_soqemussh: - cmd.run: - - name: ssh-keygen -q -N '' -t ed25519 -f /home/soqemussh/.ssh/id_ed25519 - - runas: soqemussh - - unless: test -f /home/soqemussh/.ssh/id_ed25519 - - require: - - user: create_soqemussh_user - -soqemussh_ssh_key_to_local: - cmd.run: - - name: cp /home/soqemussh/.ssh/id_ed25519.pub /opt/so/saltstack/local/salt/libvirt/ssh/keys - - onchanges: - - cmd: generate_ssh_key_soqemussh - qemu_ssh_client_config: file.managed: - name: /root/.ssh/config @@ -50,6 +16,17 @@ qemu_ssh_client_config: {% else %} +# used for qemu+ssh connection between manager and hypervisors +create_soqemussh_user: + user.present: + - name: soqemussh + - shell: /bin/bash + - home: /home/soqemussh + - groups: + - wheel + - qemu + - libvirt + soqemussh_pub_key: ssh_auth.present: - user: soqemussh From 01ac1cdccacd7d43cb2a2afaf7ec8ff6a6e96231 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Wed, 15 Jan 2025 14:13:12 -0500 Subject: [PATCH 069/315] check features and allowed/states --- salt/allowed_states.map.jinja | 4 +- salt/hypervisor/init.sls | 33 ++++++++++++ salt/libvirt/init.sls | 32 +++++++++-- salt/libvirt/packages.sls | 51 ++++++++++++++---- salt/libvirt/ssh/users.sls | 37 ++++++++++--- salt/reactor/check_hypervisor.sls | 2 +- salt/salt/cloud/init.sls | 31 ++++++++--- salt/salt/cloud/reactor_config_hypervisor.sls | 53 +++++++++++++++++++ salt/salt/master.sls | 13 +++-- 9 files changed, 226 insertions(+), 30 deletions(-) create mode 100644 salt/salt/cloud/reactor_config_hypervisor.sls diff --git a/salt/allowed_states.map.jinja b/salt/allowed_states.map.jinja index 07c677ba6..25cae50a7 100644 --- a/salt/allowed_states.map.jinja +++ b/salt/allowed_states.map.jinja @@ -86,6 +86,7 @@ 'so-manager': [ 'salt.master', 'salt.cloud', + 'libvirt', 'ca', 'ssl', 'registry', @@ -206,7 +207,8 @@ 'firewall', 'schedule', 'docker_clean', - 'stig' + 'stig', + 'hypervisor' ], 'so-desktop': [ 'ssl', diff --git a/salt/hypervisor/init.sls b/salt/hypervisor/init.sls index 3fa63bbcb..7bec6f25c 100644 --- a/salt/hypervisor/init.sls +++ b/salt/hypervisor/init.sls @@ -1,3 +1,18 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. +# +# Note: Per the Elastic License 2.0, the second limitation states: +# +# "You may not move, change, disable, or circumvent the license key functionality +# in the software, and you may not remove or obscure any functionality in the +# software that is protected by the license key." + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls in allowed_states %} +{% if 'hvn' in salt['pillar.get']('features', []) %} + hypervisor_log_dir: file.directory: - name: /opt/so/log/hypervisor @@ -7,3 +22,21 @@ hypervisor_sbin: - name: /usr/sbin - source: salt://hypervisor/tools/sbin - file_mode: 744 + +{% else %} +{{sls}}_no_license_detected: + test.fail_without_changes: + - name: {{sls}}_no_license_detected + - comment: + - "Hypervisor nodes are a feature supported only for customers with a valid license. + Contact Security Onion Solutions, LLC via our website at https://securityonionsolutions.com + for more information about purchasing a license to enable this feature." +{% endif %} + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/libvirt/init.sls b/salt/libvirt/init.sls index dae0ed2bd..b0c131330 100644 --- a/salt/libvirt/init.sls +++ b/salt/libvirt/init.sls @@ -1,9 +1,18 @@ # Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one -# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at # https://securityonion.net/license; you may not use this file except in compliance with the # Elastic License 2.0. +# +# Note: Per the Elastic License 2.0, the second limitation states: +# +# "You may not move, change, disable, or circumvent the license key functionality +# in the software, and you may not remove or obscure any functionality in the +# software that is protected by the license key." -{% from 'libvirt/map.jinja' import LIBVIRTMERGED %} +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls in allowed_states %} +{% if 'hvn' in salt['pillar.get']('features', []) %} +{% from 'libvirt/map.jinja' import LIBVIRTMERGED %} include: - libvirt.64962 @@ -94,6 +103,23 @@ down_original_mgmt_interface: - nmcli -f GENERAL.CONNECTION dev show {{ pillar.host.mainint }} | grep bridge-slave-{{ pillar.host.mainint }} - order: last - # virtlogd service may not restart following reboot without this #semanage permissive -a virtlogd_t + +{% else %} +{{sls}}_no_license_detected: + test.fail_without_changes: + - name: {{sls}}_no_license_detected + - comment: + - "Hypervisor nodes are a feature supported only for customers with a valid license. + Contact Security Onion Solutions, LLC via our website at https://securityonionsolutions.com + for more information about purchasing a license to enable this feature." +{% endif %} + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/libvirt/packages.sls b/salt/libvirt/packages.sls index 4de30568a..5f4b343a7 100644 --- a/salt/libvirt/packages.sls +++ b/salt/libvirt/packages.sls @@ -1,6 +1,25 @@ -#libvirt_source-packages_dir: - # file.directory: - # - name: /opt/so/conf/libvirt/source-packages +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. +# +# Note: Per the Elastic License 2.0, the second limitation states: +# +# "You may not move, change, disable, or circumvent the license key functionality +# in the software, and you may not remove or obscure any functionality in the +# software that is protected by the license key." + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} +{% if 'hvn' in salt['pillar.get']('features', []) %} + +# allows for creating vm images +# any node manipulating images needs this +install_qemu-img: + pkg.installed: + - name: qemu-img + +{% if 'hyper' in grains.id.split('_') | last %} install_libvirt-libs: pkg.installed: @@ -11,12 +30,6 @@ install_libvirt-client: pkg.installed: - name: libvirt-client -# allows for creating vm images -# any node manipulating images needs this -install_qemu-img: - pkg.installed: - - name: qemu-img - install_guestfs-tools: pkg.installed: - name: guestfs-tools @@ -47,3 +60,23 @@ libvirt_python_module: - name: /opt/saltstack/salt/bin/python3 -m pip install --no-index --find-links=/opt/so/conf/libvirt/source-packages/libvirt-python libvirt-python - onchanges: - file: libvirt_python_wheel + +{% endif %} + +{% else %} +{{sls}}_no_license_detected: + test.fail_without_changes: + - name: {{sls}}_no_license_detected + - comment: + - "Hypervisor nodes are a feature supported only for customers with a valid license. + Contact Security Onion Solutions, LLC via our website at https://securityonionsolutions.com + for more information about purchasing a license to enable this feature." +{% endif %} + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/libvirt/ssh/users.sls b/salt/libvirt/ssh/users.sls index f0e30caec..0829075d2 100644 --- a/salt/libvirt/ssh/users.sls +++ b/salt/libvirt/ssh/users.sls @@ -1,20 +1,27 @@ # Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one -# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at # https://securityonion.net/license; you may not use this file except in compliance with the # Elastic License 2.0. +# +# Note: Per the Elastic License 2.0, the second limitation states: +# +# "You may not move, change, disable, or circumvent the license key functionality +# in the software, and you may not remove or obscure any functionality in the +# software that is protected by the license key." -{% from 'vars/globals.map.jinja' import GLOBALS %} +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls in allowed_states %} +{% if 'hvn' in salt['pillar.get']('features', []) %} +{% from 'vars/globals.map.jinja' import GLOBALS %} - - -{% if GLOBALS.is_manager %} +{% if GLOBALS.is_manager %} qemu_ssh_client_config: file.managed: - name: /root/.ssh/config - source: salt://libvirt/ssh/files/config -{% else %} +{% else %} # used for qemu+ssh connection between manager and hypervisors create_soqemussh_user: @@ -32,4 +39,22 @@ soqemussh_pub_key: - user: soqemussh - source: salt://libvirt/ssh/keys/id_ed25519.pub +{% endif %} + +{% else %} +{{sls}}_no_license_detected: + test.fail_without_changes: + - name: {{sls}}_no_license_detected + - comment: + - "Hypervisor nodes are a feature supported only for customers with a valid license. + Contact Security Onion Solutions, LLC via our website at https://securityonionsolutions.com + for more information about purchasing a license to enable this feature." +{% endif %} + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + {% endif %} diff --git a/salt/reactor/check_hypervisor.sls b/salt/reactor/check_hypervisor.sls index fdf75453d..9afc42354 100644 --- a/salt/reactor/check_hypervisor.sls +++ b/salt/reactor/check_hypervisor.sls @@ -1,4 +1,4 @@ -{% if data['id'].endswith(('_hypervisor', '_managerhyper')) %} +{% if data['act'] == 'accept' and data['id'].endswith(('_hypervisor', '_managerhyper')) and data['result'] == True %} check_and_trigger: runner.setup_hypervisor.setup_environment: [] {% endif %} diff --git a/salt/salt/cloud/init.sls b/salt/salt/cloud/init.sls index 5e160581b..7d987a5da 100644 --- a/salt/salt/cloud/init.sls +++ b/salt/salt/cloud/init.sls @@ -2,11 +2,18 @@ # or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at # https://securityonion.net/license; you may not use this file except in compliance with the # Elastic License 2.0. +# +# Note: Per the Elastic License 2.0, the second limitation states: +# +# "You may not move, change, disable, or circumvent the license key functionality +# in the software, and you may not remove or obscure any functionality in the +# software that is protected by the license key." {% from 'allowed_states.map.jinja' import allowed_states %} {% if sls in allowed_states %} -{% from 'salt/map.jinja' import SALTVERSION %} -{% set HYPERVISORS = salt['pillar.get']('hypervisor:nodes', {} ) %} +{% if 'hvn' in salt['pillar.get']('features', []) %} +{% from 'salt/map.jinja' import SALTVERSION %} +{% set HYPERVISORS = salt['pillar.get']('hypervisor:nodes', {} ) %} include: - libvirt.packages @@ -16,6 +23,7 @@ install_salt_cloud: - name: salt-cloud - version: {{SALTVERSION}} +{% if HYPERVISORS %} cloud_providers: file.managed: - name: /etc/salt/cloud.providers.d/libvirt.conf @@ -32,15 +40,26 @@ cloud_profiles: HYPERVISORS: {{HYPERVISORS}} - template: jinja -{% for role, hosts in HYPERVISORS.items() %} -{% for host in hosts.keys() %} +{% for role, hosts in HYPERVISORS.items() %} +{% for host in hosts.keys() %} hypervisor_{{host}}_{{role}}_pillar_dir: file.directory: - name: /opt/so/saltstack/local/pillar/hypervisor/{{host}}_{{role}} -{% endfor %} -{% endfor %} +{% endfor %} +{% endfor %} +{% endif %} + +{% else %} +{{sls}}_no_license_detected: + test.fail_without_changes: + - name: {{sls}}_no_license_detected + - comment: + - "Hypervisor nodes are a feature supported only for customers with a valid license. + Contact Security Onion Solutions, LLC via our website at https://securityonionsolutions.com + for more information about purchasing a license to enable this feature." +{% endif %} {% else %} diff --git a/salt/salt/cloud/reactor_config_hypervisor.sls b/salt/salt/cloud/reactor_config_hypervisor.sls new file mode 100644 index 000000000..433e01f31 --- /dev/null +++ b/salt/salt/cloud/reactor_config_hypervisor.sls @@ -0,0 +1,53 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. +# +# Note: Per the Elastic License 2.0, the second limitation states: +# +# "You may not move, change, disable, or circumvent the license key functionality +# in the software, and you may not remove or obscure any functionality in the +# software that is protected by the license key." + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[:2]|join('.') in allowed_states %} +{% if 'hvn' in salt['pillar.get']('features', []) %} +reactor_config_hypervisor: + file.managed: + - name: /etc/salt/master.d/reactor_hypervisor.conf + - contents: | + reactor: + - 'salt/key': + - salt://reactor/check_hypervisor.sls + - 'salt/cloud/*/deploying': + - /opt/so/saltstack/default/salt/reactor/createEmptyPillar.sls + - 'setup/so-minion': + - /opt/so/saltstack/default/salt/reactor/sominion_setup.sls + - 'salt/cloud/*/destroyed': + - /opt/so/saltstack/default/salt/reactor/virtReleaseHardware.sls + - /opt/so/saltstack/default/salt/reactor/deleteKey.sls + - user: root + - group: root + - mode: 644 + - makedirs: True + - watch_in: + - service: salt_master_service + - order: last + +{% else %} +{{sls}}_no_license_detected: + test.fail_without_changes: + - name: {{sls}}_no_license_detected + - comment: + - "Hypervisor nodes are a feature supported only for customers with a valid license. + Contact Security Onion Solutions, LLC via our website at https://securityonionsolutions.com + for more information about purchasing a license to enable this feature." +{% endif %} + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/salt/master.sls b/salt/salt/master.sls index 7e823f4e8..b997ced4e 100644 --- a/salt/salt/master.sls +++ b/salt/salt/master.sls @@ -2,14 +2,21 @@ # or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at # https://securityonion.net/license; you may not use this file except in compliance with the # Elastic License 2.0. +# +# Note: Per the Elastic License 2.0, the second limitation states: +# +# "You may not move, change, disable, or circumvent the license key functionality +# in the software, and you may not remove or obscure any functionality in the +# software that is protected by the license key." {% from 'allowed_states.map.jinja' import allowed_states %} {% if sls in allowed_states %} include: - salt.minion -{% if salt['pillar.get']('hypervisor:nodes', {} ) %} +{% if 'hvn' in salt['pillar.get']('features', []) %} - salt.cloud + - salt.cloud.reactor_config_hypervisor {% endif %} hold_salt_master_package: @@ -55,10 +62,8 @@ salt_master_service: {# # we need to managed adding the following to salt-master config if there are hypervisors reactor: - - 'salt/auth/accept/*': + - 'salt/key': - salt://reactor/check_hypervisor.sls - #- salt/cloud/*/creating': - #- salt/cloud/*/requesting - 'salt/cloud/*/deploying': - /opt/so/saltstack/default/salt/reactor/createEmptyPillar.sls - 'setup/so-minion': From cbd2d8800008e62e2bbff3ec5bb4ea9da8631d22 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Wed, 15 Jan 2025 16:59:39 -0500 Subject: [PATCH 070/315] sync the runners --- salt/salt/master.sls | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/salt/salt/master.sls b/salt/salt/master.sls index b997ced4e..3f847583f 100644 --- a/salt/salt/master.sls +++ b/salt/salt/master.sls @@ -17,6 +17,10 @@ include: {% if 'hvn' in salt['pillar.get']('features', []) %} - salt.cloud - salt.cloud.reactor_config_hypervisor + +sync_runners: + salt.runner: + - name: saltutil.sync_runners {% endif %} hold_salt_master_package: From 837fbab96d947074122687f33e9de29d9749f6bf Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Wed, 15 Jan 2025 17:00:06 -0500 Subject: [PATCH 071/315] minimize packages installed on manager for hyper --- salt/libvirt/packages.sls | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/salt/libvirt/packages.sls b/salt/libvirt/packages.sls index 5f4b343a7..b1688b483 100644 --- a/salt/libvirt/packages.sls +++ b/salt/libvirt/packages.sls @@ -15,10 +15,16 @@ # allows for creating vm images # any node manipulating images needs this +# used on manager for setup_hypervisor runner install_qemu-img: pkg.installed: - name: qemu-img +# used on manager for setup_hypervisor runner +install_xorriso: + pkg.installed: + - name: xorriso + {% if 'hyper' in grains.id.split('_') | last %} install_libvirt-libs: @@ -34,10 +40,6 @@ install_guestfs-tools: pkg.installed: - name: guestfs-tools -install_xorriso: - pkg.installed: - - name: xorriso - install_virt-install: pkg.installed: - name: virt-install From e8546b82f8cdb13fc62efa472063728470df3a37 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Thu, 16 Jan 2025 08:43:46 -0500 Subject: [PATCH 072/315] default image: sool9. cloud-init add local repo --- salt/_runners/setup_hypervisor.py | 21 ++++++++++++++++--- .../cloud/cloud.profiles.d/socloud.conf.jinja | 4 ++-- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/salt/_runners/setup_hypervisor.py b/salt/_runners/setup_hypervisor.py index e444b739a..9db9e2445 100644 --- a/salt/_runners/setup_hypervisor.py +++ b/salt/_runners/setup_hypervisor.py @@ -13,7 +13,7 @@ but can also be run manually if needed. CLI Examples: - # Perform complete environment setup (creates VM named 'so-ol9' with 220G disk by default) + # Perform complete environment setup (creates VM named 'sool9' with 220G disk by default) salt-run setup_hypervisor.setup_environment # Setup with custom VM name (uses default 220G disk) @@ -38,6 +38,7 @@ import os import pwd import requests import salt.utils.files +import socket import sys import time from cryptography.hazmat.primitives import serialization @@ -253,7 +254,7 @@ def _check_vm_exists(vm_name: str) -> bool: log.info("MAIN: VM %s already exists", vm_name) return exists -def setup_environment(vm_name: str = 'so-ol9', disk_size: str = '220G'): +def setup_environment(vm_name: str = 'sool9', disk_size: str = '220G'): """ Main entry point to set up the hypervisor environment. This includes downloading the base image, generating SSH keys for remote access, @@ -261,7 +262,7 @@ def setup_environment(vm_name: str = 'so-ol9', disk_size: str = '220G'): Args: vm_name (str, optional): Name of the VM to create as part of environment setup. - Defaults to 'so-ol9'. + Defaults to 'sool9'. disk_size (str, optional): Size of the VM disk with unit. Defaults to '220G'. @@ -390,6 +391,9 @@ def create_vm(vm_name: str, disk_size: str = '220G'): log.error("CREATEVM: Failed to read SSH public key: %s", str(e)) return {'success': False, 'error': 'Failed to read SSH public key'} + # Get hostname for repo configuration + manager_hostname = socket.gethostname() + # Create meta-data meta_data = f"""instance-id: {vm_name} local-hostname: {vm_name} @@ -404,6 +408,7 @@ preserve_hostname: False hostname: {vm_name} fqdn: {vm_name}.local +# The passwd hash will be removed at release and is being used for debugging during development users: - default - name: soqemussh @@ -429,6 +434,16 @@ timezone: UTC packages: - qemu-guest-agent +write_files: + - path: /etc/yum.repos.d/securityonion.repo + content: | + [securityonion] + name=Security Onion Repo + baseurl=https://{manager_hostname}/repo + enabled=1 + gpgcheck=1 + sslverify=0 + runcmd: - systemctl enable --now qemu-guest-agent - systemctl enable --now serial-getty@ttyS0.service diff --git a/salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja b/salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja index 4d3d33ac2..70a14225c 100644 --- a/salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja +++ b/salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja @@ -6,9 +6,9 @@ {%- for role, hosts in HYPERVISORS.items() %} {%- for host in hosts.keys() -%} -core-{{host}}: +sool9-{{host}}: provider: kvm-ssh-{{host}} - base_domain: coreol9 + base_domain: sool9 ip_source: qemu-agent ssh_username: soqemussh private_key: /home/soqemussh/.ssh/id_ed25519 From 0e0fb885d257a378e330e61d28399e8ef1f5cc5e Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Thu, 16 Jan 2025 11:13:36 -0500 Subject: [PATCH 073/315] hypervisor highstate after image creation, not when key accepted --- salt/_runners/setup_hypervisor.py | 84 ++++++++++++++++++++++++++++++- salt/manager/tools/sbin/so-minion | 8 ++- salt/reactor/check_hypervisor.sls | 4 +- salt/reactor/sominion_setup.sls | 2 +- 4 files changed, 94 insertions(+), 4 deletions(-) diff --git a/salt/_runners/setup_hypervisor.py b/salt/_runners/setup_hypervisor.py index 9db9e2445..0a2845813 100644 --- a/salt/_runners/setup_hypervisor.py +++ b/salt/_runners/setup_hypervisor.py @@ -1,3 +1,14 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. +# +# Note: Per the Elastic License 2.0, the second limitation states: +# +# "You may not move, change, disable, or circumvent the license key functionality +# in the software, and you may not remove or obscure any functionality in the +# software that is protected by the license key." + """ This runner performs the initial setup required for hypervisor hosts in the environment. It handles downloading the Oracle Linux KVM image, setting up SSH keys for secure @@ -37,10 +48,12 @@ import logging import os import pwd import requests +import salt.client import salt.utils.files import socket import sys import time +import yaml from cryptography.hazmat.primitives import serialization from cryptography.hazmat.primitives.asymmetric import ed25519 @@ -55,6 +68,40 @@ formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(messag stream_handler.setFormatter(formatter) log.addHandler(stream_handler) +def _check_license(): + """Check if the license file exists and contains required values.""" + license_path = '/opt/so/saltstack/local/pillar/soc/license.sls' + + if not os.path.exists(license_path): + log.error("LICENSE: License file not found at %s", license_path) + return False + + try: + with salt.utils.files.fopen(license_path, 'r') as f: + license_data = yaml.safe_load(f) + + if not license_data: + log.error("LICENSE: Empty or invalid license file") + return False + + license_id = license_data.get('license_id') + features = license_data.get('features', []) + + if not license_id: + log.error("LICENSE: No license_id found in license file") + return False + + if 'hvn' not in features: + log.error("LICENSE: 'hvn' feature not found in license") + return False + + log.info("LICENSE: License validation successful") + return True + + except Exception as e: + log.error("LICENSE: Error reading license file: %s", str(e)) + return False + def _check_file_exists(path): """Check if a file exists and create its directory if needed.""" if os.path.exists(path): @@ -254,7 +301,7 @@ def _check_vm_exists(vm_name: str) -> bool: log.info("MAIN: VM %s already exists", vm_name) return exists -def setup_environment(vm_name: str = 'sool9', disk_size: str = '220G'): +def setup_environment(vm_name: str = 'sool9', disk_size: str = '220G', minion_id: str = None): """ Main entry point to set up the hypervisor environment. This includes downloading the base image, generating SSH keys for remote access, @@ -269,6 +316,14 @@ def setup_environment(vm_name: str = 'sool9', disk_size: str = '220G'): Returns: dict: Dictionary containing setup status and VM creation results """ + # Check license before proceeding + if not _check_license(): + return { + 'success': False, + 'error': 'Invalid license or missing hvn feature', + 'vm_result': None + } + log.info("MAIN: Starting setup_environment in setup_hypervisor runner") # Check if environment is already set up @@ -332,6 +387,21 @@ def setup_environment(vm_name: str = 'sool9', disk_size: str = '220G'): success = vm_result.get('success', False) log.info("MAIN: Setup environment completed with status: %s", "SUCCESS" if success else "FAILED") + # If setup was successful and we have a minion_id, run highstate + if success and minion_id: + log.info("MAIN: Running highstate on hypervisor %s", minion_id) + try: + # Initialize the LocalClient + local = salt.client.LocalClient() + # Run highstate on the hypervisor + highstate_result = local.cmd(minion_id, 'state.highstate', [], timeout=1800) + if highstate_result and minion_id in highstate_result: + log.info("MAIN: Highstate completed on %s", minion_id) + else: + log.error("MAIN: Highstate failed or timed out on %s", minion_id) + except Exception as e: + log.error("MAIN: Error running highstate on %s: %s", minion_id, str(e)) + return { 'success': success, 'error': vm_result.get('error') if not success else None, @@ -349,6 +419,13 @@ def create_vm(vm_name: str, disk_size: str = '220G'): Returns: dict: Dictionary containing success status and commands to run on hypervisor """ + # Check license before proceeding + if not _check_license(): + return { + 'success': False, + 'error': 'Invalid license or missing hvn feature', + } + try: # Input validation if not isinstance(vm_name, str) or not vm_name: @@ -566,6 +643,11 @@ def regenerate_ssh_keys(): Returns: bool: True if successful, False on error """ + # Check license before proceeding + if not _check_license(): + log.error("MAIN: Invalid license or missing hvn feature") + return False + log.info("MAIN: Starting SSH key regeneration") try: # Verify current state diff --git a/salt/manager/tools/sbin/so-minion b/salt/manager/tools/sbin/so-minion index 141129b6d..daa4d3bc4 100755 --- a/salt/manager/tools/sbin/so-minion +++ b/salt/manager/tools/sbin/so-minion @@ -623,6 +623,12 @@ function updateMineAndApplyStates() { #checkMine "network.ip_addrs" # calls so-common and set_minionid sets MINIONID to local minion id set_minionid + + # We don't want a hypervisor node to highstate until the image is downloaded and built. This will be triggered from the setup_hypervisor runner + if [[ "$NODETYPE" == "HYPERVISOR" ]]; then + return 0 + fi + # if this is a searchnode or heavynode, start downloading logstash and elasticsearch containers while the manager prepares for the new node if [[ "$NODETYPE" == "SEARCHNODE" || "$NODETYPE" == "HEAVYNODE" ]]; then salt-run state.orch orch.container_download pillar="{'setup': {'newnode': $MINION_ID }}" > /dev/null 2>&1 & @@ -661,7 +667,7 @@ case "$OPERATION" in updateMineAndApplyStates ;; - "addVirt") + "addVM") setupMinionFiles ;; diff --git a/salt/reactor/check_hypervisor.sls b/salt/reactor/check_hypervisor.sls index 9afc42354..79ec06988 100644 --- a/salt/reactor/check_hypervisor.sls +++ b/salt/reactor/check_hypervisor.sls @@ -1,4 +1,6 @@ {% if data['act'] == 'accept' and data['id'].endswith(('_hypervisor', '_managerhyper')) and data['result'] == True %} check_and_trigger: - runner.setup_hypervisor.setup_environment: [] + runner.setup_hypervisor.setup_environment: + - kwargs: + minion_id: {{ data['id'] }} {% endif %} diff --git a/salt/reactor/sominion_setup.sls b/salt/reactor/sominion_setup.sls index a78475e6c..21c7824fe 100644 --- a/salt/reactor/sominion_setup.sls +++ b/salt/reactor/sominion_setup.sls @@ -28,7 +28,7 @@ def run(): with open("/opt/so/saltstack/local/pillar/hypervisor/" + hv_name + "/" + minionid + ".sls", 'w') as f: yaml.dump(vm_out_data, f, default_flow_style=False) - rc = call("NODETYPE=" + DATA['NODETYPE'] + " /usr/sbin/so-minion -o=addVirt -m=" + minionid + " -n=" + DATA['MNIC'] + " -i=" + DATA['MAINIP'] + " -a=" + DATA['INTERFACE'] + " -c=" + str(DATA['CPU']) + " -d='" + DATA['NODE_DESCRIPTION'] + "'" + " -e=" + DATA['ES_HEAP_SIZE'] + " -l=" + DATA['LS_HEAP_SIZE'], shell=True) + rc = call("NODETYPE=" + DATA['NODETYPE'] + " /usr/sbin/so-minion -o=addVM -m=" + minionid + " -n=" + DATA['MNIC'] + " -i=" + DATA['MAINIP'] + " -a=" + DATA['INTERFACE'] + " -c=" + str(DATA['CPU']) + " -d='" + DATA['NODE_DESCRIPTION'] + "'" + " -e=" + DATA['ES_HEAP_SIZE'] + " -l=" + DATA['LS_HEAP_SIZE'], shell=True) logging.error('sominion_setup reactor: rc: %s' % rc) From 58be7ae5db4c7637ea9c7a3b070cf35ecbaa49e9 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Thu, 16 Jan 2025 11:16:20 -0500 Subject: [PATCH 074/315] rename from coreol9 or coreol9Small to sool9 --- salt/hypervisor/tools/sbin/so-qcow2-modify-network | 4 ++-- salt/libvirt/images/coreol9Small/README | 1 - salt/libvirt/images/init.sls | 6 +++--- salt/libvirt/images/sool9/README | 1 + salt/libvirt/init.sls | 2 +- salt/manager/tools/sbin/so-salt-cloud | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) delete mode 100644 salt/libvirt/images/coreol9Small/README create mode 100644 salt/libvirt/images/sool9/README diff --git a/salt/hypervisor/tools/sbin/so-qcow2-modify-network b/salt/hypervisor/tools/sbin/so-qcow2-modify-network index 7920985b4..4e96bca22 100644 --- a/salt/hypervisor/tools/sbin/so-qcow2-modify-network +++ b/salt/hypervisor/tools/sbin/so-qcow2-modify-network @@ -12,9 +12,9 @@ Usage: python so-qcow2-modify-network.py -I -i (--dhcp4 | --static4 --ip4 --gw4 ) [--dns4 ] [--search4 ] Examples: - python so-qcow2-modify-network.py -I /var/lib/libvirt/images/coreol9/coreol9.qcow2 -i eth0 --static4 --ip4 192.168.1.10/24 --gw4 192.168.1.1 --dns4 192.168.1.1,8.8.8.8 --search4 example.local + python so-qcow2-modify-network.py -I /var/lib/libvirt/images/sool9/sool9.qcow2 -i eth0 --static4 --ip4 192.168.1.10/24 --gw4 192.168.1.1 --dns4 192.168.1.1,8.8.8.8 --search4 example.local - python so-qcow2-modify-network.py -I /var/lib/libvirt/images/coreol9/coreol9.qcow2 -i eth0 --dhcp4 + python so-qcow2-modify-network.py -I /var/lib/libvirt/images/sool9/sool9.qcow2 -i eth0 --dhcp4 """ import argparse diff --git a/salt/libvirt/images/coreol9Small/README b/salt/libvirt/images/coreol9Small/README deleted file mode 100644 index 28d066458..000000000 --- a/salt/libvirt/images/coreol9Small/README +++ /dev/null @@ -1 +0,0 @@ -# The files in this directory (/opt/so/saltstack/local/salt/libvirt/images/coreol9Small) are generated by createvm.sh. They are then distributed to the hypervisors where a storage pool will be created then the image can be installed. diff --git a/salt/libvirt/images/init.sls b/salt/libvirt/images/init.sls index 605af2368..864a2e2eb 100644 --- a/salt/libvirt/images/init.sls +++ b/salt/libvirt/images/init.sls @@ -1,6 +1,6 @@ -# the source location will be /opt/so/saltstack/local/salt/libvirt/imaages/coreol9Small +# the source location will be /opt/so/saltstack/local/salt/libvirt/images/sool9 # this will need to change to save the images to /nsm baseimagefiles: file.recurse: - - name: /var/lib/libvirt/images/coreol9Small/ - - source: salt://libvirt/images/coreol9Small/ + - name: /var/lib/libvirt/images/sool9/ + - source: salt://libvirt/images/sool9/ diff --git a/salt/libvirt/images/sool9/README b/salt/libvirt/images/sool9/README new file mode 100644 index 000000000..286dd8a44 --- /dev/null +++ b/salt/libvirt/images/sool9/README @@ -0,0 +1 @@ +# The files in this directory (/opt/so/saltstack/local/salt/libvirt/images/sool9) are generated by createvm.sh. They are then distributed to the hypervisors where a storage pool will be created then the image can be installed. diff --git a/salt/libvirt/init.sls b/salt/libvirt/init.sls index b0c131330..de67f2971 100644 --- a/salt/libvirt/init.sls +++ b/salt/libvirt/init.sls @@ -79,7 +79,7 @@ set_default_pool: virt.pool_running: - name: default - ptype: dir - - target: /var/lib/libvirt/images/coreol9 + - target: /var/lib/libvirt/images/sool9 - permissions: - mode: 0711 - owner: qemu diff --git a/salt/manager/tools/sbin/so-salt-cloud b/salt/manager/tools/sbin/so-salt-cloud index 2691ea382..9bf4e2227 100644 --- a/salt/manager/tools/sbin/so-salt-cloud +++ b/salt/manager/tools/sbin/so-salt-cloud @@ -236,7 +236,7 @@ def run_qcow2_modify_hardware_config(profile, vm_name, cpu=None, memory=None, pc def run_qcow2_modify_network_config(profile, mode, ip=None, gateway=None, dns=None, search_domain=None): hv_name = profile.split('-')[1] target = hv_name + "_*" - image = '/var/lib/libvirt/images/coreol9/coreol9.qcow2.MODIFIED' + image = '/var/lib/libvirt/images/sool9/sool9.qcow2' interface = 'eth0' try: From 116c2b73c193dcf38bb0395aa9e8b4bc1f3b67f0 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Thu, 16 Jan 2025 11:16:34 -0500 Subject: [PATCH 075/315] update gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 1830698b0..fc9d41531 100644 --- a/.gitignore +++ b/.gitignore @@ -70,6 +70,8 @@ site-packages # Project Scope Directory .projectScope/ +.clinerules +cline_docs/ # vscode settings .vscode/ From 739f59206107a3cdd8b29b8079cdd3b588808337 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Thu, 16 Jan 2025 14:06:01 -0500 Subject: [PATCH 076/315] remove old line of code --- salt/manager/tools/sbin/so-minion | 1 - 1 file changed, 1 deletion(-) diff --git a/salt/manager/tools/sbin/so-minion b/salt/manager/tools/sbin/so-minion index daa4d3bc4..ff786772c 100755 --- a/salt/manager/tools/sbin/so-minion +++ b/salt/manager/tools/sbin/so-minion @@ -620,7 +620,6 @@ function addMinion() { function updateMineAndApplyStates() { - #checkMine "network.ip_addrs" # calls so-common and set_minionid sets MINIONID to local minion id set_minionid From 6367aed62aadaccdab3418055749a7eb734bf376 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Thu, 16 Jan 2025 14:59:11 -0500 Subject: [PATCH 077/315] reactor needs to match runner function parameter structure --- salt/reactor/check_hypervisor.sls | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/salt/reactor/check_hypervisor.sls b/salt/reactor/check_hypervisor.sls index 79ec06988..889656b36 100644 --- a/salt/reactor/check_hypervisor.sls +++ b/salt/reactor/check_hypervisor.sls @@ -1,6 +1,5 @@ {% if data['act'] == 'accept' and data['id'].endswith(('_hypervisor', '_managerhyper')) and data['result'] == True %} check_and_trigger: runner.setup_hypervisor.setup_environment: - - kwargs: - minion_id: {{ data['id'] }} + - minion_id: {{ data['id'] }} {% endif %} From 61f5614ac9977e2a3321881a87cd378a30089c58 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Thu, 16 Jan 2025 16:57:36 -0500 Subject: [PATCH 078/315] added logging and error handling so-minion --- salt/manager/tools/sbin/so-minion | 723 ++++++++++++++++++++++-------- 1 file changed, 542 insertions(+), 181 deletions(-) diff --git a/salt/manager/tools/sbin/so-minion b/salt/manager/tools/sbin/so-minion index ff786772c..f97acc2c5 100755 --- a/salt/manager/tools/sbin/so-minion +++ b/salt/manager/tools/sbin/so-minion @@ -5,6 +5,24 @@ # https://securityonion.net/license; you may not use this file except in compliance with the # Elastic License 2.0. +# Setup logging +LOG_FILE="/opt/so/log/so-minion.log" +LOG_DIR=$(dirname "$LOG_FILE") + +# Create log directory if it doesn't exist +if [ ! -d "$LOG_DIR" ]; then + mkdir -p "$LOG_DIR" +fi + +# Logging function +log() { + local level=$1 + shift + local message="$*" + local timestamp=$(date '+%Y-%m-%d %H:%M:%S') + echo "[$timestamp] [$level] $message" >> "$LOG_FILE" +} + if [ -f /usr/sbin/so-common ]; then . /usr/sbin/so-common fi @@ -14,22 +32,25 @@ if [ -f /usr/sbin/so-elastic-fleet-common ]; then fi function usage() { - echo "Usage: $0 -o= -m=[id]" - echo "" - echo " where is one of the following:" - echo "" - echo " add: Accepts a new key and adds the minion files" - echo " delete: Removes the key and deletes the minion files" - echo " list: Lists all keys with hashes" - echo " reject: Rejects a key" - echo " restart: Restart a minion (reboot)" - echo " test: Perform minion test" - echo "" - exit 1 + local usage_text="Usage: $0 -o= -m=[id] + + where is one of the following: + + add: Accepts a new key and adds the minion files + delete: Removes the key and deletes the minion files + list: Lists all keys with hashes + reject: Rejects a key + restart: Restart a minion (reboot) + test: Perform minion test +" + echo "$usage_text" + log "ERROR" "Invalid usage" + return 1 } if [[ $# -lt 1 ]]; then usage + exit 1 fi for i in "$@"; do @@ -74,10 +95,12 @@ for i in "$@"; do ;; -*|--*) echo "Unknown option $i" + log "ERROR" "Unknown option $i" exit 1 ;; *) usage + exit 1 ;; esac done @@ -86,25 +109,50 @@ PILLARFILE=/opt/so/saltstack/local/pillar/minions/$MINION_ID.sls ADVPILLARFILE=/opt/so/saltstack/local/pillar/minions/adv_$MINION_ID.sls function getinstallinfo() { + log "INFO" "Getting install info for minion $MINION_ID" # Pull from file INSTALLVARS=$(sudo salt "$MINION_ID" cp.get_file_str /opt/so/install.txt --out=newline_values_only) + if [ $? -ne 0 ]; then + log "ERROR" "Failed to get install info from $MINION_ID" + return 1 + fi + source <(echo $INSTALLVARS) + if [ $? -ne 0 ]; then + log "ERROR" "Failed to source install variables" + return 1 + fi } function pcapspace() { + log "INFO" "Calculating PCAP space for minion $MINION_ID" + if [[ "$OPERATION" == "setup" ]]; then # Use 25% for PCAP PCAP_PERCENTAGE=1 DFREEPERCENT=21 local SPACESIZE=$(df -k /nsm | tail -1 | awk '{print $2}' | tr -d \n) + if [ $? -ne 0 ]; then + log "ERROR" "Failed to get NSM partition size" + return 1 + fi else - local NSMSIZE=$(salt "$MINION_ID" disk.usage --out=json | jq -r '.[]."/nsm"."1K-blocks" ') + if [ $? -ne 0 ]; then + log "ERROR" "Failed to get NSM disk usage from minion" + return 1 + fi + local ROOTSIZE=$(salt "$MINION_ID" disk.usage --out=json | jq -r '.[]."/"."1K-blocks" ') + if [ $? -ne 0 ]; then + log "ERROR" "Failed to get root disk usage from minion" + return 1 + fi if [[ "$NSMSIZE" == "null" ]]; then # Looks like there is no dedicated nsm partition. Using root local SPACESIZE=$ROOTSIZE + log "INFO" "No dedicated NSM partition found, using root partition" else local SPACESIZE=$NSMSIZE fi @@ -114,61 +162,129 @@ function pcapspace() { local s1=$(( $s / 4 * $PCAP_PERCENTAGE )) MAX_PCAP_SPACE=$s1 - } function testMinion() { - # Always run on the host, since this is going to be the manager of a distributed grid, or an eval/standalone. - # Distributed managers must run this in order for the sensor nodes to have access to the so-tcpreplay image. + log "INFO" "Testing minion $MINION_ID" + so-test result=$? + + if [ $result -ne 0 ]; then + log "ERROR" "Local so-test failed with exit code $result" + return 1 + fi - # If this so-minion script is not running on the given minion ID, run so-test remotely on the sensor as well local_id=$(lookup_grain id) if [[ ! "$local_id" =~ "${MINION_ID}_" && "$local_id" != "${MINION_ID}" ]]; then salt "$MINION_ID" cmd.run 'so-test' result=$? + if [ $result -ne 0 ]; then + log "ERROR" "Remote so-test failed on $MINION_ID with exit code $result" + return 1 + fi fi - - exit $result } function restartMinion() { + log "INFO" "Restarting minion $MINION_ID" salt "$MINION_ID" system.reboot result=$? - - exit $result + + if [ $result -ne 0 ]; then + log "ERROR" "Failed to restart minion $MINION_ID (exit code: $result)" + return 1 + fi } function listMinions() { salt-key list -F --out=json - exit $? + result=$? + + if [ $result -ne 0 ]; then + log "ERROR" "Failed to list minion keys (exit code: $result)" + return 1 + fi } function rejectMinion() { + log "INFO" "Rejecting minion $MINION_ID" salt-key -y -r $MINION_ID - exit $? + result=$? + + if [ $result -ne 0 ]; then + log "ERROR" "Failed to reject minion $MINION_ID (exit code: $result)" + return 1 + fi } function acceptminion() { + log "INFO" "Accepting minion $MINION_ID" + + if [[ "$MINION_ID" == *"_hypervisor" ]]; then + FEATURES=$(/usr/sbin/so-yaml.py get /opt/so/saltstack/local/pillar/soc/license.sls features) + if [[ $? -ne 0 || ! "$FEATURES" =~ "hvn" ]]; then + error_msg="Cannot accept hypervisor minion - hvn feature not enabled in license" + log "ERROR" "$error_msg" + echo "Error: $error_msg" + return 1 + fi + fi + salt-key -y -a $MINION_ID + result=$? + + if [ $result -ne 0 ]; then + log "ERROR" "Failed to accept minion $MINION_ID (exit code: $result)" + return 1 + fi } function deleteMinion() { + log "INFO" "Deleting minion $MINION_ID" salt-key -y -d $MINION_ID + result=$? + + if [ $result -ne 0 ]; then + log "ERROR" "Failed to delete minion $MINION_ID (exit code: $result)" + return 1 + fi } function deleteMinionFiles () { rm -f $PILLARFILE + if [ $? -ne 0 ]; then + log "ERROR" "Failed to delete $PILLARFILE" + return 1 + fi + rm -f $ADVPILLARFILE + if [ $? -ne 0 ]; then + log "ERROR" "Failed to delete $ADVPILLARFILE" + return 1 + fi } # Create the minion file function create_minion_files() { mkdir -p /opt/so/saltstack/local/pillar/minions + if [ $? -ne 0 ]; then + log "ERROR" "Failed to create minions directory" + return 1 + fi + touch $ADVPILLARFILE + if [ $? -ne 0 ]; then + log "ERROR" "Failed to create advanced pillar file" + return 1 + fi + if [ -f "$PILLARFILE" ]; then rm $PILLARFILE + if [ $? -ne 0 ]; then + log "ERROR" "Failed to remove existing pillar file" + return 1 + fi fi } @@ -179,6 +295,10 @@ function add_elasticsearch_to_minion() { " enabled: True"\ " esheap: '$ES_HEAP_SIZE'"\ " " >> $PILLARFILE + if [ $? -ne 0 ]; then + log "ERROR" "Failed to add elasticsearch configuration to $PILLARFILE" + return 1 + fi } @@ -188,14 +308,20 @@ function add_elastic_agent_to_minion() { "elasticagent:"\ " enabled: True"\ " " >> $PILLARFILE + if [ $? -ne 0 ]; then + log "ERROR" "Failed to add elastic agent configuration to $PILLARFILE" + return 1 + fi } # Add Elastic Fleet Server settings to the minion file function add_fleet_to_minion() { - # Create ES Token for Fleet server (Curl to Kibana API) - # TODO: Add error handling ESTOKEN=$(curl -K /opt/so/conf/elasticsearch/curl.config -L -X POST "localhost:5601/api/fleet/service_tokens" -H 'kbn-xsrf: true' -H 'Content-Type: application/json' | jq -r .value) + if [ $? -ne 0 ]; then + log "ERROR" "Failed to obtain ES token for fleet server" + return 1 + fi # Write out settings to minion file printf '%s\n'\ @@ -205,6 +331,10 @@ function add_fleet_to_minion() { " server:"\ " es_token: '$ESTOKEN'"\ " " >> $PILLARFILE + if [ $? -ne 0 ]; then + log "ERROR" "Failed to add fleet configuration to $PILLARFILE" + return 1 + fi } # Add IDH Services info to the minion file @@ -214,6 +344,10 @@ function add_idh_to_minion() { " enabled: True"\ " restrict_management_ip: $IDH_MGTRESTRICT"\ " " >> $PILLARFILE + if [ $? -ne 0 ]; then + log "ERROR" "Failed to add IDH configuration to $PILLARFILE" + return 1 + fi } function add_logstash_to_minion() { @@ -226,6 +360,10 @@ function add_logstash_to_minion() { " settings:"\ " lsheap: $LSHEAP"\ " " >> $PILLARFILE + if [ $? -ne 0 ]; then + log "ERROR" "Failed to add logstash configuration to $PILLARFILE" + return 1 + fi } # Security Onion Desktop @@ -234,6 +372,10 @@ function add_desktop_to_minion() { "desktop:"\ " gui:"\ " enabled: true"\ >> $PILLARFILE + if [ $? -ne 0 ]; then + log "ERROR" "Failed to add desktop configuration to $PILLARFILE" + return 1 + fi } # Add basic host info to the minion file @@ -242,6 +384,10 @@ function add_host_to_minion() { "host:"\ " mainip: '$MAINIP'"\ " mainint: '$MNIC'" >> $PILLARFILE + if [ $? -ne 0 ]; then + log "ERROR" "Failed to add host configuration to $PILLARFILE" + return 1 + fi } # Add sensoroni specific information - Can we pull node_adrees from the host pillar? @@ -252,6 +398,10 @@ function add_sensoroni_to_minion() { " config:"\ " node_description: '${NODE_DESCRIPTION//\'/''}'"\ " " >> $PILLARFILE + if [ $? -ne 0 ]; then + log "ERROR" "Failed to add sensoroni configuration to $PILLARFILE" + return 1 + fi } # Add sensoroni specific information - Can we pull node_adrees from the host pillar? @@ -264,42 +414,55 @@ function add_sensoroni_with_analyze_to_minion() { " enabled: True"\ " node_description: '${NODE_DESCRIPTION//\'/''}'"\ " " >> $PILLARFILE + if [ $? -ne 0 ]; then + log "ERROR" "Failed to add sensoroni analyze configuration to $PILLARFILE" + return 1 + fi } # Sensor settings for the minion pillar function add_sensor_to_minion() { - echo "sensor:" >> $PILLARFILE - echo " interface: '$INTERFACE'" >> $PILLARFILE - echo " mtu: 9000" >> $PILLARFILE - echo "zeek:" >> $PILLARFILE - echo " enabled: True" >> $PILLARFILE - echo " config:" >> $PILLARFILE - echo " node:" >> $PILLARFILE - echo " lb_procs: '$CORECOUNT'" >> $PILLARFILE - echo "suricata:" >> $PILLARFILE - echo " enabled: True " >> $PILLARFILE - if [[ $is_pcaplimit ]]; then - echo " pcap:" >> $PILLARFILE - echo " maxsize: $MAX_PCAP_SPACE" >> $PILLARFILE - fi - echo " config:" >> $PILLARFILE - echo " af-packet:" >> $PILLARFILE - echo " threads: '$CORECOUNT'" >> $PILLARFILE - echo "pcap:" >> $PILLARFILE - echo " enabled: True" >> $PILLARFILE - if [[ $is_pcaplimit ]]; then - echo " config:" >> $PILLARFILE - echo " diskfreepercentage: $DFREEPERCENT" >> $PILLARFILE - fi - echo " " >> $PILLARFILE + { + echo "sensor:" + echo " interface: '$INTERFACE'" + echo " mtu: 9000" + echo "zeek:" + echo " enabled: True" + echo " config:" + echo " node:" + echo " lb_procs: '$CORECOUNT'" + echo "suricata:" + echo " enabled: True " + if [[ $is_pcaplimit ]]; then + echo " pcap:" + echo " maxsize: $MAX_PCAP_SPACE" + fi + echo " config:" + echo " af-packet:" + echo " threads: '$CORECOUNT'" + echo "pcap:" + echo " enabled: True" + if [[ $is_pcaplimit ]]; then + echo " config:" + echo " diskfreepercentage: $DFREEPERCENT" + fi + echo " " + } >> $PILLARFILE + if [ $? -ne 0 ]; then + log "ERROR" "Failed to add sensor configuration to $PILLARFILE" + return 1 + fi } - function add_elastalert_to_minion() { printf '%s\n'\ "elastalert:"\ " enabled: True"\ " " >> $PILLARFILE + if [ $? -ne 0 ]; then + log "ERROR" "Failed to add elastalert configuration to $PILLARFILE" + return 1 + fi } function add_kibana_to_minion() { @@ -307,6 +470,10 @@ function add_kibana_to_minion() { "kibana:"\ " enabled: True"\ " " >> $PILLARFILE + if [ $? -ne 0 ]; then + log "ERROR" "Failed to add kibana configuration to $PILLARFILE" + return 1 + fi } function add_redis_to_minion() { @@ -314,6 +481,10 @@ function add_redis_to_minion() { "redis:"\ " enabled: True"\ " " >> $PILLARFILE + if [ $? -ne 0 ]; then + log "ERROR" "Failed to add redis configuration to $PILLARFILE" + return 1 + fi } function add_strelka_to_minion() { @@ -332,6 +503,10 @@ function add_strelka_to_minion() { " gatekeeper:"\ " enabled: True"\ " " >> $PILLARFILE + if [ $? -ne 0 ]; then + log "ERROR" "Failed to add strelka configuration to $PILLARFILE" + return 1 + fi } function add_telegraf_to_minion() { @@ -339,6 +514,10 @@ function add_telegraf_to_minion() { "telegraf:"\ " enabled: True"\ " " >> $PILLARFILE + if [ $? -ne 0 ]; then + log "ERROR" "Failed to add telegraf configuration to $PILLARFILE" + return 1 + fi } function add_influxdb_to_minion() { @@ -346,6 +525,10 @@ function add_influxdb_to_minion() { "influxdb:"\ " enabled: True"\ " " >> $PILLARFILE + if [ $? -ne 0 ]; then + log "ERROR" "Failed to add influxdb configuration to $PILLARFILE" + return 1 + fi } function add_nginx_to_minion() { @@ -353,6 +536,10 @@ function add_nginx_to_minion() { "nginx:"\ " enabled: True"\ " " >> $PILLARFILE + if [ $? -ne 0 ]; then + log "ERROR" "Failed to add nginx configuration to $PILLARFILE" + return 1 + fi } function add_soc_to_minion() { @@ -360,6 +547,10 @@ function add_soc_to_minion() { "soc:"\ " enabled: True"\ " " >> $PILLARFILE + if [ $? -ne 0 ]; then + log "ERROR" "Failed to add soc configuration to $PILLARFILE" + return 1 + fi } function add_registry_to_minion() { @@ -367,6 +558,10 @@ function add_registry_to_minion() { "registry:"\ " enabled: True"\ " " >> $PILLARFILE + if [ $? -ne 0 ]; then + log "ERROR" "Failed to add registry configuration to $PILLARFILE" + return 1 + fi } function add_kratos_to_minion() { @@ -374,6 +569,10 @@ function add_kratos_to_minion() { "kratos:"\ " enabled: True"\ " " >> $PILLARFILE + if [ $? -ne 0 ]; then + log "ERROR" "Failed to add kratos configuration to $PILLARFILE" + return 1 + fi } function add_idstools_to_minion() { @@ -381,6 +580,10 @@ function add_idstools_to_minion() { "idstools:"\ " enabled: True"\ " " >> $PILLARFILE + if [ $? -ne 0 ]; then + log "ERROR" "Failed to add idstools configuration to $PILLARFILE" + return 1 + fi } function add_elastic_fleet_package_registry_to_minion() { @@ -388,9 +591,14 @@ function add_elastic_fleet_package_registry_to_minion() { "elastic_fleet_package_registry:"\ " enabled: True"\ " " >> $PILLARFILE + if [ $? -ne 0 ]; then + log "ERROR" "Failed to add elastic fleet package registry configuration to $PILLARFILE" + return 1 + fi } function create_fleet_policy() { + log "INFO" "Creating fleet policy for $MINION_ID" # First, set the default output to Elasticsearch # This is required because of the license output bug @@ -401,301 +609,454 @@ function create_fleet_policy() { "is_default": true, "is_default_monitoring": false }') + if [ $? -ne 0 ]; then + log "ERROR" "Failed to create elasticsearch output JSON" + return 1 + fi curl -K /opt/so/conf/elasticsearch/curl.config -L -X PUT "localhost:5601/api/fleet/outputs/so-manager_elasticsearch" -H 'kbn-xsrf: true' -H 'Content-Type: application/json' -d "$JSON_STRING" + if [ $? -ne 0 ]; then + log "ERROR" "Failed to set elasticsearch as default output" + return 1 + fi # Create the Fleet Server Policy elastic_fleet_policy_create "FleetServer_$LSHOSTNAME" "Fleet Server - $LSHOSTNAME" "false" "120" + if [ $? -ne 0 ]; then + log "ERROR" "Failed to create fleet server policy" + return 1 + fi # Modify the default integration policy to update the policy_id with the correct naming UPDATED_INTEGRATION_POLICY=$(jq --arg policy_id "FleetServer_$LSHOSTNAME" --arg name "fleet_server-$LSHOSTNAME" ' .policy_id = $policy_id | .name = $name' /opt/so/conf/elastic-fleet/integrations/fleet-server/fleet-server.json) + if [ $? -ne 0 ]; then + log "ERROR" "Failed to update integration policy" + return 1 + fi # Add the Fleet Server Integration to the new Fleet Policy elastic_fleet_integration_create "$UPDATED_INTEGRATION_POLICY" + if [ $? -ne 0 ]; then + log "ERROR" "Failed to create fleet server integration" + return 1 + fi # Set the default output back to the default /sbin/so-elastic-fleet-outputs-update + if [ $? -ne 0 ]; then + log "ERROR" "Failed to update fleet outputs" + return 1 + fi } function update_fleet_host_urls() { + log "INFO" "Updating fleet host URLs for $MINION_ID" + # Query for current Fleet Host URLs & append New Fleet Node Hostname & IP JSON_STRING=$(curl -K /opt/so/conf/elasticsearch/curl.config 'http://localhost:5601/api/fleet/fleet_server_hosts/grid-default' | jq --arg HOSTNAME "https://$LSHOSTNAME:8220" --arg IP "https://$MAINIP:8220" '.item.host_urls += [ $HOSTNAME, $IP ] | {"name":"grid-default","is_default":true,"host_urls": .item.host_urls}') + if [ $? -ne 0 ]; then + log "ERROR" "Failed to get current fleet host URLs" + return 1 + fi # Update Fleet Host URLs curl -K /opt/so/conf/elasticsearch/curl.config -L -X PUT "localhost:5601/api/fleet/fleet_server_hosts/grid-default" -H 'kbn-xsrf: true' -H 'Content-Type: application/json' -d "$JSON_STRING" + if [ $? -ne 0 ]; then + log "ERROR" "Failed to update fleet host URLs" + return 1 + fi } function update_logstash_outputs() { + log "INFO" "Updating logstash outputs for $MINION_ID" + # Query for current Logstash outputs & append New Fleet Node Hostname & IP JSON_STRING=$(curl -K /opt/so/conf/elasticsearch/curl.config 'http://localhost:5601/api/fleet/outputs/so-manager_logstash' | jq --arg HOSTNAME "$LSHOSTNAME:5055" --arg IP "$MAINIP:5055" -r '.item.hosts += [ $HOSTNAME, $IP ] | {"name":"grid-logstash","type":"logstash","hosts": .item.hosts,"is_default":true,"is_default_monitoring":true,"config_yaml":""}') + if [ $? -ne 0 ]; then + log "ERROR" "Failed to get current logstash outputs" + return 1 + fi # Update Logstash Outputs curl -K /opt/so/conf/elasticsearch/curl.config -L -X PUT "localhost:5601/api/fleet/outputs/so-manager_logstash" -H 'kbn-xsrf: true' -H 'Content-Type: application/json' -d "$JSON_STRING" + if [ $? -ne 0 ]; then + log "ERROR" "Failed to update logstash outputs" + return 1 + fi } function checkMine() { local func=$1 + log "INFO" "Checking mine for function $func on minion $MINION_ID" # make sure the minion sees itself in the mine since it needs to see itself for states as opposed to using salt-run - retry 20 1 "salt '$MINION_ID' mine.get '\*' '$func'" "$MINION_ID" - + retry 20 1 "salt '$MINION_ID' mine.get '\*' '$func'" "$MINION_ID" || { + log "ERROR" "Failed to verify mine function $func for $MINION_ID" + return 1 + } } function createEVAL() { + log "INFO" "Creating EVAL configuration for minion $MINION_ID" is_pcaplimit=true - pcapspace - add_elasticsearch_to_minion - add_sensor_to_minion - add_strelka_to_minion - add_elastalert_to_minion - add_kibana_to_minion - add_telegraf_to_minion - add_influxdb_to_minion - add_nginx_to_minion - add_soc_to_minion - add_registry_to_minion - add_kratos_to_minion - add_idstools_to_minion - add_elastic_fleet_package_registry_to_minion + pcapspace || return 1 + add_elasticsearch_to_minion || return 1 + add_sensor_to_minion || return 1 + add_strelka_to_minion || return 1 + add_elastalert_to_minion || return 1 + add_kibana_to_minion || return 1 + add_telegraf_to_minion || return 1 + add_influxdb_to_minion || return 1 + add_nginx_to_minion || return 1 + add_soc_to_minion || return 1 + add_registry_to_minion || return 1 + add_kratos_to_minion || return 1 + add_idstools_to_minion || return 1 + add_elastic_fleet_package_registry_to_minion || return 1 } function createSTANDALONE() { + log "INFO" "Creating STANDALONE configuration for minion $MINION_ID" is_pcaplimit=true - pcapspace - add_elasticsearch_to_minion - add_logstash_to_minion - add_sensor_to_minion - add_strelka_to_minion - add_elastalert_to_minion - add_kibana_to_minion - add_redis_to_minion - add_telegraf_to_minion - add_influxdb_to_minion - add_nginx_to_minion - add_soc_to_minion - add_registry_to_minion - add_kratos_to_minion - add_idstools_to_minion - add_elastic_fleet_package_registry_to_minion + pcapspace || return 1 + add_elasticsearch_to_minion || return 1 + add_logstash_to_minion || return 1 + add_sensor_to_minion || return 1 + add_strelka_to_minion || return 1 + add_elastalert_to_minion || return 1 + add_kibana_to_minion || return 1 + add_redis_to_minion || return 1 + add_telegraf_to_minion || return 1 + add_influxdb_to_minion || return 1 + add_nginx_to_minion || return 1 + add_soc_to_minion || return 1 + add_registry_to_minion || return 1 + add_kratos_to_minion || return 1 + add_idstools_to_minion || return 1 + add_elastic_fleet_package_registry_to_minion || return 1 } function createMANAGER() { - add_elasticsearch_to_minion - add_logstash_to_minion - add_elastalert_to_minion - add_kibana_to_minion - add_redis_to_minion - add_telegraf_to_minion - add_influxdb_to_minion - add_nginx_to_minion - add_soc_to_minion - add_registry_to_minion - add_kratos_to_minion - add_idstools_to_minion - add_elastic_fleet_package_registry_to_minion + log "INFO" "Creating MANAGER configuration for minion $MINION_ID" + add_elasticsearch_to_minion || return 1 + add_logstash_to_minion || return 1 + add_elastalert_to_minion || return 1 + add_kibana_to_minion || return 1 + add_redis_to_minion || return 1 + add_telegraf_to_minion || return 1 + add_influxdb_to_minion || return 1 + add_nginx_to_minion || return 1 + add_soc_to_minion || return 1 + add_registry_to_minion || return 1 + add_kratos_to_minion || return 1 + add_idstools_to_minion || return 1 + add_elastic_fleet_package_registry_to_minion || return 1 } function createMANAGERSEARCH() { - add_elasticsearch_to_minion - add_logstash_to_minion - add_elastalert_to_minion - add_kibana_to_minion - add_redis_to_minion - add_telegraf_to_minion - add_influxdb_to_minion - add_nginx_to_minion - add_soc_to_minion - add_registry_to_minion - add_kratos_to_minion - add_idstools_to_minion - add_elastic_fleet_package_registry_to_minion + log "INFO" "Creating MANAGERSEARCH configuration for minion $MINION_ID" + add_elasticsearch_to_minion || return 1 + add_logstash_to_minion || return 1 + add_elastalert_to_minion || return 1 + add_kibana_to_minion || return 1 + add_redis_to_minion || return 1 + add_telegraf_to_minion || return 1 + add_influxdb_to_minion || return 1 + add_nginx_to_minion || return 1 + add_soc_to_minion || return 1 + add_registry_to_minion || return 1 + add_kratos_to_minion || return 1 + add_idstools_to_minion || return 1 + add_elastic_fleet_package_registry_to_minion || return 1 } function createIMPORT() { - add_elasticsearch_to_minion - add_sensor_to_minion - add_kibana_to_minion - add_telegraf_to_minion - add_influxdb_to_minion - add_nginx_to_minion - add_soc_to_minion - add_registry_to_minion - add_kratos_to_minion - add_idstools_to_minion - add_elastic_fleet_package_registry_to_minion + log "INFO" "Creating IMPORT configuration for minion $MINION_ID" + add_elasticsearch_to_minion || return 1 + add_sensor_to_minion || return 1 + add_kibana_to_minion || return 1 + add_telegraf_to_minion || return 1 + add_influxdb_to_minion || return 1 + add_nginx_to_minion || return 1 + add_soc_to_minion || return 1 + add_registry_to_minion || return 1 + add_kratos_to_minion || return 1 + add_idstools_to_minion || return 1 + add_elastic_fleet_package_registry_to_minion || return 1 } function createFLEET() { - add_fleet_to_minion - add_logstash_to_minion - create_fleet_policy - update_fleet_host_urls + log "INFO" "Creating FLEET configuration for minion $MINION_ID" + add_fleet_to_minion || return 1 + add_logstash_to_minion || return 1 + create_fleet_policy || return 1 + update_fleet_host_urls || return 1 #update_logstash_outputs - add_telegraf_to_minion - add_nginx_to_minion + add_telegraf_to_minion || return 1 + add_nginx_to_minion || return 1 } function createIDH() { - add_idh_to_minion - add_telegraf_to_minion + log "INFO" "Creating IDH configuration for minion $MINION_ID" + add_idh_to_minion || return 1 + add_telegraf_to_minion || return 1 } function createHEAVYNODE() { + log "INFO" "Creating HEAVYNODE configuration for minion $MINION_ID" is_pcaplimit=true PCAP_PERCENTAGE=1 DFREEPERCENT=21 - pcapspace - add_elasticsearch_to_minion - add_elastic_agent_to_minion - add_sensor_to_minion - add_strelka_to_minion - add_redis_to_minion - add_telegraf_to_minion + pcapspace || return 1 + add_elasticsearch_to_minion || return 1 + add_elastic_agent_to_minion || return 1 + add_sensor_to_minion || return 1 + add_strelka_to_minion || return 1 + add_redis_to_minion || return 1 + add_telegraf_to_minion || return 1 } function createSENSOR() { + log "INFO" "Creating SENSOR configuration for minion $MINION_ID" is_pcaplimit=true DFREEPERCENT=10 PCAP_PERCENTAGE=3 - pcapspace - add_sensor_to_minion - add_strelka_to_minion - add_telegraf_to_minion + pcapspace || return 1 + add_sensor_to_minion || return 1 + add_strelka_to_minion || return 1 + add_telegraf_to_minion || return 1 } function createSEARCHNODE() { - add_elasticsearch_to_minion - add_logstash_to_minion - add_telegraf_to_minion + log "INFO" "Creating SEARCHNODE configuration for minion $MINION_ID" + add_elasticsearch_to_minion || return 1 + add_logstash_to_minion || return 1 + add_telegraf_to_minion || return 1 } function createRECEIVER() { - add_logstash_to_minion - add_redis_to_minion - add_telegraf_to_minion + log "INFO" "Creating RECEIVER configuration for minion $MINION_ID" + add_logstash_to_minion || return 1 + add_redis_to_minion || return 1 + add_telegraf_to_minion || return 1 } function createHYPERVISOR() { - add_telegraf_to_minion + log "INFO" "Creating HYPERVISOR configuration for minion $MINION_ID" + add_telegraf_to_minion || return 1 } function createDESKTOP() { - add_desktop_to_minion - add_telegraf_to_minion + log "INFO" "Creating DESKTOP configuration for minion $MINION_ID" + add_desktop_to_minion || return 1 + add_telegraf_to_minion || return 1 } function testConnection() { - # the minion should be trying to auth every 10 seconds so 15 seconds should be more than enough time to see this in the log - # this retry was put in because it is possible that a minion is attempted to be pinged before it has authenticated and connected to the Salt master - # causing the first ping to fail and typically wouldn't be successful until the second ping - # this check may pass without the minion being authenticated if it was previously connected and the line exists in the log + log "INFO" "Testing connection to minion $MINION_ID" + retry 15 1 "grep 'Authentication accepted from $MINION_ID' /opt/so/log/salt/master" local retauth=$? if [[ $retauth != 0 ]]; then - echo "The Minion did not authenticate with the Salt master in the allotted time" + error_msg="The Minion did not authenticate with the Salt master in the allotted time" + log "ERROR" "$error_msg" + echo "$error_msg" echo "Deleting the key" deleteminion - exit 1 + return 1 fi retry 15 3 "salt '$MINION_ID' test.ping" True local ret=$? if [[ $ret != 0 ]]; then - echo "The Minion has been accepted but is not online. Try again later" + error_msg="The Minion has been accepted but is not online" + log "ERROR" "$error_msg" + echo "$error_msg" echo "Deleting the key" deleteminion - exit 1 + return 1 fi } function addMinion() { + log "INFO" "Starting minion addition process for $MINION_ID" + # Accept the salt key - acceptminion + acceptminion || { + log "ERROR" "Failed to accept minion key" + return 1 + } + # Test to see if the minion was accepted - testConnection + testConnection || { + log "ERROR" "Failed to establish connection with minion" + return 1 + } + # Pull the info from the file to build what is needed - getinstallinfo + getinstallinfo || { + log "ERROR" "Failed to get installation information" + return 1 + } + + log "INFO" "Successfully added minion $MINION_ID" } function updateMineAndApplyStates() { + log "INFO" "Updating mine and applying states for minion $MINION_ID" # calls so-common and set_minionid sets MINIONID to local minion id set_minionid + if [ $? -ne 0 ]; then + log "ERROR" "Failed to set minion ID" + return 1 + fi # We don't want a hypervisor node to highstate until the image is downloaded and built. This will be triggered from the setup_hypervisor runner if [[ "$NODETYPE" == "HYPERVISOR" ]]; then + log "INFO" "Skipping state application for hypervisor node" return 0 fi # if this is a searchnode or heavynode, start downloading logstash and elasticsearch containers while the manager prepares for the new node if [[ "$NODETYPE" == "SEARCHNODE" || "$NODETYPE" == "HEAVYNODE" ]]; then + log "INFO" "Starting container download for $NODETYPE" salt-run state.orch orch.container_download pillar="{'setup': {'newnode': $MINION_ID }}" > /dev/null 2>&1 & + if [ $? -ne 0 ]; then + log "ERROR" "Failed to start container download" + return 1 + fi fi + if [[ "$NODETYPE" == "RECEIVER" ]]; then # Setup nodeid for Kafka + log "INFO" "Setting up Kafka node ID" salt-call state.apply kafka.nodes queue=True + if [ $? -ne 0 ]; then + log "ERROR" "Failed to setup Kafka node ID" + return 1 + fi fi + # $MINIONID is the minion id of the manager and $MINION_ID is the target node or the node being configured + log "INFO" "Deploying new node configuration" salt-run state.orch orch.deploy_newnode pillar="{'setup': {'manager': $MINIONID, 'newnode': $MINION_ID }}" > /dev/null 2>&1 & + if [ $? -ne 0 ]; then + log "ERROR" "Failed to start node deployment" + return 1 + fi } function setupMinionFiles() { + log "INFO" "Setting up minion files for $MINION_ID" + # Check to see if nodetype is set if [ -z $NODETYPE ]; then - echo "No node type specified" - exit 1 - fi - create_minion_files - add_host_to_minion - managers=("EVAL" "STANDALONE" "IMPORT" "MANAGER" "MANAGERSEARCH") - if echo "${managers[@]}" | grep -qw "$NODETYPE"; then - add_sensoroni_with_analyze_to_minion - else - add_sensoroni_to_minion + error_msg="No node type specified" + log "ERROR" "$error_msg" + echo "$error_msg" + return 1 fi - create$NODETYPE - echo "Minion file created for $MINION_ID" + # Create the base minion files + create_minion_files || return 1 + + # Add host configuration + add_host_to_minion || return 1 + + # Add sensoroni configuration based on node type + managers=("EVAL" "STANDALONE" "IMPORT" "MANAGER" "MANAGERSEARCH") + if echo "${managers[@]}" | grep -qw "$NODETYPE"; then + add_sensoroni_with_analyze_to_minion || return 1 + else + add_sensoroni_to_minion || return 1 + fi + + # Create node-specific configuration + create$NODETYPE || return 1 + + log "INFO" "Successfully created minion files for $MINION_ID" } case "$OPERATION" in "add") - addMinion - setupMinionFiles - updateMineAndApplyStates + log "INFO" "Adding minion $MINION_ID" + addMinion || { + log "ERROR" "Failed to add minion $MINION_ID" + exit 1 + } + setupMinionFiles || { + log "ERROR" "Failed to setup minion files for $MINION_ID" + exit 1 + } + updateMineAndApplyStates || { + log "ERROR" "Failed to update mine and apply states for $MINION_ID" + exit 1 + } + log "INFO" "Successfully completed all operations for minion $MINION_ID" ;; "addVM") - setupMinionFiles + log "INFO" "Adding VM minion $MINION_ID" + setupMinionFiles || { + log "ERROR" "Failed to setup VM minion files for $MINION_ID" + exit 1 + } + log "INFO" "Successfully added VM minion $MINION_ID" ;; "delete") - deleteMinionFiles - deleteMinion + log "INFO" "Removing minion $MINION_ID" + deleteMinionFiles || { + log "ERROR" "Failed to delete minion files for $MINION_ID" + exit 1 + } + deleteMinion || { + log "ERROR" "Failed to delete minion key for $MINION_ID" + exit 1 + } + log "INFO" "Successfully removed minion $MINION_ID" ;; "list") - listMinions + listMinions || { + log "ERROR" "Failed to list minion keys" + exit 1 + } ;; "reject") - rejectMinion + rejectMinion || { + log "ERROR" "Failed to reject minion $MINION_ID" + exit 1 + } ;; "restart") - restartMinion + restartMinion || { + log "ERROR" "Failed to restart minion $MINION_ID" + exit 1 + } ;; "setup") # only should be invoked directly during setup, never manually - setupMinionFiles + setupMinionFiles || { + log "ERROR" "Failed to setup minion files during setup for $MINION_ID" + exit 1 + } + log "INFO" "Successfully completed setup for minion $MINION_ID" ;; "test") - testMinion + testMinion || { + log "ERROR" "Failed to test minion $MINION_ID" + exit 1 + } ;; *) + log "ERROR" "Invalid operation: $OPERATION" usage ;; esac From 2277c792b9c04ff6b2dd42e17947d613ccf3f3f5 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Thu, 16 Jan 2025 17:13:36 -0500 Subject: [PATCH 079/315] update feature error logging in so-minion --- salt/manager/tools/sbin/so-minion | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/salt/manager/tools/sbin/so-minion b/salt/manager/tools/sbin/so-minion index f97acc2c5..fc6f0e416 100755 --- a/salt/manager/tools/sbin/so-minion +++ b/salt/manager/tools/sbin/so-minion @@ -224,9 +224,9 @@ function acceptminion() { if [[ "$MINION_ID" == *"_hypervisor" ]]; then FEATURES=$(/usr/sbin/so-yaml.py get /opt/so/saltstack/local/pillar/soc/license.sls features) if [[ $? -ne 0 || ! "$FEATURES" =~ "hvn" ]]; then - error_msg="Cannot accept hypervisor minion - hvn feature not enabled in license" + error_msg="Hypervisor nodes are a feature supported only for customers with a valid license.\n Contact Security Onion Solutions, LLC via our website at https://securityonionsolutions.com\n for more information about purchasing a license to enable this feature." log "ERROR" "$error_msg" - echo "Error: $error_msg" + echo -e "Error: $error_msg" return 1 fi fi @@ -844,6 +844,13 @@ function createRECEIVER() { function createHYPERVISOR() { log "INFO" "Creating HYPERVISOR configuration for minion $MINION_ID" + FEATURES=$(/usr/sbin/so-yaml.py get /opt/so/saltstack/local/pillar/soc/license.sls features) + if [[ $? -ne 0 || ! "$FEATURES" =~ "hvn" ]]; then + error_msg="Hypervisor nodes are a feature supported only for customers with a valid license.\n Contact Security Onion Solutions, LLC via our website at https://securityonionsolutions.com\n for more information about purchasing a license to enable this feature." + log "ERROR" "$error_msg" + echo -e "Error: $error_msg" + return 1 + fi add_telegraf_to_minion || return 1 } @@ -915,6 +922,13 @@ function updateMineAndApplyStates() { # We don't want a hypervisor node to highstate until the image is downloaded and built. This will be triggered from the setup_hypervisor runner if [[ "$NODETYPE" == "HYPERVISOR" ]]; then + FEATURES=$(/usr/sbin/so-yaml.py get /opt/so/saltstack/local/pillar/soc/license.sls features) + if [[ $? -ne 0 || ! "$FEATURES" =~ "hvn" ]]; then + error_msg="Hypervisor nodes are a feature supported only for customers with a valid license.\n Contact Security Onion Solutions, LLC via our website at https://securityonionsolutions.com\n for more information about purchasing a license to enable this feature." + log "ERROR" "$error_msg" + echo -e "Error: $error_msg" + return 1 + fi log "INFO" "Skipping state application for hypervisor node" return 0 fi @@ -999,6 +1013,13 @@ case "$OPERATION" in "addVM") log "INFO" "Adding VM minion $MINION_ID" + FEATURES=$(/usr/sbin/so-yaml.py get /opt/so/saltstack/local/pillar/soc/license.sls features) + if [[ $? -ne 0 || ! "$FEATURES" =~ "hvn" ]]; then + error_msg="Hypervisor nodes are a feature supported only for customers with a valid license.\n Contact Security Onion Solutions, LLC via our website at https://securityonionsolutions.com\n for more information about purchasing a license to enable this feature." + log "ERROR" "$error_msg" + echo -e "Error: $error_msg" + exit 1 + fi setupMinionFiles || { log "ERROR" "Failed to setup VM minion files for $MINION_ID" exit 1 From a274bfb744fb54cb5e2dfedf1e456301594b104c Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Thu, 16 Jan 2025 17:45:07 -0500 Subject: [PATCH 080/315] license note --- salt/manager/tools/sbin/so-minion | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/salt/manager/tools/sbin/so-minion b/salt/manager/tools/sbin/so-minion index fc6f0e416..fad765756 100755 --- a/salt/manager/tools/sbin/so-minion +++ b/salt/manager/tools/sbin/so-minion @@ -1,9 +1,15 @@ #!/bin/bash # Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one -# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at # https://securityonion.net/license; you may not use this file except in compliance with the # Elastic License 2.0. +# +# Note: Per the Elastic License 2.0, the second limitation states: +# +# "You may not move, change, disable, or circumvent the license key functionality +# in the software, and you may not remove or obscure any functionality in the +# software that is protected by the license key." # Setup logging LOG_FILE="/opt/so/log/so-minion.log" From 24eadf250768320433c158318c3e4253b83d52e8 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Thu, 16 Jan 2025 17:46:20 -0500 Subject: [PATCH 081/315] add libvirt state to highstate for hypervisor. update allowed_states for libvirt --- salt/allowed_states.map.jinja | 6 ++++-- salt/libvirt/packages.sls | 2 +- salt/libvirt/ssh/users.sls | 2 +- salt/top.sls | 1 + 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/salt/allowed_states.map.jinja b/salt/allowed_states.map.jinja index 25cae50a7..694c81bae 100644 --- a/salt/allowed_states.map.jinja +++ b/salt/allowed_states.map.jinja @@ -86,7 +86,8 @@ 'so-manager': [ 'salt.master', 'salt.cloud', - 'libvirt', + 'libvirt.packages', + 'libvirt.ssh.users', 'ca', 'ssl', 'registry', @@ -208,7 +209,8 @@ 'schedule', 'docker_clean', 'stig', - 'hypervisor' + 'hypervisor', + 'libvirt' ], 'so-desktop': [ 'ssl', diff --git a/salt/libvirt/packages.sls b/salt/libvirt/packages.sls index b1688b483..73a96811f 100644 --- a/salt/libvirt/packages.sls +++ b/salt/libvirt/packages.sls @@ -10,7 +10,7 @@ # software that is protected by the license key." {% from 'allowed_states.map.jinja' import allowed_states %} -{% if sls.split('.')[0] in allowed_states %} +{% if sls.split('.')[0] in allowed_states or sls in allowed_states %} {% if 'hvn' in salt['pillar.get']('features', []) %} # allows for creating vm images diff --git a/salt/libvirt/ssh/users.sls b/salt/libvirt/ssh/users.sls index 0829075d2..9b6a3beb7 100644 --- a/salt/libvirt/ssh/users.sls +++ b/salt/libvirt/ssh/users.sls @@ -10,7 +10,7 @@ # software that is protected by the license key." {% from 'allowed_states.map.jinja' import allowed_states %} -{% if sls in allowed_states %} +{% if sls.split('.')[0] in allowed_states or sls in allowed_states %} {% if 'hvn' in salt['pillar.get']('features', []) %} {% from 'vars/globals.map.jinja' import GLOBALS %} diff --git a/salt/top.sls b/salt/top.sls index 4f85b999e..d16e34d55 100644 --- a/salt/top.sls +++ b/salt/top.sls @@ -275,6 +275,7 @@ base: - firewall - elasticfleet.install_agent_grid - libvirt + - libvirt.images - stig '*_desktop and G@saltversion:{{saltversion}}': From 4cc36914891abb4591efc96ebbc405b7d228a30a Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Thu, 16 Jan 2025 17:51:39 -0500 Subject: [PATCH 082/315] give all nodes access to soc license pillar file --- pillar/top.sls | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/pillar/top.sls b/pillar/top.sls index 0f449a67c..3ff4672ae 100644 --- a/pillar/top.sls +++ b/pillar/top.sls @@ -18,6 +18,7 @@ base: - telegraf.adv_telegraf - versionlock.soc_versionlock - versionlock.adv_versionlock + - soc.license '* and not *_desktop': - firewall.soc_firewall @@ -44,7 +45,6 @@ base: - logstash.adv_logstash - soc.soc_soc - soc.adv_soc - - soc.license - kibana.soc_kibana - kibana.adv_kibana - kratos.soc_kratos @@ -88,7 +88,6 @@ base: - minions.{{ grains.id }} - minions.adv_{{ grains.id }} - stig.soc_stig - - soc.license '*_eval': - secrets @@ -113,7 +112,6 @@ base: - idstools.adv_idstools - soc.soc_soc - soc.adv_soc - - soc.license - kibana.soc_kibana - kibana.adv_kibana - strelka.soc_strelka @@ -170,7 +168,6 @@ base: - manager.adv_manager - soc.soc_soc - soc.adv_soc - - soc.license - kibana.soc_kibana - kibana.adv_kibana - strelka.soc_strelka @@ -236,7 +233,6 @@ base: - minions.{{ grains.id }} - minions.adv_{{ grains.id }} - stig.soc_stig - - soc.license - kafka.nodes - kafka.soc_kafka - kafka.adv_kafka @@ -254,8 +250,6 @@ base: - minions.adv_{{ grains.id }} - kafka.nodes - kafka.soc_kafka - - kafka.adv_kafka - - soc.license '*_import': - secrets @@ -277,7 +271,6 @@ base: - manager.adv_manager - soc.soc_soc - soc.adv_soc - - soc.license - kibana.soc_kibana - kibana.adv_kibana - backup.soc_backup @@ -320,4 +313,4 @@ base: - minions.{{ grains.id }} - minions.adv_{{ grains.id }} - stig.soc_stig - - soc.license + From 1f13554bd98aaf1928c7b869877c8ca212d818ff Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Fri, 17 Jan 2025 09:43:39 -0500 Subject: [PATCH 083/315] move add virt install and pool creation to images/init. start moving to /nsm/libvirt/ --- salt/_runners/setup_hypervisor.py | 29 +---------- salt/libvirt/images/init.sls | 81 +++++++++++++++++++++++++++++-- salt/libvirt/init.sls | 21 ++++---- 3 files changed, 88 insertions(+), 43 deletions(-) diff --git a/salt/_runners/setup_hypervisor.py b/salt/_runners/setup_hypervisor.py index 0a2845813..c5588689f 100644 --- a/salt/_runners/setup_hypervisor.py +++ b/salt/_runners/setup_hypervisor.py @@ -370,18 +370,7 @@ def setup_environment(vm_name: str = 'sool9', disk_size: str = '220G', minion_id log.info("MAIN: No changes detected, using existing VM %s", vm_name) vm_result = { 'success': True, - 'vm_dir': f'/opt/so/saltstack/local/salt/libvirt/images/{vm_name}', - 'commands': [ - f"virsh pool-create-as --name {vm_name} --type dir --target /opt/so/saltstack/local/salt/libvirt/images/{vm_name}", - f"""virt-install --name {vm_name} \\ - --memory 4096 --vcpus 4 --cpu host \\ - --disk /opt/so/saltstack/local/salt/libvirt/images/{vm_name}/{vm_name}.qcow2,format=qcow2,bus=virtio \\ - --disk /opt/so/saltstack/local/salt/libvirt/images/{vm_name}/{vm_name}-cidata.iso,device=cdrom \\ - --network bridge=br0,model=virtio \\ - --os-variant=ol9.5 \\ - --import \\ - --noautoconsole""" - ] + 'vm_dir': f'/opt/so/saltstack/local/salt/libvirt/images/{vm_name}' } success = vm_result.get('success', False) @@ -614,23 +603,9 @@ runcmd: user_data_path, meta_data_path], check=True, capture_output=True) - # Generate commands for hypervisor - commands = [ - f"virsh pool-create-as --name {vm_name} --type dir --target {vm_dir}", - f"""virt-install --name {vm_name} \\ - --memory 4096 --vcpus 4 --cpu host \\ - --disk {vm_image},format=qcow2,bus=virtio \\ - --disk {cidata_iso},device=cdrom \\ - --network bridge=br0,model=virtio \\ - --os-variant=ol9.5 \\ - --import \\ - --noautoconsole""" - ] - return { 'success': True, - 'vm_dir': vm_dir, - 'commands': commands + 'vm_dir': vm_dir } except Exception as e: diff --git a/salt/libvirt/images/init.sls b/salt/libvirt/images/init.sls index 864a2e2eb..e36fd628c 100644 --- a/salt/libvirt/images/init.sls +++ b/salt/libvirt/images/init.sls @@ -1,6 +1,79 @@ -# the source location will be /opt/so/saltstack/local/salt/libvirt/images/sool9 -# this will need to change to save the images to /nsm -baseimagefiles: +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. +# +# Note: Per the Elastic License 2.0, the second limitation states: +# +# "You may not move, change, disable, or circumvent the license key functionality +# in the software, and you may not remove or obscure any functionality in the +# software that is protected by the license key." + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states or sls in allowed_states %} +{% if 'hvn' in salt['pillar.get']('features', []) %} + +include: + - libvirt.packages + +# Copy base image files +baseimagefiles_sool9: file.recurse: - - name: /var/lib/libvirt/images/sool9/ + - name: /nsm/libvirt/images/sool9/ - source: salt://libvirt/images/sool9/ + - makedirs: True + +# Define the storage pool +define_storage_pool_sool9: + virt.pool_defined: + - name: sool9 + - ptype: dir + - target: /nsm/libvirt/images/sool9 + - require: + - file: baseimagefiles_sool9 + - cmd: libvirt_python_module + +# Start the storage pool +start_storage_pool_sool9: + virt.pool_running: + - name: sool9 + - ptype: dir + - target: /nsm/libvirt/images/sool9 + - require: + - virt: define_storage_pool_sool9 + - cmd: libvirt_python_module + +# Create and start the VM using virt-install +create_vm_sool9: + cmd.run: + - name: | + virt-install --name sool9 \ + --memory 4096 --vcpus 4 --cpu host \ + --disk /nsm/libvirt/images/sool9/sool9.qcow2,format=qcow2,bus=virtio \ + --disk /nsm/libvirt/images/sool9/sool9-cidata.iso,device=cdrom \ + --network bridge=br0,model=virtio \ + --os-variant=ol9.5 \ + --import \ + --noautoconsole + - unless: virsh list --all | grep -q sool9 + - require: + - virt: start_storage_pool_sool9 + - pkg: install_virt-install + +{% else %} +{{sls}}_no_license_detected: + test.fail_without_changes: + - name: {{sls}}_no_license_detected + - comment: + - "Hypervisor nodes are a feature supported only for customers with a valid license. + Contact Security Onion Solutions, LLC via our website at https://securityonionsolutions.com + for more information about purchasing a license to enable this feature." +{% endif %} + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/libvirt/init.sls b/salt/libvirt/init.sls index de67f2971..4321fdfb1 100644 --- a/salt/libvirt/init.sls +++ b/salt/libvirt/init.sls @@ -74,24 +74,21 @@ create_host_bridge: - forward: bridge - autostart: True -# set the default storage pool to point to the location we want -set_default_pool: - virt.pool_running: - - name: default - - ptype: dir - - target: /var/lib/libvirt/images/sool9 - - permissions: - - mode: 0711 - - owner: qemu - - group: qemu - - label: "system_u:object_r:virt_image_t:s0" # this doesnt seem to set the selinux context - - autostart: True +# Disable the default storage pool to avoid conflicts +disable_default_pool: + cmd.run: + - name: virsh pool-destroy default && virsh pool-autostart default --disable + - onlyif: virsh pool-list | grep default + - require: + - pkg: install_libvirt-client + - service: libvirt_service disable_default_bridge: cmd.run: - name: virsh net-destroy default && virsh net-autostart default --disable - require: - pkg: install_libvirt-client + - service: libvirt_service - onlyif: - virsh net-list | grep default From 54eeb0e327c672b84477f4bfb0d7500a7d3c5748 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Fri, 17 Jan 2025 19:27:04 -0500 Subject: [PATCH 084/315] handle refreshing base image and reinstalling the vm if the source qcow2 image changes --- salt/_runners/setup_hypervisor.py | 45 ++++++++++----- salt/libvirt/images/init.sls | 93 +++++++++++++++++++++++++++---- 2 files changed, 113 insertions(+), 25 deletions(-) diff --git a/salt/_runners/setup_hypervisor.py b/salt/_runners/setup_hypervisor.py index c5588689f..b7d842a52 100644 --- a/salt/_runners/setup_hypervisor.py +++ b/salt/_runners/setup_hypervisor.py @@ -10,6 +10,9 @@ # software that is protected by the license key." """ +TODO: Change default disk_size from 60G to 220G. this was set to speed up vm start during development + Remove passwd hash prior to release. used for development + This runner performs the initial setup required for hypervisor hosts in the environment. It handles downloading the Oracle Linux KVM image, setting up SSH keys for secure communication, and creating the initial VM. @@ -24,10 +27,10 @@ but can also be run manually if needed. CLI Examples: - # Perform complete environment setup (creates VM named 'sool9' with 220G disk by default) + # Perform complete environment setup (creates VM named 'sool9' with 60G disk by default) salt-run setup_hypervisor.setup_environment - # Setup with custom VM name (uses default 220G disk) + # Setup with custom VM name (uses default 60G disk) salt-run setup_hypervisor.setup_environment myvm # Setup with custom VM name and disk size @@ -36,7 +39,7 @@ CLI Examples: # Regenerate SSH keys only salt-run setup_hypervisor.regenerate_ssh_keys - # Create additional VM with default disk size (220G) + # Create additional VM with default disk size (60G) salt-run setup_hypervisor.create_vm myvm2 # Create additional VM with custom disk size @@ -301,7 +304,7 @@ def _check_vm_exists(vm_name: str) -> bool: log.info("MAIN: VM %s already exists", vm_name) return exists -def setup_environment(vm_name: str = 'sool9', disk_size: str = '220G', minion_id: str = None): +def setup_environment(vm_name: str = 'sool9', disk_size: str = '60G', minion_id: str = None): """ Main entry point to set up the hypervisor environment. This includes downloading the base image, generating SSH keys for remote access, @@ -311,7 +314,7 @@ def setup_environment(vm_name: str = 'sool9', disk_size: str = '220G', minion_id vm_name (str, optional): Name of the VM to create as part of environment setup. Defaults to 'sool9'. disk_size (str, optional): Size of the VM disk with unit. - Defaults to '220G'. + Defaults to '60G'. Returns: dict: Dictionary containing setup status and VM creation results @@ -397,13 +400,13 @@ def setup_environment(vm_name: str = 'sool9', disk_size: str = '220G', minion_id 'vm_result': vm_result } -def create_vm(vm_name: str, disk_size: str = '220G'): +def create_vm(vm_name: str, disk_size: str = '60G'): """ Create a new VM with cloud-init configuration. Args: vm_name (str): Name of the VM - disk_size (str): Size of the disk with unit (default: '220G') + disk_size (str): Size of the disk with unit (default: '60G') Returns: dict: Dictionary containing success status and commands to run on hypervisor @@ -496,10 +499,6 @@ ssh_genkeytypes: ['ed25519', 'rsa'] # set timezone for VM timezone: UTC -# Install QEMU guest agent. Enable and start the service -packages: - - qemu-guest-agent - write_files: - path: /etc/yum.repos.d/securityonion.repo content: | @@ -510,15 +509,22 @@ write_files: gpgcheck=1 sslverify=0 +packages: + - qemu-guest-agent + runcmd: - - systemctl enable --now qemu-guest-agent + # Remove all repo files except securityonion.repo + - for f in /etc/yum.repos.d/*.repo; do if [ "$(basename $f)" != "securityonion.repo" ]; then rm -f "$f"; fi; done - systemctl enable --now serial-getty@ttyS0.service - systemctl enable --now NetworkManager + - systemctl enable --now qemu-guest-agent - growpart /dev/vda 2 - pvresize /dev/vda2 - lvextend -l +100%FREE /dev/vg_main/lv_root - xfs_growfs /dev/vg_main/lv_root - - touch /etc/cloud/cloud-init.disabled + - systemctl stop cloud-init + - systemctl disable cloud-init + - dnf remove cloud-init - shutdown -P now """ user_data_path = os.path.join(vm_dir, 'user-data') @@ -603,6 +609,19 @@ runcmd: user_data_path, meta_data_path], check=True, capture_output=True) + # Generate SHA256 hash of the qcow2 image + sha256_hash = hashlib.sha256() + with salt.utils.files.fopen(vm_image, 'rb') as f: + for chunk in iter(lambda: f.read(4096), b''): + sha256_hash.update(chunk) + + # Write hash to file + hash_file = os.path.join(vm_dir, f'{vm_name}.sha256') + with salt.utils.files.fopen(hash_file, 'w') as f: + f.write(sha256_hash.hexdigest()) + + log.info("CREATEVM: Generated SHA256 hash for %s", vm_image) + return { 'success': True, 'vm_dir': vm_dir diff --git a/salt/libvirt/images/init.sls b/salt/libvirt/images/init.sls index e36fd628c..667835d3a 100644 --- a/salt/libvirt/images/init.sls +++ b/salt/libvirt/images/init.sls @@ -16,13 +16,43 @@ include: - libvirt.packages -# Copy base image files -baseimagefiles_sool9: - file.recurse: - - name: /nsm/libvirt/images/sool9/ - - source: salt://libvirt/images/sool9/ +# Manage SHA256 hash file +manage_sha256_sool9: + file.managed: + - name: /nsm/libvirt/images/sool9/sool9.sha256 + - source: salt://libvirt/images/sool9/sool9.sha256 - makedirs: True +# Manage qcow2 image +manage_qcow2_sool9: + file.managed: + - name: /nsm/libvirt/images/sool9/sool9.qcow2 + - source: salt://libvirt/images/sool9/sool9.qcow2 + - onchanges: + - file: manage_sha256_sool9 + +# Manage cloud-init files +manage_metadata_sool9: + file.managed: + - name: /nsm/libvirt/images/sool9/meta-data + - source: salt://libvirt/images/sool9/meta-data + - require: + - file: manage_qcow2_sool9 + +manage_userdata_sool9: + file.managed: + - name: /nsm/libvirt/images/sool9/user-data + - source: salt://libvirt/images/sool9/user-data + - require: + - file: manage_qcow2_sool9 + +manage_cidata_sool9: + file.managed: + - name: /nsm/libvirt/images/sool9/sool9-cidata.iso + - source: salt://libvirt/images/sool9/sool9-cidata.iso + - require: + - file: manage_qcow2_sool9 + # Define the storage pool define_storage_pool_sool9: virt.pool_defined: @@ -30,18 +60,56 @@ define_storage_pool_sool9: - ptype: dir - target: /nsm/libvirt/images/sool9 - require: - - file: baseimagefiles_sool9 + - file: manage_metadata_sool9 + - file: manage_userdata_sool9 + - file: manage_cidata_sool9 - cmd: libvirt_python_module + - unless: + - virsh pool-list --all | grep -q sool9 + +# Set pool autostart +set_pool_autostart_sool9: + cmd.run: + - name: virsh pool-autostart sool9 + - require: + - virt: define_storage_pool_sool9 + - unless: + - virsh pool-info sool9 | grep -q "Autostart.*yes" # Start the storage pool start_storage_pool_sool9: - virt.pool_running: - - name: sool9 - - ptype: dir - - target: /nsm/libvirt/images/sool9 + cmd.run: + - name: virsh pool-start sool9 - require: - virt: define_storage_pool_sool9 - cmd: libvirt_python_module + - unless: + - virsh pool-info sool9 | grep -q "State.*running" + +# Stop the VM if running and base image files change +stop_vm_sool9: + module.run: + - virt.stop: + - name: sool9 + - onchanges: + - file: manage_qcow2_sool9 + - require_in: + - module: undefine_vm_sool9 + - onlyif: + # Only try to stop if VM is actually running + - virsh list --state-running --name | grep -q sool9 + +undefine_vm_sool9: + module.run: + - virt.undefine: + - vm_: sool9 + - onchanges: + - file: manage_qcow2_sool9 + # Note: When VM doesn't exist, you'll see "error: failed to get domain 'sool9'" - this is expected + # [ERROR ] Command 'virsh' failed with return code: 1 + # [ERROR ] stdout: error: failed to get domain 'sool9' + - onlyif: + - virsh dominfo sool9 # Create and start the VM using virt-install create_vm_sool9: @@ -55,10 +123,11 @@ create_vm_sool9: --os-variant=ol9.5 \ --import \ --noautoconsole - - unless: virsh list --all | grep -q sool9 - require: - - virt: start_storage_pool_sool9 + - cmd: start_storage_pool_sool9 - pkg: install_virt-install + - onchanges: + - file: manage_qcow2_sool9 {% else %} {{sls}}_no_license_detected: From a896332db321f3487fb2214a73d93319edd27d04 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Fri, 17 Jan 2025 19:49:41 -0500 Subject: [PATCH 085/315] fix deprecation --- salt/_runners/setup_hypervisor.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/salt/_runners/setup_hypervisor.py b/salt/_runners/setup_hypervisor.py index b7d842a52..ac0811591 100644 --- a/salt/_runners/setup_hypervisor.py +++ b/salt/_runners/setup_hypervisor.py @@ -486,7 +486,7 @@ users: sudo: ALL=(ALL) NOPASSWD:ALL lock_passwd: false passwd: $6$THWuTZMZhIVMGaaw$w9kozn7z7i0Y9LRVGZwN6mcZag4vMpE3hW6eCtKNHlFpL1XLcOdiIr29JyDxx3MLBXNedIqnqcj4psqCjv58d. - ssh-authorized-keys: + ssh_authorized_keys: - {ssh_pub_key} # Configure where output will go @@ -509,9 +509,6 @@ write_files: gpgcheck=1 sslverify=0 -packages: - - qemu-guest-agent - runcmd: # Remove all repo files except securityonion.repo - for f in /etc/yum.repos.d/*.repo; do if [ "$(basename $f)" != "securityonion.repo" ]; then rm -f "$f"; fi; done From 3a78be68d6cdde2b505fe257ff970c26bf249955 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Fri, 17 Jan 2025 20:05:35 -0500 Subject: [PATCH 086/315] ensure cloud-init is removed --- salt/_runners/setup_hypervisor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/_runners/setup_hypervisor.py b/salt/_runners/setup_hypervisor.py index ac0811591..ee1e0d91d 100644 --- a/salt/_runners/setup_hypervisor.py +++ b/salt/_runners/setup_hypervisor.py @@ -521,7 +521,7 @@ runcmd: - xfs_growfs /dev/vg_main/lv_root - systemctl stop cloud-init - systemctl disable cloud-init - - dnf remove cloud-init + - dnf -y remove cloud-init - shutdown -P now """ user_data_path = os.path.join(vm_dir, 'user-data') From 60387651d20078931e18ac69a6f2430d54fb2af5 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Fri, 17 Jan 2025 20:13:42 -0500 Subject: [PATCH 087/315] recreate the base vm if any of the cloud init files change --- salt/libvirt/images/init.sls | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/salt/libvirt/images/init.sls b/salt/libvirt/images/init.sls index 667835d3a..aba2744a8 100644 --- a/salt/libvirt/images/init.sls +++ b/salt/libvirt/images/init.sls @@ -93,6 +93,9 @@ stop_vm_sool9: - name: sool9 - onchanges: - file: manage_qcow2_sool9 + - file: manage_metadata_sool9 + - file: manage_userdata_sool9 + - file: manage_cidata_sool9 - require_in: - module: undefine_vm_sool9 - onlyif: @@ -105,6 +108,9 @@ undefine_vm_sool9: - vm_: sool9 - onchanges: - file: manage_qcow2_sool9 + - file: manage_metadata_sool9 + - file: manage_userdata_sool9 + - file: manage_cidata_sool9 # Note: When VM doesn't exist, you'll see "error: failed to get domain 'sool9'" - this is expected # [ERROR ] Command 'virsh' failed with return code: 1 # [ERROR ] stdout: error: failed to get domain 'sool9' @@ -128,6 +134,9 @@ create_vm_sool9: - pkg: install_virt-install - onchanges: - file: manage_qcow2_sool9 + - file: manage_metadata_sool9 + - file: manage_userdata_sool9 + - file: manage_cidata_sool9 {% else %} {{sls}}_no_license_detected: From a74ed0daf0f11bbeac2bf1a838c08572897c2240 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Fri, 17 Jan 2025 21:25:40 -0500 Subject: [PATCH 088/315] fix disabling cloud-init and system shutdown. increase ram/cpu of base vm. shrink disk_size to 6G for testing --- salt/_runners/setup_hypervisor.py | 27 +++++++++++++++------------ salt/libvirt/images/init.sls | 2 +- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/salt/_runners/setup_hypervisor.py b/salt/_runners/setup_hypervisor.py index ee1e0d91d..145eddf7f 100644 --- a/salt/_runners/setup_hypervisor.py +++ b/salt/_runners/setup_hypervisor.py @@ -10,7 +10,7 @@ # software that is protected by the license key." """ -TODO: Change default disk_size from 60G to 220G. this was set to speed up vm start during development +TODO: Change default disk_size from 6G to 220G. this was set to speed up vm start during development Remove passwd hash prior to release. used for development This runner performs the initial setup required for hypervisor hosts in the environment. @@ -27,10 +27,10 @@ but can also be run manually if needed. CLI Examples: - # Perform complete environment setup (creates VM named 'sool9' with 60G disk by default) + # Perform complete environment setup (creates VM named 'sool9' with 6G disk by default) salt-run setup_hypervisor.setup_environment - # Setup with custom VM name (uses default 60G disk) + # Setup with custom VM name (uses default 6G disk) salt-run setup_hypervisor.setup_environment myvm # Setup with custom VM name and disk size @@ -39,7 +39,7 @@ CLI Examples: # Regenerate SSH keys only salt-run setup_hypervisor.regenerate_ssh_keys - # Create additional VM with default disk size (60G) + # Create additional VM with default disk size (6G) salt-run setup_hypervisor.create_vm myvm2 # Create additional VM with custom disk size @@ -304,7 +304,7 @@ def _check_vm_exists(vm_name: str) -> bool: log.info("MAIN: VM %s already exists", vm_name) return exists -def setup_environment(vm_name: str = 'sool9', disk_size: str = '60G', minion_id: str = None): +def setup_environment(vm_name: str = 'sool9', disk_size: str = '6G', minion_id: str = None): """ Main entry point to set up the hypervisor environment. This includes downloading the base image, generating SSH keys for remote access, @@ -314,7 +314,7 @@ def setup_environment(vm_name: str = 'sool9', disk_size: str = '60G', minion_id: vm_name (str, optional): Name of the VM to create as part of environment setup. Defaults to 'sool9'. disk_size (str, optional): Size of the VM disk with unit. - Defaults to '60G'. + Defaults to '6G'. Returns: dict: Dictionary containing setup status and VM creation results @@ -400,13 +400,13 @@ def setup_environment(vm_name: str = 'sool9', disk_size: str = '60G', minion_id: 'vm_result': vm_result } -def create_vm(vm_name: str, disk_size: str = '60G'): +def create_vm(vm_name: str, disk_size: str = '6G'): """ Create a new VM with cloud-init configuration. Args: vm_name (str): Name of the VM - disk_size (str): Size of the disk with unit (default: '60G') + disk_size (str): Size of the disk with unit (default: '6G') Returns: dict: Dictionary containing success status and commands to run on hypervisor @@ -519,10 +519,13 @@ runcmd: - pvresize /dev/vda2 - lvextend -l +100%FREE /dev/vg_main/lv_root - xfs_growfs /dev/vg_main/lv_root - - systemctl stop cloud-init - - systemctl disable cloud-init - - dnf -y remove cloud-init - - shutdown -P now + - touch /etc/cloud/cloud-init.disabled + +power_state: + delay: "now" + mode: poweroff + timeout: 30 + condition: True """ user_data_path = os.path.join(vm_dir, 'user-data') with salt.utils.files.fopen(user_data_path, 'w') as f: diff --git a/salt/libvirt/images/init.sls b/salt/libvirt/images/init.sls index aba2744a8..8532760a7 100644 --- a/salt/libvirt/images/init.sls +++ b/salt/libvirt/images/init.sls @@ -122,7 +122,7 @@ create_vm_sool9: cmd.run: - name: | virt-install --name sool9 \ - --memory 4096 --vcpus 4 --cpu host \ + --memory 12288 --vcpus 8 --cpu host \ --disk /nsm/libvirt/images/sool9/sool9.qcow2,format=qcow2,bus=virtio \ --disk /nsm/libvirt/images/sool9/sool9-cidata.iso,device=cdrom \ --network bridge=br0,model=virtio \ From ae01dc963943eea54b24fa02926107e4bedca1f4 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Fri, 17 Jan 2025 22:26:39 -0500 Subject: [PATCH 089/315] manager needs more packages for salt-cloud. change location of priv key for salt-cloud config --- salt/libvirt/packages.sls | 30 +++++++++---------- .../cloud/cloud.profiles.d/socloud.conf.jinja | 2 +- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/salt/libvirt/packages.sls b/salt/libvirt/packages.sls index 73a96811f..195232329 100644 --- a/salt/libvirt/packages.sls +++ b/salt/libvirt/packages.sls @@ -25,12 +25,25 @@ install_xorriso: pkg.installed: - name: xorriso -{% if 'hyper' in grains.id.split('_') | last %} - install_libvirt-libs: pkg.installed: - name: libvirt-libs +libvirt_python_wheel: + file.recurse: + - name: /opt/so/conf/libvirt/source-packages/libvirt-python + - source: salt://libvirt/source-packages/libvirt-python + - makedirs: True + - clean: True + +libvirt_python_module: + cmd.run: + - name: /opt/saltstack/salt/bin/python3 -m pip install --no-index --find-links=/opt/so/conf/libvirt/source-packages/libvirt-python libvirt-python + - onchanges: + - file: libvirt_python_wheel + +{% if 'hyper' in grains.id.split('_') | last %} + # provides virsh install_libvirt-client: pkg.installed: @@ -50,19 +63,6 @@ install_python3-libguestfs: - name: python3-libguestfs ### -libvirt_python_wheel: - file.recurse: - - name: /opt/so/conf/libvirt/source-packages/libvirt-python - - source: salt://libvirt/source-packages/libvirt-python - - makedirs: True - - clean: True - -libvirt_python_module: - cmd.run: - - name: /opt/saltstack/salt/bin/python3 -m pip install --no-index --find-links=/opt/so/conf/libvirt/source-packages/libvirt-python libvirt-python - - onchanges: - - file: libvirt_python_wheel - {% endif %} {% else %} diff --git a/salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja b/salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja index 70a14225c..0e65c60e0 100644 --- a/salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja +++ b/salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja @@ -11,7 +11,7 @@ sool9-{{host}}: base_domain: sool9 ip_source: qemu-agent ssh_username: soqemussh - private_key: /home/soqemussh/.ssh/id_ed25519 + private_key: /etc/ssh/auth_keys/soqemussh/id_ed25519 sudo: True deploy_command: sh /tmp/.saltcloud-*/deploy.sh script_args: -F -x python3 stable 3006.9 From c13c85bd2d2e7899b2520e1d8532cd2e0e0286e6 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Fri, 17 Jan 2025 22:54:46 -0500 Subject: [PATCH 090/315] manager needs ssh config. need -r to ignore bootstrap provided repos --- salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja | 2 +- salt/salt/cloud/init.sls | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja b/salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja index 0e65c60e0..eb2f5b75e 100644 --- a/salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja +++ b/salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja @@ -14,7 +14,7 @@ sool9-{{host}}: private_key: /etc/ssh/auth_keys/soqemussh/id_ed25519 sudo: True deploy_command: sh /tmp/.saltcloud-*/deploy.sh - script_args: -F -x python3 stable 3006.9 + script_args: -r -F -x python3 stable 3006.9 minion: master: {{ grains.host }} master_port: 4506 diff --git a/salt/salt/cloud/init.sls b/salt/salt/cloud/init.sls index 7d987a5da..b0f9ca7fa 100644 --- a/salt/salt/cloud/init.sls +++ b/salt/salt/cloud/init.sls @@ -17,6 +17,7 @@ include: - libvirt.packages + - libvirt.ssh.users install_salt_cloud: pkg.installed: From 7c50a5e17b51447a61d4ead2dbe7de930d7d69cf Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Fri, 17 Jan 2025 23:16:18 -0500 Subject: [PATCH 091/315] cloud-init needs to import repo gpg keys so packags can install --- salt/_runners/setup_hypervisor.py | 46 ++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/salt/_runners/setup_hypervisor.py b/salt/_runners/setup_hypervisor.py index 145eddf7f..a366eacad 100644 --- a/salt/_runners/setup_hypervisor.py +++ b/salt/_runners/setup_hypervisor.py @@ -46,6 +46,7 @@ CLI Examples: salt-run setup_hypervisor.create_vm myvm3 300G """ +import base64 import hashlib import logging import os @@ -71,6 +72,16 @@ formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(messag stream_handler.setFormatter(formatter) log.addHandler(stream_handler) +def _read_and_encode_key(key_path: str) -> str: + """Read a key file and return its base64 encoded content.""" + try: + with salt.utils.files.fopen(key_path, 'rb') as f: + content = f.read() + return base64.b64encode(content).decode('utf-8') + except Exception as e: + log.error("Error reading key file %s: %s", key_path, str(e)) + raise + def _check_license(): """Check if the license file exists and contains required values.""" license_path = '/opt/so/saltstack/local/pillar/soc/license.sls' @@ -463,6 +474,14 @@ def create_vm(vm_name: str, disk_size: str = '6G'): # Get hostname for repo configuration manager_hostname = socket.gethostname() + # Read and encode GPG keys + keys_dir = '/opt/so/saltstack/default/salt/repo/client/files/oracle/keys' + oracle_key = _read_and_encode_key(os.path.join(keys_dir, 'RPM-GPG-KEY-oracle')) + epel_key = _read_and_encode_key(os.path.join(keys_dir, 'RPM-GPG-KEY-EPEL-9')) + salt_key = _read_and_encode_key(os.path.join(keys_dir, 'SALT-PROJECT-GPG-PUBKEY-2023.pub')) + docker_key = _read_and_encode_key(os.path.join(keys_dir, 'docker.pub')) + securityonion_key = _read_and_encode_key(os.path.join(keys_dir, 'securityonion.pub')) + # Create meta-data meta_data = f"""instance-id: {vm_name} local-hostname: {vm_name} @@ -508,9 +527,34 @@ write_files: enabled=1 gpgcheck=1 sslverify=0 + - path: /etc/pki/rpm-gpg/RPM-GPG-KEY-oracle + encoding: b64 + content: | + {oracle_key} + - path: /etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-9 + encoding: b64 + content: | + {epel_key} + - path: /etc/pki/rpm-gpg/SALT-PROJECT-GPG-PUBKEY-2023.pub + encoding: b64 + content: | + {salt_key} + - path: /etc/pki/rpm-gpg/docker.pub + encoding: b64 + content: | + {docker_key} + - path: /etc/pki/rpm-gpg/securityonion.pub + encoding: b64 + content: | + {securityonion_key} runcmd: - # Remove all repo files except securityonion.repo + # Import GPG keys and remove repo files except securityonion.repo + - rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-oracle + - rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-9 + - rpm --import /etc/pki/rpm-gpg/SALT-PROJECT-GPG-PUBKEY-2023.pub + - rpm --import /etc/pki/rpm-gpg/docker.pub + - rpm --import /etc/pki/rpm-gpg/securityonion.pub - for f in /etc/yum.repos.d/*.repo; do if [ "$(basename $f)" != "securityonion.repo" ]; then rm -f "$f"; fi; done - systemctl enable --now serial-getty@ttyS0.service - systemctl enable --now NetworkManager From 8ed3f0b1cc0ce2ad55d42035e3280c4e1c84368a Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Sat, 18 Jan 2025 07:30:36 -0500 Subject: [PATCH 092/315] change base image path for so-salt-cloud --- salt/hypervisor/tools/sbin/so-qcow2-modify-network | 4 ++-- salt/manager/tools/sbin/so-salt-cloud | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/salt/hypervisor/tools/sbin/so-qcow2-modify-network b/salt/hypervisor/tools/sbin/so-qcow2-modify-network index 4e96bca22..c5aa1aa22 100644 --- a/salt/hypervisor/tools/sbin/so-qcow2-modify-network +++ b/salt/hypervisor/tools/sbin/so-qcow2-modify-network @@ -12,9 +12,9 @@ Usage: python so-qcow2-modify-network.py -I -i (--dhcp4 | --static4 --ip4 --gw4 ) [--dns4 ] [--search4 ] Examples: - python so-qcow2-modify-network.py -I /var/lib/libvirt/images/sool9/sool9.qcow2 -i eth0 --static4 --ip4 192.168.1.10/24 --gw4 192.168.1.1 --dns4 192.168.1.1,8.8.8.8 --search4 example.local + python so-qcow2-modify-network.py -I /nsm/libvirt/images/sool9/sool9.qcow2 -i eth0 --static4 --ip4 192.168.1.10/24 --gw4 192.168.1.1 --dns4 192.168.1.1,8.8.8.8 --search4 example.local - python so-qcow2-modify-network.py -I /var/lib/libvirt/images/sool9/sool9.qcow2 -i eth0 --dhcp4 + python so-qcow2-modify-network.py -I /nsm/libvirt/images/sool9/sool9.qcow2 -i eth0 --dhcp4 """ import argparse diff --git a/salt/manager/tools/sbin/so-salt-cloud b/salt/manager/tools/sbin/so-salt-cloud index 9bf4e2227..816f74a46 100644 --- a/salt/manager/tools/sbin/so-salt-cloud +++ b/salt/manager/tools/sbin/so-salt-cloud @@ -236,7 +236,7 @@ def run_qcow2_modify_hardware_config(profile, vm_name, cpu=None, memory=None, pc def run_qcow2_modify_network_config(profile, mode, ip=None, gateway=None, dns=None, search_domain=None): hv_name = profile.split('-')[1] target = hv_name + "_*" - image = '/var/lib/libvirt/images/sool9/sool9.qcow2' + image = '/nsm/libvirt/images/sool9/sool9.qcow2' interface = 'eth0' try: From 17943ef0dbbb197186ab0ed32ce3748b58bffe6f Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Sat, 18 Jan 2025 08:24:50 -0500 Subject: [PATCH 093/315] add hypervisor state to hypervisor node --- salt/_modules/qcow2.py | 2 +- salt/top.sls | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/salt/_modules/qcow2.py b/salt/_modules/qcow2.py index 0cbcd8707..0339849fa 100644 --- a/salt/_modules/qcow2.py +++ b/salt/_modules/qcow2.py @@ -29,7 +29,7 @@ def modify_network_config(image, interface, mode, ip4=None, gw4=None, dns4=None, .. code-block:: bash - salt '*' qcow2.modify_network_config image='/path/to/image.qcow2' interface='eth0' mode='static4' ip4='192.168.1.10/24' gw4='192.168.1.1' dns4='192.168.1.1,8.8.8.8' search4='example.local' + salt '*' qcow2.modify_network_config image='/nsm/libvirt/images/sool9/sool9.qcow2' interface='eth0' mode='static4' ip4='192.168.1.10/24' gw4='192.168.1.1' dns4='192.168.1.1,8.8.8.8' search4='example.local' ''' diff --git a/salt/top.sls b/salt/top.sls index d16e34d55..edabfe97e 100644 --- a/salt/top.sls +++ b/salt/top.sls @@ -276,6 +276,7 @@ base: - elasticfleet.install_agent_grid - libvirt - libvirt.images + - hypervisor - stig '*_desktop and G@saltversion:{{saltversion}}': From 64c923042387a88f507c9287657030fb09133a19 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Sat, 18 Jan 2025 10:44:44 -0500 Subject: [PATCH 094/315] prevent conflicts with network manager in base vm --- salt/_runners/setup_hypervisor.py | 171 ++++++++++++++++++++++++------ 1 file changed, 136 insertions(+), 35 deletions(-) diff --git a/salt/_runners/setup_hypervisor.py b/salt/_runners/setup_hypervisor.py index a366eacad..81dfd08f4 100644 --- a/salt/_runners/setup_hypervisor.py +++ b/salt/_runners/setup_hypervisor.py @@ -13,37 +13,55 @@ TODO: Change default disk_size from 6G to 220G. this was set to speed up vm start during development Remove passwd hash prior to release. used for development -This runner performs the initial setup required for hypervisor hosts in the environment. -It handles downloading the Oracle Linux KVM image, setting up SSH keys for secure -communication, and creating the initial VM. +This runner performs the initial setup required for hypervisor hosts in the Security Onion environment. +It handles downloading the Oracle Linux KVM image, setting up SSH keys for secure communication, +and creating virtual machines with cloud-init configuration. -Functions: - setup_environment: Downloads image, sets up SSH keys, and creates initial VM - regenerate_ssh_keys: Regenerates SSH keys for remote access - create_vm: Creates a new VM with cloud-init configuration +Usage: + salt-run setup_hypervisor. [arguments] -The runner is typically triggered automatically when a new hypervisor minion connects, -but can also be run manually if needed. +Options: + vm_name: Name for the virtual machine (alphanumeric, hyphens, underscores) + disk_size: Size of the VM disk with unit (e.g., '6G', '300G') + minion_id: Salt minion ID of the hypervisor (optional) -CLI Examples: - - # Perform complete environment setup (creates VM named 'sool9' with 6G disk by default) +Examples: + # Complete environment setup (default VM 'sool9' with 6G disk) salt-run setup_hypervisor.setup_environment - # Setup with custom VM name (uses default 6G disk) - salt-run setup_hypervisor.setup_environment myvm - # Setup with custom VM name and disk size salt-run setup_hypervisor.setup_environment myvm 300G - # Regenerate SSH keys only + # Regenerate SSH keys salt-run setup_hypervisor.regenerate_ssh_keys - # Create additional VM with default disk size (6G) - salt-run setup_hypervisor.create_vm myvm2 + # Create additional VM + salt-run setup_hypervisor.create_vm myvm2 300G - # Create additional VM with custom disk size - salt-run setup_hypervisor.create_vm myvm3 300G + Notes: + - Verifies Security Onion license + - Downloads and validates Oracle Linux KVM image if needed + - Generates Ed25519 SSH keys if not present + - Creates/recreates VM based on environment changes + - Forces hypervisor configuration via highstate after successful setup (when minion_id provided) + + Description: + The setup process includes: + 1. License validation + 2. Oracle Linux KVM image download and checksum verification + 3. SSH key generation for secure VM access + 4. Cloud-init configuration for VM provisioning + 5. VM creation with specified disk size + 6. Hypervisor configuration via highstate (when minion_id provided and setup successful) + +Exit Codes: + Success: Returns dictionary with 'success': True and VM details + Failure: Returns dictionary with 'success': False and error message + +Logging: + All operations are logged to: + - Standard output (INFO level and above) + - System log with 'setup_hypervisor' tag """ import base64 @@ -318,17 +336,42 @@ def _check_vm_exists(vm_name: str) -> bool: def setup_environment(vm_name: str = 'sool9', disk_size: str = '6G', minion_id: str = None): """ Main entry point to set up the hypervisor environment. - This includes downloading the base image, generating SSH keys for remote access, - and creating the initial VM. + + This function orchestrates the complete setup process for a Security Onion hypervisor, + including image management, SSH key setup, and VM creation. It ensures all components + are properly configured and validates the environment at each step. Args: - vm_name (str, optional): Name of the VM to create as part of environment setup. - Defaults to 'sool9'. - disk_size (str, optional): Size of the VM disk with unit. - Defaults to '6G'. + vm_name (str, optional): Name for the VM to create. Must contain only + alphanumeric characters, hyphens, or underscores. + Defaults to 'sool9'. + disk_size (str, optional): Size of the VM disk with unit (e.g., '6G', '300G'). + Must end with 'G' or 'M'. Defaults to '6G'. + minion_id (str, optional): Salt minion ID of the hypervisor. When provided, + forces the hypervisor to apply its configuration via + highstate after successful environment setup (image + download, SSH keys, VM creation). Returns: - dict: Dictionary containing setup status and VM creation results + dict: A dictionary containing: + - success (bool): True if setup completed successfully + - error (str): Error message if setup failed, None otherwise + - vm_result (dict): Details about VM creation if successful + + Notes: + - Verifies Security Onion license + - Downloads and validates Oracle Linux KVM image if needed + - Generates Ed25519 SSH keys if not present + - Creates/recreates VM based on environment changes + - Forces hypervisor configuration via highstate after successful setup + (when minion_id is provided) + + Example: + result = setup_environment('myvm', '300G', 'hypervisor1') + if result['success']: + print(f"VM created at {result['vm_result']['vm_dir']}") + else: + print(f"Setup failed: {result['error']}") """ # Check license before proceeding if not _check_license(): @@ -413,14 +456,39 @@ def setup_environment(vm_name: str = 'sool9', disk_size: str = '6G', minion_id: def create_vm(vm_name: str, disk_size: str = '6G'): """ - Create a new VM with cloud-init configuration. - + Creates a new virtual machine with cloud-init configuration. + + This function handles the complete VM creation process, including directory setup, + image management, and cloud-init configuration. It ensures proper setup of the VM + environment with all necessary components. + Args: - vm_name (str): Name of the VM - disk_size (str): Size of the disk with unit (default: '6G') - + vm_name (str): Name for the VM. Must contain only alphanumeric characters, + hyphens, or underscores. + disk_size (str): Size of the VM disk with unit (e.g., '6G', '300G'). + Must end with 'G' or 'M'. Defaults to '6G'. + Returns: - dict: Dictionary containing success status and commands to run on hypervisor + dict: A dictionary containing: + - success (bool): True if VM creation completed successfully + - error (str): Error message if creation failed + - vm_dir (str): Path to VM directory if successful + + Notes: + - Validates Security Onion license + - Creates cloud-init ISO for VM configuration + - Copies and resizes base Oracle Linux image + - Compresses final image for efficiency + - Generates SHA256 hash for verification + - Configures repositories and GPG keys + - Sets up system services and storage + + Example: + result = create_vm('myvm', '300G') + if result['success']: + print(f"VM created at {result['vm_dir']}") + else: + print(f"Creation failed: {result['error']}") """ # Check license before proceeding if not _check_license(): @@ -518,6 +586,10 @@ ssh_genkeytypes: ['ed25519', 'rsa'] # set timezone for VM timezone: UTC +# Disable cloud-init network configuration to prevent conflicts with NetworkManager +network: + config: disabled + write_files: - path: /etc/yum.repos.d/securityonion.repo content: | @@ -564,6 +636,7 @@ runcmd: - lvextend -l +100%FREE /dev/vg_main/lv_root - xfs_growfs /dev/vg_main/lv_root - touch /etc/cloud/cloud-init.disabled + - rm -f /etc/sysconfig/network-scripts/ifcfg-eth0 power_state: delay: "now" @@ -677,9 +750,37 @@ power_state: def regenerate_ssh_keys(): """ - Regenerate SSH keys. + Regenerates SSH keys used for hypervisor VM access. + + This function handles the complete process of SSH key regeneration, including + validation, cleanup of existing keys, and generation of new keys with proper + permissions and distribution. + Returns: - bool: True if successful, False on error + bool: True if keys were successfully regenerated, False otherwise + + Notes: + - Validates Security Onion license + - Removes existing keys if present + - Generates new Ed25519 key pair + - Sets secure permissions (600 for private, 644 for public) + - Distributes public key to required locations + + Description: + The function performs these steps: + 1. Validates Security Onion license + 2. Checks for existing SSH keys + 3. Removes old keys if present + 4. Creates required directories with secure permissions + 5. Generates new Ed25519 key pair + 6. Sets appropriate file permissions + 7. Distributes public key to required locations + + Example: + if regenerate_ssh_keys(): + print("SSH keys successfully regenerated") + else: + print("Failed to regenerate SSH keys") """ # Check license before proceeding if not _check_license(): From 9db3cd901cfe865b23c6ff86bae286732a7fee6c Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Sat, 18 Jan 2025 10:45:10 -0500 Subject: [PATCH 095/315] update documentation of core functionality --- salt/_modules/qcow2.py | 154 ++++++++++++--- .../tools/sbin/so-kvm-modify-hardware | 102 ++++++++-- .../tools/sbin/so-qcow2-modify-network | 110 ++++++++++- salt/manager/tools/sbin/so-salt-cloud | 183 ++++++++++++------ 4 files changed, 444 insertions(+), 105 deletions(-) diff --git a/salt/_modules/qcow2.py b/salt/_modules/qcow2.py index 0339849fa..37858484e 100644 --- a/salt/_modules/qcow2.py +++ b/salt/_modules/qcow2.py @@ -1,5 +1,23 @@ #!py +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +""" +Salt module for managing QCOW2 image configurations and VM hardware settings. This module provides functions +for modifying network configurations within QCOW2 images and adjusting virtual machine hardware settings. +It serves as a Salt interface to the so-qcow2-modify-network and so-kvm-modify-hardware scripts. + +The module offers two main capabilities: +1. Network Configuration: Modify network settings (DHCP/static IP) within QCOW2 images +2. Hardware Configuration: Adjust VM hardware settings (CPU, memory, PCI passthrough) + +This module is intended to work with Security Onion's virtualization infrastructure and is typically +used in conjunction with salt-cloud for VM provisioning and management. +""" + import logging import subprocess import shlex @@ -13,24 +31,67 @@ def __virtual__(): def modify_network_config(image, interface, mode, ip4=None, gw4=None, dns4=None, search4=None): ''' - Wrapper function to call so-qcow2-modify-network + Usage: + salt '*' qcow2.modify_network_config image= interface= mode= [ip4=] [gw4=] [dns4=] [search4=] - :param image: Path to the QCOW2 image. - :param interface: Network interface to modify (e.g., 'eth0'). - :param mode: 'dhcp4' or 'static4'. - :param ip4: IPv4 address with CIDR notation (e.g., '192.168.1.10/24'). Required for static configuration. - :param gw4: IPv4 gateway (e.g., '192.168.1.1'). Required for static configuration. - :param dns4: Comma-separated list of IPv4 DNS servers (e.g., '8.8.8.8,8.8.4.4'). - :param search4: DNS search domain for IPv4. + Options: + image + Path to the QCOW2 image file that will be modified + interface + Network interface name to configure (e.g., 'eth0') + mode + Network configuration mode, either 'dhcp4' or 'static4' + ip4 + IPv4 address with CIDR notation (e.g., '192.168.1.10/24') + Required when mode='static4' + gw4 + IPv4 gateway address (e.g., '192.168.1.1') + Required when mode='static4' + dns4 + Comma-separated list of IPv4 DNS servers (e.g., '8.8.8.8,8.8.4.4') + Optional for both DHCP and static configurations + search4 + DNS search domain for IPv4 (e.g., 'example.local') + Optional for both DHCP and static configurations - :return: A dictionary with the result of the script execution. + Examples: + 1. **Configure DHCP:** + ```bash + salt '*' qcow2.modify_network_config image='/nsm/libvirt/images/sool9/sool9.qcow2' interface='eth0' mode='dhcp4' + ``` + This configures eth0 to use DHCP for IP assignment - CLI Example: + 2. **Configure Static IP:** + ```bash + salt '*' qcow2.modify_network_config image='/nsm/libvirt/images/sool9/sool9.qcow2' interface='eth0' mode='static4' ip4='192.168.1.10/24' gw4='192.168.1.1' dns4='192.168.1.1,8.8.8.8' search4='example.local' + ``` + This sets a static IP configuration with DNS servers and search domain - .. code-block:: bash + Notes: + - The QCOW2 image must be accessible and writable by the salt minion + - The image should not be in use by a running VM when modified + - Network changes take effect on next VM boot + - Requires so-qcow2-modify-network script to be installed - salt '*' qcow2.modify_network_config image='/nsm/libvirt/images/sool9/sool9.qcow2' interface='eth0' mode='static4' ip4='192.168.1.10/24' gw4='192.168.1.1' dns4='192.168.1.1,8.8.8.8' search4='example.local' + Description: + This function modifies network configuration within a QCOW2 image file by executing + the so-qcow2-modify-network script. It supports both DHCP and static IPv4 configuration. + The script mounts the image, modifies the network configuration files, and unmounts + safely. All operations are logged for troubleshooting purposes. + Exit Codes: + 0: Success + 1: Invalid parameters or configuration + 2: Image access or mounting error + 3: Network configuration error + 4: System command error + 255: Unexpected error + + Logging: + - All operations are logged to the salt minion log + - Log entries are prefixed with 'qcow2 module:' + - Error conditions include detailed error messages and stack traces + - Success/failure status is logged for verification ''' cmd = ['/usr/sbin/so-qcow2-modify-network', '-I', image, '-i', interface] @@ -69,22 +130,71 @@ def modify_network_config(image, interface, mode, ip4=None, gw4=None, dns4=None, def modify_hardware_config(vm_name, cpu=None, memory=None, pci=None, start=False): ''' - Wrapper function to call so-kvm-modify-hardware + Usage: + salt '*' qcow2.modify_hardware_config vm_name= [cpu=] [memory=] [pci=] [start=] - :param vm_name: Name of the virtual machine to modify. - :param cpu: Number of virtual CPUs to assign. - :param memory: Amount of memory to assign in MiB. - :param pci: PCI hardware ID to passthrough to the VM (e.g., '0000:00:1f.2'). - :param start: Boolean flag to start the VM after modification. + Options: + vm_name + Name of the virtual machine to modify + cpu + Number of virtual CPUs to assign (positive integer) + Optional - VM's current CPU count retained if not specified + memory + Amount of memory to assign in MiB (positive integer) + Optional - VM's current memory size retained if not specified + pci + PCI hardware ID to passthrough to the VM (e.g., '0000:00:1f.2') + Optional - no PCI passthrough if not specified + start + Boolean flag to start the VM after modification + Optional - defaults to False - :return: A dictionary with the result of the script execution. + Examples: + 1. **Modify CPU and Memory:** + ```bash + salt '*' qcow2.modify_hardware_config vm_name='sensor1' cpu=4 memory=8192 + ``` + This assigns 4 CPUs and 8GB memory to the VM - CLI Example: + 2. **Enable PCI Passthrough:** + ```bash + salt '*' qcow2.modify_hardware_config vm_name='sensor1' pci='0000:00:1f.2' start=True + ``` + This configures PCI passthrough and starts the VM - .. code-block:: bash + 3. **Complete Hardware Configuration:** + ```bash + salt '*' qcow2.modify_hardware_config vm_name='sensor1' cpu=8 memory=16384 pci='0000:00:1f.2' start=True + ``` + This sets CPU, memory, PCI passthrough, and starts the VM - salt '*' qcow2.modify_hardware_config vm_name='my_vm' cpu=4 memory=8192 pci='0000:00:1f.2' start=True + Notes: + - VM must be stopped before modification unless only the start flag is set + - Memory is specified in MiB (1024 = 1GB) + - PCI devices must be available and not in use by the host + - CPU count should align with host capabilities + - Requires so-kvm-modify-hardware script to be installed + Description: + This function modifies the hardware configuration of a KVM virtual machine using + the so-kvm-modify-hardware script. It can adjust CPU count, memory allocation, + and PCI device passthrough. Changes are applied to the VM's libvirt configuration. + The VM can optionally be started after modifications are complete. + + Exit Codes: + 0: Success + 1: Invalid parameters + 2: VM state error (running when should be stopped) + 3: Hardware configuration error + 4: System command error + 255: Unexpected error + + Logging: + - All operations are logged to the salt minion log + - Log entries are prefixed with 'qcow2 module:' + - Hardware configuration changes are logged + - Errors include detailed messages and stack traces + - Final status of modification is logged ''' cmd = ['/usr/sbin/so-kvm-modify-hardware', '-v', vm_name] diff --git a/salt/hypervisor/tools/sbin/so-kvm-modify-hardware b/salt/hypervisor/tools/sbin/so-kvm-modify-hardware index b6e2ea281..e2d64919a 100644 --- a/salt/hypervisor/tools/sbin/so-kvm-modify-hardware +++ b/salt/hypervisor/tools/sbin/so-kvm-modify-hardware @@ -6,10 +6,20 @@ # Elastic License 2.0. """ -Script to modify hardware parameters of a KVM virtual machine. +Script for managing hardware configurations of KVM virtual machines. This script provides +functionality to modify CPU, memory, and PCI device settings without manual XML editing +or direct libvirt interaction. + +The script offers three main configuration capabilities: +1. CPU Management: Adjust virtual CPU count +2. Memory Management: Modify memory allocation +3. PCI Passthrough: Configure PCI device passthrough for direct hardware access + +This script is designed to work with Security Onion's virtualization infrastructure and is typically +used during VM provisioning and hardware reconfiguration tasks. **Usage:** - python so-kvm-modify-hardware.py -v [-c ] [-m ] [-p ] [-p ...] [-s] + so-kvm-modify-hardware -v [-c ] [-m ] [-p ] [-p ...] [-s] **Options:** -v, --vm Name of the virtual machine to modify. @@ -20,35 +30,99 @@ Script to modify hardware parameters of a KVM virtual machine. **Examples:** -1. **Modify VM with Multiple PCI Devices:** +1. **Modify CPU and Memory with Multiple PCI Devices:** ```bash - python so-kvm-modify-hardware.py -v my_vm -c 4 -m 8192 -p 0000:00:1f.2 -p 0000:00:1f.3 -s + so-kvm-modify-hardware -v vm1_sensor -c 4 -m 8192 -p 0000:00:1f.2 -p 0000:00:1f.3 -s ``` - This command modifies the VM named `my_vm`, setting the CPU count to 4, memory to 8192 MiB, and adds two PCI devices for passthrough (`0000:00:1f.2` and `0000:00:1f.3`). The VM is then started after modification due to the `-s` flag. + This command modifies a VM with the following settings: + - VM Name: `vm1_sensor` + - Hardware Configuration: + - CPUs: `4` + - Memory: `8192` MiB + - PCI Device Passthrough: `0000:00:1f.2`, `0000:00:1f.3` + - The VM is started after modification due to the `-s` flag -2. **Modify VM with Single PCI Device:** +2. **Add PCI Device Without Other Changes:** ```bash - python so-kvm-modify-hardware.py -v my_vm -p 0000:00:1f.2 + so-kvm-modify-hardware -v vm2_master -p 0000:00:1f.4 ``` - This command adds a single PCI device passthrough to the VM named `my_vm`. + This command adds a single PCI device passthrough to the VM: + - VM Name: `vm2_master` + - PCI Device: `0000:00:1f.4` + - Existing CPU and memory settings are preserved -3. **Modify VM Without Starting It:** +3. **Update Resource Allocation:** ```bash - python so-kvm-modify-hardware.py -v my_vm -c 2 -m 4096 + so-kvm-modify-hardware -v vm3_search -c 2 -m 4096 ``` - This command sets the CPU count and memory for `my_vm` but does not start it afterward. + This command updates only compute resources: + - VM Name: `vm3_search` + - CPUs: `2` + - Memory: `4096` MiB + - VM remains stopped after modification + +4. **Add Multiple PCI Devices:** + + ```bash + so-kvm-modify-hardware -v vm4_node -p 0000:00:1f.2 -p 0000:00:1f.3 -p 0000:00:1f.4 -s + ``` + + This command adds multiple PCI devices and starts the VM: + - VM Name: `vm4_node` + - PCI Devices: `0000:00:1f.2`, `0000:00:1f.3`, `0000:00:1f.4` + - VM is started after modification **Notes:** -- The `-p` or `--pci` option can be specified multiple times to pass through multiple PCI devices to the VM. -- The PCI hardware IDs should be in the format `0000:00:1f.2`. -- If the `-s` or `--start` flag is not provided, the VM will remain stopped after modification. +- The script automatically stops the VM if it's running before making modifications. +- At least one modification option (-c, -m, or -p) should be provided. +- The PCI hardware IDs must be in the format `domain:bus:slot.function` (e.g., `0000:00:1f.2`). +- Multiple PCI devices can be added by using the `-p` option multiple times. +- Without the `-s` flag, the VM remains stopped after modification. +- Existing hardware configurations are preserved if not explicitly modified. + +**Description:** + +The `so-kvm-modify-hardware` script modifies hardware parameters of KVM virtual machines using the following process: + +1. **VM State Management:** + - Connects to the local libvirt daemon + - Stops the VM if it's currently running + - Retrieves current VM configuration + +2. **Hardware Configuration:** + - Modifies CPU count if specified + - Updates memory allocation if specified + - Adds PCI device passthrough configurations if specified + - All changes are made through libvirt XML configuration + +3. **VM Redefinition:** + - Applies the new configuration by redefining the VM + - Optionally starts the VM if requested + - Ensures clean shutdown and startup during modifications + +4. **Error Handling:** + - Validates all input parameters + - Ensures proper XML structure + - Provides detailed error messages for troubleshooting + +**Exit Codes:** + +- `0`: Success +- `1`: An error occurred during execution + +**Logging:** + +- Logs are written to `/opt/so/log/hypervisor/so-kvm-modify-hardware.log` +- Both file and console logging are enabled for real-time monitoring +- Log entries include timestamps and severity levels +- Detailed error messages are logged for troubleshooting """ diff --git a/salt/hypervisor/tools/sbin/so-qcow2-modify-network b/salt/hypervisor/tools/sbin/so-qcow2-modify-network index c5aa1aa22..5c0a9e9b7 100644 --- a/salt/hypervisor/tools/sbin/so-qcow2-modify-network +++ b/salt/hypervisor/tools/sbin/so-qcow2-modify-network @@ -6,15 +6,112 @@ # Elastic License 2.0. """ -Script to modify the NetworkManager config within a QCOW2 image. +Script for modifying network configurations within QCOW2 virtual machine images. This script provides +functionality to update NetworkManager settings, supporting both DHCP and static IP configurations +without requiring the VM to be running. -Usage: - python so-qcow2-modify-network.py -I -i (--dhcp4 | --static4 --ip4 --gw4 ) [--dns4 ] [--search4 ] +The script offers two main configuration modes: +1. DHCP Configuration: Enable automatic IP address assignment +2. Static IP Configuration: Set specific IP address, gateway, DNS servers, and search domains -Examples: - python so-qcow2-modify-network.py -I /nsm/libvirt/images/sool9/sool9.qcow2 -i eth0 --static4 --ip4 192.168.1.10/24 --gw4 192.168.1.1 --dns4 192.168.1.1,8.8.8.8 --search4 example.local +This script is designed to work with Security Onion's virtualization infrastructure and is typically +used during VM provisioning and network reconfiguration tasks. + +**Usage:** + so-qcow2-modify-network -I -i (--dhcp4 | --static4 --ip4 --gw4 ) + [--dns4 ] [--search4 ] + +**Options:** + -I, --image Path to the QCOW2 image. + -i, --interface Network interface to modify (e.g., eth0). + --dhcp4 Configure interface for DHCP (IPv4). + --static4 Configure interface for static IPv4 settings. + --ip4 IPv4 address (e.g., 192.168.1.10/24). Required for static IPv4 configuration. + --gw4 IPv4 gateway (e.g., 192.168.1.1). Required for static IPv4 configuration. + --dns4 Comma-separated list of IPv4 DNS servers (e.g., 8.8.8.8,8.8.4.4). + --search4 DNS search domain for IPv4. + +**Examples:** + +1. **Static IP Configuration with DNS and Search Domain:** + + ```bash + so-qcow2-modify-network -I /nsm/libvirt/images/sool9/sool9.qcow2 -i eth0 --static4 \ + --ip4 192.168.1.10/24 --gw4 192.168.1.1 --dns4 192.168.1.1,192.168.1.2 --search4 example.local + ``` + + This command configures the network settings in the QCOW2 image with: + - Static IPv4 configuration: + - IP Address: `192.168.1.10/24` + - Gateway: `192.168.1.1` + - DNS Servers: `192.168.1.1`, `192.168.1.2` + - DNS Search Domain: `example.local` + +2. **DHCP Configuration:** + + ```bash + so-qcow2-modify-network -I /nsm/libvirt/images/sool9/sool9.qcow2 -i eth0 --dhcp4 + ``` + + This command configures the network interface to use DHCP for automatic IP address assignment. + +3. **Static IP Configuration without DNS Settings:** + + ```bash + so-qcow2-modify-network -I /nsm/libvirt/images/sool9/sool9.qcow2 -i eth0 --static4 \ + --ip4 192.168.1.20/24 --gw4 192.168.1.1 + ``` + + This command sets only the basic static IP configuration: + - IP Address: `192.168.1.20/24` + - Gateway: `192.168.1.1` + +**Notes:** + +- When using `--static4`, both `--ip4` and `--gw4` options are required. +- The script validates IP addresses, DNS servers, and interface names before making any changes. +- DNS servers can be specified as a comma-separated list for multiple servers. +- The script requires write permissions for the QCOW2 image file. +- Interface names must contain only alphanumeric characters, underscores, and hyphens. + +**Description:** + +The `so-qcow2-modify-network` script modifies network configuration within a QCOW2 image using the following process: + +1. **Image Access:** + - Mounts the QCOW2 image using libguestfs + - Locates and accesses the NetworkManager configuration directory + +2. **Configuration Update:** + - Reads the existing network configuration for the specified interface + - Updates IPv4 settings based on provided parameters + - Supports both DHCP and static IP configurations + - Validates all input parameters before making changes + +3. **File Management:** + - Creates or updates the NetworkManager connection file + - Maintains proper file permissions and format + - Safely unmounts the image after changes + +**Exit Codes:** + +- `0`: Success +- Non-zero: An error occurred during execution + +**Logging:** + +- Logs are written to `/opt/so/log/hypervisor/so-qcow2-modify-network.log` +- Both file and console logging are enabled for real-time monitoring +- Log entries include: + - Timestamps in ISO 8601 format + - Severity levels (INFO, WARNING, ERROR) + - Detailed error messages for troubleshooting +- Critical operations logged: + - Network configuration changes + - Image mount/unmount operations + - Validation failures + - File access errors - python so-qcow2-modify-network.py -I /nsm/libvirt/images/sool9/sool9.qcow2 -i eth0 --dhcp4 """ import argparse @@ -95,7 +192,6 @@ def update_ipv4_section(content, mode, ip=None, gateway=None, dns=None, search_d return updated_content -# modify the network config file for the interface inside the qcow2 image def modify_network_config(image_path, interface, mode, ip=None, gateway=None, dns=None, search_domain=None): if not os.access(image_path, os.W_OK): raise PermissionError(f"Write permission denied for image file: {image_path}") diff --git a/salt/manager/tools/sbin/so-salt-cloud b/salt/manager/tools/sbin/so-salt-cloud index 816f74a46..3edc1c385 100644 --- a/salt/manager/tools/sbin/so-salt-cloud +++ b/salt/manager/tools/sbin/so-salt-cloud @@ -6,13 +6,39 @@ # Elastic License 2.0. """ -Script to assist with salt-cloud VM provisioning. This is intended to work with a libvirt salt-cloud provider. +Script for automated virtual machine provisioning and configuration in Security Onion's virtualization infrastructure. +This script integrates multiple components to provide a streamlined VM deployment process: -**Usage:** - python so-salt-cloud -p (--dhcp4 | --static4 --ip4 --gw4 ) +1. Salt Cloud Integration: + - Works with libvirt salt-cloud provider for VM creation + - Manages VM lifecycle from provisioning through configuration + - Handles profile-based deployment for consistent VM setups + +2. Network Configuration Management: + - Supports both DHCP and static IPv4 networking + - Pre-configures network settings before VM deployment + - Integrates with qcow2.modify_network_config for image modification + - Ensures VMs boot with correct network configuration + +3. Hardware Resource Management: + - Flexible CPU and memory allocation + - Advanced PCI device passthrough capabilities + - Controlled VM startup sequence + - Uses qcow2.modify_hardware_config for hardware settings + +4. Security Integration: + - Automatic firewall rule configuration + - Integrates with so-firewall-minion for firewall setup on the manager + +This script serves as the primary interface for VM deployment in Security Onion, coordinating +between salt-cloud, network configuration, hardware management, and security components to +ensure proper VM provisioning and configuration. + +Usage: + so-salt-cloud -p (--dhcp4 | --static4 --ip4 --gw4 ) [-c ] [-m ] [-P ] [-P ...] [--dns4 ] [--search4 ] -**Options:** +Options: -p, --profile The cloud profile to build the VM from. The name of the VM. --dhcp4 Configure interface for DHCP (IPv4). @@ -25,98 +51,131 @@ Script to assist with salt-cloud VM provisioning. This is intended to work with -m, --memory Amount of memory to assign in MiB. -P, --pci PCI hardware ID(s) to passthrough to the VM (e.g., 0000:00:1f.2). Can be specified multiple times. -**Examples:** +Examples: -1. **Static IP Configuration with Multiple PCI Devices:** +1. Static IP Configuration with Multiple PCI Devices: - ```bash - python so-salt-cloud -p core-hype1 vm1_sensor --static4 --ip4 192.168.1.10/24 --gw4 192.168.1.1 \ + Command: + so-salt-cloud -p sool9-hyper1 vm1_sensor --static4 --ip4 192.168.1.10/24 --gw4 192.168.1.1 \ --dns4 192.168.1.1,192.168.1.2 --search4 example.local -c 4 -m 8192 -P 0000:00:1f.2 -P 0000:00:1f.3 - ``` - This command provisions a VM named `vm1_sensor` using the `core-hype1` profile with the following settings: + This command provisions a VM named vm1_sensor using the sool9-hyper1 profile with the following settings: - Static IPv4 configuration: - - IP Address: `192.168.1.10/24` - - Gateway: `192.168.1.1` - - DNS Servers: `192.168.1.1`, `192.168.1.2` - - DNS Search Domain: `example.local` + - IP Address: 192.168.1.10/24 + - Gateway: 192.168.1.1 + - DNS Servers: 192.168.1.1, 192.168.1.2 + - DNS Search Domain: example.local - Hardware Configuration: - - CPUs: `4` - - Memory: `8192` MiB - - PCI Device Passthrough: `0000:00:1f.2`, `0000:00:1f.3` + - CPUs: 4 + - Memory: 8192 MiB + - PCI Device Passthrough: 0000:00:1f.2, 0000:00:1f.3 -2. **DHCP Configuration with Default Hardware Settings:** +2. DHCP Configuration with Default Hardware Settings: - ```bash - python so-salt-cloud -p core-hype1 vm2_master --dhcp4 - ``` + Command: + so-salt-cloud -p sool9-hyper1 vm2_master --dhcp4 - This command provisions a VM named `vm2_master` using the `core-hype1` profile with DHCP for network configuration and default hardware settings. + This command provisions a VM named vm2_master using the sool9-hyper1 profile with DHCP for network configuration and default hardware settings. -3. **Static IP Configuration without Hardware Specifications:** +3. Static IP Configuration without Hardware Specifications: - ```bash - python so-salt-cloud -p core-hype1 vm3_search --static4 --ip4 192.168.1.20/24 --gw4 192.168.1.1 - ``` + Command: + so-salt-cloud -p sool9-hyper1 vm3_search --static4 --ip4 192.168.1.20/24 --gw4 192.168.1.1 - This command provisions a VM named `vm3_search` with a static IP configuration and default hardware settings. + This command provisions a VM named vm3_search with a static IP configuration and default hardware settings. -4. **DHCP Configuration with Custom Hardware Specifications and Multiple PCI Devices:** +4. DHCP Configuration with Custom Hardware Specifications and Multiple PCI Devices: - ```bash - python so-salt-cloud -p core-hype1 vm4_node --dhcp4 -c 8 -m 16384 -P 0000:00:1f.4 -P 0000:00:1f.5 - ``` + Command: + so-salt-cloud -p sool9-hyper1 vm4_node --dhcp4 -c 8 -m 16384 -P 0000:00:1f.4 -P 0000:00:1f.5 - This command provisions a VM named `vm4_node` using DHCP for network configuration and custom hardware settings: + This command provisions a VM named vm4_node using DHCP for network configuration and custom hardware settings: - - CPUs: `8` - - Memory: `16384` MiB - - PCI Device Passthrough: `0000:00:1f.4`, `0000:00:1f.5` + - CPUs: 8 + - Memory: 16384 MiB + - PCI Device Passthrough: 0000:00:1f.4, 0000:00:1f.5 -**Notes:** +5. Static IP Configuration with DNS and Search Domain: -- When using `--static4`, both `--ip4` and `--gw4` options are required. -- The script assumes the cloud profile name follows the format `basedomain-hypervisorname`. -- Hardware parameters (`-c`, `-m`, `-P`) are optional. If not provided, default values from the profile will be used. -- The `-P` or `--pci` option can be specified multiple times to pass through multiple PCI devices to the VM. -- The `vm_name` should include the role of the VM after an underscore (e.g., `hostname_role`), as the script uses this to determine the VM's role for firewall configuration. + Command: + so-salt-cloud -p sool9-hyper1 vm1_sensor --static4 --ip4 192.168.1.10/24 --gw4 192.168.1.1 --dns4 192.168.1.1 --search4 example.local -**Description:** + This command provisions a VM named vm1_sensor using the sool9-hyper1 profile with static IPv4 configuration: -The `so-salt-cloud` script automates the provisioning of virtual machines using SaltStack's `salt-cloud` utility. It performs the following steps: + - Static IPv4 configuration: + - IP Address: 192.168.1.10/24 + - Gateway: 192.168.1.1 + - DNS Server: 192.168.1.1 + - DNS Search Domain: example.local -1. **Network Configuration:** +Notes: - - Modifies the network settings of the base QCOW2 image before provisioning. - - Supports both DHCP and static IPv4 configurations. - - Uses the `qcow2.modify_network_config` module via SaltStack to apply these settings on the target hypervisor. +- When using --static4, both --ip4 and --gw4 options are required. +- The script assumes the cloud profile name follows the format basedomain-hypervisorname. +- Hardware parameters (-c, -m, -P) are optional. If not provided, default values from the profile will be used. +- The -P or --pci option can be specified multiple times to pass through multiple PCI devices to the VM. +- The vm_name should include the role of the VM after an underscore (e.g., hostname_role), as the script uses this to determine the VM's role for firewall configuration. -2. **VM Provisioning:** +Description: - - Calls `salt-cloud` to provision the VM using the specified profile and VM name. - - The VM is provisioned but not started immediately to allow for hardware configuration. +The so-salt-cloud script automates the provisioning and configuration of virtual machines in Security Onion's infrastructure. It orchestrates multiple components to ensure proper VM setup and security configuration. The script executes in the following phases: -3. **Hardware Configuration:** +1. Network Configuration Phase: + - Pre-deployment network setup using qcow2.modify_network_config + - Supports both DHCP and static IPv4 configurations + - Modifies the base QCOW2 image directly to ensure network settings persist + - Handles DNS and search domain configuration for proper name resolution + - Validates network parameters before modification + - Ensures network settings are in place before VM creation - - Modifies the hardware settings of the newly defined VM. - - Supports specifying multiple PCI devices for passthrough. - - Uses the `qcow2.modify_hardware_config` module via SaltStack to adjust CPU count, memory allocation, and PCI device passthrough. - - Starts the VM after hardware modifications. +2. VM Provisioning Phase: + - Leverages salt-cloud for consistent VM deployment + - Uses predefined profiles for standardized configurations + - Manages the VM lifecycle through libvirt + - Prevents automatic VM start to allow hardware configuration + - Validates profile and VM name format + - Extracts role information from VM name for security configuration -4. **Firewall Configuration:** +3. Hardware Configuration Phase: + - Configures VM hardware through qcow2.modify_hardware_config + - Manages CPU allocation based on host capabilities + - Handles memory assignment in MiB units + - Supports multiple PCI device passthrough for advanced networking + - Validates hardware parameters against host resources + - Controls VM startup sequence after configuration - - Monitors the output of `salt-cloud` to extract the VM's IP address. - - Calls the `so-firewall-minion` script to apply firewall rules based on the VM's role. +4. Security Integration Phase: + - Monitors salt-cloud output for VM IP address assignment + - Extracts role information from VM name + - Launches so-firewall-minion in a separate thread for non-blocking operation + - Configures role-based firewall rules automatically + - Ensures security policies are in place before VM is accessible + - Logs all security-related operations for audit purposes -**Exit Codes:** +The script implements extensive error handling and logging throughout each phase: +- Validates all input parameters before execution +- Provides detailed error messages for troubleshooting +- Logs operations to both file and console +- Handles process interruption gracefully +- Ensures atomic operations where possible +- Maintains audit trail of all configuration changes -- `0`: Success +Integration points: +- Works with Security Onion's salt-cloud provider +- Interfaces with qcow2 module for image and hardware management +- Coordinates with so-firewall-minion for security configuration +- Uses libvirt for VM management +- Leverages SaltStack for distributed execution + +Exit Codes: + +- 0: Success - Non-zero: An error occurred during execution. -**Logging:** +Logging: -- Logs are written to `/opt/so/log/salt/so-salt-cloud.log`. +- Logs are written to /opt/so/log/salt/so-salt-cloud.log. - Both file and console logging are enabled for real-time monitoring. """ From ab97d3b8b7c91f9c13cfd2fa265741f840c3b76b Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Fri, 24 Jan 2025 11:26:34 -0500 Subject: [PATCH 096/315] ensure 64962 patch applies to manager for salt-cloud --- salt/salt/cloud/init.sls | 1 + 1 file changed, 1 insertion(+) diff --git a/salt/salt/cloud/init.sls b/salt/salt/cloud/init.sls index b0f9ca7fa..5ba8b96da 100644 --- a/salt/salt/cloud/init.sls +++ b/salt/salt/cloud/init.sls @@ -17,6 +17,7 @@ include: - libvirt.packages + - libvirt.64962 - libvirt.ssh.users install_salt_cloud: From b3969a6ce091e52512a40b30bad0f1c2a2d72dbe Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Fri, 24 Jan 2025 17:19:41 -0500 Subject: [PATCH 097/315] fix hardware passthrough for pci devices --- salt/_modules/qcow2.py | 21 +++++++++--- salt/hypervisor/defaults.brainstorm.yaml | 0 .../tools/sbin/so-kvm-modify-hardware | 33 ++++++++++++------- salt/manager/tools/sbin/so-salt-cloud | 19 ++++++----- 4 files changed, 48 insertions(+), 25 deletions(-) delete mode 100644 salt/hypervisor/defaults.brainstorm.yaml diff --git a/salt/_modules/qcow2.py b/salt/_modules/qcow2.py index 37858484e..d1de6756a 100644 --- a/salt/_modules/qcow2.py +++ b/salt/_modules/qcow2.py @@ -131,7 +131,7 @@ def modify_network_config(image, interface, mode, ip4=None, gw4=None, dns4=None, def modify_hardware_config(vm_name, cpu=None, memory=None, pci=None, start=False): ''' Usage: - salt '*' qcow2.modify_hardware_config vm_name= [cpu=] [memory=] [pci=] [start=] + salt '*' qcow2.modify_hardware_config vm_name= [cpu=] [memory=] [pci=] [pci=] [start=] Options: vm_name @@ -143,7 +143,8 @@ def modify_hardware_config(vm_name, cpu=None, memory=None, pci=None, start=False Amount of memory to assign in MiB (positive integer) Optional - VM's current memory size retained if not specified pci - PCI hardware ID to passthrough to the VM (e.g., '0000:00:1f.2') + PCI hardware ID(s) to passthrough to the VM (e.g., '0000:c7:00.0') + Can be specified multiple times for multiple devices Optional - no PCI passthrough if not specified start Boolean flag to start the VM after modification @@ -158,13 +159,13 @@ def modify_hardware_config(vm_name, cpu=None, memory=None, pci=None, start=False 2. **Enable PCI Passthrough:** ```bash - salt '*' qcow2.modify_hardware_config vm_name='sensor1' pci='0000:00:1f.2' start=True + salt '*' qcow2.modify_hardware_config vm_name='sensor1' pci='0000:c7:00.0' pci='0000:c4:00.0' start=True ``` This configures PCI passthrough and starts the VM 3. **Complete Hardware Configuration:** ```bash - salt '*' qcow2.modify_hardware_config vm_name='sensor1' cpu=8 memory=16384 pci='0000:00:1f.2' start=True + salt '*' qcow2.modify_hardware_config vm_name='sensor1' cpu=8 memory=16384 pci='0000:c7:00.0' start=True ``` This sets CPU, memory, PCI passthrough, and starts the VM @@ -210,7 +211,17 @@ def modify_hardware_config(vm_name, cpu=None, memory=None, pci=None, start=False else: raise ValueError('memory must be a positive integer.') if pci: - cmd.extend(['-p', pci]) + # Handle PCI IDs (can be a single device or comma-separated list) + if isinstance(pci, str): + devices = [dev.strip() for dev in pci.split(',') if dev.strip()] + elif isinstance(pci, list): + devices = pci + else: + devices = [pci] + + # Add each device with its own -p flag + for device in devices: + cmd.extend(['-p', str(device)]) if start: cmd.append('-s') diff --git a/salt/hypervisor/defaults.brainstorm.yaml b/salt/hypervisor/defaults.brainstorm.yaml deleted file mode 100644 index e69de29bb..000000000 diff --git a/salt/hypervisor/tools/sbin/so-kvm-modify-hardware b/salt/hypervisor/tools/sbin/so-kvm-modify-hardware index e2d64919a..a6becfb95 100644 --- a/salt/hypervisor/tools/sbin/so-kvm-modify-hardware +++ b/salt/hypervisor/tools/sbin/so-kvm-modify-hardware @@ -25,7 +25,8 @@ used during VM provisioning and hardware reconfiguration tasks. -v, --vm Name of the virtual machine to modify. -c, --cpu Number of virtual CPUs to assign. -m, --memory Amount of memory to assign in MiB. - -p, --pci PCI hardware ID(s) to passthrough to the VM (e.g., 0000:00:1f.2). Can be specified multiple times. + -p, --pci PCI hardware ID(s) to passthrough to the VM (e.g., 0000:c7:00.0). Can be specified multiple times. + Format: domain:bus:device.function -s, --start Start the VM after modification. **Examples:** @@ -33,7 +34,7 @@ used during VM provisioning and hardware reconfiguration tasks. 1. **Modify CPU and Memory with Multiple PCI Devices:** ```bash - so-kvm-modify-hardware -v vm1_sensor -c 4 -m 8192 -p 0000:00:1f.2 -p 0000:00:1f.3 -s + so-kvm-modify-hardware -v vm1_sensor -c 4 -m 8192 -p 0000:c7:00.0 -p 0000:c8:00.0 -s ``` This command modifies a VM with the following settings: @@ -41,18 +42,18 @@ used during VM provisioning and hardware reconfiguration tasks. - Hardware Configuration: - CPUs: `4` - Memory: `8192` MiB - - PCI Device Passthrough: `0000:00:1f.2`, `0000:00:1f.3` + - PCI Device Passthrough: `0000:c7:00.0`, `0000:c8:00.0` - The VM is started after modification due to the `-s` flag 2. **Add PCI Device Without Other Changes:** ```bash - so-kvm-modify-hardware -v vm2_master -p 0000:00:1f.4 + so-kvm-modify-hardware -v vm2_master -p 0000:c7:00.0 ``` This command adds a single PCI device passthrough to the VM: - VM Name: `vm2_master` - - PCI Device: `0000:00:1f.4` + - PCI Device: `0000:c7:00.0` - Existing CPU and memory settings are preserved 3. **Update Resource Allocation:** @@ -70,19 +71,19 @@ used during VM provisioning and hardware reconfiguration tasks. 4. **Add Multiple PCI Devices:** ```bash - so-kvm-modify-hardware -v vm4_node -p 0000:00:1f.2 -p 0000:00:1f.3 -p 0000:00:1f.4 -s + so-kvm-modify-hardware -v vm4_node -p 0000:c7:00.0 -p 0000:c4:00.0 -p 0000:c4:00.1 -s ``` This command adds multiple PCI devices and starts the VM: - VM Name: `vm4_node` - - PCI Devices: `0000:00:1f.2`, `0000:00:1f.3`, `0000:00:1f.4` + - PCI Devices: `0000:c7:00.0`, `0000:c4:00.0`, `0000:c4:00.1` - VM is started after modification **Notes:** - The script automatically stops the VM if it's running before making modifications. - At least one modification option (-c, -m, or -p) should be provided. -- The PCI hardware IDs must be in the format `domain:bus:slot.function` (e.g., `0000:00:1f.2`). +- The PCI hardware IDs must be in the format `domain:bus:device.function` (e.g., `0000:c7:00.0`). - Multiple PCI devices can be added by using the `-p` option multiple times. - Without the `-s` flag, the VM remains stopped after modification. - Existing hardware configurations are preserved if not explicitly modified. @@ -183,9 +184,19 @@ def modify_vm(dom, cpu_count, memory_amount, pci_ids, logger): 'managed': 'yes' }) source_elem = ET.SubElement(hostdev_elem, 'source') - domain_id, bus_slot_func = pci_id.split(':', 1) - bus_slot, function = bus_slot_func.split('.') - bus, slot = bus_slot[:2], bus_slot[2:] + # Split PCI ID into components (domain:bus:slot.function) + parts = pci_id.split(':') + if len(parts) != 3: + logger.error(f"Invalid PCI ID format: {pci_id}. Expected format: domain:bus:slot.function") + sys.exit(1) + domain_id = parts[0] + bus = parts[1] + slot_func = parts[2].split('.') + if len(slot_func) != 2: + logger.error(f"Invalid PCI ID format: {pci_id}. Expected format: domain:bus:slot.function") + sys.exit(1) + slot = slot_func[0] + function = slot_func[1] address_attrs = { 'domain': f'0x{domain_id}', 'bus': f'0x{bus}', diff --git a/salt/manager/tools/sbin/so-salt-cloud b/salt/manager/tools/sbin/so-salt-cloud index 3edc1c385..78473d96a 100644 --- a/salt/manager/tools/sbin/so-salt-cloud +++ b/salt/manager/tools/sbin/so-salt-cloud @@ -49,7 +49,8 @@ Options: --search4 DNS search domain for IPv4. -c, --cpu Number of virtual CPUs to assign. -m, --memory Amount of memory to assign in MiB. - -P, --pci PCI hardware ID(s) to passthrough to the VM (e.g., 0000:00:1f.2). Can be specified multiple times. + -P, --pci PCI hardware ID(s) to passthrough to the VM (e.g., 0000:c7:00.0). Can be specified multiple times. + Format: domain:bus:device.function Examples: @@ -57,7 +58,7 @@ Examples: Command: so-salt-cloud -p sool9-hyper1 vm1_sensor --static4 --ip4 192.168.1.10/24 --gw4 192.168.1.1 \ - --dns4 192.168.1.1,192.168.1.2 --search4 example.local -c 4 -m 8192 -P 0000:00:1f.2 -P 0000:00:1f.3 + --dns4 192.168.1.1,192.168.1.2 --search4 example.local -c 4 -m 8192 -P 0000:c7:00.0 -P 0000:c4:00.0 This command provisions a VM named vm1_sensor using the sool9-hyper1 profile with the following settings: @@ -69,7 +70,7 @@ Examples: - Hardware Configuration: - CPUs: 4 - Memory: 8192 MiB - - PCI Device Passthrough: 0000:00:1f.2, 0000:00:1f.3 + - PCI Device Passthrough: 0000:c7:00.0, 0000:c4:00.0 2. DHCP Configuration with Default Hardware Settings: @@ -88,13 +89,13 @@ Examples: 4. DHCP Configuration with Custom Hardware Specifications and Multiple PCI Devices: Command: - so-salt-cloud -p sool9-hyper1 vm4_node --dhcp4 -c 8 -m 16384 -P 0000:00:1f.4 -P 0000:00:1f.5 + so-salt-cloud -p sool9-hyper1 vm4_node --dhcp4 -c 8 -m 16384 -P 0000:c7:00.0 -P 0000:c4:00.0 -P 0000:c4:00.1 This command provisions a VM named vm4_node using DHCP for network configuration and custom hardware settings: - CPUs: 8 - Memory: 16384 MiB - - PCI Device Passthrough: 0000:00:1f.4, 0000:00:1f.5 + - PCI Device Passthrough: 0000:c7:00.0, 0000:c4:00.0, 0000:c4:00.1 5. Static IP Configuration with DNS and Search Domain: @@ -116,6 +117,7 @@ Notes: - Hardware parameters (-c, -m, -P) are optional. If not provided, default values from the profile will be used. - The -P or --pci option can be specified multiple times to pass through multiple PCI devices to the VM. - The vm_name should include the role of the VM after an underscore (e.g., hostname_role), as the script uses this to determine the VM's role for firewall configuration. +- PCI hardware IDs must be in the format domain:bus:device.function (e.g., 0000:c7:00.0). Description: @@ -283,9 +285,8 @@ def run_qcow2_modify_hardware_config(profile, vm_name, cpu=None, memory=None, pc # Add PCI devices if provided if pci_list: - # Join the list of PCI IDs into a comma-separated string - pci_devices = ','.join(pci_list) - args_list.append('pci=' + pci_devices) + # Pass all PCI devices as a comma-separated list + args_list.append('pci=' + ','.join(pci_list)) r = local.cmd(target, 'qcow2.modify_hardware_config', args_list) logger.info(f'qcow2.modify_hardware_config: {r}') @@ -327,7 +328,7 @@ def parse_arguments(): parser.add_argument("--search4", help="DNS search domain for IPv4.") parser.add_argument('-c', '--cpu', type=int, help='Number of virtual CPUs to assign.') parser.add_argument('-m', '--memory', type=int, help='Amount of memory to assign in MiB.') - parser.add_argument('-P', '--pci', action='append', help='PCI hardware ID(s) to passthrough to the VM (e.g., 0000:00:1f.2). Can be specified multiple times.') + parser.add_argument('-P', '--pci', action='append', help='PCI hardware ID(s) to passthrough to the VM (e.g., 0000:c7:00.0). Can be specified multiple times.') args = parser.parse_args() From 0177f641c8d3222bafdfd0af0c2ae2c665d9786c Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Mon, 27 Jan 2025 15:09:42 -0500 Subject: [PATCH 098/315] watch for files and create a vm --- .../engines/master/virtual_node_manager.py | 507 ++++++++++++++++++ 1 file changed, 507 insertions(+) create mode 100644 salt/salt/engines/master/virtual_node_manager.py diff --git a/salt/salt/engines/master/virtual_node_manager.py b/salt/salt/engines/master/virtual_node_manager.py new file mode 100644 index 000000000..a47c68f32 --- /dev/null +++ b/salt/salt/engines/master/virtual_node_manager.py @@ -0,0 +1,507 @@ +#!/opt/saltstack/salt/bin/python3 + +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +""" +Salt Engine for Virtual Node Management + +This engine manages the automated provisioning of virtual machines in Security Onion's +virtualization infrastructure. It monitors directories for VM creation requests and +handles the entire provisioning process including hardware allocation. + +Usage: + engines: + - virtual_node_manager: + interval: 30 + base_path: /opt/so/saltstack/local/salt/hypervisor/hosts + +Options: + interval: Time in seconds between directory scans (default: 30) + base_path: Base directory to monitor for VM requests (default: /opt/so/saltstack/local/salt/hypervisor/hosts) + + Memory values in VM configuration YAML files should be specified in GB. These values + will automatically be converted to MiB when passed to so-salt-cloud. + +Examples: + 1. Basic Configuration: + engines: + - virtual_node_manager: {} + + Uses default settings to monitor for VM requests. + + 2. Custom Scan Interval: + engines: + - virtual_node_manager: + interval: 60 + + Scans for new requests every 60 seconds. + +Notes: + - Requires 'hvn' feature license + - Monitors for files named: add_sensor, add_searchnode, add_idh, add_receiver, add_heavynode, add_fleet + - Hardware allocation is tracked in hypervisor YAML files + - Creates VM-specific hardware tracking files + +Description: + The engine operates in the following phases: + + 1. License Validation + - Verifies 'hvn' feature is licensed + - Prevents operation if license is invalid + + 2. File Monitoring + - Scans configured directory for add_* files + - Parses VM configuration from YAML + - Validates configuration parameters + + 3. Hardware Allocation + - Reads hypervisor hardware inventory + - Claims requested PCI devices + - Updates hardware tracking + - Creates VM hardware record + + 4. VM Provisioning + - Executes so-salt-cloud with configuration + - Handles network setup + - Configures hardware passthrough + - Manages VM startup + +Exit Codes: + 0: Success + 1: Invalid license + 2: Configuration error + 3: Hardware allocation failure + 4: VM provisioning failure + +Logging: + Log files are written to /opt/so/log/salt/engines/virtual_node_manager.log + Critical operations, errors, and hardware allocation events are logged +""" + +import os +import glob +import yaml +import time +import logging +import subprocess +from typing import Dict, List, Optional, Tuple + +# Configure logging +log = logging.getLogger(__name__) +log.setLevel(logging.DEBUG) + +# Constants +DEFAULT_INTERVAL = 30 +DEFAULT_BASE_PATH = '/opt/so/saltstack/local/salt/hypervisor/hosts' +VALID_ROLES = ['sensor', 'searchnode', 'idh', 'receiver', 'heavynode', 'fleet'] +MAX_RETRIES = 3 +RETRY_DELAY = 5 +LICENSE_PATH = '/opt/so/saltstack/local/pillar/soc/license.sls' + +def ensure_claimed_section(hw_config: dict) -> dict: + """ + Ensure the claimed section exists and is a dict. + + Args: + hw_config: Hardware configuration section containing 'claimed' key + + Returns: + The claimed section as a dict + """ + if hw_config['claimed'] is None or not isinstance(hw_config['claimed'], dict): + hw_config['claimed'] = {} + return hw_config['claimed'] + +def convert_pci_id(pci_id: str) -> str: + """ + Convert PCI ID from pci_0000_c7_00_0 format to 0000:c7:00.0 format. + + Args: + pci_id: PCI ID in underscore format (e.g., pci_0000_c7_00_0) + + Returns: + PCI ID in domain:bus:slot.function format (e.g., 0000:c7:00.0) + + Example: + >>> convert_pci_id('pci_0000_c7_00_0') + '0000:c7:00.0' + """ + # Remove 'pci_' prefix + pci_id = pci_id.replace('pci_', '') + + # Split into components + parts = pci_id.split('_') + if len(parts) != 4: + raise ValueError(f"Invalid PCI ID format: {pci_id}. Expected format: pci_domain_bus_slot_function") + + # Reconstruct with proper format (using period for function) + domain, bus, slot, function = parts + return f"{domain}:{bus}:{slot}.{function}" + +class HardwareManager: + """ + Manages hardware allocation and tracking for virtual machines. + Handles reading hypervisor configuration, claiming PCI devices, + and maintaining hardware tracking files. + """ + + def __init__(self, hypervisor: str, base_path: str): + """Initialize the hardware manager for a specific hypervisor.""" + self.hypervisor = hypervisor + self.base_path = base_path + self.hypervisor_file = os.path.join(base_path, hypervisor, f"{hypervisor}.yaml") + + def read_hypervisor_config(self) -> dict: + """ + Read and initialize the hypervisor's hardware configuration file. + Ensures all hardware sections have a valid claimed section. + """ + try: + with open(self.hypervisor_file, 'r') as f: + config = yaml.safe_load(f) + + # Initialize any null claimed sections + modified = False + for hw_type in ['disk', 'copper', 'sfp']: + hw_config = config['hypervisor']['hardware'][hw_type] + if hw_config['claimed'] is None: + log.debug("Initializing null claimed section for %s", hw_type) + hw_config['claimed'] = {} + modified = True + + # Save if we made any changes + if modified: + log.info("Updating hypervisor config with initialized claimed sections") + self.write_hypervisor_config(config) + + return config + except Exception as e: + log.error("Failed to read hypervisor configuration: %s", str(e)) + raise + + def write_hypervisor_config(self, config: dict) -> None: + """Write updated configuration back to the hypervisor file.""" + try: + with open(self.hypervisor_file, 'w') as f: + yaml.dump(config, f, default_flow_style=False) + except Exception as e: + log.error("Failed to write hypervisor configuration: %s", str(e)) + raise + + def get_pci_ids(self, hw_type: str, indices: List[int]) -> List[str]: + """ + Look up PCI IDs for requested hardware indices. + + Args: + hw_type: Type of hardware (disk, copper, sfp) + indices: List of hardware indices to look up + + Returns: + List of PCI IDs + """ + config = self.read_hypervisor_config() + log.debug("Full config structure: %s", config) + log.debug("Looking up indices %s for hardware type %s", indices, hw_type) + pci_ids = [] + + try: + hardware_section = config['hypervisor']['hardware'] + log.debug("Hardware section: %s", hardware_section) + if hw_type not in hardware_section: + raise ValueError(f"Hardware type {hw_type} not found in configuration") + + hw_config = hardware_section[hw_type] + free_hw = hw_config['free'] + claimed_hw = ensure_claimed_section(hw_config) + + log.debug("Free hardware section for %s: %s", hw_type, free_hw) + log.debug("Claimed hardware section for %s: %s", hw_type, claimed_hw) + + for idx in indices: + if idx in free_hw: + pci_id = convert_pci_id(free_hw[idx]) + log.debug("Converting PCI ID from %s to %s", free_hw[idx], pci_id) + pci_ids.append(pci_id) + elif idx in claimed_hw: + raise ValueError(f"Hardware index {idx} for {hw_type} is already claimed") + else: + raise ValueError(f"Hardware index {idx} for {hw_type} does not exist") + except KeyError as e: + log.error("Invalid hardware configuration structure: %s", str(e)) + raise + + return pci_ids + + def claim_hardware(self, hw_type: str, indices: List[int]) -> None: + """ + Move hardware from free to claimed in the hypervisor configuration. + + Args: + hw_type: Type of hardware (disk, copper, sfp) + indices: List of hardware indices to claim + """ + config = self.read_hypervisor_config() + + try: + hw_config = config['hypervisor']['hardware'][hw_type] + ensure_claimed_section(hw_config) + + for idx in indices: + if idx in hw_config['free']: + pci_id = hw_config['free'][idx] + hw_config['claimed'][idx] = pci_id + del hw_config['free'][idx] + else: + raise ValueError(f"{hw_type} hardware index {idx} not available") + + self.write_hypervisor_config(config) + log.info("Successfully claimed %s hardware indices: %s", hw_type, indices) + except Exception as e: + log.error("Failed to claim hardware: %s", str(e)) + raise + + def create_vm_hardware_file(self, hostname: str, role: str, hardware: dict) -> None: + """ + Create a YAML file tracking hardware allocated to a VM. + + Args: + hostname: Name of the VM + role: VM role (sensor, searchnode, etc.) + hardware: Dictionary of allocated hardware + """ + vm_file = os.path.join(self.base_path, self.hypervisor, f"{hostname}_{role}.yaml") + try: + with open(vm_file, 'w') as f: + yaml.dump({'hardware': hardware}, f, default_flow_style=False) + log.info("Created hardware tracking file for %s_%s", hostname, role) + except Exception as e: + log.error("Failed to create VM hardware file: %s", str(e)) + raise + +def validate_hvn_license() -> bool: + """Check if the license file exists and contains required values.""" + if not os.path.exists(LICENSE_PATH): + log.error("LICENSE: License file not found at %s", LICENSE_PATH) + return False + + try: + with open(LICENSE_PATH, 'r') as f: + license_data = yaml.safe_load(f) + + if not license_data: + log.error("LICENSE: Empty or invalid license file") + return False + + license_id = license_data.get('license_id') + features = license_data.get('features', []) + + if not license_id: + log.error("LICENSE: No license_id found in license file") + return False + + if 'hvn' not in features: + log.error("Hypervisor nodes are a feature supported only for customers with a valid license.\n" + "Contact Security Onion Solutions, LLC via our website at https://securityonionsolutions.com\n" + "for more information about purchasing a license to enable this feature.") + return False + + log.info("LICENSE: License validation successful") + return True + + except Exception as e: + log.error("LICENSE: Error reading license file: %s", str(e)) + return False + +def parse_add_file(file_path: str) -> Tuple[str, str, dict]: + """ + Parse an add_* file to extract VM configuration. + + Returns: + Tuple of (hypervisor, role, config) + """ + try: + # Extract hypervisor and role from path + path_parts = file_path.split(os.path.sep) + hypervisor = path_parts[-2] + role = path_parts[-1].replace('add_', '') + + if role not in VALID_ROLES: + raise ValueError(f"Invalid role: {role}") + + # Read and parse YAML configuration + with open(file_path, 'r') as f: + config = yaml.safe_load(f) + + required_fields = ['hostname', 'network_mode'] + if config.get('network_mode') == 'static4': + required_fields.extend(['ip4', 'gw4']) + + for field in required_fields: + if field not in config: + raise ValueError(f"Missing required field: {field}") + + return hypervisor, role, config + except Exception as e: + log.error("Failed to parse add file %s: %s", file_path, str(e)) + raise + +def convert_gb_to_mib(gb: int) -> int: + """ + Convert memory value from GB to MiB. + + Args: + gb: Memory value in gigabytes + + Returns: + Memory value in mebibytes (1 GB = 1024 MiB) + """ + return gb * 1024 + +def execute_salt_cloud(profile: str, hostname: str, role: str, config: dict, pci_ids: List[str]) -> None: + """ + Execute so-salt-cloud to create the VM. + + Args: + profile: Salt cloud profile name + hostname: VM hostname + role: VM role + config: VM configuration + pci_ids: List of PCI IDs for hardware passthrough + """ + try: + cmd = ['so-salt-cloud', '-p', f'sool9-{profile}', f'{hostname}_{role}'] + + # Add network configuration + if config['network_mode'] == 'static4': + cmd.extend(['--static4', '--ip4', config['ip4'], '--gw4', config['gw4']]) + if 'dns4' in config: + cmd.extend(['--dns4', ','.join(config['dns4'])]) + if 'search4' in config: + cmd.extend(['--search4', config['search4']]) + else: + cmd.append('--dhcp4') + + # Add hardware configuration + if 'cpu' in config: + cmd.extend(['-c', str(config['cpu'])]) + if 'memory' in config: + # Convert memory from GB to MiB for so-salt-cloud + memory_mib = convert_gb_to_mib(config['memory']) + cmd.extend(['-m', str(memory_mib)]) + + # Add PCI devices + for pci_id in pci_ids: + cmd.extend(['-P', pci_id]) + + log.info("Executing: %s", ' '.join(cmd)) + subprocess.run(cmd, check=True) + except subprocess.CalledProcessError as e: + log.error("so-salt-cloud execution failed: %s", str(e)) + raise + except Exception as e: + log.error("Failed to execute so-salt-cloud: %s", str(e)) + raise + +def process_add_file(file_path: str, base_path: str) -> None: + """ + Process a single add_* file for VM creation. + + Args: + file_path: Path to the add_* file + base_path: Base path for hypervisor configuration + """ + try: + hypervisor, role, config = parse_add_file(file_path) + log.debug("Parsed config from add file: %s", config) + hw_manager = HardwareManager(hypervisor, base_path) + + # Collect all PCI IDs + pci_ids = [] + hardware_tracking = { + 'cpu': config.get('cpu'), + 'memory': config.get('memory') + } + + # Process each hardware type + for hw_type in ['disk', 'copper', 'sfp']: + if hw_type in config: + indices = config[hw_type] + hw_pci_ids = hw_manager.get_pci_ids(hw_type, indices) + pci_ids.extend(hw_pci_ids) + + # Track hardware allocation + hardware_tracking[hw_type] = [ + {'id': idx, 'pci': pci_id} + for idx, pci_id in zip(indices, hw_pci_ids) + ] + + # Claim the hardware + hw_manager.claim_hardware(hw_type, indices) + + # Create VM + execute_salt_cloud(hypervisor, config['hostname'], role, config, pci_ids) + + # Create hardware tracking file + hw_manager.create_vm_hardware_file(config['hostname'], role, hardware_tracking) + + # Clean up the add_* file + os.remove(file_path) + log.info("Successfully processed VM creation request: %s_%s", config['hostname'], role) + + except Exception as e: + log.error("Failed to process add file %s: %s", file_path, str(e)) + raise + +def monitor_add_files(base_path: str) -> None: + """ + Monitor directories for add_* files and process them. + + Args: + base_path: Base path to monitor for add_* files + """ + pattern = os.path.join(base_path, '*', 'add_*') + + try: + for file_path in glob.glob(pattern): + log.info("Found new VM request file: %s", file_path) + + for attempt in range(MAX_RETRIES): + try: + process_add_file(file_path, base_path) + break + except Exception as e: + if attempt < MAX_RETRIES - 1: + log.warning("Attempt %d failed, retrying in %d seconds: %s", + attempt + 1, RETRY_DELAY, str(e)) + time.sleep(RETRY_DELAY) + else: + log.error("All attempts failed for file %s", file_path) + raise + except Exception as e: + log.error("Error monitoring add files: %s", str(e)) + raise + +def start(interval: int = DEFAULT_INTERVAL, + base_path: str = DEFAULT_BASE_PATH) -> None: + """ + Main engine loop. + + Args: + interval: Time in seconds between directory scans + base_path: Base path to monitor for VM requests + """ + log.info("Starting virtual node manager engine") + + if not validate_hvn_license(): + return + + while True: + try: + monitor_add_files(base_path) + except Exception as e: + log.error("Error in main engine loop: %s", str(e)) + + time.sleep(interval) From 2cd0f6906904acdec429c57451765964bbcde851 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Mon, 27 Jan 2025 16:40:10 -0500 Subject: [PATCH 099/315] watch and build --- .../engines/master/virtual_node_manager.py | 136 ++++++++++++------ 1 file changed, 94 insertions(+), 42 deletions(-) diff --git a/salt/salt/engines/master/virtual_node_manager.py b/salt/salt/engines/master/virtual_node_manager.py index a47c68f32..ed3d10d5a 100644 --- a/salt/salt/engines/master/virtual_node_manager.py +++ b/salt/salt/engines/master/virtual_node_manager.py @@ -97,8 +97,6 @@ log.setLevel(logging.DEBUG) DEFAULT_INTERVAL = 30 DEFAULT_BASE_PATH = '/opt/so/saltstack/local/salt/hypervisor/hosts' VALID_ROLES = ['sensor', 'searchnode', 'idh', 'receiver', 'heavynode', 'fleet'] -MAX_RETRIES = 3 -RETRY_DELAY = 5 LICENSE_PATH = '/opt/so/saltstack/local/pillar/soc/license.sls' def ensure_claimed_section(hw_config: dict) -> dict: @@ -191,17 +189,21 @@ class HardwareManager: log.error("Failed to write hypervisor configuration: %s", str(e)) raise - def get_pci_ids(self, hw_type: str, indices: List[int]) -> List[str]: + def get_pci_ids(self, hw_type: str, indices: Optional[List[int]]) -> List[str]: """ Look up PCI IDs for requested hardware indices. Args: hw_type: Type of hardware (disk, copper, sfp) - indices: List of hardware indices to look up + indices: List of hardware indices to look up, or None if no hardware requested Returns: List of PCI IDs """ + # Skip if no indices provided + if indices is None: + return [] + config = self.read_hypervisor_config() log.debug("Full config structure: %s", config) log.debug("Looking up indices %s for hardware type %s", indices, hw_type) @@ -342,6 +344,12 @@ def parse_add_file(file_path: str) -> Tuple[str, str, dict]: for field in required_fields: if field not in config: raise ValueError(f"Missing required field: {field}") + + # Validate hardware sections + for hw_type in ['disk', 'copper', 'sfp']: + if hw_type in config and config[hw_type] is not None: + if not isinstance(config[hw_type], list): + raise ValueError(f"{hw_type} must be a list when present") return hypervisor, role, config except Exception as e: @@ -405,6 +413,27 @@ def execute_salt_cloud(profile: str, hostname: str, role: str, config: dict, pci log.error("Failed to execute so-salt-cloud: %s", str(e)) raise +def release_hardware(hw_manager: HardwareManager, hw_type: str, indices: List[int]) -> None: + """ + Release claimed hardware back to free pool. + + Args: + hw_manager: HardwareManager instance + hw_type: Type of hardware (disk, copper, sfp) + indices: List of hardware indices to release + """ + config = hw_manager.read_hypervisor_config() + hw_config = config['hypervisor']['hardware'][hw_type] + + for idx in indices: + if idx in hw_config['claimed']: + pci_id = hw_config['claimed'][idx] + hw_config['free'][idx] = pci_id + del hw_config['claimed'][idx] + + hw_manager.write_hypervisor_config(config) + log.info("Released %s hardware indices: %s", hw_type, indices) + def process_add_file(file_path: str, base_path: str) -> None: """ Process a single add_* file for VM creation. @@ -418,39 +447,62 @@ def process_add_file(file_path: str, base_path: str) -> None: log.debug("Parsed config from add file: %s", config) hw_manager = HardwareManager(hypervisor, base_path) - # Collect all PCI IDs + # Phase 1: Collect all hardware information without claiming pci_ids = [] + hardware_to_claim = {} # Store hardware to claim for each type hardware_tracking = { 'cpu': config.get('cpu'), 'memory': config.get('memory') } - # Process each hardware type + # Validate all hardware first for hw_type in ['disk', 'copper', 'sfp']: - if hw_type in config: - indices = config[hw_type] + indices = config.get(hw_type) + if indices is not None: + # Validate indices are available before claiming hw_pci_ids = hw_manager.get_pci_ids(hw_type, indices) - pci_ids.extend(hw_pci_ids) - - # Track hardware allocation - hardware_tracking[hw_type] = [ - {'id': idx, 'pci': pci_id} - for idx, pci_id in zip(indices, hw_pci_ids) - ] - - # Claim the hardware + if hw_pci_ids: + hardware_to_claim[hw_type] = indices + pci_ids.extend(hw_pci_ids) + hardware_tracking[hw_type] = [ + {'id': idx, 'pci': pci_id} + for idx, pci_id in zip(indices, hw_pci_ids) + ] + + # Phase 2: Claim hardware only after all validation passes + try: + # Claim all hardware + for hw_type, indices in hardware_to_claim.items(): hw_manager.claim_hardware(hw_type, indices) - - # Create VM - execute_salt_cloud(hypervisor, config['hostname'], role, config, pci_ids) - - # Create hardware tracking file - hw_manager.create_vm_hardware_file(config['hostname'], role, hardware_tracking) - - # Clean up the add_* file - os.remove(file_path) - log.info("Successfully processed VM creation request: %s_%s", config['hostname'], role) - + + # Create VM + execute_salt_cloud(hypervisor, config['hostname'], role, config, pci_ids) + + # Create hardware tracking file + hw_manager.create_vm_hardware_file(config['hostname'], role, hardware_tracking) + + log.info("Successfully processed VM creation request: %s_%s", + config['hostname'], role) + + except Exception as e: + # If anything fails after claiming, release claimed hardware + log.error("Failed after hardware claim, attempting to release hardware: %s", str(e)) + for hw_type, indices in hardware_to_claim.items(): + try: + release_hardware(hw_manager, hw_type, indices) + except Exception as release_error: + log.error("Failed to release %s hardware %s: %s", + hw_type, indices, str(release_error)) + raise + + finally: + # Always clean up the add file + try: + os.remove(file_path) + log.info("Cleaned up add file: %s", file_path) + except Exception as e: + log.error("Failed to clean up add file: %s", str(e)) + except Exception as e: log.error("Failed to process add file %s: %s", file_path, str(e)) raise @@ -467,19 +519,10 @@ def monitor_add_files(base_path: str) -> None: try: for file_path in glob.glob(pattern): log.info("Found new VM request file: %s", file_path) - - for attempt in range(MAX_RETRIES): - try: - process_add_file(file_path, base_path) - break - except Exception as e: - if attempt < MAX_RETRIES - 1: - log.warning("Attempt %d failed, retrying in %d seconds: %s", - attempt + 1, RETRY_DELAY, str(e)) - time.sleep(RETRY_DELAY) - else: - log.error("All attempts failed for file %s", file_path) - raise + try: + process_add_file(file_path, base_path) + except Exception as e: + log.error("Failed to process file %s: %s", file_path, str(e)) except Exception as e: log.error("Error monitoring add files: %s", str(e)) raise @@ -498,9 +541,18 @@ def start(interval: int = DEFAULT_INTERVAL, if not validate_hvn_license(): return + processed_files = set() while True: try: - monitor_add_files(base_path) + for file_path in glob.glob(os.path.join(base_path, '*', 'add_*')): + if file_path not in processed_files: + try: + process_add_file(file_path, base_path) + processed_files.add(file_path) + except Exception as e: + log.error("Failed to process file %s: %s", file_path, str(e)) + # Still mark as processed to avoid retrying + processed_files.add(file_path) except Exception as e: log.error("Error in main engine loop: %s", str(e)) From b66aafd168fd1cbbb02997b6c928051d874c3ea5 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Mon, 27 Jan 2025 17:24:04 -0500 Subject: [PATCH 100/315] fix claiming for cpu/mem --- .../engines/master/virtual_node_manager.py | 79 ++++++++++++++++++- 1 file changed, 76 insertions(+), 3 deletions(-) diff --git a/salt/salt/engines/master/virtual_node_manager.py b/salt/salt/engines/master/virtual_node_manager.py index ed3d10d5a..00753abc3 100644 --- a/salt/salt/engines/master/virtual_node_manager.py +++ b/salt/salt/engines/master/virtual_node_manager.py @@ -237,6 +237,63 @@ class HardwareManager: return pci_ids + def claim_cpu_memory(self, cpu_count: Optional[int], memory_gb: Optional[int]) -> None: + """ + Claim CPU cores and memory from the free pool. + + Args: + cpu_count: Number of CPU cores to claim, or None if no CPU requested + memory_gb: Amount of memory in GB to claim, or None if no memory requested + + Raises: + ValueError: If requested resources exceed available resources + """ + if cpu_count is None and memory_gb is None: + return + + config = self.read_hypervisor_config() + hw_config = config['hypervisor']['hardware'] + + # Validate and claim CPU cores + if cpu_count is not None: + if cpu_count > hw_config['cpu']['free']: + raise ValueError(f"Not enough CPU cores available. Requested: {cpu_count}, Free: {hw_config['cpu']['free']}") + hw_config['cpu']['free'] -= cpu_count + + # Validate and claim memory + if memory_gb is not None: + if memory_gb > hw_config['memory']['free']: + raise ValueError(f"Not enough memory available. Requested: {memory_gb}GB, Free: {hw_config['memory']['free']}GB") + hw_config['memory']['free'] -= memory_gb + + self.write_hypervisor_config(config) + log.info("Successfully claimed CPU cores: %s, Memory: %sGB", cpu_count, memory_gb) + + def release_cpu_memory(self, cpu_count: Optional[int], memory_gb: Optional[int]) -> None: + """ + Release CPU cores and memory back to the free pool. + + Args: + cpu_count: Number of CPU cores to release, or None if no CPU to release + memory_gb: Amount of memory in GB to release, or None if no memory to release + """ + if cpu_count is None and memory_gb is None: + return + + config = self.read_hypervisor_config() + hw_config = config['hypervisor']['hardware'] + + # Return CPU cores to free pool + if cpu_count is not None: + hw_config['cpu']['free'] += cpu_count + + # Return memory to free pool + if memory_gb is not None: + hw_config['memory']['free'] += memory_gb + + self.write_hypervisor_config(config) + log.info("Successfully released CPU cores: %s, Memory: %sGB", cpu_count, memory_gb) + def claim_hardware(self, hw_type: str, indices: List[int]) -> None: """ Move hardware from free to claimed in the hypervisor configuration. @@ -413,7 +470,8 @@ def execute_salt_cloud(profile: str, hostname: str, role: str, config: dict, pci log.error("Failed to execute so-salt-cloud: %s", str(e)) raise -def release_hardware(hw_manager: HardwareManager, hw_type: str, indices: List[int]) -> None: +def release_hardware(hw_manager: HardwareManager, hw_type: str, indices: List[int], + cpu_count: Optional[int] = None, memory_gb: Optional[int] = None) -> None: """ Release claimed hardware back to free pool. @@ -421,6 +479,8 @@ def release_hardware(hw_manager: HardwareManager, hw_type: str, indices: List[in hw_manager: HardwareManager instance hw_type: Type of hardware (disk, copper, sfp) indices: List of hardware indices to release + cpu_count: Number of CPU cores to release, or None if no CPU to release + memory_gb: Amount of memory in GB to release, or None if no memory to release """ config = hw_manager.read_hypervisor_config() hw_config = config['hypervisor']['hardware'][hw_type] @@ -471,7 +531,12 @@ def process_add_file(file_path: str, base_path: str) -> None: # Phase 2: Claim hardware only after all validation passes try: - # Claim all hardware + # Claim CPU and memory first + cpu_count = config.get('cpu') + memory_gb = config.get('memory') + hw_manager.claim_cpu_memory(cpu_count, memory_gb) + + # Then claim PCI hardware for hw_type, indices in hardware_to_claim.items(): hw_manager.claim_hardware(hw_type, indices) @@ -485,8 +550,16 @@ def process_add_file(file_path: str, base_path: str) -> None: config['hostname'], role) except Exception as e: - # If anything fails after claiming, release claimed hardware + # If anything fails after claiming, release all hardware log.error("Failed after hardware claim, attempting to release hardware: %s", str(e)) + + # Release CPU and memory + try: + hw_manager.release_cpu_memory(cpu_count, memory_gb) + except Exception as release_error: + log.error("Failed to release CPU/memory: %s", str(release_error)) + + # Release PCI hardware for hw_type, indices in hardware_to_claim.items(): try: release_hardware(hw_manager, hw_type, indices) From e32dbad0d0ac982c9d5e326ab5a38f45b26cbeba Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Tue, 28 Jan 2025 11:22:26 -0500 Subject: [PATCH 101/315] fix monitoring for add_ files --- .../engines/master/virtual_node_manager.py | 41 +++++++------------ 1 file changed, 14 insertions(+), 27 deletions(-) diff --git a/salt/salt/engines/master/virtual_node_manager.py b/salt/salt/engines/master/virtual_node_manager.py index 00753abc3..f935b2075 100644 --- a/salt/salt/engines/master/virtual_node_manager.py +++ b/salt/salt/engines/master/virtual_node_manager.py @@ -580,26 +580,6 @@ def process_add_file(file_path: str, base_path: str) -> None: log.error("Failed to process add file %s: %s", file_path, str(e)) raise -def monitor_add_files(base_path: str) -> None: - """ - Monitor directories for add_* files and process them. - - Args: - base_path: Base path to monitor for add_* files - """ - pattern = os.path.join(base_path, '*', 'add_*') - - try: - for file_path in glob.glob(pattern): - log.info("Found new VM request file: %s", file_path) - try: - process_add_file(file_path, base_path) - except Exception as e: - log.error("Failed to process file %s: %s", file_path, str(e)) - except Exception as e: - log.error("Error monitoring add files: %s", str(e)) - raise - def start(interval: int = DEFAULT_INTERVAL, base_path: str = DEFAULT_BASE_PATH) -> None: """ @@ -614,19 +594,26 @@ def start(interval: int = DEFAULT_INTERVAL, if not validate_hvn_license(): return - processed_files = set() while True: try: - for file_path in glob.glob(os.path.join(base_path, '*', 'add_*')): - if file_path not in processed_files: + pattern = os.path.join(base_path, '*', 'add_*') + log.debug("Scanning for VM request files with pattern: %s", pattern) + + try: + files = glob.glob(pattern) + if files: + log.debug("Found %d VM request file(s): %s", len(files), files) + + for file_path in files: + log.info("Processing VM request file: %s", file_path) try: process_add_file(file_path, base_path) - processed_files.add(file_path) except Exception as e: log.error("Failed to process file %s: %s", file_path, str(e)) - # Still mark as processed to avoid retrying - processed_files.add(file_path) + except Exception as e: + log.error("Error scanning for VM request files: %s", str(e)) + except Exception as e: log.error("Error in main engine loop: %s", str(e)) - + time.sleep(interval) From 91fc59cffca64a4362b9db51ccd50b1bc1206fe1 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Tue, 28 Jan 2025 14:04:02 -0500 Subject: [PATCH 102/315] add removehost option to so-firewall. add logging to console and so-firewall.log --- salt/manager/tools/sbin/so-firewall | 98 ++++++++++++++++++++++------- 1 file changed, 76 insertions(+), 22 deletions(-) diff --git a/salt/manager/tools/sbin/so-firewall b/salt/manager/tools/sbin/so-firewall index 742427518..f1746ba8d 100755 --- a/salt/manager/tools/sbin/so-firewall +++ b/salt/manager/tools/sbin/so-firewall @@ -10,27 +10,44 @@ import subprocess import sys import time import yaml +import logging + +# Configure logging to both file and console +logger = logging.getLogger('so-firewall') +logger.setLevel(logging.INFO) + +# File handler +file_handler = logging.FileHandler('/opt/so/log/so-firewall.log') +file_handler.setFormatter(logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')) +logger.addHandler(file_handler) + +# Console handler +console_handler = logging.StreamHandler() +console_handler.setFormatter(logging.Formatter('%(levelname)s - %(message)s')) +logger.addHandler(console_handler) lockFile = "/tmp/so-firewall.lock" hostgroupsFilename = "/opt/so/saltstack/local/pillar/firewall/soc_firewall.sls" defaultsFilename = "/opt/so/saltstack/default/salt/firewall/defaults.yaml" def showUsage(options, args): - print('Usage: {} [OPTIONS] [ARGS...]'.format(sys.argv[0])) - print(' Options:') - print(' --apply - After updating the firewall configuration files, apply the new firewall state') - print('') - print(' General commands:') - print(' help - Prints this usage information.') - print(' apply - Apply the firewall state.') - print('') - print(' Host commands:') - print(' includehost - Includes the given IP in the given group. Args: ') - print(' addhostgroup - Adds a new, custom host group. Args: ') - print('') - print(' Where:') - print(' GROUP_NAME - The name of an alias group (Ex: analyst)') - print(' IP - Either a single IP address (Ex: 8.8.8.8) or a CIDR block (Ex: 10.23.0.0/16).') + usage = f'''Usage: {sys.argv[0]} [OPTIONS] [ARGS...] + Options: + --apply - After updating the firewall configuration files, apply the new firewall state + + General commands: + help - Prints this usage information. + apply - Apply the firewall state. + + Host commands: + includehost - Includes the given IP in the given group. Args: + removehost - Removes the given IP from all hostgroups. Args: + addhostgroup - Adds a new, custom host group. Args: + + Where: + GROUP_NAME - The name of an alias group (Ex: analyst) + IP - Either a single IP address (Ex: 8.8.8.8) or a CIDR block (Ex: 10.23.0.0/16).''' + logger.error(usage) sys.exit(1) def checkApplyOption(options): @@ -61,7 +78,7 @@ def addIp(name, ip): else: hostgroup = content['firewall']['hostgroups'][name] else: - print('Host group not defined in salt/firewall/defaults.yaml or hostgroup name is unallowed.', file=sys.stderr) + logger.error(f"Host group {name} not defined in defaults or is unallowed") return 4 ips = hostgroup if ips is None: @@ -69,15 +86,16 @@ def addIp(name, ip): hostgroup = ips if ip not in ips: ips.append(ip) + writeYaml(hostgroupsFilename, content) + logger.info(f"Successfully added IP {ip} to hostgroup {name}") else: - print('Already exists', file=sys.stderr) + logger.error(f"IP {ip} already exists in hostgroup {name}") return 3 - writeYaml(hostgroupsFilename, content) return 0 def includehost(options, args): if len(args) != 2: - print('Missing host group name or ip argument', file=sys.stderr) + logger.error('Missing host group name or ip argument') showUsage(options, args) result = addIp(args[0], args[1]) code = result @@ -86,9 +104,44 @@ def includehost(options, args): return code def apply(options, args): + logger.info("Applying firewall configuration changes") proc = subprocess.run(['salt-call', 'state.apply', 'firewall', 'queue=True']) + if proc.returncode != 0: + logger.error("Failed to apply firewall changes") + else: + logger.info("Successfully applied firewall changes") return proc.returncode +def removehost(options, args): + """Remove an IP from all hostgroups and apply changes if requested""" + if len(args) != 1: + logger.error('Missing IP argument') + showUsage(options, args) + + ip = args[0] + content = loadYaml(hostgroupsFilename) + if not content or 'firewall' not in content or 'hostgroups' not in content['firewall']: + logger.error("Invalid firewall configuration structure") + return 4 + + modified = False + removed_from = [] + for group_name, ips in content['firewall']['hostgroups'].items(): + if ips and ip in ips: + ips.remove(ip) + modified = True + removed_from.append(group_name) + + if modified: + writeYaml(hostgroupsFilename, content) + logger.info(f"Successfully removed IP {ip} from hostgroups: {', '.join(removed_from)}") + if "--apply" in options: + return apply(None, None) + else: + logger.error(f"IP {ip} not found in any hostgroups") + + return 0 + def main(): options = [] args = sys.argv[1:] @@ -103,6 +156,7 @@ def main(): commands = { "help": showUsage, "includehost": includehost, + "removehost": removehost, "apply": apply } @@ -121,7 +175,7 @@ def main(): time.sleep(2) if lockAttempts == maxAttempts: - print("Lock file (" + lockFile + ") could not be created; proceeding without lock.") + logger.error(f"Lock file ({lockFile}) could not be created - proceeding without lock") cmd = commands.get(args[0], showUsage) code = cmd(options, args[1:]) @@ -129,9 +183,9 @@ def main(): try: os.remove(lockFile) except: - print("Lock file (" + lockFile + ") already removed") + logger.error(f"Lock file ({lockFile}) already removed") sys.exit(code) if __name__ == "__main__": - main() \ No newline at end of file + main() From d3b3a0eb8a6d48098f1d36e108a931766a0210fb Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Tue, 28 Jan 2025 14:04:58 -0500 Subject: [PATCH 103/315] wrap salt-cloud -yd. start implementing vm/minion cleanup with ip removal --- salt/manager/tools/sbin/so-salt-cloud | 176 ++++++++++++++++++++++---- 1 file changed, 151 insertions(+), 25 deletions(-) diff --git a/salt/manager/tools/sbin/so-salt-cloud b/salt/manager/tools/sbin/so-salt-cloud index 78473d96a..5ce8d9789 100644 --- a/salt/manager/tools/sbin/so-salt-cloud +++ b/salt/manager/tools/sbin/so-salt-cloud @@ -35,18 +35,28 @@ between salt-cloud, network configuration, hardware management, and security com ensure proper VM provisioning and configuration. Usage: + # Create a VM: so-salt-cloud -p (--dhcp4 | --static4 --ip4 --gw4 ) [-c ] [-m ] [-P ] [-P ...] [--dns4 ] [--search4 ] + # Delete a VM: + so-salt-cloud -p -d [-y] + Options: -p, --profile The cloud profile to build the VM from. The name of the VM. + -d, --destroy Delete the specified VM. + -y, --assume-yes Default yes in answer to all confirmation questions. + + Network Configuration (required for VM creation): --dhcp4 Configure interface for DHCP (IPv4). --static4 Configure interface for static IPv4 settings. --ip4 IPv4 address (e.g., 192.168.1.10/24). Required for static IPv4 configuration. --gw4 IPv4 gateway (e.g., 192.168.1.1). Required for static IPv4 configuration. --dns4 Comma-separated list of IPv4 DNS servers (e.g., 8.8.8.8,8.8.4.4). --search4 DNS search domain for IPv4. + + Hardware Configuration (optional): -c, --cpu Number of virtual CPUs to assign. -m, --memory Amount of memory to assign in MiB. -P, --pci PCI hardware ID(s) to passthrough to the VM (e.g., 0000:c7:00.0). Can be specified multiple times. @@ -110,6 +120,20 @@ Examples: - DNS Server: 192.168.1.1 - DNS Search Domain: example.local +6. Delete a VM with Confirmation: + + Command: + so-salt-cloud -p sool9-hyper1 vm1_sensor -d + + This command deletes the VM named vm1_sensor and will prompt for confirmation before proceeding. + +7. Delete a VM without Confirmation: + + Command: + so-salt-cloud -p sool9-hyper1 vm1_sensor -yd + + This command deletes the VM named vm1_sensor without prompting for confirmation. + Notes: - When using --static4, both --ip4 and --gw4 options are required. @@ -189,6 +213,7 @@ import sys import threading import salt.client import logging +import yaml # Initialize Salt local client local = salt.client.LocalClient() @@ -228,8 +253,94 @@ def call_so_firewall_minion(ip, role): except Exception as e: logger.error(f"An error occurred while calling so-firewall-minion: {e}") -def call_salt_cloud(profile, vm_name): +def get_vm_ip(vm_name): + """Get IP address of VM before deletion""" try: + # Get IP from minion's pillar file + pillar_file = f"/opt/so/saltstack/local/pillar/minions/{vm_name}.sls" + with open(pillar_file, 'r') as f: + pillar_data = yaml.safe_load(f) + + if pillar_data and 'host' in pillar_data and 'mainip' in pillar_data['host']: + return pillar_data['host']['mainip'] + raise Exception(f"Could not find mainip in pillar file {pillar_file}") + except FileNotFoundError: + raise Exception(f"Pillar file not found: {pillar_file}") + except Exception as e: + logger.error(f"Failed to get IP for VM {vm_name}: {e}") + raise + +def cleanup_deleted_vm(ip, role): + """Handle cleanup tasks when a VM is deleted""" + try: + # Remove IP from firewall + process = subprocess.Popen( + ['/usr/sbin/so-firewall', '--apply', 'removehost', ip], + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + text=True + ) + + for line in iter(process.stdout.readline, ''): + if line: + logger.info(line.rstrip('\n')) + + process.stdout.close() + process.wait() + + if process.returncode == 0: + logger.info(f"Successfully removed IP {ip} from firewall configuration") + else: + logger.error(f"Failed to remove IP {ip} from firewall configuration") + + except Exception as e: + logger.error(f"Error during VM cleanup: {e}") + +def delete_vm(profile, vm_name, assume_yes=False): + """Delete a VM and perform cleanup tasks""" + try: + # Get VM's IP before deletion for cleanup + ip = get_vm_ip(vm_name) + role = vm_name.split("_")[1] + + # Run salt-cloud destroy command + cmd = ['salt-cloud', '-p', profile, vm_name, '-d'] + if assume_yes: + cmd.append('-y') + + process = subprocess.Popen( + cmd, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + text=True + ) + + # Monitor output + for line in iter(process.stdout.readline, ''): + if line: + logger.info(line.rstrip('\n')) + + process.stdout.close() + process.wait() + + if process.returncode == 0: + # Start cleanup tasks + cleanup_deleted_vm(ip, role) + logger.info(f"Successfully deleted VM {vm_name}") + else: + logger.error(f"Failed to delete VM {vm_name}") + + except Exception as e: + logger.error(f"Failed to delete VM {vm_name}: {e}") + raise + +def call_salt_cloud(profile, vm_name, destroy=False, assume_yes=False): + """Call salt-cloud to create or destroy a VM""" + try: + if destroy: + delete_vm(profile, vm_name, assume_yes) + return + # Start the salt-cloud command as a subprocess process = subprocess.Popen( ['salt-cloud', '-p', profile, vm_name, '-l', 'info'], @@ -317,45 +428,60 @@ def parse_arguments(): parser = argparse.ArgumentParser(description="Call salt-cloud and pass the profile and VM name to it.") parser.add_argument('-p', '--profile', type=str, required=True, help="The cloud profile to build the VM from.") parser.add_argument('vm_name', type=str, help="The name of the VM.") + parser.add_argument('-d', '--destroy', action='store_true', help='Delete the specified VM') + parser.add_argument('-y', '--assume-yes', action='store_true', help='Default yes in answer to all confirmation questions') - group = parser.add_mutually_exclusive_group(required=True) - group.add_argument("--dhcp4", action="store_true", help="Configure interface for DHCP (IPv4).") - group.add_argument("--static4", action="store_true", help="Configure interface for static IPv4 settings.") + # Create a group for network config arguments + network_group = parser.add_argument_group('Network Configuration') + # Make the group mutually exclusive but not required by default + mode_group = network_group.add_mutually_exclusive_group() + mode_group.add_argument("--dhcp4", action="store_true", help="Configure interface for DHCP (IPv4).") + mode_group.add_argument("--static4", action="store_true", help="Configure interface for static IPv4 settings.") - parser.add_argument("--ip4", help="IPv4 address (e.g., 192.168.1.10/24). Required for static IPv4 configuration.") - parser.add_argument("--gw4", help="IPv4 gateway (e.g., 192.168.1.1). Required for static IPv4 configuration.") - parser.add_argument("--dns4", help="Comma-separated list of IPv4 DNS servers (e.g., 8.8.8.8,8.8.4.4).") - parser.add_argument("--search4", help="DNS search domain for IPv4.") - parser.add_argument('-c', '--cpu', type=int, help='Number of virtual CPUs to assign.') - parser.add_argument('-m', '--memory', type=int, help='Amount of memory to assign in MiB.') - parser.add_argument('-P', '--pci', action='append', help='PCI hardware ID(s) to passthrough to the VM (e.g., 0000:c7:00.0). Can be specified multiple times.') + # Add other network and hardware arguments + network_group.add_argument("--ip4", help="IPv4 address (e.g., 192.168.1.10/24). Required for static IPv4 configuration.") + network_group.add_argument("--gw4", help="IPv4 gateway (e.g., 192.168.1.1). Required for static IPv4 configuration.") + network_group.add_argument("--dns4", help="Comma-separated list of IPv4 DNS servers (e.g., 8.8.8.8,8.8.4.4).") + network_group.add_argument("--search4", help="DNS search domain for IPv4.") + network_group.add_argument('-c', '--cpu', type=int, help='Number of virtual CPUs to assign.') + network_group.add_argument('-m', '--memory', type=int, help='Amount of memory to assign in MiB.') + network_group.add_argument('-P', '--pci', action='append', help='PCI hardware ID(s) to passthrough to the VM (e.g., 0000:c7:00.0). Can be specified multiple times.') args = parser.parse_args() - if args.static4: - if not args.ip4 or not args.gw4: - parser.error("Both --ip4 and --gw4 are required for static IPv4 configuration.") + # Only validate network config if not destroying + if not args.destroy: + if not args.dhcp4 and not args.static4: + parser.error("One of --dhcp4 or --static4 is required for VM creation") + if args.static4 and (not args.ip4 or not args.gw4): + parser.error("Both --ip4 and --gw4 are required for static IPv4 configuration") + return args def main(): try: args = parse_arguments() - if args.dhcp4: - mode = "dhcp4" - elif args.static4: - mode = "static4" + if args.destroy: + # Handle VM deletion + call_salt_cloud(args.profile, args.vm_name, destroy=True, assume_yes=args.assume_yes) else: - mode = "dhcp4" # Default to DHCP if not specified + # Handle VM creation + if args.dhcp4: + mode = "dhcp4" + elif args.static4: + mode = "static4" + else: + mode = "dhcp4" # Default to DHCP if not specified - # Step 1: Modify network configuration - run_qcow2_modify_network_config(args.profile, mode, args.ip4, args.gw4, args.dns4, args.search4) + # Step 1: Modify network configuration + run_qcow2_modify_network_config(args.profile, mode, args.ip4, args.gw4, args.dns4, args.search4) - # Step 2: Provision the VM (without starting it) - call_salt_cloud(args.profile, args.vm_name) + # Step 2: Provision the VM (without starting it) + call_salt_cloud(args.profile, args.vm_name) - # Step 3: Modify hardware configuration - run_qcow2_modify_hardware_config(args.profile, args.vm_name, cpu=args.cpu, memory=args.memory, pci_list=args.pci, start=True) + # Step 3: Modify hardware configuration + run_qcow2_modify_hardware_config(args.profile, args.vm_name, cpu=args.cpu, memory=args.memory, pci_list=args.pci, start=True) except KeyboardInterrupt: logger.error("so-salt-cloud: Operation cancelled by user.") From 5a6a9d6ec2a3993e5ab706dd59b48c9458c25a41 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Tue, 28 Jan 2025 16:01:49 -0500 Subject: [PATCH 104/315] round ES_HEAP_SIZE --- salt/setup/virt/soinstall.map.jinja | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/setup/virt/soinstall.map.jinja b/salt/setup/virt/soinstall.map.jinja index c16f6cd78..33da9ff0c 100644 --- a/salt/setup/virt/soinstall.map.jinja +++ b/salt/setup/virt/soinstall.map.jinja @@ -35,7 +35,7 @@ {% elif total_mem >= 100000 %} {% set ES_HEAP_SIZE = "25000m" %} {% else %} -{% set ES_HEAP_SIZE = total_mem / 3 %} +{% set ES_HEAP_SIZE = (total_mem / 3) | int %} {% if ES_HEAP_SIZE > 25000 %} {% set ES_HEAP_SIZE = "25000m" %} {% else %} From 87136e9e2bb8419138c0ba6f3857a75306c7e9ab Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Tue, 28 Jan 2025 16:38:20 -0500 Subject: [PATCH 105/315] restart salt-minion to trigger highstate --- salt/setup/virt/init.sls | 2 +- salt/setup/virt/setSalt.sls | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/salt/setup/virt/init.sls b/salt/setup/virt/init.sls index be89c8588..384ae706f 100644 --- a/salt/setup/virt/init.sls +++ b/salt/setup/virt/init.sls @@ -1,4 +1,4 @@ include: - - setup.virt.setSalt - setup.virt.setHostname - setup.virt.sominion + - setup.virt.setSalt diff --git a/salt/setup/virt/setSalt.sls b/salt/setup/virt/setSalt.sls index c48282747..eb189b4b2 100644 --- a/salt/setup/virt/setSalt.sls +++ b/salt/setup/virt/setSalt.sls @@ -19,3 +19,10 @@ set_highstate: file.append: - name: /etc/salt/minion - text: 'startup_states: highstate' + +restart_salt_minion: + service.running: + - name: salt-minion + - enable: True + - watch: + - file: set_highstate From 8b3f310212c7a1a2500e0d96a1092d817a456be2 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Wed, 29 Jan 2025 04:08:30 -0500 Subject: [PATCH 106/315] install python3-dnf-plugin-versionlock on vm before first highstate --- salt/common/packages.sls | 8 ++++---- salt/setup/virt/init.sls | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/salt/common/packages.sls b/salt/common/packages.sls index c5d2729fd..5e72c50ee 100644 --- a/salt/common/packages.sls +++ b/salt/common/packages.sls @@ -1,6 +1,6 @@ -{% from 'vars/globals.map.jinja' import GLOBALS %} - -{% if GLOBALS.os_family == 'Debian' %} +# we cannot import GLOBALS from vars/globals.map.jinja in this state since it is called in setup.virt.init +# since it is early in setup of a new VM, the pillars imported in GLOBALS are not yet defined +{% if grains.os_family == 'Debian' %} commonpkgs: pkg.installed: - skip_suggestions: True @@ -45,7 +45,7 @@ python-rich: {% endif %} {% endif %} -{% if GLOBALS.os_family == 'RedHat' %} +{% if grains.os_family == 'RedHat' %} remove_mariadb: pkg.removed: diff --git a/salt/setup/virt/init.sls b/salt/setup/virt/init.sls index 384ae706f..9c173a78e 100644 --- a/salt/setup/virt/init.sls +++ b/salt/setup/virt/init.sls @@ -1,4 +1,5 @@ include: - setup.virt.setHostname - setup.virt.sominion + - common.packages # python3-dnf-plugin-versionlock - setup.virt.setSalt From ea2e026c564f429b6cef1679937e82eedc88b9e5 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Wed, 29 Jan 2025 08:10:05 -0500 Subject: [PATCH 107/315] only manager nodes or heavynodes should ever be single-node --- salt/elasticsearch/enabled.sls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/elasticsearch/enabled.sls b/salt/elasticsearch/enabled.sls index 48280c506..4699dfb1f 100644 --- a/salt/elasticsearch/enabled.sls +++ b/salt/elasticsearch/enabled.sls @@ -38,7 +38,7 @@ so-elasticsearch: {% endfor %} {% endif %} - environment: - {% if ELASTICSEARCH_SEED_HOSTS | length == 1 or GLOBALS.role == 'so-heavynode' %} + {% if (GLOBALS.role in GLOBALS.manager_roles and ELASTICSEARCH_SEED_HOSTS | length == 1) or GLOBALS.role == 'so-heavynode' %} - discovery.type=single-node {% endif %} - ES_JAVA_OPTS=-Xms{{ GLOBALS.elasticsearch.es_heap }} -Xmx{{ GLOBALS.elasticsearch.es_heap }} -Des.transport.cname_in_publish_address=true -Dlog4j2.formatMsgNoLookups=true From 3c85b482912dbcc208bbac6f1be45afc3b013d9c Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Wed, 29 Jan 2025 08:12:50 -0500 Subject: [PATCH 108/315] manage with contents to simplify salt cloud profile file_map --- .../cloud/cloud.profiles.d/socloud.conf.jinja | 10 ++++++++-- .../etc/minion.d/mine_functions.conf.jinja | 14 -------------- salt/salt/mine_functions.sls | 19 +++++++++++++++++-- 3 files changed, 25 insertions(+), 18 deletions(-) delete mode 100644 salt/salt/etc/minion.d/mine_functions.conf.jinja diff --git a/salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja b/salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja index eb2f5b75e..35b9d8bba 100644 --- a/salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja +++ b/salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja @@ -35,9 +35,15 @@ sool9-{{host}}: # - echo "preflight_cmds" # the destination directory will be created if it doesn't exist file_map: - /opt/so/saltstack/default/salt/setup/virt/initial_schedule.sls: /opt/so/conf/salt/cloud_file_map/salt/initial_schedule.sls + /opt/so/saltstack/default/salt/setup/virt/initial_schedule.sls: /opt/so/conf/salt/cloud_file_map/salt/setup/virt/initial_schedule.sls + /opt/so/saltstack/default/salt/salt/mine_functions.sls: /opt/so/conf/salt/cloud_file_map/salt/salt/mine_functions.sls inline_script: - - "sudo salt-call state.apply initial_schedule --local --file-root=/opt/so/conf/salt/cloud_file_map/salt/" + - | + sudo salt-call state.apply salt.mine_functions \ + --local \ + --file-root=/opt/so/conf/salt/cloud_file_map/salt/ \ + pillar='{"host": {"mainint": "eth0"}}' + - "sudo salt-call state.apply setup.virt.initial_schedule --local --file-root=/opt/so/conf/salt/cloud_file_map/salt/" # - "rpm --import /tmp/securityonion.pub" # grains to add to the minion diff --git a/salt/salt/etc/minion.d/mine_functions.conf.jinja b/salt/salt/etc/minion.d/mine_functions.conf.jinja deleted file mode 100644 index fb721512f..000000000 --- a/salt/salt/etc/minion.d/mine_functions.conf.jinja +++ /dev/null @@ -1,14 +0,0 @@ -{% if grains.role == 'so-hypervisor' %} -{% set interface = 'br0' %} -{% else %} -{% set interface = pillar.host.mainint %} -{% endif %} - -mine_interval: 25 -mine_functions: - network.ip_addrs: - - interface: {{ interface }} -{%- if grains.role in ['so-eval','so-import','so-manager','so-managersearch','so-standalone'] %} - x509.get_pem_entries: - - glob_path: '/etc/pki/ca.crt' -{% endif -%} diff --git a/salt/salt/mine_functions.sls b/salt/salt/mine_functions.sls index 49a47e524..a828add9b 100644 --- a/salt/salt/mine_functions.sls +++ b/salt/salt/mine_functions.sls @@ -6,8 +6,23 @@ # this state was seperated from salt.minion state since it is called during setup # GLOBALS are imported in the salt.minion state and that is not available at that point in setup # this state is included in the salt.minion state + +{% set role = salt['grains.get']('role', '') %} +{% if role == 'so-hypervisor' -%} +{% set interface = 'br0' %} +{% else %} +{% set interface = pillar.host.mainint %} +{% endif %} + mine_functions: file.managed: - name: /etc/salt/minion.d/mine_functions.conf - - source: salt://salt/etc/minion.d/mine_functions.conf.jinja - - template: jinja + - contents: | + mine_interval: 25 + mine_functions: + network.ip_addrs: + - interface: {{ interface }} + {%- if role in ['so-eval','so-import','so-manager','so-managersearch','so-standalone'] %} + x509.get_pem_entries: + - glob_path: '/etc/pki/ca.crt' + {% endif -%} From 8d1ce0460f3ae025a9e9e8766116802fac317cbf Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Wed, 29 Jan 2025 14:23:10 -0500 Subject: [PATCH 109/315] remove possible race condition caused by vm init cron for setup.virt.init. setup.virt and mine updated during salt-cloud call with init_script --- .../salt/cloud/cloud.profiles.d/socloud.conf.jinja | 14 +++++++------- salt/setup/virt/initial_schedule.sls | 13 ------------- salt/setup/virt/setSalt.sls | 14 ++------------ 3 files changed, 9 insertions(+), 32 deletions(-) delete mode 100644 salt/setup/virt/initial_schedule.sls diff --git a/salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja b/salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja index 35b9d8bba..1de995f74 100644 --- a/salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja +++ b/salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja @@ -3,6 +3,8 @@ https://securityonion.net/license; you may not use this file except in compliance with the Elastic License 2.0. #} +{#- https://docs.saltproject.io/en/latest/topics/cloud/misc.html #} + {%- for role, hosts in HYPERVISORS.items() %} {%- for host in hosts.keys() -%} @@ -34,17 +36,15 @@ sool9-{{host}}: #preflight_cmds: # - echo "preflight_cmds" # the destination directory will be created if it doesn't exist - file_map: - /opt/so/saltstack/default/salt/setup/virt/initial_schedule.sls: /opt/so/conf/salt/cloud_file_map/salt/setup/virt/initial_schedule.sls - /opt/so/saltstack/default/salt/salt/mine_functions.sls: /opt/so/conf/salt/cloud_file_map/salt/salt/mine_functions.sls + #file_map: + # /opt/so/saltstack/default/salt/salt/mine_functions.sls: /opt/so/conf/salt/cloud_file_map/salt/salt/mine_functions.sls + # if calling states with pillar values, need to pass them in since minion pillars are not set until setup.virt.sominion state runs inline_script: - | sudo salt-call state.apply salt.mine_functions \ - --local \ - --file-root=/opt/so/conf/salt/cloud_file_map/salt/ \ pillar='{"host": {"mainint": "eth0"}}' - - "sudo salt-call state.apply setup.virt.initial_schedule --local --file-root=/opt/so/conf/salt/cloud_file_map/salt/" - # - "rpm --import /tmp/securityonion.pub" + - 'sudo salt-call mine.update' + - 'sudo salt-call state.apply setup.virt' # grains to add to the minion {%- endfor %} diff --git a/salt/setup/virt/initial_schedule.sls b/salt/setup/virt/initial_schedule.sls deleted file mode 100644 index 6388e7c31..000000000 --- a/salt/setup/virt/initial_schedule.sls +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one -# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at -# https://securityonion.net/license; you may not use this file except in compliance with the -# Elastic License 2.0. - -# initially tried to use schedule.present here, but that state trys to return data to the master even if run with --local -# that causes it to fail since th firewall may not yet be open on the manager -init_node_cron: - cron.present: - - name: salt-call state.apply setup.virt.init - - identifier: init_node_cron - - user: root - - minute: '*/1' diff --git a/salt/setup/virt/setSalt.sls b/salt/setup/virt/setSalt.sls index eb189b4b2..69c8795de 100644 --- a/salt/setup/virt/setSalt.sls +++ b/salt/setup/virt/setSalt.sls @@ -8,21 +8,11 @@ set_role_grain: - name: role - value: so-{{ grains.id.split("_") | last }} -# remove the initial cron -remove_init_node_cron: - cron.absent: - - name: salt-call state.apply setup.virt.init - - identifier: init_node_cron - - user: root - set_highstate: file.append: - name: /etc/salt/minion - text: 'startup_states: highstate' -restart_salt_minion: - service.running: +enable_salt_minion: + service.enabled: - name: salt-minion - - enable: True - - watch: - - file: set_highstate From a5f2db8c803a3890019fc4d904ba3eeb3c601585 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Wed, 29 Jan 2025 18:17:29 -0500 Subject: [PATCH 110/315] add preflight check to ensure repo connectivity prior to installing salt-minion with salt-cloud --- salt/manager/tools/sbin/so-firewall | 5 +-- salt/manager/tools/sbin/so-salt-cloud | 32 +++++++++++++------ .../cloud/cloud.profiles.d/socloud.conf.jinja | 7 ++-- 3 files changed, 30 insertions(+), 14 deletions(-) diff --git a/salt/manager/tools/sbin/so-firewall b/salt/manager/tools/sbin/so-firewall index f1746ba8d..44f812cec 100755 --- a/salt/manager/tools/sbin/so-firewall +++ b/salt/manager/tools/sbin/so-firewall @@ -33,7 +33,7 @@ defaultsFilename = "/opt/so/saltstack/default/salt/firewall/defaults.yaml" def showUsage(options, args): usage = f'''Usage: {sys.argv[0]} [OPTIONS] [ARGS...] Options: - --apply - After updating the firewall configuration files, apply the new firewall state + --apply - After updating the firewall configuration files, apply the new firewall state with queue=True General commands: help - Prints this usage information. @@ -105,7 +105,8 @@ def includehost(options, args): def apply(options, args): logger.info("Applying firewall configuration changes") - proc = subprocess.run(['salt-call', 'state.apply', 'firewall', 'queue=True']) + salt_args = ['salt-call', 'state.apply', 'firewall', 'queue=True'] + proc = subprocess.run(salt_args) if proc.returncode != 0: logger.error("Failed to apply firewall changes") else: diff --git a/salt/manager/tools/sbin/so-salt-cloud b/salt/manager/tools/sbin/so-salt-cloud index 5ce8d9789..d4c728143 100644 --- a/salt/manager/tools/sbin/so-salt-cloud +++ b/salt/manager/tools/sbin/so-salt-cloud @@ -28,7 +28,9 @@ This script integrates multiple components to provide a streamlined VM deploymen 4. Security Integration: - Automatic firewall rule configuration - - Integrates with so-firewall-minion for firewall setup on the manager + - Directly integrates with so-firewall for consistent VM management + - Configures role-based firewall rules for new VMs + - Uses same firewall integration approach for both adding and removing VMs This script serves as the primary interface for VM deployment in Security Onion, coordinating between salt-cloud, network configuration, hardware management, and security components to @@ -174,9 +176,9 @@ The so-salt-cloud script automates the provisioning and configuration of virtual 4. Security Integration Phase: - Monitors salt-cloud output for VM IP address assignment - Extracts role information from VM name - - Launches so-firewall-minion in a separate thread for non-blocking operation + - Calls so-firewall directly to configure firewall rules - Configures role-based firewall rules automatically - - Ensures security policies are in place before VM is accessible + - Ensures security policies are in place for VM access - Logs all security-related operations for audit purposes The script implements extensive error handling and logging throughout each phase: @@ -190,7 +192,7 @@ The script implements extensive error handling and logging throughout each phase Integration points: - Works with Security Onion's salt-cloud provider - Interfaces with qcow2 module for image and hardware management -- Coordinates with so-firewall-minion for security configuration +- Directly integrates with so-firewall for security configuration - Uses libvirt for VM management - Leverages SaltStack for distributed execution @@ -232,11 +234,21 @@ console_handler.setFormatter(formatter) logger.addHandler(file_handler) logger.addHandler(console_handler) -def call_so_firewall_minion(ip, role): +def add_host_to_firewall(ip, role): + """Configure firewall rules for a new VM. + + Args: + ip (str): The IP address of the VM to add to the firewall + role (str): The role of the VM (e.g., 'sensor', 'manager', etc.) + + This function calls so-firewall directly to configure firewall rules, + maintaining consistency with how firewall rules are managed during + VM deletion. + """ try: - # Start so-firewall-minion as a subprocess + # Call so-firewall directly with --apply process = subprocess.Popen( - ['/usr/sbin/so-firewall-minion', f'--ip={ip}', f'--role={role}'], + ['/usr/sbin/so-firewall', 'includehost', role.lower(), ip, '--apply'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True @@ -251,7 +263,7 @@ def call_so_firewall_minion(ip, role): process.wait() except Exception as e: - logger.error(f"An error occurred while calling so-firewall-minion: {e}") + logger.error(f"An error occurred while adding host to firewall: {e}") def get_vm_ip(vm_name): """Get IP address of VM before deletion""" @@ -366,8 +378,8 @@ def call_salt_cloud(profile, vm_name, destroy=False, assume_yes=False): if len(parts) > 1: ip_address = parts[1].strip() logger.info(f"Extracted IP address: {ip_address}") - # Create and start a thread to run so-firewall-minion - thread = threading.Thread(target=call_so_firewall_minion, args=(ip_address, role.upper())) + # Create and start a thread to add host to firewall + thread = threading.Thread(target=add_host_to_firewall, args=(ip_address, role)) thread.start() else: logger.error("No IP address found.") diff --git a/salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja b/salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja index 1de995f74..2f0323482 100644 --- a/salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja +++ b/salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja @@ -33,8 +33,11 @@ sool9-{{host}}: log_file: /opt/so/log/salt/minion grains: hypervisor_host: {{host ~ "_" ~ role}} - #preflight_cmds: - # - echo "preflight_cmds" + preflight_cmds: + - | + timeout 600 bash -c 'trap "echo \"Preflight Check: Failed to establish repo connectivity\"; exit 1" TERM; \ + while ! dnf makecache --repoid=securityonion >/dev/null 2>&1; do echo "Preflight Check: Waiting for repo connectivity..."; \ + sleep 5; done && echo "Preflight Check: Successfully connected to repo" || exit 1; [ $? -eq 0 ]' # the destination directory will be created if it doesn't exist #file_map: # /opt/so/saltstack/default/salt/salt/mine_functions.sls: /opt/so/conf/salt/cloud_file_map/salt/salt/mine_functions.sls From 08bbeedbd79f38491a86b3e493f751360485c5ca Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Thu, 30 Jan 2025 09:55:26 -0500 Subject: [PATCH 111/315] add automatic NVMe device mounting for VMs with LVM support --- salt/storage/files/so-nsm-mount | 304 ++++++++++++++++++++++++++++++++ salt/storage/init.sls | 7 + salt/storage/nsm_mount.sls | 40 +++++ salt/top.sls | 3 + 4 files changed, 354 insertions(+) create mode 100644 salt/storage/files/so-nsm-mount create mode 100644 salt/storage/init.sls create mode 100644 salt/storage/nsm_mount.sls diff --git a/salt/storage/files/so-nsm-mount b/salt/storage/files/so-nsm-mount new file mode 100644 index 000000000..b06bccc2a --- /dev/null +++ b/salt/storage/files/so-nsm-mount @@ -0,0 +1,304 @@ +#!/bin/bash + +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +# Usage: +# so-nsm-mount +# +# Options: +# None - script automatically detects and configures NVMe devices +# +# Examples: +# 1. Configure and mount NVMe devices: +# ```bash +# sudo so-nsm-mount +# ``` +# +# Notes: +# - Requires root privileges +# - Automatically detects unmounted NVMe devices +# - Handles multiple NVMe devices: +# * Creates PV from each device +# * Combines all devices into single volume group +# * Creates single logical volume using total space +# - Safely handles existing LVM configurations: +# * Preserves proper existing configurations +# * Provides cleanup instructions if conflicts found +# - Creates or extends LVM configuration if no conflicts +# - Uses XFS filesystem +# - Configures persistent mount via /etc/fstab +# - Safe to run multiple times +# +# Description: +# This script automates the configuration and mounting of NVMe devices +# as /nsm in Security Onion virtual machines. It performs these steps: +# +# 1. Safety Checks: +# - Verifies root privileges +# - Checks if /nsm is already mounted +# - Detects available unmounted NVMe devices +# +# 2. LVM Configuration Check: +# - If device is part of "system" VG with "nsm" LV: +# * Uses existing configuration +# * Exits successfully +# - If device is part of different LVM configuration: +# * Logs current configuration details +# * Provides specific cleanup instructions +# * Exits with error to prevent data loss +# +# 3. New Configuration (if no conflicts): +# - Creates physical volume on each NVMe device +# - Combines all devices into single "system" volume group +# - Creates single "nsm" logical volume using total space +# - Creates XFS filesystem +# - Updates /etc/fstab for persistence +# - Mounts the filesystem as /nsm +# +# Exit Codes: +# 0: Success conditions: +# - Devices configured and mounted +# - Already properly mounted +# 1: Error conditions: +# - Must be run as root +# - No available NVMe devices found +# - Device has conflicting LVM configuration +# - Device preparation failed +# - LVM operation failed +# - Filesystem/mount operation failed +# +# Logging: +# - All operations logged to both console and /opt/so/log/so-nsm-mount.log + +set -e + +LOG_FILE="/opt/so/log/so-nsm-mount.log" +VG_NAME="system" +LV_NAME="nsm" +MOUNT_POINT="/nsm" + +# Function to log messages +log() { + local msg="$(date '+%Y-%m-%d %H:%M:%S') $1" + echo "$msg" | tee -a "$LOG_FILE" +} + +# Function to check if running as root +check_root() { + if [ "$EUID" -ne 0 ]; then + log "Error: Failed to execute - script must be run as root" + exit 1 + fi +} + +# Function to check LVM configuration of a device +check_lvm_config() { + local device=$1 + local vg_name + local lv_name + + # Check if device is a PV + if ! pvs "$device" &>/dev/null; then + return 0 + fi + + # Get VG name if any + vg_name=$(pvs --noheadings -o vg_name "$device" | tr -d ' ') + if [ -z "$vg_name" ]; then + return 0 + fi + + # If it's our expected configuration + if [ "$vg_name" = "$VG_NAME" ]; then + if lvs "$VG_NAME/$LV_NAME" &>/dev/null; then + # Our expected configuration exists + if ! mountpoint -q "$MOUNT_POINT"; then + log "Found existing LVM configuration. Remounting $MOUNT_POINT" + mount "$MOUNT_POINT" + fi + exit 0 + fi + fi + + # Get all LVs in the VG + local lvs_in_vg=$(lvs --noheadings -o lv_name "$vg_name" 2>/dev/null | tr '\n' ',' | sed 's/,$//') + + log "Error: Device $device is part of existing LVM configuration:" + log " Volume Group: $vg_name" + log " Logical Volumes: ${lvs_in_vg:-none}" + log "" + log "To preserve data safety, no changes will be made." + log "" + log "If you want to repurpose this device for /nsm, verify it's safe to proceed:" + log "1. Check current usage: lsblk $device" + log "2. Then run this command to clean up (CAUTION: THIS WILL DESTROY ALL DATA):" + log " umount $MOUNT_POINT 2>/dev/null; " + for lv in $(echo "$lvs_in_vg" | tr ',' ' '); do + log " lvremove -f /dev/$vg_name/$lv; " + done + log " vgreduce $vg_name $device && pvremove -ff -y $device && wipefs -a $device" + + exit 1 +} + +# Function to detect NVMe devices +detect_nvme_devices() { + local devices=() + for dev in /dev/nvme*n1; do + if [ -b "$dev" ]; then + # Skip if device is already part of a mounted filesystem + if ! lsblk -no MOUNTPOINT "$dev" | grep -q .; then + devices+=("$dev") + fi + fi + done + + if [ ${#devices[@]} -eq 0 ]; then + log "Error: No available NVMe devices found" + exit 1 + fi + + echo "${devices[@]}" +} + +# Function to prepare devices for LVM +prepare_devices() { + local devices=("$@") + + for device in "${devices[@]}"; do + # Check existing LVM configuration first + check_lvm_config "$device" + + # Clean existing signatures + if ! wipefs -a "$device" 2>wipefs.err; then + log "Error: Failed to clean signatures on $device: $(cat wipefs.err)" + rm -f wipefs.err + exit 1 + fi + rm -f wipefs.err + + # Create physical volume + if ! pvcreate -ff -y "$device" 2>pv.err; then + log "Error: Failed to create physical volume on $device: $(cat pv.err)" + rm -f pv.err + exit 1 + fi + rm -f pv.err + size=$(lsblk -dbn -o SIZE "$device" | numfmt --to=iec) + log "Created physical volume: $device ($size)" + done +} + +# Function to setup LVM +setup_lvm() { + local devices=("$@") + + # Create or extend volume group + if vgs "$VG_NAME" &>/dev/null; then + # Extend existing VG + if ! vgextend "$VG_NAME" "${devices[@]}" 2>vg.err; then + log "Error: Failed to extend volume group $VG_NAME: $(cat vg.err)" + rm -f vg.err + exit 1 + fi + rm -f vg.err + size=$(vgs --noheadings -o vg_size --units h "$VG_NAME" | tr -d ' ') + log "Extended volume group: $VG_NAME (total size: $size)" + else + # Create new VG + if ! vgcreate "$VG_NAME" "${devices[@]}" 2>vg.err; then + log "Error: Failed to create volume group $VG_NAME: $(cat vg.err)" + rm -f vg.err + exit 1 + fi + rm -f vg.err + size=$(vgs --noheadings -o vg_size --units h "$VG_NAME" | tr -d ' ') + log "Created volume group: $VG_NAME (size: $size)" + fi + + # Create logical volume using all available space + if ! lvs "$VG_NAME/$LV_NAME" &>/dev/null; then + if ! lvcreate -l 100%FREE -n "$LV_NAME" "$VG_NAME" 2>lv.err; then + log "Error: Failed to create logical volume $LV_NAME: $(cat lv.err)" + rm -f lv.err + exit 1 + fi + rm -f lv.err + size=$(lvs --noheadings -o lv_size --units h "$VG_NAME/$LV_NAME" | tr -d ' ') + log "Created logical volume: $LV_NAME (size: $size)" + fi +} + +# Function to create and mount filesystem +setup_filesystem() { + local device="/dev/$VG_NAME/$LV_NAME" + + # Create XFS filesystem if needed + if ! blkid "$device" | grep -q "TYPE=\"xfs\""; then + if ! mkfs.xfs -f "$device" 2>mkfs.err; then + log "Error: Failed to create XFS filesystem: $(cat mkfs.err)" + rm -f mkfs.err + exit 1 + fi + rm -f mkfs.err + size=$(lvs --noheadings -o lv_size --units h "$VG_NAME/$LV_NAME" | tr -d ' ') + log "Created XFS filesystem: $device (size: $size)" + fi + + # Create mount point + mkdir -p "$MOUNT_POINT" + + # Update fstab if needed + if ! grep -q "^$device.*$MOUNT_POINT" /etc/fstab; then + echo "$device $MOUNT_POINT xfs rw,relatime,seclabel,attr2,inode64,logbufs=8,logbsize=32k,noquota 0 0" >> /etc/fstab + log "Updated fstab configuration for $device" + fi + + # Mount the filesystem + if ! mountpoint -q "$MOUNT_POINT"; then + if ! mount "$MOUNT_POINT" 2>mount.err; then + log "Error: Failed to mount $MOUNT_POINT: $(cat mount.err)" + rm -f mount.err + exit 1 + fi + rm -f mount.err + size=$(df -h "$MOUNT_POINT" | awk 'NR==2 {print $2}') + log "Mounted filesystem: $device on $MOUNT_POINT (size: $size)" + fi +} + +# Main function +main() { + check_root + + # Check if already mounted + if mountpoint -q "$MOUNT_POINT"; then + size=$(df -h "$MOUNT_POINT" | awk 'NR==2 {print $2}') + log "$MOUNT_POINT already mounted (size: $size)" + exit 0 + fi + + # Detect NVMe devices + local devices + devices=($(detect_nvme_devices)) + log "Detected NVMe devices:" + for dev in "${devices[@]}"; do + size=$(lsblk -dbn -o SIZE "$dev" | numfmt --to=iec) + log " - $dev ($size)" + done + + # Prepare devices + prepare_devices "${devices[@]}" + + # Setup LVM + setup_lvm "${devices[@]}" + + # Create and mount filesystem + setup_filesystem +} + +# Run main function +main "$@" diff --git a/salt/storage/init.sls b/salt/storage/init.sls new file mode 100644 index 000000000..5bce7e71a --- /dev/null +++ b/salt/storage/init.sls @@ -0,0 +1,7 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +include: + - storage.nsm_mount diff --git a/salt/storage/nsm_mount.sls b/salt/storage/nsm_mount.sls new file mode 100644 index 000000000..b0476e054 --- /dev/null +++ b/salt/storage/nsm_mount.sls @@ -0,0 +1,40 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +# Install required packages +storage_nsm_mount_packages: + pkg.installed: + - pkgs: + - lvm2 + - xfsprogs + +# Ensure log directory exists +storage_nsm_mount_logdir: + file.directory: + - name: /opt/so/log + - makedirs: True + - user: root + - group: root + - mode: 755 + +# Install the NSM mount script +storage_nsm_mount_script: + file.managed: + - name: /usr/sbin/so-nsm-mount + - source: salt://storage/files/so-nsm-mount + - mode: 755 + - user: root + - group: root + - require: + - pkg: storage_nsm_mount_packages + - file: storage_nsm_mount_logdir + +# Execute the mount script if not already mounted +storage_nsm_mount_execute: + cmd.run: + - name: /usr/sbin/so-nsm-mount + - unless: mountpoint -q /nsm + - require: + - file: storage_nsm_mount_script diff --git a/salt/top.sls b/salt/top.sls index 09f7a2c28..82f074626 100644 --- a/salt/top.sls +++ b/salt/top.sls @@ -8,6 +8,9 @@ {% set INSTALLEDSALTVERSION = grains.saltversion %} base: + 'salt-cloud:driver:libvirt': + - match: grain + - storage '*': - cron.running From 61992ae78703829c7e907eaed590d01c8cb2d8fb Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Thu, 30 Jan 2025 13:28:08 -0500 Subject: [PATCH 112/315] verify script work with 1 or more nvme --- salt/storage/files/so-nsm-mount | 543 ++++++++++++++++++++++++++++---- 1 file changed, 480 insertions(+), 63 deletions(-) diff --git a/salt/storage/files/so-nsm-mount b/salt/storage/files/so-nsm-mount index b06bccc2a..9a2d00d88 100644 --- a/salt/storage/files/so-nsm-mount +++ b/salt/storage/files/so-nsm-mount @@ -83,13 +83,43 @@ MOUNT_POINT="/nsm" # Function to log messages log() { local msg="$(date '+%Y-%m-%d %H:%M:%S') $1" - echo "$msg" | tee -a "$LOG_FILE" + echo "$msg" | tee -a "$LOG_FILE" >&2 +} + +# Function to log errors +log_error() { + local msg="$(date '+%Y-%m-%d %H:%M:%S') ERROR: $1" + echo "$msg" | tee -a "$LOG_FILE" >&2 +} + +# Function to log command output +log_cmd() { + local cmd="$1" + local desc="$2" + local output + + # Use eval to properly handle shell operators + output=$(eval "$cmd" 2>&1) || { + local ret=$? + log_error "Command failed with exit code $ret: $cmd" + echo "$output" | while IFS= read -r line; do + log " $line" + done + return $ret + } + + if [ -n "$output" ]; then + log "$desc:" + echo "$output" | while IFS= read -r line; do + log " $line" + done + fi } # Function to check if running as root check_root() { if [ "$EUID" -ne 0 ]; then - log "Error: Failed to execute - script must be run as root" + log_error "Failed to execute - script must be run as root" exit 1 fi } @@ -100,23 +130,42 @@ check_lvm_config() { local vg_name local lv_name + log "Checking LVM configuration for $device" + + # Log device details + log_cmd "lsblk -o NAME,SIZE,TYPE,MOUNTPOINT $device" "Device details" + # Check if device is a PV if ! pvs "$device" &>/dev/null; then + log "Device is not a physical volume" return 0 fi + # Log PV details + log_cmd "pvs --noheadings -o pv_name,vg_name,pv_size,pv_used $device" "Physical volume details" + # Get VG name if any vg_name=$(pvs --noheadings -o vg_name "$device" | tr -d ' ') if [ -z "$vg_name" ]; then + log "Device is not part of any volume group" return 0 fi + # Log VG details + log_cmd "vgs --noheadings -o vg_name,vg_size,vg_free,pv_count $vg_name" "Volume group details" + # If it's our expected configuration if [ "$vg_name" = "$VG_NAME" ]; then if lvs "$VG_NAME/$LV_NAME" &>/dev/null; then - # Our expected configuration exists - if ! mountpoint -q "$MOUNT_POINT"; then + # Log LV details + log_cmd "lvs --noheadings -o lv_name,lv_size,lv_path $VG_NAME/$LV_NAME" "Logical volume details" + + # Check mount status + if mountpoint -q "$MOUNT_POINT"; then + log_cmd "df -h $MOUNT_POINT" "Current mount details" + else log "Found existing LVM configuration. Remounting $MOUNT_POINT" + log_cmd "grep -P \"^/dev/$VG_NAME/$LV_NAME\\s\" /etc/fstab" "Existing fstab entry" mount "$MOUNT_POINT" fi exit 0 @@ -126,7 +175,7 @@ check_lvm_config() { # Get all LVs in the VG local lvs_in_vg=$(lvs --noheadings -o lv_name "$vg_name" 2>/dev/null | tr '\n' ',' | sed 's/,$//') - log "Error: Device $device is part of existing LVM configuration:" + log_error "Device $device is part of existing LVM configuration:" log " Volume Group: $vg_name" log " Logical Volumes: ${lvs_in_vg:-none}" log "" @@ -144,130 +193,476 @@ check_lvm_config() { exit 1 } -# Function to detect NVMe devices -detect_nvme_devices() { - local devices=() - for dev in /dev/nvme*n1; do - if [ -b "$dev" ]; then - # Skip if device is already part of a mounted filesystem - if ! lsblk -no MOUNTPOINT "$dev" | grep -q .; then - devices+=("$dev") +# Function to cleanup device +cleanup_device() { + local device=$1 + + log "Cleaning up device $device" + + # Check if device is mounted + if mountpoint -q "$device"; then + log " Device is mounted, attempting unmount" + if ! umount "$device" 2>/dev/null; then + log_error "Failed to unmount device" + return 1 + fi + fi + + # Remove LVM configs if they exist + if pvs "$device" &>/dev/null; then + local vg=$(pvs --noheadings -o vg_name "$device" | tr -d ' ') + if [[ -n "$vg" && "$vg" != "$VG_NAME" ]]; then + log " Removing device from volume group $vg" + if ! vgreduce "$vg" "$device" 2>/dev/null; then + log_error "Failed to remove from volume group" + return 1 fi fi - done - - if [ ${#devices[@]} -eq 0 ]; then - log "Error: No available NVMe devices found" - exit 1 + log " Removing physical volume" + if ! pvremove -ff -y "$device" 2>/dev/null; then + log_error "Failed to remove physical volume" + return 1 + fi fi + + # Remove partitions and signatures + log " Removing partitions and signatures" + if ! wipefs -a "$device" 2>/dev/null; then + log_error "Failed to remove signatures" + return 1 + fi + + log " Device cleanup successful" + return 0 +} - echo "${devices[@]}" +# Function to validate device state +validate_device_state() { + local device=$1 + + if [[ ! -b "$device" ]]; then + log_error "$device is not a valid block device" + return 1 + fi + + # Check if device is already properly configured + if pvs "$device" &>/dev/null; then + local vg=$(pvs --noheadings -o vg_name "$device" | tr -d ' ') + if [[ "$vg" == "$VG_NAME" ]]; then + if lvs "$VG_NAME/$LV_NAME" &>/dev/null; then + log "Device $device is already properly configured in VG $VG_NAME" + log "Skipping device" + return 1 + fi + fi + fi + + # Check for existing partitions or LVM + if pvs "$device" &>/dev/null || lsblk -no TYPE "$device" | grep -q "part"; then + log "Device $device has existing configuration" + if ! cleanup_device "$device"; then + log "Failed to cleanup device $device" + return 1 + fi + fi + + return 0 +} + +# Function to log device details +log_device_details() { + local device=$1 + local size mount fs_type vg_name + + size=$(lsblk -dbn -o SIZE "$device" 2>/dev/null | numfmt --to=iec) + mount=$(lsblk -no MOUNTPOINT "$device" 2>/dev/null) + fs_type=$(lsblk -no FSTYPE "$device" 2>/dev/null) + + log "Device details for $device:" + log " Size: $size" + log " Filesystem: ${fs_type:-none}" + log " Mountpoint: ${mount:-none}" + + if pvs "$device" &>/dev/null; then + vg_name=$(pvs --noheadings -o vg_name "$device" | tr -d ' ') + log " LVM status: Physical volume in VG ${vg_name:-none}" + else + log " LVM status: Not a physical volume" + fi +} + +# Function to detect NVMe devices +detect_nvme_devices() { + local -a devices=() + local -a available_devices=() + + { + log "----------------------------------------" + log "Starting NVMe device detection" + log "----------------------------------------" + + # First get a clean list of devices + while read -r dev; do + if [[ -b "$dev" ]]; then + devices+=("$dev") + fi + done < <(find /dev -name 'nvme*n1' 2>/dev/null) + + if [ ${#devices[@]} -eq 0 ]; then + log_error "No NVMe devices found" + log "----------------------------------------" + exit 1 + fi + + log "Found ${#devices[@]} NVMe device(s)" + + # Process and validate each device + for dev in "${devices[@]}"; do + log_device_details "$dev" + + if validate_device_state "$dev"; then + available_devices+=("$dev") + log "Status: Available for use" + else + log "Status: Not available (see previous messages)" + fi + log "----------------------------------------" + done + + if [ ${#available_devices[@]} -eq 0 ]; then + log_error "No available NVMe devices found" + log "----------------------------------------" + exit 1 + fi + + log "Summary: ${#available_devices[@]} device(s) available for use" + for dev in "${available_devices[@]}"; do + local size=$(lsblk -dbn -o SIZE "$dev" 2>/dev/null | numfmt --to=iec) + log " - $dev ($size)" + done + log "----------------------------------------" + } >&2 + + # Return array elements one per line + printf '%s\n' "${available_devices[@]}" } # Function to prepare devices for LVM prepare_devices() { - local devices=("$@") + local -a devices=("$@") + local -a prepared_devices=() - for device in "${devices[@]}"; do - # Check existing LVM configuration first - check_lvm_config "$device" + { + log "----------------------------------------" + log "Starting device preparation" + log "----------------------------------------" - # Clean existing signatures - if ! wipefs -a "$device" 2>wipefs.err; then - log "Error: Failed to clean signatures on $device: $(cat wipefs.err)" + for device in "${devices[@]}"; do + if [[ ! -b "$device" ]]; then + log_error "Invalid device path: $device" + continue + fi + + log "Processing device: $device" + log_device_details "$device" + + # Check if device needs preparation + if ! validate_device_state "$device"; then + log "Skipping device $device - invalid state" + continue + fi + + log "Preparing device for LVM use:" + + # Clean existing signatures + log " Step 1: Cleaning existing signatures" + if ! wipefs -a "$device" 2>wipefs.err; then + log_error "Failed to clean signatures" + log " Details: $(cat wipefs.err)" + rm -f wipefs.err + continue + fi rm -f wipefs.err - exit 1 - fi - rm -f wipefs.err + log " Success: Signatures cleaned" - # Create physical volume - if ! pvcreate -ff -y "$device" 2>pv.err; then - log "Error: Failed to create physical volume on $device: $(cat pv.err)" + # Create physical volume + log " Step 2: Creating physical volume" + if ! pvcreate -ff -y "$device" 2>pv.err; then + log_error "Physical volume creation failed" + log " Details: $(cat pv.err)" + rm -f pv.err + continue + fi rm -f pv.err + + # Log success and add to prepared devices + size=$(lsblk -dbn -o SIZE "$device" | numfmt --to=iec) + log " Success: Created physical volume" + log " Device: $device" + log " Size: $size" + log_cmd "pvs --noheadings -o pv_name,vg_name,pv_size,pv_used $device" "Physical volume details" + + prepared_devices+=("$device") + log "----------------------------------------" + done + + if [ ${#prepared_devices[@]} -eq 0 ]; then + log_error "No devices were successfully prepared" exit 1 fi - rm -f pv.err - size=$(lsblk -dbn -o SIZE "$device" | numfmt --to=iec) - log "Created physical volume: $device ($size)" + } >&2 + + printf '%s\n' "${prepared_devices[@]}" +} + +# Function to wait for device +wait_for_device() { + local device="$1" + local timeout=10 + local count=0 + + log "Waiting for device $device to be available" + while [ ! -e "$device" ] && [ $count -lt $timeout ]; do + sleep 1 + count=$((count + 1)) + log " Attempt $count/$timeout" done + + if [ ! -e "$device" ]; then + log_error "Device $device did not appear after $timeout seconds" + return 1 + fi + + # Run udevadm trigger to ensure device nodes are created + log " Running udevadm trigger" + if ! udevadm trigger "$device" 2>/dev/null; then + log " WARNING: udevadm trigger failed, continuing anyway" + fi + + # Give udev a moment to create device nodes + sleep 1 + + # Run udevadm settle to wait for udev to finish processing + log " Waiting for udev to settle" + if ! udevadm settle 2>/dev/null; then + log " WARNING: udevadm settle failed, continuing anyway" + fi + + # Run vgscan to ensure LVM sees the device + log " Running vgscan" + if ! vgscan --mknodes 2>/dev/null; then + log " WARNING: vgscan failed, continuing anyway" + fi + + log " Device $device is now available" + return 0 } # Function to setup LVM setup_lvm() { - local devices=("$@") + local -a devices=("$@") + + log "----------------------------------------" + log "Starting LVM configuration" + log "----------------------------------------" + + # Log initial LVM state + log "Initial LVM state:" + log_cmd "pvs" "Physical volumes" + log_cmd "vgs" "Volume groups" + log_cmd "lvs" "Logical volumes" # Create or extend volume group if vgs "$VG_NAME" &>/dev/null; then + log "Step 1: Extending existing volume group" + log " Target VG: $VG_NAME" + log " Devices to add: ${devices[*]}" + # Extend existing VG if ! vgextend "$VG_NAME" "${devices[@]}" 2>vg.err; then - log "Error: Failed to extend volume group $VG_NAME: $(cat vg.err)" + log_error "Volume group extension failed" + log " Details: $(cat vg.err)" rm -f vg.err exit 1 fi rm -f vg.err + size=$(vgs --noheadings -o vg_size --units h "$VG_NAME" | tr -d ' ') - log "Extended volume group: $VG_NAME (total size: $size)" + log " Success: Extended volume group" + log " Name: $VG_NAME" + log " Total size: $size" else + log "Step 1: Creating new volume group" + log " Name: $VG_NAME" + log " Devices: ${devices[*]}" + # Create new VG if ! vgcreate "$VG_NAME" "${devices[@]}" 2>vg.err; then - log "Error: Failed to create volume group $VG_NAME: $(cat vg.err)" + log_error "Volume group creation failed" + log " Details: $(cat vg.err)" rm -f vg.err exit 1 fi rm -f vg.err + size=$(vgs --noheadings -o vg_size --units h "$VG_NAME" | tr -d ' ') - log "Created volume group: $VG_NAME (size: $size)" + log " Success: Created volume group" + log " Name: $VG_NAME" + log " Size: $size" fi + log_cmd "vgs $VG_NAME" "Volume group details" + # Create logical volume using all available space if ! lvs "$VG_NAME/$LV_NAME" &>/dev/null; then + log "Step 2: Creating logical volume" + log " Name: $LV_NAME" + log " Size: 100% of free space" + if ! lvcreate -l 100%FREE -n "$LV_NAME" "$VG_NAME" 2>lv.err; then - log "Error: Failed to create logical volume $LV_NAME: $(cat lv.err)" + log_error "Logical volume creation failed" + log " Details: $(cat lv.err)" rm -f lv.err exit 1 fi rm -f lv.err + size=$(lvs --noheadings -o lv_size --units h "$VG_NAME/$LV_NAME" | tr -d ' ') - log "Created logical volume: $LV_NAME (size: $size)" + log " Success: Created logical volume" + log " Name: $LV_NAME" + log " Size: $size" + log_cmd "lvs $VG_NAME/$LV_NAME" "Logical volume details" + else + log "Step 2: Logical volume already exists" + log_cmd "lvs $VG_NAME/$LV_NAME" "Existing logical volume details" fi + + log "----------------------------------------" } # Function to create and mount filesystem setup_filesystem() { local device="/dev/$VG_NAME/$LV_NAME" + log "----------------------------------------" + log "Starting filesystem setup" + log "----------------------------------------" + + log "Step 1: Checking device status" + log " Device path: $device" + + # Wait for device to be available + if ! wait_for_device "$device"; then + exit 1 + fi + + # Check filesystem type - don't fail if blkid fails + local fs_type + fs_type=$(blkid -o value -s TYPE "$device" 2>/dev/null || echo "none") + log " Current filesystem type: ${fs_type:-none}" + # Create XFS filesystem if needed - if ! blkid "$device" | grep -q "TYPE=\"xfs\""; then + log "Step 2: Filesystem preparation" + if [[ "$fs_type" != "xfs" ]]; then + log " Creating new XFS filesystem:" + log " Device: $device" + log " Options: -f (force)" + if ! mkfs.xfs -f "$device" 2>mkfs.err; then - log "Error: Failed to create XFS filesystem: $(cat mkfs.err)" + log_error "XFS filesystem creation failed" + log " Details: $(cat mkfs.err)" rm -f mkfs.err exit 1 fi rm -f mkfs.err + size=$(lvs --noheadings -o lv_size --units h "$VG_NAME/$LV_NAME" | tr -d ' ') - log "Created XFS filesystem: $device (size: $size)" + log " Success: Created XFS filesystem" + log " Device: $device" + log " Size: $size" + + # Verify filesystem was created + fs_type=$(blkid -o value -s TYPE "$device") + if [[ "$fs_type" != "xfs" ]]; then + log_error "Failed to verify XFS filesystem creation" + exit 1 + fi + log " Verified XFS filesystem" + else + log " XFS filesystem already exists" fi # Create mount point - mkdir -p "$MOUNT_POINT" + log "Step 3: Mount point preparation" + if [[ ! -d "$MOUNT_POINT" ]]; then + log " Creating mount point directory: $MOUNT_POINT" + mkdir -p "$MOUNT_POINT" + log " Success: Directory created" + else + log " Mount point already exists: $MOUNT_POINT" + fi # Update fstab if needed - if ! grep -q "^$device.*$MOUNT_POINT" /etc/fstab; then - echo "$device $MOUNT_POINT xfs rw,relatime,seclabel,attr2,inode64,logbufs=8,logbsize=32k,noquota 0 0" >> /etc/fstab - log "Updated fstab configuration for $device" + log "Step 4: Configuring persistent mount" + log " Checking current fstab entries:" + # Temporarily disable exit on error for fstab operations + set +e + + # Check fstab entries without failing on no match + if ! grep -P "^/dev/$VG_NAME/$LV_NAME\\s" /etc/fstab >/dev/null 2>&1; then + log " No existing fstab entry found" + else + log_cmd "grep -P '^/dev/$VG_NAME/$LV_NAME\\s' /etc/fstab" "Current configuration" + fi + + # Check if we need to add fstab entry + if ! grep -q "^$device.*$MOUNT_POINT" /etc/fstab >/dev/null 2>&1; then + # Re-enable exit on error for critical operations + set -e + log " Adding new fstab entry" + local mount_options="rw,relatime,seclabel,attr2,inode64,logbufs=8,logbsize=32k,noquota" + echo "$device $MOUNT_POINT xfs $mount_options 0 0" >> /etc/fstab + log " Success: Added entry" + log " Device: $device" + log " Mount point: $MOUNT_POINT" + log " Options: $mount_options" + log_cmd "grep -P \"^/dev/$VG_NAME/$LV_NAME\\s\" /etc/fstab" "New configuration" + + # Reload systemd to recognize new fstab entry + log " Reloading systemd to recognize new fstab entry" + if ! systemctl daemon-reload; then + log " WARNING: Failed to reload systemd, continuing anyway" + fi + else + log " Existing fstab entry found" + # Re-enable exit on error + set -e fi # Mount the filesystem + log "Step 5: Mounting filesystem" if ! mountpoint -q "$MOUNT_POINT"; then + log " Mounting $device to $MOUNT_POINT" if ! mount "$MOUNT_POINT" 2>mount.err; then - log "Error: Failed to mount $MOUNT_POINT: $(cat mount.err)" + log_error "Mount operation failed" + log " Details: $(cat mount.err)" rm -f mount.err exit 1 fi rm -f mount.err + size=$(df -h "$MOUNT_POINT" | awk 'NR==2 {print $2}') - log "Mounted filesystem: $device on $MOUNT_POINT (size: $size)" + log " Success: Filesystem mounted" + log " Device: $device" + log " Mount point: $MOUNT_POINT" + log " Size: $size" + log_cmd "df -h $MOUNT_POINT" "Mount details" + else + log " Filesystem already mounted" + log_cmd "df -h $MOUNT_POINT" "Current mount details" fi + + log "----------------------------------------" } # Main function @@ -278,26 +673,48 @@ main() { if mountpoint -q "$MOUNT_POINT"; then size=$(df -h "$MOUNT_POINT" | awk 'NR==2 {print $2}') log "$MOUNT_POINT already mounted (size: $size)" + log_cmd "df -h $MOUNT_POINT" "Current mount details" exit 0 fi - # Detect NVMe devices - local devices - devices=($(detect_nvme_devices)) - log "Detected NVMe devices:" - for dev in "${devices[@]}"; do - size=$(lsblk -dbn -o SIZE "$dev" | numfmt --to=iec) - log " - $dev ($size)" - done + # Log initial system state + log "Initial system state:" + log_cmd "lsblk" "Block devices" + log_cmd "pvs" "Physical volumes" + log_cmd "vgs" "Volume groups" + log_cmd "lvs" "Logical volumes" - # Prepare devices - prepare_devices "${devices[@]}" + # Detect NVMe devices + local -a devices=() + mapfile -t devices < <(detect_nvme_devices) - # Setup LVM - setup_lvm "${devices[@]}" + if [ ${#devices[@]} -eq 0 ]; then + log_error "No NVMe devices available for use" + exit 1 + fi + + # Prepare devices and get list of successfully prepared ones + local -a prepared_devices=() + mapfile -t prepared_devices < <(prepare_devices "${devices[@]}") + + if [ ${#prepared_devices[@]} -eq 0 ]; then + log_error "No devices were successfully prepared" + exit 1 + fi + + # Setup LVM with prepared devices + setup_lvm "${prepared_devices[@]}" # Create and mount filesystem setup_filesystem + + # Log final system state + log "Final system state:" + log_cmd "lsblk" "Block devices" + log_cmd "pvs" "Physical volumes" + log_cmd "vgs" "Volume groups" + log_cmd "lvs" "Logical volumes" + log_cmd "df -h $MOUNT_POINT" "Mount details" } # Run main function From 5c56e0f498ea9c5f5c1b3587c35866582c50c4f2 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Fri, 31 Jan 2025 11:18:11 -0500 Subject: [PATCH 113/315] already configured not failure state --- salt/storage/files/so-nsm-cleanup | 256 ++++++++++++++++++++++++++++++ salt/storage/files/so-nsm-mount | 95 +++++++---- 2 files changed, 319 insertions(+), 32 deletions(-) create mode 100644 salt/storage/files/so-nsm-cleanup diff --git a/salt/storage/files/so-nsm-cleanup b/salt/storage/files/so-nsm-cleanup new file mode 100644 index 000000000..f9af3aee8 --- /dev/null +++ b/salt/storage/files/so-nsm-cleanup @@ -0,0 +1,256 @@ +#!/bin/bash + +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +# Usage: +# so-nsm-cleanup +# +# Options: +# None - script automatically detects and cleans NVMe devices +# +# Examples: +# 1. Clean NVMe devices and LVM configuration: +# ```bash +# sudo so-nsm-cleanup +# ``` +# +# Notes: +# - Requires root privileges +# - CAUTION: This script will destroy all data on NVMe devices +# - Removes: +# * /nsm mount point +# * LVM configuration +# * Partitions and signatures +# - Safe to run multiple times +# +# Description: +# This script cleans up NVMe devices and LVM configuration to prepare +# for testing so-nsm-mount. It performs these steps: +# +# 1. Safety Checks: +# - Verifies root privileges +# - Detects NVMe devices +# - Warns about data loss +# +# 2. Cleanup Operations: +# - Unmounts and removes /nsm +# - Removes LVM configuration +# - Cleans partitions and signatures +# - Zeros out partition tables +# +# Exit Codes: +# 0: Success - cleanup completed +# 1: Error conditions: +# - Must be run as root +# - No NVMe devices found +# - Cleanup operation failed +# +# Logging: +# - All operations logged to both console and /opt/so/log/so-nsm-cleanup.log + +set -e + +LOG_FILE="/opt/so/log/so-nsm-cleanup.log" +MOUNT_POINT="/nsm" +VG_NAME="system" +LV_NAME="nsm" + +# Function to log messages +log() { + local msg="$(date '+%Y-%m-%d %H:%M:%S') $1" + echo "$msg" | tee -a "$LOG_FILE" +} + +# Function to log command output +log_cmd() { + local cmd="$1" + local output + output=$($cmd 2>&1) + if [ -n "$output" ]; then + log "$2:" + echo "$output" | while IFS= read -r line; do + log " $line" + done + fi +} + +# Function to check if running as root +check_root() { + if [ "$EUID" -ne 0 ]; then + log "Error: Failed to execute - script must be run as root" + exit 1 + fi +} + +# Function to detect NVMe devices +detect_nvme_devices() { + local -a devices=() + + { + log "----------------------------------------" + log "Starting NVMe device detection" + log "----------------------------------------" + + # Get list of NVMe devices + while read -r dev; do + if [[ -b "$dev" ]]; then + devices+=("$dev") + fi + done < <(find /dev -name 'nvme*n1' 2>/dev/null) + + if [ ${#devices[@]} -eq 0 ]; then + log "Error: No NVMe devices found" + log "----------------------------------------" + exit 1 + fi + + log "Found ${#devices[@]} NVMe device(s):" + for dev in "${devices[@]}"; do + local size=$(lsblk -dbn -o SIZE "$dev" 2>/dev/null | numfmt --to=iec) + log " - $dev ($size)" + done + log "----------------------------------------" + } >&2 + + # Only output device paths to stdout + printf '%s\n' "${devices[@]}" +} + +# Function to cleanup mount point +cleanup_mount() { + log "Cleaning up mount point $MOUNT_POINT" + + if mountpoint -q "$MOUNT_POINT" 2>/dev/null; then + log " Unmounting $MOUNT_POINT" + if ! umount "$MOUNT_POINT" 2>/dev/null; then + log " WARNING: Failed to unmount $MOUNT_POINT" + return 1 + fi + log " Successfully unmounted" + else + log " Not mounted - skipping unmount" + fi + + if [[ -d "$MOUNT_POINT" ]]; then + log " Removing directory" + rm -rf "$MOUNT_POINT" + log " Directory removed" + fi + + return 0 +} + +# Function to cleanup LVM +cleanup_lvm() { + log "Cleaning up LVM configuration" + + # Remove logical volume if it exists + if lvs "$VG_NAME/$LV_NAME" &>/dev/null; then + log " Removing logical volume $VG_NAME/$LV_NAME" + if ! lvremove -f "$VG_NAME/$LV_NAME" 2>/dev/null; then + log " WARNING: Failed to remove logical volume" + else + log " Logical volume removed" + fi + fi + + # Remove volume group if it exists + if vgs "$VG_NAME" &>/dev/null; then + log " Removing volume group $VG_NAME" + if ! vgremove -f "$VG_NAME" 2>/dev/null; then + log " WARNING: Failed to remove volume group" + else + log " Volume group removed" + fi + fi +} + +# Function to cleanup a device +cleanup_device() { + local device=$1 + + if [[ ! -b "$device" ]]; then + log "ERROR: Invalid device path: $device" + return 1 + fi + + local size=$(lsblk -dbn -o SIZE "$device" 2>/dev/null | numfmt --to=iec) + log "Processing device: $device ($size)" + + # Remove physical volume if it exists + if pvs "$device" &>/dev/null; then + log " Removing physical volume" + if ! pvremove -ff -y "$device" 2>/dev/null; then + log " WARNING: Failed to remove physical volume" + else + log " Physical volume removed" + fi + fi + + # Clean all signatures and partitions + log " Cleaning signatures and partitions" + if ! wipefs -a "$device" 2>/dev/null; then + log " WARNING: Failed to clean signatures" + else + log " Signatures cleaned" + fi + + # Zero out partition table + log " Zeroing partition table" + if ! dd if=/dev/zero of="$device" bs=1M count=10 status=none; then + log " WARNING: Failed to zero partition table" + else + log " Partition table zeroed" + fi + + log " Device cleanup completed" +} + +# Main function +main() { + check_root + + log "Starting NVMe device cleanup" + log "WARNING: This will destroy all data on NVMe devices!" + log "" + + # Log initial system state + log "Initial system state:" + log_cmd "lsblk" "Block devices" + log_cmd "pvs" "Physical volumes" + log_cmd "vgs" "Volume groups" + log_cmd "lvs" "Logical volumes" + log "" + + # Clean up mount point + cleanup_mount + + # Clean up LVM configuration + cleanup_lvm + + # Detect and clean up devices + local -a devices=() + mapfile -t devices < <(detect_nvme_devices) + + log "Starting device cleanup" + for device in "${devices[@]}"; do + cleanup_device "$device" + done + + # Log final system state + log "" + log "Final system state:" + log_cmd "lsblk" "Block devices" + log_cmd "pvs" "Physical volumes" + log_cmd "vgs" "Volume groups" + log_cmd "lvs" "Logical volumes" + + log "" + log "Cleanup completed successfully" +} + +# Run main function +main "$@" diff --git a/salt/storage/files/so-nsm-mount b/salt/storage/files/so-nsm-mount index 9a2d00d88..ab8e0a0f0 100644 --- a/salt/storage/files/so-nsm-mount +++ b/salt/storage/files/so-nsm-mount @@ -159,16 +159,7 @@ check_lvm_config() { if lvs "$VG_NAME/$LV_NAME" &>/dev/null; then # Log LV details log_cmd "lvs --noheadings -o lv_name,lv_size,lv_path $VG_NAME/$LV_NAME" "Logical volume details" - - # Check mount status - if mountpoint -q "$MOUNT_POINT"; then - log_cmd "df -h $MOUNT_POINT" "Current mount details" - else - log "Found existing LVM configuration. Remounting $MOUNT_POINT" - log_cmd "grep -P \"^/dev/$VG_NAME/$LV_NAME\\s\" /etc/fstab" "Existing fstab entry" - mount "$MOUNT_POINT" - fi - exit 0 + return 0 fi fi @@ -251,8 +242,7 @@ validate_device_state() { if [[ "$vg" == "$VG_NAME" ]]; then if lvs "$VG_NAME/$LV_NAME" &>/dev/null; then log "Device $device is already properly configured in VG $VG_NAME" - log "Skipping device" - return 1 + return 0 fi fi fi @@ -295,6 +285,7 @@ log_device_details() { detect_nvme_devices() { local -a devices=() local -a available_devices=() + local -a configured_devices=() { log "----------------------------------------" @@ -321,14 +312,35 @@ detect_nvme_devices() { log_device_details "$dev" if validate_device_state "$dev"; then - available_devices+=("$dev") - log "Status: Available for use" + if pvs "$dev" &>/dev/null; then + local vg=$(pvs --noheadings -o vg_name "$dev" | tr -d ' ') + if [[ "$vg" == "$VG_NAME" ]]; then + configured_devices+=("$dev") + log "Status: Already configured in VG $VG_NAME" + else + available_devices+=("$dev") + log "Status: Available for use" + fi + else + available_devices+=("$dev") + log "Status: Available for use" + fi else log "Status: Not available (see previous messages)" fi log "----------------------------------------" done + if [ ${#configured_devices[@]} -gt 0 ]; then + log "Found ${#configured_devices[@]} device(s) already configured:" + for dev in "${configured_devices[@]}"; do + local size=$(lsblk -dbn -o SIZE "$dev" 2>/dev/null | numfmt --to=iec) + log " - $dev ($size)" + done + log "Proceeding with mount setup" + return 0 + fi + if [ ${#available_devices[@]} -eq 0 ]; then log_error "No available NVMe devices found" log "----------------------------------------" @@ -556,6 +568,15 @@ setup_filesystem() { exit 1 fi + # Check for existing /nsm directory + if [[ -d "$MOUNT_POINT" ]]; then + log "WARNING: $MOUNT_POINT directory already exists" + if [[ -n "$(ls -A "$MOUNT_POINT")" ]]; then + log "WARNING: $MOUNT_POINT is not empty" + log "Contents will be hidden when mounted" + fi + fi + # Check filesystem type - don't fail if blkid fails local fs_type fs_type=$(blkid -o value -s TYPE "$device" 2>/dev/null || echo "none") @@ -684,27 +705,37 @@ main() { log_cmd "vgs" "Volume groups" log_cmd "lvs" "Logical volumes" - # Detect NVMe devices - local -a devices=() - mapfile -t devices < <(detect_nvme_devices) - - if [ ${#devices[@]} -eq 0 ]; then - log_error "No NVMe devices available for use" - exit 1 - fi + # Check if LVM is already configured + if vgs "$VG_NAME" &>/dev/null && lvs "$VG_NAME/$LV_NAME" &>/dev/null; then + log "Found existing LVM configuration" + log "Proceeding with filesystem setup" + else + # Detect NVMe devices + local -a devices=() + mapfile -t devices < <(detect_nvme_devices) + + if [ ${#devices[@]} -eq 0 ]; then + log_error "No NVMe devices found" + exit 1 + fi - # Prepare devices and get list of successfully prepared ones - local -a prepared_devices=() - mapfile -t prepared_devices < <(prepare_devices "${devices[@]}") - - if [ ${#prepared_devices[@]} -eq 0 ]; then - log_error "No devices were successfully prepared" - exit 1 + # Prepare devices and get list of successfully prepared ones + local -a prepared_devices=() + mapfile -t prepared_devices < <(prepare_devices "${devices[@]}") + + if [ ${#prepared_devices[@]} -eq 0 ]; then + if vgs "$VG_NAME" &>/dev/null && lvs "$VG_NAME/$LV_NAME" &>/dev/null; then + log "Devices already configured, proceeding with filesystem setup" + else + log_error "No devices were successfully prepared and no existing configuration found" + exit 1 + fi + else + # Setup LVM with prepared devices + setup_lvm "${prepared_devices[@]}" + fi fi - # Setup LVM with prepared devices - setup_lvm "${prepared_devices[@]}" - # Create and mount filesystem setup_filesystem From 0114e36cfa229ecbb59d1a676220bf3be1968e1d Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Fri, 31 Jan 2025 15:17:54 -0500 Subject: [PATCH 114/315] set lvm = system uuid and only sanitize new nvme if doesnt belong to current vm --- salt/storage/files/so-nsm-mount | 360 ++++++++++++++++++++++++++------ 1 file changed, 300 insertions(+), 60 deletions(-) diff --git a/salt/storage/files/so-nsm-mount b/salt/storage/files/so-nsm-mount index ab8e0a0f0..63cb810ec 100644 --- a/salt/storage/files/so-nsm-mount +++ b/salt/storage/files/so-nsm-mount @@ -36,6 +36,12 @@ # This script automates the configuration and mounting of NVMe devices # as /nsm in Security Onion virtual machines. It performs these steps: # +# Dependencies: +# - dmidecode: Required for getting system UUID +# - nvme-cli: Required for NVMe secure erase operations +# - lvm2: Required for LVM operations +# - xfsprogs: Required for XFS filesystem operations +# # 1. Safety Checks: # - Verifies root privileges # - Checks if /nsm is already mounted @@ -76,20 +82,18 @@ set -e LOG_FILE="/opt/so/log/so-nsm-mount.log" -VG_NAME="system" +VG_NAME="" LV_NAME="nsm" MOUNT_POINT="/nsm" # Function to log messages log() { - local msg="$(date '+%Y-%m-%d %H:%M:%S') $1" - echo "$msg" | tee -a "$LOG_FILE" >&2 + echo "$(date '+%Y-%m-%d %H:%M:%S') $1" | tee -a "$LOG_FILE" >&2 } # Function to log errors log_error() { - local msg="$(date '+%Y-%m-%d %H:%M:%S') ERROR: $1" - echo "$msg" | tee -a "$LOG_FILE" >&2 + echo "$(date '+%Y-%m-%d %H:%M:%S') ERROR: $1" | tee -a "$LOG_FILE" >&2 } # Function to log command output @@ -97,23 +101,85 @@ log_cmd() { local cmd="$1" local desc="$2" local output + local ret=0 - # Use eval to properly handle shell operators - output=$(eval "$cmd" 2>&1) || { - local ret=$? - log_error "Command failed with exit code $ret: $cmd" - echo "$output" | while IFS= read -r line; do - log " $line" - done - return $ret - } + output=$(eval "$cmd" 2>&1) || ret=$? if [ -n "$output" ]; then log "$desc:" - echo "$output" | while IFS= read -r line; do - log " $line" + printf '%s\n' "$output" | sed 's/^/ /' | while IFS= read -r line; do + log "$line" done fi + + [ $ret -eq 0 ] || log_error "Command failed with exit code $ret: $cmd" + return $ret +} + +# Get system UUID for unique VG naming +get_system_uuid() { + local uuid + + if ! uuid=$(dmidecode -s system-uuid 2>/dev/null); then + log_error "Failed to get system UUID" + exit 1 + fi + + # Just convert hyphens to underscores + echo "${uuid//-/_}" +} + +# Convert VG name back to UUID format +vg_name_to_uuid() { + local vg=$1 + # Just convert underscores back to hyphens + echo "$vg" | tr '_' '-' +} + +# Function to perform secure erase of NVMe device +secure_erase_nvme() { + local device=$1 + local ret=0 + local retry=3 + + log "Performing secure erase of NVMe device $device" + + if [[ ! "$device" =~ ^/dev/nvme[0-9]+n[0-9]+$ ]]; then + log_error "Device $device is not an NVMe device" + return 1 + fi + + # Check if device is mounted + if mountpoint -q "$device" || findmnt -n | grep -q "$device"; then + log_error "Device $device is mounted, cannot secure erase" + return 1 + fi + + # Attempt secure erase with retries + while [ $retry -gt 0 ]; do + log " Executing secure erase command (attempt $((4-retry))/3)" + if nvme format "$device" --namespace-id 1 --ses 1 --lbaf 0 --force 2>nvme.err; then + log " Success: Secure erase completed" + rm -f nvme.err + return 0 + fi + + # Check error type + if grep -q "Device or resource busy" nvme.err; then + log " Device busy, waiting before retry" + sleep 3 + else + log_error "Secure erase failed" + log " Details: $(cat nvme.err)" + rm -f nvme.err + return 1 + fi + + retry=$((retry - 1)) + done + + log_error "Failed to secure erase device after 3 attempts" + return 1 } # Function to check if running as root @@ -151,6 +217,13 @@ check_lvm_config() { return 0 fi + # Safety check - never touch system VGs + if is_system_vg "$vg_name"; then + log_error "Device $device is part of system VG: $vg_name" + log "Cannot modify system volume groups. Aborting." + exit 1 + fi + # Log VG details log_cmd "vgs --noheadings -o vg_name,vg_size,vg_free,pv_count $vg_name" "Volume group details" @@ -184,47 +257,185 @@ check_lvm_config() { exit 1 } -# Function to cleanup device -cleanup_device() { +# Function to check if VG is system critical +is_system_vg() { + local vg=$1 + local root_dev + local root_vg + local mp + local dev + + # First check if it's the current root VG + root_dev=$(findmnt -n -o SOURCE /) + if [ -n "$root_dev" ]; then + # Get VG name from root device + if lvs --noheadings -o vg_name "$root_dev" 2>/dev/null | grep -q "^$vg$"; then + return 0 # true + fi + fi + + # Check all mounted LVM devices + while read -r mp; do + # Skip our NSM mount + [ "$mp" = "$MOUNT_POINT" ] && continue + + # Check if mount uses this VG + if lvs --noheadings -o vg_name "$mp" 2>/dev/null | grep -q "^$vg$"; then + return 0 # true + fi + done < <(findmnt -n -o SOURCE -t ext4,xfs,btrfs,swap | grep "/dev/mapper/") + + # Check if VG contains any mounted devices + while read -r dev; do + if [ -n "$dev" ] && findmnt -n | grep -q "$dev"; then + return 0 # true + fi + done < <(lvs "/dev/$vg" --noheadings -o lv_path 2>/dev/null) + + # Check if VG contains critical LV names + if lvs "/dev/$vg" &>/dev/null; then + if lvs --noheadings -o lv_name "/dev/$vg" 2>/dev/null | grep -qE '^(root|swap|home|var|usr|tmp|opt|srv|boot)$'; then + return 0 # true + fi + fi + + # Check if VG has common system names + if [[ "$vg" =~ ^(vg_main|system|root|os|rhel|centos|ubuntu|debian|fedora)$ ]]; then + return 0 # true + fi + + return 1 # false +} + +# Function to deactivate LVM on device +deactivate_lvm() { local device=$1 + local vg=$2 + local ret=0 + local retry=3 - log "Cleaning up device $device" - - # Check if device is mounted - if mountpoint -q "$device"; then - log " Device is mounted, attempting unmount" - if ! umount "$device" 2>/dev/null; then - log_error "Failed to unmount device" - return 1 - fi - fi - - # Remove LVM configs if they exist - if pvs "$device" &>/dev/null; then - local vg=$(pvs --noheadings -o vg_name "$device" | tr -d ' ') - if [[ -n "$vg" && "$vg" != "$VG_NAME" ]]; then - log " Removing device from volume group $vg" - if ! vgreduce "$vg" "$device" 2>/dev/null; then - log_error "Failed to remove from volume group" - return 1 - fi - fi - log " Removing physical volume" - if ! pvremove -ff -y "$device" 2>/dev/null; then - log_error "Failed to remove physical volume" - return 1 - fi - fi - - # Remove partitions and signatures - log " Removing partitions and signatures" - if ! wipefs -a "$device" 2>/dev/null; then - log_error "Failed to remove signatures" + # Safety check - never touch system VGs + if is_system_vg "$vg"; then + log_error "Refusing to deactivate system VG: $vg" return 1 fi - log " Device cleanup successful" - return 0 + log " Deactivating LVM on device $device (VG: $vg)" + + # Get list of LVs that specifically use this device + local lvs_to_deactivate + lvs_to_deactivate=$(pvs --noheadings -o vg_name,lv_name "$device" 2>/dev/null | awk '{print $1"/"$2}') + + # Deactivate only LVs that use this device + if [ -n "$lvs_to_deactivate" ]; then + log " Deactivating logical volumes on device" + while read -r lv; do + if [ -n "$lv" ]; then + log " Deactivating: $lv" + if ! lvchange -an "/dev/$lv" 2>/dev/null; then + log " WARNING: Failed to deactivate $lv" + fi + fi + done <<< "$lvs_to_deactivate" + fi + + # Give it a moment to settle + sleep 2 + + # Try to reduce VG with retries + log " Removing device from volume group $vg" + while [ $retry -gt 0 ]; do + if vgreduce -f "$vg" "$device" 2>/dev/null; then + break + fi + log " WARNING: Failed to remove from VG, retrying... ($retry attempts left)" + retry=$((retry - 1)) + sleep 2 + done + + # If retries failed, try force removal + if [ $retry -eq 0 ]; then + log " WARNING: Failed normal removal, attempting forced cleanup" + if ! vgreduce --removemissing --force "$vg" 2>/dev/null; then + log_error "Failed to remove device from VG even with force" + ret=1 + fi + fi + + # Only remove PV if device is fully removed from VG + if ! pvs --noheadings -o vg_name "$device" | grep -q "[A-Za-z0-9]"; then + log " Removing physical volume" + if ! pvremove -ff -y "$device" 2>/dev/null; then + log_error "Failed to remove physical volume" + ret=1 + fi + else + log " WARNING: Device still part of VG, skipping PV removal" + fi + + return $ret +} + +# Function to cleanup device +cleanup_device() { + local device=$1 + local ret=0 + + log "Cleaning up device $device" + + # Check if device belongs to current system + if pvs "$device" &>/dev/null; then + local vg=$(pvs --noheadings -o vg_name "$device" | tr -d ' ') + local current_vg=$(get_system_uuid) + local vg_uuid="" + local current_uuid="" + + if [[ -n "$vg" ]]; then + # Convert VG names to UUIDs for comparison + vg_uuid=$(vg_name_to_uuid "$vg") + current_uuid=$(vg_name_to_uuid "$current_vg") + + if [[ "$vg_uuid" == "$current_uuid" ]]; then + log " Device belongs to current system, skipping secure erase" + else + log " Device belongs to different system (VG: $vg)" + + # First deactivate LVM + if ! deactivate_lvm "$device" "$vg"; then + log_error "Failed to fully deactivate LVM" + ret=1 + fi + + # Attempt secure erase even if LVM cleanup had issues + log " Performing secure erase" + if ! secure_erase_nvme "$device"; then + log_error "Failed to secure erase device" + ret=1 + fi + fi + fi + else + # No LVM configuration found, perform secure erase + log " No LVM configuration found, performing secure erase" + if ! secure_erase_nvme "$device"; then + log_error "Failed to secure erase device" + ret=1 + fi + fi + + # Always attempt to remove partitions and signatures + log " Removing partitions and signatures" + if ! wipefs -a "$device" 2>/dev/null; then + log_error "Failed to remove signatures" + ret=1 + fi + + if [ $ret -eq 0 ]; then + log " Device cleanup successful" + else + log_error "Device cleanup had some issues" + fi + return $ret } # Function to validate device state @@ -239,9 +450,21 @@ validate_device_state() { # Check if device is already properly configured if pvs "$device" &>/dev/null; then local vg=$(pvs --noheadings -o vg_name "$device" | tr -d ' ') - if [[ "$vg" == "$VG_NAME" ]]; then - if lvs "$VG_NAME/$LV_NAME" &>/dev/null; then - log "Device $device is already properly configured in VG $VG_NAME" + + # Safety check - never touch system VGs + if is_system_vg "$vg"; then + log_error "Device $device is part of system VG: $vg" + log "Cannot modify system volume groups. Aborting." + return 1 + fi + + # Convert VG names to UUIDs for comparison + local vg_uuid=$(vg_name_to_uuid "$vg") + local current_uuid=$(vg_name_to_uuid "$VG_NAME") + + if [[ "$vg_uuid" == "$current_uuid" ]]; then + if lvs "$vg/$LV_NAME" &>/dev/null; then + log "Device $device is already properly configured in VG $vg" return 0 fi fi @@ -249,6 +472,12 @@ validate_device_state() { # Check for existing partitions or LVM if pvs "$device" &>/dev/null || lsblk -no TYPE "$device" | grep -q "part"; then + # Check if device is mounted as root filesystem + if mountpoint -q / && findmnt -n -o SOURCE / | grep -q "$device"; then + log_error "Device $device contains root filesystem. Aborting." + return 1 + fi + log "Device $device has existing configuration" if ! cleanup_device "$device"; then log "Failed to cleanup device $device" @@ -314,9 +543,12 @@ detect_nvme_devices() { if validate_device_state "$dev"; then if pvs "$dev" &>/dev/null; then local vg=$(pvs --noheadings -o vg_name "$dev" | tr -d ' ') - if [[ "$vg" == "$VG_NAME" ]]; then + local vg_uuid=$(vg_name_to_uuid "$vg") + local current_uuid=$(vg_name_to_uuid "$VG_NAME") + + if [[ "$vg_uuid" == "$current_uuid" ]]; then configured_devices+=("$dev") - log "Status: Already configured in VG $VG_NAME" + log "Status: Already configured in VG $vg" else available_devices+=("$dev") log "Status: Available for use" @@ -531,7 +763,8 @@ setup_lvm() { log " Name: $LV_NAME" log " Size: 100% of free space" - if ! lvcreate -l 100%FREE -n "$LV_NAME" "$VG_NAME" 2>lv.err; then + # Create LV with yes flag + if ! lvcreate -l 100%FREE -n "$LV_NAME" "$VG_NAME" -y 2>lv.err; then log_error "Logical volume creation failed" log " Details: $(cat lv.err)" rm -f lv.err @@ -582,14 +815,18 @@ setup_filesystem() { fs_type=$(blkid -o value -s TYPE "$device" 2>/dev/null || echo "none") log " Current filesystem type: ${fs_type:-none}" - # Create XFS filesystem if needed + # Create XFS filesystem if needed log "Step 2: Filesystem preparation" if [[ "$fs_type" != "xfs" ]]; then log " Creating new XFS filesystem:" log " Device: $device" log " Options: -f (force)" - if ! mkfs.xfs -f "$device" 2>mkfs.err; then + # Clean any existing signatures first + wipefs -a "$device" 2>/dev/null || true + + # Create filesystem with force flag + if ! mkfs.xfs -f "$device" -K -q 2>mkfs.err; then log_error "XFS filesystem creation failed" log " Details: $(cat mkfs.err)" rm -f mkfs.err @@ -689,6 +926,9 @@ setup_filesystem() { # Main function main() { check_root + + # Set VG_NAME based on system UUID + VG_NAME=$(get_system_uuid) # Check if already mounted if mountpoint -q "$MOUNT_POINT"; then From 65c5abfa88f403b7a0e699b5f328ae4179aab4fa Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Fri, 31 Jan 2025 16:15:46 -0500 Subject: [PATCH 115/315] add note regarding possible missing devices --- salt/storage/files/so-nsm-mount | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/salt/storage/files/so-nsm-mount b/salt/storage/files/so-nsm-mount index 63cb810ec..c4b9e2360 100644 --- a/salt/storage/files/so-nsm-mount +++ b/salt/storage/files/so-nsm-mount @@ -938,12 +938,24 @@ main() { exit 0 fi - # Log initial system state - log "Initial system state:" + # Log initial system state with context + log "----------------------------------------" + log "Checking initial system state" + log "NOTE: If any drives were previously used in another system, you may see" + log " warnings about missing devices or volume groups below. These warnings" + log " are normal and expected when reusing drives. They indicate the drive" + log " was part of a previous system's configuration and will be automatically" + log " cleaned up in the following steps." + log "----------------------------------------" + log_cmd "lsblk" "Block devices" log_cmd "pvs" "Physical volumes" log_cmd "vgs" "Volume groups" log_cmd "lvs" "Logical volumes" + + log "----------------------------------------" + log "Proceeding with cleanup of any previous configurations and setup for /nsm" + log "----------------------------------------" # Check if LVM is already configured if vgs "$VG_NAME" &>/dev/null && lvs "$VG_NAME/$LV_NAME" &>/dev/null; then From a3013ff85b8f4417898fa08f0ae21f2169b91940 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Fri, 31 Jan 2025 16:36:51 -0500 Subject: [PATCH 116/315] simplify the LVM deactivation process by removing unnecessary VG removal attempts --- salt/storage/files/so-nsm-mount | 39 ++------------------------------- 1 file changed, 2 insertions(+), 37 deletions(-) diff --git a/salt/storage/files/so-nsm-mount b/salt/storage/files/so-nsm-mount index c4b9e2360..24125fc40 100644 --- a/salt/storage/files/so-nsm-mount +++ b/salt/storage/files/so-nsm-mount @@ -311,8 +311,6 @@ is_system_vg() { deactivate_lvm() { local device=$1 local vg=$2 - local ret=0 - local retry=3 # Safety check - never touch system VGs if is_system_vg "$vg"; then @@ -339,41 +337,8 @@ deactivate_lvm() { done <<< "$lvs_to_deactivate" fi - # Give it a moment to settle - sleep 2 - - # Try to reduce VG with retries - log " Removing device from volume group $vg" - while [ $retry -gt 0 ]; do - if vgreduce -f "$vg" "$device" 2>/dev/null; then - break - fi - log " WARNING: Failed to remove from VG, retrying... ($retry attempts left)" - retry=$((retry - 1)) - sleep 2 - done - - # If retries failed, try force removal - if [ $retry -eq 0 ]; then - log " WARNING: Failed normal removal, attempting forced cleanup" - if ! vgreduce --removemissing --force "$vg" 2>/dev/null; then - log_error "Failed to remove device from VG even with force" - ret=1 - fi - fi - - # Only remove PV if device is fully removed from VG - if ! pvs --noheadings -o vg_name "$device" | grep -q "[A-Za-z0-9]"; then - log " Removing physical volume" - if ! pvremove -ff -y "$device" 2>/dev/null; then - log_error "Failed to remove physical volume" - ret=1 - fi - else - log " WARNING: Device still part of VG, skipping PV removal" - fi - - return $ret + # No need to attempt VG removal - secure erase will handle it + return 0 } # Function to cleanup device From c8e232c59862461aabc55ebc8e8175b73c6a179c Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Mon, 3 Feb 2025 12:20:34 -0500 Subject: [PATCH 117/315] cloudinit network config out of user-data. default 220G disk --- salt/_runners/setup_hypervisor.py | 35 +++++++++++++++++-------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/salt/_runners/setup_hypervisor.py b/salt/_runners/setup_hypervisor.py index 81dfd08f4..c51166133 100644 --- a/salt/_runners/setup_hypervisor.py +++ b/salt/_runners/setup_hypervisor.py @@ -10,8 +10,7 @@ # software that is protected by the license key." """ -TODO: Change default disk_size from 6G to 220G. this was set to speed up vm start during development - Remove passwd hash prior to release. used for development +TODO: Remove passwd hash prior to release. used for development This runner performs the initial setup required for hypervisor hosts in the Security Onion environment. It handles downloading the Oracle Linux KVM image, setting up SSH keys for secure communication, @@ -22,11 +21,11 @@ Usage: Options: vm_name: Name for the virtual machine (alphanumeric, hyphens, underscores) - disk_size: Size of the VM disk with unit (e.g., '6G', '300G') + disk_size: Size of the VM disk with unit (e.g., '220G', '300G') minion_id: Salt minion ID of the hypervisor (optional) Examples: - # Complete environment setup (default VM 'sool9' with 6G disk) + # Complete environment setup (default VM 'sool9' with 220G disk) salt-run setup_hypervisor.setup_environment # Setup with custom VM name and disk size @@ -325,7 +324,8 @@ def _check_vm_exists(vm_name: str) -> bool: vm_image, cidata_iso, os.path.join(vm_dir, 'meta-data'), - os.path.join(vm_dir, 'user-data') + os.path.join(vm_dir, 'user-data'), + os.path.join(vm_dir, 'network-data') ] exists = all(os.path.exists(f) for f in required_files) @@ -333,7 +333,7 @@ def _check_vm_exists(vm_name: str) -> bool: log.info("MAIN: VM %s already exists", vm_name) return exists -def setup_environment(vm_name: str = 'sool9', disk_size: str = '6G', minion_id: str = None): +def setup_environment(vm_name: str = 'sool9', disk_size: str = '220G', minion_id: str = None): """ Main entry point to set up the hypervisor environment. @@ -345,8 +345,8 @@ def setup_environment(vm_name: str = 'sool9', disk_size: str = '6G', minion_id: vm_name (str, optional): Name for the VM to create. Must contain only alphanumeric characters, hyphens, or underscores. Defaults to 'sool9'. - disk_size (str, optional): Size of the VM disk with unit (e.g., '6G', '300G'). - Must end with 'G' or 'M'. Defaults to '6G'. + disk_size (str, optional): Size of the VM disk with unit (e.g., '220G', '300G'). + Must end with 'G' or 'M'. Defaults to '220G'. minion_id (str, optional): Salt minion ID of the hypervisor. When provided, forces the hypervisor to apply its configuration via highstate after successful environment setup (image @@ -454,7 +454,7 @@ def setup_environment(vm_name: str = 'sool9', disk_size: str = '6G', minion_id: 'vm_result': vm_result } -def create_vm(vm_name: str, disk_size: str = '6G'): +def create_vm(vm_name: str, disk_size: str = '220G'): """ Creates a new virtual machine with cloud-init configuration. @@ -465,8 +465,8 @@ def create_vm(vm_name: str, disk_size: str = '6G'): Args: vm_name (str): Name for the VM. Must contain only alphanumeric characters, hyphens, or underscores. - disk_size (str): Size of the VM disk with unit (e.g., '6G', '300G'). - Must end with 'G' or 'M'. Defaults to '6G'. + disk_size (str): Size of the VM disk with unit (e.g., '220G', '300G'). + Must end with 'G' or 'M'. Defaults to '220G'. Returns: dict: A dictionary containing: @@ -558,6 +558,13 @@ local-hostname: {vm_name} with salt.utils.files.fopen(meta_data_path, 'w') as f: f.write(meta_data) + # Create network-data + network_data = """network: + config: disabled""" + network_data_path = os.path.join(vm_dir, 'network-data') + with salt.utils.files.fopen(network_data_path, 'w') as f: + f.write(network_data) + # Create user-data user_data = f"""#cloud-config preserve_hostname: False @@ -586,10 +593,6 @@ ssh_genkeytypes: ['ed25519', 'rsa'] # set timezone for VM timezone: UTC -# Disable cloud-init network configuration to prevent conflicts with NetworkManager -network: - config: disabled - write_files: - path: /etc/yum.repos.d/securityonion.repo content: | @@ -723,7 +726,7 @@ power_state: # Create cloud-init ISO cidata_iso = os.path.join(vm_dir, f'{vm_name}-cidata.iso') subprocess.run(['mkisofs', '-output', cidata_iso, '-volid', 'CIDATA', '-rock', - user_data_path, meta_data_path], + user_data_path, meta_data_path, network_data_path], check=True, capture_output=True) # Generate SHA256 hash of the qcow2 image From 71596783854915e5d9dad95e106f9b75f87cfa35 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Thu, 6 Feb 2025 15:30:46 -0500 Subject: [PATCH 118/315] create predicatble interfaces --- salt/_modules/qcow2.py | 8 +- .../tools/sbin/so-qcow2-modify-network | 193 ++++++++- .../tools/sbin/so-qcow2-network-predictable | 378 ++++++++++++++++++ salt/hypervisor/tools/sbin/so-wait-cloud-init | 206 ++++++++++ salt/libvirt/images/init.sls | 17 +- salt/manager/tools/sbin/so-salt-cloud | 2 +- .../cloud/cloud.profiles.d/socloud.conf.jinja | 2 +- salt/setup/virt/fleet.yaml | 2 +- salt/setup/virt/heavynode.yaml | 2 +- salt/setup/virt/idh.yaml | 2 +- salt/setup/virt/receiver.yaml | 2 +- salt/setup/virt/searchnode.yaml | 2 +- salt/setup/virt/sensor.yaml | 2 +- 13 files changed, 792 insertions(+), 26 deletions(-) create mode 100644 salt/hypervisor/tools/sbin/so-qcow2-network-predictable create mode 100644 salt/hypervisor/tools/sbin/so-wait-cloud-init diff --git a/salt/_modules/qcow2.py b/salt/_modules/qcow2.py index d1de6756a..81a00ca66 100644 --- a/salt/_modules/qcow2.py +++ b/salt/_modules/qcow2.py @@ -38,7 +38,7 @@ def modify_network_config(image, interface, mode, ip4=None, gw4=None, dns4=None, image Path to the QCOW2 image file that will be modified interface - Network interface name to configure (e.g., 'eth0') + Network interface name to configure (e.g., 'enp1s0') mode Network configuration mode, either 'dhcp4' or 'static4' ip4 @@ -57,13 +57,13 @@ def modify_network_config(image, interface, mode, ip4=None, gw4=None, dns4=None, Examples: 1. **Configure DHCP:** ```bash - salt '*' qcow2.modify_network_config image='/nsm/libvirt/images/sool9/sool9.qcow2' interface='eth0' mode='dhcp4' + salt '*' qcow2.modify_network_config image='/nsm/libvirt/images/sool9/sool9.qcow2' interface='enp1s0' mode='dhcp4' ``` - This configures eth0 to use DHCP for IP assignment + This configures enp1s0 to use DHCP for IP assignment 2. **Configure Static IP:** ```bash - salt '*' qcow2.modify_network_config image='/nsm/libvirt/images/sool9/sool9.qcow2' interface='eth0' mode='static4' ip4='192.168.1.10/24' gw4='192.168.1.1' dns4='192.168.1.1,8.8.8.8' search4='example.local' + salt '*' qcow2.modify_network_config image='/nsm/libvirt/images/sool9/sool9.qcow2' interface='enp1s0' mode='static4' ip4='192.168.1.10/24' gw4='192.168.1.1' dns4='192.168.1.1,8.8.8.8' search4='example.local' ``` This sets a static IP configuration with DNS servers and search domain diff --git a/salt/hypervisor/tools/sbin/so-qcow2-modify-network b/salt/hypervisor/tools/sbin/so-qcow2-modify-network index 5c0a9e9b7..5f0690542 100644 --- a/salt/hypervisor/tools/sbin/so-qcow2-modify-network +++ b/salt/hypervisor/tools/sbin/so-qcow2-modify-network @@ -14,6 +14,13 @@ The script offers two main configuration modes: 1. DHCP Configuration: Enable automatic IP address assignment 2. Static IP Configuration: Set specific IP address, gateway, DNS servers, and search domains +For both configuration modes, the script automatically sets the following NetworkManager connection properties: +- connection.autoconnect: yes (ensures interface connects automatically) +- connection.autoconnect-priority: 999 (sets connection priority) +- connection.autoconnect-retries: -1 (unlimited connection retries) +- connection.multi-connect: 0 (single connection mode) +- connection.wait-device-timeout: -1 (wait indefinitely for device) + This script is designed to work with Security Onion's virtualization infrastructure and is typically used during VM provisioning and network reconfiguration tasks. @@ -23,7 +30,7 @@ used during VM provisioning and network reconfiguration tasks. **Options:** -I, --image Path to the QCOW2 image. - -i, --interface Network interface to modify (e.g., eth0). + -i, --interface Network interface to modify (e.g., enp1s0). --dhcp4 Configure interface for DHCP (IPv4). --static4 Configure interface for static IPv4 settings. --ip4 IPv4 address (e.g., 192.168.1.10/24). Required for static IPv4 configuration. @@ -36,7 +43,7 @@ used during VM provisioning and network reconfiguration tasks. 1. **Static IP Configuration with DNS and Search Domain:** ```bash - so-qcow2-modify-network -I /nsm/libvirt/images/sool9/sool9.qcow2 -i eth0 --static4 \ + so-qcow2-modify-network -I /nsm/libvirt/images/sool9/sool9.qcow2 -i enp1s0 --static4 \ --ip4 192.168.1.10/24 --gw4 192.168.1.1 --dns4 192.168.1.1,192.168.1.2 --search4 example.local ``` @@ -50,7 +57,7 @@ used during VM provisioning and network reconfiguration tasks. 2. **DHCP Configuration:** ```bash - so-qcow2-modify-network -I /nsm/libvirt/images/sool9/sool9.qcow2 -i eth0 --dhcp4 + so-qcow2-modify-network -I /nsm/libvirt/images/sool9/sool9.qcow2 -i enp1s0 --dhcp4 ``` This command configures the network interface to use DHCP for automatic IP address assignment. @@ -58,7 +65,7 @@ used during VM provisioning and network reconfiguration tasks. 3. **Static IP Configuration without DNS Settings:** ```bash - so-qcow2-modify-network -I /nsm/libvirt/images/sool9/sool9.qcow2 -i eth0 --static4 \ + so-qcow2-modify-network -I /nsm/libvirt/images/sool9/sool9.qcow2 -i enp1s0 --static4 \ --ip4 192.168.1.20/24 --gw4 192.168.1.1 ``` @@ -122,7 +129,9 @@ import logging import os import ipaddress import configparser +import uuid from io import StringIO +import libvirt from so_logging_utils import setup_logging # Set up logging using the so_logging_utils library @@ -154,33 +163,91 @@ def validate_interface_name(interface_name): if not re.match(r'^[a-zA-Z0-9_\-]+$', interface_name): raise ValueError(f"Invalid interface name: {interface_name}") -def update_ipv4_section(content, mode, ip=None, gateway=None, dns=None, search_domain=None): +def check_base_domain_status(image_path): + """ + Check if the base domain corresponding to the image path is currently running. + Base domains should not be running when modifying their configuration. + + Parameters: + image_path (str): Path to the QCOW2 image. + + Returns: + bool: True if the base domain is running, False otherwise. + """ + base_domain = os.path.basename(os.path.dirname(image_path)) + logger.info(f"Verifying base domain status for image: {image_path}") + logger.info(f"Checking if base domain '{base_domain}' is running...") + + try: + conn = libvirt.open('qemu:///system') + try: + dom = conn.lookupByName(base_domain) + is_running = dom.isActive() + if is_running: + logger.error(f"Base domain '{base_domain}' is running - cannot modify configuration") + return is_running + except libvirt.libvirtError: + logger.info(f"Base domain '{base_domain}' not found or not running") + return False + finally: + conn.close() + except libvirt.libvirtError as e: + logger.error(f"Failed to connect to libvirt: {e}") + return False + +def update_network_config(content, mode, ip=None, gateway=None, dns=None, search_domain=None): config = configparser.ConfigParser(strict=False) config.optionxform = str config.read_string(content) + # Ensure connection section exists and set required properties + if 'connection' not in config.sections(): + logger.info("Creating new connection section in network configuration") + config.add_section('connection') + + # Set mandatory connection properties + config.set('connection', 'autoconnect', 'yes') + config.set('connection', 'autoconnect-priority', '999') + config.set('connection', 'autoconnect-retries', '-1') + config.set('connection', 'multi-connect', '0') + config.set('connection', 'wait-device-timeout', '-1') + + # Ensure ipv4 section exists if 'ipv4' not in config.sections(): + logger.info("Creating new IPv4 section in network configuration") config.add_section('ipv4') if mode == "dhcp4": + logger.info("Configuring DHCP settings:") + logger.info(" method: auto (DHCP enabled)") + logger.info(" Removing any existing static configuration") config.set('ipv4', 'method', 'auto') config.remove_option('ipv4', 'address1') config.remove_option('ipv4', 'addresses') config.remove_option('ipv4', 'dns') config.remove_option('ipv4', 'dns-search') elif mode == "static4": + logger.info("Configuring static IP settings:") + logger.info(" method: manual (static configuration)") config.set('ipv4', 'method', 'manual') if ip and gateway: + logger.info(f" Setting address: {ip}") + logger.info(f" Setting gateway: {gateway}") config.set('ipv4', 'address1', f"{ip},{gateway}") else: + logger.error("Missing required IP address or gateway for static configuration") raise ValueError("Both IP address and gateway are required for static configuration.") if dns: + logger.info(f" Setting DNS servers: {dns}") config.set('ipv4', 'dns', f"{dns};") else: + logger.info(" No DNS servers specified") config.remove_option('ipv4', 'dns') if search_domain: + logger.info(f" Setting search domain: {search_domain}") config.set('ipv4', 'dns-search', f"{search_domain};") else: + logger.info(" No search domain specified") config.remove_option('ipv4', 'dns-search') else: raise ValueError(f"Invalid mode '{mode}'. Expected 'dhcp4' or 'static4'.") @@ -193,50 +260,138 @@ def update_ipv4_section(content, mode, ip=None, gateway=None, dns=None, search_d return updated_content def modify_network_config(image_path, interface, mode, ip=None, gateway=None, dns=None, search_domain=None): + """ + Modifies network configuration in a QCOW2 image, ensuring specific connection settings are set. + + Handles both eth0 and predictable network interface names (e.g., enp1s0). + If the requested interface configuration is not found but eth0.nmconnection exists, + it will be renamed and updated with the proper interface configuration. + """ + # Check if base domain is running + if check_base_domain_status(image_path): + raise RuntimeError("Cannot modify network configuration while base domain is running") + if not os.access(image_path, os.W_OK): + logger.error(f"Permission denied: Cannot write to image file {image_path}") raise PermissionError(f"Write permission denied for image file: {image_path}") + logger.info(f"Configuring network for VM image: {image_path}") + logger.info(f"Network configuration details for interface {interface}:") + logger.info(f" Mode: {mode.upper()}") + if mode == "static4": + logger.info(f" IP Address: {ip}") + logger.info(f" Gateway: {gateway}") + logger.info(f" DNS Servers: {dns if dns else 'Not configured'}") + logger.info(f" Search Domain: {search_domain if search_domain else 'Not configured'}") + g = guestfs.GuestFS(python_return_dict=True) try: + logger.info("Initializing GuestFS and mounting image...") g.set_network(False) g.selinux = False g.add_drive_opts(image_path, format="qcow2") g.launch() except RuntimeError as e: + logger.error(f"Failed to initialize GuestFS: {e}") raise RuntimeError(f"Failed to initialize GuestFS or launch appliance: {e}") try: os_list = g.inspect_os() if not os_list: + logger.error(f"No operating system found in image: {image_path}") raise RuntimeError(f"Unable to find any OS in {image_path}.") root_fs = os_list[0] try: g.mount(root_fs, "/") + logger.info("Successfully mounted VM image filesystem") except RuntimeError as e: + logger.error(f"Failed to mount filesystem: {e}") raise RuntimeError(f"Failed to mount the filesystem: {e}") if not g.is_dir(NETWORK_CONFIG_DIR): + logger.error(f"NetworkManager configuration directory not found: {NETWORK_CONFIG_DIR}") raise FileNotFoundError(f"NetworkManager configuration directory not found in the image at {NETWORK_CONFIG_DIR}.") - config_file_path = f"{NETWORK_CONFIG_DIR}/{interface}.nmconnection" + requested_config_path = f"{NETWORK_CONFIG_DIR}/{interface}.nmconnection" + eth0_config_path = f"{NETWORK_CONFIG_DIR}/eth0.nmconnection" + config_file_path = None + current_content = None + # Try to read the requested interface config first try: - file_content = g.read_file(config_file_path) + file_content = g.read_file(requested_config_path) current_content = file_content.decode('utf-8') + config_file_path = requested_config_path + logger.info(f"Found existing network configuration for interface {interface}") except RuntimeError: - raise FileNotFoundError(f"Configuration file for {interface} not found at {config_file_path}.") + # If not found, try eth0 config + try: + file_content = g.read_file(eth0_config_path) + current_content = file_content.decode('utf-8') + config_file_path = eth0_config_path + logger.info("Found eth0 network configuration, will update for new interface") + except RuntimeError: + logger.error(f"No network configuration found for either {interface} or eth0") + raise FileNotFoundError(f"No network configuration found at {requested_config_path} or {eth0_config_path}") except UnicodeDecodeError: - raise ValueError(f"Failed to decode the configuration file for {interface}.") + logger.error(f"Failed to decode network configuration file") + raise ValueError(f"Failed to decode the configuration file") - updated_content = update_ipv4_section(current_content, mode, ip, gateway, dns, search_domain) + # If using eth0 config, update interface-specific fields + if config_file_path == eth0_config_path: + config = configparser.ConfigParser(strict=False) + config.optionxform = str + config.read_string(current_content) + + if 'connection' not in config.sections(): + config.add_section('connection') + + # Update interface-specific fields + config.set('connection', 'id', interface) + config.set('connection', 'interface-name', interface) + config.set('connection', 'uuid', str(uuid.uuid4())) + + # Write updated content back to string + output = StringIO() + config.write(output, space_around_delimiters=False) + current_content = output.getvalue() + output.close() + + # Update config file path to new interface name + config_file_path = requested_config_path + + logger.info("Applying network configuration changes...") + updated_content = update_network_config(current_content, mode, ip, gateway, dns, search_domain) try: g.write(config_file_path, updated_content.encode('utf-8')) + # Set proper permissions (600) on the network configuration file + g.chmod(0o600, config_file_path) + logger.info("Successfully wrote updated network configuration with proper permissions (600)") + + # If we renamed eth0 to the new interface, remove the old eth0 config + if config_file_path == requested_config_path and eth0_config_path != requested_config_path: + try: + g.rm(eth0_config_path) + logger.info("Removed old eth0 configuration file") + except RuntimeError: + logger.warning("Could not remove old eth0 configuration file - it may have already been removed") + except RuntimeError as e: + logger.error(f"Failed to write network configuration: {e}") raise IOError(f"Failed to write updated configuration to {config_file_path}: {e}") - logger.info(f"Updated {interface} network configuration in {image_path} using {mode.upper()} mode.") + logger.info(f"Successfully updated network configuration:") + logger.info(f" Image: {image_path}") + logger.info(f" Interface: {interface}") + logger.info(f" Mode: {mode.upper()}") + if mode == "static4": + logger.info(f" Settings applied:") + logger.info(f" IP Address: {ip}") + logger.info(f" Gateway: {gateway}") + logger.info(f" DNS Servers: {dns if dns else 'Not configured'}") + logger.info(f" Search Domain: {search_domain if search_domain else 'Not configured'}") except Exception as e: raise e @@ -247,7 +402,7 @@ def modify_network_config(image_path, interface, mode, ip=None, gateway=None, dn def parse_arguments(): parser = argparse.ArgumentParser(description="Modify IPv4 settings in a QCOW2 image for a specified network interface.") parser.add_argument("-I", "--image", required=True, help="Path to the QCOW2 image.") - parser.add_argument("-i", "--interface", required=True, help="Network interface to modify (e.g., eth0).") + parser.add_argument("-i", "--interface", required=True, help="Network interface to modify (e.g., enp1s0).") group = parser.add_mutually_exclusive_group(required=True) group.add_argument("--dhcp4", action="store_true", help="Configure interface for DHCP (IPv4).") group.add_argument("--static4", action="store_true", help="Configure interface for static IPv4 settings.") @@ -265,30 +420,42 @@ def parse_arguments(): def main(): try: + logger.info("Starting network configuration update...") args = parse_arguments() + logger.info("Validating interface name...") validate_interface_name(args.interface) if args.dhcp4: mode = "dhcp4" + logger.info("Using DHCP configuration mode") elif args.static4: mode = "static4" + logger.info("Using static IP configuration mode") if not args.ip4 or not args.gw4: + logger.error("Missing required parameters for static configuration") raise ValueError("Both --ip4 and --gw4 are required for static IPv4 configuration.") + + logger.info("Validating IP addresses...") validate_ip_address(args.ip4, description="IPv4 address") validate_ip_address(args.gw4, description="IPv4 gateway") if args.dns4: validate_dns_addresses(args.dns4) else: + logger.error("No configuration mode specified") raise ValueError("Either --dhcp4 or --static4 must be specified.") modify_network_config(args.image, args.interface, mode, args.ip4, args.gw4, args.dns4, args.search4) + logger.info("Network configuration update completed successfully") except KeyboardInterrupt: logger.error("Operation cancelled by user.") sys.exit(1) except Exception as e: - logger.error(f"An error occurred: {e}") + if "base domain is running" in str(e): + logger.error("Cannot proceed: Base domain must not be running when modifying network configuration") + else: + logger.error(f"An error occurred: {e}") sys.exit(1) if __name__ == "__main__": diff --git a/salt/hypervisor/tools/sbin/so-qcow2-network-predictable b/salt/hypervisor/tools/sbin/so-qcow2-network-predictable new file mode 100644 index 000000000..9b09465b9 --- /dev/null +++ b/salt/hypervisor/tools/sbin/so-qcow2-network-predictable @@ -0,0 +1,378 @@ +#!/usr/bin/python3 + +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +""" +Script for configuring network interface predictability in Security Onion VMs. +This script modifies the necessary files to ensure consistent network interface naming. + +The script performs the following operations: +1. Modifies the BLS entry to set net.ifnames=1 +2. Removes any existing persistent network rules +3. Updates GRUB configuration + +**Usage:** + so-qcow2-network-predictable -n [-I ] + +**Options:** + -n, --name Domain name of the VM to configure + -I, --image (Optional) Path to the QCOW2 image. If not provided, + defaults to /nsm/libvirt/images//.qcow2 + +**Examples:** + +1. **Configure using domain name:** + ```bash + so-qcow2-network-predictable -n sool9 + ``` + This command will: + - Use default image path: /nsm/libvirt/images/sool9/sool9.qcow2 + - Configure network interface predictability + +2. **Configure using custom image path:** + ```bash + so-qcow2-network-predictable -n sool9 -I /path/to/custom/image.qcow2 + ``` + This command will: + - Use the specified image path + - Configure network interface predictability + +**Notes:** +- The VM must not be running when executing this script +- Requires root privileges +- Will automatically find and modify the appropriate BLS entry +- Removes /etc/udev/rules.d/70-persistent-net.rules if it exists +- Updates GRUB configuration after changes + +**Exit Codes:** +- 0: Success +- 1: General error (invalid arguments, file operations, etc.) +- 2: VM is running +- 3: Required files not found +- 4: Permission denied + +**Logging:** +- Logs are written to /opt/so/log/hypervisor/so-qcow2-network-predictable.log +- Both file and console logging are enabled +- Log entries include: + - Timestamps + - Operation details + - Error messages + - Configuration changes +""" + +import argparse +import guestfs +import glob +import libvirt +import logging +import os +import re +import sys +from so_logging_utils import setup_logging + +# Set up logging +logger = setup_logging( + logger_name='so-qcow2-network-predictable', + log_file_path='/opt/so/log/hypervisor/so-qcow2-network-predictable.log', + log_level=logging.INFO, + format_str='%(asctime)s - %(levelname)s - %(message)s' +) + +def check_domain_status(domain_name): + """ + Check if the specified domain exists and is not running. + + Args: + domain_name (str): Name of the libvirt domain to check + + Returns: + bool: True if domain exists and is not running, False otherwise + + Raises: + RuntimeError: If domain is running or connection to libvirt fails + """ + try: + conn = libvirt.open('qemu:///system') + try: + dom = conn.lookupByName(domain_name) + is_running = dom.isActive() + if is_running: + logger.error(f"Domain '{domain_name}' is running - cannot modify configuration") + raise RuntimeError(f"Domain '{domain_name}' must not be running") + logger.info(f"Domain '{domain_name}' exists and is not running") + return True + except libvirt.libvirtError as e: + if "no domain with matching name" in str(e): + logger.error(f"Domain '{domain_name}' not found") + raise RuntimeError(f"Domain '{domain_name}' not found") + raise + finally: + conn.close() + except libvirt.libvirtError as e: + logger.error(f"Failed to connect to libvirt: {e}") + raise RuntimeError(f"Failed to connect to libvirt: {e}") + +def modify_bls_entry(g): + """ + Find and modify the BLS entry to set net.ifnames=1. + + Args: + g: Mounted guestfs handle + + Returns: + bool: True if successful, False if no changes needed + + Raises: + RuntimeError: If BLS entry cannot be found or modified + """ + bls_dir = "/boot/loader/entries" + logger.info(f"Checking BLS directory: {bls_dir}") + if g.is_dir(bls_dir): + logger.info("BLS directory exists") + else: + logger.info("Listing /boot contents:") + try: + boot_contents = g.ls("/boot") + logger.info(f"/boot contains: {boot_contents}") + if g.is_dir("/boot/loader"): + logger.info("Listing /boot/loader contents:") + loader_contents = g.ls("/boot/loader") + logger.info(f"/boot/loader contains: {loader_contents}") + except Exception as e: + logger.error(f"Error listing /boot contents: {e}") + raise RuntimeError(f"BLS directory not found: {bls_dir}") + + # Find BLS entry file + entries = g.glob_expand(f"{bls_dir}/*.conf") + logger.info(f"Found BLS entries: {entries}") + if not entries: + logger.error("No BLS entry files found") + raise RuntimeError("No BLS entry files found") + + # Use the first entry found + bls_file = entries[0] + logger.info(f"Found BLS entry file: {bls_file}") + + try: + logger.info(f"Reading BLS file contents from: {bls_file}") + content = g.read_file(bls_file).decode('utf-8') + logger.info("Current BLS file content:") + logger.info("---BEGIN BLS CONTENT---") + logger.info(content) + logger.info("---END BLS CONTENT---") + + lines = content.splitlines() + modified = False + + for i, line in enumerate(lines): + if line.startswith('options '): + logger.info(f"Found options line: {line}") + # Check if net.ifnames parameter exists + if 'net.ifnames=' in line: + # Replace existing parameter + new_line = re.sub(r'net\.ifnames=[01]', 'net.ifnames=1', line) + if new_line != line: + lines[i] = new_line + modified = True + logger.info(f"Updated existing net.ifnames parameter to 1. New line: {new_line}") + else: + # Add parameter + lines[i] = f"{line} net.ifnames=1" + modified = True + logger.info(f"Added net.ifnames=1 parameter. New line: {lines[i]}") + break + + if modified: + new_content = '\n'.join(lines) + '\n' + logger.info("New BLS file content:") + logger.info("---BEGIN NEW BLS CONTENT---") + logger.info(new_content) + logger.info("---END NEW BLS CONTENT---") + g.write(bls_file, new_content.encode('utf-8')) + logger.info("Successfully updated BLS entry") + return True + + logger.info("No changes needed for BLS entry") + return False + + except Exception as e: + logger.error(f"Failed to modify BLS entry: {e}") + raise RuntimeError(f"Failed to modify BLS entry: {e}") + +def remove_persistent_net_rules(g): + """ + Remove the persistent network rules file if it exists. + + Args: + g: Mounted guestfs handle + + Returns: + bool: True if file was removed, False if it didn't exist + """ + rules_file = "/etc/udev/rules.d/70-persistent-net.rules" + logger.info(f"Checking for persistent network rules file: {rules_file}") + try: + if g.is_file(rules_file): + logger.info("Found persistent network rules file, removing...") + g.rm(rules_file) + logger.info(f"Successfully removed persistent network rules file: {rules_file}") + return True + logger.info("No persistent network rules file found") + return False + except Exception as e: + logger.error(f"Failed to remove persistent network rules: {e}") + raise RuntimeError(f"Failed to remove persistent network rules: {e}") + +def update_grub_config(g): + """ + Update GRUB configuration. + + Args: + g: Mounted guestfs handle + + Raises: + RuntimeError: If GRUB update fails + """ + try: + logger.info("Updating GRUB configuration...") + output = g.command(['grub2-mkconfig', '-o', '/boot/grub2/grub.cfg']) + logger.info("GRUB update output:") + logger.info(output) + logger.info("Successfully updated GRUB configuration") + except Exception as e: + logger.error(f"Failed to update GRUB configuration: {e}") + raise RuntimeError(f"Failed to update GRUB configuration: {e}") + +def configure_network_predictability(domain_name, image_path=None): + """ + Configure network interface predictability for a VM. + + Args: + domain_name (str): Name of the domain to configure + image_path (str, optional): Path to the QCOW2 image + + Raises: + RuntimeError: If configuration fails + """ + # Check domain status + check_domain_status(domain_name) + + # Use default image path if none provided + if not image_path: + image_path = f"/nsm/libvirt/images/{domain_name}/{domain_name}.qcow2" + + if not os.path.exists(image_path): + logger.error(f"Image file not found: {image_path}") + raise RuntimeError(f"Image file not found: {image_path}") + + if not os.access(image_path, os.R_OK | os.W_OK): + logger.error(f"Permission denied: Cannot access image file {image_path}") + raise RuntimeError(f"Permission denied: Cannot access image file {image_path}") + + logger.info(f"Configuring network predictability for domain: {domain_name}") + logger.info(f"Using image: {image_path}") + + g = guestfs.GuestFS(python_return_dict=True) + try: + logger.info("Initializing guestfs...") + g.set_network(False) + g.selinux = False + g.add_drive_opts(image_path, format="qcow2") + g.launch() + + logger.info("Inspecting operating system...") + roots = g.inspect_os() + if not roots: + raise RuntimeError("No operating system found in image") + + root = roots[0] + logger.info(f"Found root filesystem: {root}") + logger.info(f"Operating system type: {g.inspect_get_type(root)}") + logger.info(f"Operating system distro: {g.inspect_get_distro(root)}") + logger.info(f"Operating system major version: {g.inspect_get_major_version(root)}") + logger.info(f"Operating system minor version: {g.inspect_get_minor_version(root)}") + + logger.info("Getting mount points...") + mountpoints = g.inspect_get_mountpoints(root) + logger.info(f"Found mount points: {mountpoints}") + logger.info("Converting mount points to sortable list...") + # Convert dictionary to list of tuples + mountpoints = list(mountpoints.items()) + logger.info(f"Converted mount points: {mountpoints}") + logger.info("Sorting mount points by path length for proper mount order...") + mountpoints.sort(key=lambda m: len(m[0])) + logger.info(f"Mount order will be: {[mp[0] for mp in mountpoints]}") + + for mp_path, mp_device in mountpoints: + try: + logger.info(f"Attempting to mount {mp_device} at {mp_path}") + g.mount(mp_device, mp_path) + logger.info(f"Successfully mounted {mp_device} at {mp_path}") + except Exception as e: + logger.warning(f"Could not mount {mp_device} at {mp_path}: {str(e)}") + # Continue with other mounts + + # Perform configuration steps + bls_modified = modify_bls_entry(g) + rules_removed = remove_persistent_net_rules(g) + + if bls_modified or rules_removed: + update_grub_config(g) + logger.info("Network predictability configuration completed successfully") + else: + logger.info("No changes were necessary") + + except Exception as e: + raise RuntimeError(f"Failed to configure network predictability: {e}") + finally: + try: + logger.info("Unmounting all filesystems...") + g.umount_all() + logger.info("Successfully unmounted all filesystems") + except Exception as e: + logger.warning(f"Error unmounting filesystems: {e}") + g.close() + +def parse_arguments(): + """Parse command line arguments.""" + parser = argparse.ArgumentParser( + description="Configure network interface predictability for Security Onion VMs" + ) + parser.add_argument("-n", "--name", required=True, + help="Domain name of the VM to configure") + parser.add_argument("-I", "--image", + help="Path to the QCOW2 image (optional)") + return parser.parse_args() + +def main(): + """Main entry point for the script.""" + try: + args = parse_arguments() + configure_network_predictability(args.name, args.image) + sys.exit(0) + except RuntimeError as e: + if "must not be running" in str(e): + logger.error(str(e)) + sys.exit(2) + elif "not found" in str(e): + logger.error(str(e)) + sys.exit(3) + elif "Permission denied" in str(e): + logger.error(str(e)) + sys.exit(4) + else: + logger.error(str(e)) + sys.exit(1) + except KeyboardInterrupt: + logger.error("Operation cancelled by user") + sys.exit(1) + except Exception as e: + logger.error(f"Unexpected error: {e}") + sys.exit(1) + +if __name__ == "__main__": + main() diff --git a/salt/hypervisor/tools/sbin/so-wait-cloud-init b/salt/hypervisor/tools/sbin/so-wait-cloud-init new file mode 100644 index 000000000..322b89208 --- /dev/null +++ b/salt/hypervisor/tools/sbin/so-wait-cloud-init @@ -0,0 +1,206 @@ +#!/usr/bin/python3 + +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +""" +Script for waiting for cloud-init to complete on a Security Onion VM. +Monitors VM state to ensure proper cloud-init initialization and shutdown. + +**Usage:** + so-wait-cloud-init -n + +**Options:** + -n, --name Domain name of the VM to monitor + +**Exit Codes:** +- 0: Success (cloud-init completed and VM shutdown) +- 1: General error +- 2: VM never started +- 3: VM stopped too quickly +- 4: VM failed to shutdown + +**Description:** +This script monitors a VM's state to ensure proper cloud-init initialization and completion: +1. Waits for VM to start running +2. Verifies VM remains running (not an immediate crash) +3. Waits for VM to shutdown (indicating cloud-init completion) +4. Verifies VM remains shutdown + +The script is typically used in the libvirt.images state after creating a new VM +to ensure cloud-init completes its initialization before proceeding with further +configuration. + +**Logging:** +- Logs are written to /opt/so/log/hypervisor/so-wait-cloud-init.log +- Both file and console logging are enabled +- Log entries include: + - Timestamps + - State changes + - Error conditions + - Verification steps +""" + +import argparse +import logging +import subprocess +import sys +import time +from so_logging_utils import setup_logging + +# Set up logging +logger = setup_logging( + logger_name='so-wait-cloud-init', + log_file_path='/opt/so/log/hypervisor/so-wait-cloud-init.log', + log_level=logging.INFO, + format_str='%(asctime)s - %(levelname)s - %(message)s' +) + +def check_vm_running(domain_name): + """ + Check if VM is in running state. + + Args: + domain_name (str): Name of the domain to check + + Returns: + bool: True if VM is running, False otherwise + """ + try: + result = subprocess.run(['virsh', 'list', '--state-running', '--name'], + capture_output=True, text=True, check=True) + return domain_name in result.stdout.splitlines() + except subprocess.CalledProcessError as e: + logger.error(f"Failed to check VM state: {e}") + return False + +def wait_for_vm_start(domain_name, timeout=300): + """ + Wait for VM to start running. + + Args: + domain_name (str): Name of the domain to monitor + timeout (int): Maximum time to wait in seconds + + Returns: + bool: True if VM started, False if timeout occurred + """ + logger.info(f"Waiting for VM {domain_name} to start...") + start_time = time.time() + + while time.time() - start_time < timeout: + if check_vm_running(domain_name): + logger.info("VM is running") + return True + time.sleep(1) + + logger.error(f"Timeout waiting for VM {domain_name} to start") + return False + +def verify_vm_running(domain_name): + """ + Verify VM remains running after initial start. + + Args: + domain_name (str): Name of the domain to verify + + Returns: + bool: True if VM is still running after verification period + """ + logger.info("Verifying VM remains running...") + time.sleep(5) # Wait to ensure VM is stable + + if not check_vm_running(domain_name): + logger.error("VM stopped too quickly after starting") + return False + + logger.info("VM verified running") + return True + +def wait_for_vm_shutdown(domain_name, timeout=600): + """ + Wait for VM to shutdown. + + Args: + domain_name (str): Name of the domain to monitor + timeout (int): Maximum time to wait in seconds + + Returns: + bool: True if VM shutdown, False if timeout occurred + """ + logger.info("Waiting for cloud-init to complete and VM to shutdown...") + start_time = time.time() + check_count = 0 + + while time.time() - start_time < timeout: + if not check_vm_running(domain_name): + logger.info("VM has shutdown") + return True + + # Log status every minute (after 12 checks at 5 second intervals) + check_count += 1 + if check_count % 12 == 0: + elapsed = int(time.time() - start_time) + logger.info(f"Still waiting for cloud-init... ({elapsed} seconds elapsed)") + + time.sleep(5) + + logger.error(f"Timeout waiting for VM {domain_name} to shutdown") + return False + +def verify_vm_shutdown(domain_name): + """ + Verify VM remains shutdown. + + Args: + domain_name (str): Name of the domain to verify + + Returns: + bool: True if VM remains shutdown after verification period + """ + logger.info("Verifying VM remains shutdown...") + time.sleep(5) # Wait to ensure VM state is stable + + if check_vm_running(domain_name): + logger.error("VM is still running after shutdown check") + return False + + logger.info("VM verified shutdown") + return True + +def main(): + parser = argparse.ArgumentParser( + description="Wait for cloud-init to complete on a Security Onion VM" + ) + parser.add_argument("-n", "--name", required=True, + help="Domain name of the VM to monitor") + args = parser.parse_args() + + try: + # Wait for VM to start + if not wait_for_vm_start(args.name): + sys.exit(2) # VM never started + + # Verify VM remains running + if not verify_vm_running(args.name): + sys.exit(3) # VM stopped too quickly + + # Wait for VM to shutdown + if not wait_for_vm_shutdown(args.name): + sys.exit(4) # VM failed to shutdown + + # Verify VM remains shutdown + if not verify_vm_shutdown(args.name): + sys.exit(4) # VM failed to stay shutdown + + logger.info("Cloud-init completed successfully") + sys.exit(0) + + except Exception as e: + logger.error(f"Unexpected error: {e}") + sys.exit(1) + +if __name__ == "__main__": + main() diff --git a/salt/libvirt/images/init.sls b/salt/libvirt/images/init.sls index 8532760a7..7118400db 100644 --- a/salt/libvirt/images/init.sls +++ b/salt/libvirt/images/init.sls @@ -117,7 +117,7 @@ undefine_vm_sool9: - onlyif: - virsh dominfo sool9 -# Create and start the VM using virt-install +# Create and start the VM, letting cloud-init run create_vm_sool9: cmd.run: - name: | @@ -138,6 +138,21 @@ create_vm_sool9: - file: manage_userdata_sool9 - file: manage_cidata_sool9 +# Wait for cloud-init to complete and VM to shutdown +wait_for_cloud_init_sool9: + cmd.run: + - name: /usr/sbin/so-wait-cloud-init -n sool9 + - require: + - cmd: create_vm_sool9 + - timeout: 600 + +# Configure network predictability after cloud-init +configure_network_predictable_sool9: + cmd.run: + - name: /usr/sbin/so-qcow2-network-predictable -n sool9 + - require: + - cmd: wait_for_cloud_init_sool9 + {% else %} {{sls}}_no_license_detected: test.fail_without_changes: diff --git a/salt/manager/tools/sbin/so-salt-cloud b/salt/manager/tools/sbin/so-salt-cloud index d4c728143..b2cb0cdc2 100644 --- a/salt/manager/tools/sbin/so-salt-cloud +++ b/salt/manager/tools/sbin/so-salt-cloud @@ -420,7 +420,7 @@ def run_qcow2_modify_network_config(profile, mode, ip=None, gateway=None, dns=No hv_name = profile.split('-')[1] target = hv_name + "_*" image = '/nsm/libvirt/images/sool9/sool9.qcow2' - interface = 'eth0' + interface = 'enp1s0' try: r = local.cmd(target, 'qcow2.modify_network_config', [ diff --git a/salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja b/salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja index 2f0323482..20c12d28f 100644 --- a/salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja +++ b/salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja @@ -45,7 +45,7 @@ sool9-{{host}}: inline_script: - | sudo salt-call state.apply salt.mine_functions \ - pillar='{"host": {"mainint": "eth0"}}' + pillar='{"host": {"mainint": "enp1s0"}}' - 'sudo salt-call mine.update' - 'sudo salt-call state.apply setup.virt' # grains to add to the minion diff --git a/salt/setup/virt/fleet.yaml b/salt/setup/virt/fleet.yaml index 8a6aa06de..d6c90e11d 100644 --- a/salt/setup/virt/fleet.yaml +++ b/salt/setup/virt/fleet.yaml @@ -1,5 +1,5 @@ MAINIP: -MNIC: eth0 +MNIC: enp1s0 NODE_DESCRIPTION: 'vm' ES_HEAP_SIZE: PATCHSCHEDULENAME: diff --git a/salt/setup/virt/heavynode.yaml b/salt/setup/virt/heavynode.yaml index 8cf2e0392..a3550021f 100644 --- a/salt/setup/virt/heavynode.yaml +++ b/salt/setup/virt/heavynode.yaml @@ -1,5 +1,5 @@ MAINIP: -MNIC: eth0 +MNIC: enp1s0 NODE_DESCRIPTION: 'vm' ES_HEAP_SIZE: PATCHSCHEDULENAME: diff --git a/salt/setup/virt/idh.yaml b/salt/setup/virt/idh.yaml index 0e1ef8be0..201262db8 100644 --- a/salt/setup/virt/idh.yaml +++ b/salt/setup/virt/idh.yaml @@ -1,5 +1,5 @@ MAINIP: -MNIC: eth0 +MNIC: enp1s0 NODE_DESCRIPTION: 'vm' ES_HEAP_SIZE: PATCHSCHEDULENAME: diff --git a/salt/setup/virt/receiver.yaml b/salt/setup/virt/receiver.yaml index 5a5c714aa..e5dc0b0e7 100644 --- a/salt/setup/virt/receiver.yaml +++ b/salt/setup/virt/receiver.yaml @@ -1,5 +1,5 @@ MAINIP: -MNIC: eth0 +MNIC: enp1s0 NODE_DESCRIPTION: 'vm' ES_HEAP_SIZE: PATCHSCHEDULENAME: diff --git a/salt/setup/virt/searchnode.yaml b/salt/setup/virt/searchnode.yaml index 2e1568f29..032e0e855 100644 --- a/salt/setup/virt/searchnode.yaml +++ b/salt/setup/virt/searchnode.yaml @@ -1,5 +1,5 @@ MAINIP: -MNIC: eth0 +MNIC: enp1s0 NODE_DESCRIPTION: 'vm' ES_HEAP_SIZE: PATCHSCHEDULENAME: diff --git a/salt/setup/virt/sensor.yaml b/salt/setup/virt/sensor.yaml index e7064bdfe..9136f0b78 100644 --- a/salt/setup/virt/sensor.yaml +++ b/salt/setup/virt/sensor.yaml @@ -1,5 +1,5 @@ MAINIP: -MNIC: eth0 +MNIC: enp1s0 NODE_DESCRIPTION: 'vm' ES_HEAP_SIZE: PATCHSCHEDULENAME: From 9b8dce0c77574498e5c0a6c3bdaff3d086e702b0 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Thu, 6 Feb 2025 15:44:28 -0500 Subject: [PATCH 119/315] only wait and make predicable when virt-install runs --- salt/libvirt/images/init.sls | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/salt/libvirt/images/init.sls b/salt/libvirt/images/init.sls index 7118400db..70e668ffb 100644 --- a/salt/libvirt/images/init.sls +++ b/salt/libvirt/images/init.sls @@ -144,6 +144,8 @@ wait_for_cloud_init_sool9: - name: /usr/sbin/so-wait-cloud-init -n sool9 - require: - cmd: create_vm_sool9 + - onchanges: + - cmd: create_vm_sool9 - timeout: 600 # Configure network predictability after cloud-init @@ -152,6 +154,8 @@ configure_network_predictable_sool9: - name: /usr/sbin/so-qcow2-network-predictable -n sool9 - require: - cmd: wait_for_cloud_init_sool9 + - onchanges: + - cmd: create_vm_sool9 {% else %} {{sls}}_no_license_detected: From 924c0b63bd82a238bce4c02f34bbca5f245e4f5a Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Thu, 6 Feb 2025 16:05:56 -0500 Subject: [PATCH 120/315] put vnm engine in place --- salt/salt/files/virtual_node_manager_engine.conf | 4 ++++ salt/salt/master.sls | 15 +++++++++++++++ 2 files changed, 19 insertions(+) create mode 100644 salt/salt/files/virtual_node_manager_engine.conf diff --git a/salt/salt/files/virtual_node_manager_engine.conf b/salt/salt/files/virtual_node_manager_engine.conf new file mode 100644 index 000000000..8374f551a --- /dev/null +++ b/salt/salt/files/virtual_node_manager_engine.conf @@ -0,0 +1,4 @@ +engines: + - virtual_node_manager: + interval: 30 + base_path: /opt/so/saltstack/local/salt/hypervisor/hosts diff --git a/salt/salt/master.sls b/salt/salt/master.sls index 3f847583f..ed8da3f73 100644 --- a/salt/salt/master.sls +++ b/salt/salt/master.sls @@ -48,6 +48,21 @@ pillarWatch_engine: - name: /etc/salt/engines/pillarWatch.py - source: salt://salt/engines/master/pillarWatch.py +{% if 'hvn' in salt['pillar.get']('features', []) %} +virtual_node_manager_engine: + file.managed: + - name: /etc/salt/engines/virtual_node_manager.py + - source: salt://salt/engines/master/virtual_node_manager.py + - watch_in: + - service: salt_master_service + +virtual_node_manager_engine_config: + file.managed: + - name: /etc/salt/master.d/virtual_node_manager_engine.conf + - source: salt://salt/files/virtual_node_manager_engine.conf + +{% endif %} + engines_config: file.managed: - name: /etc/salt/master.d/engines.conf From 010c205eecafcdfbf3a2c0448dee57b3e3d047eb Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Fri, 7 Feb 2025 14:45:06 -0500 Subject: [PATCH 121/315] configure bond and monitor nics --- .../cloud/cloud.profiles.d/socloud.conf.jinja | 8 ++- salt/sensor/init.sls | 18 +++++ salt/sensor/vm/network.sls | 70 +++++++++++++++++++ salt/setup/virt/init.sls | 4 ++ 4 files changed, 97 insertions(+), 3 deletions(-) create mode 100644 salt/sensor/vm/network.sls diff --git a/salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja b/salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja index 20c12d28f..00b1a76c1 100644 --- a/salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja +++ b/salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja @@ -44,10 +44,12 @@ sool9-{{host}}: # if calling states with pillar values, need to pass them in since minion pillars are not set until setup.virt.sominion state runs inline_script: - | - sudo salt-call state.apply salt.mine_functions \ + salt-call state.apply salt.mine_functions \ + pillar='{"host": {"mainint": "enp1s0"}}' + - salt-call mine.update + - | + salt-call state.apply setup.virt \ pillar='{"host": {"mainint": "enp1s0"}}' - - 'sudo salt-call mine.update' - - 'sudo salt-call state.apply setup.virt' # grains to add to the minion {%- endfor %} diff --git a/salt/sensor/init.sls b/salt/sensor/init.sls index 730a7c7ad..4008879e9 100644 --- a/salt/sensor/init.sls +++ b/salt/sensor/init.sls @@ -1,3 +1,21 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. +# +# Note: Per the Elastic License 2.0, the second limitation states: +# +# "You may not move, change, disable, or circumvent the license key functionality +# in the software, and you may not remove or obscure any functionality in the +# software that is protected by the license key." + +{% if 'hvn' in salt['pillar.get']('features') and salt['grains.get']('salt-cloud', {}) %} + +include: + - sensor.vm.network + +{% endif %} + offload_script: file.managed: - name: /etc/NetworkManager/dispatcher.d/pre-up.d/99-so-checksum-offload-disable diff --git a/salt/sensor/vm/network.sls b/salt/sensor/vm/network.sls new file mode 100644 index 000000000..f056e307a --- /dev/null +++ b/salt/sensor/vm/network.sls @@ -0,0 +1,70 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. +# +# Note: Per the Elastic License 2.0, the second limitation states: +# +# "You may not move, change, disable, or circumvent the license key functionality +# in the software, and you may not remove or obscure any functionality in the +# software that is protected by the license key." + +{% if 'hvn' in salt['pillar.get']('features', []) %} + +{% set mainint = salt['pillar.get']('host:mainint', 'enp1s0') %} +{% set interfaces = salt['network.interfaces']() %} +{% set non_enp1s0_interfaces = [] %} +{% for iface, data in interfaces.items() %} + {% if iface != mainint and not iface.startswith(('veth', 'docker', 'lo', 'br', 'sobridge', 'bond')) %} + {% do non_enp1s0_interfaces.append(iface) %} + {% endif %} +{% endfor %} + +# Create bond0 interface with NetworkManager +bond0_interface: + cmd.run: + - name: | + nmcli con add type bond \ + con-name bond0 \ + ifname bond0 \ + mode 0 \ + miimon 100 \ + ipv4.method disabled \ + ipv6.method ignore \ + ipv6.addr-gen-mode default \ + connection.autoconnect yes + nmcli con mod bond0 ethernet.mtu 9000 + nmcli con up bond0 +{% if non_enp1s0_interfaces|length > 0 %} + - require_in: +{% for iface in non_enp1s0_interfaces %} + - cmd: {{ iface }}_slave +{% endfor %} +{% endif %} + +# Configure non-enp1s0 interfaces as bond slaves first +{% if non_enp1s0_interfaces|length > 0 %} +{% for iface in non_enp1s0_interfaces %} +{{ iface }}_slave: + cmd.run: + - name: | + nmcli con add type ethernet \ + con-name bond0-slave-{{ iface }} \ + ifname {{ iface }} \ + master bond0 \ + slave-type bond \ + ethernet.mtu 9000 + nmcli con up bond0-slave-{{ iface }} + +{% endfor %} +{% endif %} + +{% else %} +{{sls}}_no_license_detected: + test.fail_without_changes: + - name: {{sls}}_no_license_detected + - comment: + - "Hypervisor nodes are a feature supported only for customers with a valid license. + Contact Security Onion Solutions, LLC via our website at https://securityonionsolutions.com + for more information about purchasing a license to enable this feature." +{% endif %} diff --git a/salt/setup/virt/init.sls b/salt/setup/virt/init.sls index 9c173a78e..65a514ae8 100644 --- a/salt/setup/virt/init.sls +++ b/salt/setup/virt/init.sls @@ -1,5 +1,9 @@ +{% set role = grains.id.split("_") | last %} include: - setup.virt.setHostname - setup.virt.sominion - common.packages # python3-dnf-plugin-versionlock +{% if role in ['sensor', 'heavynode'] %} + - sensor.vm.network +{% endif %} - setup.virt.setSalt From 5123a860620e3538c630d7f63905da467b4968b3 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Wed, 12 Feb 2025 13:21:39 -0500 Subject: [PATCH 122/315] start of dynamic annotations for hypervisor --- salt/hypervisor/defaults.yaml | 153 +++++++++++------- salt/hypervisor/pillar.map.jinja | 29 ---- salt/hypervisor/pillarExample.sls | 48 ------ .../soc/dyanno/hypervisor/hardwareMap.example | 32 ++++ salt/soc/dyanno/hypervisor/hypervisor.yaml | 50 ++++++ .../hypervisor/init.sls | 8 +- .../hypervisor/map.jinja | 0 .../hypervisor/soc_hypervisor.yaml.example | 67 ++++++++ .../hypervisor/soc_hypervisor.yaml.jinja | 36 +++++ salt/soc/dyanno/hypervisor/vmMap.example | 14 ++ .../dynamic_annotations/hypervisor/add_node | 11 -- .../hypervisor/hypervisor.yaml | 40 ----- .../hypervisor/soc_hypervisor.yaml.jinja | 13 -- 13 files changed, 295 insertions(+), 206 deletions(-) delete mode 100644 salt/hypervisor/pillar.map.jinja delete mode 100644 salt/hypervisor/pillarExample.sls create mode 100644 salt/soc/dyanno/hypervisor/hardwareMap.example create mode 100644 salt/soc/dyanno/hypervisor/hypervisor.yaml rename salt/soc/{dynamic_annotations => dyanno}/hypervisor/init.sls (71%) rename salt/soc/{dynamic_annotations => dyanno}/hypervisor/map.jinja (100%) create mode 100644 salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.example create mode 100644 salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja create mode 100644 salt/soc/dyanno/hypervisor/vmMap.example delete mode 100644 salt/soc/dynamic_annotations/hypervisor/add_node delete mode 100644 salt/soc/dynamic_annotations/hypervisor/hypervisor.yaml delete mode 100644 salt/soc/dynamic_annotations/hypervisor/soc_hypervisor.yaml.jinja diff --git a/salt/hypervisor/defaults.yaml b/salt/hypervisor/defaults.yaml index 4a762e677..38a4f4597 100644 --- a/salt/hypervisor/defaults.yaml +++ b/salt/hypervisor/defaults.yaml @@ -1,62 +1,93 @@ hypervisor: - nodes: [] - model1: - hardware: - cpu: - total: 128 - free: 128 - memory: - total: 128 - free: 128 - disks: - free: - 3: pci_0000_c7_00_0 - 4: pci_0000_c8_00_0 - claimed: - 1: pci_0000_c5_00_0 - 2: pci_0000_c6_00_0 - copper: - free: - 1: pci_0000_c4_00_0 - 2: pci_0000_c4_00_1 - 3: pci_0000_c4_00_2 - 4: pci_0000_c4_00_3 - claimed: {} - sfp: - free: - 5: pci_0000_41_00_0 - 6: pci_0000_41_00_1 - claimed: {} - model2: - hardware: - cpu: - total: 128 - free: 128 - memory: - total: 512 - free: 512 - disks: - free: - 3: pci_0000_c8_00_0 - 4: pci_0000_c9_00_0 - 5: pci_0000_c10_00_0 - 6: pci_0000_c11_00_0 - claimed: - 1: pci_0000_c6_00_0 - 2: pci_0000_c7_00_0 - copper: - free: - 1: pci_0000_c4_00_0 - 2: pci_0000_c4_00_1 - 3: pci_0000_c4_00_2 - 4: pci_0000_c4_00_3 - 5: pci_0000_c5_00_0 - 6: pci_0000_c5_00_1 - 7: pci_0000_c5_00_2 - 8: pci_0000_c5_00_3 - claimed: {} - sfp: - free: - 9: pci_0000_41_00_0 - 10: pci_0000_41_00_1 - claimed: {} + model: + testModel: + hardware: + cpu: + total: 128 + free: 128 + memory: + total: 128 + free: 128 + disks: + free: + 3: pci_0000_c7_00_0 + 4: pci_0000_c8_00_0 + claimed: + 1: pci_0000_c5_00_0 # hypervisor + 2: pci_0000_c6_00_0 # hypervisor + copper: + free: + 3: pci_0000_c4_00_0 + 4: pci_0000_c4_00_1 + 5: pci_0000_c4_00_2 + 6: pci_0000_c4_00_3 + claimed: + 1: pci_0000_c1_00_0 # hypervisor + 2: pci_0000_c1_00_1 # hypervisor + sfp: + free: + 5: pci_0000_02_00_0 + 6: pci_0000_02_00_1 + 7: pci_0000_41_00_0 + 8: pci_0000_41_00_1 + claimed: {} + model1: + hardware: + cpu: + total: 128 + free: 128 + memory: + total: 128 + free: 128 + disks: + free: + 3: pci_0000_c7_00_0 + 4: pci_0000_c8_00_0 + claimed: + 1: pci_0000_c5_00_0 + 2: pci_0000_c6_00_0 + copper: + free: + 1: pci_0000_c4_00_0 + 2: pci_0000_c4_00_1 + 3: pci_0000_c4_00_2 + 4: pci_0000_c4_00_3 + claimed: {} + sfp: + free: + 5: pci_0000_41_00_0 + 6: pci_0000_41_00_1 + claimed: {} + model2: + hardware: + cpu: + total: 128 + free: 128 + memory: + total: 512 + free: 512 + disks: + free: + 3: pci_0000_c8_00_0 + 4: pci_0000_c9_00_0 + 5: pci_0000_c10_00_0 + 6: pci_0000_c11_00_0 + claimed: + 1: pci_0000_c6_00_0 + 2: pci_0000_c7_00_0 + copper: + free: + 1: pci_0000_c4_00_0 + 2: pci_0000_c4_00_1 + 3: pci_0000_c4_00_2 + 4: pci_0000_c4_00_3 + 5: pci_0000_c5_00_0 + 6: pci_0000_c5_00_1 + 7: pci_0000_c5_00_2 + 8: pci_0000_c5_00_3 + claimed: {} + sfp: + free: + 9: pci_0000_41_00_0 + 10: pci_0000_41_00_1 + claimed: {} diff --git a/salt/hypervisor/pillar.map.jinja b/salt/hypervisor/pillar.map.jinja deleted file mode 100644 index 3b6c275a3..000000000 --- a/salt/hypervisor/pillar.map.jinja +++ /dev/null @@ -1,29 +0,0 @@ -{% set HYPERVISORHOSTS = salt['pillar.get']('hypervisor:hosts', {}) %} - -{% import_yaml 'setup/virt/sensor.yaml' as SENSOR %} -{% import_yaml 'setup/virt/searchnode.yaml' as SEARCHNODE %} - -{% set vars = { - 'sensor': SENSOR, - 'searchnode': SEARCHNODE -} %} - -{% for host, guestDetails in HYPERVISORHOSTS.items() %} -{% if guestDetails['add_guest'] | length > 0 %} -{% for newGuest in guestDetails['add_guest'] %} -{% set indx = guestDetails['add_guest'].index(newGuest) %} -{% do guestDetails['add_guest'].pop(indx) %} -{% set NODETYPE = newGuest.split('_') | last %} -{% do guestDetails['guests'].update({ - newGuest: { - 'cpu': vars[NODETYPE].CPU, - 'memory': vars[NODETYPE].MEMORY, - 'disk': vars[NODETYPE].DISKS, - 'copper': vars[NODETYPE].COPPER, - 'sfp': vars[NODETYPE].SFP - } -}) %} - -{% endfor %} -{% endif %} -{% endfor %} diff --git a/salt/hypervisor/pillarExample.sls b/salt/hypervisor/pillarExample.sls deleted file mode 100644 index 4bc11434b..000000000 --- a/salt/hypervisor/pillarExample.sls +++ /dev/null @@ -1,48 +0,0 @@ -hypervisor: - hardware: - cpu: - total: 128 - free: 128 - memory: - total: 128 - free: 128 - disks: - free: - 3: pci_0000_c7_00_0 - 4: pci_0000_c8_00_0 - claimed: - 1: pci_0000_c5_00_0 - 2: pci_0000_c6_00_0 - copper: - free: - 1: pci_0000_c4_00_0 - 2: pci_0000_c4_00_1 - 3: pci_0000_c4_00_2 - 4: pci_0000_c4_00_3 - claimed: {} - sfp: - free: - 5: pci_0000_41_00_0 - 6: pci_0000_41_00_1 - claimed: {} - - -hypervisor: - hardware: - cpu: - total: 16 - free: 16 - memory: - total: 16 - free: 16 - disks: - free: {} - claimed: {} - copper: - free: - 2: pci_0000_00_13_0 - claimed: - 1: pci_0000_00_12_0 - sfp: - free: {} - claimed: {} diff --git a/salt/soc/dyanno/hypervisor/hardwareMap.example b/salt/soc/dyanno/hypervisor/hardwareMap.example new file mode 100644 index 000000000..ea3bec51b --- /dev/null +++ b/salt/soc/dyanno/hypervisor/hardwareMap.example @@ -0,0 +1,32 @@ +# this file will exist in /opt/so/saltstack/local/salt/hypervisor/hosts/HOSTNAME/hardwareMap +hypervisor: + hardware: + copper: + claimed: + 1: pci_0000_c1_00_0 + 2: pci_0000_c1_00_1 + free: + 3: pci_0000_c4_00_0 + 4: pci_0000_c4_00_1 + 5: pci_0000_c4_00_2 + 6: pci_0000_c4_00_3 + cpu: + free: 120 + total: 120 + disk: + claimed: + 1: pci_0000_c5_00_0 + 2: pci_0000_c6_00_0 + free: + 3: pci_0000_c7_00_0 + 4: pci_0000_c8_00_0 + memory: + free: 120 + total: 120 + sfp: + claimed: {} + free: + 8: pci_0000_02_00_1 + 7: pci_0000_02_00_0 + 9: pci_0000_41_00_0 + 10: pci_0000_41_00_1 diff --git a/salt/soc/dyanno/hypervisor/hypervisor.yaml b/salt/soc/dyanno/hypervisor/hypervisor.yaml new file mode 100644 index 000000000..3a5d000a9 --- /dev/null +++ b/salt/soc/dyanno/hypervisor/hypervisor.yaml @@ -0,0 +1,50 @@ +hypervisor: + hosts: + defaultHost: + hardwareMap: + title: 'All Hardware' + description: This shows hardware available to the hypervisor and PCIe -> INT mapping. + file: true + readonly: true + global: true # set to true to remove host drop down + multiline: true + vmMap: + title: 'VM Map' + description: This shows the VMs and the hardware they have claimed. + file: true + readonly: true + global: true + multiline: true + nodes: + description: 'Available CPU: CPUFREE | Available Memory: MEMFREE | Available Disk: DISKFREE | Available Copper NIC: COPPERFREE | Available SFP NIC: SFPFREE' + syntax: json + uiElements: + - field: hostname + label: Enter the hostname + forcedType: string + - field: nodetype + label: sensor or searchnode + - field: network_mode + label: Choose static4 or dhcp4. If static4, populate IP details below. + - field: ip4 + label: IP Address with netmask. ex. 192.168.1.10/24 + - field: gw4 + label: Gateway + - field: dns4 + label: DNS. Comma seperated list. ex. 192.168.1.1,8.8.8.8 + - field: search4 + label: Search domain + - field: cpu + label: Number of CPU cores to assign. ex. 8 + - field: memory + label: Memory, in GB to assign. ex. 16 + - field: disk + label: Choose a disk or disks to assign for passthrough. Comma seperated list. + - field: copper + label: Choose a copper port or ports to assign for passthrough. Comma seperated list. + - filed: sfp + label: Choose a sfp port or ports to assign for passthrough. Comma seperated list. + file: true + global: true + + vms: {} diff --git a/salt/soc/dynamic_annotations/hypervisor/init.sls b/salt/soc/dyanno/hypervisor/init.sls similarity index 71% rename from salt/soc/dynamic_annotations/hypervisor/init.sls rename to salt/soc/dyanno/hypervisor/init.sls index 8c857e72f..c3bfb97ef 100644 --- a/salt/soc/dynamic_annotations/hypervisor/init.sls +++ b/salt/soc/dyanno/hypervisor/init.sls @@ -1,9 +1,9 @@ -{% from 'soc/dynamic_annotations/hypervisor/map.jinja' import HYPERVISORS %} +{% from 'soc/dyanno/hypervisor/map.jinja' import HYPERVISORS %} hypervisor_annotation: file.managed: - name: /opt/so/saltstack/default/salt/hypervisor/soc_hypervisor.yaml - - source: salt://soc/dynamic_annotations/hypervisor/soc_hypervisor.yaml.jinja + - source: salt://soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja - template: jinja - defaults: HYPERVISORS: {{ HYPERVISORS }} @@ -18,11 +18,11 @@ hypervisor_host_directory_{{hypervisor}}: add_searchnode_file_{{hypervisor}}: file.managed: - name: /opt/so/saltstack/local/salt/hypervisor/hosts/{{hypervisor}}/add_searchnode - - source: salt://soc/dynamic_annotations/hypervisor/add_node + - source: salt://soc/dyanno/hypervisor/add_node add_sensor_file_{{hypervisor}}: file.managed: - name: /opt/so/saltstack/local/salt/hypervisor/hosts/{{hypervisor}}/add_sensor - - source: salt://soc/dynamic_annotations/hypervisor/add_node + - source: salt://soc/dyanno/hypervisor/add_node {% endfor %} {% endfor %} diff --git a/salt/soc/dynamic_annotations/hypervisor/map.jinja b/salt/soc/dyanno/hypervisor/map.jinja similarity index 100% rename from salt/soc/dynamic_annotations/hypervisor/map.jinja rename to salt/soc/dyanno/hypervisor/map.jinja diff --git a/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.example b/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.example new file mode 100644 index 000000000..bd5161598 --- /dev/null +++ b/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.example @@ -0,0 +1,67 @@ +# This is the start of an example of what this file will look like. It will be generated by Salt, so this yaml file is not used by Salt. +hypervisor: + hosts: + jpphype1: + hardwareMap: + title: 'All Hardware' + description: This shows hardware available to the hypervisor and PCIe -> INT mapping. + file: true + readonly: true + global: true # set to true to remove host drop down + multiline: true + cpufree: + title: 'Available CPU: 120' + description: Available CPU for this hypervisor. + readonly: true + global: true # set to true to remove host drop down + memfree: + title: 'Available Memory: 120' + description: Available memory for this hypervisor. + readonly: true + global: true # set to true to remove host drop down + diskfree: + title: 'Available Disk: 3,4' + description: Available disk for this hypervisor. + readonly: true + global: true # set to true to remove host drop down + copperfree: + title: 'Available Copper NIC: 3,4,5,6' + description: Available copper NIC for this hypervisor. + readonly: true + global: true # set to true to remove host drop down + sfpfree: + title: 'Available SFP NIC: 7,8,9,10' + description: Available SFP NIC for this hypervisor. + readonly: true + global: true # set to true to remove host drop down + nodes: + description: List of VMs. + syntax: json + uiElements: + - field: hostname + label: Enter the hostname + forcedType: string + - field: nodetype + label: sensor or searchnode + - field: network_mode + label: Choose static4 or dhcp4. If static4, populate IP details below. + - field: ip4 + label: IP Address with netmask. ex. 192.168.1.10/24 + - field: gw4 + label: Gateway + - field: dns4 + label: DNS. Comma seperated list. ex. 192.168.1.1,8.8.8.8 + - field: search4 + label: Search domain + - field: cpu + label: Number of CPU cores to assign. ex. 8 + - field: memory + label: Memory, in GB to assign. ex. 16 + - field: disk + label: Choose a disk or disks to assign for passthrough. Comma seperated list. + - field: copper + label: Choose a copper port or ports to assign for passthrough. Comma seperated list. + - filed: sfp + label: Choose a sfp port or ports to assign for passthrough. Comma seperated list. + file: true + global: true # set to true to remove host drop down diff --git a/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja b/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja new file mode 100644 index 000000000..74996605e --- /dev/null +++ b/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja @@ -0,0 +1,36 @@ +{%- import_yaml 'soc/dyanno/hypervisor/hypervisor.yaml' as ANNOTATION -%} + +{%- set TEMPLATE = ANNOTATION.hypervisor.hosts.pop('defaultHost') -%} + +{%- macro update_description(description, cpu_free, mem_free, disk_free, copper_free, sfp_free) -%} +{{- description | replace('CPUFREE', cpu_free | string) + | replace('MEMFREE', mem_free | string) + | replace('DISKFREE', disk_free | string) + | replace('COPPERFREE', copper_free | string) + | replace('SFPFREE', sfp_free | string) -}} +{%- endmacro -%} + +{%- for role in HYPERVISORS -%} +{%- for hypervisor in HYPERVISORS[role].keys() -%} +{%- set cpu_free = HYPERVISORS[role][hypervisor].available_cpu -%} +{%- set mem_free = HYPERVISORS[role][hypervisor].available_memory -%} +{%- set disk_free = HYPERVISORS[role][hypervisor].available_disk -%} +{%- set copper_free = HYPERVISORS[role][hypervisor].available_copper -%} +{%- set sfp_free = HYPERVISORS[role][hypervisor].available_sfp -%} + +{%- set updated_template = TEMPLATE.copy() -%} +{%- do updated_template.nodes.update({ + 'description': update_description( + TEMPLATE.nodes.description, + cpu_free, + mem_free, + disk_free, + copper_free, + sfp_free + ) + }) -%} +{%- do ANNOTATION.hypervisor.hosts.update({hypervisor: updated_template}) -%} +{%- endfor -%} +{%- endfor -%} + +{{- ANNOTATION | yaml(False) -}} diff --git a/salt/soc/dyanno/hypervisor/vmMap.example b/salt/soc/dyanno/hypervisor/vmMap.example new file mode 100644 index 000000000..7a67c7349 --- /dev/null +++ b/salt/soc/dyanno/hypervisor/vmMap.example @@ -0,0 +1,14 @@ +hypervisor: + vm: + sen41_sensor: + cpu: 16 + memory: 24 + disk: 3 + copper: 3,4 + sfp: 7,8 + sea42_searchnode: + cpu: 16 + memory: 24 + disk: 4 + copper: + sfp: diff --git a/salt/soc/dynamic_annotations/hypervisor/add_node b/salt/soc/dynamic_annotations/hypervisor/add_node deleted file mode 100644 index ecbde7b41..000000000 --- a/salt/soc/dynamic_annotations/hypervisor/add_node +++ /dev/null @@ -1,11 +0,0 @@ -hostname: -network_mode: -ip4: -gw4: -dns4: -search4: -cpu: -memory: -disk: -copper: -sfp: diff --git a/salt/soc/dynamic_annotations/hypervisor/hypervisor.yaml b/salt/soc/dynamic_annotations/hypervisor/hypervisor.yaml deleted file mode 100644 index 0ec53ff30..000000000 --- a/salt/soc/dynamic_annotations/hypervisor/hypervisor.yaml +++ /dev/null @@ -1,40 +0,0 @@ -hypervisor: - hosts: - defaultHost: - add_searchnode: - description: Add a new searchnode to the hypervisor. - file: True - global: True - multiline: True - add_sensor: - description: Add a new sensor to the hypervisor. - file: True - global: True - multiline: True - guests: - defaultGuest: - copper: - description: Copper nics - forcedType: "[]int" - global: True - multiline: True - sfp: - description: sfp nics - forcedType: string - global: True - multiline: True - disks: - description: disk - forcedType: "[]int" - global: True - multiline: True - cpu: - description: cpu - forcedType: int - global: True - multiline: True - memory: - description: mem - forcedType: int - global: True - multiline: True diff --git a/salt/soc/dynamic_annotations/hypervisor/soc_hypervisor.yaml.jinja b/salt/soc/dynamic_annotations/hypervisor/soc_hypervisor.yaml.jinja deleted file mode 100644 index c9dd8200d..000000000 --- a/salt/soc/dynamic_annotations/hypervisor/soc_hypervisor.yaml.jinja +++ /dev/null @@ -1,13 +0,0 @@ -{% import_yaml 'soc/dynamic_annotations/hypervisor/hypervisor.yaml' as ANNOTATION %} - -{% set TEMPLATE = ANNOTATION.hypervisor.hosts.pop('defaultHost') %} -{# remove defaultGuest so that it is not shown in Grid Configuration UI #} -{% do TEMPLATE['guests'].pop('defaultGuest') %} - -{% for role in HYPERVISORS %} -{% for hypervisor in HYPERVISORS[role].keys() %} -{% do ANNOTATION.hypervisor.hosts.update({hypervisor: TEMPLATE}) %} -{% endfor %} -{% endfor %} - -{{ ANNOTATION | yaml(False) }} From ad27c8674b44dfe677a558aa789cea1d75f1ac14 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Sat, 15 Feb 2025 10:50:09 -0500 Subject: [PATCH 123/315] no longer need add_* nodes --- salt/hypervisor/pillar.sls | 5 ----- salt/soc/dyanno/hypervisor/init.sls | 10 ---------- 2 files changed, 15 deletions(-) delete mode 100644 salt/hypervisor/pillar.sls diff --git a/salt/hypervisor/pillar.sls b/salt/hypervisor/pillar.sls deleted file mode 100644 index 92c1cbfec..000000000 --- a/salt/hypervisor/pillar.sls +++ /dev/null @@ -1,5 +0,0 @@ -soc_hypervisor_pillar: - file.managed: - - name: /opt/so/saltstack/local/pillar/hypervisor/soc_hypervisor.sls - - source: salt://hypervisor/pillar.map.jinja - - template: jinja diff --git a/salt/soc/dyanno/hypervisor/init.sls b/salt/soc/dyanno/hypervisor/init.sls index c3bfb97ef..31fe5ec93 100644 --- a/salt/soc/dyanno/hypervisor/init.sls +++ b/salt/soc/dyanno/hypervisor/init.sls @@ -14,15 +14,5 @@ hypervisor_host_directory_{{hypervisor}}: file.directory: - name: /opt/so/saltstack/local/salt/hypervisor/hosts/{{hypervisor}} - makedirs: True - -add_searchnode_file_{{hypervisor}}: - file.managed: - - name: /opt/so/saltstack/local/salt/hypervisor/hosts/{{hypervisor}}/add_searchnode - - source: salt://soc/dyanno/hypervisor/add_node - -add_sensor_file_{{hypervisor}}: - file.managed: - - name: /opt/so/saltstack/local/salt/hypervisor/hosts/{{hypervisor}}/add_sensor - - source: salt://soc/dyanno/hypervisor/add_node {% endfor %} {% endfor %} From e193347fb47c5527ff6acf0008c6220a3c2d0e51 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Sat, 15 Feb 2025 10:54:49 -0500 Subject: [PATCH 124/315] add hypervisor to host keys first connection. cleaner qcow2 logging. --- salt/manager/tools/sbin/so-salt-cloud | 104 +++++++++++++++++++++++++- 1 file changed, 100 insertions(+), 4 deletions(-) diff --git a/salt/manager/tools/sbin/so-salt-cloud b/salt/manager/tools/sbin/so-salt-cloud index b2cb0cdc2..1145c1b65 100644 --- a/salt/manager/tools/sbin/so-salt-cloud +++ b/salt/manager/tools/sbin/so-salt-cloud @@ -209,6 +209,7 @@ Logging: """ import argparse +import os import subprocess import re import sys @@ -346,6 +347,47 @@ def delete_vm(profile, vm_name, assume_yes=False): logger.error(f"Failed to delete VM {vm_name}: {e}") raise +def _add_hypervisor_host_key(hostname): + """Add hypervisor host key to root's known_hosts file. + + Args: + hostname (str): The hostname or IP of the hypervisor + + Returns: + bool: True if key was added or already exists, False on error + """ + try: + known_hosts = '/root/.ssh/known_hosts' + os.makedirs(os.path.dirname(known_hosts), exist_ok=True) + + # Check if key already exists using ssh-keygen + if os.path.exists(known_hosts): + check_result = subprocess.run(['ssh-keygen', '-F', hostname], + capture_output=True, text=True) + if check_result.returncode == 0 and check_result.stdout.strip(): + logger.info("Host key for %s already in known_hosts", hostname) + return True + + # Get host key using ssh-keyscan + logger.info("Scanning host key for %s", hostname) + process = subprocess.run(['ssh-keyscan', '-H', hostname], + capture_output=True, text=True) + + if process.returncode == 0 and process.stdout: + # Append new key + with open(known_hosts, 'a') as f: + f.write(process.stdout) + logger.info("Added host key for %s to known_hosts", hostname) + return True + else: + logger.error("Failed to get host key for %s: %s", + hostname, process.stderr) + return False + + except Exception as e: + logger.error("Error adding host key for %s: %s", hostname, str(e)) + return False + def call_salt_cloud(profile, vm_name, destroy=False, assume_yes=False): """Call salt-cloud to create or destroy a VM""" try: @@ -353,6 +395,14 @@ def call_salt_cloud(profile, vm_name, destroy=False, assume_yes=False): delete_vm(profile, vm_name, assume_yes) return + # Extract hypervisor hostname from profile (e.g., sool9-jpphype1 -> jpphype1) + hypervisor = profile.split('-', 1)[1] if '-' in profile else None + if hypervisor: + logger.info("Ensuring host key exists for hypervisor %s", hypervisor) + if not _add_hypervisor_host_key(hypervisor): + logger.error("Failed to add host key for %s, cannot proceed with VM creation", hypervisor) + sys.exit(1) + # Start the salt-cloud command as a subprocess process = subprocess.Popen( ['salt-cloud', '-p', profile, vm_name, '-l', 'info'], @@ -394,6 +444,29 @@ def call_salt_cloud(profile, vm_name, destroy=False, assume_yes=False): except Exception as e: logger.error(f"An error occurred while calling salt-cloud: {e}") +def format_qcow2_output(operation, result): + """Format the output from qcow2 module operations for better readability. + + Args: + operation (str): The name of the operation (e.g., 'Network configuration', 'Hardware configuration') + result (dict): The result dictionary from the qcow2 module + + Returns: + None - logs the formatted output directly + """ + for host, host_result in result.items(): + if isinstance(host_result, dict): + # Extract and format stderr which contains the detailed log + if 'stderr' in host_result: + logger.info(f"{operation} on {host}:") + for line in host_result['stderr'].split('\n'): + if line.strip(): + logger.info(f" {line.strip()}") + if host_result.get('retcode', 0) != 0: + logger.error(f"{operation} failed on {host} with return code {host_result.get('retcode')}") + else: + logger.info(f"{operation} result from {host}: {host_result}") + def run_qcow2_modify_hardware_config(profile, vm_name, cpu=None, memory=None, pci_list=None, start=False): hv_name = profile.split('-')[1] target = hv_name + "_*" @@ -411,8 +484,8 @@ def run_qcow2_modify_hardware_config(profile, vm_name, cpu=None, memory=None, pc # Pass all PCI devices as a comma-separated list args_list.append('pci=' + ','.join(pci_list)) - r = local.cmd(target, 'qcow2.modify_hardware_config', args_list) - logger.info(f'qcow2.modify_hardware_config: {r}') + result = local.cmd(target, 'qcow2.modify_hardware_config', args_list) + format_qcow2_output('Hardware configuration', result) except Exception as e: logger.error(f"An error occurred while running qcow2.modify_hardware_config: {e}") @@ -423,7 +496,7 @@ def run_qcow2_modify_network_config(profile, mode, ip=None, gateway=None, dns=No interface = 'enp1s0' try: - r = local.cmd(target, 'qcow2.modify_network_config', [ + result = local.cmd(target, 'qcow2.modify_network_config', [ 'image=' + image, 'interface=' + interface, 'mode=' + mode, @@ -432,7 +505,7 @@ def run_qcow2_modify_network_config(profile, mode, ip=None, gateway=None, dns=No 'dns4=' + dns if dns else '', 'search4=' + search_domain if search_domain else '' ]) - logger.info(f'qcow2.modify_network_config: {r}') + format_qcow2_output('Network configuration', result) except Exception as e: logger.error(f"An error occurred while running qcow2.modify_network_config: {e}") @@ -473,6 +546,29 @@ def parse_arguments(): def main(): try: args = parse_arguments() + + # Log the initial request + if args.destroy: + logger.info(f"Received request to destroy VM '{args.vm_name}' using profile '{args.profile}'{' with --assume-yes' if args.assume_yes else ''}") + else: + # Build network config string + network_config = "using DHCP" if args.dhcp4 else f"with static IP {args.ip4}, gateway {args.gw4}" + if args.dns4: + network_config += f", DNS {args.dns4}" + if args.search4: + network_config += f", search domain {args.search4}" + + # Build hardware config string + hw_config = [] + if args.cpu: + hw_config.append(f"{args.cpu} CPUs") + if args.memory: + hw_config.append(f"{args.memory}MB RAM") + if args.pci: + hw_config.append(f"PCI devices: {', '.join(args.pci)}") + hw_string = f" and hardware config: {', '.join(hw_config)}" if hw_config else "" + + logger.info(f"Received request to create VM '{args.vm_name}' using profile '{args.profile}' {network_config}{hw_string}") if args.destroy: # Handle VM deletion From a84f5a1e3210383e0b7519ea708c551a08bf3241 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Sat, 15 Feb 2025 11:14:39 -0500 Subject: [PATCH 125/315] updated logging added returns --- salt/_runners/setup_hypervisor.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/salt/_runners/setup_hypervisor.py b/salt/_runners/setup_hypervisor.py index c51166133..c06439eab 100644 --- a/salt/_runners/setup_hypervisor.py +++ b/salt/_runners/setup_hypervisor.py @@ -77,7 +77,6 @@ import time import yaml from cryptography.hazmat.primitives import serialization from cryptography.hazmat.primitives.asymmetric import ed25519 - # Configure logging log = logging.getLogger(__name__) log.setLevel(logging.DEBUG) @@ -442,11 +441,21 @@ def setup_environment(vm_name: str = 'sool9', disk_size: str = '220G', minion_id # Run highstate on the hypervisor highstate_result = local.cmd(minion_id, 'state.highstate', [], timeout=1800) if highstate_result and minion_id in highstate_result: - log.info("MAIN: Highstate completed on %s", minion_id) + log.info("MAIN: Highstate triggered on %s", minion_id) else: log.error("MAIN: Highstate failed or timed out on %s", minion_id) + return { + 'success': False, + 'error': 'Highstate failed or timed out', + 'vm_result': None + } except Exception as e: log.error("MAIN: Error running highstate on %s: %s", minion_id, str(e)) + return { + 'success': False, + 'error': f'Error running highstate: {str(e)}', + 'vm_result': None + } return { 'success': success, From eb4cd752186cc6535c852a5a5f070d7a07c84947 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Sat, 15 Feb 2025 11:29:47 -0500 Subject: [PATCH 126/315] virtual_node_manager lookup hardware from defaults. allocate hw in vm file --- salt/hypervisor/defaults.yaml | 125 +-- .../engines/master/virtual_node_manager.py | 983 ++++++++++-------- salt/soc/dyanno/hypervisor/hypervisor.yaml | 13 +- salt/soc/dyanno/hypervisor/init.sls | 5 + 4 files changed, 598 insertions(+), 528 deletions(-) diff --git a/salt/hypervisor/defaults.yaml b/salt/hypervisor/defaults.yaml index 38a4f4597..06509828c 100644 --- a/salt/hypervisor/defaults.yaml +++ b/salt/hypervisor/defaults.yaml @@ -2,92 +2,57 @@ hypervisor: model: testModel: hardware: - cpu: - total: 128 - free: 128 - memory: - total: 128 - free: 128 - disks: - free: - 3: pci_0000_c7_00_0 - 4: pci_0000_c8_00_0 - claimed: - 1: pci_0000_c5_00_0 # hypervisor - 2: pci_0000_c6_00_0 # hypervisor + cpu: 128 + memory: 128 + disk: + 1: pci_0000_c7_00_0 + 2: pci_0000_c8_00_0 copper: - free: - 3: pci_0000_c4_00_0 - 4: pci_0000_c4_00_1 - 5: pci_0000_c4_00_2 - 6: pci_0000_c4_00_3 - claimed: - 1: pci_0000_c1_00_0 # hypervisor - 2: pci_0000_c1_00_1 # hypervisor + 1: pci_0000_c4_00_0 + 2: pci_0000_c4_00_1 + 3: pci_0000_c4_00_2 + 4: pci_0000_c4_00_3 sfp: - free: - 5: pci_0000_02_00_0 - 6: pci_0000_02_00_1 - 7: pci_0000_41_00_0 - 8: pci_0000_41_00_1 - claimed: {} + 5: pci_0000_02_00_0 + 6: pci_0000_02_00_1 + 7: pci_0000_41_00_0 + 8: pci_0000_41_00_1 model1: hardware: - cpu: - total: 128 - free: 128 - memory: - total: 128 - free: 128 - disks: - free: - 3: pci_0000_c7_00_0 - 4: pci_0000_c8_00_0 - claimed: - 1: pci_0000_c5_00_0 - 2: pci_0000_c6_00_0 + cpu: 128 + memory: 128 + disk: + 1: pci_0000_c7_00_0 + 2: pci_0000_c8_00_0 copper: - free: - 1: pci_0000_c4_00_0 - 2: pci_0000_c4_00_1 - 3: pci_0000_c4_00_2 - 4: pci_0000_c4_00_3 - claimed: {} + 1: pci_0000_c4_00_0 + 2: pci_0000_c4_00_1 + 3: pci_0000_c4_00_2 + 4: pci_0000_c4_00_3 sfp: - free: - 5: pci_0000_41_00_0 - 6: pci_0000_41_00_1 - claimed: {} + 5: pci_0000_02_00_0 + 6: pci_0000_02_00_1 + 7: pci_0000_41_00_0 + 8: pci_0000_41_00_1 model2: - hardware: - cpu: - total: 128 - free: 128 - memory: - total: 512 - free: 512 - disks: - free: - 3: pci_0000_c8_00_0 - 4: pci_0000_c9_00_0 - 5: pci_0000_c10_00_0 - 6: pci_0000_c11_00_0 - claimed: - 1: pci_0000_c6_00_0 - 2: pci_0000_c7_00_0 + cpu: 256 + memory: 256 + disk: + 1: pci_0000_c7_00_0 + 2: pci_0000_c8_00_0 + 3: pci_0000_c9_00_0 + 4: pci_0000_c10_00_0 copper: - free: - 1: pci_0000_c4_00_0 - 2: pci_0000_c4_00_1 - 3: pci_0000_c4_00_2 - 4: pci_0000_c4_00_3 - 5: pci_0000_c5_00_0 - 6: pci_0000_c5_00_1 - 7: pci_0000_c5_00_2 - 8: pci_0000_c5_00_3 - claimed: {} + 1: pci_0000_c4_00_0 + 2: pci_0000_c4_00_1 + 3: pci_0000_c4_00_2 + 4: pci_0000_c4_00_3 + 5: pci_0000_c5_00_0 + 6: pci_0000_c5_00_1 + 7: pci_0000_c5_00_2 + 8: pci_0000_c5_00_3 sfp: - free: - 9: pci_0000_41_00_0 - 10: pci_0000_41_00_1 - claimed: {} + 9: pci_0000_02_00_0 + 10: pci_0000_02_00_1 + 11: pci_0000_41_00_0 + 12: pci_0000_41_00_1 \ No newline at end of file diff --git a/salt/salt/engines/master/virtual_node_manager.py b/salt/salt/engines/master/virtual_node_manager.py index f935b2075..80e49813a 100644 --- a/salt/salt/engines/master/virtual_node_manager.py +++ b/salt/salt/engines/master/virtual_node_manager.py @@ -8,9 +8,9 @@ """ Salt Engine for Virtual Node Management -This engine manages the automated provisioning of virtual machines in Security Onion's -virtualization infrastructure. It monitors directories for VM creation requests and -handles the entire provisioning process including hardware allocation. +This engine manages the automated provisioning of virtual machines in Security Onion's +virtualization infrastructure. It processes VM configurations from a nodes file and handles +the entire provisioning process including hardware allocation, state tracking, and file ownership. Usage: engines: @@ -19,31 +19,55 @@ Usage: base_path: /opt/so/saltstack/local/salt/hypervisor/hosts Options: - interval: Time in seconds between directory scans (default: 30) - base_path: Base directory to monitor for VM requests (default: /opt/so/saltstack/local/salt/hypervisor/hosts) + interval: Time in seconds between processing cycles (default: 30) + base_path: Base directory containing hypervisor configurations (default: /opt/so/saltstack/local/salt/hypervisor/hosts) - Memory values in VM configuration YAML files should be specified in GB. These values + Memory values in VM configuration should be specified in GB. These values will automatically be converted to MiB when passed to so-salt-cloud. +Configuration Files: + nodes: JSON file containing VM configurations + - Located at //nodes + - Contains array of VM configurations + - Each VM config specifies hardware and network settings + + defaults.yaml: Hardware capabilities configuration + - Located at /opt/so/saltstack/default/salt/hypervisor/defaults.yaml + - Defines available hardware per model + - Maps hardware indices to PCI IDs + Examples: 1. Basic Configuration: engines: - virtual_node_manager: {} - Uses default settings to monitor for VM requests. + Uses default settings to process VM configurations. - 2. Custom Scan Interval: + 2. Custom Interval: engines: - virtual_node_manager: interval: 60 - Scans for new requests every 60 seconds. + Processes configurations every 60 seconds. + +State Files: + VM Tracking Files: + - : Active VM configuration and status + - _failed: Failed VM creation details + - _invalidHW: Invalid hardware request details + + Lock Files: + - .lock: Prevents concurrent processing of VMs + - Contains VM name and timestamp + - Automatically removed after processing Notes: - Requires 'hvn' feature license - - Monitors for files named: add_sensor, add_searchnode, add_idh, add_receiver, add_heavynode, add_fleet - - Hardware allocation is tracked in hypervisor YAML files - - Creates VM-specific hardware tracking files + - Uses hypervisor's sosmodel grain for hardware capabilities + - Hardware allocation based on model-specific configurations + - All created files maintain socore ownership + - Comprehensive logging for troubleshooting + - Lock files prevent concurrent processing Description: The engine operates in the following phases: @@ -52,22 +76,26 @@ Description: - Verifies 'hvn' feature is licensed - Prevents operation if license is invalid - 2. File Monitoring - - Scans configured directory for add_* files - - Parses VM configuration from YAML + 2. Configuration Processing + - Reads nodes file from each hypervisor directory - Validates configuration parameters + - Compares against existing VM tracking files 3. Hardware Allocation - - Reads hypervisor hardware inventory - - Claims requested PCI devices - - Updates hardware tracking - - Creates VM hardware record + - Retrieves hypervisor model from grains cache + - Loads model-specific hardware capabilities + - Validates hardware requests against model limits + - Converts hardware indices to PCI IDs + - Ensures proper type handling for hardware indices + - Creates state tracking files with socore ownership 4. VM Provisioning - - Executes so-salt-cloud with configuration - - Handles network setup - - Configures hardware passthrough - - Manages VM startup + - Creates lock file to prevent concurrent operations + - Executes so-salt-cloud with validated configuration + - Handles network setup (static/DHCP) + - Configures hardware passthrough with converted PCI IDs + - Updates VM state tracking + - Removes lock file after completion Exit Codes: 0: Success @@ -75,19 +103,41 @@ Exit Codes: 2: Configuration error 3: Hardware allocation failure 4: VM provisioning failure + 5: Invalid hardware request Logging: Log files are written to /opt/so/log/salt/engines/virtual_node_manager.log - Critical operations, errors, and hardware allocation events are logged + Comprehensive logging includes: + - Hardware validation details + - PCI ID conversion process + - Command execution details + - Error conditions with full context + - File ownership operations + - Lock file management """ import os import glob import yaml +import json import time import logging import subprocess -from typing import Dict, List, Optional, Tuple +import pwd +import grp +import salt.config +import salt.runner +from typing import Dict, List, Optional, Tuple, Any +from datetime import datetime + +# Get socore uid/gid +SOCORE_UID = pwd.getpwnam('socore').pw_uid +SOCORE_GID = grp.getgrnam('socore').gr_gid + +# Initialize Salt runner once +opts = salt.config.master_config('/etc/salt/master') +opts['output'] = 'json' +runner = salt.runner.RunnerClient(opts) # Configure logging log = logging.getLogger(__name__) @@ -98,20 +148,52 @@ DEFAULT_INTERVAL = 30 DEFAULT_BASE_PATH = '/opt/so/saltstack/local/salt/hypervisor/hosts' VALID_ROLES = ['sensor', 'searchnode', 'idh', 'receiver', 'heavynode', 'fleet'] LICENSE_PATH = '/opt/so/saltstack/local/pillar/soc/license.sls' +DEFAULTS_PATH = '/opt/so/saltstack/default/salt/hypervisor/defaults.yaml' -def ensure_claimed_section(hw_config: dict) -> dict: +def read_json_file(file_path: str) -> Any: """ - Ensure the claimed section exists and is a dict. - - Args: - hw_config: Hardware configuration section containing 'claimed' key - - Returns: - The claimed section as a dict + Read and parse a JSON file. + Returns an empty array if the file is empty. """ - if hw_config['claimed'] is None or not isinstance(hw_config['claimed'], dict): - hw_config['claimed'] = {} - return hw_config['claimed'] + try: + with open(file_path, 'r') as f: + content = f.read().strip() + if not content: + return [] + return json.loads(content) + except Exception as e: + log.error("Failed to read JSON file %s: %s", file_path, str(e)) + raise + +def set_socore_ownership(path: str) -> None: + """Set socore ownership on file or directory.""" + try: + os.chown(path, SOCORE_UID, SOCORE_GID) + log.debug("Set socore ownership on %s", path) + except Exception as e: + log.error("Failed to set socore ownership on %s: %s", path, str(e)) + raise + +def write_json_file(file_path: str, data: Any) -> None: + """Write data to a JSON file with socore ownership.""" + try: + # Create parent directory if it doesn't exist + os.makedirs(os.path.dirname(file_path), exist_ok=True) + with open(file_path, 'w') as f: + json.dump(data, f, indent=2) + set_socore_ownership(file_path) + except Exception as e: + log.error("Failed to write JSON file %s: %s", file_path, str(e)) + raise + +def read_yaml_file(file_path: str) -> dict: + """Read and parse a YAML file.""" + try: + with open(file_path, 'r') as f: + return yaml.safe_load(f) + except Exception as e: + log.error("Failed to read YAML file %s: %s", file_path, str(e)) + raise def convert_pci_id(pci_id: str) -> str: """ @@ -127,218 +209,245 @@ def convert_pci_id(pci_id: str) -> str: >>> convert_pci_id('pci_0000_c7_00_0') '0000:c7:00.0' """ - # Remove 'pci_' prefix - pci_id = pci_id.replace('pci_', '') - - # Split into components - parts = pci_id.split('_') - if len(parts) != 4: - raise ValueError(f"Invalid PCI ID format: {pci_id}. Expected format: pci_domain_bus_slot_function") + try: + # Remove 'pci_' prefix + pci_id = pci_id.replace('pci_', '') - # Reconstruct with proper format (using period for function) - domain, bus, slot, function = parts - return f"{domain}:{bus}:{slot}.{function}" + # Split into components + parts = pci_id.split('_') + if len(parts) != 4: + raise ValueError(f"Invalid PCI ID format: {pci_id}. Expected format: pci_domain_bus_slot_function") + + # Reconstruct with proper format (using period for function) + domain, bus, slot, function = parts + return f"{domain}:{bus}:{slot}.{function}" + except Exception as e: + log.error("Failed to convert PCI ID %s: %s", pci_id, str(e)) + raise -class HardwareManager: - """ - Manages hardware allocation and tracking for virtual machines. - Handles reading hypervisor configuration, claiming PCI devices, - and maintaining hardware tracking files. +def create_lock_file(hypervisor_path: str, vm_name: str) -> bool: + """Create .lock file for VM processing.""" + lock_file = os.path.join(hypervisor_path, '.lock') + try: + if os.path.exists(lock_file): + log.warning("Lock file already exists at %s", lock_file) + return False + write_json_file(lock_file, { + 'vm': vm_name, + 'timestamp': datetime.now().isoformat() + }) + return True + except Exception as e: + log.error("Failed to create lock file: %s", str(e)) + return False + +def remove_lock_file(hypervisor_path: str) -> None: + """Remove .lock file after processing.""" + lock_file = os.path.join(hypervisor_path, '.lock') + try: + if os.path.exists(lock_file): + os.remove(lock_file) + except Exception as e: + log.error("Failed to remove lock file: %s", str(e)) + +def is_locked(hypervisor_path: str) -> bool: + """Check if hypervisor directory is locked.""" + return os.path.exists(os.path.join(hypervisor_path, '.lock')) + +def get_hypervisor_model(hypervisor: str) -> str: + """Get sosmodel from hypervisor grains.""" + log.info(hypervisor) #MOD + try: + # Get cached grains using Salt runner + grains = runner.cmd( + 'cache.grains', + [f'{hypervisor}_*', 'glob'] + ) + log.info(grains) #MOD + if not grains: + raise ValueError(f"No grains found for hypervisor {hypervisor}") + + # Get the first minion ID that matches our hypervisor + minion_id = next(iter(grains.keys())) + log.info(minion_id) #MOD + model = grains[minion_id].get('sosmodel') + log.info(model) #MOD + if not model: + raise ValueError(f"No sosmodel grain found for hypervisor {hypervisor}") + + log.debug("Found model %s for hypervisor %s", model, hypervisor) + return model + + except Exception as e: + log.error("Failed to get hypervisor model: %s", str(e)) + raise + +def load_hardware_defaults(model: str) -> dict: + """Load hardware configuration from defaults.yaml.""" + try: + defaults = read_yaml_file(DEFAULTS_PATH) + if not defaults or 'hypervisor' not in defaults: + raise ValueError("Invalid defaults.yaml structure") + if 'model' not in defaults['hypervisor']: + raise ValueError("No model configurations found in defaults.yaml") + if model not in defaults['hypervisor']['model']: + raise ValueError(f"Model {model} not found in defaults.yaml") + return defaults['hypervisor']['model'][model] + except Exception as e: + log.error("Failed to load hardware defaults: %s", str(e)) + raise + +def validate_hardware_request(model_config: dict, requested_hw: dict) -> Tuple[bool, Optional[dict]]: """ + Validate hardware request against model capabilities. - def __init__(self, hypervisor: str, base_path: str): - """Initialize the hardware manager for a specific hypervisor.""" - self.hypervisor = hypervisor - self.base_path = base_path - self.hypervisor_file = os.path.join(base_path, hypervisor, f"{hypervisor}.yaml") - - def read_hypervisor_config(self) -> dict: - """ - Read and initialize the hypervisor's hardware configuration file. - Ensures all hardware sections have a valid claimed section. - """ + Returns: + Tuple of (is_valid, error_details) + """ + errors = {} + log.debug("Validating hardware request: %s", requested_hw) + log.debug("Against model config: %s", model_config['hardware']) + + # Validate CPU + if 'cpu' in requested_hw: try: - with open(self.hypervisor_file, 'r') as f: - config = yaml.safe_load(f) - - # Initialize any null claimed sections - modified = False - for hw_type in ['disk', 'copper', 'sfp']: - hw_config = config['hypervisor']['hardware'][hw_type] - if hw_config['claimed'] is None: - log.debug("Initializing null claimed section for %s", hw_type) - hw_config['claimed'] = {} - modified = True - - # Save if we made any changes - if modified: - log.info("Updating hypervisor config with initialized claimed sections") - self.write_hypervisor_config(config) - - return config - except Exception as e: - log.error("Failed to read hypervisor configuration: %s", str(e)) - raise + cpu_count = int(requested_hw['cpu']) + log.debug("Validating CPU request: %d against maximum: %d", + cpu_count, model_config['hardware']['cpu']) + if cpu_count > model_config['hardware']['cpu']: + errors['cpu'] = f"Requested {cpu_count} CPU cores exceeds maximum {model_config['hardware']['cpu']}" + except ValueError: + errors['cpu'] = "Invalid CPU value" - def write_hypervisor_config(self, config: dict) -> None: - """Write updated configuration back to the hypervisor file.""" + # Validate Memory + if 'memory' in requested_hw: try: - with open(self.hypervisor_file, 'w') as f: - yaml.dump(config, f, default_flow_style=False) - except Exception as e: - log.error("Failed to write hypervisor configuration: %s", str(e)) - raise + memory = int(requested_hw['memory']) + log.debug("Validating memory request: %dGB against maximum: %dGB", + memory, model_config['hardware']['memory']) + if memory > model_config['hardware']['memory']: + errors['memory'] = f"Requested {memory}GB memory exceeds maximum {model_config['hardware']['memory']}GB" + except ValueError: + errors['memory'] = "Invalid memory value" - def get_pci_ids(self, hw_type: str, indices: Optional[List[int]]) -> List[str]: - """ - Look up PCI IDs for requested hardware indices. - - Args: - hw_type: Type of hardware (disk, copper, sfp) - indices: List of hardware indices to look up, or None if no hardware requested - - Returns: - List of PCI IDs - """ - # Skip if no indices provided - if indices is None: - return [] - - config = self.read_hypervisor_config() - log.debug("Full config structure: %s", config) - log.debug("Looking up indices %s for hardware type %s", indices, hw_type) - pci_ids = [] - - try: - hardware_section = config['hypervisor']['hardware'] - log.debug("Hardware section: %s", hardware_section) - if hw_type not in hardware_section: - raise ValueError(f"Hardware type {hw_type} not found in configuration") - - hw_config = hardware_section[hw_type] - free_hw = hw_config['free'] - claimed_hw = ensure_claimed_section(hw_config) - - log.debug("Free hardware section for %s: %s", hw_type, free_hw) - log.debug("Claimed hardware section for %s: %s", hw_type, claimed_hw) - - for idx in indices: - if idx in free_hw: - pci_id = convert_pci_id(free_hw[idx]) - log.debug("Converting PCI ID from %s to %s", free_hw[idx], pci_id) - pci_ids.append(pci_id) - elif idx in claimed_hw: - raise ValueError(f"Hardware index {idx} for {hw_type} is already claimed") - else: - raise ValueError(f"Hardware index {idx} for {hw_type} does not exist") - except KeyError as e: - log.error("Invalid hardware configuration structure: %s", str(e)) - raise - - return pci_ids + # Validate PCI devices + for hw_type in ['disk', 'copper', 'sfp']: + if hw_type in requested_hw and requested_hw[hw_type]: + try: + indices = [int(x) for x in str(requested_hw[hw_type]).split(',')] + log.debug("Validating %s indices: %s", hw_type, indices) + + if hw_type not in model_config['hardware']: + log.error("Hardware type %s not found in model config", hw_type) + errors[hw_type] = f"No {hw_type} configuration found in model" + continue + + available_indices = set(int(k) for k in model_config['hardware'][hw_type].keys()) + log.debug("Available %s indices: %s", hw_type, available_indices) + + invalid_indices = [idx for idx in indices if idx not in available_indices] + if invalid_indices: + log.error("Invalid %s indices found: %s", hw_type, invalid_indices) + errors[hw_type] = f"Invalid {hw_type} indices: {invalid_indices}" + except ValueError: + log.error("Invalid %s indices format: %s", hw_type, requested_hw[hw_type]) + errors[hw_type] = f"Invalid {hw_type} indices format" + except KeyError: + log.error("No %s configuration found in model", hw_type) + errors[hw_type] = f"No {hw_type} configuration found in model" - def claim_cpu_memory(self, cpu_count: Optional[int], memory_gb: Optional[int]) -> None: - """ - Claim CPU cores and memory from the free pool. + if errors: + log.error("Hardware validation failed with errors: %s", errors) + else: + log.debug("Hardware validation successful") - Args: - cpu_count: Number of CPU cores to claim, or None if no CPU requested - memory_gb: Amount of memory in GB to claim, or None if no memory requested - - Raises: - ValueError: If requested resources exceed available resources - """ - if cpu_count is None and memory_gb is None: - return - - config = self.read_hypervisor_config() - hw_config = config['hypervisor']['hardware'] - - # Validate and claim CPU cores - if cpu_count is not None: - if cpu_count > hw_config['cpu']['free']: - raise ValueError(f"Not enough CPU cores available. Requested: {cpu_count}, Free: {hw_config['cpu']['free']}") - hw_config['cpu']['free'] -= cpu_count - - # Validate and claim memory - if memory_gb is not None: - if memory_gb > hw_config['memory']['free']: - raise ValueError(f"Not enough memory available. Requested: {memory_gb}GB, Free: {hw_config['memory']['free']}GB") - hw_config['memory']['free'] -= memory_gb - - self.write_hypervisor_config(config) - log.info("Successfully claimed CPU cores: %s, Memory: %sGB", cpu_count, memory_gb) + return (len(errors) == 0, errors if errors else None) - def release_cpu_memory(self, cpu_count: Optional[int], memory_gb: Optional[int]) -> None: - """ - Release CPU cores and memory back to the free pool. - - Args: - cpu_count: Number of CPU cores to release, or None if no CPU to release - memory_gb: Amount of memory in GB to release, or None if no memory to release - """ - if cpu_count is None and memory_gb is None: - return +def check_hardware_availability(hypervisor_path: str, vm_name: str) -> bool: + """Check if requested hardware is already claimed by another VM.""" + try: + # List all VM tracking files + files = glob.glob(os.path.join(hypervisor_path, '*_*')) + for file_path in files: + # Skip the VM we're checking and any failed/invalid VMs + basename = os.path.basename(file_path) + if basename.startswith(vm_name) or '_failed' in basename or '_invalidHW' in basename: + continue - config = self.read_hypervisor_config() - hw_config = config['hypervisor']['hardware'] - - # Return CPU cores to free pool - if cpu_count is not None: - hw_config['cpu']['free'] += cpu_count - - # Return memory to free pool - if memory_gb is not None: - hw_config['memory']['free'] += memory_gb - - self.write_hypervisor_config(config) - log.info("Successfully released CPU cores: %s, Memory: %sGB", cpu_count, memory_gb) + # Check if any hardware overlaps + vm_config = read_json_file(file_path) + if 'hardware' in vm_config and 'allocated' in vm_config['hardware']: + # TODO: Implement hardware conflict checking + pass + return True + except Exception as e: + log.error("Failed to check hardware availability: %s", str(e)) + return False - def claim_hardware(self, hw_type: str, indices: List[int]) -> None: - """ - Move hardware from free to claimed in the hypervisor configuration. +def create_vm_tracking_file(hypervisor_path: str, vm_name: str, config: dict) -> None: + """Create VM tracking file with initial state.""" + file_path = os.path.join(hypervisor_path, vm_name) + log.debug("Creating VM tracking file at %s", file_path) + try: + # Create parent directory if it doesn't exist + os.makedirs(os.path.dirname(file_path), exist_ok=True) + set_socore_ownership(os.path.dirname(file_path)) - Args: - hw_type: Type of hardware (disk, copper, sfp) - indices: List of hardware indices to claim - """ - config = self.read_hypervisor_config() - - try: - hw_config = config['hypervisor']['hardware'][hw_type] - ensure_claimed_section(hw_config) - - for idx in indices: - if idx in hw_config['free']: - pci_id = hw_config['free'][idx] - hw_config['claimed'][idx] = pci_id - del hw_config['free'][idx] - else: - raise ValueError(f"{hw_type} hardware index {idx} not available") - - self.write_hypervisor_config(config) - log.info("Successfully claimed %s hardware indices: %s", hw_type, indices) - except Exception as e: - log.error("Failed to claim hardware: %s", str(e)) - raise + data = { + 'config': config, + 'status': 'creating', + 'hardware': { + 'allocated': {} + } + } + # Write file and set ownership + with open(file_path, 'w') as f: + json.dump(data, f, indent=2) + set_socore_ownership(file_path) + log.debug("Successfully created VM tracking file with socore ownership") + except Exception as e: + log.error("Failed to create VM tracking file: %s", str(e)) + raise - def create_vm_hardware_file(self, hostname: str, role: str, hardware: dict) -> None: - """ - Create a YAML file tracking hardware allocated to a VM. - - Args: - hostname: Name of the VM - role: VM role (sensor, searchnode, etc.) - hardware: Dictionary of allocated hardware - """ - vm_file = os.path.join(self.base_path, self.hypervisor, f"{hostname}_{role}.yaml") - try: - with open(vm_file, 'w') as f: - yaml.dump({'hardware': hardware}, f, default_flow_style=False) - log.info("Created hardware tracking file for %s_%s", hostname, role) - except Exception as e: - log.error("Failed to create VM hardware file: %s", str(e)) - raise +def mark_vm_failed(vm_file: str, error_code: int, message: str) -> None: + """Mark VM as failed with error details.""" + try: + # Rename file to add _failed suffix if not already present + if not vm_file.endswith('_failed'): + new_file = f"{vm_file}_failed" + os.rename(vm_file, new_file) + vm_file = new_file + + # Update file contents + data = read_json_file(vm_file) + data['status'] = 'failed' + data['error'] = { + 'code': error_code, + 'message': message, + 'timestamp': datetime.now().isoformat() + } + write_json_file(vm_file, data) + except Exception as e: + log.error("Failed to mark VM as failed: %s", str(e)) + raise + +def mark_invalid_hardware(hypervisor_path: str, vm_name: str, config: dict, error_details: dict) -> None: + """Create invalid hardware tracking file with error details.""" + file_path = os.path.join(hypervisor_path, f"{vm_name}_invalidHW") + try: + data = { + 'config': config, + 'error': { + 'code': 5, + 'message': "Invalid hardware configuration", + 'invalid_hardware': error_details, + 'timestamp': datetime.now().isoformat() + } + } + write_json_file(file_path, data) + except Exception as e: + log.error("Failed to create invalid hardware file: %s", str(e)) + raise def validate_hvn_license() -> bool: """Check if the license file exists and contains required values.""" @@ -374,211 +483,215 @@ def validate_hvn_license() -> bool: log.error("LICENSE: Error reading license file: %s", str(e)) return False -def parse_add_file(file_path: str) -> Tuple[str, str, dict]: - """ - Parse an add_* file to extract VM configuration. +def process_vm_creation(hypervisor_path: str, vm_config: dict) -> None: + """Process a single VM creation request.""" + # Get the actual hypervisor name (last directory in path) + hypervisor = os.path.basename(hypervisor_path) + vm_name = f"{vm_config['hostname']}_{vm_config['role']}" - Returns: - Tuple of (hypervisor, role, config) - """ try: - # Extract hypervisor and role from path - path_parts = file_path.split(os.path.sep) - hypervisor = path_parts[-2] - role = path_parts[-1].replace('add_', '') - - if role not in VALID_ROLES: - raise ValueError(f"Invalid role: {role}") - - # Read and parse YAML configuration - with open(file_path, 'r') as f: - config = yaml.safe_load(f) - - required_fields = ['hostname', 'network_mode'] - if config.get('network_mode') == 'static4': - required_fields.extend(['ip4', 'gw4']) - - for field in required_fields: - if field not in config: - raise ValueError(f"Missing required field: {field}") - - # Validate hardware sections - for hw_type in ['disk', 'copper', 'sfp']: - if hw_type in config and config[hw_type] is not None: - if not isinstance(config[hw_type], list): - raise ValueError(f"{hw_type} must be a list when present") - - return hypervisor, role, config - except Exception as e: - log.error("Failed to parse add file %s: %s", file_path, str(e)) - raise + # Create lock file + if not create_lock_file(hypervisor_path, vm_name): + return -def convert_gb_to_mib(gb: int) -> int: - """ - Convert memory value from GB to MiB. - - Args: - gb: Memory value in gigabytes - - Returns: - Memory value in mebibytes (1 GB = 1024 MiB) - """ - return gb * 1024 + # Get hypervisor model and capabilities + model = get_hypervisor_model(hypervisor) + model_config = load_hardware_defaults(model) -def execute_salt_cloud(profile: str, hostname: str, role: str, config: dict, pci_ids: List[str]) -> None: - """ - Execute so-salt-cloud to create the VM. - - Args: - profile: Salt cloud profile name - hostname: VM hostname - role: VM role - config: VM configuration - pci_ids: List of PCI IDs for hardware passthrough - """ - try: - cmd = ['so-salt-cloud', '-p', f'sool9-{profile}', f'{hostname}_{role}'] + # Validate hardware request + is_valid, errors = validate_hardware_request(model_config, vm_config) + if not is_valid: + mark_invalid_hardware(hypervisor_path, vm_name, vm_config, errors) + return + + # Check hardware availability + if not check_hardware_availability(hypervisor_path, vm_name): + mark_vm_failed(os.path.join(hypervisor_path, vm_name), 3, + "Requested hardware is already in use") + return + + # Create tracking file + create_vm_tracking_file(hypervisor_path, vm_name, vm_config) + + # Build so-salt-cloud command + log.debug("Building so-salt-cloud command for VM %s", vm_name) + cmd = ['so-salt-cloud', '-p', f'sool9-{hypervisor}', vm_name] + log.debug("Base command: %s", ' '.join(cmd)) # Add network configuration - if config['network_mode'] == 'static4': - cmd.extend(['--static4', '--ip4', config['ip4'], '--gw4', config['gw4']]) - if 'dns4' in config: - cmd.extend(['--dns4', ','.join(config['dns4'])]) - if 'search4' in config: - cmd.extend(['--search4', config['search4']]) + if vm_config['network_mode'] == 'static4': + log.debug("Adding static network configuration") + cmd.extend(['--static4', '--ip4', vm_config['ip4'], '--gw4', vm_config['gw4']]) + if 'dns4' in vm_config: + cmd.extend(['--dns4', vm_config['dns4']]) + if 'search4' in vm_config: + cmd.extend(['--search4', vm_config['search4']]) else: + log.debug("Using DHCP network configuration") cmd.append('--dhcp4') # Add hardware configuration - if 'cpu' in config: - cmd.extend(['-c', str(config['cpu'])]) - if 'memory' in config: - # Convert memory from GB to MiB for so-salt-cloud - memory_mib = convert_gb_to_mib(config['memory']) + if 'cpu' in vm_config: + log.debug("Adding CPU configuration: %s cores", vm_config['cpu']) + cmd.extend(['-c', str(vm_config['cpu'])]) + if 'memory' in vm_config: + memory_mib = int(vm_config['memory']) * 1024 + log.debug("Adding memory configuration: %sGB (%sMiB)", vm_config['memory'], memory_mib) cmd.extend(['-m', str(memory_mib)]) - # Add PCI devices - for pci_id in pci_ids: - cmd.extend(['-P', pci_id]) - - log.info("Executing: %s", ' '.join(cmd)) - subprocess.run(cmd, check=True) - except subprocess.CalledProcessError as e: - log.error("so-salt-cloud execution failed: %s", str(e)) - raise - except Exception as e: - log.error("Failed to execute so-salt-cloud: %s", str(e)) - raise - -def release_hardware(hw_manager: HardwareManager, hw_type: str, indices: List[int], - cpu_count: Optional[int] = None, memory_gb: Optional[int] = None) -> None: - """ - Release claimed hardware back to free pool. - - Args: - hw_manager: HardwareManager instance - hw_type: Type of hardware (disk, copper, sfp) - indices: List of hardware indices to release - cpu_count: Number of CPU cores to release, or None if no CPU to release - memory_gb: Amount of memory in GB to release, or None if no memory to release - """ - config = hw_manager.read_hypervisor_config() - hw_config = config['hypervisor']['hardware'][hw_type] - - for idx in indices: - if idx in hw_config['claimed']: - pci_id = hw_config['claimed'][idx] - hw_config['free'][idx] = pci_id - del hw_config['claimed'][idx] - - hw_manager.write_hypervisor_config(config) - log.info("Released %s hardware indices: %s", hw_type, indices) - -def process_add_file(file_path: str, base_path: str) -> None: - """ - Process a single add_* file for VM creation. - - Args: - file_path: Path to the add_* file - base_path: Base path for hypervisor configuration - """ - try: - hypervisor, role, config = parse_add_file(file_path) - log.debug("Parsed config from add file: %s", config) - hw_manager = HardwareManager(hypervisor, base_path) - - # Phase 1: Collect all hardware information without claiming - pci_ids = [] - hardware_to_claim = {} # Store hardware to claim for each type - hardware_tracking = { - 'cpu': config.get('cpu'), - 'memory': config.get('memory') - } - - # Validate all hardware first + # Add PCI devices with proper conversion for hw_type in ['disk', 'copper', 'sfp']: - indices = config.get(hw_type) - if indices is not None: - # Validate indices are available before claiming - hw_pci_ids = hw_manager.get_pci_ids(hw_type, indices) - if hw_pci_ids: - hardware_to_claim[hw_type] = indices - pci_ids.extend(hw_pci_ids) - hardware_tracking[hw_type] = [ - {'id': idx, 'pci': pci_id} - for idx, pci_id in zip(indices, hw_pci_ids) - ] - - # Phase 2: Claim hardware only after all validation passes + if hw_type in vm_config and vm_config[hw_type]: + log.debug("Processing %s hardware configuration", hw_type) + indices = [int(x) for x in str(vm_config[hw_type]).split(',')] + log.debug("Requested %s indices: %s", hw_type, indices) + for idx in indices: + try: + log.debug("Looking up PCI ID for %s index %d in model config", hw_type, idx) + log.debug("Model config for %s: %s", hw_type, model_config['hardware'][hw_type]) + + # Convert all keys to integers for comparison + hw_config = {int(k): v for k, v in model_config['hardware'][hw_type].items()} + log.debug("Converted hardware config: %s", hw_config) + + pci_id = hw_config[idx] + log.debug("Found PCI ID for %s index %d: %s", hw_type, idx, pci_id) + converted_pci_id = convert_pci_id(pci_id) + log.debug("Converted PCI ID from %s to %s", pci_id, converted_pci_id) + cmd.extend(['-P', converted_pci_id]) + except Exception as e: + log.error("Failed to process PCI ID for %s index %d: %s", hw_type, idx, str(e)) + log.error("Hardware config keys: %s, looking for index: %s", + list(model_config['hardware'][hw_type].keys()), idx) + raise + + # Execute so-salt-cloud + log.info("Executing command: %s", ' '.join(cmd)) try: - # Claim CPU and memory first - cpu_count = config.get('cpu') - memory_gb = config.get('memory') - hw_manager.claim_cpu_memory(cpu_count, memory_gb) - - # Then claim PCI hardware - for hw_type, indices in hardware_to_claim.items(): - hw_manager.claim_hardware(hw_type, indices) - - # Create VM - execute_salt_cloud(hypervisor, config['hostname'], role, config, pci_ids) - - # Create hardware tracking file - hw_manager.create_vm_hardware_file(config['hostname'], role, hardware_tracking) - - log.info("Successfully processed VM creation request: %s_%s", - config['hostname'], role) - - except Exception as e: - # If anything fails after claiming, release all hardware - log.error("Failed after hardware claim, attempting to release hardware: %s", str(e)) - - # Release CPU and memory - try: - hw_manager.release_cpu_memory(cpu_count, memory_gb) - except Exception as release_error: - log.error("Failed to release CPU/memory: %s", str(release_error)) - - # Release PCI hardware - for hw_type, indices in hardware_to_claim.items(): - try: - release_hardware(hw_manager, hw_type, indices) - except Exception as release_error: - log.error("Failed to release %s hardware %s: %s", - hw_type, indices, str(release_error)) + result = subprocess.run(cmd, capture_output=True, text=True, check=True) + log.debug("Command completed successfully") + log.debug("Command stdout: %s", result.stdout) + if result.stderr: + log.warning("Command stderr (non-fatal): %s", result.stderr) + except subprocess.CalledProcessError as e: + error_msg = f"so-salt-cloud execution failed (code {e.returncode})" + if e.stdout: + log.error("Command stdout: %s", e.stdout) + if e.stderr: + log.error("Command stderr: %s", e.stderr) + error_msg = f"{error_msg}: {e.stderr}" + log.error(error_msg) + mark_vm_failed(os.path.join(hypervisor_path, vm_name), 4, error_msg) raise - - finally: - # Always clean up the add file - try: - os.remove(file_path) - log.info("Cleaned up add file: %s", file_path) - except Exception as e: - log.error("Failed to clean up add file: %s", str(e)) - - except Exception as e: - log.error("Failed to process add file %s: %s", file_path, str(e)) + + # Update tracking file status + tracking_file = os.path.join(hypervisor_path, vm_name) + data = read_json_file(tracking_file) + data['status'] = 'running' + write_json_file(tracking_file, data) + log.info("Successfully updated VM status to running") + + except subprocess.CalledProcessError as e: + error_msg = f"so-salt-cloud execution failed (code {e.returncode})" + if e.stdout: + log.error("Command stdout: %s", e.stdout) + if e.stderr: + log.error("Command stderr: %s", e.stderr) + error_msg = f"{error_msg}: {e.stderr}" + log.error(error_msg) + mark_vm_failed(os.path.join(hypervisor_path, vm_name), 4, error_msg) raise + except Exception as e: + error_msg = f"VM creation failed: {str(e)}" + log.error(error_msg) + # If we haven't created the tracking file yet, create a failed one + if not os.path.exists(os.path.join(hypervisor_path, vm_name)): + mark_vm_failed(os.path.join(hypervisor_path, f"{vm_name}_failed"), 4, error_msg) + finally: + remove_lock_file(hypervisor_path) + +def process_vm_deletion(hypervisor_path: str, vm_name: str) -> None: + """Process a single VM deletion request.""" + try: + if not create_lock_file(hypervisor_path, vm_name): + return + + # Get the actual hypervisor name (last directory in path) + hypervisor = os.path.basename(hypervisor_path) + cmd = ['so-salt-cloud', '-p', f'sool9-{hypervisor}', vm_name, '-yd'] + + log.info("Executing: %s", ' '.join(cmd)) + result = subprocess.run(cmd, capture_output=True, text=True) + + # Log command output + if result.stdout: + log.debug("Command stdout: %s", result.stdout) + if result.stderr: + log.warning("Command stderr: %s", result.stderr) + + # Check return code + if result.returncode != 0: + error_msg = f"so-salt-cloud deletion failed (code {result.returncode}): {result.stderr}" + log.error(error_msg) + raise subprocess.CalledProcessError( + result.returncode, cmd, + output=result.stdout, + stderr=result.stderr + ) + + # Remove VM tracking file + vm_file = os.path.join(hypervisor_path, vm_name) + if os.path.exists(vm_file): + os.remove(vm_file) + log.info("Successfully removed VM tracking file") + + except Exception as e: + log.error("Error processing VM deletion: %s", str(e)) + raise + finally: + remove_lock_file(hypervisor_path) + +def process_hypervisor(hypervisor_path: str) -> None: + """Process VM configurations for a single hypervisor.""" + try: + if is_locked(hypervisor_path): + return + + # Read nodes file + nodes_file = os.path.join(hypervisor_path, 'nodes') + if not os.path.exists(nodes_file): + return + + nodes_config = read_json_file(nodes_file) + if not nodes_config: + return + + # Get existing VMs + existing_vms = set() + for file_path in glob.glob(os.path.join(hypervisor_path, '*_*')): + basename = os.path.basename(file_path) + if not any(x in basename for x in ['_failed', '_invalidHW']): + existing_vms.add(basename) + + # Process new VMs + configured_vms = set() + for vm_config in nodes_config: + if 'hostname' not in vm_config or 'role' not in vm_config: + log.error("Invalid VM configuration: missing hostname or role") + continue + + vm_name = f"{vm_config['hostname']}_{vm_config['role']}" + configured_vms.add(vm_name) + + if vm_name not in existing_vms: + process_vm_creation(hypervisor_path, vm_config) + + # Process VM deletions + for vm_name in existing_vms - configured_vms: + process_vm_deletion(hypervisor_path, vm_name) + + except Exception as e: + log.error("Failed to process hypervisor %s: %s", hypervisor_path, str(e)) def start(interval: int = DEFAULT_INTERVAL, base_path: str = DEFAULT_BASE_PATH) -> None: @@ -586,8 +699,8 @@ def start(interval: int = DEFAULT_INTERVAL, Main engine loop. Args: - interval: Time in seconds between directory scans - base_path: Base path to monitor for VM requests + interval: Time in seconds between processing cycles + base_path: Base path containing hypervisor configurations """ log.info("Starting virtual node manager engine") @@ -596,23 +709,11 @@ def start(interval: int = DEFAULT_INTERVAL, while True: try: - pattern = os.path.join(base_path, '*', 'add_*') - log.debug("Scanning for VM request files with pattern: %s", pattern) - - try: - files = glob.glob(pattern) - if files: - log.debug("Found %d VM request file(s): %s", len(files), files) - - for file_path in files: - log.info("Processing VM request file: %s", file_path) - try: - process_add_file(file_path, base_path) - except Exception as e: - log.error("Failed to process file %s: %s", file_path, str(e)) - except Exception as e: - log.error("Error scanning for VM request files: %s", str(e)) - + # Process each hypervisor directory + for hypervisor_path in glob.glob(os.path.join(base_path, '*')): + if os.path.isdir(hypervisor_path): + process_hypervisor(hypervisor_path) + except Exception as e: log.error("Error in main engine loop: %s", str(e)) diff --git a/salt/soc/dyanno/hypervisor/hypervisor.yaml b/salt/soc/dyanno/hypervisor/hypervisor.yaml index 3a5d000a9..2b9a0d70e 100644 --- a/salt/soc/dyanno/hypervisor/hypervisor.yaml +++ b/salt/soc/dyanno/hypervisor/hypervisor.yaml @@ -21,8 +21,7 @@ hypervisor: uiElements: - field: hostname label: Enter the hostname - forcedType: string - - field: nodetype + - field: role label: sensor or searchnode - field: network_mode label: Choose static4 or dhcp4. If static4, populate IP details below. @@ -31,7 +30,7 @@ hypervisor: - field: gw4 label: Gateway - field: dns4 - label: DNS. Comma seperated list. ex. 192.168.1.1,8.8.8.8 + label: DNS. Comma separated list. ex. 192.168.1.1,8.8.8.8 - field: search4 label: Search domain - field: cpu @@ -39,11 +38,11 @@ hypervisor: - field: memory label: Memory, in GB to assign. ex. 16 - field: disk - label: Choose a disk or disks to assign for passthrough. Comma seperated list. + label: Choose a disk or disks to assign for passthrough. Comma separated list. - field: copper - label: Choose a copper port or ports to assign for passthrough. Comma seperated list. - - filed: sfp - label: Choose a sfp port or ports to assign for passthrough. Comma seperated list. + label: Choose a copper port or ports to assign for passthrough. Comma separated list. + - field: sfp + label: Choose a sfp port or ports to assign for passthrough. Comma separated list. file: true global: true diff --git a/salt/soc/dyanno/hypervisor/init.sls b/salt/soc/dyanno/hypervisor/init.sls index 31fe5ec93..a0b83fd5d 100644 --- a/salt/soc/dyanno/hypervisor/init.sls +++ b/salt/soc/dyanno/hypervisor/init.sls @@ -14,5 +14,10 @@ hypervisor_host_directory_{{hypervisor}}: file.directory: - name: /opt/so/saltstack/local/salt/hypervisor/hosts/{{hypervisor}} - makedirs: True + - user: socore + - group: socore + - recurse: + - user + - group {% endfor %} {% endfor %} From ad54afe39a7c529f68ff69b85acab7d8ecc935b0 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Sat, 15 Feb 2025 12:11:23 -0500 Subject: [PATCH 127/315] ensure socore:socore ownership --- salt/manager/tools/sbin/so-minion | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/salt/manager/tools/sbin/so-minion b/salt/manager/tools/sbin/so-minion index fad765756..cc78e69e1 100755 --- a/salt/manager/tools/sbin/so-minion +++ b/salt/manager/tools/sbin/so-minion @@ -272,6 +272,15 @@ function deleteMinionFiles () { } # Create the minion file +function ensure_socore_ownership() { + log "INFO" "Setting socore ownership on minion files" + chown -R socore:socore /opt/so/saltstack/local/pillar/minions/ + if [ $? -ne 0 ]; then + log "ERROR" "Failed to set socore ownership on minion files" + return 1 + fi +} + function create_minion_files() { mkdir -p /opt/so/saltstack/local/pillar/minions if [ $? -ne 0 ]; then @@ -292,6 +301,9 @@ function create_minion_files() { return 1 fi fi + + # Set proper ownership after file creation + ensure_socore_ownership || return 1 } # Add Elastic settings to the minion file @@ -996,6 +1008,9 @@ function setupMinionFiles() { # Create node-specific configuration create$NODETYPE || return 1 + # Ensure proper ownership after all content is written + ensure_socore_ownership || return 1 + log "INFO" "Successfully created minion files for $MINION_ID" } From ec2fc0a5f2740aee9d2a67b47aef9518dda09ed5 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Sat, 15 Feb 2025 18:56:04 -0500 Subject: [PATCH 128/315] change locking method --- .../engines/master/virtual_node_manager.py | 302 ++++++++---------- 1 file changed, 137 insertions(+), 165 deletions(-) diff --git a/salt/salt/engines/master/virtual_node_manager.py b/salt/salt/engines/master/virtual_node_manager.py index 80e49813a..5cce857b4 100644 --- a/salt/salt/engines/master/virtual_node_manager.py +++ b/salt/salt/engines/master/virtual_node_manager.py @@ -19,7 +19,7 @@ Usage: base_path: /opt/so/saltstack/local/salt/hypervisor/hosts Options: - interval: Time in seconds between processing cycles (default: 30) + interval: Time in seconds between engine runs (managed by salt-master, default: 30) base_path: Base directory containing hypervisor configurations (default: /opt/so/saltstack/local/salt/hypervisor/hosts) Memory values in VM configuration should be specified in GB. These values @@ -55,47 +55,52 @@ State Files: - : Active VM configuration and status - _failed: Failed VM creation details - _invalidHW: Invalid hardware request details - - Lock Files: - - .lock: Prevents concurrent processing of VMs - - Contains VM name and timestamp - - Automatically removed after processing - Notes: - Requires 'hvn' feature license - Uses hypervisor's sosmodel grain for hardware capabilities - Hardware allocation based on model-specific configurations - All created files maintain socore ownership - Comprehensive logging for troubleshooting - - Lock files prevent concurrent processing + - Single engine-wide lock prevents concurrent instances + - Lock remains if error occurs (requires admin intervention) Description: - The engine operates in the following phases: + The engine operates in the following phases: - 1. License Validation - - Verifies 'hvn' feature is licensed - - Prevents operation if license is invalid + 1. Engine Lock Acquisition + - Acquires single engine-wide lock + - Prevents multiple instances from running + - Lock remains until clean shutdown or error - 2. Configuration Processing - - Reads nodes file from each hypervisor directory - - Validates configuration parameters - - Compares against existing VM tracking files + 2. License Validation + - Verifies 'hvn' feature is licensed + - Prevents operation if license is invalid - 3. Hardware Allocation - - Retrieves hypervisor model from grains cache - - Loads model-specific hardware capabilities - - Validates hardware requests against model limits - - Converts hardware indices to PCI IDs - - Ensures proper type handling for hardware indices - - Creates state tracking files with socore ownership + 3. Configuration Processing + - Reads nodes file from each hypervisor directory + - Validates configuration parameters + - Compares against existing VM tracking files - 4. VM Provisioning - - Creates lock file to prevent concurrent operations - - Executes so-salt-cloud with validated configuration - - Handles network setup (static/DHCP) - - Configures hardware passthrough with converted PCI IDs - - Updates VM state tracking - - Removes lock file after completion + 4. Hardware Allocation + - Retrieves hypervisor model from grains cache + - Loads model-specific hardware capabilities + - Validates hardware requests against model limits + - Converts hardware indices to PCI IDs + - Ensures proper type handling for hardware indices + - Creates state tracking files with socore ownership + + 5. VM Provisioning + - Executes so-salt-cloud with validated configuration + - Handles network setup (static/DHCP) + - Configures hardware passthrough with converted PCI IDs + - Updates VM state tracking + + Lock Management: + - Lock acquired at engine start + - Released only on clean shutdown + - Remains if error occurs + - Admin must restart service to clear lock + - Error-level logging for lock issues Exit Codes: 0: Success @@ -129,6 +134,7 @@ import salt.config import salt.runner from typing import Dict, List, Optional, Tuple, Any from datetime import datetime +from threading import Lock # Get socore uid/gid SOCORE_UID = pwd.getpwnam('socore').pw_uid @@ -150,6 +156,9 @@ VALID_ROLES = ['sensor', 'searchnode', 'idh', 'receiver', 'heavynode', 'fleet'] LICENSE_PATH = '/opt/so/saltstack/local/pillar/soc/license.sls' DEFAULTS_PATH = '/opt/so/saltstack/default/salt/hypervisor/defaults.yaml' +# Single engine-wide lock for virtual node manager +engine_lock = Lock() + def read_json_file(file_path: str) -> Any: """ Read and parse a JSON file. @@ -225,53 +234,20 @@ def convert_pci_id(pci_id: str) -> str: log.error("Failed to convert PCI ID %s: %s", pci_id, str(e)) raise -def create_lock_file(hypervisor_path: str, vm_name: str) -> bool: - """Create .lock file for VM processing.""" - lock_file = os.path.join(hypervisor_path, '.lock') - try: - if os.path.exists(lock_file): - log.warning("Lock file already exists at %s", lock_file) - return False - write_json_file(lock_file, { - 'vm': vm_name, - 'timestamp': datetime.now().isoformat() - }) - return True - except Exception as e: - log.error("Failed to create lock file: %s", str(e)) - return False - -def remove_lock_file(hypervisor_path: str) -> None: - """Remove .lock file after processing.""" - lock_file = os.path.join(hypervisor_path, '.lock') - try: - if os.path.exists(lock_file): - os.remove(lock_file) - except Exception as e: - log.error("Failed to remove lock file: %s", str(e)) - -def is_locked(hypervisor_path: str) -> bool: - """Check if hypervisor directory is locked.""" - return os.path.exists(os.path.join(hypervisor_path, '.lock')) - def get_hypervisor_model(hypervisor: str) -> str: """Get sosmodel from hypervisor grains.""" - log.info(hypervisor) #MOD try: # Get cached grains using Salt runner grains = runner.cmd( 'cache.grains', [f'{hypervisor}_*', 'glob'] ) - log.info(grains) #MOD if not grains: raise ValueError(f"No grains found for hypervisor {hypervisor}") # Get the first minion ID that matches our hypervisor minion_id = next(iter(grains.keys())) - log.info(minion_id) #MOD model = grains[minion_id].get('sosmodel') - log.info(model) #MOD if not model: raise ValueError(f"No sosmodel grain found for hypervisor {hypervisor}") @@ -452,7 +428,7 @@ def mark_invalid_hardware(hypervisor_path: str, vm_name: str, config: dict, erro def validate_hvn_license() -> bool: """Check if the license file exists and contains required values.""" if not os.path.exists(LICENSE_PATH): - log.error("LICENSE: License file not found at %s", LICENSE_PATH) + log.error("License file not found at %s", LICENSE_PATH) return False try: @@ -460,14 +436,14 @@ def validate_hvn_license() -> bool: license_data = yaml.safe_load(f) if not license_data: - log.error("LICENSE: Empty or invalid license file") + log.error("Empty or invalid license file") return False license_id = license_data.get('license_id') features = license_data.get('features', []) if not license_id: - log.error("LICENSE: No license_id found in license file") + log.error("No license_id found in license file") return False if 'hvn' not in features: @@ -476,29 +452,35 @@ def validate_hvn_license() -> bool: "for more information about purchasing a license to enable this feature.") return False - log.info("LICENSE: License validation successful") + log.info("License validation successful") return True except Exception as e: - log.error("LICENSE: Error reading license file: %s", str(e)) + log.error("Error reading license file: %s", str(e)) return False def process_vm_creation(hypervisor_path: str, vm_config: dict) -> None: - """Process a single VM creation request.""" + """ + Process a single VM creation request. + + This function handles the creation of a new VM, including hardware validation, + resource allocation, and provisioning. All operations are protected by the + engine-wide lock that is acquired at engine start. + + Args: + hypervisor_path: Path to the hypervisor directory + vm_config: Dictionary containing VM configuration + """ # Get the actual hypervisor name (last directory in path) hypervisor = os.path.basename(hypervisor_path) vm_name = f"{vm_config['hostname']}_{vm_config['role']}" try: - # Create lock file - if not create_lock_file(hypervisor_path, vm_name): - return - # Get hypervisor model and capabilities model = get_hypervisor_model(hypervisor) model_config = load_hardware_defaults(model) - # Validate hardware request + # Initial hardware validation is_valid, errors = validate_hardware_request(model_config, vm_config) if not is_valid: mark_invalid_hardware(hypervisor_path, vm_name, vm_config, errors) @@ -506,97 +488,55 @@ def process_vm_creation(hypervisor_path: str, vm_config: dict) -> None: # Check hardware availability if not check_hardware_availability(hypervisor_path, vm_name): - mark_vm_failed(os.path.join(hypervisor_path, vm_name), 3, - "Requested hardware is already in use") + mark_vm_failed(os.path.join(hypervisor_path, vm_name), 3, + "Requested hardware is already in use") return # Create tracking file create_vm_tracking_file(hypervisor_path, vm_name, vm_config) - # Build so-salt-cloud command - log.debug("Building so-salt-cloud command for VM %s", vm_name) + # Build and execute so-salt-cloud command cmd = ['so-salt-cloud', '-p', f'sool9-{hypervisor}', vm_name] - log.debug("Base command: %s", ' '.join(cmd)) # Add network configuration if vm_config['network_mode'] == 'static4': - log.debug("Adding static network configuration") cmd.extend(['--static4', '--ip4', vm_config['ip4'], '--gw4', vm_config['gw4']]) if 'dns4' in vm_config: cmd.extend(['--dns4', vm_config['dns4']]) if 'search4' in vm_config: cmd.extend(['--search4', vm_config['search4']]) else: - log.debug("Using DHCP network configuration") cmd.append('--dhcp4') # Add hardware configuration if 'cpu' in vm_config: - log.debug("Adding CPU configuration: %s cores", vm_config['cpu']) cmd.extend(['-c', str(vm_config['cpu'])]) if 'memory' in vm_config: memory_mib = int(vm_config['memory']) * 1024 - log.debug("Adding memory configuration: %sGB (%sMiB)", vm_config['memory'], memory_mib) cmd.extend(['-m', str(memory_mib)]) - # Add PCI devices with proper conversion + # Add PCI devices for hw_type in ['disk', 'copper', 'sfp']: if hw_type in vm_config and vm_config[hw_type]: - log.debug("Processing %s hardware configuration", hw_type) indices = [int(x) for x in str(vm_config[hw_type]).split(',')] - log.debug("Requested %s indices: %s", hw_type, indices) for idx in indices: - try: - log.debug("Looking up PCI ID for %s index %d in model config", hw_type, idx) - log.debug("Model config for %s: %s", hw_type, model_config['hardware'][hw_type]) - - # Convert all keys to integers for comparison - hw_config = {int(k): v for k, v in model_config['hardware'][hw_type].items()} - log.debug("Converted hardware config: %s", hw_config) - - pci_id = hw_config[idx] - log.debug("Found PCI ID for %s index %d: %s", hw_type, idx, pci_id) - converted_pci_id = convert_pci_id(pci_id) - log.debug("Converted PCI ID from %s to %s", pci_id, converted_pci_id) - cmd.extend(['-P', converted_pci_id]) - except Exception as e: - log.error("Failed to process PCI ID for %s index %d: %s", hw_type, idx, str(e)) - log.error("Hardware config keys: %s, looking for index: %s", - list(model_config['hardware'][hw_type].keys()), idx) - raise + hw_config = {int(k): v for k, v in model_config['hardware'][hw_type].items()} + pci_id = hw_config[idx] + converted_pci_id = convert_pci_id(pci_id) + cmd.extend(['-P', converted_pci_id]) - # Execute so-salt-cloud - log.info("Executing command: %s", ' '.join(cmd)) - try: - result = subprocess.run(cmd, capture_output=True, text=True, check=True) - log.debug("Command completed successfully") - log.debug("Command stdout: %s", result.stdout) - if result.stderr: - log.warning("Command stderr (non-fatal): %s", result.stderr) - except subprocess.CalledProcessError as e: - error_msg = f"so-salt-cloud execution failed (code {e.returncode})" - if e.stdout: - log.error("Command stdout: %s", e.stdout) - if e.stderr: - log.error("Command stderr: %s", e.stderr) - error_msg = f"{error_msg}: {e.stderr}" - log.error(error_msg) - mark_vm_failed(os.path.join(hypervisor_path, vm_name), 4, error_msg) - raise + # Execute command + result = subprocess.run(cmd, capture_output=True, text=True, check=True) # Update tracking file status tracking_file = os.path.join(hypervisor_path, vm_name) data = read_json_file(tracking_file) data['status'] = 'running' write_json_file(tracking_file, data) - log.info("Successfully updated VM status to running") except subprocess.CalledProcessError as e: error_msg = f"so-salt-cloud execution failed (code {e.returncode})" - if e.stdout: - log.error("Command stdout: %s", e.stdout) if e.stderr: - log.error("Command stderr: %s", e.stderr) error_msg = f"{error_msg}: {e.stderr}" log.error(error_msg) mark_vm_failed(os.path.join(hypervisor_path, vm_name), 4, error_msg) @@ -604,24 +544,28 @@ def process_vm_creation(hypervisor_path: str, vm_config: dict) -> None: except Exception as e: error_msg = f"VM creation failed: {str(e)}" log.error(error_msg) - # If we haven't created the tracking file yet, create a failed one if not os.path.exists(os.path.join(hypervisor_path, vm_name)): mark_vm_failed(os.path.join(hypervisor_path, f"{vm_name}_failed"), 4, error_msg) - finally: - remove_lock_file(hypervisor_path) + raise def process_vm_deletion(hypervisor_path: str, vm_name: str) -> None: - """Process a single VM deletion request.""" + """ + Process a single VM deletion request. + + This function handles the deletion of an existing VM. All operations are protected + by the engine-wide lock that is acquired at engine start. + + Args: + hypervisor_path: Path to the hypervisor directory + vm_name: Name of the VM to delete + """ try: - if not create_lock_file(hypervisor_path, vm_name): - return - # Get the actual hypervisor name (last directory in path) hypervisor = os.path.basename(hypervisor_path) cmd = ['so-salt-cloud', '-p', f'sool9-{hypervisor}', vm_name, '-yd'] log.info("Executing: %s", ' '.join(cmd)) - result = subprocess.run(cmd, capture_output=True, text=True) + result = subprocess.run(cmd, capture_output=True, text=True, check=True) # Log command output if result.stdout: @@ -629,35 +573,39 @@ def process_vm_deletion(hypervisor_path: str, vm_name: str) -> None: if result.stderr: log.warning("Command stderr: %s", result.stderr) - # Check return code - if result.returncode != 0: - error_msg = f"so-salt-cloud deletion failed (code {result.returncode}): {result.stderr}" - log.error(error_msg) - raise subprocess.CalledProcessError( - result.returncode, cmd, - output=result.stdout, - stderr=result.stderr - ) - # Remove VM tracking file vm_file = os.path.join(hypervisor_path, vm_name) if os.path.exists(vm_file): os.remove(vm_file) log.info("Successfully removed VM tracking file") + except subprocess.CalledProcessError as e: + error_msg = f"so-salt-cloud deletion failed (code {e.returncode}): {e.stderr}" + log.error(error_msg) + raise except Exception as e: log.error("Error processing VM deletion: %s", str(e)) raise - finally: - remove_lock_file(hypervisor_path) def process_hypervisor(hypervisor_path: str) -> None: - """Process VM configurations for a single hypervisor.""" + """ + Process VM configurations for a single hypervisor. + + This function handles the processing of VM configurations for a hypervisor, + including creation of new VMs and deletion of removed VMs. All operations + are protected by the engine-wide lock that is acquired at engine start. + + The function performs the following steps: + 1. Reads and validates nodes configuration + 2. Identifies existing VMs + 3. Processes new VM creation requests + 4. Handles VM deletions for removed configurations + + Args: + hypervisor_path: Path to the hypervisor directory + """ try: - if is_locked(hypervisor_path): - return - - # Read nodes file + # Detection phase - no lock needed nodes_file = os.path.join(hypervisor_path, 'nodes') if not os.path.exists(nodes_file): return @@ -666,7 +614,7 @@ def process_hypervisor(hypervisor_path: str) -> None: if not nodes_config: return - # Get existing VMs + # Get existing VMs - no lock needed existing_vms = set() for file_path in glob.glob(os.path.join(hypervisor_path, '*_*')): basename = os.path.basename(file_path) @@ -684,6 +632,7 @@ def process_hypervisor(hypervisor_path: str) -> None: configured_vms.add(vm_name) if vm_name not in existing_vms: + # process_vm_creation handles its own locking process_vm_creation(hypervisor_path, vm_config) # Process VM deletions @@ -692,29 +641,52 @@ def process_hypervisor(hypervisor_path: str) -> None: except Exception as e: log.error("Failed to process hypervisor %s: %s", hypervisor_path, str(e)) + raise def start(interval: int = DEFAULT_INTERVAL, base_path: str = DEFAULT_BASE_PATH) -> None: """ - Main engine loop. + Process virtual node configurations. + + This function implements a single engine-wide lock to ensure only one + instance of the virtual node manager runs at a time. The lock is: + - Acquired at start + - Released after processing completes + - Maintained if error occurs Args: - interval: Time in seconds between processing cycles + interval: Time in seconds between engine runs (managed by salt-master) base_path: Base path containing hypervisor configurations + + Notes: + - Lock remains if engine encounters an error + - Admin must restart service to clear lock + - Error-level logging used for lock issues """ log.info("Starting virtual node manager engine") if not validate_hvn_license(): return + + # Attempt to acquire engine lock + if not engine_lock.acquire(blocking=False): + log.error("Another virtual node manager is already running") + return - while True: - try: - # Process each hypervisor directory - for hypervisor_path in glob.glob(os.path.join(base_path, '*')): - if os.path.isdir(hypervisor_path): - process_hypervisor(hypervisor_path) - - except Exception as e: - log.error("Error in main engine loop: %s", str(e)) - - time.sleep(interval) + log.debug("Virtual node manager acquired engine lock") + + try: + # Process each hypervisor directory + for hypervisor_path in glob.glob(os.path.join(base_path, '*')): + if os.path.isdir(hypervisor_path): + process_hypervisor(hypervisor_path) + + # Clean shutdown - release lock + log.debug("Virtual node manager releasing engine lock") + engine_lock.release() + log.info("Virtual node manager completed successfully") + + except Exception as e: + log.error("Error in virtual node manager - lock will remain until cleared: %s", str(e)) + # Don't release lock on error - requires admin intervention + return From c34be5313dcdd292136c6b336e1f42dc8b2171c4 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Sat, 15 Feb 2025 21:41:01 -0500 Subject: [PATCH 129/315] hardware logging. vm state file logging --- .../engines/master/virtual_node_manager.py | 231 +++++++++++++----- 1 file changed, 164 insertions(+), 67 deletions(-) diff --git a/salt/salt/engines/master/virtual_node_manager.py b/salt/salt/engines/master/virtual_node_manager.py index 5cce857b4..da8c8dab4 100644 --- a/salt/salt/engines/master/virtual_node_manager.py +++ b/salt/salt/engines/master/virtual_node_manager.py @@ -52,9 +52,8 @@ Examples: State Files: VM Tracking Files: - - : Active VM configuration and status - - _failed: Failed VM creation details - - _invalidHW: Invalid hardware request details + - : Active VM with status 'creating' or 'running' + - .error: Error state with detailed message Notes: - Requires 'hvn' feature license - Uses hypervisor's sosmodel grain for hardware capabilities @@ -106,9 +105,8 @@ Exit Codes: 0: Success 1: Invalid license 2: Configuration error - 3: Hardware allocation failure - 4: VM provisioning failure - 5: Invalid hardware request + 3: Hardware validation failure (hardware doesn't exist in model or is already in use by another VM) + 4: VM provisioning failure (so-salt-cloud execution failed) Logging: Log files are written to /opt/so/log/salt/engines/virtual_node_manager.log @@ -281,14 +279,15 @@ def validate_hardware_request(model_config: dict, requested_hw: dict) -> Tuple[b Tuple of (is_valid, error_details) """ errors = {} - log.debug("Validating hardware request: %s", requested_hw) - log.debug("Against model config: %s", model_config['hardware']) + log.debug("Validating if requested hardware exists in model configuration") + log.debug("Requested hardware: %s", requested_hw) + log.debug("Model hardware configuration: %s", model_config['hardware']) # Validate CPU if 'cpu' in requested_hw: try: cpu_count = int(requested_hw['cpu']) - log.debug("Validating CPU request: %d against maximum: %d", + log.debug("Checking if %d CPU cores exist in model (maximum: %d)", cpu_count, model_config['hardware']['cpu']) if cpu_count > model_config['hardware']['cpu']: errors['cpu'] = f"Requested {cpu_count} CPU cores exceeds maximum {model_config['hardware']['cpu']}" @@ -299,7 +298,7 @@ def validate_hardware_request(model_config: dict, requested_hw: dict) -> Tuple[b if 'memory' in requested_hw: try: memory = int(requested_hw['memory']) - log.debug("Validating memory request: %dGB against maximum: %dGB", + log.debug("Checking if %dGB memory exists in model (maximum: %dGB)", memory, model_config['hardware']['memory']) if memory > model_config['hardware']['memory']: errors['memory'] = f"Requested {memory}GB memory exceeds maximum {model_config['hardware']['memory']}GB" @@ -311,19 +310,19 @@ def validate_hardware_request(model_config: dict, requested_hw: dict) -> Tuple[b if hw_type in requested_hw and requested_hw[hw_type]: try: indices = [int(x) for x in str(requested_hw[hw_type]).split(',')] - log.debug("Validating %s indices: %s", hw_type, indices) + log.debug("Checking if %s indices %s exist in model", hw_type, indices) if hw_type not in model_config['hardware']: log.error("Hardware type %s not found in model config", hw_type) errors[hw_type] = f"No {hw_type} configuration found in model" continue - available_indices = set(int(k) for k in model_config['hardware'][hw_type].keys()) - log.debug("Available %s indices: %s", hw_type, available_indices) + model_indices = set(int(k) for k in model_config['hardware'][hw_type].keys()) + log.debug("Model has %s indices: %s", hw_type, model_indices) - invalid_indices = [idx for idx in indices if idx not in available_indices] + invalid_indices = [idx for idx in indices if idx not in model_indices] if invalid_indices: - log.error("Invalid %s indices found: %s", hw_type, invalid_indices) + log.error("%s indices %s do not exist in model", hw_type, invalid_indices) errors[hw_type] = f"Invalid {hw_type} indices: {invalid_indices}" except ValueError: log.error("Invalid %s indices format: %s", hw_type, requested_hw[hw_type]) @@ -339,26 +338,117 @@ def validate_hardware_request(model_config: dict, requested_hw: dict) -> Tuple[b return (len(errors) == 0, errors if errors else None) -def check_hardware_availability(hypervisor_path: str, vm_name: str) -> bool: - """Check if requested hardware is already claimed by another VM.""" - try: - # List all VM tracking files - files = glob.glob(os.path.join(hypervisor_path, '*_*')) - for file_path in files: - # Skip the VM we're checking and any failed/invalid VMs - basename = os.path.basename(file_path) - if basename.startswith(vm_name) or '_failed' in basename or '_invalidHW' in basename: - continue +def check_hardware_availability(hypervisor_path: str, vm_name: str, requested_hw: dict, model_config: dict) -> Tuple[bool, Optional[dict]]: + """ + Check if requested hardware is available. + + Args: + hypervisor_path: Path to hypervisor directory + vm_name: Name of requesting VM + requested_hw: Hardware being requested + model_config: Model hardware configuration + + Returns: + Tuple of (is_available, error_details) + """ + log.debug("Checking if requested hardware is currently in use by other VMs") + log.debug("VM requesting hardware: %s", vm_name) + log.debug("Hardware being requested: %s", requested_hw) + + errors = {} + + # Track total CPU/memory usage + total_cpu = 0 + total_memory = 0 + + # Track used unique resources and which VM is using them + used_resources = { + 'disk': {}, # {index: vm_name} + 'copper': {}, # {index: vm_name} + 'sfp': {} # {index: vm_name} + } + + # Calculate current usage from existing VMs + log.debug("Scanning existing VMs to check hardware usage") + for vm_file in glob.glob(os.path.join(hypervisor_path, '*_*')): + basename = os.path.basename(vm_file) + # Skip if it's the same VM requesting hardware or in error state + if basename.startswith(vm_name): + log.debug("Skipping file %s (same VM requesting hardware)", basename) + continue + if basename.endswith('.error'): + log.debug("Skipping file %s (error state)", basename) + continue - # Check if any hardware overlaps - vm_config = read_json_file(file_path) - if 'hardware' in vm_config and 'allocated' in vm_config['hardware']: - # TODO: Implement hardware conflict checking - pass - return True - except Exception as e: - log.error("Failed to check hardware availability: %s", str(e)) - return False + vm_config = read_json_file(vm_file) + if 'config' not in vm_config or vm_config.get('status') != 'running': + log.debug("Skipping VM %s (not running)", basename) + continue + + config = vm_config['config'] + log.debug("Processing running VM %s", basename) + + # Add to CPU/memory totals + vm_cpu = int(config.get('cpu', 0)) + vm_memory = int(config.get('memory', 0)) + total_cpu += vm_cpu + total_memory += vm_memory + log.debug("Found running VM %s using CPU: %d, Memory: %dGB", basename, vm_cpu, vm_memory) + + # Track unique resources + for hw_type in ['disk', 'copper', 'sfp']: + if hw_type in config and config[hw_type]: + indices = [int(x) for x in str(config[hw_type]).split(',')] + for idx in indices: + used_resources[hw_type][idx] = basename.replace('_sensor', '') # Store VM name without role + log.debug("VM %s is using %s indices: %s", basename, hw_type, indices) + + log.debug("Total hardware currently in use - CPU: %d, Memory: %dGB", total_cpu, total_memory) + log.debug("Hardware indices currently in use: %s", used_resources) + + # Check CPU capacity + requested_cpu = int(requested_hw.get('cpu', 0)) + total_cpu_needed = total_cpu + requested_cpu + log.debug("Checking CPU capacity - Currently in use: %d + Requested: %d = %d (Max: %d)", + total_cpu, requested_cpu, total_cpu_needed, model_config['hardware']['cpu']) + if total_cpu_needed > model_config['hardware']['cpu']: + errors['cpu'] = f"Total CPU usage ({total_cpu_needed}) would exceed capacity ({model_config['hardware']['cpu']})" + + # Check memory capacity + requested_memory = int(requested_hw.get('memory', 0)) + total_memory_needed = total_memory + requested_memory + log.debug("Checking memory capacity - Currently in use: %d + Requested: %d = %d (Max: %d)", + total_memory, requested_memory, total_memory_needed, model_config['hardware']['memory']) + if total_memory_needed > model_config['hardware']['memory']: + errors['memory'] = f"Total memory usage ({total_memory_needed}GB) would exceed capacity ({model_config['hardware']['memory']}GB)" + + # Check for hardware conflicts + for hw_type in ['disk', 'copper', 'sfp']: + if hw_type in requested_hw and requested_hw[hw_type]: + requested_indices = [int(x) for x in str(requested_hw[hw_type]).split(',')] + log.debug("Checking for %s conflicts - Requesting indices: %s, Currently in use: %s", + hw_type, requested_indices, used_resources[hw_type]) + conflicts = {} # {index: vm_name} + for idx in requested_indices: + if idx in used_resources[hw_type]: + conflicts[idx] = used_resources[hw_type][idx] + + if conflicts: + # Create one sentence per conflict + conflict_details = [] + hw_name = hw_type.upper() if hw_type == 'sfp' else hw_type.capitalize() + for idx, vm in conflicts.items(): + conflict_details.append(f"{hw_name} index {idx} in use by {vm}") + + log.debug("Found conflicting %s indices: %s", hw_type, conflict_details) + errors[hw_type] = ". ".join(conflict_details) + "." + + if errors: + log.debug("Hardware validation failed with errors: %s", errors) + else: + log.debug("Hardware validation successful") + + return (len(errors) == 0, errors if errors else None) def create_vm_tracking_file(hypervisor_path: str, vm_name: str, config: dict) -> None: """Create VM tracking file with initial state.""" @@ -371,52 +461,58 @@ def create_vm_tracking_file(hypervisor_path: str, vm_name: str, config: dict) -> data = { 'config': config, - 'status': 'creating', - 'hardware': { - 'allocated': {} - } + 'status': 'creating' } # Write file and set ownership - with open(file_path, 'w') as f: - json.dump(data, f, indent=2) - set_socore_ownership(file_path) + write_json_file(file_path, data) log.debug("Successfully created VM tracking file with socore ownership") except Exception as e: log.error("Failed to create VM tracking file: %s", str(e)) raise def mark_vm_failed(vm_file: str, error_code: int, message: str) -> None: - """Mark VM as failed with error details.""" + """Create error file with VM failure details.""" try: - # Rename file to add _failed suffix if not already present - if not vm_file.endswith('_failed'): - new_file = f"{vm_file}_failed" - os.rename(vm_file, new_file) - vm_file = new_file + # Get original config if it exists + config = {} + if os.path.exists(vm_file): + data = read_json_file(vm_file) + config = data.get('config', {}) + # Remove the original file since we'll create an error file + os.remove(vm_file) - # Update file contents - data = read_json_file(vm_file) - data['status'] = 'failed' - data['error'] = { - 'code': error_code, - 'message': message, - 'timestamp': datetime.now().isoformat() + # Create error file + error_file = f"{vm_file}.error" + data = { + 'config': config, + 'status': 'error', + 'error_details': { + 'message': message, + 'timestamp': datetime.now().isoformat() + } } - write_json_file(vm_file, data) + write_json_file(error_file, data) except Exception as e: - log.error("Failed to mark VM as failed: %s", str(e)) + log.error("Failed to create error file: %s", str(e)) raise def mark_invalid_hardware(hypervisor_path: str, vm_name: str, config: dict, error_details: dict) -> None: - """Create invalid hardware tracking file with error details.""" - file_path = os.path.join(hypervisor_path, f"{vm_name}_invalidHW") + """Create error file with hardware validation failure details.""" + file_path = os.path.join(hypervisor_path, f"{vm_name}.error") try: + # Build error message from error details + error_messages = [] + for hw_type, message in error_details.items(): + error_messages.append(message) + + # Join all messages with proper sentence structure + full_message = "Hardware validation failure: " + " ".join(error_messages) + data = { 'config': config, - 'error': { - 'code': 5, - 'message': "Invalid hardware configuration", - 'invalid_hardware': error_details, + 'status': 'error', + 'error_details': { + 'message': full_message, 'timestamp': datetime.now().isoformat() } } @@ -480,16 +576,17 @@ def process_vm_creation(hypervisor_path: str, vm_config: dict) -> None: model = get_hypervisor_model(hypervisor) model_config = load_hardware_defaults(model) - # Initial hardware validation + # Initial hardware validation against model is_valid, errors = validate_hardware_request(model_config, vm_config) if not is_valid: mark_invalid_hardware(hypervisor_path, vm_name, vm_config, errors) return # Check hardware availability - if not check_hardware_availability(hypervisor_path, vm_name): - mark_vm_failed(os.path.join(hypervisor_path, vm_name), 3, - "Requested hardware is already in use") + is_available, availability_errors = check_hardware_availability( + hypervisor_path, vm_name, vm_config, model_config) + if not is_available: + mark_invalid_hardware(hypervisor_path, vm_name, vm_config, availability_errors) return # Create tracking file @@ -618,7 +715,7 @@ def process_hypervisor(hypervisor_path: str) -> None: existing_vms = set() for file_path in glob.glob(os.path.join(hypervisor_path, '*_*')): basename = os.path.basename(file_path) - if not any(x in basename for x in ['_failed', '_invalidHW']): + if not basename.endswith('.error'): existing_vms.add(basename) # Process new VMs From 6ff701bd5cf6b03117bd2403e14cf15d3d497645 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Sun, 16 Feb 2025 01:33:50 -0500 Subject: [PATCH 130/315] soc ui improvements for hypervisor layout. show free hardware for a hypervisor in the description --- salt/hypervisor/map.jinja | 45 +++++++++++ .../engines/master/virtual_node_manager.py | 24 +++--- salt/soc/dyanno/hypervisor/hypervisor.yaml | 76 ++++++++----------- salt/soc/dyanno/hypervisor/init.sls | 2 +- .../hypervisor/soc_hypervisor.yaml.jinja | 59 +++++++++++--- 5 files changed, 140 insertions(+), 66 deletions(-) create mode 100644 salt/hypervisor/map.jinja diff --git a/salt/hypervisor/map.jinja b/salt/hypervisor/map.jinja new file mode 100644 index 000000000..b187bdfb1 --- /dev/null +++ b/salt/hypervisor/map.jinja @@ -0,0 +1,45 @@ +{# Import defaults.yaml for model hardware capabilities #} +{% import_yaml 'hypervisor/defaults.yaml' as DEFAULTS %} + +{# Get hypervisor nodes from pillar #} +{% set NODES = salt['pillar.get']('hypervisor:nodes', {}) %} + +{# Build enhanced HYPERVISORS structure #} +{% set HYPERVISORS = {} %} +{% for role, hypervisors in NODES.items() %} + {% do HYPERVISORS.update({role: {}}) %} + {% for hypervisor, config in hypervisors.items() %} + {# Get model from cached grains using Salt runner #} + {% set grains = salt.saltutil.runner('cache.grains', tgt=hypervisor ~ '_*', tgt_type='glob') %} + {% set model = '' %} + {% if grains %} + {% set minion_id = grains.keys() | first %} + {% set model = grains[minion_id].get('sosmodel', '') %} + {% endif %} + {% set model_config = DEFAULTS.hypervisor.model.get(model, {}) %} + + {# Get VM list and states #} + {% set vms = {} %} + {% import_json 'hypervisor/hosts/' ~ hypervisor ~ 'VMs' as vm_list %} + + {# Load state for each VM #} + {% for vm in vm_list %} + {% set hostname = vm.get('hostname', '') %} + {% set role = vm.get('role', '') %} + {% if hostname and role %} + {% import_json 'hypervisor/hosts/' ~ hypervisor ~ '/' ~ hostname ~ '_' ~ role as vm_state %} + {% do vms.update({hostname: vm_state}) %} + {% endif %} + {% endfor %} + + {# Merge node config with model capabilities and VM states #} + {% do HYPERVISORS[role].update({ + hypervisor: { + 'config': config, + 'model': model, + 'hardware': model_config.get('hardware', {}), + 'vms': vms + } + }) %} + {% endfor %} +{% endfor %} \ No newline at end of file diff --git a/salt/salt/engines/master/virtual_node_manager.py b/salt/salt/engines/master/virtual_node_manager.py index da8c8dab4..ef04032ce 100644 --- a/salt/salt/engines/master/virtual_node_manager.py +++ b/salt/salt/engines/master/virtual_node_manager.py @@ -9,7 +9,7 @@ Salt Engine for Virtual Node Management This engine manages the automated provisioning of virtual machines in Security Onion's -virtualization infrastructure. It processes VM configurations from a nodes file and handles +virtualization infrastructure. It processes VM configurations from a VMs file and handles the entire provisioning process including hardware allocation, state tracking, and file ownership. Usage: @@ -26,8 +26,8 @@ Options: will automatically be converted to MiB when passed to so-salt-cloud. Configuration Files: - nodes: JSON file containing VM configurations - - Located at //nodes + VMs: JSON file containing VM configurations + - Located at /VMs - Contains array of VM configurations - Each VM config specifies hardware and network settings @@ -54,6 +54,7 @@ State Files: VM Tracking Files: - : Active VM with status 'creating' or 'running' - .error: Error state with detailed message + Notes: - Requires 'hvn' feature license - Uses hypervisor's sosmodel grain for hardware capabilities @@ -76,7 +77,7 @@ Description: - Prevents operation if license is invalid 3. Configuration Processing - - Reads nodes file from each hypervisor directory + - Reads VMs file for each hypervisor - Validates configuration parameters - Compares against existing VM tracking files @@ -693,7 +694,7 @@ def process_hypervisor(hypervisor_path: str) -> None: are protected by the engine-wide lock that is acquired at engine start. The function performs the following steps: - 1. Reads and validates nodes configuration + 1. Reads VMs configuration from VMs file 2. Identifies existing VMs 3. Processes new VM creation requests 4. Handles VM deletions for removed configurations @@ -702,13 +703,18 @@ def process_hypervisor(hypervisor_path: str) -> None: hypervisor_path: Path to the hypervisor directory """ try: - # Detection phase - no lock needed - nodes_file = os.path.join(hypervisor_path, 'nodes') - if not os.path.exists(nodes_file): + # Get hypervisor name from path + hypervisor = os.path.basename(hypervisor_path) + + # Read VMs file instead of nodes + vms_file = os.path.join(os.path.dirname(hypervisor_path), f"{hypervisor}VMs") + if not os.path.exists(vms_file): + log.debug("No VMs file found at %s", vms_file) return - nodes_config = read_json_file(nodes_file) + nodes_config = read_json_file(vms_file) if not nodes_config: + log.debug("Empty VMs configuration in %s", vms_file) return # Get existing VMs - no lock needed diff --git a/salt/soc/dyanno/hypervisor/hypervisor.yaml b/salt/soc/dyanno/hypervisor/hypervisor.yaml index 2b9a0d70e..477525259 100644 --- a/salt/soc/dyanno/hypervisor/hypervisor.yaml +++ b/salt/soc/dyanno/hypervisor/hypervisor.yaml @@ -1,49 +1,33 @@ hypervisor: hosts: defaultHost: - hardwareMap: - title: 'All Hardware' - description: This shows hardware available to the hypervisor and PCIe -> INT mapping. - file: true - readonly: true - global: true # set to true to remove host drop down - multiline: true - vmMap: - title: 'VM Map' - description: This shows the VMs and the hardware they have claimed. - file: true - readonly: true - global: true - multiline: true - nodes: - description: 'Available CPU: CPUFREE | Available Memory: MEMFREE | Available Disk: DISKFREE | Available Copper NIC: COPPERFREE | Available SFP NIC: SFPFREE' - syntax: json - uiElements: - - field: hostname - label: Enter the hostname - - field: role - label: sensor or searchnode - - field: network_mode - label: Choose static4 or dhcp4. If static4, populate IP details below. - - field: ip4 - label: IP Address with netmask. ex. 192.168.1.10/24 - - field: gw4 - label: Gateway - - field: dns4 - label: DNS. Comma separated list. ex. 192.168.1.1,8.8.8.8 - - field: search4 - label: Search domain - - field: cpu - label: Number of CPU cores to assign. ex. 8 - - field: memory - label: Memory, in GB to assign. ex. 16 - - field: disk - label: Choose a disk or disks to assign for passthrough. Comma separated list. - - field: copper - label: Choose a copper port or ports to assign for passthrough. Comma separated list. - - field: sfp - label: Choose a sfp port or ports to assign for passthrough. Comma separated list. - file: true - global: true - - vms: {} + title: defaultHost + description: 'Available CPU: CPUFREE | Available Memory: MEMFREE | Available Disk: DISKFREE | Available Copper NIC: COPPERFREE | Available SFP NIC: SFPFREE' + syntax: json + uiElements: + - field: hostname + label: Enter the hostname + - field: role + label: sensor or searchnode + - field: network_mode + label: Choose static4 or dhcp4. If static4, populate IP details below. + - field: ip4 + label: IP Address with netmask. ex. 192.168.1.10/24 + - field: gw4 + label: Gateway + - field: dns4 + label: DNS. Comma separated list. ex. 192.168.1.1,8.8.8.8 + - field: search4 + label: Search domain + - field: cpu + label: Number of CPU cores to assign. ex. 8 + - field: memory + label: Memory, in GB to assign. ex. 16 + - field: disk + label: Choose a disk or disks to assign for passthrough. Comma separated list. + - field: copper + label: Choose a copper port or ports to assign for passthrough. Comma separated list. + - field: sfp + label: Choose a sfp port or ports to assign for passthrough. Comma separated list. + file: true + global: true diff --git a/salt/soc/dyanno/hypervisor/init.sls b/salt/soc/dyanno/hypervisor/init.sls index a0b83fd5d..5645a8f63 100644 --- a/salt/soc/dyanno/hypervisor/init.sls +++ b/salt/soc/dyanno/hypervisor/init.sls @@ -1,4 +1,4 @@ -{% from 'soc/dyanno/hypervisor/map.jinja' import HYPERVISORS %} +{% from 'hypervisor/map.jinja' import HYPERVISORS %} hypervisor_annotation: file.managed: diff --git a/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja b/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja index 74996605e..2e274157b 100644 --- a/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja +++ b/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja @@ -1,27 +1,66 @@ {%- import_yaml 'soc/dyanno/hypervisor/hypervisor.yaml' as ANNOTATION -%} +{%- from 'hypervisor/map.jinja' import HYPERVISORS -%} {%- set TEMPLATE = ANNOTATION.hypervisor.hosts.pop('defaultHost') -%} {%- macro update_description(description, cpu_free, mem_free, disk_free, copper_free, sfp_free) -%} -{{- description | replace('CPUFREE', cpu_free | string) - | replace('MEMFREE', mem_free | string) +{{- description | replace('CPUFREE', cpu_free | string) + | replace('MEMFREE', mem_free | string) | replace('DISKFREE', disk_free | string) | replace('COPPERFREE', copper_free | string) | replace('SFPFREE', sfp_free | string) -}} {%- endmacro -%} +{%- macro get_available_pci(hw_config, device_type, used_indices) -%} +{%- set available = [] -%} +{%- for idx in hw_config.get(device_type, {}).keys() -%} + {%- if idx | string not in used_indices -%} + {%- do available.append(idx) -%} + {%- endif -%} +{%- endfor -%} +{{- available | join(',') -}} +{%- endmacro -%} + {%- for role in HYPERVISORS -%} {%- for hypervisor in HYPERVISORS[role].keys() -%} -{%- set cpu_free = HYPERVISORS[role][hypervisor].available_cpu -%} -{%- set mem_free = HYPERVISORS[role][hypervisor].available_memory -%} -{%- set disk_free = HYPERVISORS[role][hypervisor].available_disk -%} -{%- set copper_free = HYPERVISORS[role][hypervisor].available_copper -%} -{%- set sfp_free = HYPERVISORS[role][hypervisor].available_sfp -%} +{%- set hw_config = HYPERVISORS[role][hypervisor].hardware -%} +{%- set vms = HYPERVISORS[role][hypervisor].vms -%} + +{# Calculate used CPU and memory #} +{%- set used_cpu = 0 -%} +{%- set used_memory = 0 -%} +{%- set ns = namespace(used_cpu=0, used_memory=0) -%} #MOD +{%- for hostname, vm_data in vms.items() -%} +{%- set vm_config = vm_data.config -%} +{%- set ns.used_cpu = ns.used_cpu + vm_config.cpu | int -%} +{%- set ns.used_memory = ns.used_memory + vm_config.memory | int -%} +{%- endfor -%} + +{# Calculate available resources #} +{%- set cpu_free = hw_config.cpu - ns.used_cpu -%} +{%- set mem_free = hw_config.memory - ns.used_memory -%} + +{# Get used PCI indices #} +{%- set used_disk = [] -%} +{%- set used_copper = [] -%} +{%- set used_sfp = [] -%} +{%- for hostname, vm in vms.items() -%} +{%- set config = vm.get('config', {}) -%} +{%- do used_disk.extend((config.get('disk', '') | string).split(',') | map('trim') | list) -%} +{%- do used_copper.extend((config.get('copper', '') | string).split(',') | map('trim') | list) -%} +{%- do used_sfp.extend((config.get('sfp', '') | string).split(',') | map('trim') | list) -%} +{%- endfor -%} + +{# Get available PCI indices #} +{%- set disk_free = get_available_pci(hw_config, 'disk', used_disk) -%} +{%- set copper_free = get_available_pci(hw_config, 'copper', used_copper) -%} +{%- set sfp_free = get_available_pci(hw_config, 'sfp', used_sfp) -%} {%- set updated_template = TEMPLATE.copy() -%} -{%- do updated_template.nodes.update({ +{%- do updated_template.update({ + 'title': hypervisor, 'description': update_description( - TEMPLATE.nodes.description, + TEMPLATE.description, cpu_free, mem_free, disk_free, @@ -29,7 +68,7 @@ sfp_free ) }) -%} -{%- do ANNOTATION.hypervisor.hosts.update({hypervisor: updated_template}) -%} +{%- do ANNOTATION.hypervisor.hosts.update({hypervisor ~ 'VMs': updated_template}) -%} {%- endfor -%} {%- endfor -%} From 0d335e30567ef8f63d193b5e6dc4d43e61794d82 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Sun, 16 Feb 2025 02:23:11 -0500 Subject: [PATCH 131/315] free and totals in labels --- salt/soc/dyanno/hypervisor/hypervisor.yaml | 26 +++++++------- .../hypervisor/soc_hypervisor.yaml.jinja | 34 +++++++++++++++++-- 2 files changed, 45 insertions(+), 15 deletions(-) diff --git a/salt/soc/dyanno/hypervisor/hypervisor.yaml b/salt/soc/dyanno/hypervisor/hypervisor.yaml index 477525259..f6c955970 100644 --- a/salt/soc/dyanno/hypervisor/hypervisor.yaml +++ b/salt/soc/dyanno/hypervisor/hypervisor.yaml @@ -2,32 +2,32 @@ hypervisor: hosts: defaultHost: title: defaultHost - description: 'Available CPU: CPUFREE | Available Memory: MEMFREE | Available Disk: DISKFREE | Available Copper NIC: COPPERFREE | Available SFP NIC: SFPFREE' + description: "Available CPU: CPUFREE | Available Memory: MEMFREE | Available Disk: DISKFREE | Available Copper NIC: COPPERFREE | Available SFP NIC: SFPFREE" syntax: json uiElements: - field: hostname - label: Enter the hostname + label: "Enter the hostname" - field: role - label: sensor or searchnode + label: "sensor or searchnode" - field: network_mode - label: Choose static4 or dhcp4. If static4, populate IP details below. + label: "Choose static4 or dhcp4. If static4, populate IP details below." - field: ip4 - label: IP Address with netmask. ex. 192.168.1.10/24 + label: "IP Address with netmask. ex. 192.168.1.10/24" - field: gw4 - label: Gateway + label: "Gateway" - field: dns4 - label: DNS. Comma separated list. ex. 192.168.1.1,8.8.8.8 + label: "DNS. Comma separated list. ex. 192.168.1.1,8.8.8.8" - field: search4 - label: Search domain + label: "Search domain" - field: cpu - label: Number of CPU cores to assign. ex. 8 + label: "CPU cores to assign. Free: FREE | Total: TOTAL" - field: memory - label: Memory, in GB to assign. ex. 16 + label: "Memory to assign, in GB. Free: FREE | Total: TOTAL" - field: disk - label: Choose a disk or disks to assign for passthrough. Comma separated list. + label: "Disk(s) for passthrough. Comma separated list. Free: FREE | Total: TOTAL" - field: copper - label: Choose a copper port or ports to assign for passthrough. Comma separated list. + label: "Copper port(s) for passthrough. Comma separated list. Free: FREE | Total: TOTAL" - field: sfp - label: Choose a sfp port or ports to assign for passthrough. Comma separated list. + label: "SFP port(s) for passthrough. Comma separated list. Free: FREE | Total: TOTAL" file: true global: true diff --git a/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja b/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja index 2e274157b..6541da318 100644 --- a/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja +++ b/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja @@ -11,6 +11,11 @@ | replace('SFPFREE', sfp_free | string) -}} {%- endmacro -%} +{%- macro update_label(label, total, free) -%} +{{- label | replace('TOTAL', total | string) + | replace('FREE', free | string) -}} +{%- endmacro -%} + {%- macro get_available_pci(hw_config, device_type, used_indices) -%} {%- set available = [] -%} {%- for idx in hw_config.get(device_type, {}).keys() -%} @@ -29,7 +34,7 @@ {# Calculate used CPU and memory #} {%- set used_cpu = 0 -%} {%- set used_memory = 0 -%} -{%- set ns = namespace(used_cpu=0, used_memory=0) -%} #MOD +{%- set ns = namespace(used_cpu=0, used_memory=0) -%} {%- for hostname, vm_data in vms.items() -%} {%- set vm_config = vm_data.config -%} {%- set ns.used_cpu = ns.used_cpu + vm_config.cpu | int -%} @@ -55,8 +60,33 @@ {%- set disk_free = get_available_pci(hw_config, 'disk', used_disk) -%} {%- set copper_free = get_available_pci(hw_config, 'copper', used_copper) -%} {%- set sfp_free = get_available_pci(hw_config, 'sfp', used_sfp) -%} - + +{# Get total resources #} +{%- set cpu_total = hw_config.cpu -%} +{%- set mem_total = hw_config.memory -%} +{%- set disk_total = hw_config.disk.keys() | join(',') -%} +{%- set copper_total = hw_config.copper.keys() | join(',') -%} +{%- set sfp_total = hw_config.sfp.keys() | join(',') -%} + +{# Update field labels with total and free values #} {%- set updated_template = TEMPLATE.copy() -%} +{%- set updated_elements = [] -%} +{%- for field in updated_template.uiElements -%} +{%- set updated_field = field.copy() -%} +{%- if field.field == 'cpu' -%} +{%- do updated_field.update({'label': field.label | replace('FREE', cpu_free | string) | replace('TOTAL', cpu_total | string)}) -%} +{%- elif field.field == 'memory' -%} +{%- do updated_field.update({'label': field.label | replace('FREE', mem_free | string) | replace('TOTAL', mem_total | string)}) -%} +{%- elif field.field == 'disk' -%} +{%- do updated_field.update({'label': field.label | replace('FREE', disk_free) | replace('TOTAL', disk_total)}) -%} +{%- elif field.field == 'copper' -%} +{%- do updated_field.update({'label': field.label | replace('FREE', copper_free) | replace('TOTAL', copper_total)}) -%} +{%- elif field.field == 'sfp' -%} +{%- do updated_field.update({'label': field.label | replace('FREE', sfp_free) | replace('TOTAL', sfp_total)}) -%} +{%- endif -%} +{%- do updated_elements.append(updated_field) -%} +{%- endfor -%} +{%- do updated_template.update({'uiElements': updated_elements}) -%} {%- do updated_template.update({ 'title': hypervisor, 'description': update_description( From f46548ed884810c7b140d452663c26e800021774 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Sun, 16 Feb 2025 02:25:18 -0500 Subject: [PATCH 132/315] remove free hw from description --- salt/soc/dyanno/hypervisor/hypervisor.yaml | 2 +- salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja | 6 +----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/salt/soc/dyanno/hypervisor/hypervisor.yaml b/salt/soc/dyanno/hypervisor/hypervisor.yaml index f6c955970..e2a0028a8 100644 --- a/salt/soc/dyanno/hypervisor/hypervisor.yaml +++ b/salt/soc/dyanno/hypervisor/hypervisor.yaml @@ -2,7 +2,7 @@ hypervisor: hosts: defaultHost: title: defaultHost - description: "Available CPU: CPUFREE | Available Memory: MEMFREE | Available Disk: DISKFREE | Available Copper NIC: COPPERFREE | Available SFP NIC: SFPFREE" + description: "Hypervisor Configuration" syntax: json uiElements: - field: hostname diff --git a/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja b/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja index 6541da318..f5ce34563 100644 --- a/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja +++ b/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja @@ -4,11 +4,7 @@ {%- set TEMPLATE = ANNOTATION.hypervisor.hosts.pop('defaultHost') -%} {%- macro update_description(description, cpu_free, mem_free, disk_free, copper_free, sfp_free) -%} -{{- description | replace('CPUFREE', cpu_free | string) - | replace('MEMFREE', mem_free | string) - | replace('DISKFREE', disk_free | string) - | replace('COPPERFREE', copper_free | string) - | replace('SFPFREE', sfp_free | string) -}} +{{- description -}} {%- endmacro -%} {%- macro update_label(label, total, free) -%} From 8ffd4fc664355c839455a74cef27569eb93e42f0 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Sun, 16 Feb 2025 02:31:52 -0500 Subject: [PATCH 133/315] new examples --- .../soc/dyanno/hypervisor/hardwareMap.example | 32 ------ .../hypervisor/soc_hypervisor.yaml.example | 97 +++++++------------ 2 files changed, 33 insertions(+), 96 deletions(-) delete mode 100644 salt/soc/dyanno/hypervisor/hardwareMap.example diff --git a/salt/soc/dyanno/hypervisor/hardwareMap.example b/salt/soc/dyanno/hypervisor/hardwareMap.example deleted file mode 100644 index ea3bec51b..000000000 --- a/salt/soc/dyanno/hypervisor/hardwareMap.example +++ /dev/null @@ -1,32 +0,0 @@ -# this file will exist in /opt/so/saltstack/local/salt/hypervisor/hosts/HOSTNAME/hardwareMap -hypervisor: - hardware: - copper: - claimed: - 1: pci_0000_c1_00_0 - 2: pci_0000_c1_00_1 - free: - 3: pci_0000_c4_00_0 - 4: pci_0000_c4_00_1 - 5: pci_0000_c4_00_2 - 6: pci_0000_c4_00_3 - cpu: - free: 120 - total: 120 - disk: - claimed: - 1: pci_0000_c5_00_0 - 2: pci_0000_c6_00_0 - free: - 3: pci_0000_c7_00_0 - 4: pci_0000_c8_00_0 - memory: - free: 120 - total: 120 - sfp: - claimed: {} - free: - 8: pci_0000_02_00_1 - 7: pci_0000_02_00_0 - 9: pci_0000_41_00_0 - 10: pci_0000_41_00_1 diff --git a/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.example b/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.example index bd5161598..902d9b1b1 100644 --- a/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.example +++ b/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.example @@ -1,67 +1,36 @@ # This is the start of an example of what this file will look like. It will be generated by Salt, so this yaml file is not used by Salt. hypervisor: hosts: - jpphype1: - hardwareMap: - title: 'All Hardware' - description: This shows hardware available to the hypervisor and PCIe -> INT mapping. - file: true - readonly: true - global: true # set to true to remove host drop down - multiline: true - cpufree: - title: 'Available CPU: 120' - description: Available CPU for this hypervisor. - readonly: true - global: true # set to true to remove host drop down - memfree: - title: 'Available Memory: 120' - description: Available memory for this hypervisor. - readonly: true - global: true # set to true to remove host drop down - diskfree: - title: 'Available Disk: 3,4' - description: Available disk for this hypervisor. - readonly: true - global: true # set to true to remove host drop down - copperfree: - title: 'Available Copper NIC: 3,4,5,6' - description: Available copper NIC for this hypervisor. - readonly: true - global: true # set to true to remove host drop down - sfpfree: - title: 'Available SFP NIC: 7,8,9,10' - description: Available SFP NIC for this hypervisor. - readonly: true - global: true # set to true to remove host drop down - nodes: - description: List of VMs. - syntax: json - uiElements: - - field: hostname - label: Enter the hostname - forcedType: string - - field: nodetype - label: sensor or searchnode - - field: network_mode - label: Choose static4 or dhcp4. If static4, populate IP details below. - - field: ip4 - label: IP Address with netmask. ex. 192.168.1.10/24 - - field: gw4 - label: Gateway - - field: dns4 - label: DNS. Comma seperated list. ex. 192.168.1.1,8.8.8.8 - - field: search4 - label: Search domain - - field: cpu - label: Number of CPU cores to assign. ex. 8 - - field: memory - label: Memory, in GB to assign. ex. 16 - - field: disk - label: Choose a disk or disks to assign for passthrough. Comma seperated list. - - field: copper - label: Choose a copper port or ports to assign for passthrough. Comma seperated list. - - filed: sfp - label: Choose a sfp port or ports to assign for passthrough. Comma seperated list. - file: true - global: true # set to true to remove host drop down + jpphype1VMs: + description: Hypervisor Configuration + file: true + global: true + syntax: json + title: jpphype1 + uiElements: + - field: hostname + label: Enter the hostname + - field: role + label: sensor or searchnode + - field: network_mode + label: Choose static4 or dhcp4. If static4, populate IP details below. + - field: ip4 + label: IP Address with netmask. ex. 192.168.1.10/24 + - field: gw4 + label: Gateway + - field: dns4 + label: DNS. Comma separated list. ex. 192.168.1.1,8.8.8.8 + - field: search4 + label: Search domain + - field: cpu + label: 'CPU cores to assign. Free: 120 | Total: 128' + - field: memory + label: 'Memory to assign, in GB. Free: 112 | Total: 128' + - field: disk + label: 'Disk(s) for passthrough. Comma separated list. Free: 2 | Total: 1,2' + - field: copper + label: 'Copper port(s) for passthrough. Comma separated list. Free: 3,4 | + Total: 1,2,3,4' + - field: sfp + label: 'SFP port(s) for passthrough. Comma separated list. Free: 5,6,7,8 | + Total: 5,6,7,8' From b68f561e6fa462ad4c88e1594306c3ea338c7982 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Fri, 21 Feb 2025 09:50:01 -0500 Subject: [PATCH 134/315] progress and hw tracking for soc hypervisor dynamic annotations --- salt/_modules/qcow2.py | 8 +- .../so-salt-emit-vm-deployment-status-event | 116 +++++++++++++++++ salt/hypervisor/map.jinja | 52 +++++++- .../tools/sbin/so-kvm-modify-hardware | 79 +++++++++++- .../tools/sbin/so-qcow2-modify-network | 61 ++++++++- salt/manager/tools/sbin/so-salt-cloud | 5 +- salt/orch/dyanno_hypervisor.sls | 97 +++++++++++++++ salt/reactor/createEmptyPillar.sls | 24 +++- salt/reactor/vm_status.sls | 117 ++++++++++++++++++ salt/salt/cloud/reactor_config_hypervisor.sls | 10 +- .../engines/master/virtual_node_manager.py | 30 +++-- salt/soc/dyanno/hypervisor/init.sls | 2 + .../hypervisor/soc_hypervisor.yaml.jinja | 26 +++- salt/soc/dyanno/hypervisor/write_status.sls | 69 +++++++++++ salt/top.sls | 1 + salt/vm_status/init.sls | 10 ++ 16 files changed, 674 insertions(+), 33 deletions(-) create mode 100644 salt/common/tools/sbin/so-salt-emit-vm-deployment-status-event create mode 100644 salt/orch/dyanno_hypervisor.sls create mode 100644 salt/reactor/vm_status.sls create mode 100644 salt/soc/dyanno/hypervisor/write_status.sls create mode 100644 salt/vm_status/init.sls diff --git a/salt/_modules/qcow2.py b/salt/_modules/qcow2.py index 81a00ca66..6e71dc459 100644 --- a/salt/_modules/qcow2.py +++ b/salt/_modules/qcow2.py @@ -29,10 +29,10 @@ __virtualname__ = 'qcow2' def __virtual__(): return __virtualname__ -def modify_network_config(image, interface, mode, ip4=None, gw4=None, dns4=None, search4=None): +def modify_network_config(image, interface, mode, vm_name, ip4=None, gw4=None, dns4=None, search4=None): ''' Usage: - salt '*' qcow2.modify_network_config image= interface= mode= [ip4=] [gw4=] [dns4=] [search4=] + salt '*' qcow2.modify_network_config image= interface= mode= vm_name= [ip4=] [gw4=] [dns4=] [search4=] Options: image @@ -41,6 +41,8 @@ def modify_network_config(image, interface, mode, ip4=None, gw4=None, dns4=None, Network interface name to configure (e.g., 'enp1s0') mode Network configuration mode, either 'dhcp4' or 'static4' + vm_name + Full name of the VM (hostname_role) ip4 IPv4 address with CIDR notation (e.g., '192.168.1.10/24') Required when mode='static4' @@ -94,7 +96,7 @@ def modify_network_config(image, interface, mode, ip4=None, gw4=None, dns4=None, - Success/failure status is logged for verification ''' - cmd = ['/usr/sbin/so-qcow2-modify-network', '-I', image, '-i', interface] + cmd = ['/usr/sbin/so-qcow2-modify-network', '-I', image, '-i', interface, '-n', vm_name] if mode.lower() == 'dhcp4': cmd.append('--dhcp4') diff --git a/salt/common/tools/sbin/so-salt-emit-vm-deployment-status-event b/salt/common/tools/sbin/so-salt-emit-vm-deployment-status-event new file mode 100644 index 000000000..454e1ba9b --- /dev/null +++ b/salt/common/tools/sbin/so-salt-emit-vm-deployment-status-event @@ -0,0 +1,116 @@ +#!/opt/saltstack/salt/bin/python3 + +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +""" +Script for emitting VM deployment status events to the Salt event bus. + +This script provides functionality to emit status events for VM deployment operations, +used by various Security Onion VM management tools. + +Usage: + so-salt-emit-vm-deployment-status-event -v -H -s + +Arguments: + -v, --vm-name Name of the VM (hostname_role) + -H, --hypervisor Name of the hypervisor + -s, --status Current deployment status of the VM + +Example: + so-salt-emit-vm-deployment-status-event -v sensor1_sensor -H hypervisor1 -s "Creating" +""" + +import sys +import argparse +import logging +import salt.client +from typing import Dict, Any + +# Configure logging +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s - %(levelname)s - %(message)s' +) +log = logging.getLogger(__name__) + +def emit_event(vm_name: str, hypervisor: str, status: str) -> bool: + """ + Emit a VM deployment status event to the salt event bus. + + Args: + vm_name: Name of the VM (hostname_role) + hypervisor: Name of the hypervisor + status: Current deployment status of the VM + + Returns: + bool: True if event was sent successfully, False otherwise + + Raises: + ValueError: If status is not a valid deployment status + """ + log.info("Attempting to emit deployment event...") + + try: + caller = salt.client.Caller() + event_data = { + 'vm_name': vm_name, + 'hypervisor': hypervisor, + 'status': status + } + + # Use consistent event tag structure + event_tag = f'soc/dyanno/hypervisor/{status.lower()}' + + ret = caller.cmd( + 'event.send', + event_tag, + event_data + ) + + if not ret: + log.error("Failed to emit VM deployment status event: %s", event_data) + return False + + log.info("Successfully emitted VM deployment status event: %s", event_data) + return True + + except Exception as e: + log.error("Error emitting VM deployment status event: %s", str(e)) + return False + +def parse_args(): + """Parse command line arguments.""" + parser = argparse.ArgumentParser( + description='Emit VM deployment status events to the Salt event bus.' + ) + parser.add_argument('-v', '--vm-name', required=True, + help='Name of the VM (hostname_role)') + parser.add_argument('-H', '--hypervisor', required=True, + help='Name of the hypervisor') + parser.add_argument('-s', '--status', required=True, + help='Current deployment status of the VM') + return parser.parse_args() + +def main(): + """Main entry point for the script.""" + try: + args = parse_args() + + success = emit_event( + vm_name=args.vm_name, + hypervisor=args.hypervisor, + status=args.status + ) + + if not success: + sys.exit(1) + + except Exception as e: + log.error("Failed to emit status event: %s", str(e)) + sys.exit(1) + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/salt/hypervisor/map.jinja b/salt/hypervisor/map.jinja index b187bdfb1..cf323f51d 100644 --- a/salt/hypervisor/map.jinja +++ b/salt/hypervisor/map.jinja @@ -6,9 +6,12 @@ {# Build enhanced HYPERVISORS structure #} {% set HYPERVISORS = {} %} +{% do salt.log.info('salt/hypervisor/map.jinja: NODES content: ' ~ NODES | tojson) %} {% for role, hypervisors in NODES.items() %} + {% do salt.log.info('salt/hypervisor/map.jinja: Processing role: ' ~ role) %} {% do HYPERVISORS.update({role: {}}) %} {% for hypervisor, config in hypervisors.items() %} + {% do salt.log.info('salt/hypervisor/map.jinja: Processing hypervisor: ' ~ hypervisor ~ ' with config: ' ~ config | tojson) %} {# Get model from cached grains using Salt runner #} {% set grains = salt.saltutil.runner('cache.grains', tgt=hypervisor ~ '_*', tgt_type='glob') %} {% set model = '' %} @@ -18,17 +21,54 @@ {% endif %} {% set model_config = DEFAULTS.hypervisor.model.get(model, {}) %} - {# Get VM list and states #} + {# Get VM list from VMs file #} {% set vms = {} %} - {% import_json 'hypervisor/hosts/' ~ hypervisor ~ 'VMs' as vm_list %} + {% set vm_list = [] %} + {% set vm_list_file = 'hypervisor/hosts/' ~ hypervisor ~ 'VMs' %} + {% do salt.log.info('salt/hypervisor/map.jinja: VM list file: ' ~ vm_list_file) %} + {% import_json vm_list_file as vm_list %} + {% if vm_list %} + {% do salt.log.info('salt/hypervisor/map.jinja: VM list content: ' ~ vm_list | tojson) %} + {% else %} + {# we won't get here if the vm_list_file doesn't exist because we will get TemplateNotFound on the import_json #} + {% do salt.log.info('salt/hypervisor/map.jinja: VM list empty: ' ~ vm_list_file) %} + {% endif %} - {# Load state for each VM #} + {# Load status and configuration for each VM #} {% for vm in vm_list %} + {# Get VM details from list entry #} {% set hostname = vm.get('hostname', '') %} {% set role = vm.get('role', '') %} - {% if hostname and role %} - {% import_json 'hypervisor/hosts/' ~ hypervisor ~ '/' ~ hostname ~ '_' ~ role as vm_state %} - {% do vms.update({hostname: vm_state}) %} + {% do salt.log.info('salt/hypervisor/map.jinja: Processing VM - hostname: ' ~ hostname ~ ', role: ' ~ role) %} + + {# Load VM configuration from config file #} + {% set vm_file = 'hypervisor/hosts/' ~ hypervisor ~ '/' ~ hostname ~ '_' ~ role %} + {% do salt.log.info('salt/hypervisor/map.jinja: VM config file: ' ~ vm_file) %} + {% import_json vm_file as vm_state %} + {% if vm_state %} + {% do salt.log.info('salt/hypervisor/map.jinja: VM config content: ' ~ vm_state | tojson) %} + {% set vm_data = {'config': vm_state.config} %} + + {# Load VM status from status file #} + {% set status_file = vm_file ~ '.status' %} + {% do salt.log.info('salt/hypervisor/map.jinja: VM status file: ' ~ status_file) %} + {% import_json status_file as status_data %} + {% if status_data %} + {% do salt.log.info('salt/hypervisor/map.jinja: VM status content: ' ~ status_data | tojson) %} + {% do vm_data.update({'status': status_data}) %} + {% else %} + {% do salt.log.info('salt/hypervisor/map.jinja: Status file empty: ' ~ status_file) %} + {% do vm_data.update({ + 'status': { + 'status': '', + 'details': null, + 'timestamp': '' + } + }) %} + {% endif %} + {% do vms.update({hostname: vm_data}) %} + {% else %} + {% do salt.log.info('salt/hypervisor/map.jinja: Config file empty: ' ~ vm_file) %} {% endif %} {% endfor %} diff --git a/salt/hypervisor/tools/sbin/so-kvm-modify-hardware b/salt/hypervisor/tools/sbin/so-kvm-modify-hardware index a6becfb95..3d80ebaeb 100644 --- a/salt/hypervisor/tools/sbin/so-kvm-modify-hardware +++ b/salt/hypervisor/tools/sbin/so-kvm-modify-hardware @@ -25,7 +25,7 @@ used during VM provisioning and hardware reconfiguration tasks. -v, --vm Name of the virtual machine to modify. -c, --cpu Number of virtual CPUs to assign. -m, --memory Amount of memory to assign in MiB. - -p, --pci PCI hardware ID(s) to passthrough to the VM (e.g., 0000:c7:00.0). Can be specified multiple times. + -p, --pci PCI hardware ID(s) to passthrough to the VM (e.g., 0000:00:1f.2). Can be specified multiple times. Format: domain:bus:device.function -s, --start Start the VM after modification. @@ -124,16 +124,34 @@ The `so-kvm-modify-hardware` script modifies hardware parameters of KVM virtual - Both file and console logging are enabled for real-time monitoring - Log entries include timestamps and severity levels - Detailed error messages are logged for troubleshooting - """ import argparse import sys import libvirt import logging +import socket import xml.etree.ElementTree as ET +from io import StringIO from so_vm_utils import start_vm, stop_vm from so_logging_utils import setup_logging +import subprocess + +# Get hypervisor name from local hostname +HYPERVISOR = socket.gethostname() + +# Custom log handler to capture output +class StringIOHandler(logging.Handler): + def __init__(self): + super().__init__() + self.strio = StringIO() + + def emit(self, record): + msg = self.format(record) + self.strio.write(msg + '\n') + + def get_value(self): + return self.strio.getvalue() def parse_arguments(): parser = argparse.ArgumentParser(description='Modify hardware parameters of a KVM virtual machine.') @@ -226,12 +244,15 @@ def redefine_vm(conn, new_xml_desc, logger): def main(): # Set up logging using the so_logging_utils library + string_handler = StringIOHandler() + string_handler.setFormatter(logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')) logger = setup_logging( logger_name='so-kvm-modify-hardware', log_file_path='/opt/so/log/hypervisor/so-kvm-modify-hardware.log', log_level=logging.INFO, format_str='%(asctime)s - %(levelname)s - %(message)s' ) + logger.addHandler(string_handler) try: args = parse_arguments() @@ -247,6 +268,15 @@ def main(): conn = libvirt.open(None) except libvirt.libvirtError as e: logger.error(f"Failed to open connection to libvirt: {e}") + try: + subprocess.run([ + 'so-salt-emit-vm-deployment-status-event', + '-v', vm_name, + '-H', HYPERVISOR, + '-s', 'Hardware Configuration Failed' + ], check=True) + except subprocess.CalledProcessError as e: + logger.error(f"Failed to emit failure status event: {e}") sys.exit(1) # Stop VM if running @@ -262,16 +292,57 @@ def main(): if start_vm_flag: dom = conn.lookupByName(vm_name) start_vm(dom, logger) + logger.info(f"VM '{vm_name}' started successfully.") else: logger.info("VM start flag not provided; VM will remain stopped.") # Close connection conn.close() + + # Send success status event + try: + subprocess.run([ + 'so-salt-emit-vm-deployment-status-event', + '-v', vm_name, + '-H', HYPERVISOR, + '-s', 'Hardware Configuration' + ], check=True) + except subprocess.CalledProcessError as e: + logger.error(f"Failed to emit success status event: {e}") + except KeyboardInterrupt: - logger.error("Operation cancelled by user.") + error_msg = "Operation cancelled by user" + logger.error(error_msg) + try: + subprocess.run([ + 'so-salt-emit-vm-deployment-status-event', + '-v', vm_name, + '-H', HYPERVISOR, + '-s', 'Hardware Configuration Failed' + ], check=True) + except subprocess.CalledProcessError as e: + logger.error(f"Failed to emit failure status event: {e}") sys.exit(1) except Exception as e: - logger.error(f"An error occurred: {e}") + error_msg = str(e) + if "Failed to open connection to libvirt" in error_msg: + error_msg = f"Failed to connect to libvirt: {error_msg}" + elif "Failed to redefine VM" in error_msg: + error_msg = f"Failed to apply hardware changes: {error_msg}" + elif "Failed to modify VM XML" in error_msg: + error_msg = f"Failed to update hardware configuration: {error_msg}" + else: + error_msg = f"An error occurred: {error_msg}" + logger.error(error_msg) + try: + subprocess.run([ + 'so-salt-emit-vm-deployment-status-event', + '-v', vm_name, + '-h', HYPERVISOR, + '-s', 'Hardware Configuration Failed' + ], check=True) + except subprocess.CalledProcessError as e: + logger.error(f"Failed to emit failure status event: {e}") sys.exit(1) if __name__ == '__main__': diff --git a/salt/hypervisor/tools/sbin/so-qcow2-modify-network b/salt/hypervisor/tools/sbin/so-qcow2-modify-network index 5f0690542..b2651a9c7 100644 --- a/salt/hypervisor/tools/sbin/so-qcow2-modify-network +++ b/salt/hypervisor/tools/sbin/so-qcow2-modify-network @@ -118,7 +118,6 @@ The `so-qcow2-modify-network` script modifies network configuration within a QCO - Image mount/unmount operations - Validation failures - File access errors - """ import argparse @@ -127,20 +126,41 @@ import re import sys import logging import os +import socket import ipaddress import configparser import uuid from io import StringIO import libvirt from so_logging_utils import setup_logging +import subprocess + +# Get hypervisor name from local hostname +HYPERVISOR = socket.gethostname() + +# Custom log handler to capture output +class StringIOHandler(logging.Handler): + def __init__(self): + super().__init__() + self.strio = StringIO() + + def emit(self, record): + msg = self.format(record) + self.strio.write(msg + '\n') + + def get_value(self): + return self.strio.getvalue() # Set up logging using the so_logging_utils library +string_handler = StringIOHandler() +string_handler.setFormatter(logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')) logger = setup_logging( logger_name='so-qcow2-modify-network', log_file_path='/opt/so/log/hypervisor/so-qcow2-modify-network.log', log_level=logging.INFO, format_str='%(asctime)s - %(levelname)s - %(message)s' ) +logger.addHandler(string_handler) NETWORK_CONFIG_DIR = "/etc/NetworkManager/system-connections" @@ -403,6 +423,7 @@ def parse_arguments(): parser = argparse.ArgumentParser(description="Modify IPv4 settings in a QCOW2 image for a specified network interface.") parser.add_argument("-I", "--image", required=True, help="Path to the QCOW2 image.") parser.add_argument("-i", "--interface", required=True, help="Network interface to modify (e.g., enp1s0).") + parser.add_argument("-n", "--vm-name", required=True, help="Full name of the VM (hostname_role).") group = parser.add_mutually_exclusive_group(required=True) group.add_argument("--dhcp4", action="store_true", help="Configure interface for DHCP (IPv4).") group.add_argument("--static4", action="store_true", help="Configure interface for static IPv4 settings.") @@ -448,15 +469,47 @@ def main(): modify_network_config(args.image, args.interface, mode, args.ip4, args.gw4, args.dns4, args.search4) logger.info("Network configuration update completed successfully") + # Send success status event + try: + subprocess.run([ + 'so-salt-emit-vm-deployment-status-event', + '-v', args.vm_name, + '-H', HYPERVISOR, + '-s', 'IP Configuration' + ], check=True) + except subprocess.CalledProcessError as e: + logger.error(f"Failed to emit success status event: {e}") + except KeyboardInterrupt: - logger.error("Operation cancelled by user.") + error_msg = "Operation cancelled by user" + logger.error(error_msg) + try: + subprocess.run([ + 'so-salt-emit-vm-deployment-status-event', + '-v', args.vm_name, + '-H', HYPERVISOR, + '-s', 'IP Configuration Failed' + ], check=True) + except subprocess.CalledProcessError as e: + logger.error(f"Failed to emit failure status event: {e}") sys.exit(1) except Exception as e: - if "base domain is running" in str(e): + error_msg = str(e) + if "base domain is running" in error_msg: logger.error("Cannot proceed: Base domain must not be running when modifying network configuration") + error_msg = "Base domain must not be running when modifying network configuration" else: logger.error(f"An error occurred: {e}") + try: + subprocess.run([ + 'so-salt-emit-vm-deployment-status-event', + '-v', args.vm_name, + '-H', HYPERVISOR, + '-s', 'IP Configuration Failed' + ], check=True) + except subprocess.CalledProcessError as e: + logger.error(f"Failed to emit failure status event: {e}") sys.exit(1) -if __name__ == "__main__": +if __name__ == '__main__': main() diff --git a/salt/manager/tools/sbin/so-salt-cloud b/salt/manager/tools/sbin/so-salt-cloud index 1145c1b65..0d5f5c81c 100644 --- a/salt/manager/tools/sbin/so-salt-cloud +++ b/salt/manager/tools/sbin/so-salt-cloud @@ -489,7 +489,7 @@ def run_qcow2_modify_hardware_config(profile, vm_name, cpu=None, memory=None, pc except Exception as e: logger.error(f"An error occurred while running qcow2.modify_hardware_config: {e}") -def run_qcow2_modify_network_config(profile, mode, ip=None, gateway=None, dns=None, search_domain=None): +def run_qcow2_modify_network_config(profile, vm_name, mode, ip=None, gateway=None, dns=None, search_domain=None): hv_name = profile.split('-')[1] target = hv_name + "_*" image = '/nsm/libvirt/images/sool9/sool9.qcow2' @@ -500,6 +500,7 @@ def run_qcow2_modify_network_config(profile, mode, ip=None, gateway=None, dns=No 'image=' + image, 'interface=' + interface, 'mode=' + mode, + 'vm_name=' + vm_name, 'ip4=' + ip if ip else '', 'gw4=' + gateway if gateway else '', 'dns4=' + dns if dns else '', @@ -583,7 +584,7 @@ def main(): mode = "dhcp4" # Default to DHCP if not specified # Step 1: Modify network configuration - run_qcow2_modify_network_config(args.profile, mode, args.ip4, args.gw4, args.dns4, args.search4) + run_qcow2_modify_network_config(args.profile, args.vm_name, mode, args.ip4, args.gw4, args.dns4, args.search4) # Step 2: Provision the VM (without starting it) call_salt_cloud(args.profile, args.vm_name) diff --git a/salt/orch/dyanno_hypervisor.sls b/salt/orch/dyanno_hypervisor.sls new file mode 100644 index 000000000..0e2d91e7c --- /dev/null +++ b/salt/orch/dyanno_hypervisor.sls @@ -0,0 +1,97 @@ +{% do salt.log.info('dyanno_hypervisor_orch: Running') %} +{% set event_data = pillar.get('event_data', {}) %} +{% set event_tag = pillar.get('event_tag', '') %} +{% set timestamp = event_data.get('_stamp') %} +{% do salt.log.debug('dyanno_hypervisor_orch: tag: ' ~ event_tag) %} + + +{# Our custom tag #} +{% if event_tag.startswith('soc/dyanno/hypervisor') %} +{% set status_data = event_data.get('data')%} +{% do salt.log.debug('dyanno_hypervisor_orch: Received data: ' ~ status_data|json|string) %} +{% do salt.log.debug('dyanno_hypervisor_orch: Setting vm_name, hypervisor and status') %} +{% set vm_name = status_data.get('vm_name') %} +{% set hypervisor = status_data.get('hypervisor') %} +{% set status = status_data.get('status') %} +{% set details = status_data.get('details', '') %} +{% do salt.log.info('dyanno_hypervisor_orch: vm_name: ' ~ vm_name ~ ' hypervisor: ' ~ hypervisor ~ ' status: ' ~ status) %} +{% endif %} + +{# salt-cloud tag #} +{% if 'salt/cloud/' in event_tag and event_tag.endswith('/destroyed') %} +{% set status_data = event_data %} +{% do salt.log.debug('dyanno_hypervisor_orch: Setting vm_name, hypervisor and status') %} +{% do salt.log.debug('dyanno_hypervisor_orch: Received data: ' ~ status_data|json|string) %} +{% set vm_name = status_data.get('name') %} +{% set hypervisor = None %} +{% set status = status_data.get('event') %} +{% do salt.log.info('dyanno_hypervisor_orch: vm_name: ' ~ vm_name ~ ' hypervisor: ' ~ hypervisor ~ ' status: ' ~ status) %} +{% endif %} + +{# +{% if event_tag.startswith('soc/dyanno/hypervisor') %} +{% if vm_name and status and hypervisor %} +{% do salt.log.info('dyanno_hypervisor_orch: soc.dyanno.hypervisor.write_status state running - vm_name: ' ~ vm_name ~ ' hypervisor: ' ~ hypervisor ~ ' status: ' ~ status) %} +# Write status file + +write_vm_status: + salt.runner: + - name: state.orchestrate + - mods: soc.dyanno.hypervisor.write_status + - pillar: + vm_name: {{ vm_name }} + hypervisor: {{ hypervisor }} + status_data: + timestamp: {{ timestamp }} + status: {{ status }} + details: {{ details }} + event_tag: {{ event_tag }} + +write_vm_status: + salt.state: + - tgt: 'G@role:so-manager or G@role:so-managersearch or G@role:so-standalone or G@role:so-eval' + - tgt_type: compound + - sls: + - soc.dyanno.hypervisor.write_status + - concurrent: True + - pillar: + vm_name: {{ vm_name }} + hypervisor: {{ hypervisor }} + status_data: + timestamp: {{ timestamp }} + status: {{ status }} + details: {{ details }} + event_tag: {{ event_tag }} + + +{% else %} +{% do salt.log.error('dyanno_hypervisor_orch: Missing required fields - vm_name: ' ~ vm_name ~ ' hypervisor: ' ~ hypervisor ~ ' status: ' ~ status) %} +{% endif %} +{% endif %} +#} + +{# +update_hypervisor_status: + salt.runner: + - name: state.orchestrate + - mods: soc.dyanno.hypervisor +{% if event_tag.startswith('soc/dyanno/hypervisor') %} + - require: + - salt: write_vm_status +{% endif %} +#} + +# Update hypervisor status +update_hypervisor_annotation: + salt.state: + - tgt: 'G@role:so-manager or G@role:so-managersearch or G@role:so-standalone or G@role:so-eval' + - tgt_type: compound + - sls: + - soc.dyanno.hypervisor + - concurrent: True +{#% if event_tag.startswith('soc/dyanno/hypervisor') %} + - require: + - salt: write_vm_status +{% endif %#} + +{% do salt.log.info('dyanno_hypervisor_orch: Completed') %} \ No newline at end of file diff --git a/salt/reactor/createEmptyPillar.sls b/salt/reactor/createEmptyPillar.sls index a182e1338..dccf25f89 100644 --- a/salt/reactor/createEmptyPillar.sls +++ b/salt/reactor/createEmptyPillar.sls @@ -7,14 +7,32 @@ import logging import os +import pwd +import grp def run(): vm_name = data['kwargs']['name'] logging.error("createEmptyPillar reactor: vm_name: %s" % vm_name) pillar_root = '/opt/so/saltstack/local/pillar/minions/' pillar_files = ['adv_' + vm_name + '.sls', vm_name + '.sls'] - for f in pillar_files: - if not os.path.exists(pillar_root + f): - os.mknod(pillar_root + f) + + try: + # Get socore user and group IDs + socore_uid = pwd.getpwnam('socore').pw_uid + socore_gid = grp.getgrnam('socore').gr_gid + + for f in pillar_files: + full_path = pillar_root + f + if not os.path.exists(full_path): + # Create empty file + os.mknod(full_path) + # Set ownership to socore:socore + os.chown(full_path, socore_uid, socore_gid) + # Set mode to 644 (rw-r--r--) + os.chmod(full_path, 0o644) + logging.error("createEmptyPillar reactor: created %s with socore:socore ownership and mode 644" % f) + + except (KeyError, OSError) as e: + logging.error("createEmptyPillar reactor: Error setting ownership/permissions: %s" % str(e)) return {} diff --git a/salt/reactor/vm_status.sls b/salt/reactor/vm_status.sls new file mode 100644 index 000000000..5dc0c0f6d --- /dev/null +++ b/salt/reactor/vm_status.sls @@ -0,0 +1,117 @@ +{% do salt.log.debug('vm_status_reactor: Running') %} +{% do salt.log.debug('vm_status_reactor: tag: ' ~ tag | string) %} + +{# Remove all the nasty characters that exist in this data #} +{% if tag.startswith('salt/cloud/') and tag.endswith('/deploying') %} +{% set data = { + "_stamp": data._stamp, + "event": data.event, + "kwargs": { + "cloud_grains": data.kwargs.cloud_grains + } +} %} +{% endif %} + +{% do salt.log.debug('vm_status_reactor: Received data: ' ~ data|json|string) %} + +{# +update_hypervisor: + runner.state.orchestrate: + - args: + - mods: orch.dyanno_hypervisor + - pillar: + event_tag: {{ tag }} + event_data: {{ data }} +#} + +{# Our custom tag #} +{% if tag.startswith('soc/dyanno/hypervisor') %} +{% set status_data = data.get('data')%} +{% do salt.log.debug('vm_status_reactor: Received data: ' ~ status_data|json|string) %} +{% do salt.log.debug('vm_status_reactor: Setting vm_name, hypervisor and status') %} +{% set vm_name = status_data.get('vm_name') %} +{% set hypervisor = status_data.get('hypervisor') %} +{% set status = status_data.get('status') %} +{% set details = status_data.get('details', '') %} +{% endif %} + +{# setup/so-minion tag #} +{% if tag == ('setup/so-minion') %} +{% set status_data = data.get('data')%} +{% do salt.log.debug('vm_status_reactor: Received data: ' ~ status_data|json|string) %} +{% do salt.log.debug('vm_status_reactor: Setting vm_name, hypervisor and status') %} +{% set vm_name = data.get('id') %} + +{% set grains = salt.saltutil.runner('cache.grains', tgt=vm_name).get(vm_name) %} +{% if grains %} +{% do salt.log.debug('vm_status_reactor: Got cache.grains ' ~ grains|string) %} +{% if grains.get('salt-cloud').get('profile') %} +{% do salt.log.debug('vm_status_reactor: Found salt-cloud:profile grain: ' ~ grains.get('salt-cloud').get('profile')|string) %} +{% set hypervisor = grains.get('salt-cloud').get('profile').split('-')[1] %} +{% do salt.log.debug('vm_status_reactor: Got hypervisor: ' ~ hypervisor) %} +{% endif %} +{% else %} +{% do salt.log.debug('vm_status_reactor: Did not get cache.grains.') %} +{% endif %} + +{% set hypervisor = hypervisor %} +{% set status = 'Initialize Minion Pillars' %} +{% set details = status_data.get('details', '') %} +{% endif %} + +{# salt-cloud tag #} +{% if tag.startswith('salt/cloud/') and (tag.endswith('/creating') or tag.endswith('/deploying') or tag.endswith('/created') or tag.endswith('/destroyed')) %} +{% do salt.log.debug('vm_status_reactor: Received data: ' ~ data|json|string) %} +{% do salt.log.debug('vm_status_reactor: Setting vm_name, hypervisor and status') %} +{% set vm_name = tag.split('/')[2] %} +{% do salt.log.debug('vm_status_reactor: Got vm_name from tag: ' ~ vm_name) %} + +{% if tag.endswith('/deploying') %} +{% set hypervisor = data.get('kwargs').get('cloud_grains').get('profile').split('-')[1] %} +{% endif %} + +{% if data.get('profile', False) %} +{% do salt.log.debug('vm_status_reactor: Did not get cache.grains.') %} +{% set hypervisor = data.profile.split('-')[1] %} +{% do salt.log.debug('vm_status_reactor: Got hypervisor from data: ' ~ hypervisor) %} +{% else %} +{% set grains = salt.saltutil.runner('cache.grains', tgt=vm_name).get(vm_name) %} +{% if grains %} +{% do salt.log.debug('vm_status_reactor: Got cache.grains: ' ~ grains|string) %} +{% if grains.get('salt-cloud').get('profile') %} +{% do salt.log.debug('vm_status_reactor: Found salt-cloud:profile grain: ' ~ grains.get('salt-cloud').get('profile')|string) %} +{% set hypervisor = grains.get('salt-cloud').get('profile').split('-')[1] %} +{% do salt.log.debug('vm_status_reactor: Got hypervisor: ' ~ hypervisor) %} +{% endif %} +{% endif %} +{% endif %} + +{% set status = data.get('event').title() %} +{% set details = data.get('details', '') %} +{% endif %} + +{% do salt.log.info('vm_status_reactor: vm_name: ' ~ vm_name ~ ' hypervisor: ' ~ hypervisor ~ ' status: ' ~ status) %} + +{% set timestamp = data.get('_stamp') %} +write_vm_status: + runner.state.orchestrate: + - args: + - mods: soc.dyanno.hypervisor.write_status + - pillar: + vm_name: {{ vm_name }} + hypervisor: {{ hypervisor }} + status_data: + timestamp: {{ timestamp }} + status: {{ status }} + details: {{ details }} + event_tag: {{ tag }} + +update_hypervisor: + runner.state.orchestrate: + - args: + - mods: orch.dyanno_hypervisor + - pillar: + event_tag: {{ tag }} + event_data: {{ data }} + +{% do salt.log.debug('vm_status_reactor: Completed') %} \ No newline at end of file diff --git a/salt/salt/cloud/reactor_config_hypervisor.sls b/salt/salt/cloud/reactor_config_hypervisor.sls index 433e01f31..fcf1a5dfe 100644 --- a/salt/salt/cloud/reactor_config_hypervisor.sls +++ b/salt/salt/cloud/reactor_config_hypervisor.sls @@ -19,13 +19,21 @@ reactor_config_hypervisor: reactor: - 'salt/key': - salt://reactor/check_hypervisor.sls + - 'salt/cloud/*/creating': + - /opt/so/saltstack/default/salt/reactor/vm_status.sls - 'salt/cloud/*/deploying': - /opt/so/saltstack/default/salt/reactor/createEmptyPillar.sls + - /opt/so/saltstack/default/salt/reactor/vm_status.sls - 'setup/so-minion': - /opt/so/saltstack/default/salt/reactor/sominion_setup.sls + - /opt/so/saltstack/default/salt/reactor/vm_status.sls + - 'salt/cloud/*/created': + - /opt/so/saltstack/default/salt/reactor/vm_status.sls + - 'soc/dyanno/hypervisor/*': + - /opt/so/saltstack/default/salt/reactor/vm_status.sls - 'salt/cloud/*/destroyed': - - /opt/so/saltstack/default/salt/reactor/virtReleaseHardware.sls - /opt/so/saltstack/default/salt/reactor/deleteKey.sls + - /opt/so/saltstack/default/salt/reactor/vm_status.sls - user: root - group: root - mode: 644 diff --git a/salt/salt/engines/master/virtual_node_manager.py b/salt/salt/engines/master/virtual_node_manager.py index ef04032ce..9e59b3d9a 100644 --- a/salt/salt/engines/master/virtual_node_manager.py +++ b/salt/salt/engines/master/virtual_node_manager.py @@ -462,7 +462,8 @@ def create_vm_tracking_file(hypervisor_path: str, vm_name: str, config: dict) -> data = { 'config': config, - 'status': 'creating' + 'status': 'creating', + 'timestamp': datetime.now().isoformat() } # Write file and set ownership write_json_file(file_path, data) @@ -487,9 +488,10 @@ def mark_vm_failed(vm_file: str, error_code: int, message: str) -> None: data = { 'config': config, 'status': 'error', + 'timestamp': datetime.now().isoformat(), 'error_details': { - 'message': message, - 'timestamp': datetime.now().isoformat() + 'code': error_code, + 'message': message } } write_json_file(error_file, data) @@ -512,9 +514,10 @@ def mark_invalid_hardware(hypervisor_path: str, vm_name: str, config: dict, erro data = { 'config': config, 'status': 'error', + 'timestamp': datetime.now().isoformat(), 'error_details': { - 'message': full_message, - 'timestamp': datetime.now().isoformat() + 'code': 3, # Hardware validation failure code + 'message': full_message } } write_json_file(file_path, data) @@ -577,6 +580,17 @@ def process_vm_creation(hypervisor_path: str, vm_config: dict) -> None: model = get_hypervisor_model(hypervisor) model_config = load_hardware_defaults(model) + # Send Processing status event + try: + subprocess.run([ + 'so-salt-emit-vm-deployment-status-event', + '-v', vm_name, + '-H', hypervisor, + '-s', 'Processing' + ], check=True) + except subprocess.CalledProcessError as e: + logger.error(f"Failed to emit success status event: {e}") + # Initial hardware validation against model is_valid, errors = validate_hardware_request(model_config, vm_config) if not is_valid: @@ -626,10 +640,11 @@ def process_vm_creation(hypervisor_path: str, vm_config: dict) -> None: # Execute command result = subprocess.run(cmd, capture_output=True, text=True, check=True) - # Update tracking file status + # Update tracking file status with timestamp tracking_file = os.path.join(hypervisor_path, vm_name) data = read_json_file(tracking_file) data['status'] = 'running' + data['timestamp'] = datetime.now().isoformat() write_json_file(tracking_file, data) except subprocess.CalledProcessError as e: @@ -721,7 +736,8 @@ def process_hypervisor(hypervisor_path: str) -> None: existing_vms = set() for file_path in glob.glob(os.path.join(hypervisor_path, '*_*')): basename = os.path.basename(file_path) - if not basename.endswith('.error'): + # Skip error and status files + if not basename.endswith('.error') and not basename.endswith('.status'): existing_vms.add(basename) # Process new VMs diff --git a/salt/soc/dyanno/hypervisor/init.sls b/salt/soc/dyanno/hypervisor/init.sls index 5645a8f63..5914cdf5b 100644 --- a/salt/soc/dyanno/hypervisor/init.sls +++ b/salt/soc/dyanno/hypervisor/init.sls @@ -5,6 +5,8 @@ hypervisor_annotation: - name: /opt/so/saltstack/default/salt/hypervisor/soc_hypervisor.yaml - source: salt://soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja - template: jinja + - user: socore + - group: socore - defaults: HYPERVISORS: {{ HYPERVISORS }} diff --git a/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja b/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja index f5ce34563..f24ca69da 100644 --- a/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja +++ b/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja @@ -3,8 +3,27 @@ {%- set TEMPLATE = ANNOTATION.hypervisor.hosts.pop('defaultHost') -%} -{%- macro update_description(description, cpu_free, mem_free, disk_free, copper_free, sfp_free) -%} -{{- description -}} +{%- macro update_description(description, cpu_free, mem_free, disk_free, copper_free, sfp_free, vm_list) -%} +{{- description }} + +Resource Summary: +- CPU: {{ cpu_free }} cores available +- Memory: {{ mem_free }}GB available +- Disk Slots: {{ disk_free if disk_free else 'None' }} available +- Copper Ports: {{ copper_free if copper_free else 'None' }} available +- SFP Ports: {{ sfp_free if sfp_free else 'None' }} available + +{%- if vm_list %} +Virtual Machines: +{%- for hostname, vm_data in vm_list.items() %} +- {{ hostname }}: + Status: {{ vm_data.get('status', {}).get('status', 'Unknown') }} + Details: {{ vm_data.get('status', {}).get('details', 'No details available') }} + Last Updated: {{ vm_data.get('status', {}).get('timestamp', 'Never') }} +{%- endfor %} +{%- else %} +No Virtual Machines Found +{%- endif %} {%- endmacro -%} {%- macro update_label(label, total, free) -%} @@ -91,7 +110,8 @@ mem_free, disk_free, copper_free, - sfp_free + sfp_free, + vms ) }) -%} {%- do ANNOTATION.hypervisor.hosts.update({hypervisor ~ 'VMs': updated_template}) -%} diff --git a/salt/soc/dyanno/hypervisor/write_status.sls b/salt/soc/dyanno/hypervisor/write_status.sls new file mode 100644 index 000000000..96dcf7e9f --- /dev/null +++ b/salt/soc/dyanno/hypervisor/write_status.sls @@ -0,0 +1,69 @@ +{% do salt.log.info('soc/dyanno/hypervisor/write_status: Running') %} +{% set vm_name = pillar.get('vm_name') %} +{% set hypervisor = pillar.get('hypervisor') %} +{% set status_data = pillar.get('status_data', {}) %} +{% set event_tag = pillar.get('event_tag') %} +{% do salt.log.debug('soc/dyanno/hypervisor/write_status: tag: ' ~ event_tag) %} +{% set base_path = '/opt/so/saltstack/local/salt/hypervisor/hosts' %} +{% set status_dir = base_path ~ '/' ~ hypervisor %} +{% set status_file = status_dir ~ '/' ~ vm_name ~ '.status' %} + +# Define the list of process steps in order (case-sensitive) +{% set process_steps = ['Processing', 'IP Configuration', 'Starting Create', 'Executing Deploy Script', 'Initialize Minion Pillars', 'Created Instance', 'Hardware Configuration', 'Highstate Triggered', 'Destroyed Instance'] %} +{% set new_index = process_steps.index(status_data.get('status')) %} +{% do salt.log.debug('soc/dyanno/hypervisor/write_status: new_index: ' ~ new_index|string) %} + +# Function to read and parse current JSON status file +{% macro get_current_status(status_file) %} +{% do salt.log.debug('soc/dyanno/hypervisor/write_status: getting current status from file: ' ~ status_file) %} + +{% set rel_path_status_file = 'hypervisor/hosts' ~ '/' ~ hypervisor ~ '/' ~ vm_name ~ '.status' %} +{# If the status file doesn't exist, then we are just now Processing, so return -1 #} +{% if salt['file.file_exists'](status_file)%} +{% import_json rel_path_status_file as current_status %} +{% do salt.log.debug('soc/dyanno/hypervisor/write_status: current status: ' ~ current_status) %} +{% do salt.log.debug('soc/dyanno/hypervisor/write_status: current status: ' ~ current_status.get('status')) %} +{% if current_status.get('status') in process_steps %} +{% set current_index = process_steps.index(current_status.get('status')) %} +{% do salt.log.debug('soc/dyanno/hypervisor/write_status: current_index: ' ~ current_index|string) %} +{%- set return_value = current_index -%} +{% else %} +{%- set return_value = -1 -%} +{% endif %} +{% else %} +{% set return_value = -1 %} +{% endif %} +{{- return_value -}} +{% endmacro %} + +{% set current_index = get_current_status(status_file)|int %} +{% do salt.log.debug('soc/dyanno/hypervisor/write_status: ' ~ status_file ~ ' current status index: ' ~ current_index|string) %} + +ensure_status_dir: + file.directory: + - name: {{ status_dir }} + - user: 939 + - group: 939 + - mode: 755 + - makedirs: True + + +{# Some of the status updates trigger within a second of each other can can cause, for example, IP Configuration orchestration to process before the Processing #} +{# This check has been put in place to ensure a status sooner in the process can't overwrite this file if a status later in the process wrote to it first. #} +{# The final step is Destroyed, so we allow Processing to overwrite that incase someone creates a new VM with same name that was previously destroyed. #} +{% if new_index > current_index or current_index == process_steps | length - 1 %} +write_status_file: + file.serialize: + - name: {{ status_file }} + - dataset: {{ status_data|json }} + - formatter: json + - user: 939 + - group: 939 + - mode: 600 + - indent: 2 + - require: + - file: ensure_status_dir +{% else %} +{% do salt.log.debug('soc/dyanno/hypervisor/write_status: File not written. ' ~ process_steps[new_index] ~ ' cannot overwrite ' ~ process_steps[current_index] ~ '.' ) %} +{% endif %} +{% do salt.log.info('soc/dyanno/hypervisor/write_status: Completed') %} diff --git a/salt/top.sls b/salt/top.sls index 82f074626..0d22bd782 100644 --- a/salt/top.sls +++ b/salt/top.sls @@ -11,6 +11,7 @@ base: 'salt-cloud:driver:libvirt': - match: grain - storage + - vm_status '*': - cron.running diff --git a/salt/vm_status/init.sls b/salt/vm_status/init.sls new file mode 100644 index 000000000..ba2b21968 --- /dev/null +++ b/salt/vm_status/init.sls @@ -0,0 +1,10 @@ +# Send highstate trigger event for VM deployment status tracking +# so-salt-emit-vm-deployment-status sets event_tag = f'soc/dyanno/hypervisor/{status.lower()}' +vm_highstate_trigger: + event.send: + - name: soc/dyanno/hypervisor/highstate triggered + - data: + status: Highstate Triggered + vm_name: {{ grains.id }} + hypervisor: {{ salt['grains.get']('salt-cloud:profile', '').split('-')[1] }} + - order: 1 # Ensure this runs early in the highstate process \ No newline at end of file From 3246176c0a8c5c076be29c6b6f7ffabea2ddc1be Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Fri, 21 Feb 2025 14:34:08 -0500 Subject: [PATCH 135/315] comments --- .../so-salt-emit-vm-deployment-status-event | 18 +++++++++- salt/hypervisor/init.sls | 7 ++++ salt/hypervisor/map.jinja | 25 +++++++++++++- .../so-kvm-modify-hardware | 16 +++++++++ .../so-qcow2-modify-network | 16 +++++++++ .../tools/{sbin => sbin_jinja}/so-salt-cloud | 16 +++++++++ salt/orch/dyanno_hypervisor.sls | 27 +++++++++++++-- salt/reactor/vm_status.sls | 7 +++- .../engines/master/virtual_node_manager.py | 6 ++++ salt/soc/dyanno/hypervisor/init.sls | 33 ++++++++++++++++--- .../hypervisor/soc_hypervisor.yaml.jinja | 23 +++++++++++++ salt/soc/dyanno/hypervisor/write_status.sls | 26 +++++++++++++++ salt/vm_status/init.sls | 27 ++++++++++++++- 13 files changed, 237 insertions(+), 10 deletions(-) rename salt/common/tools/{sbin => sbin_jinja}/so-salt-emit-vm-deployment-status-event (84%) rename salt/hypervisor/tools/{sbin => sbin_jinja}/so-kvm-modify-hardware (95%) rename salt/hypervisor/tools/{sbin => sbin_jinja}/so-qcow2-modify-network (97%) rename salt/manager/tools/{sbin => sbin_jinja}/so-salt-cloud (97%) diff --git a/salt/common/tools/sbin/so-salt-emit-vm-deployment-status-event b/salt/common/tools/sbin_jinja/so-salt-emit-vm-deployment-status-event similarity index 84% rename from salt/common/tools/sbin/so-salt-emit-vm-deployment-status-event rename to salt/common/tools/sbin_jinja/so-salt-emit-vm-deployment-status-event index 454e1ba9b..61f071130 100644 --- a/salt/common/tools/sbin/so-salt-emit-vm-deployment-status-event +++ b/salt/common/tools/sbin_jinja/so-salt-emit-vm-deployment-status-event @@ -4,6 +4,14 @@ # or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at # https://securityonion.net/license; you may not use this file except in compliance with the # Elastic License 2.0. +# +# Note: Per the Elastic License 2.0, the second limitation states: +# +# "You may not move, change, disable, or circumvent the license key functionality +# in the software, and you may not remove or obscure any functionality in the +# software that is protected by the license key." + +{% if 'hvn' in salt['pillar.get']('features', []) -%} """ Script for emitting VM deployment status events to the Salt event bus. @@ -113,4 +121,12 @@ def main(): sys.exit(1) if __name__ == '__main__': - main() \ No newline at end of file + main() + +{%- else -%} + +echo "Hypervisor nodes are a feature supported only for customers with a valid license. \ + Contact Security Onion Solutions, LLC via our website at https://securityonionsolutions.com \ + for more information about purchasing a license to enable this feature." + +{% endif -%} diff --git a/salt/hypervisor/init.sls b/salt/hypervisor/init.sls index 7bec6f25c..677ab8642 100644 --- a/salt/hypervisor/init.sls +++ b/salt/hypervisor/init.sls @@ -23,6 +23,13 @@ hypervisor_sbin: - source: salt://hypervisor/tools/sbin - file_mode: 744 +hypervisor_sbin_jinja: + file.recurse: + - name: /usr/sbin + - source: salt://hypervisor/tools/sbin_jinja + - template: jinja + - file_mode: 744 + {% else %} {{sls}}_no_license_detected: test.fail_without_changes: diff --git a/salt/hypervisor/map.jinja b/salt/hypervisor/map.jinja index cf323f51d..a9a76e557 100644 --- a/salt/hypervisor/map.jinja +++ b/salt/hypervisor/map.jinja @@ -1,3 +1,16 @@ +{# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one + or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at + https://securityonion.net/license; you may not use this file except in compliance with the + Elastic License 2.0. + + Note: Per the Elastic License 2.0, the second limitation states: + + "You may not move, change, disable, or circumvent the license key functionality + in the software, and you may not remove or obscure any functionality in the + software that is protected by the license key." #} + +{% if 'hvn' in salt['pillar.get']('features', []) %} + {# Import defaults.yaml for model hardware capabilities #} {% import_yaml 'hypervisor/defaults.yaml' as DEFAULTS %} @@ -82,4 +95,14 @@ } }) %} {% endfor %} -{% endfor %} \ No newline at end of file +{% endfor %} + +{% else %} + +{% do salt.log.error( + 'Hypervisor nodes are a feature supported only for customers with a valid license.' + 'Contact Security Onion Solutions, LLC via our website at https://securityonionsolutions.com' + 'for more information about purchasing a license to enable this feature.' +) %} + +{% endif %} diff --git a/salt/hypervisor/tools/sbin/so-kvm-modify-hardware b/salt/hypervisor/tools/sbin_jinja/so-kvm-modify-hardware similarity index 95% rename from salt/hypervisor/tools/sbin/so-kvm-modify-hardware rename to salt/hypervisor/tools/sbin_jinja/so-kvm-modify-hardware index 3d80ebaeb..25506a0ae 100644 --- a/salt/hypervisor/tools/sbin/so-kvm-modify-hardware +++ b/salt/hypervisor/tools/sbin_jinja/so-kvm-modify-hardware @@ -4,6 +4,14 @@ # or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at # https://securityonion.net/license; you may not use this file except in compliance with the # Elastic License 2.0. +# +# Note: Per the Elastic License 2.0, the second limitation states: +# +# "You may not move, change, disable, or circumvent the license key functionality +# in the software, and you may not remove or obscure any functionality in the +# software that is protected by the license key." + +{% if 'hvn' in salt['pillar.get']('features', []) %} """ Script for managing hardware configurations of KVM virtual machines. This script provides @@ -347,3 +355,11 @@ def main(): if __name__ == '__main__': main() + +{%- else -%} + +echo "Hypervisor nodes are a feature supported only for customers with a valid license. \ + Contact Security Onion Solutions, LLC via our website at https://securityonionsolutions.com \ + for more information about purchasing a license to enable this feature." + +{% endif -%} diff --git a/salt/hypervisor/tools/sbin/so-qcow2-modify-network b/salt/hypervisor/tools/sbin_jinja/so-qcow2-modify-network similarity index 97% rename from salt/hypervisor/tools/sbin/so-qcow2-modify-network rename to salt/hypervisor/tools/sbin_jinja/so-qcow2-modify-network index b2651a9c7..cd7869fd8 100644 --- a/salt/hypervisor/tools/sbin/so-qcow2-modify-network +++ b/salt/hypervisor/tools/sbin_jinja/so-qcow2-modify-network @@ -4,6 +4,14 @@ # or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at # https://securityonion.net/license; you may not use this file except in compliance with the # Elastic License 2.0. +# +# Note: Per the Elastic License 2.0, the second limitation states: +# +# "You may not move, change, disable, or circumvent the license key functionality +# in the software, and you may not remove or obscure any functionality in the +# software that is protected by the license key." + +{% if 'hvn' in salt['pillar.get']('features', []) -%} """ Script for modifying network configurations within QCOW2 virtual machine images. This script provides @@ -513,3 +521,11 @@ def main(): if __name__ == '__main__': main() + +{%- else -%} + +echo "Hypervisor nodes are a feature supported only for customers with a valid license. \ + Contact Security Onion Solutions, LLC via our website at https://securityonionsolutions.com \ + for more information about purchasing a license to enable this feature." + +{% endif -%} diff --git a/salt/manager/tools/sbin/so-salt-cloud b/salt/manager/tools/sbin_jinja/so-salt-cloud similarity index 97% rename from salt/manager/tools/sbin/so-salt-cloud rename to salt/manager/tools/sbin_jinja/so-salt-cloud index 0d5f5c81c..cddcbb474 100644 --- a/salt/manager/tools/sbin/so-salt-cloud +++ b/salt/manager/tools/sbin_jinja/so-salt-cloud @@ -4,6 +4,14 @@ # or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at # https://securityonion.net/license; you may not use this file except in compliance with the # Elastic License 2.0. +# +# Note: Per the Elastic License 2.0, the second limitation states: +# +# "You may not move, change, disable, or circumvent the license key functionality +# in the software, and you may not remove or obscure any functionality in the +# software that is protected by the license key." + +{% if 'hvn' in salt['pillar.get']('features', []) -%} """ Script for automated virtual machine provisioning and configuration in Security Onion's virtualization infrastructure. @@ -601,3 +609,11 @@ def main(): if __name__ == "__main__": main() + +{%- else -%} + +echo "Hypervisor nodes are a feature supported only for customers with a valid license. \ + Contact Security Onion Solutions, LLC via our website at https://securityonionsolutions.com \ + for more information about purchasing a license to enable this feature." + +{% endif -%} diff --git a/salt/orch/dyanno_hypervisor.sls b/salt/orch/dyanno_hypervisor.sls index 0e2d91e7c..9bac12a6b 100644 --- a/salt/orch/dyanno_hypervisor.sls +++ b/salt/orch/dyanno_hypervisor.sls @@ -1,3 +1,16 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. +# +# Note: Per the Elastic License 2.0, the second limitation states: +# +# "You may not move, change, disable, or circumvent the license key functionality +# in the software, and you may not remove or obscure any functionality in the +# software that is protected by the license key." + +{% if 'hvn' in salt['pillar.get']('features', []) %} + {% do salt.log.info('dyanno_hypervisor_orch: Running') %} {% set event_data = pillar.get('event_data', {}) %} {% set event_tag = pillar.get('event_tag', '') %} @@ -70,7 +83,7 @@ write_vm_status: {% endif %} #} -{# +{# We will need to populate hypervisor:hosts in this orch and pass to state to run as runner update_hypervisor_status: salt.runner: - name: state.orchestrate @@ -94,4 +107,14 @@ update_hypervisor_annotation: - salt: write_vm_status {% endif %#} -{% do salt.log.info('dyanno_hypervisor_orch: Completed') %} \ No newline at end of file +{% do salt.log.info('dyanno_hypervisor_orch: Completed') %} + +{% else %} + +{% do salt.log.error( + 'Hypervisor nodes are a feature supported only for customers with a valid license.' + 'Contact Security Onion Solutions, LLC via our website at https://securityonionsolutions.com' + 'for more information about purchasing a license to enable this feature.' +) %} + +{% endif %} diff --git a/salt/reactor/vm_status.sls b/salt/reactor/vm_status.sls index 5dc0c0f6d..5e32ac18f 100644 --- a/salt/reactor/vm_status.sls +++ b/salt/reactor/vm_status.sls @@ -1,3 +1,8 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + {% do salt.log.debug('vm_status_reactor: Running') %} {% do salt.log.debug('vm_status_reactor: tag: ' ~ tag | string) %} @@ -114,4 +119,4 @@ update_hypervisor: event_tag: {{ tag }} event_data: {{ data }} -{% do salt.log.debug('vm_status_reactor: Completed') %} \ No newline at end of file +{% do salt.log.debug('vm_status_reactor: Completed') %} diff --git a/salt/salt/engines/master/virtual_node_manager.py b/salt/salt/engines/master/virtual_node_manager.py index 9e59b3d9a..98a4eb572 100644 --- a/salt/salt/engines/master/virtual_node_manager.py +++ b/salt/salt/engines/master/virtual_node_manager.py @@ -4,6 +4,12 @@ # or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at # https://securityonion.net/license; you may not use this file except in compliance with the # Elastic License 2.0. +# +# Note: Per the Elastic License 2.0, the second limitation states: +# +# "You may not move, change, disable, or circumvent the license key functionality +# in the software, and you may not remove or obscure any functionality in the +# software that is protected by the license key." """ Salt Engine for Virtual Node Management diff --git a/salt/soc/dyanno/hypervisor/init.sls b/salt/soc/dyanno/hypervisor/init.sls index 5914cdf5b..f29ef0367 100644 --- a/salt/soc/dyanno/hypervisor/init.sls +++ b/salt/soc/dyanno/hypervisor/init.sls @@ -1,4 +1,17 @@ -{% from 'hypervisor/map.jinja' import HYPERVISORS %} +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. +# +# Note: Per the Elastic License 2.0, the second limitation states: +# +# "You may not move, change, disable, or circumvent the license key functionality +# in the software, and you may not remove or obscure any functionality in the +# software that is protected by the license key." + +{% if 'hvn' in salt['pillar.get']('features', []) %} + +{% from 'hypervisor/map.jinja' import HYPERVISORS %} hypervisor_annotation: file.managed: @@ -10,8 +23,8 @@ hypervisor_annotation: - defaults: HYPERVISORS: {{ HYPERVISORS }} -{% for role in HYPERVISORS %} -{% for hypervisor in HYPERVISORS[role].keys() %} +{% for role in HYPERVISORS %} +{% for hypervisor in HYPERVISORS[role].keys() %} hypervisor_host_directory_{{hypervisor}}: file.directory: - name: /opt/so/saltstack/local/salt/hypervisor/hosts/{{hypervisor}} @@ -21,5 +34,17 @@ hypervisor_host_directory_{{hypervisor}}: - recurse: - user - group +{% endfor %} {% endfor %} -{% endfor %} + +{% else %} + +{{sls}}_no_license_detected: + test.fail_without_changes: + - name: {{sls}}_no_license_detected + - comment: + - "Hypervisor nodes are a feature supported only for customers with a valid license. + Contact Security Onion Solutions, LLC via our website at https://securityonionsolutions.com + for more information about purchasing a license to enable this feature." + +{% endif %} diff --git a/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja b/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja index f24ca69da..453aa436c 100644 --- a/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja +++ b/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja @@ -1,3 +1,16 @@ +{# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one + or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at + https://securityonion.net/license; you may not use this file except in compliance with the + Elastic License 2.0. + + Note: Per the Elastic License 2.0, the second limitation states: + + "You may not move, change, disable, or circumvent the license key functionality + in the software, and you may not remove or obscure any functionality in the + software that is protected by the license key." #} + +{%- if 'hvn' in salt['pillar.get']('features', []) -%} + {%- import_yaml 'soc/dyanno/hypervisor/hypervisor.yaml' as ANNOTATION -%} {%- from 'hypervisor/map.jinja' import HYPERVISORS -%} @@ -119,3 +132,13 @@ No Virtual Machines Found {%- endfor -%} {{- ANNOTATION | yaml(False) -}} + +{%- else -%} + +{%- do salt.log.error( + 'Hypervisor nodes are a feature supported only for customers with a valid license.' + 'Contact Security Onion Solutions, LLC via our website at https://securityonionsolutions.com' + 'for more information about purchasing a license to enable this feature.' +) -%} + +{%- endif -%} diff --git a/salt/soc/dyanno/hypervisor/write_status.sls b/salt/soc/dyanno/hypervisor/write_status.sls index 96dcf7e9f..4babf7687 100644 --- a/salt/soc/dyanno/hypervisor/write_status.sls +++ b/salt/soc/dyanno/hypervisor/write_status.sls @@ -1,3 +1,16 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. +# +# Note: Per the Elastic License 2.0, the second limitation states: +# +# "You may not move, change, disable, or circumvent the license key functionality +# in the software, and you may not remove or obscure any functionality in the +# software that is protected by the license key." + +{% if 'hvn' in salt['pillar.get']('features', []) %} + {% do salt.log.info('soc/dyanno/hypervisor/write_status: Running') %} {% set vm_name = pillar.get('vm_name') %} {% set hypervisor = pillar.get('hypervisor') %} @@ -64,6 +77,19 @@ write_status_file: - require: - file: ensure_status_dir {% else %} + {% do salt.log.debug('soc/dyanno/hypervisor/write_status: File not written. ' ~ process_steps[new_index] ~ ' cannot overwrite ' ~ process_steps[current_index] ~ '.' ) %} + {% endif %} + {% do salt.log.info('soc/dyanno/hypervisor/write_status: Completed') %} + +{% else %} + +{% do salt.log.error( + 'Hypervisor nodes are a feature supported only for customers with a valid license.' + 'Contact Security Onion Solutions, LLC via our website at https://securityonionsolutions.com' + 'for more information about purchasing a license to enable this feature.' +) %} + +{% endif %} diff --git a/salt/vm_status/init.sls b/salt/vm_status/init.sls index ba2b21968..c6b39c12e 100644 --- a/salt/vm_status/init.sls +++ b/salt/vm_status/init.sls @@ -1,3 +1,16 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. +# +# Note: Per the Elastic License 2.0, the second limitation states: +# +# "You may not move, change, disable, or circumvent the license key functionality +# in the software, and you may not remove or obscure any functionality in the +# software that is protected by the license key." + +{% if 'hvn' in salt['pillar.get']('features', []) %} + # Send highstate trigger event for VM deployment status tracking # so-salt-emit-vm-deployment-status sets event_tag = f'soc/dyanno/hypervisor/{status.lower()}' vm_highstate_trigger: @@ -7,4 +20,16 @@ vm_highstate_trigger: status: Highstate Triggered vm_name: {{ grains.id }} hypervisor: {{ salt['grains.get']('salt-cloud:profile', '').split('-')[1] }} - - order: 1 # Ensure this runs early in the highstate process \ No newline at end of file + - order: 1 # Ensure this runs early in the highstate process + +{% else %} + +{{sls}}_no_license_detected: + test.fail_without_changes: + - name: {{sls}}_no_license_detected + - comment: + - "Hypervisor nodes are a feature supported only for customers with a valid license. + Contact Security Onion Solutions, LLC via our website at https://securityonionsolutions.com + for more information about purchasing a license to enable this feature." + +{% endif %} From fd9a4966ec29ffba13cdde365e56a090da30c60e Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Sun, 23 Feb 2025 14:07:51 -0500 Subject: [PATCH 136/315] move logic from reactor to orchestration --- salt/orch/dyanno_hypervisor.sls | 124 +++++++++++++++++--------------- salt/reactor/vm_status.sls | 108 +++------------------------- 2 files changed, 76 insertions(+), 156 deletions(-) diff --git a/salt/orch/dyanno_hypervisor.sls b/salt/orch/dyanno_hypervisor.sls index 9bac12a6b..959a4a9c4 100644 --- a/salt/orch/dyanno_hypervisor.sls +++ b/salt/orch/dyanno_hypervisor.sls @@ -12,76 +12,72 @@ {% if 'hvn' in salt['pillar.get']('features', []) %} {% do salt.log.info('dyanno_hypervisor_orch: Running') %} -{% set event_data = pillar.get('event_data', {}) %} -{% set event_tag = pillar.get('event_tag', '') %} -{% set timestamp = event_data.get('_stamp') %} -{% do salt.log.debug('dyanno_hypervisor_orch: tag: ' ~ event_tag) %} - +{% set data = pillar.get('data', {}) %} +{% set tag = pillar.get('tag', '') %} +{% set timestamp = data.get('_stamp') %} +{% do salt.log.debug('dyanno_hypervisor_orch: tag: ' ~ tag) %} +{% do salt.log.debug('dyanno_hypervisor_orch: Received data: ' ~ data|json|string) %} {# Our custom tag #} -{% if event_tag.startswith('soc/dyanno/hypervisor') %} -{% set status_data = event_data.get('data')%} +{% if tag.startswith('soc/dyanno/hypervisor') %} +{% set status_data = data.get('data')%} {% do salt.log.debug('dyanno_hypervisor_orch: Received data: ' ~ status_data|json|string) %} {% do salt.log.debug('dyanno_hypervisor_orch: Setting vm_name, hypervisor and status') %} {% set vm_name = status_data.get('vm_name') %} {% set hypervisor = status_data.get('hypervisor') %} {% set status = status_data.get('status') %} -{% set details = status_data.get('details', '') %} -{% do salt.log.info('dyanno_hypervisor_orch: vm_name: ' ~ vm_name ~ ' hypervisor: ' ~ hypervisor ~ ' status: ' ~ status) %} +{% endif %} + +{# setup/so-minion tag #} +{% if tag == ('setup/so-minion') %} +{% set status_data = data.get('data')%} +{% do salt.log.debug('dyanno_hypervisor_orch: Received data: ' ~ status_data|json|string) %} +{% do salt.log.debug('dyanno_hypervisor_orch: Setting vm_name, hypervisor and status') %} +{% set vm_name = data.get('id') %} +{% set grains = salt.saltutil.runner('cache.grains', tgt=vm_name).get(vm_name) %} +{% if grains %} +{% do salt.log.debug('dyanno_hypervisor_orch: Got cache.grains ' ~ grains|string) %} +{% if grains.get('salt-cloud').get('profile') %} +{% do salt.log.debug('dyanno_hypervisor_orch: Found salt-cloud:profile grain: ' ~ grains.get('salt-cloud').get('profile')|string) %} +{% set hypervisor = grains.get('salt-cloud').get('profile').split('-')[1] %} +{% do salt.log.debug('dyanno_hypervisor_orch: Got hypervisor: ' ~ hypervisor) %} +{% endif %} +{% else %} +{% do salt.log.debug('dyanno_hypervisor_orch: Did not get cache.grains.') %} +{% endif %} +{% set hypervisor = hypervisor %} +{% set status = 'Initialize Minion Pillars' %} {% endif %} {# salt-cloud tag #} -{% if 'salt/cloud/' in event_tag and event_tag.endswith('/destroyed') %} -{% set status_data = event_data %} +{% if tag.startswith('salt/cloud/') and (tag.endswith('/creating') or tag.endswith('/deploying') or tag.endswith('/created') or tag.endswith('/destroyed')) %} +{% do salt.log.debug('dyanno_hypervisor_orch: Received data: ' ~ data|json|string) %} {% do salt.log.debug('dyanno_hypervisor_orch: Setting vm_name, hypervisor and status') %} -{% do salt.log.debug('dyanno_hypervisor_orch: Received data: ' ~ status_data|json|string) %} -{% set vm_name = status_data.get('name') %} -{% set hypervisor = None %} -{% set status = status_data.get('event') %} -{% do salt.log.info('dyanno_hypervisor_orch: vm_name: ' ~ vm_name ~ ' hypervisor: ' ~ hypervisor ~ ' status: ' ~ status) %} -{% endif %} - -{# -{% if event_tag.startswith('soc/dyanno/hypervisor') %} -{% if vm_name and status and hypervisor %} -{% do salt.log.info('dyanno_hypervisor_orch: soc.dyanno.hypervisor.write_status state running - vm_name: ' ~ vm_name ~ ' hypervisor: ' ~ hypervisor ~ ' status: ' ~ status) %} -# Write status file - -write_vm_status: - salt.runner: - - name: state.orchestrate - - mods: soc.dyanno.hypervisor.write_status - - pillar: - vm_name: {{ vm_name }} - hypervisor: {{ hypervisor }} - status_data: - timestamp: {{ timestamp }} - status: {{ status }} - details: {{ details }} - event_tag: {{ event_tag }} - -write_vm_status: - salt.state: - - tgt: 'G@role:so-manager or G@role:so-managersearch or G@role:so-standalone or G@role:so-eval' - - tgt_type: compound - - sls: - - soc.dyanno.hypervisor.write_status - - concurrent: True - - pillar: - vm_name: {{ vm_name }} - hypervisor: {{ hypervisor }} - status_data: - timestamp: {{ timestamp }} - status: {{ status }} - details: {{ details }} - event_tag: {{ event_tag }} - - -{% else %} -{% do salt.log.error('dyanno_hypervisor_orch: Missing required fields - vm_name: ' ~ vm_name ~ ' hypervisor: ' ~ hypervisor ~ ' status: ' ~ status) %} +{% set vm_name = tag.split('/')[2] %} +{% do salt.log.debug('dyanno_hypervisor_orch: Got vm_name from tag: ' ~ vm_name) %} +{% if tag.endswith('/deploying') %} +{% set hypervisor = data.get('kwargs').get('cloud_grains').get('profile').split('-')[1] %} {% endif %} +{% if data.get('profile', False) %} +{% do salt.log.debug('dyanno_hypervisor_orch: Did not get cache.grains.') %} +{% set hypervisor = data.profile.split('-')[1] %} +{% do salt.log.debug('dyanno_hypervisor_orch: Got hypervisor from data: ' ~ hypervisor) %} +{% else %} +{% set grains = salt.saltutil.runner('cache.grains', tgt=vm_name).get(vm_name) %} +{% if grains %} +{% do salt.log.debug('dyanno_hypervisor_orch: Got cache.grains: ' ~ grains|string) %} +{% if grains.get('salt-cloud').get('profile') %} +{% do salt.log.debug('dyanno_hypervisor_orch: Found salt-cloud:profile grain: ' ~ grains.get('salt-cloud').get('profile')|string) %} +{% set hypervisor = grains.get('salt-cloud').get('profile').split('-')[1] %} +{% do salt.log.debug('dyanno_hypervisor_orch: Got hypervisor: ' ~ hypervisor) %} +{% endif %} +{% endif %} +{% endif %} +{% set status = data.get('event').title() %} {% endif %} -#} + +{% do salt.log.info('dyanno_hypervisor_orch: vm_name: ' ~ vm_name ~ ' hypervisor: ' ~ hypervisor ~ ' status: ' ~ status) %} + {# We will need to populate hypervisor:hosts in this orch and pass to state to run as runner update_hypervisor_status: @@ -94,6 +90,18 @@ update_hypervisor_status: {% endif %} #} +write_vm_status: + salt.runner: + - name: state.orchestrate + - mods: soc.dyanno.hypervisor.write_status + - pillar: + vm_name: {{ vm_name }} + hypervisor: {{ hypervisor }} + status_data: + timestamp: {{ timestamp }} + status: {{ status }} + event_tag: {{ tag }} + # Update hypervisor status update_hypervisor_annotation: salt.state: @@ -102,10 +110,8 @@ update_hypervisor_annotation: - sls: - soc.dyanno.hypervisor - concurrent: True -{#% if event_tag.startswith('soc/dyanno/hypervisor') %} - require: - salt: write_vm_status -{% endif %#} {% do salt.log.info('dyanno_hypervisor_orch: Completed') %} diff --git a/salt/reactor/vm_status.sls b/salt/reactor/vm_status.sls index 5e32ac18f..75b4596cb 100644 --- a/salt/reactor/vm_status.sls +++ b/salt/reactor/vm_status.sls @@ -4,119 +4,33 @@ # Elastic License 2.0. {% do salt.log.debug('vm_status_reactor: Running') %} -{% do salt.log.debug('vm_status_reactor: tag: ' ~ tag | string) %} +{% do salt.log.debug('vm_status_reactor: tag: ' ~ tag) %} {# Remove all the nasty characters that exist in this data #} {% if tag.startswith('salt/cloud/') and tag.endswith('/deploying') %} -{% set data = { + +{% set event_data = { "_stamp": data._stamp, "event": data.event, "kwargs": { "cloud_grains": data.kwargs.cloud_grains } } %} + +{% else %} + +{% set event_data = data %} + {% endif %} -{% do salt.log.debug('vm_status_reactor: Received data: ' ~ data|json|string) %} - -{# -update_hypervisor: - runner.state.orchestrate: - - args: - - mods: orch.dyanno_hypervisor - - pillar: - event_tag: {{ tag }} - event_data: {{ data }} -#} - -{# Our custom tag #} -{% if tag.startswith('soc/dyanno/hypervisor') %} -{% set status_data = data.get('data')%} -{% do salt.log.debug('vm_status_reactor: Received data: ' ~ status_data|json|string) %} -{% do salt.log.debug('vm_status_reactor: Setting vm_name, hypervisor and status') %} -{% set vm_name = status_data.get('vm_name') %} -{% set hypervisor = status_data.get('hypervisor') %} -{% set status = status_data.get('status') %} -{% set details = status_data.get('details', '') %} -{% endif %} - -{# setup/so-minion tag #} -{% if tag == ('setup/so-minion') %} -{% set status_data = data.get('data')%} -{% do salt.log.debug('vm_status_reactor: Received data: ' ~ status_data|json|string) %} -{% do salt.log.debug('vm_status_reactor: Setting vm_name, hypervisor and status') %} -{% set vm_name = data.get('id') %} - -{% set grains = salt.saltutil.runner('cache.grains', tgt=vm_name).get(vm_name) %} -{% if grains %} -{% do salt.log.debug('vm_status_reactor: Got cache.grains ' ~ grains|string) %} -{% if grains.get('salt-cloud').get('profile') %} -{% do salt.log.debug('vm_status_reactor: Found salt-cloud:profile grain: ' ~ grains.get('salt-cloud').get('profile')|string) %} -{% set hypervisor = grains.get('salt-cloud').get('profile').split('-')[1] %} -{% do salt.log.debug('vm_status_reactor: Got hypervisor: ' ~ hypervisor) %} -{% endif %} -{% else %} -{% do salt.log.debug('vm_status_reactor: Did not get cache.grains.') %} -{% endif %} - -{% set hypervisor = hypervisor %} -{% set status = 'Initialize Minion Pillars' %} -{% set details = status_data.get('details', '') %} -{% endif %} - -{# salt-cloud tag #} -{% if tag.startswith('salt/cloud/') and (tag.endswith('/creating') or tag.endswith('/deploying') or tag.endswith('/created') or tag.endswith('/destroyed')) %} -{% do salt.log.debug('vm_status_reactor: Received data: ' ~ data|json|string) %} -{% do salt.log.debug('vm_status_reactor: Setting vm_name, hypervisor and status') %} -{% set vm_name = tag.split('/')[2] %} -{% do salt.log.debug('vm_status_reactor: Got vm_name from tag: ' ~ vm_name) %} - -{% if tag.endswith('/deploying') %} -{% set hypervisor = data.get('kwargs').get('cloud_grains').get('profile').split('-')[1] %} -{% endif %} - -{% if data.get('profile', False) %} -{% do salt.log.debug('vm_status_reactor: Did not get cache.grains.') %} -{% set hypervisor = data.profile.split('-')[1] %} -{% do salt.log.debug('vm_status_reactor: Got hypervisor from data: ' ~ hypervisor) %} -{% else %} -{% set grains = salt.saltutil.runner('cache.grains', tgt=vm_name).get(vm_name) %} -{% if grains %} -{% do salt.log.debug('vm_status_reactor: Got cache.grains: ' ~ grains|string) %} -{% if grains.get('salt-cloud').get('profile') %} -{% do salt.log.debug('vm_status_reactor: Found salt-cloud:profile grain: ' ~ grains.get('salt-cloud').get('profile')|string) %} -{% set hypervisor = grains.get('salt-cloud').get('profile').split('-')[1] %} -{% do salt.log.debug('vm_status_reactor: Got hypervisor: ' ~ hypervisor) %} -{% endif %} -{% endif %} -{% endif %} - -{% set status = data.get('event').title() %} -{% set details = data.get('details', '') %} -{% endif %} - -{% do salt.log.info('vm_status_reactor: vm_name: ' ~ vm_name ~ ' hypervisor: ' ~ hypervisor ~ ' status: ' ~ status) %} - -{% set timestamp = data.get('_stamp') %} -write_vm_status: - runner.state.orchestrate: - - args: - - mods: soc.dyanno.hypervisor.write_status - - pillar: - vm_name: {{ vm_name }} - hypervisor: {{ hypervisor }} - status_data: - timestamp: {{ timestamp }} - status: {{ status }} - details: {{ details }} - event_tag: {{ tag }} +{% do salt.log.debug('vm_status_reactor: Received data: ' ~ event_data|json|string) %} update_hypervisor: runner.state.orchestrate: - args: - mods: orch.dyanno_hypervisor - pillar: - event_tag: {{ tag }} - event_data: {{ data }} + tag: {{ tag }} + data: {{ event_data }} {% do salt.log.debug('vm_status_reactor: Completed') %} From 6ac14f832e194faf32d2f3a72ee94a14f0b6d691 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Mon, 24 Feb 2025 12:22:52 -0500 Subject: [PATCH 137/315] only allow first process step to overwrite last --- salt/soc/dyanno/hypervisor/write_status.sls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/soc/dyanno/hypervisor/write_status.sls b/salt/soc/dyanno/hypervisor/write_status.sls index 4babf7687..7859069a1 100644 --- a/salt/soc/dyanno/hypervisor/write_status.sls +++ b/salt/soc/dyanno/hypervisor/write_status.sls @@ -64,7 +64,7 @@ ensure_status_dir: {# Some of the status updates trigger within a second of each other can can cause, for example, IP Configuration orchestration to process before the Processing #} {# This check has been put in place to ensure a status sooner in the process can't overwrite this file if a status later in the process wrote to it first. #} {# The final step is Destroyed, so we allow Processing to overwrite that incase someone creates a new VM with same name that was previously destroyed. #} -{% if new_index > current_index or current_index == process_steps | length - 1 %} +{% if new_index > current_index or (current_index == process_steps | length - 1 and new_index == 0) %} write_status_file: file.serialize: - name: {{ status_file }} From 0006948c293b0cb82c00e7577d86b9866d433d2b Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Mon, 24 Feb 2025 12:26:28 -0500 Subject: [PATCH 138/315] get hypervisor from dir name --- salt/orch/dyanno_hypervisor.sls | 44 ++++++++++++++------------------- 1 file changed, 19 insertions(+), 25 deletions(-) diff --git a/salt/orch/dyanno_hypervisor.sls b/salt/orch/dyanno_hypervisor.sls index 959a4a9c4..b580339ad 100644 --- a/salt/orch/dyanno_hypervisor.sls +++ b/salt/orch/dyanno_hypervisor.sls @@ -12,6 +12,7 @@ {% if 'hvn' in salt['pillar.get']('features', []) %} {% do salt.log.info('dyanno_hypervisor_orch: Running') %} + {% set data = pillar.get('data', {}) %} {% set tag = pillar.get('tag', '') %} {% set timestamp = data.get('_stamp') %} @@ -58,19 +59,23 @@ {% if tag.endswith('/deploying') %} {% set hypervisor = data.get('kwargs').get('cloud_grains').get('profile').split('-')[1] %} {% endif %} +{# Set the hypervisor #} +{# First try to get it from the event #} {% if data.get('profile', False) %} {% do salt.log.debug('dyanno_hypervisor_orch: Did not get cache.grains.') %} {% set hypervisor = data.profile.split('-')[1] %} {% do salt.log.debug('dyanno_hypervisor_orch: Got hypervisor from data: ' ~ hypervisor) %} {% else %} -{% set grains = salt.saltutil.runner('cache.grains', tgt=vm_name).get(vm_name) %} -{% if grains %} -{% do salt.log.debug('dyanno_hypervisor_orch: Got cache.grains: ' ~ grains|string) %} -{% if grains.get('salt-cloud').get('profile') %} -{% do salt.log.debug('dyanno_hypervisor_orch: Found salt-cloud:profile grain: ' ~ grains.get('salt-cloud').get('profile')|string) %} -{% set hypervisor = grains.get('salt-cloud').get('profile').split('-')[1] %} -{% do salt.log.debug('dyanno_hypervisor_orch: Got hypervisor: ' ~ hypervisor) %} -{% endif %} +{# If not in the event, find it by the .status file location #} +{% set path = salt['file.find']('/opt/so/saltstack/local/salt/hypervisor/hosts/',type='f', name=vm_name ~ '.status') %} +{% if path | length == 1 %} +{% set parts = path[0].split('/') %} +{% set hypervisor = parts[-2] %} +{% do salt.log.debug('dyanno_hypervisor_orch: Found hypervisor from file.find: ' ~ hypervisor) %} +{% elif path | length == 0 %} +{% do salt.log.error('dyanno_hypervisor_orch: ' ~ vm_name ~ ' not found in any hypervisor directories') %} +{% else %} +{% do salt.log.error('dyanno_hypervisor_orch: Found ' ~ vm_name ~ ' in multiple hypervisor directories: ' ~ path | string) %} {% endif %} {% endif %} {% set status = data.get('event').title() %} @@ -78,22 +83,13 @@ {% do salt.log.info('dyanno_hypervisor_orch: vm_name: ' ~ vm_name ~ ' hypervisor: ' ~ hypervisor ~ ' status: ' ~ status) %} - -{# We will need to populate hypervisor:hosts in this orch and pass to state to run as runner -update_hypervisor_status: - salt.runner: - - name: state.orchestrate - - mods: soc.dyanno.hypervisor -{% if event_tag.startswith('soc/dyanno/hypervisor') %} - - require: - - salt: write_vm_status -{% endif %} -#} - write_vm_status: - salt.runner: - - name: state.orchestrate - - mods: soc.dyanno.hypervisor.write_status + salt.state: + - tgt: 'G@role:so-manager or G@role:so-managersearch or G@role:so-standalone or G@role:so-eval' + - tgt_type: compound + - sls: + - soc.dyanno.hypervisor.write_status + - concurrent: True - pillar: vm_name: {{ vm_name }} hypervisor: {{ hypervisor }} @@ -110,8 +106,6 @@ update_hypervisor_annotation: - sls: - soc.dyanno.hypervisor - concurrent: True - - require: - - salt: write_vm_status {% do salt.log.info('dyanno_hypervisor_orch: Completed') %} From c8967854806ce10f4dd38c63f6102490485c0cdc Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Mon, 24 Feb 2025 14:20:09 -0500 Subject: [PATCH 139/315] fix vm deletion --- salt/orch/dyanno_hypervisor.sls | 43 +++++++++---------- .../engines/master/virtual_node_manager.py | 10 +++-- salt/soc/dyanno/hypervisor/write_status.sls | 12 +++++- 3 files changed, 38 insertions(+), 27 deletions(-) diff --git a/salt/orch/dyanno_hypervisor.sls b/salt/orch/dyanno_hypervisor.sls index b580339ad..c298a6101 100644 --- a/salt/orch/dyanno_hypervisor.sls +++ b/salt/orch/dyanno_hypervisor.sls @@ -11,6 +11,23 @@ {% if 'hvn' in salt['pillar.get']('features', []) %} +{# Macro to find hypervisor name from VM status file #} +{% macro find_hypervisor_from_status(vm_name) -%} + {%- set path = salt['file.find']('/opt/so/saltstack/local/salt/hypervisor/hosts/',type='f', name=vm_name ~ '.status') -%} + {%- if path | length == 1 -%} + {%- set parts = path[0].split('/') -%} + {%- set hypervisor = parts[-2] -%} + {%- do salt.log.debug('dyanno_hypervisor_orch: Found hypervisor from file.find: ' ~ hypervisor) -%} + {{- hypervisor -}} + {%- elif path | length == 0 -%} + {%- do salt.log.error('dyanno_hypervisor_orch: ' ~ vm_name ~ ' not found in any hypervisor directories') -%} + {{- '' -}} + {%- else -%} + {%- do salt.log.error('dyanno_hypervisor_orch: Found ' ~ vm_name ~ ' in multiple hypervisor directories: ' ~ path | string) -%} + {{- '' -}} + {%- endif -%} +{%- endmacro %} + {% do salt.log.info('dyanno_hypervisor_orch: Running') %} {% set data = pillar.get('data', {}) %} @@ -35,21 +52,11 @@ {% do salt.log.debug('dyanno_hypervisor_orch: Received data: ' ~ status_data|json|string) %} {% do salt.log.debug('dyanno_hypervisor_orch: Setting vm_name, hypervisor and status') %} {% set vm_name = data.get('id') %} -{% set grains = salt.saltutil.runner('cache.grains', tgt=vm_name).get(vm_name) %} -{% if grains %} -{% do salt.log.debug('dyanno_hypervisor_orch: Got cache.grains ' ~ grains|string) %} -{% if grains.get('salt-cloud').get('profile') %} -{% do salt.log.debug('dyanno_hypervisor_orch: Found salt-cloud:profile grain: ' ~ grains.get('salt-cloud').get('profile')|string) %} -{% set hypervisor = grains.get('salt-cloud').get('profile').split('-')[1] %} -{% do salt.log.debug('dyanno_hypervisor_orch: Got hypervisor: ' ~ hypervisor) %} -{% endif %} -{% else %} -{% do salt.log.debug('dyanno_hypervisor_orch: Did not get cache.grains.') %} -{% endif %} -{% set hypervisor = hypervisor %} +{% set hypervisor = find_hypervisor_from_status(vm_name) %} {% set status = 'Initialize Minion Pillars' %} {% endif %} + {# salt-cloud tag #} {% if tag.startswith('salt/cloud/') and (tag.endswith('/creating') or tag.endswith('/deploying') or tag.endswith('/created') or tag.endswith('/destroyed')) %} {% do salt.log.debug('dyanno_hypervisor_orch: Received data: ' ~ data|json|string) %} @@ -66,17 +73,7 @@ {% set hypervisor = data.profile.split('-')[1] %} {% do salt.log.debug('dyanno_hypervisor_orch: Got hypervisor from data: ' ~ hypervisor) %} {% else %} -{# If not in the event, find it by the .status file location #} -{% set path = salt['file.find']('/opt/so/saltstack/local/salt/hypervisor/hosts/',type='f', name=vm_name ~ '.status') %} -{% if path | length == 1 %} -{% set parts = path[0].split('/') %} -{% set hypervisor = parts[-2] %} -{% do salt.log.debug('dyanno_hypervisor_orch: Found hypervisor from file.find: ' ~ hypervisor) %} -{% elif path | length == 0 %} -{% do salt.log.error('dyanno_hypervisor_orch: ' ~ vm_name ~ ' not found in any hypervisor directories') %} -{% else %} -{% do salt.log.error('dyanno_hypervisor_orch: Found ' ~ vm_name ~ ' in multiple hypervisor directories: ' ~ path | string) %} -{% endif %} +{% set hypervisor = find_hypervisor_from_status(vm_name) %} {% endif %} {% set status = data.get('event').title() %} {% endif %} diff --git a/salt/salt/engines/master/virtual_node_manager.py b/salt/salt/engines/master/virtual_node_manager.py index 98a4eb572..6425a0063 100644 --- a/salt/salt/engines/master/virtual_node_manager.py +++ b/salt/salt/engines/master/virtual_node_manager.py @@ -736,9 +736,8 @@ def process_hypervisor(hypervisor_path: str) -> None: nodes_config = read_json_file(vms_file) if not nodes_config: log.debug("Empty VMs configuration in %s", vms_file) - return - # Get existing VMs - no lock needed + # Get existing VMs existing_vms = set() for file_path in glob.glob(os.path.join(hypervisor_path, '*_*')): basename = os.path.basename(file_path) @@ -761,7 +760,12 @@ def process_hypervisor(hypervisor_path: str) -> None: process_vm_creation(hypervisor_path, vm_config) # Process VM deletions - for vm_name in existing_vms - configured_vms: + vms_to_delete = existing_vms - configured_vms + log.debug(f"Existing VMs: {existing_vms}") + log.debug(f"Configured VMs: {configured_vms}") + log.debug(f"VMs to delete: {vms_to_delete}") + for vm_name in vms_to_delete: + log.info(f"Initiating deletion process for VM: {vm_name}") process_vm_deletion(hypervisor_path, vm_name) except Exception as e: diff --git a/salt/soc/dyanno/hypervisor/write_status.sls b/salt/soc/dyanno/hypervisor/write_status.sls index 7859069a1..be03b26b7 100644 --- a/salt/soc/dyanno/hypervisor/write_status.sls +++ b/salt/soc/dyanno/hypervisor/write_status.sls @@ -22,7 +22,17 @@ {% set status_file = status_dir ~ '/' ~ vm_name ~ '.status' %} # Define the list of process steps in order (case-sensitive) -{% set process_steps = ['Processing', 'IP Configuration', 'Starting Create', 'Executing Deploy Script', 'Initialize Minion Pillars', 'Created Instance', 'Hardware Configuration', 'Highstate Triggered', 'Destroyed Instance'] %} +{% set process_steps = [ + 'Processing', + 'IP Configuration', + 'Starting Create', + 'Executing Deploy Script', + 'Initialize Minion Pillars', + 'Created Instance', + 'Hardware Configuration', + 'Highstate Triggered', + 'Destroyed Instance' +] %} {% set new_index = process_steps.index(status_data.get('status')) %} {% do salt.log.debug('soc/dyanno/hypervisor/write_status: new_index: ' ~ new_index|string) %} From b5276a6a1d4ce57b652c8b45e4a4655b684a5f90 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Tue, 25 Feb 2025 04:41:59 -0500 Subject: [PATCH 140/315] add hypervisor to firewall annotation --- salt/firewall/soc_firewall.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/salt/firewall/soc_firewall.yaml b/salt/firewall/soc_firewall.yaml index 222bcc8a2..879b42f21 100644 --- a/salt/firewall/soc_firewall.yaml +++ b/salt/firewall/soc_firewall.yaml @@ -35,6 +35,7 @@ firewall: external_suricata: *hostgroupsettings fleet: *hostgroupsettings heavynode: *hostgroupsettings + hypervisor: *hostgroupsettings idh: *hostgroupsettings import: *hostgroupsettings localhost: *ROhostgroupsettingsadv From e0a3b51ca27643e83794eec16ce6907573bc8e21 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Tue, 25 Feb 2025 08:54:04 -0500 Subject: [PATCH 141/315] md in description --- salt/hypervisor/hosts/README | 1 + .../hypervisor/soc_hypervisor.yaml.jinja | 37 +++++++++++-------- 2 files changed, 23 insertions(+), 15 deletions(-) create mode 100644 salt/hypervisor/hosts/README diff --git a/salt/hypervisor/hosts/README b/salt/hypervisor/hosts/README new file mode 100644 index 000000000..406fd0bec --- /dev/null +++ b/salt/hypervisor/hosts/README @@ -0,0 +1 @@ +This directory will contain hypervisor hosts. We need this README in place to ensure /opt/so/saltstack/local/salt/hypervisor/hosts directory gets created during setup. diff --git a/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja b/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja index 453aa436c..cb8be8b18 100644 --- a/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja +++ b/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja @@ -16,25 +16,27 @@ {%- set TEMPLATE = ANNOTATION.hypervisor.hosts.pop('defaultHost') -%} -{%- macro update_description(description, cpu_free, mem_free, disk_free, copper_free, sfp_free, vm_list) -%} -{{- description }} +{%- macro update_description(description, cpu_free, mem_free, disk_free, copper_free, sfp_free, vm_list, cpu_total, mem_total, disk_total, copper_total, sfp_total) -%} +# Hypervisor Configuration: {{ description }} -Resource Summary: -- CPU: {{ cpu_free }} cores available -- Memory: {{ mem_free }}GB available -- Disk Slots: {{ disk_free if disk_free else 'None' }} available -- Copper Ports: {{ copper_free if copper_free else 'None' }} available -- SFP Ports: {{ sfp_free if sfp_free else 'None' }} available +## Resource Summary +| Resource | Available | Total | +|-------------|-----------|-----------| +| CPU Cores | {{ cpu_free }} | {{ cpu_total }} | +| Memory (GB) | {{ mem_free }} | {{ mem_total }} | +| Disk | {{ disk_free if disk_free else 'None' }} | {{ disk_total }} | +| Copper | {{ copper_free if copper_free else 'None' }} | {{ copper_total }} | +| SFP | {{ sfp_free if sfp_free else 'None' }} | {{ sfp_total }} | {%- if vm_list %} -Virtual Machines: +## Virtual Machines +| Name | Status | CPU | RAM(GB)| Disk | Copper | SFP | Last Updated | +|--------------------|--------------------|-----|--------|------|--------|------|---------------------| {%- for hostname, vm_data in vm_list.items() %} -- {{ hostname }}: - Status: {{ vm_data.get('status', {}).get('status', 'Unknown') }} - Details: {{ vm_data.get('status', {}).get('details', 'No details available') }} - Last Updated: {{ vm_data.get('status', {}).get('timestamp', 'Never') }} +| {{ hostname }}_{{ vm_data.get('config', {}).get('role', 'unknown') }} | {{ vm_data.get('status', {}).get('status', 'Unknown') }} | {{ vm_data.get('config', {}).get('cpu', 'N/A') }} | {{ vm_data.get('config', {}).get('memory', 'N/A') }} | {{ vm_data.get('config', {}).get('disk', '-') if vm_data.get('config', {}).get('disk') else '-' }} | {{ vm_data.get('config', {}).get('copper', '-') if vm_data.get('config', {}).get('copper') else '-' }} | {{ vm_data.get('config', {}).get('sfp', '-') if vm_data.get('config', {}).get('sfp') else '-' }} | {{ vm_data.get('status', {}).get('timestamp', 'Never') | replace('T', ' ') | regex_replace('\\.[0-9]+', '') }} | {%- endfor %} {%- else %} +## Virtual Machines No Virtual Machines Found {%- endif %} {%- endmacro -%} @@ -118,13 +120,18 @@ No Virtual Machines Found {%- do updated_template.update({ 'title': hypervisor, 'description': update_description( - TEMPLATE.description, + hypervisor, cpu_free, mem_free, disk_free, copper_free, sfp_free, - vms + vms, + cpu_total, + mem_total, + disk_total, + copper_total, + sfp_total ) }) -%} {%- do ANNOTATION.hypervisor.hosts.update({hypervisor ~ 'VMs': updated_template}) -%} From 5811b184be051fe706195514ed5f145baaa9dc5e Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Tue, 25 Feb 2025 11:13:35 -0500 Subject: [PATCH 142/315] enhance annotations. account for line separation instead of comma for hardware --- .../engines/master/virtual_node_manager.py | 8 +-- salt/soc/dyanno/hypervisor/hypervisor.yaml | 59 +++++++++++++++++-- .../hypervisor/soc_hypervisor.yaml.jinja | 30 +++++----- 3 files changed, 73 insertions(+), 24 deletions(-) diff --git a/salt/salt/engines/master/virtual_node_manager.py b/salt/salt/engines/master/virtual_node_manager.py index 6425a0063..bc203fb59 100644 --- a/salt/salt/engines/master/virtual_node_manager.py +++ b/salt/salt/engines/master/virtual_node_manager.py @@ -316,7 +316,7 @@ def validate_hardware_request(model_config: dict, requested_hw: dict) -> Tuple[b for hw_type in ['disk', 'copper', 'sfp']: if hw_type in requested_hw and requested_hw[hw_type]: try: - indices = [int(x) for x in str(requested_hw[hw_type]).split(',')] + indices = [int(x) for x in str(requested_hw[hw_type]).split('\n')] log.debug("Checking if %s indices %s exist in model", hw_type, indices) if hw_type not in model_config['hardware']: @@ -405,7 +405,7 @@ def check_hardware_availability(hypervisor_path: str, vm_name: str, requested_hw # Track unique resources for hw_type in ['disk', 'copper', 'sfp']: if hw_type in config and config[hw_type]: - indices = [int(x) for x in str(config[hw_type]).split(',')] + indices = [int(x) for x in str(config[hw_type]).split('\n')] for idx in indices: used_resources[hw_type][idx] = basename.replace('_sensor', '') # Store VM name without role log.debug("VM %s is using %s indices: %s", basename, hw_type, indices) @@ -432,7 +432,7 @@ def check_hardware_availability(hypervisor_path: str, vm_name: str, requested_hw # Check for hardware conflicts for hw_type in ['disk', 'copper', 'sfp']: if hw_type in requested_hw and requested_hw[hw_type]: - requested_indices = [int(x) for x in str(requested_hw[hw_type]).split(',')] + requested_indices = [int(x) for x in str(requested_hw[hw_type]).split('\n')] log.debug("Checking for %s conflicts - Requesting indices: %s, Currently in use: %s", hw_type, requested_indices, used_resources[hw_type]) conflicts = {} # {index: vm_name} @@ -636,7 +636,7 @@ def process_vm_creation(hypervisor_path: str, vm_config: dict) -> None: # Add PCI devices for hw_type in ['disk', 'copper', 'sfp']: if hw_type in vm_config and vm_config[hw_type]: - indices = [int(x) for x in str(vm_config[hw_type]).split(',')] + indices = [int(x) for x in str(vm_config[hw_type]).split('\n')] for idx in indices: hw_config = {int(k): v for k, v in model_config['hardware'][hw_type].items()} pci_id = hw_config[idx] diff --git a/salt/soc/dyanno/hypervisor/hypervisor.yaml b/salt/soc/dyanno/hypervisor/hypervisor.yaml index e2a0028a8..c282d4e7b 100644 --- a/salt/soc/dyanno/hypervisor/hypervisor.yaml +++ b/salt/soc/dyanno/hypervisor/hypervisor.yaml @@ -6,28 +6,77 @@ hypervisor: syntax: json uiElements: - field: hostname - label: "Enter the hostname" + label: "Hostname" + forcedType: string + required: true + readonly: true - field: role - label: "sensor or searchnode" + label: "Role" + required: true + readonly: true + options: + - searchnode + - sensor + - receiver + - idh + - heavynode + - fleet - field: network_mode label: "Choose static4 or dhcp4. If static4, populate IP details below." + required: true + readonly: true + options: + - static4 + - dhcp4 - field: ip4 label: "IP Address with netmask. ex. 192.168.1.10/24" + forcedType: string + regex: '^(\d{1,3}\.){3}\d{1,3}/\d{1,2}$' + regexFailureMessage: "Enter a properly formatted CIDR address" + readonly: true - field: gw4 label: "Gateway" + forcedType: string + regex: '^(\d{1,3}\.){3}\d{1,3}$' + regexFailureMessage: "Enter a properly formatted IP address" + readonly: true - field: dns4 label: "DNS. Comma separated list. ex. 192.168.1.1,8.8.8.8" + forcedType: string + regex: '^(\d{1,3}\.){3}\d{1,3}$' + regexFailureMessage: "Enter a properly formatted IP address" + readonly: true - field: search4 label: "Search domain" + forcedType: string + readonly: true - field: cpu label: "CPU cores to assign. Free: FREE | Total: TOTAL" + forcedType: int + required: true + readonly: true - field: memory label: "Memory to assign, in GB. Free: FREE | Total: TOTAL" + required: true + readonly: true + forcedType: int - field: disk - label: "Disk(s) for passthrough. Comma separated list. Free: FREE | Total: TOTAL" + label: "Disk(s) for passthrough. Line-delimited list. Free: FREE | Total: TOTAL" + required: true + readonly: true + forcedType: '[]int' + multiline: true - field: copper - label: "Copper port(s) for passthrough. Comma separated list. Free: FREE | Total: TOTAL" + label: "Copper port(s) for passthrough. Line-delimited list. Free: FREE | Total: TOTAL" + required: true + readonly: true + forcedType: '[]int' + multiline: true - field: sfp - label: "SFP port(s) for passthrough. Comma separated list. Free: FREE | Total: TOTAL" + label: "SFP port(s) for passthrough. Line-delimited list. Free: FREE | Total: TOTAL" + required: true + readonly: true + forcedType: '[]int' + multiline: true file: true global: true diff --git a/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja b/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja index cb8be8b18..0f409eada 100644 --- a/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja +++ b/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja @@ -24,16 +24,16 @@ |-------------|-----------|-----------| | CPU Cores | {{ cpu_free }} | {{ cpu_total }} | | Memory (GB) | {{ mem_free }} | {{ mem_total }} | -| Disk | {{ disk_free if disk_free else 'None' }} | {{ disk_total }} | -| Copper | {{ copper_free if copper_free else 'None' }} | {{ copper_total }} | -| SFP | {{ sfp_free if sfp_free else 'None' }} | {{ sfp_total }} | +| Disk | {{ disk_free | replace('\n', ',') if disk_free else 'None' }} | {{ disk_total | replace('\n', ',') }} | +| Copper | {{ copper_free | replace('\n', ',') if copper_free else 'None' }} | {{ copper_total | replace('\n', ',') }} | +| SFP | {{ sfp_free | replace('\n', ',') if sfp_free else 'None' }} | {{ sfp_total | replace('\n', ',') }} | {%- if vm_list %} ## Virtual Machines -| Name | Status | CPU | RAM(GB)| Disk | Copper | SFP | Last Updated | -|--------------------|--------------------|-----|--------|------|--------|------|---------------------| +| Name | Status | CPU Cores | Memory (GB)| Disk | Copper | SFP | Last Updated | +|--------------------|--------------------|-----------|------------|------|--------|------|---------------------| {%- for hostname, vm_data in vm_list.items() %} -| {{ hostname }}_{{ vm_data.get('config', {}).get('role', 'unknown') }} | {{ vm_data.get('status', {}).get('status', 'Unknown') }} | {{ vm_data.get('config', {}).get('cpu', 'N/A') }} | {{ vm_data.get('config', {}).get('memory', 'N/A') }} | {{ vm_data.get('config', {}).get('disk', '-') if vm_data.get('config', {}).get('disk') else '-' }} | {{ vm_data.get('config', {}).get('copper', '-') if vm_data.get('config', {}).get('copper') else '-' }} | {{ vm_data.get('config', {}).get('sfp', '-') if vm_data.get('config', {}).get('sfp') else '-' }} | {{ vm_data.get('status', {}).get('timestamp', 'Never') | replace('T', ' ') | regex_replace('\\.[0-9]+', '') }} | +| {{ hostname }}_{{ vm_data.get('config', {}).get('role', 'unknown') }} | {{ vm_data.get('status', {}).get('status', 'Unknown') }} | {{ vm_data.get('config', {}).get('cpu', 'N/A') }} | {{ vm_data.get('config', {}).get('memory', 'N/A') }} | {{ vm_data.get('config', {}).get('disk', '-') | replace('\n', ',') if vm_data.get('config', {}).get('disk') else '-' }} | {{ vm_data.get('config', {}).get('copper', '-') | replace('\n', ',') if vm_data.get('config', {}).get('copper') else '-' }} | {{ vm_data.get('config', {}).get('sfp', '-') | replace('\n', ',') if vm_data.get('config', {}).get('sfp') else '-' }} | {{ vm_data.get('status', {}).get('timestamp', 'Never') | replace('T', ' ') | regex_replace('\\.[0-9]+', '') }} | {%- endfor %} {%- else %} ## Virtual Machines @@ -81,9 +81,9 @@ No Virtual Machines Found {%- set used_sfp = [] -%} {%- for hostname, vm in vms.items() -%} {%- set config = vm.get('config', {}) -%} -{%- do used_disk.extend((config.get('disk', '') | string).split(',') | map('trim') | list) -%} -{%- do used_copper.extend((config.get('copper', '') | string).split(',') | map('trim') | list) -%} -{%- do used_sfp.extend((config.get('sfp', '') | string).split(',') | map('trim') | list) -%} +{%- do used_disk.extend((config.get('disk', '') | string).split('\n') | map('trim') | list) -%} +{%- do used_copper.extend((config.get('copper', '') | string).split('\n') | map('trim') | list) -%} +{%- do used_sfp.extend((config.get('sfp', '') | string).split('\n') | map('trim') | list) -%} {%- endfor -%} {# Get available PCI indices #} @@ -94,9 +94,9 @@ No Virtual Machines Found {# Get total resources #} {%- set cpu_total = hw_config.cpu -%} {%- set mem_total = hw_config.memory -%} -{%- set disk_total = hw_config.disk.keys() | join(',') -%} -{%- set copper_total = hw_config.copper.keys() | join(',') -%} -{%- set sfp_total = hw_config.sfp.keys() | join(',') -%} +{%- set disk_total = hw_config.disk.keys() | join('\n') -%} +{%- set copper_total = hw_config.copper.keys() | join('\n') -%} +{%- set sfp_total = hw_config.sfp.keys() | join('\n') -%} {# Update field labels with total and free values #} {%- set updated_template = TEMPLATE.copy() -%} @@ -108,11 +108,11 @@ No Virtual Machines Found {%- elif field.field == 'memory' -%} {%- do updated_field.update({'label': field.label | replace('FREE', mem_free | string) | replace('TOTAL', mem_total | string)}) -%} {%- elif field.field == 'disk' -%} -{%- do updated_field.update({'label': field.label | replace('FREE', disk_free) | replace('TOTAL', disk_total)}) -%} +{%- do updated_field.update({'label': field.label | replace('FREE', disk_free) | replace('TOTAL', disk_total | replace('\n', ','))}) -%} {%- elif field.field == 'copper' -%} -{%- do updated_field.update({'label': field.label | replace('FREE', copper_free) | replace('TOTAL', copper_total)}) -%} +{%- do updated_field.update({'label': field.label | replace('FREE', copper_free) | replace('TOTAL', copper_total | replace('\n', ','))}) -%} {%- elif field.field == 'sfp' -%} -{%- do updated_field.update({'label': field.label | replace('FREE', sfp_free) | replace('TOTAL', sfp_total)}) -%} +{%- do updated_field.update({'label': field.label | replace('FREE', sfp_free) | replace('TOTAL', sfp_total | replace('\n', ','))}) -%} {%- endif -%} {%- do updated_elements.append(updated_field) -%} {%- endfor -%} From d6f527881a59832cc1ce151e31da721938fddc0f Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Wed, 26 Feb 2025 09:06:45 -0500 Subject: [PATCH 143/315] allow for destroyed vms to be displayed in ui. VNM cleanup destroyed status files after 48h --- salt/hypervisor/map.jinja | 54 +++++++++++++++ .../engines/master/virtual_node_manager.py | 62 +++++++++++++++-- salt/soc/dyanno/hypervisor/hypervisor.yaml | 7 +- salt/soc/dyanno/hypervisor/map.jinja | 13 ++++ .../hypervisor/soc_hypervisor.yaml.jinja | 67 ++++++++++++++----- salt/soc/dyanno/hypervisor/write_status.sls | 25 +++---- 6 files changed, 186 insertions(+), 42 deletions(-) diff --git a/salt/hypervisor/map.jinja b/salt/hypervisor/map.jinja index a9a76e557..e52d7ae1a 100644 --- a/salt/hypervisor/map.jinja +++ b/salt/hypervisor/map.jinja @@ -85,6 +85,60 @@ {% endif %} {% endfor %} + {# Find and add destroyed VMs from status files #} + {% set processed_vms = [] %} + {% for vm_name, vm_data in vms.items() %} + {% do processed_vms.append(vm_name) %} + {% endfor %} + + {# Find all status files for this hypervisor #} + {% set relative_path = 'hypervisor/hosts/' ~ hypervisor %} + {% set absolute_path = '/opt/so/saltstack/local/salt/' ~ relative_path %} + {% do salt.log.info('salt/hypervisor/map.jinja: Scanning for status files in: ' ~ absolute_path) %} + + {# Try to find status files using file.find with absolute path #} + {% set status_files = salt['file.find'](absolute_path, name='*_*.status', type='f') %} + {% do salt.log.info('salt/hypervisor/map.jinja: Found status files: ' ~ status_files | tojson) %} + + {# Convert absolute paths back to relative paths for processing #} + {% set relative_status_files = [] %} + {% for status_file in status_files %} + {% set relative_file = status_file | replace('/opt/so/saltstack/local/salt/', '') %} + {% do relative_status_files.append(relative_file) %} + {% endfor %} + {% set status_files = relative_status_files %} + + {% do salt.log.info('salt/hypervisor/map.jinja: Converted to relative paths: ' ~ status_files | tojson) %} + + {% for status_file in status_files %} + {# Extract the VM name from the filename #} + {% set basename = status_file.split('/')[-1] %} + {% set vm_name = basename.replace('.status', '') %} + {% set hostname = vm_name.split('_')[0] %} + + {# Skip already processed VMs #} + {% if hostname in processed_vms %} + {% continue %} + {% endif %} + + {# Read the status file #} + {% do salt.log.info('salt/hypervisor/map.jinja: Processing potential destroyed VM status file: ' ~ status_file) %} + {% import_json status_file as status_data %} + + {# Only process files with "Destroyed Instance" status #} + {% if status_data and status_data.status == 'Destroyed Instance' %} + {% do salt.log.info('salt/hypervisor/map.jinja: Found VM with Destroyed Instance status: ' ~ hostname) %} + + {# Add to vms with minimal config #} + {% do vms.update({ + hostname: { + 'status': status_data, + 'config': {} + } + }) %} + {% endif %} + {% endfor %} + {# Merge node config with model capabilities and VM states #} {% do HYPERVISORS[role].update({ hypervisor: { diff --git a/salt/salt/engines/master/virtual_node_manager.py b/salt/salt/engines/master/virtual_node_manager.py index bc203fb59..c64cd7276 100644 --- a/salt/salt/engines/master/virtual_node_manager.py +++ b/salt/salt/engines/master/virtual_node_manager.py @@ -73,7 +73,7 @@ Notes: Description: The engine operates in the following phases: - 1. Engine Lock Acquisition + 1. Lock Acquisition - Acquires single engine-wide lock - Prevents multiple instances from running - Lock remains until clean shutdown or error @@ -138,7 +138,7 @@ import grp import salt.config import salt.runner from typing import Dict, List, Optional, Tuple, Any -from datetime import datetime +from datetime import datetime, timedelta from threading import Lock # Get socore uid/gid @@ -160,6 +160,8 @@ DEFAULT_BASE_PATH = '/opt/so/saltstack/local/salt/hypervisor/hosts' VALID_ROLES = ['sensor', 'searchnode', 'idh', 'receiver', 'heavynode', 'fleet'] LICENSE_PATH = '/opt/so/saltstack/local/pillar/soc/license.sls' DEFAULTS_PATH = '/opt/so/saltstack/default/salt/hypervisor/defaults.yaml' +# Define the retention period for destroyed VMs (in hours) +DESTROYED_VM_RETENTION_HOURS = 48 # Single engine-wide lock for virtual node manager engine_lock = Lock() @@ -667,6 +669,50 @@ def process_vm_creation(hypervisor_path: str, vm_config: dict) -> None: mark_vm_failed(os.path.join(hypervisor_path, f"{vm_name}_failed"), 4, error_msg) raise +def cleanup_destroyed_vm_status_files(hypervisor_path: str) -> None: + """ + Clean up status files for destroyed VMs that are older than the retention period. + + Args: + hypervisor_path: Path to the hypervisor directory + """ + try: + log.debug(f"Using destroyed VM retention period of {DESTROYED_VM_RETENTION_HOURS} hours") + + # Calculate the retention cutoff time + cutoff_time = datetime.now() - timedelta(hours=DESTROYED_VM_RETENTION_HOURS) + + # Find all status files for destroyed VMs + status_files = glob.glob(os.path.join(hypervisor_path, '*_*.status')) + log.debug(f"Found {len(status_files)} status files to check for expired destroyed VMs") + + for status_file in status_files: + try: + # Read the status file + status_data = read_json_file(status_file) + + # Check if this is a destroyed VM + if status_data.get('status') == 'Destroyed Instance': + # Parse the timestamp + timestamp_str = status_data.get('timestamp', '') + if timestamp_str: + timestamp = datetime.fromisoformat(timestamp_str) + vm_name = os.path.basename(status_file).replace('.status', '') + age_hours = (datetime.now() - timestamp).total_seconds() / 3600 + + # If older than retention period, delete the file + if timestamp < cutoff_time: + log.info(f"Removing expired status file for VM {vm_name} (age: {age_hours:.1f} hours > retention: {DESTROYED_VM_RETENTION_HOURS} hours)") + os.remove(status_file) + else: + log.debug(f"Status file for VM {vm_name} (age: {age_hours:.1f} hours < retention: {DESTROYED_VM_RETENTION_HOURS} hours)") + except Exception as e: + log.error(f"Error processing status file {status_file}: {e}") + + except Exception as e: + log.error(f"Failed to clean up destroyed VM status files: {e}") + + def process_vm_deletion(hypervisor_path: str, vm_name: str) -> None: """ Process a single VM deletion request. @@ -731,6 +777,9 @@ def process_hypervisor(hypervisor_path: str) -> None: vms_file = os.path.join(os.path.dirname(hypervisor_path), f"{hypervisor}VMs") if not os.path.exists(vms_file): log.debug("No VMs file found at %s", vms_file) + + # Even if no VMs file exists, we should still clean up any expired status files + cleanup_destroyed_vm_status_files(hypervisor_path) return nodes_config = read_json_file(vms_file) @@ -768,6 +817,9 @@ def process_hypervisor(hypervisor_path: str) -> None: log.info(f"Initiating deletion process for VM: {vm_name}") process_vm_deletion(hypervisor_path, vm_name) + # Clean up expired status files for destroyed VMs + cleanup_destroyed_vm_status_files(hypervisor_path) + except Exception as e: log.error("Failed to process hypervisor %s: %s", hypervisor_path, str(e)) raise @@ -797,12 +849,12 @@ def start(interval: int = DEFAULT_INTERVAL, if not validate_hvn_license(): return - # Attempt to acquire engine lock + # Attempt to acquire lock if not engine_lock.acquire(blocking=False): log.error("Another virtual node manager is already running") return - log.debug("Virtual node manager acquired engine lock") + log.debug("Virtual node manager acquired lock") try: # Process each hypervisor directory @@ -811,7 +863,7 @@ def start(interval: int = DEFAULT_INTERVAL, process_hypervisor(hypervisor_path) # Clean shutdown - release lock - log.debug("Virtual node manager releasing engine lock") + log.debug("Virtual node manager releasing lock") engine_lock.release() log.info("Virtual node manager completed successfully") diff --git a/salt/soc/dyanno/hypervisor/hypervisor.yaml b/salt/soc/dyanno/hypervisor/hypervisor.yaml index c282d4e7b..0166dbc3c 100644 --- a/salt/soc/dyanno/hypervisor/hypervisor.yaml +++ b/salt/soc/dyanno/hypervisor/hypervisor.yaml @@ -4,6 +4,8 @@ hypervisor: title: defaultHost description: "Hypervisor Configuration" syntax: json + file: true + global: true uiElements: - field: hostname label: "Hostname" @@ -62,21 +64,16 @@ hypervisor: forcedType: int - field: disk label: "Disk(s) for passthrough. Line-delimited list. Free: FREE | Total: TOTAL" - required: true readonly: true forcedType: '[]int' multiline: true - field: copper label: "Copper port(s) for passthrough. Line-delimited list. Free: FREE | Total: TOTAL" - required: true readonly: true forcedType: '[]int' multiline: true - field: sfp label: "SFP port(s) for passthrough. Line-delimited list. Free: FREE | Total: TOTAL" - required: true readonly: true forcedType: '[]int' multiline: true - file: true - global: true diff --git a/salt/soc/dyanno/hypervisor/map.jinja b/salt/soc/dyanno/hypervisor/map.jinja index b14a437b5..88b3f4425 100644 --- a/salt/soc/dyanno/hypervisor/map.jinja +++ b/salt/soc/dyanno/hypervisor/map.jinja @@ -1 +1,14 @@ {% set HYPERVISORS = salt['pillar.get']('hypervisor:nodes', {}) %} + +{# Define the list of process steps in order (case-sensitive) #} +{% set PROCESS_STEPS = [ + 'Processing', + 'IP Configuration', + 'Starting Create', + 'Executing Deploy Script', + 'Initialize Minion Pillars', + 'Created Instance', + 'Hardware Configuration', + 'Highstate Triggered', + 'Destroyed Instance' +] %} diff --git a/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja b/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja index 0f409eada..a72717de9 100644 --- a/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja +++ b/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja @@ -13,6 +13,7 @@ {%- import_yaml 'soc/dyanno/hypervisor/hypervisor.yaml' as ANNOTATION -%} {%- from 'hypervisor/map.jinja' import HYPERVISORS -%} +{%- from 'soc/dyanno/hypervisor/map.jinja' import PROCESS_STEPS -%} {%- set TEMPLATE = ANNOTATION.hypervisor.hosts.pop('defaultHost') -%} @@ -20,23 +21,53 @@ # Hypervisor Configuration: {{ description }} ## Resource Summary -| Resource | Available | Total | -|-------------|-----------|-----------| -| CPU Cores | {{ cpu_free }} | {{ cpu_total }} | -| Memory (GB) | {{ mem_free }} | {{ mem_total }} | -| Disk | {{ disk_free | replace('\n', ',') if disk_free else 'None' }} | {{ disk_total | replace('\n', ',') }} | -| Copper | {{ copper_free | replace('\n', ',') if copper_free else 'None' }} | {{ copper_total | replace('\n', ',') }} | -| SFP | {{ sfp_free | replace('\n', ',') if sfp_free else 'None' }} | {{ sfp_total | replace('\n', ',') }} | +| | CPU Cores | Memory (GB) | Disk | Copper | SFP | +|-----------|-----------|-------------|-------------|-------------|-------------| +| Available | {{ cpu_free }} | {{ mem_free }} | {{ disk_free | replace('\n', ',') if disk_free else 'None' }} | {{ copper_free | replace('\n', ',') if copper_free else 'None' }} | {{ sfp_free | replace('\n', ',') if sfp_free else 'None' }} | +| Total | {{ cpu_total }} | {{ mem_total }} | {{ disk_total | replace('\n', ',') }} | {{ copper_total | replace('\n', ',') }} | {{ sfp_total | replace('\n', ',') }} | {%- if vm_list %} ## Virtual Machines +VMs can have the following status values: {% for step in PROCESS_STEPS %}{{ step }}{% if not loop.last %}, {% endif %}{% endfor %}. The "Last Updated" timestamp shows when the VM status was last changed. After reaching "Highstate Triggered" status, additional highstate runs will not update the timestamp. Only changing to "Destroyed Instance" status will update the timestamp again. + | Name | Status | CPU Cores | Memory (GB)| Disk | Copper | SFP | Last Updated | |--------------------|--------------------|-----------|------------|------|--------|------|---------------------| {%- for hostname, vm_data in vm_list.items() %} -| {{ hostname }}_{{ vm_data.get('config', {}).get('role', 'unknown') }} | {{ vm_data.get('status', {}).get('status', 'Unknown') }} | {{ vm_data.get('config', {}).get('cpu', 'N/A') }} | {{ vm_data.get('config', {}).get('memory', 'N/A') }} | {{ vm_data.get('config', {}).get('disk', '-') | replace('\n', ',') if vm_data.get('config', {}).get('disk') else '-' }} | {{ vm_data.get('config', {}).get('copper', '-') | replace('\n', ',') if vm_data.get('config', {}).get('copper') else '-' }} | {{ vm_data.get('config', {}).get('sfp', '-') | replace('\n', ',') if vm_data.get('config', {}).get('sfp') else '-' }} | {{ vm_data.get('status', {}).get('timestamp', 'Never') | replace('T', ' ') | regex_replace('\\.[0-9]+', '') }} | +{%- set vm_status = vm_data.get('status', {}).get('status', 'Unknown') %} +{%- set is_destroyed = vm_status == 'Destroyed Instance' %} +{%- set vm_role = vm_data.get('config', {}).get('role', 'unknown') %} +{%- set name = hostname ~ (('_' ~ vm_role) if not is_destroyed and vm_role != 'unknown' else '') %} +| {{ name }} | {{ vm_status }} | +{%- if is_destroyed -%} +- +{%- else -%} +{{ vm_data.get('config', {}).get('cpu', 'N/A') }} +{%- endif %} | +{%- if is_destroyed -%} +- +{%- else -%} +{{ vm_data.get('config', {}).get('memory', 'N/A') }} +{%- endif %} | +{%- if is_destroyed -%} +- +{%- else -%} +{{ vm_data.get('config', {}).get('disk', '-') | replace('\n', ',') if vm_data.get('config', {}).get('disk') else '-' }} +{%- endif %} | +{%- if is_destroyed -%} +- +{%- else -%} +{{ vm_data.get('config', {}).get('copper', '-') | replace('\n', ',') if vm_data.get('config', {}).get('copper') else '-' }} +{%- endif %} | +{%- if is_destroyed -%} +- +{%- else -%} +{{ vm_data.get('config', {}).get('sfp', '-') | replace('\n', ',') if vm_data.get('config', {}).get('sfp') else '-' }} +{%- endif %} | {{ vm_data.get('status', {}).get('timestamp', 'Never') | replace('T', ' ') | regex_replace('\\.[0-9]+', '') }} | {%- endfor %} {%- else %} ## Virtual Machines +VMs can have the following status values: {% for step in PROCESS_STEPS %}{{ step }}{% if not loop.last %}, {% endif %}{% endfor %}. The "Last Updated" timestamp shows when the VM status was last changed. After reaching "Highstate Triggered" status, additional highstate runs will not update the timestamp. Only changing to "Destroyed Instance" status will update the timestamp again. + No Virtual Machines Found {%- endif %} {%- endmacro -%} @@ -66,9 +97,12 @@ No Virtual Machines Found {%- set used_memory = 0 -%} {%- set ns = namespace(used_cpu=0, used_memory=0) -%} {%- for hostname, vm_data in vms.items() -%} -{%- set vm_config = vm_data.config -%} -{%- set ns.used_cpu = ns.used_cpu + vm_config.cpu | int -%} -{%- set ns.used_memory = ns.used_memory + vm_config.memory | int -%} +{%- set vm_status = vm_data.get('status', {}).get('status', '') -%} +{%- if vm_status != 'Destroyed Instance' -%} +{%- set vm_config = vm_data.config -%} +{%- set ns.used_cpu = ns.used_cpu + vm_config.get('cpu', 0) | int -%} +{%- set ns.used_memory = ns.used_memory + vm_config.get('memory', 0) | int -%} +{%- endif -%} {%- endfor -%} {# Calculate available resources #} @@ -80,10 +114,13 @@ No Virtual Machines Found {%- set used_copper = [] -%} {%- set used_sfp = [] -%} {%- for hostname, vm in vms.items() -%} -{%- set config = vm.get('config', {}) -%} -{%- do used_disk.extend((config.get('disk', '') | string).split('\n') | map('trim') | list) -%} -{%- do used_copper.extend((config.get('copper', '') | string).split('\n') | map('trim') | list) -%} -{%- do used_sfp.extend((config.get('sfp', '') | string).split('\n') | map('trim') | list) -%} +{%- set vm_status = vm.get('status', {}).get('status', '') -%} +{%- if vm_status != 'Destroyed Instance' -%} +{%- set config = vm.get('config', {}) -%} +{%- do used_disk.extend((config.get('disk', '') | string).split('\n') | map('trim') | list) -%} +{%- do used_copper.extend((config.get('copper', '') | string).split('\n') | map('trim') | list) -%} +{%- do used_sfp.extend((config.get('sfp', '') | string).split('\n') | map('trim') | list) -%} +{%- endif -%} {%- endfor -%} {# Get available PCI indices #} diff --git a/salt/soc/dyanno/hypervisor/write_status.sls b/salt/soc/dyanno/hypervisor/write_status.sls index be03b26b7..d2aa590e6 100644 --- a/salt/soc/dyanno/hypervisor/write_status.sls +++ b/salt/soc/dyanno/hypervisor/write_status.sls @@ -11,6 +11,9 @@ {% if 'hvn' in salt['pillar.get']('features', []) %} +{# Import the process steps from map.jinja #} +{% from 'soc/dyanno/hypervisor/map.jinja' import PROCESS_STEPS %} + {% do salt.log.info('soc/dyanno/hypervisor/write_status: Running') %} {% set vm_name = pillar.get('vm_name') %} {% set hypervisor = pillar.get('hypervisor') %} @@ -21,19 +24,7 @@ {% set status_dir = base_path ~ '/' ~ hypervisor %} {% set status_file = status_dir ~ '/' ~ vm_name ~ '.status' %} -# Define the list of process steps in order (case-sensitive) -{% set process_steps = [ - 'Processing', - 'IP Configuration', - 'Starting Create', - 'Executing Deploy Script', - 'Initialize Minion Pillars', - 'Created Instance', - 'Hardware Configuration', - 'Highstate Triggered', - 'Destroyed Instance' -] %} -{% set new_index = process_steps.index(status_data.get('status')) %} +{% set new_index = PROCESS_STEPS.index(status_data.get('status')) %} {% do salt.log.debug('soc/dyanno/hypervisor/write_status: new_index: ' ~ new_index|string) %} # Function to read and parse current JSON status file @@ -46,8 +37,8 @@ {% import_json rel_path_status_file as current_status %} {% do salt.log.debug('soc/dyanno/hypervisor/write_status: current status: ' ~ current_status) %} {% do salt.log.debug('soc/dyanno/hypervisor/write_status: current status: ' ~ current_status.get('status')) %} -{% if current_status.get('status') in process_steps %} -{% set current_index = process_steps.index(current_status.get('status')) %} +{% if current_status.get('status') in PROCESS_STEPS %} +{% set current_index = PROCESS_STEPS.index(current_status.get('status')) %} {% do salt.log.debug('soc/dyanno/hypervisor/write_status: current_index: ' ~ current_index|string) %} {%- set return_value = current_index -%} {% else %} @@ -74,7 +65,7 @@ ensure_status_dir: {# Some of the status updates trigger within a second of each other can can cause, for example, IP Configuration orchestration to process before the Processing #} {# This check has been put in place to ensure a status sooner in the process can't overwrite this file if a status later in the process wrote to it first. #} {# The final step is Destroyed, so we allow Processing to overwrite that incase someone creates a new VM with same name that was previously destroyed. #} -{% if new_index > current_index or (current_index == process_steps | length - 1 and new_index == 0) %} +{% if new_index > current_index or (current_index == PROCESS_STEPS | length - 1 and new_index == 0) %} write_status_file: file.serialize: - name: {{ status_file }} @@ -88,7 +79,7 @@ write_status_file: - file: ensure_status_dir {% else %} -{% do salt.log.debug('soc/dyanno/hypervisor/write_status: File not written. ' ~ process_steps[new_index] ~ ' cannot overwrite ' ~ process_steps[current_index] ~ '.' ) %} +{% do salt.log.debug('soc/dyanno/hypervisor/write_status: File not written. ' ~ PROCESS_STEPS[new_index] ~ ' cannot overwrite ' ~ PROCESS_STEPS[current_index] ~ '.' ) %} {% endif %} From 1a9d5f151f9c89496facaa95738141f2e4607c1c Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Wed, 26 Feb 2025 14:28:31 -0500 Subject: [PATCH 144/315] change description formatting. include full vm name in HYPERVISORS --- salt/hypervisor/map.jinja | 12 ++--- .../engines/master/virtual_node_manager.py | 12 ++--- .../hypervisor/soc_hypervisor.yaml.jinja | 45 +++++-------------- 3 files changed, 20 insertions(+), 49 deletions(-) diff --git a/salt/hypervisor/map.jinja b/salt/hypervisor/map.jinja index e52d7ae1a..3d08b15d5 100644 --- a/salt/hypervisor/map.jinja +++ b/salt/hypervisor/map.jinja @@ -79,7 +79,7 @@ } }) %} {% endif %} - {% do vms.update({hostname: vm_data}) %} + {% do vms.update({hostname ~ '_' ~ role: vm_data}) %} {% else %} {% do salt.log.info('salt/hypervisor/map.jinja: Config file empty: ' ~ vm_file) %} {% endif %} @@ -87,8 +87,8 @@ {# Find and add destroyed VMs from status files #} {% set processed_vms = [] %} - {% for vm_name, vm_data in vms.items() %} - {% do processed_vms.append(vm_name) %} + {% for vm_full_name, vm_data in vms.items() %} + {% do processed_vms.append(vm_full_name) %} {% endfor %} {# Find all status files for this hypervisor #} @@ -117,7 +117,7 @@ {% set hostname = vm_name.split('_')[0] %} {# Skip already processed VMs #} - {% if hostname in processed_vms %} + {% if vm_name in processed_vms %} {% continue %} {% endif %} @@ -127,11 +127,11 @@ {# Only process files with "Destroyed Instance" status #} {% if status_data and status_data.status == 'Destroyed Instance' %} - {% do salt.log.info('salt/hypervisor/map.jinja: Found VM with Destroyed Instance status: ' ~ hostname) %} + {% do salt.log.info('salt/hypervisor/map.jinja: Found VM with Destroyed Instance status: ' ~ vm_name) %} {# Add to vms with minimal config #} {% do vms.update({ - hostname: { + vm_name: { 'status': status_data, 'config': {} } diff --git a/salt/salt/engines/master/virtual_node_manager.py b/salt/salt/engines/master/virtual_node_manager.py index c64cd7276..689f1f3f8 100644 --- a/salt/salt/engines/master/virtual_node_manager.py +++ b/salt/salt/engines/master/virtual_node_manager.py @@ -390,8 +390,8 @@ def check_hardware_availability(hypervisor_path: str, vm_name: str, requested_hw continue vm_config = read_json_file(vm_file) - if 'config' not in vm_config or vm_config.get('status') != 'running': - log.debug("Skipping VM %s (not running)", basename) + if 'config' not in vm_config: + log.debug("Skipping VM %s (no config found)", basename) continue config = vm_config['config'] @@ -469,9 +469,7 @@ def create_vm_tracking_file(hypervisor_path: str, vm_name: str, config: dict) -> set_socore_ownership(os.path.dirname(file_path)) data = { - 'config': config, - 'status': 'creating', - 'timestamp': datetime.now().isoformat() + 'config': config } # Write file and set ownership write_json_file(file_path, data) @@ -648,11 +646,9 @@ def process_vm_creation(hypervisor_path: str, vm_config: dict) -> None: # Execute command result = subprocess.run(cmd, capture_output=True, text=True, check=True) - # Update tracking file status with timestamp + # Update tracking file if needed tracking_file = os.path.join(hypervisor_path, vm_name) data = read_json_file(tracking_file) - data['status'] = 'running' - data['timestamp'] = datetime.now().isoformat() write_json_file(tracking_file, data) except subprocess.CalledProcessError as e: diff --git a/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja b/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja index a72717de9..ff654b4b8 100644 --- a/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja +++ b/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja @@ -18,55 +18,30 @@ {%- set TEMPLATE = ANNOTATION.hypervisor.hosts.pop('defaultHost') -%} {%- macro update_description(description, cpu_free, mem_free, disk_free, copper_free, sfp_free, vm_list, cpu_total, mem_total, disk_total, copper_total, sfp_total) -%} -# Hypervisor Configuration: {{ description }} - -## Resource Summary +#### Resource Summary | | CPU Cores | Memory (GB) | Disk | Copper | SFP | |-----------|-----------|-------------|-------------|-------------|-------------| | Available | {{ cpu_free }} | {{ mem_free }} | {{ disk_free | replace('\n', ',') if disk_free else 'None' }} | {{ copper_free | replace('\n', ',') if copper_free else 'None' }} | {{ sfp_free | replace('\n', ',') if sfp_free else 'None' }} | | Total | {{ cpu_total }} | {{ mem_total }} | {{ disk_total | replace('\n', ',') }} | {{ copper_total | replace('\n', ',') }} | {{ sfp_total | replace('\n', ',') }} | {%- if vm_list %} -## Virtual Machines -VMs can have the following status values: {% for step in PROCESS_STEPS %}{{ step }}{% if not loop.last %}, {% endif %}{% endfor %}. The "Last Updated" timestamp shows when the VM status was last changed. After reaching "Highstate Triggered" status, additional highstate runs will not update the timestamp. Only changing to "Destroyed Instance" status will update the timestamp again. +#### Virtual Machines +Status values: {% for step in PROCESS_STEPS %}{{ step }}{% if not loop.last %}, {% endif %}{% endfor %}. "Last Updated" shows when status changed. After "Highstate Triggered", only "Destroyed Instance" updates the timestamp. | Name | Status | CPU Cores | Memory (GB)| Disk | Copper | SFP | Last Updated | |--------------------|--------------------|-----------|------------|------|--------|------|---------------------| {%- for hostname, vm_data in vm_list.items() %} {%- set vm_status = vm_data.get('status', {}).get('status', 'Unknown') %} {%- set is_destroyed = vm_status == 'Destroyed Instance' %} -{%- set vm_role = vm_data.get('config', {}).get('role', 'unknown') %} -{%- set name = hostname ~ (('_' ~ vm_role) if not is_destroyed and vm_role != 'unknown' else '') %} -| {{ name }} | {{ vm_status }} | -{%- if is_destroyed -%} -- -{%- else -%} -{{ vm_data.get('config', {}).get('cpu', 'N/A') }} -{%- endif %} | -{%- if is_destroyed -%} -- -{%- else -%} -{{ vm_data.get('config', {}).get('memory', 'N/A') }} -{%- endif %} | -{%- if is_destroyed -%} -- -{%- else -%} -{{ vm_data.get('config', {}).get('disk', '-') | replace('\n', ',') if vm_data.get('config', {}).get('disk') else '-' }} -{%- endif %} | -{%- if is_destroyed -%} -- -{%- else -%} -{{ vm_data.get('config', {}).get('copper', '-') | replace('\n', ',') if vm_data.get('config', {}).get('copper') else '-' }} -{%- endif %} | -{%- if is_destroyed -%} -- -{%- else -%} -{{ vm_data.get('config', {}).get('sfp', '-') | replace('\n', ',') if vm_data.get('config', {}).get('sfp') else '-' }} -{%- endif %} | {{ vm_data.get('status', {}).get('timestamp', 'Never') | replace('T', ' ') | regex_replace('\\.[0-9]+', '') }} | +{%- if is_destroyed %} +| {{ hostname }} | {{ vm_status }} | - | - | - | - | - | {{ vm_data.get('status', {}).get('timestamp', 'Never') | replace('T', ' ') | regex_replace('\\.[0-9]+', '') }} | +{%- else %} +| {{ hostname }} | {{ vm_status }} | {{ vm_data.get('config', {}).get('cpu', 'N/A') }} | {{ vm_data.get('config', {}).get('memory', 'N/A') }} | {{ vm_data.get('config', {}).get('disk', '-') | replace('\n', ',') if vm_data.get('config', {}).get('disk') else '-' }} | {{ vm_data.get('config', {}).get('copper', '-') | replace('\n', ',') if vm_data.get('config', {}).get('copper') else '-' }} | {{ vm_data.get('config', {}).get('sfp', '-') | replace('\n', ',') if vm_data.get('config', {}).get('sfp') else '-' }} | {{ vm_data.get('status', {}).get('timestamp', 'Never') | replace('T', ' ') | regex_replace('\\.[0-9]+', '') }} | +{%- endif %} {%- endfor %} {%- else %} -## Virtual Machines -VMs can have the following status values: {% for step in PROCESS_STEPS %}{{ step }}{% if not loop.last %}, {% endif %}{% endfor %}. The "Last Updated" timestamp shows when the VM status was last changed. After reaching "Highstate Triggered" status, additional highstate runs will not update the timestamp. Only changing to "Destroyed Instance" status will update the timestamp again. +#### Virtual Machines +Status values: {% for step in PROCESS_STEPS %}{{ step }}{% if not loop.last %}, {% endif %}{% endfor %}. "Last Updated" shows when status changed. After "Highstate Triggered", only "Destroyed Instance" updates the timestamp. No Virtual Machines Found {%- endif %} From 52839e2a7d9c4f02d3cb50967cc2395dceb718ba Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Wed, 26 Feb 2025 15:22:36 -0500 Subject: [PATCH 145/315] implement regex for cpu and mem --- .../hypervisor/soc_hypervisor.yaml.jinja | 38 ++++++++++++++++++- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja b/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja index ff654b4b8..cf272b221 100644 --- a/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja +++ b/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja @@ -116,9 +116,43 @@ No Virtual Machines Found {%- for field in updated_template.uiElements -%} {%- set updated_field = field.copy() -%} {%- if field.field == 'cpu' -%} -{%- do updated_field.update({'label': field.label | replace('FREE', cpu_free | string) | replace('TOTAL', cpu_total | string)}) -%} +{%- if cpu_free < 10 -%} +{%- set cpu_regex = '^[1-' ~ cpu_free ~ ']$' -%} +{%- elif cpu_free < 100 -%} +{%- set tens_digit = cpu_free // 10 -%} +{%- set ones_digit = cpu_free % 10 -%} +{%- if ones_digit == 0 -%} +{%- set cpu_regex = '^([1-9]|[1-' ~ (tens_digit-1) ~ '][0-9]|' ~ tens_digit ~ '0)$' -%} +{%- else -%} +{%- set cpu_regex = '^([1-9]|[1-' ~ (tens_digit-1) ~ '][0-9]|' ~ tens_digit ~ '[0-' ~ ones_digit ~ '])$' -%} +{%- endif -%} +{%- else -%} +{%- set cpu_regex = '^([1-9]|[1-9][0-9]|100)$' -%} +{%- endif -%} +{%- do updated_field.update({ + 'label': field.label | replace('FREE', cpu_free | string) | replace('TOTAL', cpu_total | string), + 'regex': cpu_regex, + 'regexFailureMessage': 'Enter a value not exceeding ' ~ cpu_free | string ~ ' cores' + }) -%} {%- elif field.field == 'memory' -%} -{%- do updated_field.update({'label': field.label | replace('FREE', mem_free | string) | replace('TOTAL', mem_total | string)}) -%} +{%- if mem_free < 10 -%} +{%- set mem_regex = '^[1-' ~ mem_free ~ ']$' -%} +{%- elif mem_free < 100 -%} +{%- set tens_digit = mem_free // 10 -%} +{%- set ones_digit = mem_free % 10 -%} +{%- if ones_digit == 0 -%} +{%- set mem_regex = '^([1-9]|[1-' ~ (tens_digit-1) ~ '][0-9]|' ~ tens_digit ~ '0)$' -%} +{%- else -%} +{%- set mem_regex = '^([1-9]|[1-' ~ (tens_digit-1) ~ '][0-9]|' ~ tens_digit ~ '[0-' ~ ones_digit ~ '])$' -%} +{%- endif -%} +{%- else -%} +{%- set mem_regex = '^([1-9]|[1-9][0-9]|[1-9][0-9][0-9])$' -%} +{%- endif -%} +{%- do updated_field.update({ + 'label': field.label | replace('FREE', mem_free | string) | replace('TOTAL', mem_total | string), + 'regex': mem_regex, + 'regexFailureMessage': 'Enter a value not exceeding ' ~ mem_free | string ~ ' GB' + }) -%} {%- elif field.field == 'disk' -%} {%- do updated_field.update({'label': field.label | replace('FREE', disk_free) | replace('TOTAL', disk_total | replace('\n', ','))}) -%} {%- elif field.field == 'copper' -%} From 4e954c24f7dac902836f3fd580f5d3a9cfcb1a4e Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Wed, 26 Feb 2025 17:58:09 -0500 Subject: [PATCH 146/315] handle cpu, copper and sfp as options --- .../engines/master/virtual_node_manager.py | 107 +++++++++++++----- salt/soc/dyanno/hypervisor/hypervisor.yaml | 12 +- .../hypervisor/soc_hypervisor.yaml.jinja | 26 +++-- 3 files changed, 102 insertions(+), 43 deletions(-) diff --git a/salt/salt/engines/master/virtual_node_manager.py b/salt/salt/engines/master/virtual_node_manager.py index 689f1f3f8..42d8f6725 100644 --- a/salt/salt/engines/master/virtual_node_manager.py +++ b/salt/salt/engines/master/virtual_node_manager.py @@ -36,6 +36,7 @@ Configuration Files: - Located at /VMs - Contains array of VM configurations - Each VM config specifies hardware and network settings + - Hardware indices (disk, copper, sfp) must be specified as JSON arrays: "disk":["1","2"] defaults.yaml: Hardware capabilities configuration - Located at /opt/so/saltstack/default/salt/hypervisor/defaults.yaml @@ -210,7 +211,6 @@ def read_yaml_file(file_path: str) -> dict: except Exception as e: log.error("Failed to read YAML file %s: %s", file_path, str(e)) raise - def convert_pci_id(pci_id: str) -> str: """ Convert PCI ID from pci_0000_c7_00_0 format to 0000:c7:00.0 format. @@ -241,6 +241,35 @@ def convert_pci_id(pci_id: str) -> str: log.error("Failed to convert PCI ID %s: %s", pci_id, str(e)) raise +def parse_hardware_indices(hw_value: Any) -> List[int]: + """ + Parse hardware indices from JSON array format. + + Args: + hw_value: Hardware value which should be a list + + Returns: + List of integer indices + """ + indices = [] + + if hw_value is None: + return indices + + # If it's a list (expected format) + if isinstance(hw_value, list): + try: + indices = [int(x) for x in hw_value] + log.debug("Parsed hardware indices from list format: %s", indices) + except (ValueError, TypeError) as e: + log.error("Failed to parse hardware indices from list format: %s", str(e)) + raise ValueError(f"Invalid hardware indices format in list: {hw_value}") + else: + log.warning("Unexpected type for hardware indices: %s", type(hw_value)) + raise ValueError(f"Hardware indices must be in array format, got: {type(hw_value)}") + + return indices + def get_hypervisor_model(hypervisor: str) -> str: """Get sosmodel from hypervisor grains.""" try: @@ -318,7 +347,7 @@ def validate_hardware_request(model_config: dict, requested_hw: dict) -> Tuple[b for hw_type in ['disk', 'copper', 'sfp']: if hw_type in requested_hw and requested_hw[hw_type]: try: - indices = [int(x) for x in str(requested_hw[hw_type]).split('\n')] + indices = parse_hardware_indices(requested_hw[hw_type]) log.debug("Checking if %s indices %s exist in model", hw_type, indices) if hw_type not in model_config['hardware']: @@ -333,8 +362,8 @@ def validate_hardware_request(model_config: dict, requested_hw: dict) -> Tuple[b if invalid_indices: log.error("%s indices %s do not exist in model", hw_type, invalid_indices) errors[hw_type] = f"Invalid {hw_type} indices: {invalid_indices}" - except ValueError: - log.error("Invalid %s indices format: %s", hw_type, requested_hw[hw_type]) + except ValueError as e: + log.error("Invalid %s indices format: %s", hw_type, str(e)) errors[hw_type] = f"Invalid {hw_type} indices format" except KeyError: log.error("No %s configuration found in model", hw_type) @@ -407,10 +436,13 @@ def check_hardware_availability(hypervisor_path: str, vm_name: str, requested_hw # Track unique resources for hw_type in ['disk', 'copper', 'sfp']: if hw_type in config and config[hw_type]: - indices = [int(x) for x in str(config[hw_type]).split('\n')] - for idx in indices: - used_resources[hw_type][idx] = basename.replace('_sensor', '') # Store VM name without role - log.debug("VM %s is using %s indices: %s", basename, hw_type, indices) + try: + indices = parse_hardware_indices(config[hw_type]) + for idx in indices: + used_resources[hw_type][idx] = basename.replace('_sensor', '') # Store VM name without role + log.debug("VM %s is using %s indices: %s", basename, hw_type, indices) + except ValueError as e: + log.error("Error parsing %s indices for VM %s: %s", hw_type, basename, str(e)) log.debug("Total hardware currently in use - CPU: %d, Memory: %dGB", total_cpu, total_memory) log.debug("Hardware indices currently in use: %s", used_resources) @@ -434,23 +466,27 @@ def check_hardware_availability(hypervisor_path: str, vm_name: str, requested_hw # Check for hardware conflicts for hw_type in ['disk', 'copper', 'sfp']: if hw_type in requested_hw and requested_hw[hw_type]: - requested_indices = [int(x) for x in str(requested_hw[hw_type]).split('\n')] - log.debug("Checking for %s conflicts - Requesting indices: %s, Currently in use: %s", - hw_type, requested_indices, used_resources[hw_type]) - conflicts = {} # {index: vm_name} - for idx in requested_indices: - if idx in used_resources[hw_type]: - conflicts[idx] = used_resources[hw_type][idx] - - if conflicts: - # Create one sentence per conflict - conflict_details = [] - hw_name = hw_type.upper() if hw_type == 'sfp' else hw_type.capitalize() - for idx, vm in conflicts.items(): - conflict_details.append(f"{hw_name} index {idx} in use by {vm}") + try: + requested_indices = parse_hardware_indices(requested_hw[hw_type]) + log.debug("Checking for %s conflicts - Requesting indices: %s, Currently in use: %s", + hw_type, requested_indices, used_resources[hw_type]) + conflicts = {} # {index: vm_name} + for idx in requested_indices: + if idx in used_resources[hw_type]: + conflicts[idx] = used_resources[hw_type][idx] - log.debug("Found conflicting %s indices: %s", hw_type, conflict_details) - errors[hw_type] = ". ".join(conflict_details) + "." + if conflicts: + # Create one sentence per conflict + conflict_details = [] + hw_name = hw_type.upper() if hw_type == 'sfp' else hw_type.capitalize() + for idx, vm in conflicts.items(): + conflict_details.append(f"{hw_name} index {idx} in use by {vm}") + + log.debug("Found conflicting %s indices: %s", hw_type, conflict_details) + errors[hw_type] = ". ".join(conflict_details) + "." + except ValueError as e: + log.error("Error parsing %s indices for conflict check: %s", hw_type, str(e)) + errors[hw_type] = f"Invalid {hw_type} indices format" if errors: log.debug("Hardware validation failed with errors: %s", errors) @@ -636,12 +672,23 @@ def process_vm_creation(hypervisor_path: str, vm_config: dict) -> None: # Add PCI devices for hw_type in ['disk', 'copper', 'sfp']: if hw_type in vm_config and vm_config[hw_type]: - indices = [int(x) for x in str(vm_config[hw_type]).split('\n')] - for idx in indices: - hw_config = {int(k): v for k, v in model_config['hardware'][hw_type].items()} - pci_id = hw_config[idx] - converted_pci_id = convert_pci_id(pci_id) - cmd.extend(['-P', converted_pci_id]) + try: + indices = parse_hardware_indices(vm_config[hw_type]) + for idx in indices: + hw_config = {int(k): v for k, v in model_config['hardware'][hw_type].items()} + pci_id = hw_config[idx] + converted_pci_id = convert_pci_id(pci_id) + cmd.extend(['-P', converted_pci_id]) + except ValueError as e: + error_msg = f"Failed to parse {hw_type} indices: {str(e)}" + log.error(error_msg) + mark_vm_failed(os.path.join(hypervisor_path, vm_name), 3, error_msg) + raise ValueError(error_msg) + except KeyError as e: + error_msg = f"Invalid {hw_type} index: {str(e)}" + log.error(error_msg) + mark_vm_failed(os.path.join(hypervisor_path, vm_name), 3, error_msg) + raise KeyError(error_msg) # Execute command result = subprocess.run(cmd, capture_output=True, text=True, check=True) diff --git a/salt/soc/dyanno/hypervisor/hypervisor.yaml b/salt/soc/dyanno/hypervisor/hypervisor.yaml index 0166dbc3c..59e8da940 100644 --- a/salt/soc/dyanno/hypervisor/hypervisor.yaml +++ b/salt/soc/dyanno/hypervisor/hypervisor.yaml @@ -63,17 +63,17 @@ hypervisor: readonly: true forcedType: int - field: disk - label: "Disk(s) for passthrough. Line-delimited list. Free: FREE | Total: TOTAL" + label: "Disk(s) for passthrough. Free: FREE | Total: TOTAL" readonly: true + options: [] forcedType: '[]int' - multiline: true - field: copper - label: "Copper port(s) for passthrough. Line-delimited list. Free: FREE | Total: TOTAL" + label: "Copper port(s) for passthrough. Free: FREE | Total: TOTAL" readonly: true + options: [] forcedType: '[]int' - multiline: true - field: sfp - label: "SFP port(s) for passthrough. Line-delimited list. Free: FREE | Total: TOTAL" + label: "SFP port(s) for passthrough. Free: FREE | Total: TOTAL" readonly: true + options: [] forcedType: '[]int' - multiline: true diff --git a/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja b/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja index cf272b221..c3eeee689 100644 --- a/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja +++ b/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja @@ -36,7 +36,7 @@ Status values: {% for step in PROCESS_STEPS %}{{ step }}{% if not loop.last %}, {%- if is_destroyed %} | {{ hostname }} | {{ vm_status }} | - | - | - | - | - | {{ vm_data.get('status', {}).get('timestamp', 'Never') | replace('T', ' ') | regex_replace('\\.[0-9]+', '') }} | {%- else %} -| {{ hostname }} | {{ vm_status }} | {{ vm_data.get('config', {}).get('cpu', 'N/A') }} | {{ vm_data.get('config', {}).get('memory', 'N/A') }} | {{ vm_data.get('config', {}).get('disk', '-') | replace('\n', ',') if vm_data.get('config', {}).get('disk') else '-' }} | {{ vm_data.get('config', {}).get('copper', '-') | replace('\n', ',') if vm_data.get('config', {}).get('copper') else '-' }} | {{ vm_data.get('config', {}).get('sfp', '-') | replace('\n', ',') if vm_data.get('config', {}).get('sfp') else '-' }} | {{ vm_data.get('status', {}).get('timestamp', 'Never') | replace('T', ' ') | regex_replace('\\.[0-9]+', '') }} | +| {{ hostname }} | {{ vm_status }} | {{ vm_data.get('config', {}).get('cpu', 'N/A') }} | {{ vm_data.get('config', {}).get('memory', 'N/A') }} | {{ vm_data.get('config', {}).get('disk', []) | join(',') if vm_data.get('config', {}).get('disk') else '-' }} | {{ vm_data.get('config', {}).get('copper', []) | join(',') if vm_data.get('config', {}).get('copper') else '-' }} | {{ vm_data.get('config', {}).get('sfp', []) | join(',') if vm_data.get('config', {}).get('sfp') else '-' }} | {{ vm_data.get('status', {}).get('timestamp', 'Never') | replace('T', ' ') | regex_replace('\\.[0-9]+', '') }} | {%- endif %} {%- endfor %} {%- else %} @@ -92,9 +92,9 @@ No Virtual Machines Found {%- set vm_status = vm.get('status', {}).get('status', '') -%} {%- if vm_status != 'Destroyed Instance' -%} {%- set config = vm.get('config', {}) -%} -{%- do used_disk.extend((config.get('disk', '') | string).split('\n') | map('trim') | list) -%} -{%- do used_copper.extend((config.get('copper', '') | string).split('\n') | map('trim') | list) -%} -{%- do used_sfp.extend((config.get('sfp', '') | string).split('\n') | map('trim') | list) -%} +{%- do used_disk.extend(config.get('disk', [])) -%} +{%- do used_copper.extend(config.get('copper', [])) -%} +{%- do used_sfp.extend(config.get('sfp', [])) -%} {%- endif -%} {%- endfor -%} @@ -154,11 +154,23 @@ No Virtual Machines Found 'regexFailureMessage': 'Enter a value not exceeding ' ~ mem_free | string ~ ' GB' }) -%} {%- elif field.field == 'disk' -%} -{%- do updated_field.update({'label': field.label | replace('FREE', disk_free) | replace('TOTAL', disk_total | replace('\n', ','))}) -%} +{%- set disk_free_list = disk_free.split(',') if disk_free else [] -%} +{%- do updated_field.update({ + 'label': field.label | replace('FREE', disk_free) | replace('TOTAL', disk_total | replace('\n', ',')), + 'options': disk_free_list + }) -%} {%- elif field.field == 'copper' -%} -{%- do updated_field.update({'label': field.label | replace('FREE', copper_free) | replace('TOTAL', copper_total | replace('\n', ','))}) -%} +{%- set copper_free_list = copper_free.split(',') if copper_free else [] -%} +{%- do updated_field.update({ + 'label': field.label | replace('FREE', copper_free) | replace('TOTAL', copper_total | replace('\n', ',')), + 'options': copper_free_list + }) -%} {%- elif field.field == 'sfp' -%} -{%- do updated_field.update({'label': field.label | replace('FREE', sfp_free) | replace('TOTAL', sfp_total | replace('\n', ','))}) -%} +{%- set sfp_free_list = sfp_free.split(',') if sfp_free else [] -%} +{%- do updated_field.update({ + 'label': field.label | replace('FREE', sfp_free) | replace('TOTAL', sfp_total | replace('\n', ',')), + 'options': sfp_free_list + }) -%} {%- endif -%} {%- do updated_elements.append(updated_field) -%} {%- endfor -%} From c8a1c8377a0e230c9df6e3fdae24a4e5896fac9b Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Thu, 27 Feb 2025 16:04:44 -0500 Subject: [PATCH 147/315] vm power operations --- .../engines/master/virtual_power_manager.py | 330 ++++++++++++++++++ salt/salt/files/hvn_engine.conf | 7 + .../files/virtual_node_manager_engine.conf | 4 - salt/salt/master.sls | 17 +- salt/soc/dyanno/hypervisor/hypervisor.yaml | 8 + 5 files changed, 357 insertions(+), 9 deletions(-) create mode 100644 salt/salt/engines/master/virtual_power_manager.py create mode 100644 salt/salt/files/hvn_engine.conf delete mode 100644 salt/salt/files/virtual_node_manager_engine.conf diff --git a/salt/salt/engines/master/virtual_power_manager.py b/salt/salt/engines/master/virtual_power_manager.py new file mode 100644 index 000000000..8cca82606 --- /dev/null +++ b/salt/salt/engines/master/virtual_power_manager.py @@ -0,0 +1,330 @@ +#!/opt/saltstack/salt/bin/python3 + +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. +# +# Note: Per the Elastic License 2.0, the second limitation states: +# +# "You may not move, change, disable, or circumvent the license key functionality +# in the software, and you may not remove or obscure any functionality in the +# software that is protected by the license key." + +""" +Salt Engine for Virtual Machine Power Management + +This engine manages power control actions for virtual machines in Security Onion's +virtualization infrastructure. It monitors VM configurations for power control requests +and executes the appropriate virt module actions. + +Usage: + engines: + - virtual_power_manager: + interval: 60 + base_path: /opt/so/saltstack/local/salt/hypervisor/hosts + +Options: + interval: Time in seconds between engine runs (managed by salt-master, default: 60) + base_path: Base directory containing hypervisor configurations (default: /opt/so/saltstack/local/salt/hypervisor/hosts) + +Configuration Files: + VMs: JSON file containing VM configurations + - Located at /VMs + - Contains array of VM configurations + - Power control requests are specified with the "powercontrol" key + - Valid values for "powercontrol": "Reboot", "Reset", "Shutdown", "Start", "Stop" + +Examples: + 1. Basic Configuration: + engines: + - virtual_power_manager: {} + + Uses default settings to process power control requests every 60 seconds. + + 2. Custom Interval: + engines: + - virtual_power_manager: + interval: 120 + + Processes power control requests every 120 seconds. + +Power Control Actions: + - Reboot: Gracefully reboot the VM (virt.reboot) + - Reset: Force reset the VM (virt.reset) + - Shutdown: Gracefully shut down the VM (virt.shutdown) + - Start: Start the VM (virt.start) + - Stop: Force stop the VM (virt.stop) + +Notes: + - File locking is used to prevent race conditions when multiple processes access the VMs file + - The "powercontrol" key is removed from the VM configuration after successful execution + - Comprehensive logging for troubleshooting + - No continuous loop (salt-master handles scheduling) + - File locking is only applied when a powercontrol key is detected, not on every run + +Description: + The engine operates in the following phases: + + 1. Configuration Processing + - Reads VMs file for each hypervisor without locking + - Identifies VMs with "powercontrol" key + - If powercontrol key is found, acquires lock and reads file again + + 2. Power Control Execution + - Maps "powercontrol" value to virt module function + - Executes appropriate virt module command + - Removes "powercontrol" key after successful execution + + 3. File Locking + - Acquires lock only when a powercontrol key is detected + - Releases lock after modifications + - Handles lock acquisition failures + +Logging: + Log files are written to /opt/so/log/salt/master + Comprehensive logging includes: + - Power control action details + - Command execution results + - Error conditions with full context + - File locking operations +""" + +import os +import glob +import json +import logging +import fcntl +import salt.client +from typing import Dict, List, Optional, Any, Tuple + +# Configure logging +log = logging.getLogger(__name__) +log.setLevel(logging.DEBUG) + +# Constants +DEFAULT_INTERVAL = 60 +DEFAULT_BASE_PATH = '/opt/so/saltstack/local/salt/hypervisor/hosts' +VALID_POWER_ACTIONS = {'Reboot', 'Reset', 'Shutdown', 'Start', 'Stop'} + +class FileLock: + """ + Context manager for file locking. + + This class provides a context manager for file locking using fcntl. + It acquires an exclusive lock on the file when entering the context + and releases the lock when exiting. + + Example: + with FileLock(file_path): + # Read and modify file + # Lock is automatically released when exiting the context + """ + + def __init__(self, file_path: str): + self.file_path = file_path + self.lock_path = f"{file_path}.lock" + self.lock_file = None + + def __enter__(self): + try: + # Open the lock file + self.lock_file = open(self.lock_path, 'w') + + # Acquire exclusive lock + fcntl.flock(self.lock_file, fcntl.LOCK_EX) + log.debug("Acquired lock on %s", self.file_path) + + return self + + except Exception as e: + log.error("Failed to acquire lock on %s: %s", self.file_path, str(e)) + if self.lock_file: + self.lock_file.close() + raise + + def __exit__(self, exc_type, exc_val, exc_tb): + try: + # Release lock + if self.lock_file: + fcntl.flock(self.lock_file, fcntl.LOCK_UN) + self.lock_file.close() + log.debug("Released lock on %s", self.file_path) + + # Remove lock file + if os.path.exists(self.lock_path): + os.remove(self.lock_path) + + except Exception as e: + log.error("Error releasing lock on %s: %s", self.file_path, str(e)) + +def read_json_file(file_path: str) -> Any: + """ + Read and parse a JSON file. + Returns an empty array if the file is empty. + """ + try: + with open(file_path, 'r') as f: + content = f.read().strip() + if not content: + return [] + return json.loads(content) + except Exception as e: + log.error("Failed to read JSON file %s: %s", file_path, str(e)) + raise + +def write_json_file(file_path: str, data: Any) -> None: + """Write data to a JSON file.""" + try: + with open(file_path, 'w') as f: + json.dump(data, f, indent=2) + except Exception as e: + log.error("Failed to write JSON file %s: %s", file_path, str(e)) + raise + +def has_power_control_requests(nodes_config: List[Dict]) -> bool: + """ + Check if any VM in the configuration has a powercontrol key. + + Args: + nodes_config: List of VM configurations + + Returns: + True if at least one VM has a powercontrol key, False otherwise + """ + return any('powercontrol' in vm_config for vm_config in nodes_config) + +def process_power_control(hypervisor: str, vm_config: dict) -> bool: + """ + Process a power control request for a VM. + + Args: + hypervisor: Name of the hypervisor + vm_config: VM configuration dictionary + + Returns: + True if the power control action was successful, False otherwise + """ + try: + # Get VM name and power control action + vm_name = f"{vm_config['hostname']}_{vm_config['role']}" + power_action = vm_config['powercontrol'] + + # Validate power action + if power_action not in VALID_POWER_ACTIONS: + log.error("Invalid power control action: %s", power_action) + return False + + # Map power action to virt module function + virt_function = power_action.lower() + + # Execute power control action + log.info("Executing %s on VM %s", power_action, vm_name) + client = salt.client.LocalClient() + result = client.cmd( + f"{hypervisor}_*", + f"virt.{virt_function}", + [vm_name], + expr_form="glob" + ) + + # Check result + if result and any(success for success in result.values()): + log.info("Successfully executed %s on VM %s", power_action, vm_name) + return True + else: + log.error("Failed to execute %s on VM %s: %s", power_action, vm_name, result) + return False + + except Exception as e: + log.error("Error processing power control for VM %s: %s", vm_config.get('hostname', 'unknown'), str(e)) + return False + +def process_hypervisor_power_requests(hypervisor_path: str) -> None: + """ + Process power control requests for a single hypervisor. + + Args: + hypervisor_path: Path to the hypervisor directory + """ + try: + # Get hypervisor name from path + hypervisor = os.path.basename(hypervisor_path) + + # Read VMs file + vms_file = os.path.join(os.path.dirname(hypervisor_path), f"{hypervisor}VMs") + if not os.path.exists(vms_file): + log.debug("No VMs file found at %s", vms_file) + return + + # First, read the file without locking to check if any VM has a powercontrol key + nodes_config = read_json_file(vms_file) + if not nodes_config: + log.debug("Empty VMs configuration in %s", vms_file) + return + + # Check if any VM has a powercontrol key + if not has_power_control_requests(nodes_config): + log.debug("No power control requests found in %s", vms_file) + return + + # If we found powercontrol keys, lock the file and process the requests + with FileLock(vms_file): + # Read the VMs file again with the lock to ensure we have the latest data + nodes_config = read_json_file(vms_file) + if not nodes_config: + log.debug("Empty VMs configuration in %s (after lock)", vms_file) + return + + # Track if any changes were made + changes_made = False + + # Process each VM configuration + for i, vm_config in enumerate(nodes_config): + if 'powercontrol' in vm_config: + # Process power control request + log.info("Found power control request for VM %s_%s: %s", + vm_config.get('hostname', 'unknown'), + vm_config.get('role', 'unknown'), + vm_config['powercontrol']) + + success = process_power_control(hypervisor, vm_config) + if success: + # Remove powercontrol key + log.info("Power control action successful, removing powercontrol key") + del nodes_config[i]['powercontrol'] + changes_made = True + + # Write updated configuration if changes were made + if changes_made: + log.info("Writing updated VM configuration to %s", vms_file) + write_json_file(vms_file, nodes_config) + + except Exception as e: + log.error("Failed to process hypervisor %s: %s", hypervisor_path, str(e)) + raise + +def start(interval: int = DEFAULT_INTERVAL, + base_path: str = DEFAULT_BASE_PATH) -> None: + """ + Process virtual machine power control requests. + + This function processes power control requests for virtual machines + by monitoring the VMs files for the "powercontrol" key. + + Args: + interval: Time in seconds between engine runs (managed by salt-master) + base_path: Base path containing hypervisor configurations + """ + log.info("Starting virtual power manager engine") + + try: + # Process each hypervisor directory + for hypervisor_path in glob.glob(os.path.join(base_path, '*')): + if os.path.isdir(hypervisor_path): + process_hypervisor_power_requests(hypervisor_path) + + log.info("Virtual power manager completed successfully") + + except Exception as e: + log.error("Error in virtual power manager: %s", str(e)) diff --git a/salt/salt/files/hvn_engine.conf b/salt/salt/files/hvn_engine.conf new file mode 100644 index 000000000..9ec2bc998 --- /dev/null +++ b/salt/salt/files/hvn_engine.conf @@ -0,0 +1,7 @@ +engines: + - virtual_node_manager: + interval: 10 + base_path: /opt/so/saltstack/local/salt/hypervisor/hosts + - virtual_power_manager: + interval: 10 + base_path: /opt/so/saltstack/local/salt/hypervisor/hosts diff --git a/salt/salt/files/virtual_node_manager_engine.conf b/salt/salt/files/virtual_node_manager_engine.conf deleted file mode 100644 index 8374f551a..000000000 --- a/salt/salt/files/virtual_node_manager_engine.conf +++ /dev/null @@ -1,4 +0,0 @@ -engines: - - virtual_node_manager: - interval: 30 - base_path: /opt/so/saltstack/local/salt/hypervisor/hosts diff --git a/salt/salt/master.sls b/salt/salt/master.sls index ed8da3f73..56f529e89 100644 --- a/salt/salt/master.sls +++ b/salt/salt/master.sls @@ -49,6 +49,13 @@ pillarWatch_engine: - source: salt://salt/engines/master/pillarWatch.py {% if 'hvn' in salt['pillar.get']('features', []) %} +hvn_engine_config: + file.managed: + - name: /etc/salt/master.d/hvn_engine.conf + - source: salt://salt/files/hvn_engine.conf + - watch_in: + - service: salt_master_service + virtual_node_manager_engine: file.managed: - name: /etc/salt/engines/virtual_node_manager.py @@ -56,11 +63,12 @@ virtual_node_manager_engine: - watch_in: - service: salt_master_service -virtual_node_manager_engine_config: +virtual_power_manager_engine: file.managed: - - name: /etc/salt/master.d/virtual_node_manager_engine.conf - - source: salt://salt/files/virtual_node_manager_engine.conf - + - name: /etc/salt/engines/virtual_power_manager.py + - source: salt://salt/engines/master/virtual_power_manager.py + - watch_in: + - service: salt_master_service {% endif %} engines_config: @@ -88,7 +96,6 @@ reactor: - 'setup/so-minion': - /opt/so/saltstack/default/salt/reactor/sominion_setup.sls - 'salt/cloud/*/destroyed': - - /opt/so/saltstack/default/salt/reactor/virtReleaseHardware.sls - /opt/so/saltstack/default/salt/reactor/deleteKey.sls #} diff --git a/salt/soc/dyanno/hypervisor/hypervisor.yaml b/salt/soc/dyanno/hypervisor/hypervisor.yaml index 59e8da940..6b0458265 100644 --- a/salt/soc/dyanno/hypervisor/hypervisor.yaml +++ b/salt/soc/dyanno/hypervisor/hypervisor.yaml @@ -77,3 +77,11 @@ hypervisor: readonly: true options: [] forcedType: '[]int' + - field: powercontrol + label: "Execute VM power operations" + options: + - Start + - Reboot + - Shutdown + - Reset + - Stop From c6c979dc190743c7b9e3ded03355fd699841e457 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Fri, 28 Feb 2025 16:12:28 -0500 Subject: [PATCH 148/315] properly set memory and CPUCORES for minion pillars during vm setup --- salt/reactor/sominion_setup.sls | 36 +++++++++------- salt/setup/virt/soinstall.map.jinja | 65 ++++++++++++++++++++++++----- salt/setup/virt/sominion.sls | 19 ++++----- 3 files changed, 85 insertions(+), 35 deletions(-) diff --git a/salt/reactor/sominion_setup.sls b/salt/reactor/sominion_setup.sls index 21c7824fe..91889158b 100644 --- a/salt/reactor/sominion_setup.sls +++ b/salt/reactor/sominion_setup.sls @@ -10,26 +10,32 @@ from subprocess import call import yaml def run(): + logging.debug('sominion_setup_reactor: Running') minionid = data['id'] DATA = data['data'] hv_name = DATA['HYPERVISOR_HOST'] - logging.error("sominion_setup reactor: %s " % DATA) + logging.debug('sominion_setup_reactor: DATA: %s' % DATA) - vm_out_data = { - 'cpu': DATA['CPU'], - 'memory': DATA['MEMORY'], - 'disks': DATA['DISKS'], - 'copper': DATA['COPPER'], - 'sfp': DATA['SFP'] - } - logging.error("sominion_setup reactor: vm_out_data: %s " % vm_out_data) + # Build the base command + cmd = "NODETYPE=" + DATA['NODETYPE'] + " /usr/sbin/so-minion -o=addVM -m=" + minionid + " -n=" + DATA['MNIC'] + " -i=" + DATA['MAINIP'] + " -d='" + DATA['NODE_DESCRIPTION'] + "'" + + # Add optional arguments only if they exist in DATA + if 'CORECOUNT' in DATA: + cmd += " -c=" + str(DATA['CORECOUNT']) + + if 'INTERFACE' in DATA: + cmd += " -a=" + DATA['INTERFACE'] + + if 'ES_HEAP_SIZE' in DATA: + cmd += " -e=" + DATA['ES_HEAP_SIZE'] + + if 'LS_HEAP_SIZE' in DATA: + cmd += " -l=" + DATA['LS_HEAP_SIZE'] + + logging.debug('sominion_setup_reactor: Command: %s' % cmd) + rc = call(cmd, shell=True) - with open("/opt/so/saltstack/local/pillar/hypervisor/" + hv_name + "/" + minionid + ".sls", 'w') as f: - yaml.dump(vm_out_data, f, default_flow_style=False) - - rc = call("NODETYPE=" + DATA['NODETYPE'] + " /usr/sbin/so-minion -o=addVM -m=" + minionid + " -n=" + DATA['MNIC'] + " -i=" + DATA['MAINIP'] + " -a=" + DATA['INTERFACE'] + " -c=" + str(DATA['CPU']) + " -d='" + DATA['NODE_DESCRIPTION'] + "'" + " -e=" + DATA['ES_HEAP_SIZE'] + " -l=" + DATA['LS_HEAP_SIZE'], shell=True) - - logging.error('sominion_setup reactor: rc: %s' % rc) + logging.info('sominion_setup_reactor: rc: %s' % rc) return {} diff --git a/salt/setup/virt/soinstall.map.jinja b/salt/setup/virt/soinstall.map.jinja index 33da9ff0c..1d70ac67e 100644 --- a/salt/setup/virt/soinstall.map.jinja +++ b/salt/setup/virt/soinstall.map.jinja @@ -4,18 +4,67 @@ Elastic License 2.0. #} {% set nodetype = grains.id.split("_") | last %} -{% import_yaml 'setup/virt/' ~ nodetype ~ '.yaml' as DATA %} -{% set total_mem = grains.mem_total %} +{% set hypervisor = salt['grains.get']('salt-cloud:profile').split('-')[1] %} +{# Import hardware details from VM hardware tracking file #} +{% import_json 'hypervisor/hosts/' ~ hypervisor ~ '/' ~ grains.id as vm_hardware %} + +{% set DATA = {} %} +{% do DATA.update({'MNIC': 'enp1s0'}) %} {% do DATA.update({'MAINIP': grains.ip_interfaces.get(DATA.MNIC)[0]}) %} -{% do DATA.update({'CORECOUNT': grains.num_cpus}) %} -{% do DATA.update({'CPUCORES': grains.num_cpus}) %} + +{# Use CPU value from VM hardware file if available, otherwise fallback to grains #} +{% if vm_hardware and vm_hardware.get('config', {}).get('cpu') %} + {% do DATA.update({'CPUCORES': vm_hardware.get('config', {}).get('cpu')|int }) %} + {% do salt.log.info('Using CPU from VM hardware file: ' ~ vm_hardware.get('config', {}).get('cpu')|string) %} +{% else %} + {% do DATA.update({'CPUCORES': grains.num_cpus }) %} + {% do salt.log.error('Using CPU from grains: ' ~ grains.num_cpus|string) %} +{% endif %} + +{# Use memory value from VM hardware file if available, otherwise fallback to grains. If grains is used, it will be from cpu/mem from the base domain. #} +{% if vm_hardware and vm_hardware.get('config', {}).get('memory') %} + {% set total_mem = vm_hardware.get('config', {}).get('memory')|int * 1024 %} + {% do salt.log.info('Using memory from VM hardware file: ' ~ vm_hardware.get('config', {}).get('memory')|string ~ ' (converted to ' ~ total_mem|string ~ ')') %} +{% else %} + {% set total_mem = grains.mem_total %} + {% do salt.log.error('Using memory from grains: ' ~ total_mem|string) %} +{% endif %} + +{% do DATA.update({'NODE_DESCRIPTION': 'VM of ' ~ hypervisor}) %} +{% do DATA.update({'NODETYPE': nodetype | upper}) %} + +{% if nodetype in ['standalone', 'sensor', 'heavynode']%} +{% do DATA.update({'INTERFACE': 'bond0'}) %} +{% endif %} + +{# Calculate reasonable core usage #} +{% set cores_for_zeek = (DATA.CPUCORES / 2) - 1 %} +{% do salt.log.info('cores_for_zeek calculation using CPUCORES: ' ~ DATA.CPUCORES|string) %} +{% do salt.log.info('cores_for_zeek: ' ~ cores_for_zeek|string) %} +{% set lb_procs_round = cores_for_zeek|round|int %} +{% do salt.log.info('lb_procs_round: ' ~ lb_procs_round|string) %} +{% set lb_procs = 1 if lb_procs_round < 1 else lb_procs_round %} +{% do salt.log.info('lb_procs: ' ~ lb_procs|string) %} +{# Check memory conditions #} +{% set low_mem = false %} +{% do salt.log.info('Memory check using total_mem: ' ~ total_mem|string) %} +{% if nodetype in ['standalone', 'heavynode'] %} +{% if total_mem > 15000 and total_mem < 24000 %} +{% set low_mem = true %} +{% endif %} +{% endif %} +{# Set CORECOUNT based on memory conditions #} +{% if low_mem %} +{% do DATA.update({'CORECOUNT': 1}) %} +{% else %} +{% do DATA.update({'CORECOUNT': lb_procs}) %} +{% endif %} + {% if nodetype in ['searchnode', 'receiver', 'fleet', 'heavynode'] %} - {# we can't use the host grain here because the grain may not be updated yet from the hostname change #} {% do DATA.update({'LSHOSTNAME': grains.id.split("_") | first}) %} - {% if total_mem >= 32000 or nodetype in ['managersearch','heavynode','standalone'] %} {% set LSHEAP="1000m" %} {% elif nodetype == 'eval' %} @@ -24,11 +73,8 @@ {% set LSHEAP="500m" %} {% endif %} {% do DATA.update({'LSHEAP': LSHEAP}) %} - {% endif %} - {% if nodetype in ['searchnode', 'heavynode'] %} - {# this replicates the function es_heapsize in so-functions #} {% if total_mem < 8000 %} {% set ES_HEAP_SIZE = "600m" %} @@ -43,5 +89,4 @@ {% endif %} {% endif %} {% do DATA.update({'ES_HEAP_SIZE': ES_HEAP_SIZE}) %} - {% endif %} diff --git a/salt/setup/virt/sominion.sls b/salt/setup/virt/sominion.sls index 55e3a796a..e0598a4d3 100644 --- a/salt/setup/virt/sominion.sls +++ b/salt/setup/virt/sominion.sls @@ -13,18 +13,17 @@ create_pillar: MAINIP: {{ DATA.MAINIP }} MNIC: {{ DATA.MNIC }} NODE_DESCRIPTION: '{{ DATA.NODE_DESCRIPTION }}' - ES_HEAP_SIZE: {{ DATA.ES_HEAP_SIZE }} - PATCHSCHEDULENAME: {{ DATA.PATCHSCHEDULENAME }} INTERFACE: {{ DATA.INTERFACE }} NODETYPE: {{ DATA.NODETYPE }} + {% if 'CORECOUNT' in DATA %} CORECOUNT: {{ DATA.CORECOUNT }} + {% endif %} + {% if 'ES_HEAP_SIZE' in DATA %} + ES_HEAP_SIZE: {{ DATA.ES_HEAP_SIZE }} + {% endif %} + {% if 'LSHOSTNAME' in DATA %} LSHOSTNAME: {{ DATA.LSHOSTNAME }} + {% endif %} + {% if 'LSHEAP' in DATA %} LS_HEAP_SIZE: {{ DATA.LSHEAP }} - CPUCORES: {{ DATA.CPUCORES }} - IDH_MGTRESTRICT: {{ DATA.IDH_MGTRESTRICT }} - IDH_SERVICES: {{ DATA.IDH_SERVICES }} - CPU: {{ DATA.CPU }} - MEMORY: {{ DATA.MEMORY }} - DISKS: {{ DATA.DISKS }} - COPPER: {{ DATA.COPPER }} - SFP: {{ DATA.SFP }} + {% endif %} From 8047e196fe8236afdef4bb245b248d5ea8edd61b Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Fri, 28 Feb 2025 17:21:06 -0500 Subject: [PATCH 149/315] fix pipeline workers, zeek/suricata lbprocs, CPUCORES and CORECOUNT --- salt/manager/tools/sbin/so-minion | 10 ++++++++-- salt/reactor/sominion_setup.sls | 5 ++--- salt/setup/virt/fleet.yaml | 18 ------------------ salt/setup/virt/heavynode.yaml | 18 ------------------ salt/setup/virt/idh.yaml | 18 ------------------ salt/setup/virt/receiver.yaml | 18 ------------------ salt/setup/virt/searchnode.yaml | 18 ------------------ salt/setup/virt/sensor.yaml | 18 ------------------ salt/setup/virt/soinstall.map.jinja | 5 +---- salt/setup/virt/sominion.sls | 5 ++++- 10 files changed, 15 insertions(+), 118 deletions(-) delete mode 100644 salt/setup/virt/fleet.yaml delete mode 100644 salt/setup/virt/heavynode.yaml delete mode 100644 salt/setup/virt/idh.yaml delete mode 100644 salt/setup/virt/receiver.yaml delete mode 100644 salt/setup/virt/searchnode.yaml delete mode 100644 salt/setup/virt/sensor.yaml diff --git a/salt/manager/tools/sbin/so-minion b/salt/manager/tools/sbin/so-minion index cc78e69e1..6de864e4b 100755 --- a/salt/manager/tools/sbin/so-minion +++ b/salt/manager/tools/sbin/so-minion @@ -95,10 +95,16 @@ for i in "$@"; do MAINIP="${i#*=}" shift ;; - -c=*|--cpu=*) + # Usable / Load Balance Cores for Zeek / Suricata + -C=*|--lbc=*) CORECOUNT="${i#*=}" shift ;; + # Total number of CPU Cores + -c=*|--cpu=*) + CPUCORES="${i#*=}" + shift + ;; -*|--*) echo "Unknown option $i" log "ERROR" "Unknown option $i" @@ -374,7 +380,7 @@ function add_logstash_to_minion() { "logstash:"\ " enabled: True"\ " config:"\ - " pipeline_x_workers: $CORECOUNT"\ + " pipeline_x_workers: $CPUCORES"\ " settings:"\ " lsheap: $LSHEAP"\ " " >> $PILLARFILE diff --git a/salt/reactor/sominion_setup.sls b/salt/reactor/sominion_setup.sls index 91889158b..547b1b686 100644 --- a/salt/reactor/sominion_setup.sls +++ b/salt/reactor/sominion_setup.sls @@ -16,13 +16,12 @@ def run(): hv_name = DATA['HYPERVISOR_HOST'] logging.debug('sominion_setup_reactor: DATA: %s' % DATA) - # Build the base command - cmd = "NODETYPE=" + DATA['NODETYPE'] + " /usr/sbin/so-minion -o=addVM -m=" + minionid + " -n=" + DATA['MNIC'] + " -i=" + DATA['MAINIP'] + " -d='" + DATA['NODE_DESCRIPTION'] + "'" + cmd = "NODETYPE=" + DATA['NODETYPE'] + " /usr/sbin/so-minion -o=addVM -m=" + minionid + " -n=" + DATA['MNIC'] + " -i=" + DATA['MAINIP'] + " -c=" + str(DATA['CPUCORES']) + " -d='" + DATA['NODE_DESCRIPTION'] + "'" # Add optional arguments only if they exist in DATA if 'CORECOUNT' in DATA: - cmd += " -c=" + str(DATA['CORECOUNT']) + cmd += " -C=" + str(DATA['CORECOUNT']) if 'INTERFACE' in DATA: cmd += " -a=" + DATA['INTERFACE'] diff --git a/salt/setup/virt/fleet.yaml b/salt/setup/virt/fleet.yaml deleted file mode 100644 index d6c90e11d..000000000 --- a/salt/setup/virt/fleet.yaml +++ /dev/null @@ -1,18 +0,0 @@ -MAINIP: -MNIC: enp1s0 -NODE_DESCRIPTION: 'vm' -ES_HEAP_SIZE: -PATCHSCHEDULENAME: -INTERFACE: -NODETYPE: FLEET -CORECOUNT: 8 -LSHOSTNAME: -LSHEAP: -CPUCORES: 8 -IDH_MGTRESTRICT: -IDH_SERVICES: -CPU: 8 -MEMORY: 8 -DISKS: 0 -COPPER: 0 -SFP: 0 diff --git a/salt/setup/virt/heavynode.yaml b/salt/setup/virt/heavynode.yaml deleted file mode 100644 index a3550021f..000000000 --- a/salt/setup/virt/heavynode.yaml +++ /dev/null @@ -1,18 +0,0 @@ -MAINIP: -MNIC: enp1s0 -NODE_DESCRIPTION: 'vm' -ES_HEAP_SIZE: -PATCHSCHEDULENAME: -INTERFACE: bond0 -NODETYPE: HEAVYNODE -CORECOUNT: 8 -LSHOSTNAME: -LSHEAP: -CPUCORES: 8 -IDH_MGTRESTRICT: -IDH_SERVICES: -CPU: 8 -MEMORY: 16 -DISKS: 0 -COPPER: 0 -SFP: 0 diff --git a/salt/setup/virt/idh.yaml b/salt/setup/virt/idh.yaml deleted file mode 100644 index 201262db8..000000000 --- a/salt/setup/virt/idh.yaml +++ /dev/null @@ -1,18 +0,0 @@ -MAINIP: -MNIC: enp1s0 -NODE_DESCRIPTION: 'vm' -ES_HEAP_SIZE: -PATCHSCHEDULENAME: -INTERFACE: -NODETYPE: IDH -CORECOUNT: 2 -LSHOSTNAME: -LSHEAP: -CPUCORES: 2 -IDH_MGTRESTRICT: -IDH_SERVICES: -CPU: 2 -MEMORY: 1 -DISKS: 0 -COPPER: 0 -SFP: 0 diff --git a/salt/setup/virt/receiver.yaml b/salt/setup/virt/receiver.yaml deleted file mode 100644 index e5dc0b0e7..000000000 --- a/salt/setup/virt/receiver.yaml +++ /dev/null @@ -1,18 +0,0 @@ -MAINIP: -MNIC: enp1s0 -NODE_DESCRIPTION: 'vm' -ES_HEAP_SIZE: -PATCHSCHEDULENAME: -INTERFACE: -NODETYPE: RECEIVER -CORECOUNT: 2 -LSHOSTNAME: -LSHEAP: -CPUCORES: 2 -IDH_MGTRESTRICT: -IDH_SERVICES: -CPU: 2 -MEMORY: 8 -DISKS: 0 -COPPER: 0 -SFP: 0 diff --git a/salt/setup/virt/searchnode.yaml b/salt/setup/virt/searchnode.yaml deleted file mode 100644 index 032e0e855..000000000 --- a/salt/setup/virt/searchnode.yaml +++ /dev/null @@ -1,18 +0,0 @@ -MAINIP: -MNIC: enp1s0 -NODE_DESCRIPTION: 'vm' -ES_HEAP_SIZE: -PATCHSCHEDULENAME: -INTERFACE: -NODETYPE: SEARCHNODE -CORECOUNT: 8 -LSHOSTNAME: -LSHEAP: -CPUCORES: 8 -IDH_MGTRESTRICT: -IDH_SERVICES: -CPU: 8 -MEMORY: 16 -DISKS: 1 -COPPER: 0 -SFP: 0 diff --git a/salt/setup/virt/sensor.yaml b/salt/setup/virt/sensor.yaml deleted file mode 100644 index 9136f0b78..000000000 --- a/salt/setup/virt/sensor.yaml +++ /dev/null @@ -1,18 +0,0 @@ -MAINIP: -MNIC: enp1s0 -NODE_DESCRIPTION: 'vm' -ES_HEAP_SIZE: -PATCHSCHEDULENAME: -INTERFACE: bond0 -NODETYPE: SENSOR -CORECOUNT: 4 -LSHOSTNAME: -LSHEAP: -CPUCORES: 4 -IDH_MGTRESTRICT: -IDH_SERVICES: -CPU: 8 -MEMORY: 12 -DISKS: 0 -COPPER: 0 -SFP: 0 diff --git a/salt/setup/virt/soinstall.map.jinja b/salt/setup/virt/soinstall.map.jinja index 1d70ac67e..d839235b0 100644 --- a/salt/setup/virt/soinstall.map.jinja +++ b/salt/setup/virt/soinstall.map.jinja @@ -40,12 +40,9 @@ {# Calculate reasonable core usage #} {% set cores_for_zeek = (DATA.CPUCORES / 2) - 1 %} -{% do salt.log.info('cores_for_zeek calculation using CPUCORES: ' ~ DATA.CPUCORES|string) %} -{% do salt.log.info('cores_for_zeek: ' ~ cores_for_zeek|string) %} {% set lb_procs_round = cores_for_zeek|round|int %} -{% do salt.log.info('lb_procs_round: ' ~ lb_procs_round|string) %} {% set lb_procs = 1 if lb_procs_round < 1 else lb_procs_round %} -{% do salt.log.info('lb_procs: ' ~ lb_procs|string) %} +{% do salt.log.info('Cores for load balancing: ' ~ lb_procs|string) %} {# Check memory conditions #} {% set low_mem = false %} {% do salt.log.info('Memory check using total_mem: ' ~ total_mem|string) %} diff --git a/salt/setup/virt/sominion.sls b/salt/setup/virt/sominion.sls index e0598a4d3..70acb52db 100644 --- a/salt/setup/virt/sominion.sls +++ b/salt/setup/virt/sominion.sls @@ -13,11 +13,14 @@ create_pillar: MAINIP: {{ DATA.MAINIP }} MNIC: {{ DATA.MNIC }} NODE_DESCRIPTION: '{{ DATA.NODE_DESCRIPTION }}' - INTERFACE: {{ DATA.INTERFACE }} NODETYPE: {{ DATA.NODETYPE }} + CPUCORES: {{ DATA.CPUCORES }} {% if 'CORECOUNT' in DATA %} CORECOUNT: {{ DATA.CORECOUNT }} {% endif %} + {% if 'INTERFACE' in DATA %} + INTERFACE: {{ DATA.INTERFACE }} + {% endif %} {% if 'ES_HEAP_SIZE' in DATA %} ES_HEAP_SIZE: {{ DATA.ES_HEAP_SIZE }} {% endif %} From 2c5861a0c2af8ac2bfecafc722ed83cf1340aaae Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Wed, 5 Mar 2025 08:51:10 -0500 Subject: [PATCH 150/315] ensure local hypervisor dir when new hypervisor key accepted. apply soc.dyanno.hypervisor when hypervisor key accepted --- salt/_runners/setup_hypervisor.py | 172 +++++++++++++++++- salt/hypervisor/map.jinja | 4 +- salt/orch/dyanno_hypervisor.sls | 10 + salt/soc/dyanno/hypervisor/init.sls | 1 + .../hypervisor/soc_hypervisor.yaml.jinja | 6 +- 5 files changed, 187 insertions(+), 6 deletions(-) diff --git a/salt/_runners/setup_hypervisor.py b/salt/_runners/setup_hypervisor.py index c06439eab..782419d27 100644 --- a/salt/_runners/setup_hypervisor.py +++ b/salt/_runners/setup_hypervisor.py @@ -163,6 +163,7 @@ def _validate_image_checksum(path, expected_sha256): IMAGE_URL = "https://yum.oracle.com/templates/OracleLinux/OL9/u5/x86_64/OL9U5_x86_64-kvm-b253.qcow2" IMAGE_SHA256 = "3b00bbbefc8e78dd28d9f538834fb9e2a03d5ccdc2cadf2ffd0036c0a8f02021" IMAGE_PATH = "/nsm/libvirt/boot/OL9U5_x86_64-kvm-b253.qcow2" +MANAGER_HOSTNAME = socket.gethostname() def _download_image(): """ @@ -332,6 +333,135 @@ def _check_vm_exists(vm_name: str) -> bool: log.info("MAIN: VM %s already exists", vm_name) return exists +def _ensure_hypervisor_host_dir(minion_id: str = None): + """ + Ensure the hypervisor host directory exists. + + This function creates the directory structure for a hypervisor host if it doesn't exist. + The path is: /opt/so/saltstack/local/salt/hypervisor/hosts/ + + Args: + minion_id (str, optional): Salt minion ID of the hypervisor. + + Returns: + bool: True if directory exists or was created successfully, False otherwise + """ + if not minion_id: + log.warning("HOSTDIR: No minion_id provided, skipping host directory creation") + return True + + try: + # Extract hostname from minion_id by removing role suffix (anything after first underscore) + hostname = minion_id.split('_', 1)[0] if '_' in minion_id else minion_id + + # Define the directory path + host_dir = f'/opt/so/saltstack/local/salt/hypervisor/hosts/{hostname}' + + # Check if directory exists and create it if it doesn't + if os.path.exists(host_dir): + log.info(f"HOSTDIR: Hypervisor host directory already exists: {host_dir}") + # Create the VMs file if it doesn't exist + vms_file = f'/opt/so/saltstack/local/salt/hypervisor/hosts/{hostname}VMs' + if not os.path.exists(vms_file): + with salt.utils.files.fopen(vms_file, 'w') as f: + f.write('[]') + log.info(f"HOSTDIR: Created empty VMs file: {vms_file}") + + # Set proper ownership for the VMs file + try: + socore_uid = pwd.getpwnam('socore').pw_uid + socore_gid = pwd.getpwnam('socore').pw_gid + os.chown(vms_file, socore_uid, socore_gid) + log.info(f"HOSTDIR: Set ownership to socore:socore for {vms_file}") + except (KeyError, Exception) as e: + log.warning(f"HOSTDIR: Failed to set ownership for VMs file: {str(e)}") + return True + + # Create all necessary parent directories + os.makedirs(host_dir, exist_ok=True) + log.info(f"HOSTDIR: Created hypervisor host directory: {host_dir}") + + # Create the VMs file with an empty JSON array + vms_file = f'/opt/so/saltstack/local/salt/hypervisor/hosts/{hostname}VMs' + with salt.utils.files.fopen(vms_file, 'w') as f: + f.write('[]') + log.info(f"HOSTDIR: Created empty VMs file: {vms_file}") + + # Set proper ownership (socore:socore) + try: + socore_uid = pwd.getpwnam('socore').pw_uid + socore_gid = pwd.getpwnam('socore').pw_gid + os.chown(host_dir, socore_uid, socore_gid) + os.chown(vms_file, socore_uid, socore_gid) + + # Also set ownership for parent directories if they were just created + parent_dir = os.path.dirname(host_dir) # /opt/so/saltstack/local/salt/hypervisor/hosts + if os.path.exists(parent_dir): + os.chown(parent_dir, socore_uid, socore_gid) + + parent_dir = os.path.dirname(parent_dir) # /opt/so/saltstack/local/salt/hypervisor + if os.path.exists(parent_dir): + os.chown(parent_dir, socore_uid, socore_gid) + + log.info(f"HOSTDIR: Set ownership to socore:socore for {host_dir} and {vms_file}") + except KeyError: + log.warning("HOSTDIR: socore user not found, skipping ownership change") + except Exception as e: + log.warning(f"HOSTDIR: Failed to set ownership: {str(e)}") + + return True + except Exception as e: + log.error(f"HOSTDIR: Error creating hypervisor host directory: {str(e)}") + return False + +def _apply_dyanno_hypervisor_state(): + """ + Apply the soc.dyanno.hypervisor state on the salt master. + + This function applies the soc.dyanno.hypervisor state on the salt master + to update the hypervisor annotation and ensure all hypervisor host directories exist. + + Returns: + bool: True if state was applied successfully, False otherwise + """ + try: + log.info("DYANNO: Applying soc.dyanno.hypervisor state on salt master") + + # Initialize the LocalClient + local = salt.client.LocalClient() + + # Target the salt master (localhost) to apply the soc.dyanno.hypervisor state + target = MANAGER_HOSTNAME + '_*' + state_result = local.cmd(target, 'state.apply', ['soc.dyanno.hypervisor'], tgt_type='glob', concurrent=True) + log.debug(f"DYANNO: state_result: {state_result}") + # Check if state was applied successfully + if state_result: + success = True + for minion, states in state_result.items(): + if not isinstance(states, dict): + log.error(f"DYANNO: Unexpected result format from {minion}: {states}") + success = False + continue + + for state_id, state_data in states.items(): + if not state_data.get('result', False): + log.error(f"DYANNO: State {state_id} failed on {minion}: {state_data.get('comment', 'No comment')}") + success = False + + if success: + log.info("DYANNO: Successfully applied soc.dyanno.hypervisor state") + return True + else: + log.error("DYANNO: Failed to apply soc.dyanno.hypervisor state") + return False + else: + log.error("DYANNO: No response from salt master when applying soc.dyanno.hypervisor state") + return False + + except Exception as e: + log.error(f"DYANNO: Error applying soc.dyanno.hypervisor state: {str(e)}") + return False + def setup_environment(vm_name: str = 'sool9', disk_size: str = '220G', minion_id: str = None): """ Main entry point to set up the hypervisor environment. @@ -380,6 +510,43 @@ def setup_environment(vm_name: str = 'sool9', disk_size: str = '220G', minion_id 'vm_result': None } + # Ensure hypervisor host directory exists + if not _ensure_hypervisor_host_dir(minion_id): + return { + 'success': False, + 'error': 'Failed to create hypervisor host directory', + 'vm_result': None + } + + # Initialize the LocalClient + local = salt.client.LocalClient() + + # Add retry logic for mine.update + max_retries = 10 + retry_delay = 3 + mine_update_success = False + + for attempt in range(1, max_retries + 1): + mine_update_result = local.cmd(minion_id, 'mine.update') + log.debug(f"DYANNO: mine_update_result: {mine_update_result}") + + # Check if mine.update was successful + if mine_update_result and all(mine_update_result.values()): + log.info(f"DYANNO: mine.update successful on attempt {attempt}") + mine_update_success = True + break + else: + log.warning(f"DYANNO: mine.update failed on attempt {attempt}/{max_retries}, retrying in {retry_delay} seconds...") + time.sleep(retry_delay) + + if not mine_update_success: + log.error(f"DYANNO: mine.update failed after {max_retries} attempts") + + # Apply the soc.dyanno.hypervisor state on the salt master + if not _apply_dyanno_hypervisor_state(): + log.warning("MAIN: Failed to apply soc.dyanno.hypervisor state, continuing with setup") + # We don't return an error here as we want to continue with the setup process + log.info("MAIN: Starting setup_environment in setup_hypervisor runner") # Check if environment is already set up @@ -548,9 +715,6 @@ def create_vm(vm_name: str, disk_size: str = '220G'): log.error("CREATEVM: Failed to read SSH public key: %s", str(e)) return {'success': False, 'error': 'Failed to read SSH public key'} - # Get hostname for repo configuration - manager_hostname = socket.gethostname() - # Read and encode GPG keys keys_dir = '/opt/so/saltstack/default/salt/repo/client/files/oracle/keys' oracle_key = _read_and_encode_key(os.path.join(keys_dir, 'RPM-GPG-KEY-oracle')) @@ -607,7 +771,7 @@ write_files: content: | [securityonion] name=Security Onion Repo - baseurl=https://{manager_hostname}/repo + baseurl=https://{MANAGER_HOSTNAME}/repo enabled=1 gpgcheck=1 sslverify=0 diff --git a/salt/hypervisor/map.jinja b/salt/hypervisor/map.jinja index 3d08b15d5..d19aacf48 100644 --- a/salt/hypervisor/map.jinja +++ b/salt/hypervisor/map.jinja @@ -39,7 +39,9 @@ {% set vm_list = [] %} {% set vm_list_file = 'hypervisor/hosts/' ~ hypervisor ~ 'VMs' %} {% do salt.log.info('salt/hypervisor/map.jinja: VM list file: ' ~ vm_list_file) %} - {% import_json vm_list_file as vm_list %} + {% if salt['file.file_exists']('/opt/so/saltstack/local/salt/' ~ vm_list_file) %} + {% import_json vm_list_file as vm_list %} + {% endif %} {% if vm_list %} {% do salt.log.info('salt/hypervisor/map.jinja: VM list content: ' ~ vm_list | tojson) %} {% else %} diff --git a/salt/orch/dyanno_hypervisor.sls b/salt/orch/dyanno_hypervisor.sls index c298a6101..c9ba20115 100644 --- a/salt/orch/dyanno_hypervisor.sls +++ b/salt/orch/dyanno_hypervisor.sls @@ -95,6 +95,16 @@ write_vm_status: status: {{ status }} event_tag: {{ tag }} +{# Check if the base domain exists / is ready for VMs #} +{#% set file_exists = False %} +{% set ret = salt.saltutil.runner('salt.execute', [hypervisor ~ '_*','file.file_exists', ['/nsm/libvirt/images/sool9/sool9.qcow2'], 'glob']) %} +{% do salt.log.debug('dyanno_hypervisor_orch: File /nsm/libvirt/images/sool9/sool9.qcow2 exists: ' ~ ret) %} +{% for minion, file_exists in ret.items() %} +{% if minion.startswith(hypervisor ~ '_') %} +{% do salt.log.info('dyanno_hypervisor_orch: File /nsm/libvirt/images/sool9/sool9.qcow2 exists: ' ~ file_exists) %} +{% endif %} +{% endfor %#} + # Update hypervisor status update_hypervisor_annotation: salt.state: diff --git a/salt/soc/dyanno/hypervisor/init.sls b/salt/soc/dyanno/hypervisor/init.sls index f29ef0367..5d3e3ae45 100644 --- a/salt/soc/dyanno/hypervisor/init.sls +++ b/salt/soc/dyanno/hypervisor/init.sls @@ -22,6 +22,7 @@ hypervisor_annotation: - group: socore - defaults: HYPERVISORS: {{ HYPERVISORS }} + base_domain_ready: {{ salt['pillar.get']('base_domain_ready', False) }} {% for role in HYPERVISORS %} {% for hypervisor in HYPERVISORS[role].keys() %} diff --git a/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja b/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja index c3eeee689..f90e3b579 100644 --- a/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja +++ b/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja @@ -174,7 +174,11 @@ No Virtual Machines Found {%- endif -%} {%- do updated_elements.append(updated_field) -%} {%- endfor -%} -{%- do updated_template.update({'uiElements': updated_elements}) -%} +{%- if base_domain_ready -%} +{%- do updated_template.update({'uiElements': updated_elements}) -%} +{%- else -%} +{%- do updated_template.pop('uiElements') -%} +{%- endif -%} {%- do updated_template.update({ 'title': hypervisor, 'description': update_description( From f30938ed59f4f9bdaf2e8d425a1f309260a2efee Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Thu, 6 Mar 2025 15:26:08 -0500 Subject: [PATCH 151/315] hypervisor annotation show if base domain is initialized or not --- salt/_runners/setup_hypervisor.py | 4 +-- salt/libvirt/images/init.sls | 11 ++++++ salt/orch/dyanno_hypervisor.sls | 34 ++++++++++++------ salt/salt/minion.sls | 5 --- salt/soc/dyanno/hypervisor/init.sls | 2 +- .../hypervisor/soc_hypervisor.yaml.example | 36 ------------------- .../hypervisor/soc_hypervisor.yaml.jinja | 26 ++++++++------ 7 files changed, 53 insertions(+), 65 deletions(-) delete mode 100644 salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.example diff --git a/salt/_runners/setup_hypervisor.py b/salt/_runners/setup_hypervisor.py index 782419d27..6b3f289e8 100644 --- a/salt/_runners/setup_hypervisor.py +++ b/salt/_runners/setup_hypervisor.py @@ -430,9 +430,9 @@ def _apply_dyanno_hypervisor_state(): # Initialize the LocalClient local = salt.client.LocalClient() - # Target the salt master (localhost) to apply the soc.dyanno.hypervisor state + # Target the salt master to apply the soc.dyanno.hypervisor state target = MANAGER_HOSTNAME + '_*' - state_result = local.cmd(target, 'state.apply', ['soc.dyanno.hypervisor'], tgt_type='glob', concurrent=True) + state_result = local.cmd(target, 'state.apply', ['soc.dyanno.hypervisor', "pillar={'baseDomain': {'status': 'PreInit'}}", 'concurrent=True'], tgt_type='glob') log.debug(f"DYANNO: state_result: {state_result}") # Check if state was applied successfully if state_result: diff --git a/salt/libvirt/images/init.sls b/salt/libvirt/images/init.sls index 70e668ffb..91350de42 100644 --- a/salt/libvirt/images/init.sls +++ b/salt/libvirt/images/init.sls @@ -157,6 +157,17 @@ configure_network_predictable_sool9: - onchanges: - cmd: create_vm_sool9 +# Fire event here that causes soc.dyanno.hypervisor state to be applied +base_domain_ready: + event.send: + - name: soc/dyanno/hypervisor/baseDomain + - data: + status: 'Initialized' + - require: + - cmd: configure_network_predictable_sool9 + - onchanges: + - cmd: create_vm_sool9 + {% else %} {{sls}}_no_license_detected: test.fail_without_changes: diff --git a/salt/orch/dyanno_hypervisor.sls b/salt/orch/dyanno_hypervisor.sls index c9ba20115..fa6a2f2ff 100644 --- a/salt/orch/dyanno_hypervisor.sls +++ b/salt/orch/dyanno_hypervisor.sls @@ -11,6 +11,16 @@ {% if 'hvn' in salt['pillar.get']('features', []) %} +{% do salt.log.info('dyanno_hypervisor_orch: Running') %} +{% set vm_name = None %} +{% set hypervisor = None %} +{% set status = None %} +{% set data = pillar.get('data', {}) %} +{% set tag = pillar.get('tag', '') %} +{% set timestamp = data.get('_stamp') %} +{% do salt.log.debug('dyanno_hypervisor_orch: tag: ' ~ tag) %} +{% do salt.log.debug('dyanno_hypervisor_orch: Received data: ' ~ data|json|string) %} + {# Macro to find hypervisor name from VM status file #} {% macro find_hypervisor_from_status(vm_name) -%} {%- set path = salt['file.find']('/opt/so/saltstack/local/salt/hypervisor/hosts/',type='f', name=vm_name ~ '.status') -%} @@ -28,22 +38,17 @@ {%- endif -%} {%- endmacro %} -{% do salt.log.info('dyanno_hypervisor_orch: Running') %} - -{% set data = pillar.get('data', {}) %} -{% set tag = pillar.get('tag', '') %} -{% set timestamp = data.get('_stamp') %} -{% do salt.log.debug('dyanno_hypervisor_orch: tag: ' ~ tag) %} -{% do salt.log.debug('dyanno_hypervisor_orch: Received data: ' ~ data|json|string) %} - {# Our custom tag #} {% if tag.startswith('soc/dyanno/hypervisor') %} {% set status_data = data.get('data')%} {% do salt.log.debug('dyanno_hypervisor_orch: Received data: ' ~ status_data|json|string) %} -{% do salt.log.debug('dyanno_hypervisor_orch: Setting vm_name, hypervisor and status') %} -{% set vm_name = status_data.get('vm_name') %} -{% set hypervisor = status_data.get('hypervisor') %} +{% if not tag.endswith('/baseDomain') %} +{% do salt.log.debug('dyanno_hypervisor_orch: Setting vm_name, hypervisor and status') %} +{% set vm_name = status_data.get('vm_name') %} +{% set hypervisor = status_data.get('hypervisor') %} +{% endif %} {% set status = status_data.get('status') %} +{% set hypervisor = data.get('id') %} {% endif %} {# setup/so-minion tag #} @@ -80,6 +85,7 @@ {% do salt.log.info('dyanno_hypervisor_orch: vm_name: ' ~ vm_name ~ ' hypervisor: ' ~ hypervisor ~ ' status: ' ~ status) %} +{% if vm_name and hypervisor and timestamp and status and tag %} write_vm_status: salt.state: - tgt: 'G@role:so-manager or G@role:so-managersearch or G@role:so-standalone or G@role:so-eval' @@ -94,6 +100,7 @@ write_vm_status: timestamp: {{ timestamp }} status: {{ status }} event_tag: {{ tag }} +{% endif %} {# Check if the base domain exists / is ready for VMs #} {#% set file_exists = False %} @@ -113,6 +120,11 @@ update_hypervisor_annotation: - sls: - soc.dyanno.hypervisor - concurrent: True +{% if tag == ('soc/dyanno/hypervisor/baseDomain') %} + - pillar: + baseDomain: + status: {{ status }} +{% endif %} {% do salt.log.info('dyanno_hypervisor_orch: Completed') %} diff --git a/salt/salt/minion.sls b/salt/salt/minion.sls index de0f35c50..1402bea5e 100644 --- a/salt/salt/minion.sls +++ b/salt/salt/minion.sls @@ -83,11 +83,6 @@ enable_startup_states: - regex: '^startup_states: highstate$' - unless: pgrep so-setup -# manager with hypervisors with need this beacon added to the minion config -#beacons: -# add_virtual_node_beacon: -# - base_path: /opt/so/saltstack/local/salt/hypervisor/hosts/*/add_* - # prior to 2.4.30 this managed file would restart the salt-minion service when updated # since this file is currently only adding a sleep timer on service start # it is not required to restart the service diff --git a/salt/soc/dyanno/hypervisor/init.sls b/salt/soc/dyanno/hypervisor/init.sls index 5d3e3ae45..e4ce3b47c 100644 --- a/salt/soc/dyanno/hypervisor/init.sls +++ b/salt/soc/dyanno/hypervisor/init.sls @@ -22,7 +22,7 @@ hypervisor_annotation: - group: socore - defaults: HYPERVISORS: {{ HYPERVISORS }} - base_domain_ready: {{ salt['pillar.get']('base_domain_ready', False) }} + baseDomainStatus: {{ salt['pillar.get']('baseDomain:status', 'Initialized') }} {% for role in HYPERVISORS %} {% for hypervisor in HYPERVISORS[role].keys() %} diff --git a/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.example b/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.example deleted file mode 100644 index 902d9b1b1..000000000 --- a/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.example +++ /dev/null @@ -1,36 +0,0 @@ -# This is the start of an example of what this file will look like. It will be generated by Salt, so this yaml file is not used by Salt. -hypervisor: - hosts: - jpphype1VMs: - description: Hypervisor Configuration - file: true - global: true - syntax: json - title: jpphype1 - uiElements: - - field: hostname - label: Enter the hostname - - field: role - label: sensor or searchnode - - field: network_mode - label: Choose static4 or dhcp4. If static4, populate IP details below. - - field: ip4 - label: IP Address with netmask. ex. 192.168.1.10/24 - - field: gw4 - label: Gateway - - field: dns4 - label: DNS. Comma separated list. ex. 192.168.1.1,8.8.8.8 - - field: search4 - label: Search domain - - field: cpu - label: 'CPU cores to assign. Free: 120 | Total: 128' - - field: memory - label: 'Memory to assign, in GB. Free: 112 | Total: 128' - - field: disk - label: 'Disk(s) for passthrough. Comma separated list. Free: 2 | Total: 1,2' - - field: copper - label: 'Copper port(s) for passthrough. Comma separated list. Free: 3,4 | - Total: 1,2,3,4' - - field: sfp - label: 'SFP port(s) for passthrough. Comma separated list. Free: 5,6,7,8 | - Total: 5,6,7,8' diff --git a/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja b/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja index f90e3b579..17603ab9d 100644 --- a/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja +++ b/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja @@ -24,26 +24,32 @@ | Available | {{ cpu_free }} | {{ mem_free }} | {{ disk_free | replace('\n', ',') if disk_free else 'None' }} | {{ copper_free | replace('\n', ',') if copper_free else 'None' }} | {{ sfp_free | replace('\n', ',') if sfp_free else 'None' }} | | Total | {{ cpu_total }} | {{ mem_total }} | {{ disk_total | replace('\n', ',') }} | {{ copper_total | replace('\n', ',') }} | {{ sfp_total | replace('\n', ',') }} | -{%- if vm_list %} +{%- if baseDomainStatus == 'Initialized' %} +{%- if vm_list %} #### Virtual Machines Status values: {% for step in PROCESS_STEPS %}{{ step }}{% if not loop.last %}, {% endif %}{% endfor %}. "Last Updated" shows when status changed. After "Highstate Triggered", only "Destroyed Instance" updates the timestamp. | Name | Status | CPU Cores | Memory (GB)| Disk | Copper | SFP | Last Updated | |--------------------|--------------------|-----------|------------|------|--------|------|---------------------| -{%- for hostname, vm_data in vm_list.items() %} -{%- set vm_status = vm_data.get('status', {}).get('status', 'Unknown') %} -{%- set is_destroyed = vm_status == 'Destroyed Instance' %} -{%- if is_destroyed %} +{%- for hostname, vm_data in vm_list.items() %} +{%- set vm_status = vm_data.get('status', {}).get('status', 'Unknown') %} +{%- set is_destroyed = vm_status == 'Destroyed Instance' %} +{%- if is_destroyed %} | {{ hostname }} | {{ vm_status }} | - | - | - | - | - | {{ vm_data.get('status', {}).get('timestamp', 'Never') | replace('T', ' ') | regex_replace('\\.[0-9]+', '') }} | -{%- else %} +{%- else %} | {{ hostname }} | {{ vm_status }} | {{ vm_data.get('config', {}).get('cpu', 'N/A') }} | {{ vm_data.get('config', {}).get('memory', 'N/A') }} | {{ vm_data.get('config', {}).get('disk', []) | join(',') if vm_data.get('config', {}).get('disk') else '-' }} | {{ vm_data.get('config', {}).get('copper', []) | join(',') if vm_data.get('config', {}).get('copper') else '-' }} | {{ vm_data.get('config', {}).get('sfp', []) | join(',') if vm_data.get('config', {}).get('sfp') else '-' }} | {{ vm_data.get('status', {}).get('timestamp', 'Never') | replace('T', ' ') | regex_replace('\\.[0-9]+', '') }} | -{%- endif %} -{%- endfor %} -{%- else %} +{%- endif %} +{%- endfor %} +{%- else %} #### Virtual Machines Status values: {% for step in PROCESS_STEPS %}{{ step }}{% if not loop.last %}, {% endif %}{% endfor %}. "Last Updated" shows when status changed. After "Highstate Triggered", only "Destroyed Instance" updates the timestamp. No Virtual Machines Found +{%- endif %} +{%- else %} +#### WARNING + +Base domain has not been initialized. {%- endif %} {%- endmacro -%} @@ -174,7 +180,7 @@ No Virtual Machines Found {%- endif -%} {%- do updated_elements.append(updated_field) -%} {%- endfor -%} -{%- if base_domain_ready -%} +{%- if baseDomainStatus == 'Initialized' %} {%- do updated_template.update({'uiElements': updated_elements}) -%} {%- else -%} {%- do updated_template.pop('uiElements') -%} From c66cd3b2f3c25880b8c440c14fa50c20ff7dec64 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Mon, 10 Mar 2025 11:23:26 -0400 Subject: [PATCH 152/315] ensure image is readded if removed --- salt/libvirt/images/init.sls | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/salt/libvirt/images/init.sls b/salt/libvirt/images/init.sls index 91350de42..94cf4959d 100644 --- a/salt/libvirt/images/init.sls +++ b/salt/libvirt/images/init.sls @@ -16,6 +16,12 @@ include: - libvirt.packages +# Remove hash file if image isn't present. This will allow for the image to redownload and initialize. +remove_sha256_sool9: + file.absent: + - name: /nsm/libvirt/images/sool9/sool9.sha256 + - unless: test -f /nsm/libvirt/images/sool9/sool9.qcow2 + # Manage SHA256 hash file manage_sha256_sool9: file.managed: From c784a6e4409883791224aac836e8de0db5e7b414 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Mon, 10 Mar 2025 16:55:02 -0400 Subject: [PATCH 153/315] fix setting hypervisor for our custom event tag --- salt/orch/dyanno_hypervisor.sls | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/salt/orch/dyanno_hypervisor.sls b/salt/orch/dyanno_hypervisor.sls index fa6a2f2ff..8af529a5f 100644 --- a/salt/orch/dyanno_hypervisor.sls +++ b/salt/orch/dyanno_hypervisor.sls @@ -46,9 +46,10 @@ {% do salt.log.debug('dyanno_hypervisor_orch: Setting vm_name, hypervisor and status') %} {% set vm_name = status_data.get('vm_name') %} {% set hypervisor = status_data.get('hypervisor') %} +{% else %} +{% set hypervisor = data.get('id') %} {% endif %} {% set status = status_data.get('status') %} -{% set hypervisor = data.get('id') %} {% endif %} {# setup/so-minion tag #} From ae993c47c15195adb01bc316cbbe48ad9f707e23 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Tue, 11 Mar 2025 11:12:45 -0400 Subject: [PATCH 154/315] remove minion pillar files when a vm is destroyed --- salt/orch/dyanno_hypervisor.sls | 10 ---------- salt/orch/vm_pillar_clean.sls | 35 +++++++++++++++++++++++++++++++++ salt/reactor/deleteKey.sls | 9 ++++++++- 3 files changed, 43 insertions(+), 11 deletions(-) create mode 100644 salt/orch/vm_pillar_clean.sls diff --git a/salt/orch/dyanno_hypervisor.sls b/salt/orch/dyanno_hypervisor.sls index 8af529a5f..624bb12f3 100644 --- a/salt/orch/dyanno_hypervisor.sls +++ b/salt/orch/dyanno_hypervisor.sls @@ -103,16 +103,6 @@ write_vm_status: event_tag: {{ tag }} {% endif %} -{# Check if the base domain exists / is ready for VMs #} -{#% set file_exists = False %} -{% set ret = salt.saltutil.runner('salt.execute', [hypervisor ~ '_*','file.file_exists', ['/nsm/libvirt/images/sool9/sool9.qcow2'], 'glob']) %} -{% do salt.log.debug('dyanno_hypervisor_orch: File /nsm/libvirt/images/sool9/sool9.qcow2 exists: ' ~ ret) %} -{% for minion, file_exists in ret.items() %} -{% if minion.startswith(hypervisor ~ '_') %} -{% do salt.log.info('dyanno_hypervisor_orch: File /nsm/libvirt/images/sool9/sool9.qcow2 exists: ' ~ file_exists) %} -{% endif %} -{% endfor %#} - # Update hypervisor status update_hypervisor_annotation: salt.state: diff --git a/salt/orch/vm_pillar_clean.sls b/salt/orch/vm_pillar_clean.sls new file mode 100644 index 000000000..5c0011f6f --- /dev/null +++ b/salt/orch/vm_pillar_clean.sls @@ -0,0 +1,35 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. +# +# Note: Per the Elastic License 2.0, the second limitation states: +# +# "You may not move, change, disable, or circumvent the license key functionality +# in the software, and you may not remove or obscure any functionality in the +# software that is protected by the license key." + +{% if 'hvn' in salt['pillar.get']('features', []) %} + +{% do salt.log.debug('vm_pillar_clean_orch: Running') %} +{% set vm_name = pillar.get('vm_name') %} + +delete_adv_{{ vm_name }}_pillar: + module.run: + - file.remove: + - path: /opt/so/saltstack/local/pillar/minions/adv_{{ vm_name }}.sls + +delete_{{ vm_name }}_pillar: + module.run: + - file.remove: + - path: /opt/so/saltstack/local/pillar/minions/{{ vm_name }}.sls + +{% else %} + +{% do salt.log.error( + 'Hypervisor nodes are a feature supported only for customers with a valid license.' + 'Contact Security Onion Solutions, LLC via our website at https://securityonionsolutions.com' + 'for more information about purchasing a license to enable this feature.' +) %} + +{% endif %} diff --git a/salt/reactor/deleteKey.sls b/salt/reactor/deleteKey.sls index 646e17948..4d522a4b5 100644 --- a/salt/reactor/deleteKey.sls +++ b/salt/reactor/deleteKey.sls @@ -1,5 +1,5 @@ # Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one -# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at # https://securityonion.net/license; you may not use this file except in compliance with the # Elastic License 2.0. @@ -8,4 +8,11 @@ remove_key: - args: - match: {{ data['name'] }} +{{ data['name'] }}_pillar_clean: + runner.state.orchestrate: + - args: + - mods: orch.vm_pillar_clean + - pillar: + vm_name: {{ data['name'] }} + {% do salt.log.info('deleteKey reactor: deleted minion key: %s' % data['name']) %} From 44a5b3b1e50c737663e20d90c7a78804e744e657 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Wed, 12 Mar 2025 21:05:04 -0400 Subject: [PATCH 155/315] MANAGERHYPE setup is now complete! --- pillar/top.sls | 2 +- salt/allowed_states.map.jinja | 423 +++++++++++----------------- salt/common/init.sls | 2 +- salt/elasticfleet/config.sls | 2 +- salt/elasticsearch/config.map.jinja | 2 +- salt/elasticsearch/defaults.yaml | 8 + salt/elasticsearch/enabled.sls | 2 +- salt/firewall/defaults.yaml | 210 ++++++++++++++ salt/logstash/defaults.yaml | 2 + salt/logstash/enabled.sls | 24 +- salt/manager/tools/sbin/so-minion | 17 ++ salt/nginx/enabled.sls | 4 +- salt/nginx/etc/nginx.conf | 4 +- salt/repo/client/oracle.sls | 2 +- salt/ssl/init.sls | 12 +- salt/telegraf/defaults.yaml | 9 + salt/top.sls | 8 +- salt/vars/globals.map.jinja | 1 + salt/vars/hypervisor.map.jinja | 8 +- salt/vars/managerhype.map.jinja | 8 + setup/so-functions | 10 +- setup/so-setup | 23 ++ setup/so-whiptail | 7 +- 23 files changed, 493 insertions(+), 297 deletions(-) create mode 100644 salt/vars/managerhype.map.jinja diff --git a/pillar/top.sls b/pillar/top.sls index bd78b5712..6a2311a64 100644 --- a/pillar/top.sls +++ b/pillar/top.sls @@ -27,7 +27,7 @@ base: - nginx.adv_nginx - node_data.ips - '*_manager or *_managersearch': + '*_manager or *_managersearch or *_managerhype': - match: compound {% if salt['file.file_exists']('/opt/so/saltstack/local/pillar/elasticsearch/auth.sls') %} - elasticsearch.auth diff --git a/salt/allowed_states.map.jinja b/salt/allowed_states.map.jinja index bfa7ebe50..af9bcaa5d 100644 --- a/salt/allowed_states.map.jinja +++ b/salt/allowed_states.map.jinja @@ -7,271 +7,174 @@ {% import_yaml 'salt/minion.defaults.yaml' as saltversion %} {% set saltversion = saltversion.salt.minion.version %} -{# this is the list we are returning from this map file, it gets built below #} -{% set allowed_states= [] %} +{# Define common state groups to reduce redundancy #} +{% set base_states = [ + 'common', + 'patch.os.schedule', + 'motd', + 'salt.minion-check', + 'sensoroni', + 'salt.lasthighstate', + 'salt.minion' +] %} + +{% set ssl_states = [ + 'ssl', + 'telegraf', + 'firewall', + 'schedule', + 'docker_clean' +] %} + +{% set manager_states = [ + 'salt.master', + 'ca', + 'registry', + 'manager', + 'nginx', + 'influxdb', + 'soc', + 'kratos', + 'hydra', + 'elasticfleet', + 'elastic-fleet-package-registry', + 'idstools', + 'suricata.manager', + 'utility' +] %} + +{% set sensor_states = [ + 'pcap', + 'suricata', + 'healthcheck', + 'tcpreplay' +] %} + +{% set kafka_states = [ + 'kafka' +] %} + +{% set stig_states = [ + 'stig' +] %} + +{% set elastic_stack_states = [ + 'elasticsearch', + 'elasticsearch.auth', + 'kibana', + 'kibana.secrets', + 'elastalert', + 'logstash', + 'redis' +] %} + +{# Initialize the allowed_states list #} +{% set allowed_states = [] %} {% if grains.saltversion | string == saltversion | string %} + {# Map role-specific states #} + {% set role_states = { + 'so-eval': ( + ssl_states + + manager_states + + sensor_states + + elastic_stack_states + ), + 'so-heavynode': ( + ssl_states + + sensor_states + + ['elasticagent', 'zeek', 'strelka'] + + ['elasticsearch', 'logstash', 'redis'] + + stig_states + ), + 'so-idh': ( + ssl_states + + ['idh'] + ), + 'so-import': ( + ssl_states + + manager_states + + sensor_states + + ['zeek'] + + ['elasticsearch', 'elasticsearch.auth', 'kibana', 'kibana.secrets'] + ), + 'so-manager': ( + ssl_states + + manager_states + + ['salt.cloud', 'libvirt.packages', 'libvirt.ssh.users', 'strelka.manager'] + + stig_states + + kafka_states + + elastic_stack_states + ), + 'so-managerhype': ( + ssl_states + + manager_states + + ['salt.cloud', 'strelka.manager', 'hypervisor', 'libvirt'] + + stig_states + + kafka_states + + elastic_stack_states + ), + 'so-managersearch': ( + ssl_states + + manager_states + + ['strelka.manager'] + + stig_states + + kafka_states + + elastic_stack_states + ), + 'so-searchnode': ( + ssl_states + + ['kafka.ca', 'kafka.ssl', 'elasticsearch', 'logstash'] + + stig_states + ), + 'so-standalone': ( + ssl_states + + manager_states + + sensor_states + + stig_states + + kafka_states + + elastic_stack_states + + ['zeek', 'strelka'] + ), + 'so-sensor': ( + ssl_states + + sensor_states + + ['nginx', 'zeek', 'strelka'] + + stig_states + ), + 'so-fleet': ( + ssl_states + + ['logstash', 'nginx', 'healthcheck', 'elasticfleet'] + ), + 'so-receiver': ( + ssl_states + + kafka_states + + stig_states + + ['logstash', 'redis'] + ), + 'so-hypervisor': ( + ssl_states + + stig_states + + ['hypervisor', 'libvirt'] + ), + 'so-desktop': ( + ['ssl', 'docker_clean', 'telegraf'] + + stig_states + ) + } %} - {% set allowed_states= salt['grains.filter_by']({ - 'so-eval': [ - 'salt.master', - 'ca', - 'ssl', - 'registry', - 'manager', - 'nginx', - 'telegraf', - 'influxdb', - 'soc', - 'kratos', - 'hydra', - 'elasticfleet', - 'elastic-fleet-package-registry', - 'firewall', - 'idstools', - 'suricata.manager', - 'healthcheck', - 'pcap', - 'suricata', - 'utility', - 'schedule', - 'tcpreplay', - 'docker_clean' - ], - 'so-heavynode': [ - 'ssl', - 'nginx', - 'telegraf', - 'firewall', - 'pcap', - 'suricata', - 'healthcheck', - 'elasticagent', - 'schedule', - 'tcpreplay', - 'docker_clean' - ], - 'so-idh': [ - 'ssl', - 'telegraf', - 'firewall', - 'idh', - 'schedule', - 'docker_clean' - ], - 'so-import': [ - 'salt.master', - 'ca', - 'ssl', - 'registry', - 'manager', - 'nginx', - 'strelka.manager', - 'soc', - 'kratos', - 'hydra', - 'influxdb', - 'telegraf', - 'firewall', - 'idstools', - 'suricata.manager', - 'pcap', - 'utility', - 'suricata', - 'zeek', - 'schedule', - 'tcpreplay', - 'docker_clean', - 'elasticfleet', - 'elastic-fleet-package-registry' - ], - 'so-manager': [ - 'salt.master', - 'salt.cloud', - 'libvirt.packages', - 'libvirt.ssh.users', - 'ca', - 'ssl', - 'registry', - 'manager', - 'nginx', - 'telegraf', - 'influxdb', - 'strelka.manager', - 'soc', - 'kratos', - 'hydra', - 'elasticfleet', - 'elastic-fleet-package-registry', - 'firewall', - 'idstools', - 'suricata.manager', - 'utility', - 'schedule', - 'docker_clean', - 'stig', - 'kafka' - ], - 'so-managersearch': [ - 'salt.master', - 'ca', - 'ssl', - 'registry', - 'nginx', - 'telegraf', - 'influxdb', - 'strelka.manager', - 'soc', - 'kratos', - 'hydra', - 'elastic-fleet-package-registry', - 'elasticfleet', - 'firewall', - 'manager', - 'idstools', - 'suricata.manager', - 'utility', - 'schedule', - 'docker_clean', - 'stig', - 'kafka' - ], - 'so-searchnode': [ - 'ssl', - 'nginx', - 'telegraf', - 'firewall', - 'schedule', - 'docker_clean', - 'stig', - 'kafka.ca', - 'kafka.ssl' - ], - 'so-standalone': [ - 'salt.master', - 'ca', - 'ssl', - 'registry', - 'manager', - 'nginx', - 'telegraf', - 'influxdb', - 'soc', - 'kratos', - 'hydra', - 'elastic-fleet-package-registry', - 'elasticfleet', - 'firewall', - 'idstools', - 'suricata.manager', - 'pcap', - 'suricata', - 'healthcheck', - 'utility', - 'schedule', - 'tcpreplay', - 'docker_clean', - 'stig', - 'kafka' - ], - 'so-sensor': [ - 'ssl', - 'telegraf', - 'firewall', - 'nginx', - 'pcap', - 'suricata', - 'healthcheck', - 'schedule', - 'tcpreplay', - 'docker_clean', - 'stig' - ], - 'so-fleet': [ - 'ssl', - 'telegraf', - 'firewall', - 'logstash', - 'nginx', - 'healthcheck', - 'schedule', - 'elasticfleet', - 'docker_clean' - ], - 'so-receiver': [ - 'ssl', - 'telegraf', - 'firewall', - 'schedule', - 'docker_clean', - 'kafka', - 'stig' - ], - 'so-hypervisor': [ - 'ssl', - 'telegraf', - 'firewall', - 'schedule', - 'docker_clean', - 'stig', - 'hypervisor', - 'libvirt' - ], - 'so-desktop': [ - 'ssl', - 'docker_clean', - 'telegraf', - 'stig' - ], - }, grain='role') %} - - {%- if grains.role in ['so-sensor', 'so-eval', 'so-standalone', 'so-heavynode'] %} - {% do allowed_states.append('zeek') %} - {%- endif %} - - {% if grains.role in ['so-sensor', 'so-eval', 'so-standalone', 'so-heavynode'] %} - {% do allowed_states.append('strelka') %} - {% endif %} - - {% if grains.role in ['so-eval', 'so-manager', 'so-standalone', 'so-searchnode', 'so-managersearch', 'so-heavynode', 'so-import'] %} - {% do allowed_states.append('elasticsearch') %} - {% endif %} - - {% if grains.role in ['so-eval', 'so-manager', 'so-standalone', 'so-managersearch', 'so-import'] %} - {% do allowed_states.append('elasticsearch.auth') %} - {% endif %} - - {% if grains.role in ['so-eval', 'so-manager', 'so-standalone', 'so-managersearch', 'so-import'] %} - {% do allowed_states.append('kibana') %} - {% do allowed_states.append('kibana.secrets') %} - {% endif %} - - {% if grains.role in ['so-eval', 'so-manager', 'so-standalone', 'so-managersearch'] %} - {% do allowed_states.append('elastalert') %} - {% endif %} - - {% if grains.role in ['so-manager', 'so-standalone', 'so-searchnode', 'so-managersearch', 'so-heavynode', 'so-receiver'] %} - {% do allowed_states.append('logstash') %} - {% endif %} - - {% if grains.role in ['so-manager', 'so-standalone', 'so-managersearch', 'so-heavynode', 'so-receiver', 'so-eval'] %} - {% do allowed_states.append('redis') %} - {% endif %} - - {# all nodes on the right salt version can run the following states #} - {% do allowed_states.append('common') %} - {% do allowed_states.append('patch.os.schedule') %} - {% do allowed_states.append('motd') %} - {% do allowed_states.append('salt.minion-check') %} - {% do allowed_states.append('sensoroni') %} - {% do allowed_states.append('salt.lasthighstate') %} + {# Get states for the current role #} + {% if grains.role in role_states %} + {% set allowed_states = role_states[grains.role] %} + {% endif %} + {# Add base states that apply to all roles #} + {% for state in base_states %} + {% do allowed_states.append(state) %} + {% endfor %} {% endif %} - +{# Add airgap state if needed #} {% if ISAIRGAP %} - {% do allowed_states.append('airgap') %} + {% do allowed_states.append('airgap') %} {% endif %} - -{# all nodes can always run salt.minion state #} -{% do allowed_states.append('salt.minion') %} diff --git a/salt/common/init.sls b/salt/common/init.sls index d4d90cbed..bb7d648a4 100644 --- a/salt/common/init.sls +++ b/salt/common/init.sls @@ -106,7 +106,7 @@ Etc/UTC: timezone.system # Sync curl configuration for Elasticsearch authentication -{% if GLOBALS.role in ['so-eval', 'so-heavynode', 'so-import', 'so-manager', 'so-managersearch', 'so-searchnode', 'so-standalone'] %} +{% if GLOBALS.is_manager or GLOBALS.role in ['so-heavynode', 'so-searchnode'] %} elastic_curl_config: file.managed: - name: /opt/so/conf/elasticsearch/curl.config diff --git a/salt/elasticfleet/config.sls b/salt/elasticfleet/config.sls index ef921b404..f347a3c80 100644 --- a/salt/elasticfleet/config.sls +++ b/salt/elasticfleet/config.sls @@ -166,7 +166,7 @@ eaoptionalintegrationsdir: {% for minion in node_data %} {% set role = node_data[minion]["role"] %} -{% if role in [ "eval","fleet","heavynode","import","manager","managersearch","standalone" ] %} +{% if role in [ "eval","fleet","heavynode","import","manager", "managerhype", "managersearch","standalone" ] %} {% set optional_integrations = ELASTICFLEETMERGED.optional_integrations %} {% set integration_keys = optional_integrations.keys() %} fleet_server_integrations_{{ minion }}: diff --git a/salt/elasticsearch/config.map.jinja b/salt/elasticsearch/config.map.jinja index f6062e1f2..cfbab8524 100644 --- a/salt/elasticsearch/config.map.jinja +++ b/salt/elasticsearch/config.map.jinja @@ -28,7 +28,7 @@ {% endfor %} {% endfor %} -{% if grains.id.split('_') | last in ['manager','managersearch','standalone'] %} +{% if grains.id.split('_') | last in ['manager','managerhype','managersearch','standalone'] %} {% if ELASTICSEARCH_SEED_HOSTS | length > 1 %} {% do ELASTICSEARCHDEFAULTS.elasticsearch.config.update({'discovery': {'seed_hosts': []}}) %} {% for NODE in ELASTICSEARCH_SEED_HOSTS %} diff --git a/salt/elasticsearch/defaults.yaml b/salt/elasticsearch/defaults.yaml index 7b38ed0bb..f55f49197 100644 --- a/salt/elasticsearch/defaults.yaml +++ b/salt/elasticsearch/defaults.yaml @@ -4479,6 +4479,14 @@ elasticsearch: - data - remote_cluster_client - transform + so-managerhype: + config: + node: + roles: + - master + - data + - remote_cluster_client + - transform so-managersearch: config: node: diff --git a/salt/elasticsearch/enabled.sls b/salt/elasticsearch/enabled.sls index af162d9e9..4e1eecd0a 100644 --- a/salt/elasticsearch/enabled.sls +++ b/salt/elasticsearch/enabled.sls @@ -204,7 +204,7 @@ so-elasticsearch-roles-load: - docker_container: so-elasticsearch - file: elasticsearch_sbin_jinja -{% if grains.role in ['so-eval', 'so-standalone', 'so-managersearch', 'so-heavynode', 'so-manager'] %} +{% if GLOBALS.role in ['so-eval', 'so-standalone', 'so-managersearch', 'so-heavynode', 'so-manager', 'so-managerhype'] %} {% if ELASTICSEARCHMERGED.index_clean %} {% set ap = "present" %} {% else %} diff --git a/salt/firewall/defaults.yaml b/salt/firewall/defaults.yaml index 9b4e0a430..930ceac25 100644 --- a/salt/firewall/defaults.yaml +++ b/salt/firewall/defaults.yaml @@ -19,6 +19,7 @@ firewall: localhost: - 127.0.0.1 manager: [] + managerhype: [] managersearch: [] receiver: [] searchnode: [] @@ -573,6 +574,215 @@ firewall: portgroups: [] customhostgroup9: portgroups: [] + managerhype: + chain: + DOCKER-USER: + hostgroups: + managerhype: + portgroups: + - kibana + - redis + - influxdb + - elasticsearch_rest + - elasticsearch_node + - docker_registry + - elastic_agent_control + - elastic_agent_data + - elastic_agent_update + - localrules + - sensoroni + fleet: + portgroups: + - elasticsearch_rest + - docker_registry + - influxdb + - sensoroni + - yum + - beats_5044 + - beats_5644 + - beats_5056 + - elastic_agent_control + - elastic_agent_data + - elastic_agent_update + idh: + portgroups: + - docker_registry + - influxdb + - sensoroni + - yum + - beats_5044 + - beats_5644 + - elastic_agent_control + - elastic_agent_data + - elastic_agent_update + sensor: + portgroups: + - beats_5044 + - beats_5644 + - elastic_agent_control + - elastic_agent_data + - elastic_agent_update + - yum + - docker_registry + - influxdb + - sensoroni + searchnode: + portgroups: + - redis + - elasticsearch_rest + - elasticsearch_node + - beats_5644 + - yum + - docker_registry + - influxdb + - elastic_agent_control + - elastic_agent_data + - elastic_agent_update + - sensoroni + heavynode: + portgroups: + - redis + - elasticsearch_rest + - elasticsearch_node + - beats_5644 + - yum + - docker_registry + - influxdb + - elastic_agent_control + - elastic_agent_data + - elastic_agent_update + - sensoroni + receiver: + portgroups: + - yum + - docker_registry + - influxdb + - elastic_agent_control + - elastic_agent_data + - elastic_agent_update + - sensoroni + analyst: + portgroups: + - nginx + beats_endpoint: + portgroups: + - beats_5044 + beats_endpoint_ssl: + portgroups: + - beats_5644 + elasticsearch_rest: + portgroups: + - elasticsearch_rest + elastic_agent_endpoint: + portgroups: + - elastic_agent_control + - elastic_agent_data + - elastic_agent_update + endgame: + portgroups: + - endgame + external_suricata: + portgroups: + - external_suricata + desktop: + portgroups: + - docker_registry + - influxdb + - sensoroni + - yum + - elastic_agent_control + - elastic_agent_data + - elastic_agent_update + hypervisor: + portgroups: + - yum + - docker_registry + - influxdb + - elastic_agent_control + - elastic_agent_data + - elastic_agent_update + - sensoroni + customhostgroup0: + portgroups: [] + customhostgroup1: + portgroups: [] + customhostgroup2: + portgroups: [] + customhostgroup3: + portgroups: [] + customhostgroup4: + portgroups: [] + customhostgroup5: + portgroups: [] + customhostgroup6: + portgroups: [] + customhostgroup7: + portgroups: [] + customhostgroup8: + portgroups: [] + customhostgroup9: + portgroups: [] + INPUT: + hostgroups: + anywhere: + portgroups: + - ssh + dockernet: + portgroups: + - all + fleet: + portgroups: + - salt_manager + idh: + portgroups: + - salt_manager + localhost: + portgroups: + - all + sensor: + portgroups: + - salt_manager + searchnode: + portgroups: + - salt_manager + heavynode: + portgroups: + - salt_manager + receiver: + portgroups: + - salt_manager + desktop: + portgroups: + - salt_manager + hypervisor: + portgroups: + - salt_manager + self: + portgroups: + - syslog + syslog: + portgroups: + - syslog + customhostgroup0: + portgroups: [] + customhostgroup1: + portgroups: [] + customhostgroup2: + portgroups: [] + customhostgroup3: + portgroups: [] + customhostgroup4: + portgroups: [] + customhostgroup5: + portgroups: [] + customhostgroup6: + portgroups: [] + customhostgroup7: + portgroups: [] + customhostgroup8: + portgroups: [] + customhostgroup9: + portgroups: [] managersearch: chain: DOCKER-USER: diff --git a/salt/logstash/defaults.yaml b/salt/logstash/defaults.yaml index 9930b7bcf..5af366459 100644 --- a/salt/logstash/defaults.yaml +++ b/salt/logstash/defaults.yaml @@ -12,6 +12,8 @@ logstash: - search manager: - manager + managerhype: + - manager managersearch: - manager - search diff --git a/salt/logstash/enabled.sls b/salt/logstash/enabled.sls index 0f44a3767..cd71cd574 100644 --- a/salt/logstash/enabled.sls +++ b/salt/logstash/enabled.sls @@ -16,7 +16,7 @@ include: - elasticsearch.ca {% endif %} {# Kafka ca runs on nodes that can run logstash for Kafka input / output. Only when Kafka is global pipeline #} -{% if GLOBALS.role in ['so-searchnode', 'so-manager', 'so-managersearch', 'so-receiver', 'so-standalone'] and GLOBALS.pipeline == 'KAFKA' %} +{% if GLOBALS.role in ['so-searchnode', 'so-manager', 'so-managerhype', 'so-managersearch', 'so-receiver', 'so-standalone'] and GLOBALS.pipeline == 'KAFKA' %} - kafka.ca - kafka.ssl {% endif %} @@ -65,26 +65,26 @@ so-logstash: - /opt/so/log/logstash:/var/log/logstash:rw - /sys/fs/cgroup:/sys/fs/cgroup:ro - /opt/so/conf/logstash/etc/certs:/usr/share/logstash/certs:ro - {% if GLOBALS.role in ['so-manager', 'so-managersearch', 'so-standalone', 'so-import', 'so-heavynode', 'so-receiver'] %} + {% if GLOBALS.role in ['so-manager', 'so-managerhype', 'so-managersearch', 'so-standalone', 'so-import', 'so-heavynode', 'so-receiver'] %} - /etc/pki/filebeat.crt:/usr/share/logstash/filebeat.crt:ro - /etc/pki/filebeat.p8:/usr/share/logstash/filebeat.key:ro {% endif %} - {% if GLOBALS.role in ['so-manager', 'so-managersearch', 'so-standalone', 'so-import', 'so-eval','so-fleet', 'so-heavynode', 'so-receiver'] %} + {% if GLOBALS.is_manager or GLOBALS.role in ['so-fleet', 'so-heavynode', 'so-receiver'] %} - /etc/pki/elasticfleet-logstash.crt:/usr/share/logstash/elasticfleet-logstash.crt:ro - /etc/pki/elasticfleet-logstash.key:/usr/share/logstash/elasticfleet-logstash.key:ro - /etc/pki/elasticfleet-lumberjack.crt:/usr/share/logstash/elasticfleet-lumberjack.crt:ro - /etc/pki/elasticfleet-lumberjack.key:/usr/share/logstash/elasticfleet-lumberjack.key:ro {% endif %} - {% if GLOBALS.role in ['so-manager', 'so-managersearch', 'so-standalone', 'so-import'] %} + {% if GLOBALS.role in ['so-manager', 'so-managerhype', 'so-managersearch', 'so-standalone', 'so-import'] %} - /etc/pki/ca.crt:/usr/share/filebeat/ca.crt:ro {% else %} - /etc/pki/tls/certs/intca.crt:/usr/share/filebeat/ca.crt:ro {% endif %} - {% if GLOBALS.role in ['so-manager', 'so-managersearch', 'so-standalone', 'so-import', 'so-heavynode', 'so-searchnode' ] %} + {% if GLOBALS.role in ['so-manager', 'so-managerhype', 'so-managersearch', 'so-standalone', 'so-import', 'so-heavynode', 'so-searchnode' ] %} - /opt/so/conf/ca/cacerts:/etc/pki/ca-trust/extracted/java/cacerts:ro - /opt/so/conf/ca/tls-ca-bundle.pem:/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem:ro {% endif %} - {% if GLOBALS.pipeline == "KAFKA" and GLOBALS.role in ['so-manager', 'so-managersearch', 'so-standalone', 'so-searchnode'] %} + {% if GLOBALS.pipeline == "KAFKA" and GLOBALS.role in ['so-manager', 'so-managerhype', 'so-managersearch', 'so-standalone', 'so-searchnode'] %} - /etc/pki/kafka-logstash.p12:/usr/share/logstash/kafka-logstash.p12:ro - /opt/so/conf/kafka/kafka-truststore.jks:/etc/pki/kafka-truststore.jks:ro {% endif %} @@ -100,7 +100,7 @@ so-logstash: {% endfor %} {% endif %} - watch: - {% if grains['role'] in ['so-manager', 'so-eval', 'so-managersearch', 'so-standalone', 'so-import', 'so-fleet', 'so-receiver'] %} + {% if GLOBALS.is_manager or GLOBALS.role in ['so-fleet', 'so-receiver'] %} - x509: etc_elasticfleet_logstash_key - x509: etc_elasticfleet_logstash_crt {% endif %} @@ -111,23 +111,23 @@ so-logstash: - file: ls_pipeline_{{assigned_pipeline}}_{{CONFIGFILE.split('.')[0] | replace("/","_") }} {% endfor %} {% endfor %} - {% if GLOBALS.pipeline == 'KAFKA' and GLOBALS.role in ['so-manager', 'so-managersearch', 'so-standalone', 'so-searchnode'] %} + {% if GLOBALS.pipeline == 'KAFKA' and GLOBALS.role in ['so-manager', 'so-managerhype', 'so-managersearch', 'so-standalone', 'so-searchnode'] %} - file: kafkacertz {% endif %} - require: - {% if grains['role'] in ['so-manager', 'so-managersearch', 'so-standalone', 'so-import', 'so-heavynode', 'so-receiver'] %} + {% if grains['role'] in ['so-manager', 'so-managerhype', 'so-managersearch', 'so-standalone', 'so-import', 'so-heavynode', 'so-receiver'] %} - x509: etc_filebeat_crt {% endif %} - {% if grains['role'] in ['so-manager', 'so-managersearch', 'so-standalone', 'so-import'] %} + {% if grains['role'] in ['so-manager', 'so-managerhype', 'so-managersearch', 'so-standalone', 'so-import'] %} - x509: pki_public_ca_crt {% else %} - x509: trusttheca {% endif %} - {% if grains.role in ['so-manager', 'so-managersearch', 'so-standalone', 'so-import'] %} + {% if grains.role in ['so-manager', 'so-managerhype', 'so-managersearch', 'so-standalone', 'so-import'] %} - file: cacertz - file: capemz {% endif %} - {% if GLOBALS.pipeline == 'KAFKA' and GLOBALS.role in ['so-manager', 'so-managersearch', 'so-standalone', 'so-searchnode'] %} + {% if GLOBALS.pipeline == 'KAFKA' and GLOBALS.role in ['so-manager', 'so-managerhype', 'so-managersearch', 'so-standalone', 'so-searchnode'] %} - file: kafkacertz {% endif %} diff --git a/salt/manager/tools/sbin/so-minion b/salt/manager/tools/sbin/so-minion index 6de864e4b..222119bde 100755 --- a/salt/manager/tools/sbin/so-minion +++ b/salt/manager/tools/sbin/so-minion @@ -878,6 +878,23 @@ function createHYPERVISOR() { add_telegraf_to_minion || return 1 } +function createMANAGERHYPE() { + log "INFO" "Creating MANAGERHYPE configuration for minion $MINION_ID" + add_elasticsearch_to_minion || return 1 + add_logstash_to_minion || return 1 + add_elastalert_to_minion || return 1 + add_kibana_to_minion || return 1 + add_redis_to_minion || return 1 + add_telegraf_to_minion || return 1 + add_influxdb_to_minion || return 1 + add_nginx_to_minion || return 1 + add_soc_to_minion || return 1 + add_registry_to_minion || return 1 + add_kratos_to_minion || return 1 + add_idstools_to_minion || return 1 + add_elastic_fleet_package_registry_to_minion || return 1 +} + function createDESKTOP() { log "INFO" "Creating DESKTOP configuration for minion $MINION_ID" add_desktop_to_minion || return 1 diff --git a/salt/nginx/enabled.sls b/salt/nginx/enabled.sls index e2bcef863..76bf7aba4 100644 --- a/salt/nginx/enabled.sls +++ b/salt/nginx/enabled.sls @@ -123,7 +123,7 @@ so-nginx: - /opt/so/tmp/nginx/:/run:rw - /opt/so/saltstack/local/salt/elasticfleet/files/so_agent-installers/:/opt/socore/html/packages - /nsm/elastic-fleet/artifacts/:/opt/socore/html/artifacts - {% if grains.role in ['so-manager', 'so-managersearch', 'so-eval', 'so-standalone', 'so-import'] %} + {% if GLOBALS.is_manager %} - /etc/pki/managerssl.crt:/etc/pki/nginx/server.crt:ro - /etc/pki/managerssl.key:/etc/pki/nginx/server.key:ro # ATT&CK Navigator binds @@ -156,7 +156,7 @@ so-nginx: - file: nginxconfdir - require: - file: nginxconf -{% if grains.role in ['so-manager', 'so-managersearch', 'so-eval', 'so-standalone', 'so-import'] %} +{% if GLOBALS.is_manager %} {% if NGINXMERGED.ssl.replace_cert %} - file: managerssl_key - file: managerssl_crt diff --git a/salt/nginx/etc/nginx.conf b/salt/nginx/etc/nginx.conf index 069e55cdb..0506c1e60 100644 --- a/salt/nginx/etc/nginx.conf +++ b/salt/nginx/etc/nginx.conf @@ -59,7 +59,7 @@ http { {%- endif %} - {%- if role in ['eval', 'managersearch', 'manager', 'standalone', 'import'] %} + {%- if GLOBALS.is_manager %} server { listen 80 default_server; @@ -108,7 +108,7 @@ http { {%- endif %} - {%- if role in ['eval', 'managersearch', 'manager', 'standalone', 'import'] %} + {%- if GLOBALS.is_manager %} server { listen 7788; diff --git a/salt/repo/client/oracle.sls b/salt/repo/client/oracle.sls index 89d41beae..2f421b700 100644 --- a/salt/repo/client/oracle.sls +++ b/salt/repo/client/oracle.sls @@ -49,7 +49,7 @@ so_repo: pkgrepo.managed: - name: securityonion - humanname: Security Onion Repo - {% if GLOBALS.role in ['so-eval', 'so-standalone', 'so-import', 'so-manager', 'so-managersearch'] %} + {% if GLOBALS.is_manager %} - baseurl: file:///nsm/repo/ {% else %} - baseurl: https://{{ GLOBALS.repo_host }}/repo diff --git a/salt/ssl/init.sls b/salt/ssl/init.sls index f5be34c40..0cef8c1e3 100644 --- a/salt/ssl/init.sls +++ b/salt/ssl/init.sls @@ -17,7 +17,7 @@ {% set COMMONNAME = GLOBALS.manager %} {% endif %} -{% if grains.id.split('_')|last in ['manager', 'managersearch', 'eval', 'standalone', 'import'] %} +{% if GLOBALS.is_manager %} include: - ca {% set trusttheca_text = salt['cp.get_file_str']('/etc/pki/ca.crt')|replace('\n', '') %} @@ -99,7 +99,7 @@ influxkeyperms: - mode: 640 - group: 939 -{% if grains['role'] in ['so-manager', 'so-eval', 'so-managersearch', 'so-standalone', 'so-import', 'so-heavynode', 'so-fleet', 'so-receiver'] %} +{% if GLOBALS.is_manager or GLOBALS.role in ['so-heavynode', 'so-fleet', 'so-receiver'] %} # Create a cert for Redis encryption redis_key: x509.private_key_managed: @@ -139,7 +139,7 @@ rediskeyperms: - group: 939 {% endif %} -{% if grains['role'] in ['so-manager', 'so-eval', 'so-managersearch', 'so-standalone', 'so-import', 'so-heavynode', 'so-fleet', 'so-receiver'] %} +{% if GLOBALS.is_manager or GLOBALS.role in ['so-heavynode', 'so-fleet', 'so-receiver'] %} {% if grains['role'] not in [ 'so-heavynode', 'so-receiver'] %} # Start -- Elastic Fleet Host Cert @@ -388,7 +388,7 @@ chownelasticfleetagentkey: {% endif %} -{% if grains['role'] in ['so-manager', 'so-eval', 'so-managersearch', 'so-standalone', 'so-import', 'so-heavynode', 'so-receiver'] %} +{% if GLOBALS.is_manager or GLOBALS.role in ['so-heavynode', 'so-receiver'] %} etc_filebeat_key: x509.private_key_managed: - name: /etc/pki/filebeat.key @@ -552,7 +552,7 @@ elasticp12perms: {% endif %} -{% if grains['role'] in ['so-sensor', 'so-manager', 'so-searchnode', 'so-eval', 'so-managersearch', 'so-heavynode', 'so-fleet', 'so-standalone', 'so-idh', 'so-import', 'so-receiver'] %} +{% if GLOBALS.is_manager or GLOBALS.role in ['so-sensor', 'so-searchnode', 'so-heavynode', 'so-fleet', 'so-idh', 'so-receiver'] %} fbcertdir: file.directory: @@ -663,7 +663,7 @@ elastickeyperms: - group: 930 {%- endif %} -{% if grains['role'] in ['so-manager', 'so-managersearch', 'so-standalone'] %} +{% if GLOBALS.role in ['so-manager', 'so-managerhype', 'so-managersearch', 'so-standalone'] %} elasticfleet_kafka_key: x509.private_key_managed: - name: /etc/pki/elasticfleet-kafka.key diff --git a/salt/telegraf/defaults.yaml b/salt/telegraf/defaults.yaml index d32fff179..79ad9008d 100644 --- a/salt/telegraf/defaults.yaml +++ b/salt/telegraf/defaults.yaml @@ -48,6 +48,15 @@ telegraf: - redis.sh - sostatus.sh - features.sh + managerhype: + - agentstatus.sh + - influxdbsize.sh + - lasthighstate.sh + - os.sh + - raid.sh + - redis.sh + - sostatus.sh + - features.sh managersearch: - agentstatus.sh - eps.sh diff --git a/salt/top.sls b/salt/top.sls index 0d22bd782..260bb9c74 100644 --- a/salt/top.sls +++ b/salt/top.sls @@ -85,7 +85,7 @@ base: - utility - elasticfleet - '*_manager and G@saltversion:{{saltversion}}': + '*_manager or *_managerhype and G@saltversion:{{saltversion}}': - match: compound - salt.master - ca @@ -276,17 +276,19 @@ base: - elasticfleet.install_agent_grid - schedule - '*_hypervisor and G@saltversion:{{saltversion}}': + '*_hypervisor or *_managerhype and I@features:hvn and G@saltversion:{{saltversion}}': - match: compound - ssl - sensoroni - telegraf - firewall - - elasticfleet.install_agent_grid - libvirt - libvirt.images - hypervisor - stig + + '*_hypervisor and I@features:hvn and G@saltversion:{{saltversion}}': + - elasticfleet.install_agent_grid '*_desktop and G@saltversion:{{saltversion}}': - ssl diff --git a/salt/vars/globals.map.jinja b/salt/vars/globals.map.jinja index 000cfa354..ca75437eb 100644 --- a/salt/vars/globals.map.jinja +++ b/salt/vars/globals.map.jinja @@ -38,6 +38,7 @@ 'so-import', 'so-manager', 'so-managersearch', + 'so-managerhype', 'so-standalone' ], 'sensor_roles': [ diff --git a/salt/vars/hypervisor.map.jinja b/salt/vars/hypervisor.map.jinja index b8fd4ac1f..0a9dfd3f7 100644 --- a/salt/vars/hypervisor.map.jinja +++ b/salt/vars/hypervisor.map.jinja @@ -1,6 +1,12 @@ {% import 'vars/init.map.jinja' as INIT %} +{% + set has_br0 = INIT.GRAINS is defined and INIT.GRAINS.ip_interfaces is defined and 'br0' in INIT.GRAINS.ip_interfaces and INIT.GRAINS.ip_interfaces.br0 is defined and INIT.GRAINS.ip_interfaces.br0|length > 0 %} +{% + set has_mainint = INIT.PILLAR is defined and INIT.PILLAR.host is defined and INIT.PILLAR.host.mainint is defined %} +{% + set fallback_ip = INIT.GRAINS.ip_interfaces.get(INIT.PILLAR.host.mainint, ['127.0.0.1'])[0] if has_mainint else '127.0.0.1' %} {% set ROLE_GLOBALS = { - 'node_ip': INIT.GRAINS.ip_interfaces.get('br0')[0] + 'node_ip': INIT.GRAINS.ip_interfaces.get('br0', [fallback_ip])[0] if has_br0 else fallback_ip } %} diff --git a/salt/vars/managerhype.map.jinja b/salt/vars/managerhype.map.jinja new file mode 100644 index 000000000..5f7118f31 --- /dev/null +++ b/salt/vars/managerhype.map.jinja @@ -0,0 +1,8 @@ +{% from 'vars/manager.map.jinja' import ROLE_GLOBALS as MANAGER_GLOBALS %} +{% from 'vars/hypervisor.map.jinja' import ROLE_GLOBALS as HYPERVISOR_GLOBALS %} + +{% set ROLE_GLOBALS = {} %} + +{# Merge both role globals #} +{% do salt['defaults.merge'](ROLE_GLOBALS, HYPERVISOR_GLOBALS, merge_lists=False, in_place=True) %} +{% do salt['defaults.merge'](ROLE_GLOBALS, MANAGER_GLOBALS, merge_lists=False, in_place=True) %} diff --git a/setup/so-functions b/setup/so-functions index 25362f179..db0741851 100755 --- a/setup/so-functions +++ b/setup/so-functions @@ -512,7 +512,7 @@ configure_minion() { 'workstation') echo "master: '$MSRV'" >> "$minion_config" ;; - 'manager' | 'eval' | 'managersearch' | 'standalone' | 'import') + 'manager'* | 'eval' | 'standalone' | 'import') cp -f ../salt/ca/files/signing_policies.conf /etc/salt/minion.d/signing_policies.conf printf '%s\n'\ "master: '$HOSTNAME'"\ @@ -609,6 +609,10 @@ check_requirements() { req_mem=8 req_cores=2 req_nics=1 + elif [[ $is_managerhype || $is_hypervisor ]]; then + req_mem=64 + req_cores=32 + req_nics=1 fi if [[ $setup_type == 'network' ]] ; then @@ -1574,6 +1578,10 @@ process_installtype() { is_receiver=true elif [ "$install_type" = 'DESKTOP' ]; then is_desktop=true + elif [ "$install_type" = 'HYPERVISOR' ]; then + is_hypervisor=true + elif [ "$install_type" = 'MANAGERHYPE' ]; then + is_managerhype=true fi } diff --git a/setup/so-setup b/setup/so-setup index 0f445850f..6217511fc 100755 --- a/setup/so-setup +++ b/setup/so-setup @@ -635,6 +635,29 @@ if ! [[ -f $install_opt_file ]]; then set_minion_info whiptail_end_settings + elif [[ $is_managerhype ]]; then + info "Setting up as node type managerhype" + check_elastic_license + waitforstate=true + [[ $is_iso ]] && whiptail_airgap + check_requirements + networking_needful + configure_hyper_bridge + [[ ! $is_airgap ]] && collect_net_method + collect_dockernet + [[ ! $is_airgap ]] && detect_cloud + set_minion_info + set_default_log_size >> $setup_log 2>&1 + info "Verifying all network devices are managed by Network Manager that should be" + check_network_manager_conf + set_network_dev_status_list + calculate_useable_cores + collect_webuser_inputs + get_redirect + collect_so_allow + [[ ! $is_airgap ]] && whiptail_accept_telemetry + whiptail_end_settings + fi if [[ $waitforstate ]]; then diff --git a/setup/so-whiptail b/setup/so-whiptail index 2ea5dd38b..57bd10b8c 100755 --- a/setup/so-whiptail +++ b/setup/so-whiptail @@ -654,9 +654,10 @@ whiptail_install_type_dist_new() { Note: MANAGER is the recommended option for most users. MANAGERSEARCH should only be used in very specific situations. EOM - install_type=$(whiptail --title "$whiptail_title" --menu "$mngr_msg" 20 75 2 \ + install_type=$(whiptail --title "$whiptail_title" --menu "$mngr_msg" 20 75 3 \ "MANAGER" "New grid, requires separate search node(s) " \ "MANAGERSEARCH" "New grid, separate search node(s) are optional " \ + "MANAGERHYPE" "Manager with hypervisor - Security Onion Pro required " \ 3>&1 1>&2 2>&3 ) @@ -681,7 +682,7 @@ whiptail_install_type_dist_existing() { "HEAVYNODE" "Sensor + Search Node " \ "IDH" "Intrusion Detection Honeypot Node " \ "RECEIVER" "Receiver Node " \ - "HYPERVISOR" "Hypervisor Node " \ + "HYPERVISOR" "Hypervisor Node - Security Onion Pro required " \ 3>&1 1>&2 2>&3 # "HOTNODE" "Add Hot Node (Uses Elastic Clustering)" \ # TODO # "WARMNODE" "Add Warm Node to existing Hot or Search node" \ # TODO @@ -714,8 +715,6 @@ whiptail_install_type_dist_existing() { is_receiver=true elif [ "$install_type" = 'DESKTOP' ]; then is_desktop=true - elif [ "$install_type" = 'HYPERVISOR' ]; then - is_hypervisor=true fi local exitstatus=$? From c93a5de460ab8d7fad17b9ac1a3f733956f18449 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Thu, 13 Mar 2025 10:55:49 -0400 Subject: [PATCH 156/315] additional changes for managerhype --- pillar/hypervisor/nodes.sls | 2 +- salt/libvirt/packages.sls | 2 +- salt/libvirt/ssh/users.sls | 4 +++- salt/salt/master.sls | 13 ------------- salt/salt/mine_functions.sls | 4 ++-- 5 files changed, 7 insertions(+), 18 deletions(-) diff --git a/pillar/hypervisor/nodes.sls b/pillar/hypervisor/nodes.sls index 0cdec95d3..a25239d8d 100644 --- a/pillar/hypervisor/nodes.sls +++ b/pillar/hypervisor/nodes.sls @@ -1,7 +1,7 @@ {% set node_types = {} %} {% for minionid, ip in salt.saltutil.runner( 'mine.get', - tgt='G@role:so-hypervisor', + tgt='G@role:so-hypervisor or G@role:so-managerhype', fun='network.ip_addrs', tgt_type='compound') | dictsort() %} diff --git a/salt/libvirt/packages.sls b/salt/libvirt/packages.sls index 195232329..d2cbd6e2d 100644 --- a/salt/libvirt/packages.sls +++ b/salt/libvirt/packages.sls @@ -42,7 +42,7 @@ libvirt_python_module: - onchanges: - file: libvirt_python_wheel -{% if 'hyper' in grains.id.split('_') | last %} +{% if 'hype' in grains.id.split('_') | last %} # provides virsh install_libvirt-client: diff --git a/salt/libvirt/ssh/users.sls b/salt/libvirt/ssh/users.sls index 9b6a3beb7..375a42c38 100644 --- a/salt/libvirt/ssh/users.sls +++ b/salt/libvirt/ssh/users.sls @@ -21,7 +21,9 @@ qemu_ssh_client_config: - name: /root/.ssh/config - source: salt://libvirt/ssh/files/config -{% else %} +{% endif %} + +{% if GLOBALS.role in ['so-hypervisor', 'so-managerhype'] %} # used for qemu+ssh connection between manager and hypervisors create_soqemussh_user: diff --git a/salt/salt/master.sls b/salt/salt/master.sls index 56f529e89..d6bd84496 100644 --- a/salt/salt/master.sls +++ b/salt/salt/master.sls @@ -86,19 +86,6 @@ salt_master_service: - file: engines_config - order: last -{# -# we need to managed adding the following to salt-master config if there are hypervisors -reactor: - - 'salt/key': - - salt://reactor/check_hypervisor.sls - - 'salt/cloud/*/deploying': - - /opt/so/saltstack/default/salt/reactor/createEmptyPillar.sls - - 'setup/so-minion': - - /opt/so/saltstack/default/salt/reactor/sominion_setup.sls - - 'salt/cloud/*/destroyed': - - /opt/so/saltstack/default/salt/reactor/deleteKey.sls -#} - {% else %} {{sls}}_state_not_allowed: diff --git a/salt/salt/mine_functions.sls b/salt/salt/mine_functions.sls index a828add9b..3b81fd4a3 100644 --- a/salt/salt/mine_functions.sls +++ b/salt/salt/mine_functions.sls @@ -8,7 +8,7 @@ # this state is included in the salt.minion state {% set role = salt['grains.get']('role', '') %} -{% if role == 'so-hypervisor' -%} +{% if role in ['so-hypervisor','so-managerhype'] and salt['network.ip_addrs']('br0')|length > 0 -%} {% set interface = 'br0' %} {% else %} {% set interface = pillar.host.mainint %} @@ -22,7 +22,7 @@ mine_functions: mine_functions: network.ip_addrs: - interface: {{ interface }} - {%- if role in ['so-eval','so-import','so-manager','so-managersearch','so-standalone'] %} + {%- if role in ['so-eval','so-import','so-manager','so-managerhype','so-managersearch','so-standalone'] %} x509.get_pem_entries: - glob_path: '/etc/pki/ca.crt' {% endif -%} From 2dc977ddd8cdf2a760074dd3781759ea29ee3783 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Thu, 13 Mar 2025 14:33:48 -0400 Subject: [PATCH 157/315] managerhype --- setup/so-functions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup/so-functions b/setup/so-functions index db0741851..798ab934b 100755 --- a/setup/so-functions +++ b/setup/so-functions @@ -1138,7 +1138,7 @@ generate_ca() { generate_ssl() { # if the install type is a manager then we need to wait for the minion to be ready before trying # to run the ssl state since we need the minion to sign the certs - if [[ "$install_type" =~ ^(EVAL|MANAGER|MANAGERSEARCH|STANDALONE|IMPORT|HELIXSENSOR)$ ]]; then + if [[ $waitforstate ]]; then (wait_for_salt_minion "$MINION_ID" "5" '/dev/stdout' || fail_setup) 2>&1 | tee -a "$setup_log" fi info "Applying SSL state" From 269919b980f5149931d3cc52a876bbfaf6469625 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Tue, 18 Mar 2025 09:39:49 -0400 Subject: [PATCH 158/315] run setup_hypervisor.setup_environment for mangerhype if needed --- salt/manager/hypervisor.sls | 64 +++++++++++++++++++++++++++++++++++++ salt/top.sls | 10 +++--- 2 files changed, 70 insertions(+), 4 deletions(-) create mode 100644 salt/manager/hypervisor.sls diff --git a/salt/manager/hypervisor.sls b/salt/manager/hypervisor.sls new file mode 100644 index 000000000..d4f07946c --- /dev/null +++ b/salt/manager/hypervisor.sls @@ -0,0 +1,64 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. +# +# Note: Per the Elastic License 2.0, the second limitation states: +# +# "You may not move, change, disable, or circumvent the license key functionality +# in the software, and you may not remove or obscure any functionality in the +# software that is protected by the license key." + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} +{% if 'hvn' in salt['pillar.get']('features', []) %} +{% set manager_hostname = grains.id.split('_')[0] %} + +# Check if hypervisor environment has been set up +{% set ssh_user_exists = salt['user.info']('soqemussh') %} +{% set ssh_keys_exist = salt['file.file_exists']('/etc/ssh/auth_keys/soqemussh/id_ed25519') and + salt['file.file_exists']('/etc/ssh/auth_keys/soqemussh/id_ed25519.pub') and + salt['file.file_exists']('/opt/so/saltstack/local/salt/libvirt/ssh/keys/id_ed25519.pub') %} +{% set base_image_exists = salt['file.file_exists']('/nsm/libvirt/boot/OL9U5_x86_64-kvm-b253.qcow2') %} +{% set vm_files_exist = salt['file.directory_exists']('/opt/so/saltstack/local/salt/libvirt/images/sool9') and + salt['file.file_exists']('/opt/so/saltstack/local/salt/libvirt/images/sool9/sool9.qcow2') and + salt['file.file_exists']('/opt/so/saltstack/local/salt/libvirt/images/sool9/sool9-cidata.iso') %} +{% set hypervisor_host_dir_exists = salt['file.directory_exists']('/opt/so/saltstack/local/salt/hypervisor/hosts/' ~ manager_hostname) %} + +{% if ssh_user_exists and ssh_keys_exist and base_image_exists and vm_files_exist and hypervisor_host_dir_exists %} +# Hypervisor environment is already set up, include the necessary states +include: + - libvirt + - libvirt.images + - hypervisor + +hypervisor_setup_verified: + test.succeed_without_changes: + - name: Hypervisor environment is already set up + - comment: All required files and configurations for the hypervisor environment exist + +{% else %} +# Hypervisor environment needs to be set up +run_setup_hypervisor: + salt.runner: + - name: setup_hypervisor.setup_environment + - minion_id: {{ grains.id }} +{% endif %} + +{% else %} +{{sls}}_no_license_detected: + test.fail_without_changes: + - name: {{sls}}_no_license_detected + - comment: + - "Hypervisor nodes are a feature supported only for customers with a valid license. + Contact Security Onion Solutions, LLC via our website at https://securityonionsolutions.com + for more information about purchasing a license to enable this feature." +{% endif %} + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/top.sls b/salt/top.sls index 260bb9c74..39ab50165 100644 --- a/salt/top.sls +++ b/salt/top.sls @@ -116,6 +116,10 @@ base: - stig - kafka + '*_managerhype and I@features:hvn and G@saltversion:{{saltversion}}': + - match: compound + - manager.hypervisor + '*_standalone and G@saltversion:{{saltversion}}': - match: compound - salt.master @@ -276,7 +280,7 @@ base: - elasticfleet.install_agent_grid - schedule - '*_hypervisor or *_managerhype and I@features:hvn and G@saltversion:{{saltversion}}': + '*_hypervisor and I@features:hvn and G@saltversion:{{saltversion}}': - match: compound - ssl - sensoroni @@ -285,11 +289,9 @@ base: - libvirt - libvirt.images - hypervisor + - elasticfleet.install_agent_grid - stig - '*_hypervisor and I@features:hvn and G@saltversion:{{saltversion}}': - - elasticfleet.install_agent_grid - '*_desktop and G@saltversion:{{saltversion}}': - ssl - sensoroni From 64f71143dcbb86f03cb14434ad3f3b878d055fbc Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Mon, 31 Mar 2025 15:51:32 -0400 Subject: [PATCH 159/315] fix docker fw rules managerhype --- salt/firewall/containers.map.jinja | 2 +- salt/manager/tools/sbin/so-firewall-minion | 4 ++++ setup/so-functions | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/salt/firewall/containers.map.jinja b/salt/firewall/containers.map.jinja index cc0a20299..2d1135e5f 100644 --- a/salt/firewall/containers.map.jinja +++ b/salt/firewall/containers.map.jinja @@ -21,7 +21,7 @@ 'so-strelka-filestream' ] %} -{% elif GLOBALS.role == 'so-manager' or GLOBALS.role == 'so-standalone' or GLOBALS.role == 'so-managersearch' %} +{% elif GLOBALS.role in ['so-manager', 'so-standalone','so-managersearch', 'so-managerhype'] %} {% set NODE_CONTAINERS = [ 'so-dockerregistry', 'so-elasticsearch', diff --git a/salt/manager/tools/sbin/so-firewall-minion b/salt/manager/tools/sbin/so-firewall-minion index 4b0fb766e..8b8fbfc99 100755 --- a/salt/manager/tools/sbin/so-firewall-minion +++ b/salt/manager/tools/sbin/so-firewall-minion @@ -51,6 +51,10 @@ fi 'MANAGER') so-firewall includehost manager "$IP" ;; + 'MANAGERHYPE') + so-firewall includehost manager "$IP" + so-firewall includehost hypervisor "$IP" --apply + ;; 'MANAGERSEARCH') so-firewall includehost manager "$IP" so-firewall includehost searchnode "$IP" --apply diff --git a/setup/so-functions b/setup/so-functions index 3cad975fd..d28d7baf3 100755 --- a/setup/so-functions +++ b/setup/so-functions @@ -2234,7 +2234,7 @@ set_hostname() { set_initial_firewall_policy() { case "$install_type" in - 'EVAL' | 'MANAGER' | 'MANAGERSEARCH' | 'STANDALONE' | 'IMPORT') + 'EVAL' | 'MANAGER' | 'MANAGERHYPE' | 'MANAGERSEARCH' | 'STANDALONE' | 'IMPORT') so-firewall includehost $minion_type $MAINIP --apply ;; esac From e7aa4428de80f4358dfbcd88522dddb65478b3ec Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Mon, 31 Mar 2025 16:03:19 -0400 Subject: [PATCH 160/315] managerhype udate mine when switch to br0 --- salt/libvirt/init.sls | 3 +++ salt/salt/mine_functions.sls | 6 ++++++ 2 files changed, 9 insertions(+) diff --git a/salt/libvirt/init.sls b/salt/libvirt/init.sls index 4321fdfb1..3e21089b2 100644 --- a/salt/libvirt/init.sls +++ b/salt/libvirt/init.sls @@ -18,6 +18,7 @@ include: - libvirt.64962 - libvirt.packages - libvirt.ssh.users + - salt.mine_functions install_libvirt: pkg.installed: @@ -99,6 +100,8 @@ down_original_mgmt_interface: - unless: - nmcli -f GENERAL.CONNECTION dev show {{ pillar.host.mainint }} | grep bridge-slave-{{ pillar.host.mainint }} - order: last + - onchanges_in: + - file: mine_functions # virtlogd service may not restart following reboot without this #semanage permissive -a virtlogd_t diff --git a/salt/salt/mine_functions.sls b/salt/salt/mine_functions.sls index 3b81fd4a3..6fc6fcb49 100644 --- a/salt/salt/mine_functions.sls +++ b/salt/salt/mine_functions.sls @@ -26,3 +26,9 @@ mine_functions: x509.get_pem_entries: - glob_path: '/etc/pki/ca.crt' {% endif -%} + +mine_update_mine_functions: + module.run: + - mine.update: [] + - onchanges: + - file: mine_functions From a60e55e5cd009b1a0c6e455f061a375376e60dd7 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Mon, 31 Mar 2025 16:44:48 -0400 Subject: [PATCH 161/315] remove whitespace control --- salt/salt/mine_functions.sls | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/salt/salt/mine_functions.sls b/salt/salt/mine_functions.sls index 6fc6fcb49..b167dec4b 100644 --- a/salt/salt/mine_functions.sls +++ b/salt/salt/mine_functions.sls @@ -8,7 +8,7 @@ # this state is included in the salt.minion state {% set role = salt['grains.get']('role', '') %} -{% if role in ['so-hypervisor','so-managerhype'] and salt['network.ip_addrs']('br0')|length > 0 -%} +{% if role in ['so-hypervisor','so-managerhype'] and salt['network.ip_addrs']('br0')|length > 0 %} {% set interface = 'br0' %} {% else %} {% set interface = pillar.host.mainint %} @@ -22,10 +22,10 @@ mine_functions: mine_functions: network.ip_addrs: - interface: {{ interface }} - {%- if role in ['so-eval','so-import','so-manager','so-managerhype','so-managersearch','so-standalone'] %} + {% if role in ['so-eval','so-import','so-manager','so-managerhype','so-managersearch','so-standalone'] %} x509.get_pem_entries: - glob_path: '/etc/pki/ca.crt' - {% endif -%} + {% endif %} mine_update_mine_functions: module.run: From b22fe5bd3d07927cbc43ca061f86fea596dd01cf Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Tue, 1 Apr 2025 09:27:50 -0400 Subject: [PATCH 162/315] set interface for hypervisor/managerhype --- salt/salt/map.jinja | 7 +++++++ salt/salt/mine_functions.sls | 8 ++------ salt/salt/service/salt-minion.service.jinja | 4 +++- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/salt/salt/map.jinja b/salt/salt/map.jinja index d77e23100..55b3a7ffb 100644 --- a/salt/salt/map.jinja +++ b/salt/salt/map.jinja @@ -3,6 +3,13 @@ https://securityonion.net/license; you may not use this file except in compliance with the Elastic License 2.0. #} +{% set role = salt['grains.get']('role', '') %} +{% if role in ['so-hypervisor','so-managerhype'] and salt['network.ip_addrs']('br0')|length > 0 %} +{% set interface = 'br0' %} +{% else %} +{% set interface = pillar.host.mainint %} +{% endif %} + {% import_yaml 'salt/minion.defaults.yaml' as saltminion %} {% set SALTVERSION = saltminion.salt.minion.version | string %} {% set INSTALLEDSALTVERSION = grains.saltversion | string %} diff --git a/salt/salt/mine_functions.sls b/salt/salt/mine_functions.sls index b167dec4b..305fe2ce4 100644 --- a/salt/salt/mine_functions.sls +++ b/salt/salt/mine_functions.sls @@ -7,12 +7,8 @@ # GLOBALS are imported in the salt.minion state and that is not available at that point in setup # this state is included in the salt.minion state -{% set role = salt['grains.get']('role', '') %} -{% if role in ['so-hypervisor','so-managerhype'] and salt['network.ip_addrs']('br0')|length > 0 %} -{% set interface = 'br0' %} -{% else %} -{% set interface = pillar.host.mainint %} -{% endif %} +{% from 'salt/map.jinja' import interface %} +{% from 'salt/map.jinja' import role %} mine_functions: file.managed: diff --git a/salt/salt/service/salt-minion.service.jinja b/salt/salt/service/salt-minion.service.jinja index 2763b30f5..ba5702654 100644 --- a/salt/salt/service/salt-minion.service.jinja +++ b/salt/salt/service/salt-minion.service.jinja @@ -1,3 +1,5 @@ +{% from 'salt/map.jinja' import interface -%} + [Unit] Description=The Salt Minion Documentation=man:salt-minion(1) file:///usr/share/doc/salt/html/contents.html https://docs.saltproject.io/en/latest/contents.html @@ -8,7 +10,7 @@ KillMode=process Type=notify NotifyAccess=all LimitNOFILE=8192 -ExecStartPre=/bin/bash -c 'until /sbin/ip -4 addr show dev {{ salt["pillar.get"]("host:mainint") }} | grep -q "inet "; do sleep 1; done' +ExecStartPre=/bin/bash -c 'until /sbin/ip -4 addr show dev {{ interface }} | grep -q "inet "; do sleep 1; done' ExecStart=/usr/bin/salt-minion TimeoutStartSec=120 From 3083e3bc63abe6d3e64eb22f5e3721f5481ac0a4 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Thu, 3 Apr 2025 13:42:02 -0400 Subject: [PATCH 163/315] sync runners and create soqemussh user ssh keypair for manager and managerhype --- setup/so-setup | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/setup/so-setup b/setup/so-setup index 6217511fc..5b8a14a01 100755 --- a/setup/so-setup +++ b/setup/so-setup @@ -753,8 +753,14 @@ if ! [[ -f $install_opt_file ]]; then logCmd "salt-call state.show_top" sleep 2 # Debug RSA Key format errors logCmd "salt-key -ya $MINION_ID" - logCmd "salt-call saltutil.sync_all" - + # we need to sync the runner and generate the soqemussh user keys so that first highstate after license created + # doesnt have a state failure for soqemussh_pub_key source for id_ed25519.pub missing + if [[ $is_manager || $is_managerhype ]]; then + logCmd "salt-run saltutil.sync_all" + logCmd "salt-run setup_hypervisor.regenerate_ssh_keys" + else + logCmd "salt-call saltutil.sync_all" + fi logCmd "salt-call state.apply common.packages" logCmd "salt-call state.apply common" # this will apply the salt.minion state first since salt.master includes salt.minion From 445afca6eea4a09c383c07e128a75b62776dffd7 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Thu, 3 Apr 2025 13:44:13 -0400 Subject: [PATCH 164/315] use vrt --- salt/_runners/setup_hypervisor.py | 13 ++++--------- .../so-salt-emit-vm-deployment-status-event | 2 +- salt/hypervisor/init.sls | 2 +- salt/hypervisor/map.jinja | 2 +- .../tools/sbin_jinja/so-kvm-modify-hardware | 2 +- .../tools/sbin_jinja/so-qcow2-modify-network | 2 +- salt/libvirt/images/init.sls | 2 +- salt/libvirt/init.sls | 2 +- salt/libvirt/packages.sls | 2 +- salt/libvirt/ssh/users.sls | 2 +- salt/manager/hypervisor.sls | 2 +- salt/manager/tools/sbin/so-minion | 8 ++++---- salt/manager/tools/sbin_jinja/so-salt-cloud | 2 +- salt/orch/dyanno_hypervisor.sls | 2 +- salt/orch/vm_pillar_clean.sls | 2 +- salt/salt/cloud/init.sls | 2 +- salt/salt/cloud/reactor_config_hypervisor.sls | 2 +- salt/salt/engines/master/virtual_node_manager.py | 10 +++++----- .../salt/files/{hvn_engine.conf => vrt_engine.conf} | 0 salt/salt/master.sls | 10 +++++----- salt/sensor/init.sls | 2 +- salt/sensor/vm/network.sls | 2 +- salt/soc/dyanno/hypervisor/init.sls | 2 +- .../soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja | 2 +- salt/soc/dyanno/hypervisor/write_status.sls | 2 +- salt/top.sls | 4 ++-- salt/vm_status/init.sls | 2 +- 27 files changed, 41 insertions(+), 46 deletions(-) rename salt/salt/files/{hvn_engine.conf => vrt_engine.conf} (100%) diff --git a/salt/_runners/setup_hypervisor.py b/salt/_runners/setup_hypervisor.py index 6b3f289e8..35d1bad21 100644 --- a/salt/_runners/setup_hypervisor.py +++ b/salt/_runners/setup_hypervisor.py @@ -121,8 +121,8 @@ def _check_license(): log.error("LICENSE: No license_id found in license file") return False - if 'hvn' not in features: - log.error("LICENSE: 'hvn' feature not found in license") + if 'vrt' not in features: + log.error("LICENSE: 'vrt' feature not found in license") return False log.info("LICENSE: License validation successful") @@ -506,7 +506,7 @@ def setup_environment(vm_name: str = 'sool9', disk_size: str = '220G', minion_id if not _check_license(): return { 'success': False, - 'error': 'Invalid license or missing hvn feature', + 'error': 'Invalid license or missing vrt feature', 'vm_result': None } @@ -670,7 +670,7 @@ def create_vm(vm_name: str, disk_size: str = '220G'): if not _check_license(): return { 'success': False, - 'error': 'Invalid license or missing hvn feature', + 'error': 'Invalid license or missing vrt feature', } try: @@ -958,11 +958,6 @@ def regenerate_ssh_keys(): else: print("Failed to regenerate SSH keys") """ - # Check license before proceeding - if not _check_license(): - log.error("MAIN: Invalid license or missing hvn feature") - return False - log.info("MAIN: Starting SSH key regeneration") try: # Verify current state diff --git a/salt/common/tools/sbin_jinja/so-salt-emit-vm-deployment-status-event b/salt/common/tools/sbin_jinja/so-salt-emit-vm-deployment-status-event index 61f071130..fe51485e6 100644 --- a/salt/common/tools/sbin_jinja/so-salt-emit-vm-deployment-status-event +++ b/salt/common/tools/sbin_jinja/so-salt-emit-vm-deployment-status-event @@ -11,7 +11,7 @@ # in the software, and you may not remove or obscure any functionality in the # software that is protected by the license key." -{% if 'hvn' in salt['pillar.get']('features', []) -%} +{% if 'vrt' in salt['pillar.get']('features', []) -%} """ Script for emitting VM deployment status events to the Salt event bus. diff --git a/salt/hypervisor/init.sls b/salt/hypervisor/init.sls index 677ab8642..4a2edad75 100644 --- a/salt/hypervisor/init.sls +++ b/salt/hypervisor/init.sls @@ -11,7 +11,7 @@ {% from 'allowed_states.map.jinja' import allowed_states %} {% if sls in allowed_states %} -{% if 'hvn' in salt['pillar.get']('features', []) %} +{% if 'vrt' in salt['pillar.get']('features', []) %} hypervisor_log_dir: file.directory: diff --git a/salt/hypervisor/map.jinja b/salt/hypervisor/map.jinja index d19aacf48..da8716415 100644 --- a/salt/hypervisor/map.jinja +++ b/salt/hypervisor/map.jinja @@ -9,7 +9,7 @@ in the software, and you may not remove or obscure any functionality in the software that is protected by the license key." #} -{% if 'hvn' in salt['pillar.get']('features', []) %} +{% if 'vrt' in salt['pillar.get']('features', []) %} {# Import defaults.yaml for model hardware capabilities #} {% import_yaml 'hypervisor/defaults.yaml' as DEFAULTS %} diff --git a/salt/hypervisor/tools/sbin_jinja/so-kvm-modify-hardware b/salt/hypervisor/tools/sbin_jinja/so-kvm-modify-hardware index 25506a0ae..ebd606b1e 100644 --- a/salt/hypervisor/tools/sbin_jinja/so-kvm-modify-hardware +++ b/salt/hypervisor/tools/sbin_jinja/so-kvm-modify-hardware @@ -11,7 +11,7 @@ # in the software, and you may not remove or obscure any functionality in the # software that is protected by the license key." -{% if 'hvn' in salt['pillar.get']('features', []) %} +{% if 'vrt' in salt['pillar.get']('features', []) %} """ Script for managing hardware configurations of KVM virtual machines. This script provides diff --git a/salt/hypervisor/tools/sbin_jinja/so-qcow2-modify-network b/salt/hypervisor/tools/sbin_jinja/so-qcow2-modify-network index cd7869fd8..527131f3f 100644 --- a/salt/hypervisor/tools/sbin_jinja/so-qcow2-modify-network +++ b/salt/hypervisor/tools/sbin_jinja/so-qcow2-modify-network @@ -11,7 +11,7 @@ # in the software, and you may not remove or obscure any functionality in the # software that is protected by the license key." -{% if 'hvn' in salt['pillar.get']('features', []) -%} +{% if 'vrt' in salt['pillar.get']('features', []) -%} """ Script for modifying network configurations within QCOW2 virtual machine images. This script provides diff --git a/salt/libvirt/images/init.sls b/salt/libvirt/images/init.sls index 94cf4959d..c7734c69d 100644 --- a/salt/libvirt/images/init.sls +++ b/salt/libvirt/images/init.sls @@ -11,7 +11,7 @@ {% from 'allowed_states.map.jinja' import allowed_states %} {% if sls.split('.')[0] in allowed_states or sls in allowed_states %} -{% if 'hvn' in salt['pillar.get']('features', []) %} +{% if 'vrt' in salt['pillar.get']('features', []) %} include: - libvirt.packages diff --git a/salt/libvirt/init.sls b/salt/libvirt/init.sls index 3e21089b2..f82b3d9c1 100644 --- a/salt/libvirt/init.sls +++ b/salt/libvirt/init.sls @@ -11,7 +11,7 @@ {% from 'allowed_states.map.jinja' import allowed_states %} {% if sls in allowed_states %} -{% if 'hvn' in salt['pillar.get']('features', []) %} +{% if 'vrt' in salt['pillar.get']('features', []) %} {% from 'libvirt/map.jinja' import LIBVIRTMERGED %} include: diff --git a/salt/libvirt/packages.sls b/salt/libvirt/packages.sls index d2cbd6e2d..d0de3d81f 100644 --- a/salt/libvirt/packages.sls +++ b/salt/libvirt/packages.sls @@ -11,7 +11,7 @@ {% from 'allowed_states.map.jinja' import allowed_states %} {% if sls.split('.')[0] in allowed_states or sls in allowed_states %} -{% if 'hvn' in salt['pillar.get']('features', []) %} +{% if 'vrt' in salt['pillar.get']('features', []) %} # allows for creating vm images # any node manipulating images needs this diff --git a/salt/libvirt/ssh/users.sls b/salt/libvirt/ssh/users.sls index 375a42c38..0e9c045a0 100644 --- a/salt/libvirt/ssh/users.sls +++ b/salt/libvirt/ssh/users.sls @@ -11,7 +11,7 @@ {% from 'allowed_states.map.jinja' import allowed_states %} {% if sls.split('.')[0] in allowed_states or sls in allowed_states %} -{% if 'hvn' in salt['pillar.get']('features', []) %} +{% if 'vrt' in salt['pillar.get']('features', []) %} {% from 'vars/globals.map.jinja' import GLOBALS %} {% if GLOBALS.is_manager %} diff --git a/salt/manager/hypervisor.sls b/salt/manager/hypervisor.sls index d4f07946c..84cd478c8 100644 --- a/salt/manager/hypervisor.sls +++ b/salt/manager/hypervisor.sls @@ -11,7 +11,7 @@ {% from 'allowed_states.map.jinja' import allowed_states %} {% if sls.split('.')[0] in allowed_states %} -{% if 'hvn' in salt['pillar.get']('features', []) %} +{% if 'vrt' in salt['pillar.get']('features', []) %} {% set manager_hostname = grains.id.split('_')[0] %} # Check if hypervisor environment has been set up diff --git a/salt/manager/tools/sbin/so-minion b/salt/manager/tools/sbin/so-minion index 222119bde..211b036cf 100755 --- a/salt/manager/tools/sbin/so-minion +++ b/salt/manager/tools/sbin/so-minion @@ -235,7 +235,7 @@ function acceptminion() { if [[ "$MINION_ID" == *"_hypervisor" ]]; then FEATURES=$(/usr/sbin/so-yaml.py get /opt/so/saltstack/local/pillar/soc/license.sls features) - if [[ $? -ne 0 || ! "$FEATURES" =~ "hvn" ]]; then + if [[ $? -ne 0 || ! "$FEATURES" =~ "vrt" ]]; then error_msg="Hypervisor nodes are a feature supported only for customers with a valid license.\n Contact Security Onion Solutions, LLC via our website at https://securityonionsolutions.com\n for more information about purchasing a license to enable this feature." log "ERROR" "$error_msg" echo -e "Error: $error_msg" @@ -869,7 +869,7 @@ function createRECEIVER() { function createHYPERVISOR() { log "INFO" "Creating HYPERVISOR configuration for minion $MINION_ID" FEATURES=$(/usr/sbin/so-yaml.py get /opt/so/saltstack/local/pillar/soc/license.sls features) - if [[ $? -ne 0 || ! "$FEATURES" =~ "hvn" ]]; then + if [[ $? -ne 0 || ! "$FEATURES" =~ "vrt" ]]; then error_msg="Hypervisor nodes are a feature supported only for customers with a valid license.\n Contact Security Onion Solutions, LLC via our website at https://securityonionsolutions.com\n for more information about purchasing a license to enable this feature." log "ERROR" "$error_msg" echo -e "Error: $error_msg" @@ -964,7 +964,7 @@ function updateMineAndApplyStates() { # We don't want a hypervisor node to highstate until the image is downloaded and built. This will be triggered from the setup_hypervisor runner if [[ "$NODETYPE" == "HYPERVISOR" ]]; then FEATURES=$(/usr/sbin/so-yaml.py get /opt/so/saltstack/local/pillar/soc/license.sls features) - if [[ $? -ne 0 || ! "$FEATURES" =~ "hvn" ]]; then + if [[ $? -ne 0 || ! "$FEATURES" =~ "vrt" ]]; then error_msg="Hypervisor nodes are a feature supported only for customers with a valid license.\n Contact Security Onion Solutions, LLC via our website at https://securityonionsolutions.com\n for more information about purchasing a license to enable this feature." log "ERROR" "$error_msg" echo -e "Error: $error_msg" @@ -1058,7 +1058,7 @@ case "$OPERATION" in "addVM") log "INFO" "Adding VM minion $MINION_ID" FEATURES=$(/usr/sbin/so-yaml.py get /opt/so/saltstack/local/pillar/soc/license.sls features) - if [[ $? -ne 0 || ! "$FEATURES" =~ "hvn" ]]; then + if [[ $? -ne 0 || ! "$FEATURES" =~ "vrt" ]]; then error_msg="Hypervisor nodes are a feature supported only for customers with a valid license.\n Contact Security Onion Solutions, LLC via our website at https://securityonionsolutions.com\n for more information about purchasing a license to enable this feature." log "ERROR" "$error_msg" echo -e "Error: $error_msg" diff --git a/salt/manager/tools/sbin_jinja/so-salt-cloud b/salt/manager/tools/sbin_jinja/so-salt-cloud index cddcbb474..f1346130f 100644 --- a/salt/manager/tools/sbin_jinja/so-salt-cloud +++ b/salt/manager/tools/sbin_jinja/so-salt-cloud @@ -11,7 +11,7 @@ # in the software, and you may not remove or obscure any functionality in the # software that is protected by the license key." -{% if 'hvn' in salt['pillar.get']('features', []) -%} +{% if 'vrt' in salt['pillar.get']('features', []) -%} """ Script for automated virtual machine provisioning and configuration in Security Onion's virtualization infrastructure. diff --git a/salt/orch/dyanno_hypervisor.sls b/salt/orch/dyanno_hypervisor.sls index 624bb12f3..859e87df6 100644 --- a/salt/orch/dyanno_hypervisor.sls +++ b/salt/orch/dyanno_hypervisor.sls @@ -9,7 +9,7 @@ # in the software, and you may not remove or obscure any functionality in the # software that is protected by the license key." -{% if 'hvn' in salt['pillar.get']('features', []) %} +{% if 'vrt' in salt['pillar.get']('features', []) %} {% do salt.log.info('dyanno_hypervisor_orch: Running') %} {% set vm_name = None %} diff --git a/salt/orch/vm_pillar_clean.sls b/salt/orch/vm_pillar_clean.sls index 5c0011f6f..ca5c16054 100644 --- a/salt/orch/vm_pillar_clean.sls +++ b/salt/orch/vm_pillar_clean.sls @@ -9,7 +9,7 @@ # in the software, and you may not remove or obscure any functionality in the # software that is protected by the license key." -{% if 'hvn' in salt['pillar.get']('features', []) %} +{% if 'vrt' in salt['pillar.get']('features', []) %} {% do salt.log.debug('vm_pillar_clean_orch: Running') %} {% set vm_name = pillar.get('vm_name') %} diff --git a/salt/salt/cloud/init.sls b/salt/salt/cloud/init.sls index 5ba8b96da..114133204 100644 --- a/salt/salt/cloud/init.sls +++ b/salt/salt/cloud/init.sls @@ -11,7 +11,7 @@ {% from 'allowed_states.map.jinja' import allowed_states %} {% if sls in allowed_states %} -{% if 'hvn' in salt['pillar.get']('features', []) %} +{% if 'vrt' in salt['pillar.get']('features', []) %} {% from 'salt/map.jinja' import SALTVERSION %} {% set HYPERVISORS = salt['pillar.get']('hypervisor:nodes', {} ) %} diff --git a/salt/salt/cloud/reactor_config_hypervisor.sls b/salt/salt/cloud/reactor_config_hypervisor.sls index fcf1a5dfe..d0851d75c 100644 --- a/salt/salt/cloud/reactor_config_hypervisor.sls +++ b/salt/salt/cloud/reactor_config_hypervisor.sls @@ -11,7 +11,7 @@ {% from 'allowed_states.map.jinja' import allowed_states %} {% if sls.split('.')[:2]|join('.') in allowed_states %} -{% if 'hvn' in salt['pillar.get']('features', []) %} +{% if 'vrt' in salt['pillar.get']('features', []) %} reactor_config_hypervisor: file.managed: - name: /etc/salt/master.d/reactor_hypervisor.conf diff --git a/salt/salt/engines/master/virtual_node_manager.py b/salt/salt/engines/master/virtual_node_manager.py index 42d8f6725..78f8f0294 100644 --- a/salt/salt/engines/master/virtual_node_manager.py +++ b/salt/salt/engines/master/virtual_node_manager.py @@ -63,7 +63,7 @@ State Files: - .error: Error state with detailed message Notes: - - Requires 'hvn' feature license + - Requires 'vrt' feature license - Uses hypervisor's sosmodel grain for hardware capabilities - Hardware allocation based on model-specific configurations - All created files maintain socore ownership @@ -80,7 +80,7 @@ Description: - Lock remains until clean shutdown or error 2. License Validation - - Verifies 'hvn' feature is licensed + - Verifies 'vrt' feature is licensed - Prevents operation if license is invalid 3. Configuration Processing @@ -567,7 +567,7 @@ def mark_invalid_hardware(hypervisor_path: str, vm_name: str, config: dict, erro log.error("Failed to create invalid hardware file: %s", str(e)) raise -def validate_hvn_license() -> bool: +def validate_vrt_license() -> bool: """Check if the license file exists and contains required values.""" if not os.path.exists(LICENSE_PATH): log.error("License file not found at %s", LICENSE_PATH) @@ -588,7 +588,7 @@ def validate_hvn_license() -> bool: log.error("No license_id found in license file") return False - if 'hvn' not in features: + if 'vrt' not in features: log.error("Hypervisor nodes are a feature supported only for customers with a valid license.\n" "Contact Security Onion Solutions, LLC via our website at https://securityonionsolutions.com\n" "for more information about purchasing a license to enable this feature.") @@ -889,7 +889,7 @@ def start(interval: int = DEFAULT_INTERVAL, """ log.info("Starting virtual node manager engine") - if not validate_hvn_license(): + if not validate_vrt_license(): return # Attempt to acquire lock diff --git a/salt/salt/files/hvn_engine.conf b/salt/salt/files/vrt_engine.conf similarity index 100% rename from salt/salt/files/hvn_engine.conf rename to salt/salt/files/vrt_engine.conf diff --git a/salt/salt/master.sls b/salt/salt/master.sls index d6bd84496..413c90cd5 100644 --- a/salt/salt/master.sls +++ b/salt/salt/master.sls @@ -14,7 +14,7 @@ include: - salt.minion -{% if 'hvn' in salt['pillar.get']('features', []) %} +{% if 'vrt' in salt['pillar.get']('features', []) %} - salt.cloud - salt.cloud.reactor_config_hypervisor @@ -48,11 +48,11 @@ pillarWatch_engine: - name: /etc/salt/engines/pillarWatch.py - source: salt://salt/engines/master/pillarWatch.py -{% if 'hvn' in salt['pillar.get']('features', []) %} -hvn_engine_config: +{% if 'vrt' in salt['pillar.get']('features', []) %} +vrt_engine_config: file.managed: - - name: /etc/salt/master.d/hvn_engine.conf - - source: salt://salt/files/hvn_engine.conf + - name: /etc/salt/master.d/vrt_engine.conf + - source: salt://salt/files/vrt_engine.conf - watch_in: - service: salt_master_service diff --git a/salt/sensor/init.sls b/salt/sensor/init.sls index 4008879e9..9c7e52d62 100644 --- a/salt/sensor/init.sls +++ b/salt/sensor/init.sls @@ -9,7 +9,7 @@ # in the software, and you may not remove or obscure any functionality in the # software that is protected by the license key." -{% if 'hvn' in salt['pillar.get']('features') and salt['grains.get']('salt-cloud', {}) %} +{% if 'vrt' in salt['pillar.get']('features') and salt['grains.get']('salt-cloud', {}) %} include: - sensor.vm.network diff --git a/salt/sensor/vm/network.sls b/salt/sensor/vm/network.sls index f056e307a..9e25bca65 100644 --- a/salt/sensor/vm/network.sls +++ b/salt/sensor/vm/network.sls @@ -9,7 +9,7 @@ # in the software, and you may not remove or obscure any functionality in the # software that is protected by the license key." -{% if 'hvn' in salt['pillar.get']('features', []) %} +{% if 'vrt' in salt['pillar.get']('features', []) %} {% set mainint = salt['pillar.get']('host:mainint', 'enp1s0') %} {% set interfaces = salt['network.interfaces']() %} diff --git a/salt/soc/dyanno/hypervisor/init.sls b/salt/soc/dyanno/hypervisor/init.sls index e4ce3b47c..1f17552e7 100644 --- a/salt/soc/dyanno/hypervisor/init.sls +++ b/salt/soc/dyanno/hypervisor/init.sls @@ -9,7 +9,7 @@ # in the software, and you may not remove or obscure any functionality in the # software that is protected by the license key." -{% if 'hvn' in salt['pillar.get']('features', []) %} +{% if 'vrt' in salt['pillar.get']('features', []) %} {% from 'hypervisor/map.jinja' import HYPERVISORS %} diff --git a/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja b/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja index 17603ab9d..8976e7cc7 100644 --- a/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja +++ b/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja @@ -9,7 +9,7 @@ in the software, and you may not remove or obscure any functionality in the software that is protected by the license key." #} -{%- if 'hvn' in salt['pillar.get']('features', []) -%} +{%- if 'vrt' in salt['pillar.get']('features', []) -%} {%- import_yaml 'soc/dyanno/hypervisor/hypervisor.yaml' as ANNOTATION -%} {%- from 'hypervisor/map.jinja' import HYPERVISORS -%} diff --git a/salt/soc/dyanno/hypervisor/write_status.sls b/salt/soc/dyanno/hypervisor/write_status.sls index d2aa590e6..60a94b3e9 100644 --- a/salt/soc/dyanno/hypervisor/write_status.sls +++ b/salt/soc/dyanno/hypervisor/write_status.sls @@ -9,7 +9,7 @@ # in the software, and you may not remove or obscure any functionality in the # software that is protected by the license key." -{% if 'hvn' in salt['pillar.get']('features', []) %} +{% if 'vrt' in salt['pillar.get']('features', []) %} {# Import the process steps from map.jinja #} {% from 'soc/dyanno/hypervisor/map.jinja' import PROCESS_STEPS %} diff --git a/salt/top.sls b/salt/top.sls index 5a0c7416b..4f8029706 100644 --- a/salt/top.sls +++ b/salt/top.sls @@ -155,7 +155,7 @@ base: - stig - kafka - '*_managerhype and I@features:hvn and G@saltversion:{{saltversion}}': + '*_managerhype and I@features:vrt and G@saltversion:{{saltversion}}': - match: compound - manager.hypervisor @@ -299,7 +299,7 @@ base: - elasticfleet.install_agent_grid - schedule - '*_hypervisor and I@features:hvn and G@saltversion:{{saltversion}}': + '*_hypervisor and I@features:vrt and G@saltversion:{{saltversion}}': - match: compound - ssl - sensoroni diff --git a/salt/vm_status/init.sls b/salt/vm_status/init.sls index c6b39c12e..570b36d19 100644 --- a/salt/vm_status/init.sls +++ b/salt/vm_status/init.sls @@ -9,7 +9,7 @@ # in the software, and you may not remove or obscure any functionality in the # software that is protected by the license key." -{% if 'hvn' in salt['pillar.get']('features', []) %} +{% if 'vrt' in salt['pillar.get']('features', []) %} # Send highstate trigger event for VM deployment status tracking # so-salt-emit-vm-deployment-status sets event_tag = f'soc/dyanno/hypervisor/{status.lower()}' From 8f3664f26c4dcf057e88f3ece0d2f7a2a7fc71f3 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Fri, 4 Apr 2025 09:00:22 -0400 Subject: [PATCH 165/315] need to sync --- setup/so-setup | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/setup/so-setup b/setup/so-setup index 5b8a14a01..115bdadb7 100755 --- a/setup/so-setup +++ b/setup/so-setup @@ -753,13 +753,12 @@ if ! [[ -f $install_opt_file ]]; then logCmd "salt-call state.show_top" sleep 2 # Debug RSA Key format errors logCmd "salt-key -ya $MINION_ID" + logCmd "salt-call saltutil.sync_all" # we need to sync the runner and generate the soqemussh user keys so that first highstate after license created # doesnt have a state failure for soqemussh_pub_key source for id_ed25519.pub missing if [[ $is_manager || $is_managerhype ]]; then logCmd "salt-run saltutil.sync_all" logCmd "salt-run setup_hypervisor.regenerate_ssh_keys" - else - logCmd "salt-call saltutil.sync_all" fi logCmd "salt-call state.apply common.packages" logCmd "salt-call state.apply common" From bf9f92b04eefa7b15d86fafddc4f2e9c0caf71cf Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Fri, 4 Apr 2025 13:47:54 -0400 Subject: [PATCH 166/315] remove soc_hypervisor.yaml --- salt/hypervisor/soc_hypervisor.yaml | 15 --------------- 1 file changed, 15 deletions(-) delete mode 100644 salt/hypervisor/soc_hypervisor.yaml diff --git a/salt/hypervisor/soc_hypervisor.yaml b/salt/hypervisor/soc_hypervisor.yaml deleted file mode 100644 index 571b1661d..000000000 --- a/salt/hypervisor/soc_hypervisor.yaml +++ /dev/null @@ -1,15 +0,0 @@ -# This is the start of an example of what this file will look like. It will be generated by Salt, so this yaml file is not used by Salt. -hypervisor: - hosts: - jpphype1: - add_searchnode: - description: Add a new searchnode to the hypervisor. - file: true - global: true - multiline: true - add_sensor: - description: Add a new sensor to the hypervisor. - file: true - global: true - multiline: true - guests: {} From f6a0e6285326cd613386c7fdee4f98c830d4187f Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Tue, 8 Apr 2025 09:50:26 -0400 Subject: [PATCH 167/315] include managerhype in orch. run hypervisor state before libvirt states --- salt/manager/hypervisor.sls | 2 +- salt/orch/dyanno_hypervisor.sls | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/salt/manager/hypervisor.sls b/salt/manager/hypervisor.sls index 84cd478c8..315775446 100644 --- a/salt/manager/hypervisor.sls +++ b/salt/manager/hypervisor.sls @@ -28,9 +28,9 @@ {% if ssh_user_exists and ssh_keys_exist and base_image_exists and vm_files_exist and hypervisor_host_dir_exists %} # Hypervisor environment is already set up, include the necessary states include: + - hypervisor - libvirt - libvirt.images - - hypervisor hypervisor_setup_verified: test.succeed_without_changes: diff --git a/salt/orch/dyanno_hypervisor.sls b/salt/orch/dyanno_hypervisor.sls index 859e87df6..a47e3c1b6 100644 --- a/salt/orch/dyanno_hypervisor.sls +++ b/salt/orch/dyanno_hypervisor.sls @@ -89,7 +89,7 @@ {% if vm_name and hypervisor and timestamp and status and tag %} write_vm_status: salt.state: - - tgt: 'G@role:so-manager or G@role:so-managersearch or G@role:so-standalone or G@role:so-eval' + - tgt: 'G@role:so-manager or G@role:so-managerhype or G@role:so-managersearch or G@role:so-standalone or G@role:so-eval' - tgt_type: compound - sls: - soc.dyanno.hypervisor.write_status @@ -106,7 +106,7 @@ write_vm_status: # Update hypervisor status update_hypervisor_annotation: salt.state: - - tgt: 'G@role:so-manager or G@role:so-managersearch or G@role:so-standalone or G@role:so-eval' + - tgt: 'G@role:so-manager or G@role:so-managerhype or G@role:so-managersearch or G@role:so-standalone or G@role:so-eval' - tgt_type: compound - sls: - soc.dyanno.hypervisor From 0f120f7500a57e7735b816622962d2a12448fd07 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Wed, 9 Apr 2025 11:19:18 -0400 Subject: [PATCH 168/315] ensure manager is in /etc/hosts --- salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja | 2 ++ salt/salt/cloud/init.sls | 2 ++ 2 files changed, 4 insertions(+) diff --git a/salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja b/salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja index 00b1a76c1..128dc9fc6 100644 --- a/salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja +++ b/salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja @@ -34,6 +34,8 @@ sool9-{{host}}: grains: hypervisor_host: {{host ~ "_" ~ role}} preflight_cmds: + - | + tee -a /etc/hosts <<< "{{ MANAGERIP }} {{ MANAGERHOSTNAME }}" - | timeout 600 bash -c 'trap "echo \"Preflight Check: Failed to establish repo connectivity\"; exit 1" TERM; \ while ! dnf makecache --repoid=securityonion >/dev/null 2>&1; do echo "Preflight Check: Waiting for repo connectivity..."; \ diff --git a/salt/salt/cloud/init.sls b/salt/salt/cloud/init.sls index 114133204..c2d885e3c 100644 --- a/salt/salt/cloud/init.sls +++ b/salt/salt/cloud/init.sls @@ -40,6 +40,8 @@ cloud_profiles: - source: salt://salt/cloud/cloud.profiles.d/socloud.conf.jinja - defaults: HYPERVISORS: {{HYPERVISORS}} + MANAGERHOSTNAME: {{ grains.host }} + MANAGERIP: {{ pillar.host.mainip }} - template: jinja {% for role, hosts in HYPERVISORS.items() %} From 8ab38956d19c46be66d0058174dfd62c08c5a337 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Wed, 9 Apr 2025 11:19:55 -0400 Subject: [PATCH 169/315] change from error to warning --- salt/manager/tools/sbin/so-firewall | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/manager/tools/sbin/so-firewall b/salt/manager/tools/sbin/so-firewall index 44f812cec..23a174588 100755 --- a/salt/manager/tools/sbin/so-firewall +++ b/salt/manager/tools/sbin/so-firewall @@ -89,7 +89,7 @@ def addIp(name, ip): writeYaml(hostgroupsFilename, content) logger.info(f"Successfully added IP {ip} to hostgroup {name}") else: - logger.error(f"IP {ip} already exists in hostgroup {name}") + logger.warning(f"IP {ip} already exists in hostgroup {name}") return 3 return 0 From 888ab162bdbc2ca5a7b422d63393d6ba18836d13 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Thu, 10 Apr 2025 15:04:08 -0400 Subject: [PATCH 170/315] update mine_functions and mine after mainint switch to br0. ensure br0 has ip before updating mine --- salt/libvirt/init.sls | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/salt/libvirt/init.sls b/salt/libvirt/init.sls index f82b3d9c1..1312cc112 100644 --- a/salt/libvirt/init.sls +++ b/salt/libvirt/init.sls @@ -100,8 +100,39 @@ down_original_mgmt_interface: - unless: - nmcli -f GENERAL.CONNECTION dev show {{ pillar.host.mainint }} | grep bridge-slave-{{ pillar.host.mainint }} - order: last - - onchanges_in: - - file: mine_functions + +update_mine_functions_interface: + file.replace: + - name: /etc/salt/minion.d/mine_functions.conf + - pattern: " - interface: ([a-zA-Z0-9]+)" + - repl: " - interface: br0" + - onchanges: + - cmd: down_original_mgmt_interface + +wait_for_br0_ip: + cmd.run: + - name: | + counter=0 + until ip addr show br0 | grep -q "inet "; do + sleep 1 + counter=$((counter+1)) + if [ $counter -ge 90 ]; then + echo "Timeout waiting for br0 to get an IP address" + exit 1 + fi + done + echo "br0 has IP address: $(ip addr show br0 | grep 'inet ' | awk '{print $2}')" + - timeout: 95 + - onchanges: + - file: update_mine_functions_interface + +mine_update_mine_interface: + module.run: + - mine.send: + - network.ip_addrs + - interface: br0 + - onchanges: + - cmd: wait_for_br0_ip # virtlogd service may not restart following reboot without this #semanage permissive -a virtlogd_t From 0bcb6040c9e0ccccc18ac3ca60c66679877a155b Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Fri, 18 Apr 2025 14:02:17 -0400 Subject: [PATCH 171/315] recreate sool9 if user-data or meta-data cloud-init changes --- salt/libvirt/images/init.sls | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/salt/libvirt/images/init.sls b/salt/libvirt/images/init.sls index c7734c69d..43fc400bd 100644 --- a/salt/libvirt/images/init.sls +++ b/salt/libvirt/images/init.sls @@ -29,6 +29,17 @@ manage_sha256_sool9: - source: salt://libvirt/images/sool9/sool9.sha256 - makedirs: True +# Manage cloud-init files +manage_metadata_sool9: + file.managed: + - name: /nsm/libvirt/images/sool9/meta-data + - source: salt://libvirt/images/sool9/meta-data + +manage_userdata_sool9: + file.managed: + - name: /nsm/libvirt/images/sool9/user-data + - source: salt://libvirt/images/sool9/user-data + # Manage qcow2 image manage_qcow2_sool9: file.managed: @@ -36,27 +47,14 @@ manage_qcow2_sool9: - source: salt://libvirt/images/sool9/sool9.qcow2 - onchanges: - file: manage_sha256_sool9 - -# Manage cloud-init files -manage_metadata_sool9: - file.managed: - - name: /nsm/libvirt/images/sool9/meta-data - - source: salt://libvirt/images/sool9/meta-data - - require: - - file: manage_qcow2_sool9 - -manage_userdata_sool9: - file.managed: - - name: /nsm/libvirt/images/sool9/user-data - - source: salt://libvirt/images/sool9/user-data - - require: - - file: manage_qcow2_sool9 + - file: manage_metadata_sool9 + - file: manage_userdata_sool9 manage_cidata_sool9: file.managed: - name: /nsm/libvirt/images/sool9/sool9-cidata.iso - source: salt://libvirt/images/sool9/sool9-cidata.iso - - require: + - onchanges: - file: manage_qcow2_sool9 # Define the storage pool From 285d73d52632a4b06d37166af8ab58fd934d7b07 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Fri, 18 Apr 2025 14:07:32 -0400 Subject: [PATCH 172/315] enable/disable soqemussh. allow for pw to be set --- pillar/top.sls | 5 +++ salt/_runners/setup_hypervisor.py | 29 ++++++++++--- salt/top.sls | 3 +- salt/vm/defaults.yaml | 5 +++ salt/vm/map.jinja | 25 ++++++++++++ salt/vm/soc_vm.yaml | 10 +++++ salt/{vm_status => vm/status}/init.sls | 0 salt/vm/user/init.sls | 56 ++++++++++++++++++++++++++ 8 files changed, 127 insertions(+), 6 deletions(-) create mode 100644 salt/vm/defaults.yaml create mode 100644 salt/vm/map.jinja create mode 100644 salt/vm/soc_vm.yaml rename salt/{vm_status => vm/status}/init.sls (100%) create mode 100644 salt/vm/user/init.sls diff --git a/pillar/top.sls b/pillar/top.sls index c118073a1..1fdb59deb 100644 --- a/pillar/top.sls +++ b/pillar/top.sls @@ -26,6 +26,11 @@ base: - nginx.soc_nginx - nginx.adv_nginx + 'salt-cloud:driver:libvirt': + - match: grain + - vm.soc_vm + - vm.adv_vm + '*_manager or *_managersearch or *_managerhype': - match: compound - node_data.ips diff --git a/salt/_runners/setup_hypervisor.py b/salt/_runners/setup_hypervisor.py index 35d1bad21..028771291 100644 --- a/salt/_runners/setup_hypervisor.py +++ b/salt/_runners/setup_hypervisor.py @@ -10,8 +10,6 @@ # software that is protected by the license key." """ -TODO: Remove passwd hash prior to release. used for development - This runner performs the initial setup required for hypervisor hosts in the Security Onion environment. It handles downloading the Oracle Linux KVM image, setting up SSH keys for secure communication, and creating virtual machines with cloud-init configuration. @@ -715,6 +713,24 @@ def create_vm(vm_name: str, disk_size: str = '220G'): log.error("CREATEVM: Failed to read SSH public key: %s", str(e)) return {'success': False, 'error': 'Failed to read SSH public key'} + # Read pillar data for soqemussh password hash + pillar_path = '/opt/so/saltstack/local/pillar/vm/soc_vm.sls' + password_hash = None + passwd_line = "" # Default to empty if no hash found + try: + if os.path.exists(pillar_path): + with salt.utils.files.fopen(pillar_path, 'r') as f: + pillar_data = yaml.safe_load(f) + if pillar_data: + password_hash = pillar_data.get('vm', {}).get('user', {}).get('soqemussh', {}).get('passwordHash') + if password_hash: + passwd_line = f" passwd: {password_hash}\n" + log.info("CREATEVM: Found soqemussh password hash in pillar.") + else: + log.info("CREATEVM: No soqemussh password hash found in pillar, omitting passwd line.") + except Exception as e: + log.warning(f"CREATEVM: Error reading or parsing pillar file {pillar_path}: {str(e)}. Omitting passwd line.") + # Read and encode GPG keys keys_dir = '/opt/so/saltstack/default/salt/repo/client/files/oracle/keys' oracle_key = _read_and_encode_key(os.path.join(keys_dir, 'RPM-GPG-KEY-oracle')) @@ -752,8 +768,7 @@ users: shell: /bin/bash sudo: ALL=(ALL) NOPASSWD:ALL lock_passwd: false - passwd: $6$THWuTZMZhIVMGaaw$w9kozn7z7i0Y9LRVGZwN6mcZag4vMpE3hW6eCtKNHlFpL1XLcOdiIr29JyDxx3MLBXNedIqnqcj4psqCjv58d. - ssh_authorized_keys: +{passwd_line} ssh_authorized_keys: - {ssh_pub_key} # Configure where output will go @@ -796,6 +811,10 @@ write_files: content: | {securityonion_key} +# Run on every boot - this will only run *after* the first boot and successful cloud-init run +bootcmd: + - if [ -f /var/lib/cloud/instance/boot-finished ]; then touch /etc/cloud/cloud-init.disabled; fi + runcmd: # Import GPG keys and remove repo files except securityonion.repo - rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-oracle @@ -811,7 +830,6 @@ runcmd: - pvresize /dev/vda2 - lvextend -l +100%FREE /dev/vg_main/lv_root - xfs_growfs /dev/vg_main/lv_root - - touch /etc/cloud/cloud-init.disabled - rm -f /etc/sysconfig/network-scripts/ifcfg-eth0 power_state: @@ -819,6 +837,7 @@ power_state: mode: poweroff timeout: 30 condition: True + message: Cloud-init completed, powering off """ user_data_path = os.path.join(vm_dir, 'user-data') with salt.utils.files.fopen(user_data_path, 'w') as f: diff --git a/salt/top.sls b/salt/top.sls index 4f8029706..073f24d29 100644 --- a/salt/top.sls +++ b/salt/top.sls @@ -11,7 +11,8 @@ base: 'salt-cloud:driver:libvirt': - match: grain - storage - - vm_status + - vm.status + - vm.user '*': - cron.running diff --git a/salt/vm/defaults.yaml b/salt/vm/defaults.yaml new file mode 100644 index 000000000..f9d607532 --- /dev/null +++ b/salt/vm/defaults.yaml @@ -0,0 +1,5 @@ +vm: + user: + soqemussh: + enabled: False + passwordHash: diff --git a/salt/vm/map.jinja b/salt/vm/map.jinja new file mode 100644 index 000000000..c55784e8f --- /dev/null +++ b/salt/vm/map.jinja @@ -0,0 +1,25 @@ +{# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one + or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at + https://securityonion.net/license; you may not use this file except in compliance with the + Elastic License 2.0. + + Note: Per the Elastic License 2.0, the second limitation states: + + "You may not move, change, disable, or circumvent the license key functionality + in the software, and you may not remove or obscure any functionality in the + software that is protected by the license key." #} + +{% if 'vrt' in salt['pillar.get']('features', []) %} + +{% import_yaml 'vm/defaults.yaml' as VMDEFAULTS %} +{% set VMMERGED = salt['pillar.get']('vm', VMDEFAULTS.vm, merge=True) %} + +{% else %} + +{% do salt.log.error( + 'Hypervisor nodes are a feature supported only for customers with a valid license.' + 'Contact Security Onion Solutions, LLC via our website at https://securityonionsolutions.com' + 'for more information about purchasing a license to enable this feature.' +) %} + +{% endif %} diff --git a/salt/vm/soc_vm.yaml b/salt/vm/soc_vm.yaml new file mode 100644 index 000000000..3b3cdbbfa --- /dev/null +++ b/salt/vm/soc_vm.yaml @@ -0,0 +1,10 @@ +vm: + user: + soqemussh: + enabled: + description: Enable or disable the soqemussh user. + forcedType: bool + passwordHash: + description: 'Enter a SHA-512 password hash to set the soqemussh user password. Generate this hash by running the following command on the manager: `openssl passwd -6`' + forcedType: string + global: True diff --git a/salt/vm_status/init.sls b/salt/vm/status/init.sls similarity index 100% rename from salt/vm_status/init.sls rename to salt/vm/status/init.sls diff --git a/salt/vm/user/init.sls b/salt/vm/user/init.sls new file mode 100644 index 000000000..48185a9da --- /dev/null +++ b/salt/vm/user/init.sls @@ -0,0 +1,56 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. +# +# Note: Per the Elastic License 2.0, the second limitation states: +# +# "You may not move, change, disable, or circumvent the license key functionality +# in the software, and you may not remove or obscure any functionality in the +# software that is protected by the license key." + +{% if 'vrt' in salt['pillar.get']('features', []) %} + +{% from 'vm/map.jinja' import VMMERGED %} + +{% if VMMERGED.user.soqemussh.enabled %} + +vm_user_soqemussh: + user.present: + - name: soqemussh + - shell: /bin/bash + - home: /home/soqemussh +{% if VMMERGED.user.soqemussh.passwordHash %} + - password: '{{ VMMERGED.user.soqemussh.passwordHash }}' +{% endif %} + +vm_user_soqemussh_home_directory: + file.directory: + - name: /home/soqemussh + - user: soqemussh + - group: soqemussh + - mode: 700 + - recurse: + - user + - group + +{% else %} + +vm_user_soqemussh: + user.absent: + - name: soqemussh + - force: True + +{% endif %} + +{% else %} + +{{sls}}_no_license_detected: + test.fail_without_changes: + - name: {{sls}}_no_license_detected + - comment: + - "Hypervisor nodes are a feature supported only for customers with a valid license. + Contact Security Onion Solutions, LLC via our website at https://securityonionsolutions.com + for more information about purchasing a license to enable this feature." + +{% endif %} From 4df3070a1d1ccc03a57c30c6342b87cba3041d08 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Thu, 24 Apr 2025 12:59:06 -0400 Subject: [PATCH 173/315] ensure file permissions of libvirt images --- salt/libvirt/images/init.sls | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/salt/libvirt/images/init.sls b/salt/libvirt/images/init.sls index 43fc400bd..40017b3a5 100644 --- a/salt/libvirt/images/init.sls +++ b/salt/libvirt/images/init.sls @@ -16,6 +16,15 @@ include: - libvirt.packages +nsm_libvirt_images: + file.directory: + - name: /nsm/libvirt/images/sool9 + - dir_mode: 775 + - file_mode: 640 + - recurse: + - mode + - makedirs: True + # Remove hash file if image isn't present. This will allow for the image to redownload and initialize. remove_sha256_sool9: file.absent: @@ -27,7 +36,6 @@ manage_sha256_sool9: file.managed: - name: /nsm/libvirt/images/sool9/sool9.sha256 - source: salt://libvirt/images/sool9/sool9.sha256 - - makedirs: True # Manage cloud-init files manage_metadata_sool9: From b2bd8577b97a6d9528c87a2b1f31169b65c3df8b Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Thu, 24 Apr 2025 12:59:43 -0400 Subject: [PATCH 174/315] only update mine if hypervisor provided --- salt/_runners/setup_hypervisor.py | 45 ++++++++++++++++--------------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/salt/_runners/setup_hypervisor.py b/salt/_runners/setup_hypervisor.py index 028771291..c1984760b 100644 --- a/salt/_runners/setup_hypervisor.py +++ b/salt/_runners/setup_hypervisor.py @@ -516,29 +516,30 @@ def setup_environment(vm_name: str = 'sool9', disk_size: str = '220G', minion_id 'vm_result': None } - # Initialize the LocalClient - local = salt.client.LocalClient() - - # Add retry logic for mine.update - max_retries = 10 - retry_delay = 3 - mine_update_success = False - - for attempt in range(1, max_retries + 1): - mine_update_result = local.cmd(minion_id, 'mine.update') - log.debug(f"DYANNO: mine_update_result: {mine_update_result}") + if minion_id: + # Initialize the LocalClient + local = salt.client.LocalClient() - # Check if mine.update was successful - if mine_update_result and all(mine_update_result.values()): - log.info(f"DYANNO: mine.update successful on attempt {attempt}") - mine_update_success = True - break - else: - log.warning(f"DYANNO: mine.update failed on attempt {attempt}/{max_retries}, retrying in {retry_delay} seconds...") - time.sleep(retry_delay) - - if not mine_update_success: - log.error(f"DYANNO: mine.update failed after {max_retries} attempts") + # Add retry logic for mine.update + max_retries = 10 + retry_delay = 3 + mine_update_success = False + + for attempt in range(1, max_retries + 1): + mine_update_result = local.cmd(minion_id, 'mine.update') + log.debug(f"DYANNO: mine_update_result: {mine_update_result}") + + # Check if mine.update was successful + if mine_update_result and all(mine_update_result.values()): + log.info(f"DYANNO: mine.update successful on attempt {attempt}") + mine_update_success = True + break + else: + log.warning(f"DYANNO: mine.update failed on attempt {attempt}/{max_retries}, retrying in {retry_delay} seconds...") + time.sleep(retry_delay) + + if not mine_update_success: + log.error(f"DYANNO: mine.update failed after {max_retries} attempts") # Apply the soc.dyanno.hypervisor state on the salt master if not _apply_dyanno_hypervisor_state(): From 151db2af30aa7bc17e11f0b553e1d4784aa03917 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Mon, 28 Apr 2025 15:38:29 -0400 Subject: [PATCH 175/315] ensure ownership and mode --- salt/_runners/setup_hypervisor.py | 40 +++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/salt/_runners/setup_hypervisor.py b/salt/_runners/setup_hypervisor.py index c1984760b..6db1def5c 100644 --- a/salt/_runners/setup_hypervisor.py +++ b/salt/_runners/setup_hypervisor.py @@ -86,6 +86,19 @@ formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(messag stream_handler.setFormatter(formatter) log.addHandler(stream_handler) +def _set_ownership_and_perms(path: str, mode: int): + """Set ownership to socore:socore and apply file mode.""" + try: + socore_uid = pwd.getpwnam('socore').pw_uid + socore_gid = pwd.getpwnam('socore').pw_gid + os.chown(path, socore_uid, socore_gid) + os.chmod(path, mode) + log.debug(f"PERMS: Set ownership socore:socore and mode {oct(mode)} for {path}") + except KeyError: + log.warning(f"PERMS: socore user not found, skipping ownership/permission change for {path}") + except Exception as e: + log.warning(f"PERMS: Failed to set ownership/permissions for {path}: {str(e)}") + def _read_and_encode_key(key_path: str) -> str: """Read a key file and return its base64 encoded content.""" try: @@ -704,6 +717,8 @@ def create_vm(vm_name: str, disk_size: str = '220G'): base_dir = '/opt/so/saltstack/local/salt/libvirt/images' vm_dir = f'{base_dir}/{vm_name}' os.makedirs(vm_dir, exist_ok=True) + # Set ownership and permissions for the VM directory + _set_ownership_and_perms(vm_dir, mode=0o750) # Read the SSH public key pub_key_path = '/opt/so/saltstack/local/salt/libvirt/ssh/keys/id_ed25519.pub' @@ -745,15 +760,23 @@ def create_vm(vm_name: str, disk_size: str = '220G'): local-hostname: {vm_name} """ meta_data_path = os.path.join(vm_dir, 'meta-data') + # Create empty file, set perms, then write + open(meta_data_path, 'a').close() + _set_ownership_and_perms(meta_data_path, mode=0o640) with salt.utils.files.fopen(meta_data_path, 'w') as f: f.write(meta_data) + log.info("CREATEVM: Created meta-data") # Create network-data network_data = """network: config: disabled""" network_data_path = os.path.join(vm_dir, 'network-data') + # Create empty file, set perms, then write + open(network_data_path, 'a').close() + _set_ownership_and_perms(network_data_path, mode=0o640) with salt.utils.files.fopen(network_data_path, 'w') as f: f.write(network_data) + log.info("CREATEVM: Created network-data") # Create user-data user_data = f"""#cloud-config @@ -841,8 +864,12 @@ power_state: message: Cloud-init completed, powering off """ user_data_path = os.path.join(vm_dir, 'user-data') + # Create empty file, set perms, then write + open(user_data_path, 'a').close() + _set_ownership_and_perms(user_data_path, mode=0o640) with salt.utils.files.fopen(user_data_path, 'w') as f: f.write(user_data) + log.info("CREATEVM: Created user-data") # Copy and resize base image base_image = IMAGE_PATH @@ -852,8 +879,10 @@ power_state: import shutil log.info("CREATEVM: Copying base image to %s", vm_image) shutil.copy2(base_image, vm_image) + # Set ownership and permissions for the copied image + _set_ownership_and_perms(vm_image, mode=0o640) log.info("CREATEVM: Base image copy complete") - + # Get current image size import subprocess try: @@ -908,6 +937,8 @@ power_state: # Check if compression completed successfully if process.returncode == 0: os.replace(temp_image, vm_image) + # Set ownership and permissions for the compressed image + _set_ownership_and_perms(vm_image, mode=0o640) log.info("CREATEVM: Image compression complete") else: error = process.stderr.read().decode('utf-8') @@ -921,6 +952,9 @@ power_state: subprocess.run(['mkisofs', '-output', cidata_iso, '-volid', 'CIDATA', '-rock', user_data_path, meta_data_path, network_data_path], check=True, capture_output=True) + # Set ownership and permissions for the created ISO + _set_ownership_and_perms(cidata_iso, mode=0o640) + log.info("CREATEVM: Created cidata ISO") # Generate SHA256 hash of the qcow2 image sha256_hash = hashlib.sha256() @@ -932,7 +966,9 @@ power_state: hash_file = os.path.join(vm_dir, f'{vm_name}.sha256') with salt.utils.files.fopen(hash_file, 'w') as f: f.write(sha256_hash.hexdigest()) - + # Set ownership and permissions for the hash file + _set_ownership_and_perms(hash_file, mode=0o640) + log.info("CREATEVM: Generated SHA256 hash for %s", vm_image) return { From 6246e25fbeb60c453770ef5e65f3a678ad0d741e Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Tue, 29 Apr 2025 10:19:01 -0400 Subject: [PATCH 176/315] 640 for pubkey and empty pillar --- salt/_runners/setup_hypervisor.py | 2 +- salt/reactor/createEmptyPillar.sls | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/salt/_runners/setup_hypervisor.py b/salt/_runners/setup_hypervisor.py index 6db1def5c..fd1496c85 100644 --- a/salt/_runners/setup_hypervisor.py +++ b/salt/_runners/setup_hypervisor.py @@ -300,7 +300,7 @@ def _setup_ssh_keys(): # Set proper permissions os.chmod(key_path, 0o600) - os.chmod(pub_key_path, 0o644) + os.chmod(pub_key_path, 0o640) log.info("SETUP_KEYS: SSH keys generated successfully") diff --git a/salt/reactor/createEmptyPillar.sls b/salt/reactor/createEmptyPillar.sls index dccf25f89..c6c655bab 100644 --- a/salt/reactor/createEmptyPillar.sls +++ b/salt/reactor/createEmptyPillar.sls @@ -29,7 +29,7 @@ def run(): # Set ownership to socore:socore os.chown(full_path, socore_uid, socore_gid) # Set mode to 644 (rw-r--r--) - os.chmod(full_path, 0o644) + os.chmod(full_path, 0o640) logging.error("createEmptyPillar reactor: created %s with socore:socore ownership and mode 644" % f) except (KeyError, OSError) as e: From c3b3e0ab2142a4032f2bd66af7f2e0cbd54f1d50 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Wed, 30 Apr 2025 08:12:35 -0400 Subject: [PATCH 177/315] manager hostname in pubkey --- salt/_runners/setup_hypervisor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/_runners/setup_hypervisor.py b/salt/_runners/setup_hypervisor.py index fd1496c85..618da9dd8 100644 --- a/salt/_runners/setup_hypervisor.py +++ b/salt/_runners/setup_hypervisor.py @@ -289,7 +289,7 @@ def _setup_ssh_keys(): encoding=serialization.Encoding.OpenSSH, format=serialization.PublicFormat.OpenSSH ) - public_bytes = public_bytes + b' soqemussh@salt-master\n' + public_bytes = public_bytes + f' soqemussh@{MANAGER_HOSTNAME}\n'.encode('utf-8') # Write the keys to files with salt.utils.files.fopen(key_path, 'wb') as f: From 7a60afdd5a2f3f0abe5411d7f1843c16aa812d54 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Wed, 30 Apr 2025 09:11:55 -0400 Subject: [PATCH 178/315] remove duplicate logging --- salt/_runners/setup_hypervisor.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/salt/_runners/setup_hypervisor.py b/salt/_runners/setup_hypervisor.py index 618da9dd8..dc0d9eca8 100644 --- a/salt/_runners/setup_hypervisor.py +++ b/salt/_runners/setup_hypervisor.py @@ -79,12 +79,6 @@ from cryptography.hazmat.primitives.asymmetric import ed25519 log = logging.getLogger(__name__) log.setLevel(logging.DEBUG) -# Ensure we have a stream handler -stream_handler = logging.StreamHandler(sys.stdout) -stream_handler.setLevel(logging.DEBUG) -formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') -stream_handler.setFormatter(formatter) -log.addHandler(stream_handler) def _set_ownership_and_perms(path: str, mode: int): """Set ownership to socore:socore and apply file mode.""" From 5a8e542f968df3e74fc29f5173dc44441a604af5 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Wed, 30 Apr 2025 13:08:54 -0400 Subject: [PATCH 179/315] create macro for resource regex and fix regex logic for mem and cpu --- .../hypervisor/soc_hypervisor.yaml.jinja | 81 ++++++++++--------- 1 file changed, 45 insertions(+), 36 deletions(-) diff --git a/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja b/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja index 8976e7cc7..8ac7a7225 100644 --- a/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja +++ b/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja @@ -68,6 +68,49 @@ Base domain has not been initialized. {{- available | join(',') -}} {%- endmacro -%} +{%- macro update_resource_field(field, free_value, total_value, unit_label) -%} +{%- set resource_regex = '' -%} +{%- if free_value < 10 -%} +{%- set resource_regex = '^[1-' ~ free_value ~ ']$' -%} +{%- elif free_value < 100 -%} +{%- set tens_digit = free_value // 10 -%} +{%- set ones_digit = free_value % 10 -%} +{%- if ones_digit == 0 -%} +{%- set resource_regex = '^([1-9]|[1-' ~ (tens_digit-1) ~ '][0-9]|' ~ tens_digit ~ '0)$' -%} +{%- else -%} +{%- set resource_regex = '^([1-9]|[1-' ~ (tens_digit-1) ~ '][0-9]|' ~ tens_digit ~ '[0-' ~ ones_digit ~ '])$' -%} +{%- endif -%} +{%- elif free_value < 1000 -%} +{%- set hundreds_digit = free_value // 100 -%} +{%- set tens_digit = (free_value % 100) // 10 -%} +{%- set ones_digit = free_value % 10 -%} +{%- if hundreds_digit == 1 -%} +{%- if tens_digit == 0 and ones_digit == 0 -%} +{%- set resource_regex = '^([1-9]|[1-9][0-9]|100)$' -%} +{%- elif tens_digit == 0 -%} +{%- set resource_regex = '^([1-9]|[1-9][0-9]|10[0-' ~ ones_digit ~ '])$' -%} +{%- elif ones_digit == 0 -%} +{%- set resource_regex = '^([1-9]|[1-9][0-9]|10[0-9]|1[1-' ~ tens_digit ~ ']0)$' -%} +{%- else -%} +{%- set resource_regex = '^([1-9]|[1-9][0-9]|10[0-9]|1[1-' ~ (tens_digit-1) ~ '][0-9]|1' ~ tens_digit ~ '[0-' ~ ones_digit ~ '])$' -%} +{%- endif -%} +{%- else -%} +{%- if tens_digit == 0 and ones_digit == 0 -%} +{%- set resource_regex = '^([1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-' ~ (hundreds_digit-1) ~ '][0-9][0-9]|' ~ hundreds_digit ~ '00)$' -%} +{%- elif ones_digit == 0 -%} +{%- set resource_regex = '^([1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-' ~ (hundreds_digit-1) ~ '][0-9][0-9]|' ~ hundreds_digit ~ '[0-' ~ tens_digit ~ ']0)$' -%} +{%- else -%} +{%- set resource_regex = '^([1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-' ~ (hundreds_digit-1) ~ '][0-9][0-9]|' ~ hundreds_digit ~ '[0-' ~ (tens_digit-1) ~ '][0-9]|' ~ hundreds_digit ~ tens_digit ~ '[0-' ~ ones_digit ~ '])$' -%} +{%- endif -%} +{%- endif -%} +{%- endif -%} +{%- do field.update({ + 'label': field.label | replace('FREE', free_value | string) | replace('TOTAL', total_value | string), + 'regex': resource_regex, + 'regexFailureMessage': 'Enter a value not exceeding ' ~ free_value | string ~ ' ' ~ unit_label + }) -%} +{%- endmacro -%} + {%- for role in HYPERVISORS -%} {%- for hypervisor in HYPERVISORS[role].keys() -%} {%- set hw_config = HYPERVISORS[role][hypervisor].hardware -%} @@ -122,43 +165,9 @@ Base domain has not been initialized. {%- for field in updated_template.uiElements -%} {%- set updated_field = field.copy() -%} {%- if field.field == 'cpu' -%} -{%- if cpu_free < 10 -%} -{%- set cpu_regex = '^[1-' ~ cpu_free ~ ']$' -%} -{%- elif cpu_free < 100 -%} -{%- set tens_digit = cpu_free // 10 -%} -{%- set ones_digit = cpu_free % 10 -%} -{%- if ones_digit == 0 -%} -{%- set cpu_regex = '^([1-9]|[1-' ~ (tens_digit-1) ~ '][0-9]|' ~ tens_digit ~ '0)$' -%} -{%- else -%} -{%- set cpu_regex = '^([1-9]|[1-' ~ (tens_digit-1) ~ '][0-9]|' ~ tens_digit ~ '[0-' ~ ones_digit ~ '])$' -%} -{%- endif -%} -{%- else -%} -{%- set cpu_regex = '^([1-9]|[1-9][0-9]|100)$' -%} -{%- endif -%} -{%- do updated_field.update({ - 'label': field.label | replace('FREE', cpu_free | string) | replace('TOTAL', cpu_total | string), - 'regex': cpu_regex, - 'regexFailureMessage': 'Enter a value not exceeding ' ~ cpu_free | string ~ ' cores' - }) -%} +{%- do update_resource_field(updated_field, cpu_free, cpu_total, 'cores') -%} {%- elif field.field == 'memory' -%} -{%- if mem_free < 10 -%} -{%- set mem_regex = '^[1-' ~ mem_free ~ ']$' -%} -{%- elif mem_free < 100 -%} -{%- set tens_digit = mem_free // 10 -%} -{%- set ones_digit = mem_free % 10 -%} -{%- if ones_digit == 0 -%} -{%- set mem_regex = '^([1-9]|[1-' ~ (tens_digit-1) ~ '][0-9]|' ~ tens_digit ~ '0)$' -%} -{%- else -%} -{%- set mem_regex = '^([1-9]|[1-' ~ (tens_digit-1) ~ '][0-9]|' ~ tens_digit ~ '[0-' ~ ones_digit ~ '])$' -%} -{%- endif -%} -{%- else -%} -{%- set mem_regex = '^([1-9]|[1-9][0-9]|[1-9][0-9][0-9])$' -%} -{%- endif -%} -{%- do updated_field.update({ - 'label': field.label | replace('FREE', mem_free | string) | replace('TOTAL', mem_total | string), - 'regex': mem_regex, - 'regexFailureMessage': 'Enter a value not exceeding ' ~ mem_free | string ~ ' GB' - }) -%} +{%- do update_resource_field(updated_field, mem_free, mem_total, 'GB') -%} {%- elif field.field == 'disk' -%} {%- set disk_free_list = disk_free.split(',') if disk_free else [] -%} {%- do updated_field.update({ From 3a31d80a856860d3d95d53b5ae518106204833f5 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Wed, 30 Apr 2025 13:10:49 -0400 Subject: [PATCH 180/315] fix regex and label for hypervisor annotation --- salt/soc/dyanno/hypervisor/hypervisor.yaml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/salt/soc/dyanno/hypervisor/hypervisor.yaml b/salt/soc/dyanno/hypervisor/hypervisor.yaml index 6b0458265..a629aebfd 100644 --- a/salt/soc/dyanno/hypervisor/hypervisor.yaml +++ b/salt/soc/dyanno/hypervisor/hypervisor.yaml @@ -31,22 +31,22 @@ hypervisor: - static4 - dhcp4 - field: ip4 - label: "IP Address with netmask. ex. 192.168.1.10/24" + label: "IP address with netmask: 192.168.1.10/24 - If using dhcp, enter a character in this field and delete it. This will eliminate the incomplete/invalid setting entry error as well as the improperly formatted address error." forcedType: string - regex: '^(\d{1,3}\.){3}\d{1,3}/\d{1,2}$' + regex: "^$|^(\\d{1,3}\\.){3}\\d{1,3}/\\d{1,2}$" regexFailureMessage: "Enter a properly formatted CIDR address" readonly: true - field: gw4 - label: "Gateway" + label: "Gateway - If using dhcp, enter a character in this field and delete it. This will eliminate the incomplete/invalid setting entry error as well as the improperly formatted address error." forcedType: string - regex: '^(\d{1,3}\.){3}\d{1,3}$' + regex: "^$|^(\\d{1,3}\\.){3}\\d{1,3}$" regexFailureMessage: "Enter a properly formatted IP address" readonly: true - field: dns4 - label: "DNS. Comma separated list. ex. 192.168.1.1,8.8.8.8" + label: "Single DNS IP or comma separated list: 192.168.1.1,8.8.8.8 - If using dhcp, enter a character in this field and delete it. This will eliminate the incomplete/invalid setting entry error as well as the improperly formatted address error." forcedType: string - regex: '^(\d{1,3}\.){3}\d{1,3}$' - regexFailureMessage: "Enter a properly formatted IP address" + regex: "^$|^(\\d{1,3}\\.){3}\\d{1,3}(,\\s*(\\d{1,3}\\.){3}\\d{1,3})*$" + regexFailureMessage: "Enter a properly formatted IP address or list of addresses" readonly: true - field: search4 label: "Search domain" From e5c0f8a46c2db337f97a8f195daa0ad4e18017fa Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Wed, 30 Apr 2025 16:09:57 -0400 Subject: [PATCH 181/315] allow for dhcp4 --- salt/manager/tools/sbin_jinja/so-salt-cloud | 24 +++++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/salt/manager/tools/sbin_jinja/so-salt-cloud b/salt/manager/tools/sbin_jinja/so-salt-cloud index f1346130f..bf15efcc2 100644 --- a/salt/manager/tools/sbin_jinja/so-salt-cloud +++ b/salt/manager/tools/sbin_jinja/so-salt-cloud @@ -504,16 +504,26 @@ def run_qcow2_modify_network_config(profile, vm_name, mode, ip=None, gateway=Non interface = 'enp1s0' try: - result = local.cmd(target, 'qcow2.modify_network_config', [ + # Base arguments that are always included + args = [ 'image=' + image, 'interface=' + interface, 'mode=' + mode, - 'vm_name=' + vm_name, - 'ip4=' + ip if ip else '', - 'gw4=' + gateway if gateway else '', - 'dns4=' + dns if dns else '', - 'search4=' + search_domain if search_domain else '' - ]) + 'vm_name=' + vm_name + ] + + # Only include IP-related arguments if not using DHCP + if mode != "dhcp4": + if ip: + args.append('ip4=' + ip) + if gateway: + args.append('gw4=' + gateway) + if dns: + args.append('dns4=' + dns) + if search_domain: + args.append('search4=' + search_domain) + + result = local.cmd(target, 'qcow2.modify_network_config', args) format_qcow2_output('Network configuration', result) except Exception as e: logger.error(f"An error occurred while running qcow2.modify_network_config: {e}") From 26d7ceebb22b92f03c7df1c486097a2061e9426c Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Fri, 2 May 2025 11:30:35 -0400 Subject: [PATCH 182/315] libvirt.images requires scripts from hypervisor state --- salt/libvirt/images/init.sls | 1 + salt/top.sls | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/salt/libvirt/images/init.sls b/salt/libvirt/images/init.sls index 40017b3a5..6ed472405 100644 --- a/salt/libvirt/images/init.sls +++ b/salt/libvirt/images/init.sls @@ -14,6 +14,7 @@ {% if 'vrt' in salt['pillar.get']('features', []) %} include: + - hypervisor - libvirt.packages nsm_libvirt_images: diff --git a/salt/top.sls b/salt/top.sls index 073f24d29..a75346462 100644 --- a/salt/top.sls +++ b/salt/top.sls @@ -306,9 +306,9 @@ base: - sensoroni - telegraf - firewall + - hypervisor - libvirt - libvirt.images - - hypervisor - elasticfleet.install_agent_grid - stig From a167e5e5206ecfe1e388b23b7909c9e05bb7e669 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Fri, 2 May 2025 11:32:03 -0400 Subject: [PATCH 183/315] fix whitespace for multiple hypervisors --- salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja b/salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja index 128dc9fc6..0b795a8ab 100644 --- a/salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja +++ b/salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja @@ -3,10 +3,8 @@ https://securityonion.net/license; you may not use this file except in compliance with the Elastic License 2.0. #} -{#- https://docs.saltproject.io/en/latest/topics/cloud/misc.html #} - {%- for role, hosts in HYPERVISORS.items() %} -{%- for host in hosts.keys() -%} +{%- for host in hosts.keys() %} sool9-{{host}}: provider: kvm-ssh-{{host}} @@ -20,10 +18,6 @@ sool9-{{host}}: minion: master: {{ grains.host }} master_port: 4506 - #startup_states: sls - #sls_list: - # - setup.virt.initial_schedule - # - setup.virt.setHostname use_superseded: - module.run features: @@ -52,7 +46,6 @@ sool9-{{host}}: - | salt-call state.apply setup.virt \ pillar='{"host": {"mainint": "enp1s0"}}' - # grains to add to the minion {%- endfor %} {%- endfor %} From a595bc4b31c4947d4580786d7e74f5ea93cc2edf Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Tue, 6 May 2025 10:13:02 -0400 Subject: [PATCH 184/315] info to debug log level --- salt/salt/engines/master/virtual_node_manager.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/salt/salt/engines/master/virtual_node_manager.py b/salt/salt/engines/master/virtual_node_manager.py index 78f8f0294..e7c28ef6a 100644 --- a/salt/salt/engines/master/virtual_node_manager.py +++ b/salt/salt/engines/master/virtual_node_manager.py @@ -594,7 +594,7 @@ def validate_vrt_license() -> bool: "for more information about purchasing a license to enable this feature.") return False - log.info("License validation successful") + log.debug("License validation successful") return True except Exception as e: @@ -887,7 +887,7 @@ def start(interval: int = DEFAULT_INTERVAL, - Admin must restart service to clear lock - Error-level logging used for lock issues """ - log.info("Starting virtual node manager engine") + log.debug("Starting virtual node manager engine") if not validate_vrt_license(): return @@ -908,7 +908,7 @@ def start(interval: int = DEFAULT_INTERVAL, # Clean shutdown - release lock log.debug("Virtual node manager releasing lock") engine_lock.release() - log.info("Virtual node manager completed successfully") + log.debug("Virtual node manager completed successfully") except Exception as e: log.error("Error in virtual node manager - lock will remain until cleared: %s", str(e)) From ef436026d55d520dcc4f8aa214d9407e8658f052 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Tue, 6 May 2025 11:51:59 -0400 Subject: [PATCH 185/315] info to debug. remove old reactors --- salt/reactor/setHostname.sls | 22 --- salt/reactor/setSalt.sls | 22 --- salt/reactor/sominion.sls | 21 --- salt/reactor/virtReleaseHardware.sls | 74 ----------- salt/reactor/virtUpdate.sls | 125 ------------------ .../engines/master/virtual_power_manager.py | 4 +- 6 files changed, 2 insertions(+), 266 deletions(-) delete mode 100644 salt/reactor/setHostname.sls delete mode 100644 salt/reactor/setSalt.sls delete mode 100644 salt/reactor/sominion.sls delete mode 100644 salt/reactor/virtReleaseHardware.sls delete mode 100644 salt/reactor/virtUpdate.sls diff --git a/salt/reactor/setHostname.sls b/salt/reactor/setHostname.sls deleted file mode 100644 index 3733a71bb..000000000 --- a/salt/reactor/setHostname.sls +++ /dev/null @@ -1,22 +0,0 @@ -#!py - -# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one -# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at -# https://securityonion.net/license; you may not use this file except in compliance with the -# Elastic License 2.0. - -import logging -import salt.client -local = salt.client.LocalClient() - -def run(): - - vm_name = data['name'] - logging.error("setHostname reactor: start for: %s " % vm_name) - - r = local.cmd(vm_name, 'state.apply', ['setup.virt.setHostname']) - - logging.error("setHostname reactor: return for %s: %s " % (vm_name,r)) - logging.error("setHostname reactor: end for: %s " % vm_name) - - return {} diff --git a/salt/reactor/setSalt.sls b/salt/reactor/setSalt.sls deleted file mode 100644 index 5d8b33a4a..000000000 --- a/salt/reactor/setSalt.sls +++ /dev/null @@ -1,22 +0,0 @@ -#!py - -# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one -# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at -# https://securityonion.net/license; you may not use this file except in compliance with the -# Elastic License 2.0. - -import logging -import salt.client -local = salt.client.LocalClient() - -def run(): - - vm_name = data['name'] - logging.error("setSalt reactor: start for: %s " % vm_name) - - r = local.cmd(vm_name, 'state.apply', ['setup.virt.setSalt']) - - logging.error("setSalt reactor: return for: %s: %s " % (vm_name,r)) - logging.error("setSalt reactor: end for: %s " % vm_name) - - return {} diff --git a/salt/reactor/sominion.sls b/salt/reactor/sominion.sls deleted file mode 100644 index 24b448f2e..000000000 --- a/salt/reactor/sominion.sls +++ /dev/null @@ -1,21 +0,0 @@ -#!py - -# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one -# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at -# https://securityonion.net/license; you may not use this file except in compliance with the -# Elastic License 2.0. - -import logging -import salt.client -local = salt.client.LocalClient() - -def run(): - - vm_name = data['name'] - logging.error("sominion reactor: start for: %s " % vm_name) - - r = local.cmd(vm_name, 'state.apply', ['setup.virt.sominion']) - - logging.error("sominion reactor: end for: %s " % vm_name) - - return {} diff --git a/salt/reactor/virtReleaseHardware.sls b/salt/reactor/virtReleaseHardware.sls deleted file mode 100644 index 8e95e080f..000000000 --- a/salt/reactor/virtReleaseHardware.sls +++ /dev/null @@ -1,74 +0,0 @@ -#!py - -# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one -# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at -# https://securityonion.net/license; you may not use this file except in compliance with the -# Elastic License 2.0. - -import logging -import yaml -import os -import glob - -def run(): - - def release_compute(): - compute = hv_data['hypervisor']['hardware'][hw_type] - compute.update({'free': compute.get('free') + vm_data.get(hw_type)}) - logging.error("virtReboot reactor: claiming %s compute: %s " % (hw_type,compute)) - - def release_pci(): - free_hw = hv_data['hypervisor']['hardware'][hw_type]['free'] - # this could be 0 if nothing is assigned - if vm_data[hw_type] != 0: - for hw in vm_data[hw_type]: - f_hw = {hw: hv_data['hypervisor']['hardware'][hw_type]['claimed'].pop(hw)} - free_hw.update(f_hw) - logging.error("virtReleaseHardware reactor: released %s: %s" % (hw_type, f_hw)) - - def get_hypervisor(): - base_dir = '/opt/so/saltstack/local/pillar/hypervisor' - pattern = os.path.join(base_dir, '**', vm_name + '.sls') - files = glob.glob(pattern, recursive=True) - logging.error("virtReleaseHardware reactor: files: %s " % files) - if files: - return files[0].split('/')[7] - - vm_name = data['name'] - # since the vm has been destroyed, we can't get the hypervisor_host grain - hv_name = get_hypervisor() - logging.error("virtReleaseHardware reactor: hv_name: %s " % hv_name) - - with open("/opt/so/saltstack/local/pillar/hypervisor/" + hv_name + "/" + vm_name + ".sls") as f: - try: - vm_data=yaml.safe_load(f) - logging.error("virtReleaseHardware reactor: vm_data %s " % vm_data) - #logging.error(yaml.safe_load(f)) - except yaml.YAMLError as exc: - logging.error(exc) - - with open("/opt/so/saltstack/local/pillar/hypervisor/" + hv_name + "/" + hv_name + ".sls") as f: - try: - hv_data=yaml.safe_load(f) - logging.error("virtReleaseHardware reactor: hv_data: %s " % hv_data) - #logging.error(yaml.safe_load(f)) - except yaml.YAMLError as exc: - logging.error(exc) - - for hw_type in ['disks', 'copper', 'sfp']: - release_pci() - - for hw_type in ['cpu', 'memory']: - release_compute() - - # update the free hardware for the hypervisor - with open("/opt/so/saltstack/local/pillar/hypervisor/" + hv_name + "/" + hv_name + ".sls", 'w') as f: - yaml.dump(hv_data, f, default_flow_style=False) - - # remove the old vm_data file since the vm has been purged - os.remove("/opt/so/saltstack/local/pillar/hypervisor/" + hv_name + "/" + vm_name + ".sls") - # remove minion pillar files - os.remove("/opt/so/saltstack/local/pillar/minions/adv_" + vm_name + ".sls") - os.remove("/opt/so/saltstack/local/pillar/minions/" + vm_name + ".sls") - - return {} diff --git a/salt/reactor/virtUpdate.sls b/salt/reactor/virtUpdate.sls deleted file mode 100644 index 2e691b5b1..000000000 --- a/salt/reactor/virtUpdate.sls +++ /dev/null @@ -1,125 +0,0 @@ -#!py - -# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one -# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at -# https://securityonion.net/license; you may not use this file except in compliance with the -# Elastic License 2.0. - -import logging -import salt.client -local = salt.client.LocalClient() -import yaml -from time import sleep - -def run(): - - def claim_compute(hw_type): - compute = hv_data['hypervisor']['hardware'][hw_type] - compute.update({'free': compute.get('free') - vm_data.get(hw_type)}) - logging.error("virtUpdate reactor: claiming %s compute: %s " % (hw_type,compute)) - - def claim_pci(hw_type): - claimed_hw = hv_data['hypervisor']['hardware'][hw_type]['claimed'] - # if a list of devices was defined - if type(vm_data[hw_type]) == list: - for hw in vm_data[hw_type]: - try: - c_hw = {hw: hv_data['hypervisor']['hardware'][hw_type]['free'].pop(hw)} - claimed_hw.update(c_hw) - host_devices.append(c_hw[hw]) - except KeyError: - logging.error("virtUpdate reactor: could not claim %s with key %s " % (hw_type,hw)) - return {'key1': 'val1'} - # if a number of devices was defined - else: - n = vm_data[hw_type] - vm_data[hw_type] = [] - # grab the first number of devices as defined for the node type - claiming_hw = list(hv_data['hypervisor']['hardware'][hw_type]['free'].items())[:n] - logging.error("virtUpdate reactor: claiming %s hardware: %s " % (hw_type,claiming_hw)) - # claiming_hw is a list of tuples containing (numerical_id, pci_id) - # claiming_hw example: [(1, 'pci_0000_c4_00_0'), (2, 'pci_0000_c4_00_1')] - for hw in claiming_hw: - c_hw = {hw[0]: hv_data['hypervisor']['hardware'][hw_type]['free'].pop(hw[0])} - claimed_hw.update(c_hw) - vm_data[hw_type].append(hw[0]) - host_devices.append(hw[1]) - logging.error("virtUpdate reactor: claimed_hw: %s " % claimed_hw) - - vm_name = data['id'] - logging.error("virtUpdate reactor: vm_name: %s " % vm_name) - hv_name = local.cmd(vm_name, 'grains.get', ['hypervisor_host']).get(vm_name) - logging.error("virtUpdate reactor: hv_name: %s " % hv_name) - - host_devices = [] - - with open("/opt/so/saltstack/local/pillar/hypervisor/" + hv_name + "/" + vm_name + ".sls") as f: - try: - vm_data=yaml.safe_load(f) - logging.error("virtUpdate reactor: vm_data %s " % vm_data) - #logging.error(yaml.safe_load(f)) - except yaml.YAMLError as exc: - logging.error(exc) - - with open("/opt/so/saltstack/local/pillar/hypervisor/" + hv_name + "/" + hv_name + ".sls") as f: - try: - hv_data=yaml.safe_load(f) - logging.error("virtUpdate reactor: hv_data: %s " % hv_data) - #logging.error(yaml.safe_load(f)) - except yaml.YAMLError as exc: - logging.error(exc) - - r = local.cmd(hv_name, 'virt.shutdown', ['vm_=' + vm_name]) - logging.error("virtUpdate reactor: virt.shutdown: %s return: %s " % (vm_name,r)) - - c = 0 - while True: - if c == 60: - logging.error("virtUpdate reactor: vm_name: %s failed virt.shutdown in time " % vm_name) - return {} - r = local.cmd(hv_name, 'virt.shutdown', ['vm_=' + vm_name]) - logging.error("virtUpdate reactor: virt.shutdown: %s return: %s " % (vm_name,r)) - if r.get(hv_name): - break - c += 1 - sleep(1) - - c = 0 - while True: - if c == 60: - logging.error("virtUpdate reactor: vm_name: %s failed to go inactive in time " % vm_name) - return {} - r = local.cmd(hv_name, 'virt.list_inactive_vms') - logging.error("virtUpdate reactor: virt.list_inactive_vms: %s " % r.get(hv_name)) - if vm_name in r.get(hv_name): - break - c += 1 - sleep(1) - - for hw_type in ['disks', 'copper', 'sfp']: - claim_pci(hw_type) - - for hw_type in ['cpu', 'memory']: - claim_compute(hw_type) - - logging.error("virtUpdate reactor: host_devices: %s " % host_devices) - - # update the claimed hardware for the hypervisor - with open("/opt/so/saltstack/local/pillar/hypervisor/" + hv_name + "/" + hv_name + ".sls", 'w') as f: - yaml.dump(hv_data, f, default_flow_style=False) - - # since the original hw request provided was a count of hw instead of specific pci ids - # we need to update the vm_data file with the assigned pci ids that were claimed - # update the vm_data file with the hardware it claimed - logging.error("virtUpdate reactor: new vm_data: %s " % vm_data) - with open("/opt/so/saltstack/local/pillar/hypervisor/" + hv_name + "/" + vm_name + ".sls", 'w') as f: - yaml.dump(vm_data, f, default_flow_style=False) - - mem = vm_data['memory'] * 1024 - r = local.cmd(hv_name, 'virt.update', ['name=' + vm_name, 'mem=' + str(mem), 'cpu=' + str(vm_data['cpu']), 'host_devices=' + str(host_devices)]) - logging.error("virtUpdate reactor: virt.update: vm_name: %s return: %s" % (vm_name,r)) - - r = local.cmd(hv_name, 'virt.start', ['name=' + vm_name]) - logging.error("virtUpdate reactor: virt.start: vm_name: %s return: %s" % (vm_name,r)) - - return {} diff --git a/salt/salt/engines/master/virtual_power_manager.py b/salt/salt/engines/master/virtual_power_manager.py index 8cca82606..de4b3bc7d 100644 --- a/salt/salt/engines/master/virtual_power_manager.py +++ b/salt/salt/engines/master/virtual_power_manager.py @@ -316,7 +316,7 @@ def start(interval: int = DEFAULT_INTERVAL, interval: Time in seconds between engine runs (managed by salt-master) base_path: Base path containing hypervisor configurations """ - log.info("Starting virtual power manager engine") + log.debug("Starting virtual power manager engine") try: # Process each hypervisor directory @@ -324,7 +324,7 @@ def start(interval: int = DEFAULT_INTERVAL, if os.path.isdir(hypervisor_path): process_hypervisor_power_requests(hypervisor_path) - log.info("Virtual power manager completed successfully") + log.debug("Virtual power manager completed successfully") except Exception as e: log.error("Error in virtual power manager: %s", str(e)) From 9e0f13cce5f89c2b6815bde09ce90e43fd5b5e37 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Wed, 7 May 2025 09:01:22 -0400 Subject: [PATCH 186/315] no longer need to create hypervisor pillar directory --- salt/salt/cloud/init.sls | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/salt/salt/cloud/init.sls b/salt/salt/cloud/init.sls index c2d885e3c..b9764344e 100644 --- a/salt/salt/cloud/init.sls +++ b/salt/salt/cloud/init.sls @@ -43,16 +43,6 @@ cloud_profiles: MANAGERHOSTNAME: {{ grains.host }} MANAGERIP: {{ pillar.host.mainip }} - template: jinja - -{% for role, hosts in HYPERVISORS.items() %} -{% for host in hosts.keys() %} - -hypervisor_{{host}}_{{role}}_pillar_dir: - file.directory: - - name: /opt/so/saltstack/local/pillar/hypervisor/{{host}}_{{role}} - -{% endfor %} -{% endfor %} {% endif %} {% else %} From 6988f03ebc7fd5746ee1a245a3f18ca5896a69de Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Fri, 16 May 2025 14:24:07 -0400 Subject: [PATCH 187/315] setup bridge and fix salt before first highstate for hypervisors --- salt/libvirt/bridge.sls | 49 +++++++++++++++++++++++++++++++++++++++++ salt/libvirt/init.sls | 46 +------------------------------------- setup/so-functions | 9 ++++++++ setup/so-setup | 2 ++ 4 files changed, 61 insertions(+), 45 deletions(-) create mode 100644 salt/libvirt/bridge.sls diff --git a/salt/libvirt/bridge.sls b/salt/libvirt/bridge.sls new file mode 100644 index 000000000..5ff5d670c --- /dev/null +++ b/salt/libvirt/bridge.sls @@ -0,0 +1,49 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'libvirt/map.jinja' import LIBVIRTMERGED %} +{% from 'salt/map.jinja' import SYSTEMD_UNIT_FILE %} + +down_original_mgmt_interface: + cmd.run: + - name: "nmcli con down {{ pillar.host.mainint }}" + - unless: + - nmcli -f GENERAL.CONNECTION dev show {{ pillar.host.mainint }} | grep bridge-slave-{{ pillar.host.mainint }} + - order: last + +wait_for_br0_ip: + cmd.run: + - name: | + counter=0 + until ip addr show br0 | grep -q "inet "; do + sleep 1 + counter=$((counter+1)) + if [ $counter -ge 90 ]; then + echo "Timeout waiting for br0 to get an IP address" + exit 1 + fi + done + echo "br0 has IP address: $(ip addr show br0 | grep 'inet ' | awk '{print $2}')" + - timeout: 95 + - onchanges: + - cmd: down_original_mgmt_interface + +update_mine_functions: + file.managed: + - name: /etc/salt/minion.d/mine_functions.conf + - contents: | + mine_interval: 25 + mine_functions: + network.ip_addrs: + - interface: br0 + - onchanges: + - cmd: wait_for_br0_ip + +restart_salt_minion_service: + service.running: + - name: salt-minion + - enable: True + - listen: + - file: update_mine_functions diff --git a/salt/libvirt/init.sls b/salt/libvirt/init.sls index 1312cc112..576c29c33 100644 --- a/salt/libvirt/init.sls +++ b/salt/libvirt/init.sls @@ -13,12 +13,12 @@ {% if sls in allowed_states %} {% if 'vrt' in salt['pillar.get']('features', []) %} {% from 'libvirt/map.jinja' import LIBVIRTMERGED %} +{% from 'salt/map.jinja' import SYSTEMD_UNIT_FILE %} include: - libvirt.64962 - libvirt.packages - libvirt.ssh.users - - salt.mine_functions install_libvirt: pkg.installed: @@ -93,50 +93,6 @@ disable_default_bridge: - onlyif: - virsh net-list | grep default -# this should only run during the first highstate after setup. it will transfer connection from mgmt to br0 -down_original_mgmt_interface: - cmd.run: - - name: "nmcli con down {{ pillar.host.mainint }}" - - unless: - - nmcli -f GENERAL.CONNECTION dev show {{ pillar.host.mainint }} | grep bridge-slave-{{ pillar.host.mainint }} - - order: last - -update_mine_functions_interface: - file.replace: - - name: /etc/salt/minion.d/mine_functions.conf - - pattern: " - interface: ([a-zA-Z0-9]+)" - - repl: " - interface: br0" - - onchanges: - - cmd: down_original_mgmt_interface - -wait_for_br0_ip: - cmd.run: - - name: | - counter=0 - until ip addr show br0 | grep -q "inet "; do - sleep 1 - counter=$((counter+1)) - if [ $counter -ge 90 ]; then - echo "Timeout waiting for br0 to get an IP address" - exit 1 - fi - done - echo "br0 has IP address: $(ip addr show br0 | grep 'inet ' | awk '{print $2}')" - - timeout: 95 - - onchanges: - - file: update_mine_functions_interface - -mine_update_mine_interface: - module.run: - - mine.send: - - network.ip_addrs - - interface: br0 - - onchanges: - - cmd: wait_for_br0_ip - -# virtlogd service may not restart following reboot without this -#semanage permissive -a virtlogd_t - {% else %} {{sls}}_no_license_detected: test.fail_without_changes: diff --git a/setup/so-functions b/setup/so-functions index d28d7baf3..a03e0166b 100755 --- a/setup/so-functions +++ b/setup/so-functions @@ -1186,6 +1186,15 @@ get_minion_type() { echo "$minion_type" } +hypervisor_local_states() { + # these states need to run before the first highstate so that we dont deal with the salt-minion restarting + # and we need these setup prior to the highstate + if [ $is_hypervisor ] || [ $is_managerhype ]; then + salt-call state.apply libvirt.64962 --local --file-root=../salt/ -l info + salt-call state.apply libvirt.bridge --local --file-root=../salt/ -l info pillar='{"host": {"mainint": "enp1s0"}}' + fi +} + install_cleanup() { if [ -f "$temp_install_dir" ]; then info "Installer removing the following files:" diff --git a/setup/so-setup b/setup/so-setup index 115bdadb7..1736da5bc 100755 --- a/setup/so-setup +++ b/setup/so-setup @@ -822,6 +822,7 @@ if ! [[ -f $install_opt_file ]]; then checkin_at_boot set_initial_firewall_access logCmd "salt-call schedule.enable -linfo --local" + hypervisor_local_states verify_setup else touch /root/accept_changes @@ -847,6 +848,7 @@ if ! [[ -f $install_opt_file ]]; then configure_minion "$minion_type" check_sos_appliance drop_install_options + hypervisor_local_states verify_setup fi From 28aedcf50b52bdc2a73e91ca31cf01177bef6d51 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Mon, 19 May 2025 09:58:43 -0400 Subject: [PATCH 188/315] remove vm map example --- salt/soc/dyanno/hypervisor/vmMap.example | 14 -------------- 1 file changed, 14 deletions(-) delete mode 100644 salt/soc/dyanno/hypervisor/vmMap.example diff --git a/salt/soc/dyanno/hypervisor/vmMap.example b/salt/soc/dyanno/hypervisor/vmMap.example deleted file mode 100644 index 7a67c7349..000000000 --- a/salt/soc/dyanno/hypervisor/vmMap.example +++ /dev/null @@ -1,14 +0,0 @@ -hypervisor: - vm: - sen41_sensor: - cpu: 16 - memory: 24 - disk: 3 - copper: 3,4 - sfp: 7,8 - sea42_searchnode: - cpu: 16 - memory: 24 - disk: 4 - copper: - sfp: From a32aac71112f226c243b0ed7eef4b073d3963fc5 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Tue, 20 May 2025 13:38:24 -0400 Subject: [PATCH 189/315] apply salt.cloud.config when hypervisor joins --- salt/_runners/setup_hypervisor.py | 50 ++++++++++++++++++++++++++++ salt/salt/cloud/config.sls | 55 +++++++++++++++++++++++++++++++ salt/salt/cloud/init.sls | 21 ------------ 3 files changed, 105 insertions(+), 21 deletions(-) create mode 100644 salt/salt/cloud/config.sls diff --git a/salt/_runners/setup_hypervisor.py b/salt/_runners/setup_hypervisor.py index dc0d9eca8..47afc25d4 100644 --- a/salt/_runners/setup_hypervisor.py +++ b/salt/_runners/setup_hypervisor.py @@ -467,6 +467,51 @@ def _apply_dyanno_hypervisor_state(): log.error(f"DYANNO: Error applying soc.dyanno.hypervisor state: {str(e)}") return False +def _apply_cloud_config_state(): + """ + Apply the salt.cloud.config state on the salt master. + + Returns: + bool: True if state was applied successfully, False otherwise + """ + try: + log.info("CLOUDCONFIG: Applying salt.cloud.config state on salt master") + + # Initialize the LocalClient + local = salt.client.LocalClient() + + # Target the salt master to apply the soc.dyanno.hypervisor state + target = MANAGER_HOSTNAME + '_*' + state_result = local.cmd(target, 'state.apply', ['salt.cloud.config', 'concurrent=True'], tgt_type='glob') + log.debug(f"CLOUDCONFIG: state_result: {state_result}") + # Check if state was applied successfully + if state_result: + success = True + for minion, states in state_result.items(): + if not isinstance(states, dict): + log.error(f"CLOUDCONFIG: Unexpected result format from {minion}: {states}") + success = False + continue + + for state_id, state_data in states.items(): + if not state_data.get('result', False): + log.error(f"CLOUDCONFIG: State {state_id} failed on {minion}: {state_data.get('comment', 'No comment')}") + success = False + + if success: + log.info("CLOUDCONFIG: Successfully applied salt.cloud.config state") + return True + else: + log.error("CLOUDCONFIG: Failed to apply salt.cloud.config state") + return False + else: + log.error("CLOUDCONFIG: No response from salt master when applying salt.cloud.config state") + return False + + except Exception as e: + log.error(f"CLOUDCONFIG: Error applying salt.cloud.config state: {str(e)}") + return False + def setup_environment(vm_name: str = 'sool9', disk_size: str = '220G', minion_id: str = None): """ Main entry point to set up the hypervisor environment. @@ -548,6 +593,11 @@ def setup_environment(vm_name: str = 'sool9', disk_size: str = '220G', minion_id if not mine_update_success: log.error(f"DYANNO: mine.update failed after {max_retries} attempts") + # Apply the soc.dyanno.hypervisor state on the salt master + if not _apply_cloud_config_state(): + log.warning("MAIN: Failed to apply salt.cloud.config state, continuing with setup") + # We don't return an error here as we want to continue with the setup process + # Apply the soc.dyanno.hypervisor state on the salt master if not _apply_dyanno_hypervisor_state(): log.warning("MAIN: Failed to apply soc.dyanno.hypervisor state, continuing with setup") diff --git a/salt/salt/cloud/config.sls b/salt/salt/cloud/config.sls new file mode 100644 index 000000000..0456c34dc --- /dev/null +++ b/salt/salt/cloud/config.sls @@ -0,0 +1,55 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. +# +# Note: Per the Elastic License 2.0, the second limitation states: +# +# "You may not move, change, disable, or circumvent the license key functionality +# in the software, and you may not remove or obscure any functionality in the +# software that is protected by the license key." + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls in allowed_states %} +{% if 'vrt' in salt['pillar.get']('features', []) %} +{% set HYPERVISORS = salt['pillar.get']('hypervisor:nodes', {} ) %} + +{% if HYPERVISORS %} +cloud_providers: + file.managed: + - name: /etc/salt/cloud.providers.d/libvirt.conf + - source: salt://salt/cloud/cloud.providers.d/libvirt.conf.jinja + - defaults: + HYPERVISORS: {{HYPERVISORS}} + - template: jinja + - makedirs: True + +cloud_profiles: + file.managed: + - name: /etc/salt/cloud.profiles.d/socloud.conf + - source: salt://salt/cloud/cloud.profiles.d/socloud.conf.jinja + - defaults: + HYPERVISORS: {{HYPERVISORS}} + MANAGERHOSTNAME: {{ grains.host }} + MANAGERIP: {{ pillar.host.mainip }} + - template: jinja + - makedirs: True +{% endif %} + +{% else %} +{{sls}}_no_license_detected: + test.fail_without_changes: + - name: {{sls}}_no_license_detected + - comment: + - "Hypervisor nodes are a feature supported only for customers with a valid license. + Contact Security Onion Solutions, LLC via our website at https://securityonionsolutions.com + for more information about purchasing a license to enable this feature." +{% endif %} + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/salt/cloud/init.sls b/salt/salt/cloud/init.sls index b9764344e..5705a3b54 100644 --- a/salt/salt/cloud/init.sls +++ b/salt/salt/cloud/init.sls @@ -13,7 +13,6 @@ {% if sls in allowed_states %} {% if 'vrt' in salt['pillar.get']('features', []) %} {% from 'salt/map.jinja' import SALTVERSION %} -{% set HYPERVISORS = salt['pillar.get']('hypervisor:nodes', {} ) %} include: - libvirt.packages @@ -25,26 +24,6 @@ install_salt_cloud: - name: salt-cloud - version: {{SALTVERSION}} -{% if HYPERVISORS %} -cloud_providers: - file.managed: - - name: /etc/salt/cloud.providers.d/libvirt.conf - - source: salt://salt/cloud/cloud.providers.d/libvirt.conf.jinja - - defaults: - HYPERVISORS: {{HYPERVISORS}} - - template: jinja - -cloud_profiles: - file.managed: - - name: /etc/salt/cloud.profiles.d/socloud.conf - - source: salt://salt/cloud/cloud.profiles.d/socloud.conf.jinja - - defaults: - HYPERVISORS: {{HYPERVISORS}} - MANAGERHOSTNAME: {{ grains.host }} - MANAGERIP: {{ pillar.host.mainip }} - - template: jinja -{% endif %} - {% else %} {{sls}}_no_license_detected: test.fail_without_changes: From a430a47a3045e24a91ab9ac154eeef74f61a57e2 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Wed, 21 May 2025 14:45:34 -0400 Subject: [PATCH 190/315] fix allowed_states check --- salt/salt/cloud/config.sls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/salt/cloud/config.sls b/salt/salt/cloud/config.sls index 0456c34dc..dfbfda56b 100644 --- a/salt/salt/cloud/config.sls +++ b/salt/salt/cloud/config.sls @@ -10,7 +10,7 @@ # software that is protected by the license key." {% from 'allowed_states.map.jinja' import allowed_states %} -{% if sls in allowed_states %} +{% if '.'.join(sls.split('.')[:2]) in allowed_states %} {% if 'vrt' in salt['pillar.get']('features', []) %} {% set HYPERVISORS = salt['pillar.get']('hypervisor:nodes', {} ) %} From 31df0b5d7d22427ed4f402efe33d2c71e1ba0c40 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Thu, 22 May 2025 09:10:09 -0400 Subject: [PATCH 191/315] create vm pillar files --- setup/so-functions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup/so-functions b/setup/so-functions index a03e0166b..c2eb0b349 100755 --- a/setup/so-functions +++ b/setup/so-functions @@ -1472,7 +1472,7 @@ make_some_dirs() { mkdir -p $local_salt_dir/salt/firewall/portgroups mkdir -p $local_salt_dir/salt/firewall/ports - for THEDIR in bpf pcap elasticsearch ntp firewall redis backup influxdb strelka sensoroni soc docker zeek suricata nginx telegraf logstash soc manager kratos hydra idstools idh elastalert stig global kafka versionlock hypervisor; do + for THEDIR in bpf pcap elasticsearch ntp firewall redis backup influxdb strelka sensoroni soc docker zeek suricata nginx telegraf logstash soc manager kratos hydra idstools idh elastalert stig global kafka versionlock hypervisor vm; do mkdir -p $local_salt_dir/pillar/$THEDIR touch $local_salt_dir/pillar/$THEDIR/adv_$THEDIR.sls touch $local_salt_dir/pillar/$THEDIR/soc_$THEDIR.sls From 18d899a7f9c14bbcd2fa5b3115d045cca3bdbb6d Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Thu, 22 May 2025 09:29:51 -0400 Subject: [PATCH 192/315] add so-docker-prune from hotfix/2.4.150 --- salt/common/tools/sbin/so-docker-prune | 117 ++++++++++++++----------- 1 file changed, 65 insertions(+), 52 deletions(-) diff --git a/salt/common/tools/sbin/so-docker-prune b/salt/common/tools/sbin/so-docker-prune index 224cbd222..156c3b002 100755 --- a/salt/common/tools/sbin/so-docker-prune +++ b/salt/common/tools/sbin/so-docker-prune @@ -4,22 +4,16 @@ # or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at # https://securityonion.net/license; you may not use this file except in compliance with the # Elastic License 2.0. - - - -import sys, argparse, re, docker +import sys, argparse, re, subprocess, json from packaging.version import Version, InvalidVersion from itertools import groupby, chain - def get_image_name(string) -> str: return ':'.join(string.split(':')[:-1]) - def get_so_image_basename(string) -> str: return get_image_name(string).split('/so-')[-1] - def get_image_version(string) -> str: ver = string.split(':')[-1] if ver == 'latest': @@ -35,56 +29,75 @@ def get_image_version(string) -> str: return '999999.9.9' return ver +def run_command(command): + process = subprocess.run(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) + if process.returncode != 0: + print(f"Error executing command: {command}", file=sys.stderr) + print(f"Error message: {process.stderr}", file=sys.stderr) + exit(1) + return process.stdout def main(quiet): - client = docker.from_env() - - # Prune old/stopped containers - if not quiet: print('Pruning old containers') - client.containers.prune() - - image_list = client.images.list(filters={ 'dangling': False }) - - # Map list of image objects to flattened list of tags (format: "name:version") - tag_list = list(chain.from_iterable(list(map(lambda x: x.attrs.get('RepoTags'), image_list)))) - - # Filter to only SO images (base name begins with "so-") - tag_list = list(filter(lambda x: re.match(r'^.*\/so-[^\/]*$', get_image_name(x)), tag_list)) - - # Group tags into lists by base name (sort by same projection first) - tag_list.sort(key=lambda x: get_so_image_basename(x)) - grouped_tag_lists = [ list(it) for _, it in groupby(tag_list, lambda x: get_so_image_basename(x)) ] - - no_prunable = True - for t_list in grouped_tag_lists: try: - # Group tags by version, in case multiple images exist with the same version string - t_list.sort(key=lambda x: Version(get_image_version(x)), reverse=True) - grouped_t_list = [ list(it) for _,it in groupby(t_list, lambda x: get_image_version(x)) ] - - # Keep the 2 most current version groups - if len(grouped_t_list) <= 2: - continue - else: - no_prunable = False - for group in grouped_t_list[2:]: - for tag in group: - if not quiet: print(f'Removing image {tag}') + # Prune old/stopped containers using docker CLI + if not quiet: print('Pruning old containers') + run_command('docker container prune -f') + + # Get list of images using docker CLI + images_json = run_command('docker images --format "{{json .}}"') + + # Parse the JSON output + image_list = [] + for line in images_json.strip().split('\n'): + if line: # Skip empty lines + image_list.append(json.loads(line)) + + # Extract tags in the format "name:version" + tag_list = [] + for img in image_list: + # Skip dangling images + if img.get('Repository') != "" and img.get('Tag') != "": + tag = f"{img.get('Repository')}:{img.get('Tag')}" + # Filter to only SO images (base name begins with "so-") + if re.match(r'^.*\/so-[^\/]*$', get_image_name(tag)): + tag_list.append(tag) + + # Group tags into lists by base name (sort by same projection first) + tag_list.sort(key=lambda x: get_so_image_basename(x)) + grouped_tag_lists = [list(it) for k, it in groupby(tag_list, lambda x: get_so_image_basename(x))] + + no_prunable = True + for t_list in grouped_tag_lists: try: - client.images.remove(tag, force=True) - except docker.errors.ClientError as e: - print(f'Could not remove image {tag}, continuing...') - except (docker.errors.APIError, InvalidVersion) as e: - print(f'so-{get_so_image_basename(t_list[0])}: {e}', file=sys.stderr) - exit(1) + # Group tags by version, in case multiple images exist with the same version string + t_list.sort(key=lambda x: Version(get_image_version(x)), reverse=True) + grouped_t_list = [list(it) for k, it in groupby(t_list, lambda x: get_image_version(x))] + # Keep the 2 most current version groups + if len(grouped_t_list) <= 2: + continue + else: + no_prunable = False + for group in grouped_t_list[2:]: + for tag in group: + if not quiet: print(f'Removing image {tag}') + try: + run_command(f'docker rmi -f {tag}') + except Exception as e: + print(f'Could not remove image {tag}, continuing...') + except (InvalidVersion) as e: + print(f'so-{get_so_image_basename(t_list[0])}: {e}', file=sys.stderr) + exit(1) + except Exception as e: + print('Unhandled exception occurred:') + print(f'so-{get_so_image_basename(t_list[0])}: {e}', file=sys.stderr) + exit(1) + + if no_prunable and not quiet: + print('No Security Onion images to prune') + except Exception as e: - print('Unhandled exception occurred:') - print(f'so-{get_so_image_basename(t_list[0])}: {e}', file=sys.stderr) - exit(1) - - if no_prunable and not quiet: - print('No Security Onion images to prune') - + print(f"Error: {e}", file=sys.stderr) + exit(1) if __name__ == "__main__": main_parser = argparse.ArgumentParser(add_help=False) From 08f208cd38cb3e30be8920503623e812c626df9f Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Thu, 22 May 2025 15:37:34 -0400 Subject: [PATCH 193/315] ensure bootstrap-salt is updated for salt-cloud installs --- salt/salt/init.sls | 1 + salt/salt/master.sls | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/salt/salt/init.sls b/salt/salt/init.sls index b2ea31a65..724f79a95 100644 --- a/salt/salt/init.sls +++ b/salt/salt/init.sls @@ -5,6 +5,7 @@ saltpymodules: - python3-docker {% endif %} +# distribute to minions for salt upgrades salt_bootstrap: file.managed: - name: /usr/sbin/bootstrap-salt.sh diff --git a/salt/salt/master.sls b/salt/salt/master.sls index 413c90cd5..fce702932 100644 --- a/salt/salt/master.sls +++ b/salt/salt/master.sls @@ -76,6 +76,13 @@ engines_config: - name: /etc/salt/master.d/engines.conf - source: salt://salt/files/engines.conf +# update the bootstrap script when used for salt-cloud +salt_bootstrap_cloud: + file.managed: + - name: /opt/saltstack/salt/lib/python3.10/site-packages/salt/cloud/deploy/bootstrap-salt.sh + - source: salt://salt/scripts/bootstrap-salt.sh + - show_changes: False + salt_master_service: service.running: - name: salt-master From be5e41227f01ace25d22781a7f75e0d3381a3373 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Fri, 23 May 2025 11:41:45 -0400 Subject: [PATCH 194/315] rename step --- salt/_runners/setup_hypervisor.py | 2 +- salt/soc/dyanno/hypervisor/map.jinja | 2 +- salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja | 4 ++-- salt/vm/status/init.sls | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/salt/_runners/setup_hypervisor.py b/salt/_runners/setup_hypervisor.py index 47afc25d4..17bdacbd5 100644 --- a/salt/_runners/setup_hypervisor.py +++ b/salt/_runners/setup_hypervisor.py @@ -664,7 +664,7 @@ def setup_environment(vm_name: str = 'sool9', disk_size: str = '220G', minion_id # Run highstate on the hypervisor highstate_result = local.cmd(minion_id, 'state.highstate', [], timeout=1800) if highstate_result and minion_id in highstate_result: - log.info("MAIN: Highstate triggered on %s", minion_id) + log.info("MAIN: Highstate initiated on %s", minion_id) else: log.error("MAIN: Highstate failed or timed out on %s", minion_id) return { diff --git a/salt/soc/dyanno/hypervisor/map.jinja b/salt/soc/dyanno/hypervisor/map.jinja index 88b3f4425..4a5107371 100644 --- a/salt/soc/dyanno/hypervisor/map.jinja +++ b/salt/soc/dyanno/hypervisor/map.jinja @@ -9,6 +9,6 @@ 'Initialize Minion Pillars', 'Created Instance', 'Hardware Configuration', - 'Highstate Triggered', + 'Highstate Initiated', 'Destroyed Instance' ] %} diff --git a/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja b/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja index 8ac7a7225..4222ff6b2 100644 --- a/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja +++ b/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja @@ -27,7 +27,7 @@ {%- if baseDomainStatus == 'Initialized' %} {%- if vm_list %} #### Virtual Machines -Status values: {% for step in PROCESS_STEPS %}{{ step }}{% if not loop.last %}, {% endif %}{% endfor %}. "Last Updated" shows when status changed. After "Highstate Triggered", only "Destroyed Instance" updates the timestamp. +Status values: {% for step in PROCESS_STEPS %}{{ step }}{% if not loop.last %}, {% endif %}{% endfor %}. "Last Updated" shows when status changed. After "Highstate Initiated", only "Destroyed Instance" updates the timestamp. | Name | Status | CPU Cores | Memory (GB)| Disk | Copper | SFP | Last Updated | |--------------------|--------------------|-----------|------------|------|--------|------|---------------------| @@ -42,7 +42,7 @@ Status values: {% for step in PROCESS_STEPS %}{{ step }}{% if not loop.last %}, {%- endfor %} {%- else %} #### Virtual Machines -Status values: {% for step in PROCESS_STEPS %}{{ step }}{% if not loop.last %}, {% endif %}{% endfor %}. "Last Updated" shows when status changed. After "Highstate Triggered", only "Destroyed Instance" updates the timestamp. +Status values: {% for step in PROCESS_STEPS %}{{ step }}{% if not loop.last %}, {% endif %}{% endfor %}. "Last Updated" shows when status changed. After "Highstate Initiated", only "Destroyed Instance" updates the timestamp. No Virtual Machines Found {%- endif %} diff --git a/salt/vm/status/init.sls b/salt/vm/status/init.sls index 570b36d19..64124aa85 100644 --- a/salt/vm/status/init.sls +++ b/salt/vm/status/init.sls @@ -15,9 +15,9 @@ # so-salt-emit-vm-deployment-status sets event_tag = f'soc/dyanno/hypervisor/{status.lower()}' vm_highstate_trigger: event.send: - - name: soc/dyanno/hypervisor/highstate triggered + - name: soc/dyanno/hypervisor/highstate initiated - data: - status: Highstate Triggered + status: Highstate Initiated vm_name: {{ grains.id }} hypervisor: {{ salt['grains.get']('salt-cloud:profile', '').split('-')[1] }} - order: 1 # Ensure this runs early in the highstate process From e5b12ecdb9e95bb978e4e5ce8409e0330f60ebf2 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Fri, 23 May 2025 12:44:42 -0400 Subject: [PATCH 195/315] need to allow for pw removal --- salt/vm/user/init.sls | 2 -- 1 file changed, 2 deletions(-) diff --git a/salt/vm/user/init.sls b/salt/vm/user/init.sls index 48185a9da..6abffe3f9 100644 --- a/salt/vm/user/init.sls +++ b/salt/vm/user/init.sls @@ -20,9 +20,7 @@ vm_user_soqemussh: - name: soqemussh - shell: /bin/bash - home: /home/soqemussh -{% if VMMERGED.user.soqemussh.passwordHash %} - password: '{{ VMMERGED.user.soqemussh.passwordHash }}' -{% endif %} vm_user_soqemussh_home_directory: file.directory: From 05dfce62fbc940135adbca710c15c6153bd50ab9 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Wed, 28 May 2025 13:34:17 -0400 Subject: [PATCH 196/315] corrections to allowed_states --- salt/allowed_states.map.jinja | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/salt/allowed_states.map.jinja b/salt/allowed_states.map.jinja index af9bcaa5d..3edda8a4c 100644 --- a/salt/allowed_states.map.jinja +++ b/salt/allowed_states.map.jinja @@ -47,7 +47,9 @@ 'pcap', 'suricata', 'healthcheck', - 'tcpreplay' + 'tcpreplay', + 'zeek', + 'strelka' ] %} {% set kafka_states = [ @@ -78,14 +80,12 @@ ssl_states + manager_states + sensor_states + - elastic_stack_states + elastic_stack_states | reject('equalto', 'logstash') | list ), 'so-heavynode': ( ssl_states + sensor_states + - ['elasticagent', 'zeek', 'strelka'] + - ['elasticsearch', 'logstash', 'redis'] + - stig_states + ['elasticagent', 'elasticsearch', 'logstash', 'redis', 'nginx'] ), 'so-idh': ( ssl_states + @@ -94,9 +94,8 @@ 'so-import': ( ssl_states + manager_states + - sensor_states + - ['zeek'] + - ['elasticsearch', 'elasticsearch.auth', 'kibana', 'kibana.secrets'] + sensor_states | reject('equalto', 'strelka') | reject('equalto', 'healthcheck') | list + + ['elasticsearch', 'elasticsearch.auth', 'kibana', 'kibana.secrets', 'strelka.manager'] ), 'so-manager': ( ssl_states + @@ -124,7 +123,7 @@ ), 'so-searchnode': ( ssl_states + - ['kafka.ca', 'kafka.ssl', 'elasticsearch', 'logstash'] + + ['kafka.ca', 'kafka.ssl', 'elasticsearch', 'logstash', 'nginx'] + stig_states ), 'so-standalone': ( @@ -133,13 +132,12 @@ sensor_states + stig_states + kafka_states + - elastic_stack_states + - ['zeek', 'strelka'] + elastic_stack_states ), 'so-sensor': ( ssl_states + sensor_states + - ['nginx', 'zeek', 'strelka'] + + ['nginx'] + stig_states ), 'so-fleet': ( From 40531dd9192b1d2a24e5ab924b454a131ff9cd3f Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Thu, 29 May 2025 12:22:52 -0400 Subject: [PATCH 197/315] add LSHOSTNAME option to so-minion. use -L in sominion_setup reactor --- salt/manager/tools/sbin/so-minion | 4 ++++ salt/reactor/sominion_setup.sls | 13 +++++++++---- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/salt/manager/tools/sbin/so-minion b/salt/manager/tools/sbin/so-minion index 55cd699ae..34ebdaeec 100755 --- a/salt/manager/tools/sbin/so-minion +++ b/salt/manager/tools/sbin/so-minion @@ -75,6 +75,10 @@ for i in "$@"; do ES_HEAP_SIZE="${i#*=}" shift ;; + -L=*|--lshostname=*) + LSHOSTNAME="${i#*=}" + shift + ;; -l=*|--lsheap=*) LSHEAP="${i#*=}" shift diff --git a/salt/reactor/sominion_setup.sls b/salt/reactor/sominion_setup.sls index 547b1b686..64b3666f4 100644 --- a/salt/reactor/sominion_setup.sls +++ b/salt/reactor/sominion_setup.sls @@ -9,12 +9,14 @@ import logging from subprocess import call import yaml +log = logging.getLogger(__name__) + def run(): - logging.debug('sominion_setup_reactor: Running') + log.info('sominion_setup_reactor: Running') minionid = data['id'] DATA = data['data'] hv_name = DATA['HYPERVISOR_HOST'] - logging.debug('sominion_setup_reactor: DATA: %s' % DATA) + log.info('sominion_setup_reactor: DATA: %s' % DATA) # Build the base command cmd = "NODETYPE=" + DATA['NODETYPE'] + " /usr/sbin/so-minion -o=addVM -m=" + minionid + " -n=" + DATA['MNIC'] + " -i=" + DATA['MAINIP'] + " -c=" + str(DATA['CPUCORES']) + " -d='" + DATA['NODE_DESCRIPTION'] + "'" @@ -31,10 +33,13 @@ def run(): if 'LS_HEAP_SIZE' in DATA: cmd += " -l=" + DATA['LS_HEAP_SIZE'] + + if 'LSHOSTNAME' in DATA: + cmd += " -L=" + DATA['LSHOSTNAME'] - logging.debug('sominion_setup_reactor: Command: %s' % cmd) + log.info('sominion_setup_reactor: Command: %s' % cmd) rc = call(cmd, shell=True) - logging.info('sominion_setup_reactor: rc: %s' % rc) + log.info('sominion_setup_reactor: rc: %s' % rc) return {} From 08d99a3890ba45f6e1d5bb9583a277313797019f Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Fri, 30 May 2025 12:50:13 -0400 Subject: [PATCH 198/315] remove unneeded files --- salt/_beacons/add_virtual_node_beacon.py | 113 ---------- salt/hypervisor/raid.sh | 20 -- salt/hypervisor/raid3.sh | 200 ------------------ .../{raid2.sh => tools/sbin/so-nvme-raid1.sh} | 34 +++ salt/libvirt/configgood | 50 ----- salt/libvirt/configstock | 51 ----- .../{configstockstock => etc/libvirtd.conf} | 0 salt/libvirt/images/sool9/README | 2 +- salt/libvirt/init.sls | 2 +- salt/libvirt/scripts/createvm.sh | 190 ----------------- salt/libvirt/scripts/createvm2.sh | 144 ------------- salt/setup/highstate_cron.sls | 7 - 12 files changed, 36 insertions(+), 777 deletions(-) delete mode 100644 salt/_beacons/add_virtual_node_beacon.py delete mode 100644 salt/hypervisor/raid.sh delete mode 100644 salt/hypervisor/raid3.sh rename salt/hypervisor/{raid2.sh => tools/sbin/so-nvme-raid1.sh} (80%) delete mode 100644 salt/libvirt/configgood delete mode 100644 salt/libvirt/configstock rename salt/libvirt/{configstockstock => etc/libvirtd.conf} (100%) delete mode 100644 salt/libvirt/scripts/createvm.sh delete mode 100644 salt/libvirt/scripts/createvm2.sh delete mode 100644 salt/setup/highstate_cron.sls diff --git a/salt/_beacons/add_virtual_node_beacon.py b/salt/_beacons/add_virtual_node_beacon.py deleted file mode 100644 index 6cbd3574c..000000000 --- a/salt/_beacons/add_virtual_node_beacon.py +++ /dev/null @@ -1,113 +0,0 @@ -''' -Add Virtual Node Beacon - -This beacon monitors for creation or modification of files matching a specific pattern -and sends the contents of the files up to the Salt Master's event bus, including -the hypervisor and nodetype extracted from the file path. - -Configuration: - - beacons: - add_virtual_node_beacon: - - base_path: /path/to/files/* - -If base_path is not specified, it defaults to '/opt/so/saltstack/local/salt/hypervisor/hosts/*/add_*' -''' - -import os -import glob -import logging -import re - -log = logging.getLogger(__name__) - -__virtualname__ = 'add_virtual_node_beacon' -DEFAULT_BASE_PATH = '/opt/so/saltstack/local/salt/hypervisor/hosts/*/add_*' - -def __virtual__(): - ''' - Return the virtual name of the beacon. - ''' - return __virtualname__ - -def validate(config): - ''' - Validate the beacon configuration. - - Args: - config (list): Configuration of the beacon. - - Returns: - tuple: A tuple of (bool, str) indicating success and message. - ''' - if not isinstance(config, list): - return False, 'Configuration for add_virtual_node_beacon must be a list of dictionaries' - for item in config: - if not isinstance(item, dict): - return False, 'Each item in configuration must be a dictionary' - if 'base_path' in item and not isinstance(item['base_path'], str): - return False, 'base_path must be a string' - return True, 'Valid beacon configuration' - -def beacon(config): - ''' - Monitor for creation or modification of files and send events. - - Args: - config (list): Configuration of the beacon. - - Returns: - list: A list of events to send to the Salt Master. - ''' - if 'add_virtual_node_beacon' not in __context__: - __context__['add_virtual_node_beacon'] = {} - - ret = [] - - for item in config: - base_path = item.get('base_path', DEFAULT_BASE_PATH) - file_list = glob.glob(base_path) - - log.debug('Starting add_virtual_node_beacon. Found %d files matching pattern %s', len(file_list), base_path) - - for file_path in file_list: - try: - mtime = os.path.getmtime(file_path) - prev_mtime = __context__['add_virtual_node_beacon'].get(file_path, 0) - if mtime > prev_mtime: - log.info('File %s is new or modified', file_path) - with open(file_path, 'r') as f: - contents = f.read() - - data = {} - # Parse the contents of the file - for line in contents.splitlines(): - if ':' in line: - key, value = line.split(':', 1) - data[key.strip()] = value.strip() - else: - log.warning('Line in file %s does not contain colon: %s', file_path, line) - - # Extract hypervisor and nodetype from the file path - match = re.match(r'^.*/hosts/(?P[^/]+)/add_(?P[^/]+)$', file_path) - if match: - data['hypervisor'] = match.group('hypervisor') - data['nodetype'] = match.group('nodetype') - else: - log.warning('Unable to extract hypervisor and nodetype from file path: %s', file_path) - data['hypervisor'] = None - data['nodetype'] = None - - event = {'tag': f'add_virtual_node/{os.path.basename(file_path)}', 'data': data} - ret.append(event) - __context__['add_virtual_node_beacon'][file_path] = mtime - else: - log.debug('File %s has not been modified since last check', file_path) - except FileNotFoundError: - log.warning('File not found: %s', file_path) - except PermissionError: - log.error('Permission denied when accessing file: %s', file_path) - except Exception as e: - log.error('Error processing file %s: %s', file_path, str(e)) - - return ret diff --git a/salt/hypervisor/raid.sh b/salt/hypervisor/raid.sh deleted file mode 100644 index b4539ba05..000000000 --- a/salt/hypervisor/raid.sh +++ /dev/null @@ -1,20 +0,0 @@ -# quick script to create raid -# this is an example of the base functions -parted -s /dev/nvme0n1 rm 1 -parted -s /dev/nvme0n1 mklabel gpt -parted -s /dev/nvme0n1 mkpart primary xfs 0% 100% -parted -s /dev/nvme0n1 set 1 raid on -parted -s /dev/nvme1n1 rm 1 -parted -s /dev/nvme1n1 mklabel gpt -parted -s /dev/nvme1n1 mkpart primary xfs 0% 100% -parted -s /dev/nvme1n1 set 1 raid on -yes | mdadm --create /dev/md0 --level=1 --raid-devices=2 /dev/nvme0n1p1 /dev/nvme1n1p1 - -mkfs -t xfs -f /dev/md0 -echo "Create NSM mount point" -mkdir -p /nsm -echo "Add mount to fstab" -echo "/dev/md0 /nsm xfs defaults,nofail 0 0" >> /etc/fstab -echo "Mounting /nsm" -mount -a -mdadm --detail --scan --verbose >> /etc/mdadm.conf diff --git a/salt/hypervisor/raid3.sh b/salt/hypervisor/raid3.sh deleted file mode 100644 index 4e5bd6c7f..000000000 --- a/salt/hypervisor/raid3.sh +++ /dev/null @@ -1,200 +0,0 @@ -#!/bin/bash - -#raid3.sh is a refinement of raid2.sh. raid2.sh was used to create the raid in testing -#More detailed logging -#More thorough RAID array cleanup -#Better organized cleanup procedures -#Simplified device wiping using more modern tools (sgdisk instead of dd) -#More robust handling of existing MD arrays -#The core RAID creation and mounting functionality remains the same between both scripts, but the second version has improved error handling and cleanup procedures. - -# Exit on any error -set -e - -# Function to log messages -log() { - echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" -} - -# Function to check if running as root -check_root() { - if [ "$EUID" -ne 0 ]; then - log "Error: Please run as root" - exit 1 - fi -} - -# Function to perform thorough device cleanup -ensure_devices_free() { - local device=$1 - - log "Performing thorough cleanup of device $device" - - # Kill any processes using the device - fuser -k "${device}"* 2>/dev/null || true - - # Force unmount any partitions - for part in "${device}"*; do - if mount | grep -q "$part"; then - umount -f "$part" 2>/dev/null || true - fi - done - - # Stop any MD arrays using this device - for md in $(ls /dev/md* 2>/dev/null || true); do - if mdadm --detail "$md" 2>/dev/null | grep -q "$device"; then - log "Stopping MD array $md" - mdadm --stop "$md" 2>/dev/null || true - fi - done - - # Thorough RAID cleanup - log "Cleaning RAID metadata from $device" - mdadm --zero-superblock "$device" 2>/dev/null || true - if [ -e "${device}p1" ]; then - mdadm --zero-superblock "${device}p1" 2>/dev/null || true - fi - - # Remove LVM PV if exists - pvremove -ff -y "$device" 2>/dev/null || true - - # Clear all signatures - log "Wiping all signatures from $device" - wipefs -a "$device" 2>/dev/null || true - - # Clear partition table - log "Clearing partition table on $device" - sgdisk -Z "$device" 2>/dev/null || true - - # Force kernel to reread - log "Forcing kernel to reread partition table" - partprobe "$device" 2>/dev/null || true - sleep 2 -} - -# Function to check if RAID is already set up -check_existing_raid() { - # Clear existing mdadm configuration first - log "Initializing clean mdadm configuration" - echo "DEVICE partitions" > /etc/mdadm.conf - - if [ -e "/dev/md0" ]; then - if mdadm --detail /dev/md0 &>/dev/null; then - local raid_state=$(mdadm --detail /dev/md0 | grep "State" | awk '{print $3}') - local mount_point="/nsm" - - log "Found existing RAID array /dev/md0 (State: $raid_state)" - - if mountpoint -q "$mount_point"; then - log "RAID is already mounted at $mount_point" - log "Current RAID details:" - mdadm --detail /dev/md0 - - # Check if resyncing - if grep -q "resync" /proc/mdstat; then - log "RAID is currently resyncing:" - grep resync /proc/mdstat - log "You can monitor progress with: watch -n 60 cat /proc/mdstat" - else - log "RAID is fully synced and operational" - fi - - # Show disk usage - log "Current disk usage:" - df -h "$mount_point" - - exit 0 - fi - fi - fi - - # Check if any MD arrays exist and try to clean them up - if [ -f /proc/mdstat ]; then - log "Checking for existing MD arrays" - if grep -q "md" /proc/mdstat; then - log "Found existing MD arrays, attempting cleanup" - for md in $(awk '/md/{print $1}' /proc/mdstat); do - log "Stopping array $md" - mdadm --stop "/dev/$md" 2>/dev/null || true - done - fi - fi - - # Check if any of the target devices are in use - for device in "/dev/nvme0n1" "/dev/nvme1n1"; do - if lsblk -o NAME,MOUNTPOINT "$device" | grep -q "nsm"; then - log "Error: $device is already mounted at /nsm" - exit 1 - fi - done -} - -# Main script -main() { - log "Starting RAID setup script" - - # Check if running as root - check_root - - # Check for existing RAID setup - check_existing_raid - - # Clean and prepare devices - for device in "/dev/nvme0n1" "/dev/nvme1n1"; do - ensure_devices_free "$device" - - log "Creating new partition table on $device" - sgdisk -Z "$device" - sgdisk -o "$device" - - log "Creating RAID partition" - sgdisk -n 1:0:0 -t 1:fd00 "$device" - - partprobe "$device" - udevadm settle - sleep 5 - done - - log "Final verification of partition availability" - if ! [ -b "/dev/nvme0n1p1" ] || ! [ -b "/dev/nvme1n1p1" ]; then - log "Error: Partitions not available after creation" - exit 1 - fi - - log "Creating RAID array" - mdadm --create /dev/md0 --level=1 --raid-devices=2 \ - --metadata=1.2 \ - /dev/nvme0n1p1 /dev/nvme1n1p1 \ - --force --run - - log "Creating XFS filesystem" - mkfs.xfs -f /dev/md0 - - log "Creating mount point" - mkdir -p /nsm - - log "Updating fstab" - sed -i '/\/dev\/md0/d' /etc/fstab - echo "/dev/md0 /nsm xfs defaults,nofail 0 0" >> /etc/fstab - - log "Reloading systemd daemon" - systemctl daemon-reload - - log "Mounting filesystem" - mount -a - - log "Saving RAID configuration" - mdadm --detail --scan > /etc/mdadm.conf - - log "RAID setup complete" - log "RAID array details:" - mdadm --detail /dev/md0 - - if grep -q "resync" /proc/mdstat; then - log "RAID is currently resyncing. You can monitor progress with:" - log "watch -n 60 cat /proc/mdstat" - fi -} - -# Run main function -main "$@" diff --git a/salt/hypervisor/raid2.sh b/salt/hypervisor/tools/sbin/so-nvme-raid1.sh similarity index 80% rename from salt/hypervisor/raid2.sh rename to salt/hypervisor/tools/sbin/so-nvme-raid1.sh index 83e1970df..79ccbb33c 100644 --- a/salt/hypervisor/raid2.sh +++ b/salt/hypervisor/tools/sbin/so-nvme-raid1.sh @@ -1,5 +1,39 @@ #!/bin/bash +################################################################# +# RAID-1 Setup Script for NVMe Drives +################################################################# +# +# DESCRIPTION: +# This script automatically sets up a RAID-1 (mirrored) array using two NVMe drives +# (/dev/nvme0n1 and /dev/nvme1n1) and mounts it at /nsm with XFS filesystem. +# +# FUNCTIONALITY: +# - Detects and reports existing RAID configurations +# - Thoroughly cleans target drives of any existing data/configurations +# - Creates GPT partition tables with RAID-type partitions +# - Establishes RAID-1 array (/dev/md0) for data redundancy +# - Formats the array with XFS filesystem for performance +# - Automatically mounts at /nsm and configures for boot persistence +# - Provides monitoring information for resync operations +# +# SAFETY FEATURES: +# - Requires root privileges +# - Exits gracefully if RAID already exists and is mounted +# - Performs comprehensive cleanup to avoid conflicts +# - Forces partition table updates and waits for system recognition +# +# PREREQUISITES: +# - Two NVMe drives: /dev/nvme0n1 and /dev/nvme1n1 +# - Root access +# - mdadm, sgdisk, and standard Linux utilities +# +# WARNING: This script will DESTROY all data on the target drives! +# +# USAGE: sudo ./raid_setup.sh +# +################################################################# + # Exit on any error set -e diff --git a/salt/libvirt/configgood b/salt/libvirt/configgood deleted file mode 100644 index 72369709d..000000000 --- a/salt/libvirt/configgood +++ /dev/null @@ -1,50 +0,0 @@ -#listen_tls = "0" -#listen_tcp = "0" -#tls_port = "16514" -#tcp_port = "16509" -#listen_addr = "0.0.0.0" -#unix_sock_group = "root" -#unix_sock_ro_perms = "0777" -#unix_sock_rw_perms = "0770" -#unix_sock_admin_perms = "0700" -#unix_sock_dir = "/run/libvirt" -#auth_unix_ro = "none" -#auth_unix_rw = "none" -#auth_tcp = "none" -#auth_tls = "none" -#access_drivers = "[ \"nop\" ]" -#key_file = "/etc/pki/libvirt/private/serverkey.pem" -#cert_file = "/etc/pki/libvirt/servercert.pem" -#ca_file = "/etc/pki/CA/cacert.pem" -#crl_file = "/etc/pki/CA/crl.pem" -#tls_no_sanity_certificate = "0" -#tls_no_verify_certificate = "0" -#tls_allowed_dn_list = "[\"DN1\", \"DN2\"]" -#tls_priority = "NORMAL" -#sasl_allowed_username_list = "[\"joe@example.com\", \"fred@example.com\"]" -#max_clients = "5000" -#max_queued_clients = "20" -#max_anonymous_clients = "20" -#min_workers = "5" -#max_workers = "20" -#prio_workers = "5" -#max_client_requests = "5" -#admin_min_workers = "1" -#admin_max_workers = "5" -#admin_max_clients = "5" -#admin_max_queued_clients = "5" -#admin_max_client_requests = "5" -#log_level = "3" -#log_filters = "\"1:qemu 1:libvirt 4:object 4:json 4:event 1:util\"" -#log_outputs = "\"3:syslog:libvirtd\"" -#audit_level = "1" -#audit_logging = "0" -#host_uuid = "00000000-0000-0000-0000-000000000000" -#host_uuid_source = "smbios" -#keepalive_interval = "5" -#keepalive_count = "5" -#keepalive_required = "0" -#admin_keepalive_required = "0" -#admin_keepalive_interval = "5" -#admin_keepalive_count = "5" -#ovs_timeout = "5" diff --git a/salt/libvirt/configstock b/salt/libvirt/configstock deleted file mode 100644 index ac1174cfb..000000000 --- a/salt/libvirt/configstock +++ /dev/null @@ -1,51 +0,0 @@ -#listen_tls = 0 -#listen_tcp = 1 -#tls_port = "16514" -#tcp_port = "16509" -#listen_addr = "192.168.0.1" -#unix_sock_group = "libvirt" -#unix_sock_ro_perms = "0777" -#unix_sock_rw_perms = "0770" -#unix_sock_admin_perms = "0700" -#unix_sock_dir = "/run/libvirt" -#auth_unix_ro = "polkit" -#auth_unix_rw = "polkit" -#auth_tcp = "sasl" -#auth_tls = "none" -#tcp_min_ssf = 112 -#access_drivers = [ "polkit" ] -#key_file = "/etc/pki/libvirt/private/serverkey.pem" -#cert_file = "/etc/pki/libvirt/servercert.pem" -#ca_file = "/etc/pki/CA/cacert.pem" -#crl_file = "/etc/pki/CA/crl.pem" -#tls_no_sanity_certificate = 1 -#tls_no_verify_certificate = 1 -#tls_allowed_dn_list = ["DN1", "DN2"] -#tls_priority="NORMAL" -#sasl_allowed_username_list = ["joe@EXAMPLE.COM", "fred@EXAMPLE.COM" ] -#max_clients = 5000 -#max_queued_clients = 1000 -#max_anonymous_clients = 20 -#min_workers = 5 -#max_workers = 20 -#prio_workers = 5 -#max_client_requests = 5 -#admin_min_workers = 1 -#admin_max_workers = 5 -#admin_max_clients = 5 -#admin_max_queued_clients = 5 -#admin_max_client_requests = 5 -#log_level = 3 -#log_filters="1:qemu 1:libvirt 4:object 4:json 4:event 1:util" -#log_outputs="3:syslog:libvirtd" -#audit_level = 2 -#audit_logging = 1 -#host_uuid = "00000000-0000-0000-0000-000000000000" -#host_uuid_source = "smbios" -#keepalive_interval = 5 -#keepalive_count = 5 -#keepalive_required = 1 -#admin_keepalive_required = 1 -#admin_keepalive_interval = 5 -#admin_keepalive_count = 5 -#ovs_timeout = 5 diff --git a/salt/libvirt/configstockstock b/salt/libvirt/etc/libvirtd.conf similarity index 100% rename from salt/libvirt/configstockstock rename to salt/libvirt/etc/libvirtd.conf diff --git a/salt/libvirt/images/sool9/README b/salt/libvirt/images/sool9/README index 286dd8a44..dcb68b4e8 100644 --- a/salt/libvirt/images/sool9/README +++ b/salt/libvirt/images/sool9/README @@ -1 +1 @@ -# The files in this directory (/opt/so/saltstack/local/salt/libvirt/images/sool9) are generated by createvm.sh. They are then distributed to the hypervisors where a storage pool will be created then the image can be installed. +# The files in this directory (/opt/so/saltstack/local/salt/libvirt/images/sool9) are generated by the setup_hypervisor runner. They are then distributed to the hypervisors where a storage pool will be created then the image can be installed. diff --git a/salt/libvirt/init.sls b/salt/libvirt/init.sls index 576c29c33..e25a3bcc6 100644 --- a/salt/libvirt/init.sls +++ b/salt/libvirt/init.sls @@ -34,7 +34,7 @@ libvirt_conf_dir: libvirt_config: file.managed: - name: /opt/so/conf/libvirt/libvirtd.conf - - source: salt://libvirt/configstockstock + - source: salt://libvirt/etc/libvirtd.conf # - source: salt://libvirt/etc/libvirtd.conf.jinja # - template: jinja # - defaults: diff --git a/salt/libvirt/scripts/createvm.sh b/salt/libvirt/scripts/createvm.sh deleted file mode 100644 index 4a88ecb1f..000000000 --- a/salt/libvirt/scripts/createvm.sh +++ /dev/null @@ -1,190 +0,0 @@ -#!/bin/bash - -# Ensure /root/create_vm/var/lib/libvirt/images exists -# Place this script in /root/create_vm -# Download OL9U5_x86_64-kvm-b253.qcow2 from https://yum.oracle.com/oracle-linux-templates.html, place in /root/create_vm/ - -# These steps will be removed from the process to create the final image and is being used for development -# This is used for the user-data auth portion of cloud-init -# Create passwd hash: -# python3 -c 'import crypt; print(crypt.crypt("YOUR_PASSWD_HERE", crypt.mksalt(crypt.METHOD_SHA512)))' -# Create ssh keypair: -# ssh-keygen -t ed25519 -C "soqemussh" -f ~/.ssh/soqemussh - -# Run the script: createvm.sh coreol9Small 205G -# IP options may be removed for final version - -# After running the script, the following will be output: -#[root@jppvirtman create_vm]# ll var/lib/libvirt/images/coreol9Small/ -#total 610376 -#-rw-r--r--. 1 root root 380928 Dec 20 14:33 coreol9Small-cidata.iso -#-rw-r--r--. 1 root root 624623616 Dec 20 14:33 coreol9Small.qcow2 -#-rw-r--r--. 1 root root 55 Dec 20 14:32 meta-data -#-rw-r--r--. 1 root root 333 Dec 20 14:32 network-config -#-rw-r--r--. 1 root root 1047 Dec 20 14:32 user-data - -# These files are now scp to a hypervisor node -# Place the files in /var/lib/libvirt/images/coreol9Small (or whatever is the same as the vm name) -# Create your storage pool as instructed by the script. this is only needed if one doesn't already exist -# Run the virt-install command as instructed by the script - -# Could add the following to the final runcmd in the user-data to fill the disk to avoid the cons of thin provisioning the disk -# - dd if=/dev/zero of=/tmp/fill bs=1M || true -# - rm -f /tmp/fill - -# Exit on any error -set -e - -# Set variables and defaults -VM=${1:-"small-vm"} # VM name -DISK_SIZE=${2:-"205G"} # Disk size with unit (default 205G) -IP=${3:-"192.168.1.10"} # IP address -GATEWAY=${4:-"192.168.1.1"} # Gateway -DNS=${5:-"192.168.1.1"} # Comma-separated list of DNS servers -MAC_ADDRESS="52:54:00:f2:c3:df" # Default MAC - will be overridden if found - -# Show usage if help is requested -if [[ "$1" == "-h" || "$1" == "--help" ]]; then - echo "Usage: $0 " - echo "Example: $0 myvm 100G 192.168.1.50 192.168.1.1 8.8.8.8,8.8.4.4" - echo "Parameters:" - echo " vm_name : Name of the VM (default: small-vm)" - echo " disk_size : Size of the disk with unit G/M (default: 205G)" - echo " ip : IP address (default: 192.168.1.10)" - echo " gateway : Gateway address (default: 192.168.1.1)" - echo " dns_servers: Comma-separated DNS servers (default: 192.168.1.1)" - echo "All parameters are optional and will use defaults if not specified" - exit 0 -fi - -# Validate disk size format -if ! [[ $DISK_SIZE =~ ^[0-9]+[GM]$ ]]; then - echo "Error: Disk size must be a number followed by G (gigabytes) or M (megabytes)" - echo "Example: 100G or 51200M" - exit 1 -fi - -# Convert comma-separated DNS servers to yaml format -format_dns() { - local IFS=',' - local dns_list=($1) - local yaml="" - for dns in "${dns_list[@]}"; do - yaml="$yaml - $dns"$'\n' - done - echo "$yaml" -} - -DNS_YAML=$(format_dns "$DNS") - -# Set up directory structure -D=/root/create_vm/var/lib/libvirt/images -mkdir -vp $D/$VM -cd $D/$VM - -# Create cloud-init metadata -cat > meta-data << EOF -instance-id: ${VM} -local-hostname: ${VM} -EOF - -# Create network configuration -cat > network-config << EOF -version: 2 -ethernets: - eth0: - match: - macaddress: ${MAC_ADDRESS} - dhcp4: false - dhcp6: false - addresses: - - ${IP}/24 - routes: - - to: 0.0.0.0/0 - via: ${GATEWAY} - nameservers: - addresses: -$(format_dns "$DNS") -EOF - -# Create user-data with network configuration -cat > user-data << EOF -#cloud-config -preserve_hostname: False -hostname: ${VM} -fqdn: ${VM}.local - -users: - - default - - name: soqemussh - groups: ['wheel'] - shell: /bin/bash - sudo: ALL=(ALL) NOPASSWD:ALL - lock_passwd: false - passwd: $(echo '___YOUR_HASH_HERE___') - ssh-authorized-keys: - - ssh-ed25519 ___YOUR_PUB_KEY_HERE___ soqemussh - -# Configure where output will go -output: - all: ">> /var/log/cloud-init.log" - -# configure interaction with ssh server -ssh_genkeytypes: ['ed25519', 'rsa'] - -# set timezone for VM -timezone: UTC - -# Install QEMU guest agent. Enable and start the service -packages: - - qemu-guest-agent - -runcmd: - - systemctl enable --now qemu-guest-agent - - systemctl enable --now serial-getty@ttyS0.service - - systemctl enable --now NetworkManager - - growpart /dev/vda 2 - - pvresize /dev/vda2 - - lvextend -l +100%FREE /dev/vg_main/lv_root - - xfs_growfs /dev/vg_main/lv_root -EOF - -# First, copy the base image with progress -echo "Creating base VM image..." -rsync --progress /root/create_vm/OL9U5_x86_64-kvm-b253.qcow2 $VM.qcow2 - -# Resize the image to specified size -echo "Resizing image to $DISK_SIZE..." -echo "Current image size: $(qemu-img info $VM.qcow2 | grep 'virtual size' | cut -d':' -f2 | cut -d'(' -f1 | tr -d ' ')" -qemu-img resize -f qcow2 $VM.qcow2 $DISK_SIZE -echo "New image size: $(qemu-img info $VM.qcow2 | grep 'virtual size' | cut -d':' -f2 | cut -d'(' -f1 | tr -d ' ')" - -# Now compress it with progress -echo "Compressing image..." -qemu-img convert -p -O qcow2 -c $VM.qcow2 $VM-compressed.qcow2 -mv -v $VM-compressed.qcow2 $VM.qcow2 - -# Create a cloud-init ISO with network config and progress indication -echo "Creating cloud-init ISO..." -mkisofs -output $VM-cidata.iso -volid CIDATA -rock -verbose user-data meta-data network-config - -# Echo the configuration for verification -echo "Creating VM with the following configuration:" -echo "VM Name: $VM" -echo "Disk Size: $DISK_SIZE" -echo "IP Address: $IP" -echo "Gateway: $GATEWAY" -echo "DNS Servers: $DNS" -echo "MAC Address: $MAC_ADDRESS" - -echo "Files have been created in $D/$VM" -echo -echo "To complete VM creation on the hypervisor, run:" -echo "virsh pool-create-as --name $VM --type dir --target $D/$VM" -echo "virt-install --import --name ${VM} \\" -echo " --memory 4096 --vcpus 4 --cpu host \\" -echo " --disk ${VM}.qcow2,format=qcow2,bus=virtio \\" -echo " --disk ${VM}-cidata.iso,device=cdrom \\" -echo " --network bridge=br0,model=virtio,mac=${MAC_ADDRESS} \\" -echo " --os-variant=ol9.5 \\" -echo " --noautoconsole" diff --git a/salt/libvirt/scripts/createvm2.sh b/salt/libvirt/scripts/createvm2.sh deleted file mode 100644 index b2be0d5b4..000000000 --- a/salt/libvirt/scripts/createvm2.sh +++ /dev/null @@ -1,144 +0,0 @@ -#!/bin/bash - -# Ensure /root/create_vm/var/lib/libvirt/images exists -# Place this script in /root/create_vm -# Download OL9U5_x86_64-kvm-b253.qcow2 from https://yum.oracle.com/oracle-linux-templates.html, place in /root/create_vm/ - -# These steps will be removed from the process to create the final image and is being used for development -# This is used for the user-data auth portion of cloud-init -# Create passwd hash: -# python3 -c 'import crypt; print(crypt.crypt("YOUR_PASSWD_HERE", crypt.mksalt(crypt.METHOD_SHA512)))' -# Create ssh keypair: -# ssh-keygen -t ed25519 -C "soqemussh" -f ~/.ssh/soqemussh - -# Run the script: createbase.sh coreol9Small 20G -# After running the script, the following will be output: -#[root@jppvirtman create_vm]# ll var/lib/libvirt/images/coreol9Small/ -#total 610376 -#-rw-r--r--. 1 root root 380928 Dec 20 14:33 coreol9Small-cidata.iso -#-rw-r--r--. 1 root root 624623616 Dec 20 14:33 coreol9Small.qcow2 -#-rw-r--r--. 1 root root 55 Dec 20 14:32 meta-data -#-rw-r--r--. 1 root root 1047 Dec 20 14:32 user-data - -# These files are now scp to a hypervisor node -# Place the files in /var/lib/libvirt/images/coreol9Small (or whatever is the same as the vm name) -# Create your storage pool as instructed by the script if one doesn't already exist -# Run the virt-install command as instructed by the script - -# Exit on any error -set -e - -# Set variables and defaults -VM=${1:-"base-vm"} # VM name -DISK_SIZE=${2:-"220G"} # Disk size with unit (default 20G) - -# Show usage if help is requested -if [[ "$1" == "-h" || "$1" == "--help" ]]; then - echo "Usage: $0 " - echo "Example: $0 myvm 20G" - echo "Parameters:" - echo " vm_name : Name of the VM (default: base-vm)" - echo " disk_size : Size of the disk with unit G/M (default: 20G)" - echo "All parameters are optional and will use defaults if not specified" - exit 0 -fi - -# Validate disk size format -if ! [[ $DISK_SIZE =~ ^[0-9]+[GM]$ ]]; then - echo "Error: Disk size must be a number followed by G (gigabytes) or M (megabytes)" - echo "Example: 20G or 20480M" - exit 1 -fi - -# Set up directory structure -#D=/root/create_vm/var/lib/libvirt/images -D=/opt/so/saltstack/local/salt/libvirt/images -mkdir -vp $D/$VM -cd $D/$VM - -# Create cloud-init metadata -cat > meta-data << EOF -instance-id: ${VM} -local-hostname: ${VM} -EOF - -# Create user-data configuration -cat > user-data << EOF -#cloud-config -preserve_hostname: False -hostname: ${VM} -fqdn: ${VM}.local - -users: - - default - - name: soqemussh - groups: ['wheel'] - shell: /bin/bash - sudo: ALL=(ALL) NOPASSWD:ALL - lock_passwd: false - passwd: $(echo '___YOUR_HASH_HERE___') - ssh-authorized-keys: - - ssh-ed25519 ___YOUR_PUB_KEY_HERE___ soqemussh - -# Configure where output will go -output: - all: ">> /var/log/cloud-init.log" - -# configure interaction with ssh server -ssh_genkeytypes: ['ed25519', 'rsa'] - -# set timezone for VM -timezone: UTC - -# Install QEMU guest agent. Enable and start the service -packages: - - qemu-guest-agent - -runcmd: - - systemctl enable --now qemu-guest-agent - - systemctl enable --now serial-getty@ttyS0.service - - systemctl enable --now NetworkManager - - growpart /dev/vda 2 - - pvresize /dev/vda2 - - lvextend -l +100%FREE /dev/vg_main/lv_root - - xfs_growfs /dev/vg_main/lv_root - - touch /etc/cloud/cloud-init.disabled - - shutdown -P now -EOF - -# First, copy the base image with progress -echo "Creating base VM image..." -rsync --progress /root/create_vm/OL9U5_x86_64-kvm-b253.qcow2 $VM.qcow2 - -# Resize the image to specified size -echo "Resizing image to $DISK_SIZE..." -echo "Current image size: $(qemu-img info $VM.qcow2 | grep 'virtual size' | cut -d':' -f2 | cut -d'(' -f1 | tr -d ' ')" -qemu-img resize -f qcow2 $VM.qcow2 $DISK_SIZE -echo "New image size: $(qemu-img info $VM.qcow2 | grep 'virtual size' | cut -d':' -f2 | cut -d'(' -f1 | tr -d ' ')" - -# Now compress it with progress -echo "Compressing image..." -qemu-img convert -p -O qcow2 -c $VM.qcow2 $VM-compressed.qcow2 -mv -v $VM-compressed.qcow2 $VM.qcow2 - -# Create a cloud-init ISO with progress indication -echo "Creating cloud-init ISO..." -mkisofs -output $VM-cidata.iso -volid CIDATA -rock -verbose user-data meta-data - -# Echo the configuration for verification -echo "Creating VM with the following configuration:" -echo "VM Name: $VM" -echo "Disk Size: $DISK_SIZE" - -echo "Files have been created in $D/$VM" -echo -echo "To complete VM creation on the hypervisor, run:" -echo "virsh pool-create-as --name $VM --type dir --target $D/$VM" -echo "virt-install --name ${VM} \\" -echo " --memory 4096 --vcpus 4 --cpu host \\" -echo " --disk ${VM}.qcow2,format=qcow2,bus=virtio \\" -echo " --disk ${VM}-cidata.iso,device=cdrom \\" -echo " --network bridge=br0,model=virtio \\" -echo " --os-variant=ol9.5 \\" -echo " --import \\" -echo " --noautoconsole" diff --git a/salt/setup/highstate_cron.sls b/salt/setup/highstate_cron.sls deleted file mode 100644 index f8f76e737..000000000 --- a/salt/setup/highstate_cron.sls +++ /dev/null @@ -1,7 +0,0 @@ -post_setup_cron: - cron.present: - - name: 'PATH=$PATH:/usr/sbin salt-call state.highstate' - - identifier: post_setup_cron - - user: root - - minute: '*/5' - - identifier: post_setup_cron From 395c4e37bae3fc2fb25595cd4929cc4015a3e5aa Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Wed, 4 Jun 2025 16:57:59 -0400 Subject: [PATCH 199/315] fix issue with predicable names after kernel update --- .../tools/sbin/so-qcow2-network-predictable | 74 +++++++++++++++---- 1 file changed, 60 insertions(+), 14 deletions(-) diff --git a/salt/hypervisor/tools/sbin/so-qcow2-network-predictable b/salt/hypervisor/tools/sbin/so-qcow2-network-predictable index 9b09465b9..64ec53953 100644 --- a/salt/hypervisor/tools/sbin/so-qcow2-network-predictable +++ b/salt/hypervisor/tools/sbin/so-qcow2-network-predictable @@ -171,19 +171,21 @@ def modify_bls_entry(g): for i, line in enumerate(lines): if line.startswith('options '): logger.info(f"Found options line: {line}") - # Check if net.ifnames parameter exists - if 'net.ifnames=' in line: - # Replace existing parameter - new_line = re.sub(r'net\.ifnames=[01]', 'net.ifnames=1', line) - if new_line != line: - lines[i] = new_line - modified = True - logger.info(f"Updated existing net.ifnames parameter to 1. New line: {new_line}") - else: - # Add parameter - lines[i] = f"{line} net.ifnames=1" + + # First remove any existing net.ifnames parameters (both =0 and =1) + new_line = re.sub(r'\s*net\.ifnames=[01]\s*', ' ', line) + # Also remove any quoted versions + new_line = re.sub(r'\s*"net\.ifnames=[01]"\s*', ' ', new_line) + # Clean up multiple spaces + new_line = re.sub(r'\s+', ' ', new_line).strip() + + # Now add net.ifnames=1 at the end + new_line = f"{new_line} net.ifnames=1" + + if new_line != line: + lines[i] = new_line modified = True - logger.info(f"Added net.ifnames=1 parameter. New line: {lines[i]}") + logger.info(f"Updated options line. New line: {new_line}") break if modified: @@ -238,10 +240,54 @@ def update_grub_config(g): RuntimeError: If GRUB update fails """ try: + # First, read the current grubenv to get the existing kernelopts + logger.info("Reading current grubenv...") + grubenv_content = g.read_file('/boot/grub2/grubenv').decode('utf-8') + logger.info("Current grubenv content:") + logger.info(grubenv_content) + + # Extract current kernelopts + kernelopts_match = re.search(r'^kernelopts="([^"]+)"', grubenv_content, re.MULTILINE) + if kernelopts_match: + current_kernelopts = kernelopts_match.group(1) + logger.info(f"Current kernelopts: {current_kernelopts}") + + # Remove any existing net.ifnames parameters + new_kernelopts = re.sub(r'\s*net\.ifnames=[01]\s*', ' ', current_kernelopts) + # Clean up multiple spaces + new_kernelopts = re.sub(r'\s+', ' ', new_kernelopts).strip() + # Add net.ifnames=1 + new_kernelopts = f"{new_kernelopts} net.ifnames=1" + + logger.info(f"New kernelopts: {new_kernelopts}") + + # Update grubenv with the new kernelopts + logger.info("Setting kernelopts with net.ifnames=1...") + output_editenv = g.command(['grub2-editenv', '-', 'set', f'kernelopts={new_kernelopts}']) + logger.info("grub2-editenv output:") + logger.info(output_editenv) + else: + # If we can't find existing kernelopts, use the default + logger.warning("Could not find existing kernelopts, using default") + output_editenv = g.command(['grub2-editenv', '-', 'set', 'kernelopts=console=tty0 no_timer_check biosdevname=0 resume=/dev/mapper/vg_main-lv_swap rd.lvm.lv=vg_main/lv_root rd.lvm.lv=vg_main/lv_swap net.ifnames=1 crashkernel=1G-64G:448M,64G-:512M']) + logger.info("grub2-editenv output:") + logger.info(output_editenv) + + logger.info("Updating grubby with net.ifnames=1...") + # First remove any existing net.ifnames arguments + output_grubby_remove = g.command(['grubby', '--update-kernel=ALL', '--remove-args=net.ifnames=0 net.ifnames=1']) + logger.info("grubby remove output:") + logger.info(output_grubby_remove) + + # Then add net.ifnames=1 + output_grubby_add = g.command(['grubby', '--update-kernel=ALL', '--args=net.ifnames=1']) + logger.info("grubby add output:") + logger.info(output_grubby_add) + logger.info("Updating GRUB configuration...") - output = g.command(['grub2-mkconfig', '-o', '/boot/grub2/grub.cfg']) + output_mkconfig = g.command(['grub2-mkconfig', '-o', '/boot/grub2/grub.cfg']) logger.info("GRUB update output:") - logger.info(output) + logger.info(output_mkconfig) logger.info("Successfully updated GRUB configuration") except Exception as e: logger.error(f"Failed to update GRUB configuration: {e}") From d9fb79403b9d32cf72a66bbe69076d9cfc0746d3 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Thu, 5 Jun 2025 15:57:56 -0400 Subject: [PATCH 200/315] seems new openldap / libldap.so.2 doesnt have EVP_md2 dependency so check for it before trying to remove it --- salt/libvirt/64962/scripts/so-fix-salt-ldap.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/salt/libvirt/64962/scripts/so-fix-salt-ldap.py b/salt/libvirt/64962/scripts/so-fix-salt-ldap.py index 919b50261..90d603904 100644 --- a/salt/libvirt/64962/scripts/so-fix-salt-ldap.py +++ b/salt/libvirt/64962/scripts/so-fix-salt-ldap.py @@ -21,7 +21,9 @@ uname = 'salt' gname = 'salt' lib = lief.parse(str(src_lib)) -sym = next(i for i in lib.imported_symbols if i.name == 'EVP_md2') + +sym = next((i for i in lib.imported_symbols if i.name == 'EVP_md2'), None) + if sym: # Get the Salt services from DBus. sysbus = dbus.SystemBus() @@ -71,5 +73,7 @@ if sym: if svcs: for sn in svcs: mgr.RestartUnit(sn, 'replace') +else: + print('No EVP_md2 symbol found in the library. No modifications needed.') print('Done.') From 0f71b45e0f47b9288276940b5f77c5751c27a7e8 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Mon, 9 Jun 2025 09:55:16 -0400 Subject: [PATCH 201/315] CPU model=host is deprecated --- salt/libvirt/images/init.sls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/libvirt/images/init.sls b/salt/libvirt/images/init.sls index 6ed472405..b6a5baf04 100644 --- a/salt/libvirt/images/init.sls +++ b/salt/libvirt/images/init.sls @@ -135,7 +135,7 @@ create_vm_sool9: cmd.run: - name: | virt-install --name sool9 \ - --memory 12288 --vcpus 8 --cpu host \ + --memory 12288 --vcpus 8 --cpu host-model \ --disk /nsm/libvirt/images/sool9/sool9.qcow2,format=qcow2,bus=virtio \ --disk /nsm/libvirt/images/sool9/sool9-cidata.iso,device=cdrom \ --network bridge=br0,model=virtio \ From 4666670f4fd7d1c5e73225101005683c34b36ca9 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Mon, 9 Jun 2025 13:53:23 -0400 Subject: [PATCH 202/315] remove logging prefixes --- salt/_runners/setup_hypervisor.py | 208 +++++++++++++++--------------- 1 file changed, 104 insertions(+), 104 deletions(-) diff --git a/salt/_runners/setup_hypervisor.py b/salt/_runners/setup_hypervisor.py index 17bdacbd5..6ddd571c9 100644 --- a/salt/_runners/setup_hypervisor.py +++ b/salt/_runners/setup_hypervisor.py @@ -87,11 +87,11 @@ def _set_ownership_and_perms(path: str, mode: int): socore_gid = pwd.getpwnam('socore').pw_gid os.chown(path, socore_uid, socore_gid) os.chmod(path, mode) - log.debug(f"PERMS: Set ownership socore:socore and mode {oct(mode)} for {path}") + log.debug(f"Set ownership socore:socore and mode {oct(mode)} for {path}") except KeyError: - log.warning(f"PERMS: socore user not found, skipping ownership/permission change for {path}") + log.warning(f"socore user not found, skipping ownership/permission change for {path}") except Exception as e: - log.warning(f"PERMS: Failed to set ownership/permissions for {path}: {str(e)}") + log.warning(f"Failed to set ownership/permissions for {path}: {str(e)}") def _read_and_encode_key(key_path: str) -> str: """Read a key file and return its base64 encoded content.""" @@ -108,7 +108,7 @@ def _check_license(): license_path = '/opt/so/saltstack/local/pillar/soc/license.sls' if not os.path.exists(license_path): - log.error("LICENSE: License file not found at %s", license_path) + log.error("License file not found at %s", license_path) return False try: @@ -116,25 +116,25 @@ def _check_license(): license_data = yaml.safe_load(f) if not license_data: - log.error("LICENSE: Empty or invalid license file") + log.error("Empty or invalid license file") return False license_id = license_data.get('license_id') features = license_data.get('features', []) if not license_id: - log.error("LICENSE: No license_id found in license file") + log.error("No license_id found in license file") return False if 'vrt' not in features: - log.error("LICENSE: 'vrt' feature not found in license") + log.error("vrt feature not found in license") return False - log.info("LICENSE: License validation successful") + log.info("License validation successful") return True except Exception as e: - log.error("LICENSE: Error reading license file: %s", str(e)) + log.error("Error reading license file: %s", str(e)) return False def _check_file_exists(path): @@ -157,11 +157,11 @@ def _validate_image_checksum(path, expected_sha256): downloaded_sha256 = sha256_hash.hexdigest() if downloaded_sha256 != expected_sha256: - log.error("VALIDATE: Checksum validation failed for %s - expected: %s, got: %s", + log.error("Checksum validation failed for %s - expected: %s, got: %s", path, expected_sha256, downloaded_sha256) return False - log.info("VALIDATE: Checksum validation successful for %s", path) + log.info("Checksum validation successful for %s", path) return True # Constants @@ -181,14 +181,14 @@ def _download_image(): if _validate_image_checksum(IMAGE_PATH, IMAGE_SHA256): return True else: - log.warning("DOWNLOAD: Existing image has invalid checksum, will re-download") + log.warning("Existing image has invalid checksum, will re-download") os.unlink(IMAGE_PATH) - log.info("DOWNLOAD: Starting image download process") + log.info("Starting image download process") try: # Download file - log.info("DOWNLOAD: Downloading Oracle Linux KVM image from %s to %s", IMAGE_URL, IMAGE_PATH) + log.info("Downloading Oracle Linux KVM image from %s to %s", IMAGE_URL, IMAGE_PATH) response = requests.get(IMAGE_URL, stream=True) response.raise_for_status() @@ -207,7 +207,7 @@ def _download_image(): current_time = time.time() if current_time - last_log_time >= 1: progress = (downloaded_size / total_size) * 100 if total_size > 0 else 0 - log.info("DOWNLOAD: Progress - %.1f%% (%d/%d bytes)", + log.info("Progress - %.1f%% (%d/%d bytes)", progress, downloaded_size, total_size) last_log_time = current_time @@ -216,11 +216,11 @@ def _download_image(): os.unlink(IMAGE_PATH) return False - log.info("DOWNLOAD: Successfully downloaded and validated Oracle Linux KVM image") + log.info("Successfully downloaded and validated Oracle Linux KVM image") return True except Exception as e: - log.error("DOWNLOAD: Error downloading hypervisor image: %s", str(e)) + log.error("Error downloading hypervisor image: %s", str(e)) if os.path.exists(IMAGE_PATH): os.unlink(IMAGE_PATH) return False @@ -238,7 +238,7 @@ def _check_ssh_keys_exist(): dest_path = os.path.join(dest_dir, os.path.basename(pub_key_path)) if os.path.exists(key_path) and os.path.exists(pub_key_path) and os.path.exists(dest_path): - log.info("SETUP_KEYS: SSH keys already exist") + log.info("SSH keys already exist") return True return False @@ -258,7 +258,7 @@ def _setup_ssh_keys(): return True # Create key directories if they don't exist and set permissions - log.info("SETUP_KEYS: Setting up SSH directory and keys") + log.info("Setting up SSH directory and keys") parent_dir = os.path.dirname(key_dir) # /etc/ssh/auth_keys os.makedirs(parent_dir, exist_ok=True) os.chmod(parent_dir, 0o700) @@ -267,7 +267,7 @@ def _setup_ssh_keys(): os.chmod(key_dir, 0o700) # Generate new ed25519 key pair - log.info("SETUP_KEYS: Generating new SSH keys") + log.info("Generating new SSH keys") private_key = ed25519.Ed25519PrivateKey.generate() public_key = private_key.public_key() @@ -296,7 +296,7 @@ def _setup_ssh_keys(): os.chmod(key_path, 0o600) os.chmod(pub_key_path, 0o640) - log.info("SETUP_KEYS: SSH keys generated successfully") + log.info("SSH keys generated successfully") # Copy public key to saltstack directory dest_dir = '/opt/so/saltstack/local/salt/libvirt/ssh/keys' @@ -307,11 +307,11 @@ def _setup_ssh_keys(): with salt.utils.files.fopen(dest_path, 'wb') as dst: dst.write(src.read()) - log.info("SETUP_KEYS: Public key copied to %s", dest_dir) + log.info("Public key copied to %s", dest_dir) return True except Exception as e: - log.error("SETUP_KEYS: Error setting up SSH keys: %s", str(e)) + log.error("Error setting up SSH keys: %s", str(e)) return False def _check_vm_exists(vm_name: str) -> bool: @@ -335,7 +335,7 @@ def _check_vm_exists(vm_name: str) -> bool: exists = all(os.path.exists(f) for f in required_files) if exists: - log.info("MAIN: VM %s already exists", vm_name) + log.info("VM %s already exists", vm_name) return exists def _ensure_hypervisor_host_dir(minion_id: str = None): @@ -352,7 +352,7 @@ def _ensure_hypervisor_host_dir(minion_id: str = None): bool: True if directory exists or was created successfully, False otherwise """ if not minion_id: - log.warning("HOSTDIR: No minion_id provided, skipping host directory creation") + log.warning("No minion_id provided, skipping host directory creation") return True try: @@ -364,33 +364,33 @@ def _ensure_hypervisor_host_dir(minion_id: str = None): # Check if directory exists and create it if it doesn't if os.path.exists(host_dir): - log.info(f"HOSTDIR: Hypervisor host directory already exists: {host_dir}") + log.info(f"Hypervisor host directory already exists: {host_dir}") # Create the VMs file if it doesn't exist vms_file = f'/opt/so/saltstack/local/salt/hypervisor/hosts/{hostname}VMs' if not os.path.exists(vms_file): with salt.utils.files.fopen(vms_file, 'w') as f: f.write('[]') - log.info(f"HOSTDIR: Created empty VMs file: {vms_file}") + log.info(f"Created empty VMs file: {vms_file}") # Set proper ownership for the VMs file try: socore_uid = pwd.getpwnam('socore').pw_uid socore_gid = pwd.getpwnam('socore').pw_gid os.chown(vms_file, socore_uid, socore_gid) - log.info(f"HOSTDIR: Set ownership to socore:socore for {vms_file}") + log.info(f"Set ownership to socore:socore for {vms_file}") except (KeyError, Exception) as e: - log.warning(f"HOSTDIR: Failed to set ownership for VMs file: {str(e)}") + log.warning(f"Failed to set ownership for VMs file: {str(e)}") return True # Create all necessary parent directories os.makedirs(host_dir, exist_ok=True) - log.info(f"HOSTDIR: Created hypervisor host directory: {host_dir}") + log.info(f"Created hypervisor host directory: {host_dir}") # Create the VMs file with an empty JSON array vms_file = f'/opt/so/saltstack/local/salt/hypervisor/hosts/{hostname}VMs' with salt.utils.files.fopen(vms_file, 'w') as f: f.write('[]') - log.info(f"HOSTDIR: Created empty VMs file: {vms_file}") + log.info(f"Created empty VMs file: {vms_file}") # Set proper ownership (socore:socore) try: @@ -408,15 +408,15 @@ def _ensure_hypervisor_host_dir(minion_id: str = None): if os.path.exists(parent_dir): os.chown(parent_dir, socore_uid, socore_gid) - log.info(f"HOSTDIR: Set ownership to socore:socore for {host_dir} and {vms_file}") + log.info(f"Set ownership to socore:socore for {host_dir} and {vms_file}") except KeyError: - log.warning("HOSTDIR: socore user not found, skipping ownership change") + log.warning("socore user not found, skipping ownership change") except Exception as e: - log.warning(f"HOSTDIR: Failed to set ownership: {str(e)}") + log.warning(f"Failed to set ownership: {str(e)}") return True except Exception as e: - log.error(f"HOSTDIR: Error creating hypervisor host directory: {str(e)}") + log.error(f"Error creating hypervisor host directory: {str(e)}") return False def _apply_dyanno_hypervisor_state(): @@ -430,7 +430,7 @@ def _apply_dyanno_hypervisor_state(): bool: True if state was applied successfully, False otherwise """ try: - log.info("DYANNO: Applying soc.dyanno.hypervisor state on salt master") + log.info("Applying soc.dyanno.hypervisor state on salt master") # Initialize the LocalClient local = salt.client.LocalClient() @@ -438,33 +438,33 @@ def _apply_dyanno_hypervisor_state(): # Target the salt master to apply the soc.dyanno.hypervisor state target = MANAGER_HOSTNAME + '_*' state_result = local.cmd(target, 'state.apply', ['soc.dyanno.hypervisor', "pillar={'baseDomain': {'status': 'PreInit'}}", 'concurrent=True'], tgt_type='glob') - log.debug(f"DYANNO: state_result: {state_result}") + log.debug(f"state_result: {state_result}") # Check if state was applied successfully if state_result: success = True for minion, states in state_result.items(): if not isinstance(states, dict): - log.error(f"DYANNO: Unexpected result format from {minion}: {states}") + log.error(f"Unexpected result format from {minion}: {states}") success = False continue for state_id, state_data in states.items(): if not state_data.get('result', False): - log.error(f"DYANNO: State {state_id} failed on {minion}: {state_data.get('comment', 'No comment')}") + log.error(f"State {state_id} failed on {minion}: {state_data.get('comment', 'No comment')}") success = False if success: - log.info("DYANNO: Successfully applied soc.dyanno.hypervisor state") + log.info("Successfully applied soc.dyanno.hypervisor state") return True else: - log.error("DYANNO: Failed to apply soc.dyanno.hypervisor state") + log.error("Failed to apply soc.dyanno.hypervisor state") return False else: - log.error("DYANNO: No response from salt master when applying soc.dyanno.hypervisor state") + log.error("No response from salt master when applying soc.dyanno.hypervisor state") return False except Exception as e: - log.error(f"DYANNO: Error applying soc.dyanno.hypervisor state: {str(e)}") + log.error(f"Error applying soc.dyanno.hypervisor state: {str(e)}") return False def _apply_cloud_config_state(): @@ -475,7 +475,7 @@ def _apply_cloud_config_state(): bool: True if state was applied successfully, False otherwise """ try: - log.info("CLOUDCONFIG: Applying salt.cloud.config state on salt master") + log.info("Applying salt.cloud.config state on salt master") # Initialize the LocalClient local = salt.client.LocalClient() @@ -483,33 +483,33 @@ def _apply_cloud_config_state(): # Target the salt master to apply the soc.dyanno.hypervisor state target = MANAGER_HOSTNAME + '_*' state_result = local.cmd(target, 'state.apply', ['salt.cloud.config', 'concurrent=True'], tgt_type='glob') - log.debug(f"CLOUDCONFIG: state_result: {state_result}") + log.debug(f"state_result: {state_result}") # Check if state was applied successfully if state_result: success = True for minion, states in state_result.items(): if not isinstance(states, dict): - log.error(f"CLOUDCONFIG: Unexpected result format from {minion}: {states}") + log.error(f"Unexpected result format from {minion}: {states}") success = False continue for state_id, state_data in states.items(): if not state_data.get('result', False): - log.error(f"CLOUDCONFIG: State {state_id} failed on {minion}: {state_data.get('comment', 'No comment')}") + log.error(f"State {state_id} failed on {minion}: {state_data.get('comment', 'No comment')}") success = False if success: - log.info("CLOUDCONFIG: Successfully applied salt.cloud.config state") + log.info("Successfully applied salt.cloud.config state") return True else: - log.error("CLOUDCONFIG: Failed to apply salt.cloud.config state") + log.error("Failed to apply salt.cloud.config state") return False else: - log.error("CLOUDCONFIG: No response from salt master when applying salt.cloud.config state") + log.error("No response from salt master when applying salt.cloud.config state") return False except Exception as e: - log.error(f"CLOUDCONFIG: Error applying salt.cloud.config state: {str(e)}") + log.error(f"Error applying salt.cloud.config state: {str(e)}") return False def setup_environment(vm_name: str = 'sool9', disk_size: str = '220G', minion_id: str = None): @@ -579,31 +579,31 @@ def setup_environment(vm_name: str = 'sool9', disk_size: str = '220G', minion_id for attempt in range(1, max_retries + 1): mine_update_result = local.cmd(minion_id, 'mine.update') - log.debug(f"DYANNO: mine_update_result: {mine_update_result}") + log.debug(f"mine_update_result: {mine_update_result}") # Check if mine.update was successful if mine_update_result and all(mine_update_result.values()): - log.info(f"DYANNO: mine.update successful on attempt {attempt}") + log.info(f"mine.update successful on attempt {attempt}") mine_update_success = True break else: - log.warning(f"DYANNO: mine.update failed on attempt {attempt}/{max_retries}, retrying in {retry_delay} seconds...") + log.warning(f"mine.update failed on attempt {attempt}/{max_retries}, retrying in {retry_delay} seconds...") time.sleep(retry_delay) if not mine_update_success: - log.error(f"DYANNO: mine.update failed after {max_retries} attempts") + log.error(f"mine.update failed after {max_retries} attempts") # Apply the soc.dyanno.hypervisor state on the salt master if not _apply_cloud_config_state(): - log.warning("MAIN: Failed to apply salt.cloud.config state, continuing with setup") + log.warning("Failed to apply salt.cloud.config state, continuing with setup") # We don't return an error here as we want to continue with the setup process # Apply the soc.dyanno.hypervisor state on the salt master if not _apply_dyanno_hypervisor_state(): - log.warning("MAIN: Failed to apply soc.dyanno.hypervisor state, continuing with setup") + log.warning("Failed to apply soc.dyanno.hypervisor state, continuing with setup") # We don't return an error here as we want to continue with the setup process - log.info("MAIN: Starting setup_environment in setup_hypervisor runner") + log.info("Starting setup_environment in setup_hypervisor runner") # Check if environment is already set up image_exists = _check_file_exists(IMAGE_PATH) @@ -616,9 +616,9 @@ def setup_environment(vm_name: str = 'sool9', disk_size: str = '220G', minion_id # Handle image setup if needed if not image_valid: - log.info("MAIN: Starting image download/validation process") + log.info("Starting image download/validation process") if not _download_image(): - log.error("MAIN: Image download failed") + log.error("Image download failed") return { 'success': False, 'error': 'Image download failed', @@ -628,9 +628,9 @@ def setup_environment(vm_name: str = 'sool9', disk_size: str = '220G', minion_id # Handle SSH key setup if needed if not keys_exist: - log.info("MAIN: Setting up SSH keys") + log.info("Setting up SSH keys") if not _setup_ssh_keys(): - log.error("MAIN: SSH key setup failed") + log.error("SSH key setup failed") return { 'success': False, 'error': 'SSH key setup failed', @@ -641,39 +641,39 @@ def setup_environment(vm_name: str = 'sool9', disk_size: str = '220G', minion_id # Create/recreate VM if needed if create_vm_needed or not vm_exists: if vm_exists: - log.info("MAIN: Environment changes detected, recreating VM %s", vm_name) + log.info("Environment changes detected, recreating VM %s", vm_name) else: - log.info("MAIN: Creating new VM %s", vm_name) + log.info("Creating new VM %s", vm_name) vm_result = create_vm(vm_name, disk_size) else: - log.info("MAIN: No changes detected, using existing VM %s", vm_name) + log.info("No changes detected, using existing VM %s", vm_name) vm_result = { 'success': True, 'vm_dir': f'/opt/so/saltstack/local/salt/libvirt/images/{vm_name}' } success = vm_result.get('success', False) - log.info("MAIN: Setup environment completed with status: %s", "SUCCESS" if success else "FAILED") + log.info("Setup environment completed with status: %s", "SUCCESS" if success else "FAILED") # If setup was successful and we have a minion_id, run highstate if success and minion_id: - log.info("MAIN: Running highstate on hypervisor %s", minion_id) + log.info("Running highstate on hypervisor %s", minion_id) try: # Initialize the LocalClient local = salt.client.LocalClient() # Run highstate on the hypervisor highstate_result = local.cmd(minion_id, 'state.highstate', [], timeout=1800) if highstate_result and minion_id in highstate_result: - log.info("MAIN: Highstate initiated on %s", minion_id) + log.info("Highstate initiated on %s", minion_id) else: - log.error("MAIN: Highstate failed or timed out on %s", minion_id) + log.error("Highstate failed or timed out on %s", minion_id) return { 'success': False, 'error': 'Highstate failed or timed out', 'vm_result': None } except Exception as e: - log.error("MAIN: Error running highstate on %s: %s", minion_id, str(e)) + log.error("Error running highstate on %s: %s", minion_id, str(e)) return { 'success': False, 'error': f'Error running highstate: {str(e)}', @@ -732,16 +732,16 @@ def create_vm(vm_name: str, disk_size: str = '220G'): try: # Input validation if not isinstance(vm_name, str) or not vm_name: - log.error("CREATEVM: Invalid VM name") + log.error("Invalid VM name") return {'success': False, 'error': 'Invalid VM name'} if not vm_name.isalnum() and not all(c in '-_' for c in vm_name if not c.isalnum()): - log.error("CREATEVM: VM name must contain only alphanumeric characters, hyphens, or underscores") + log.error("VM name must contain only alphanumeric characters, hyphens, or underscores") return {'success': False, 'error': 'Invalid VM name format'} # Validate disk size format if not isinstance(disk_size, str) or not disk_size.endswith(('G', 'M')): - log.error("CREATEVM: Invalid disk size format. Must end with G or M") + log.error("Invalid disk size format. Must end with G or M") return {'success': False, 'error': 'Invalid disk size format'} try: @@ -749,12 +749,12 @@ def create_vm(vm_name: str, disk_size: str = '220G'): if size_num <= 0: raise ValueError except ValueError: - log.error("CREATEVM: Invalid disk size number") + log.error("Invalid disk size number") return {'success': False, 'error': 'Invalid disk size number'} # Ensure base image exists if not os.path.exists(IMAGE_PATH): - log.error("CREATEVM: Base image not found at %s", IMAGE_PATH) + log.error("Base image not found at %s", IMAGE_PATH) return {'success': False, 'error': 'Base image not found'} # Set up directory structure @@ -770,7 +770,7 @@ def create_vm(vm_name: str, disk_size: str = '220G'): with salt.utils.files.fopen(pub_key_path, 'r') as f: ssh_pub_key = f.read().strip() except Exception as e: - log.error("CREATEVM: Failed to read SSH public key: %s", str(e)) + log.error("Failed to read SSH public key: %s", str(e)) return {'success': False, 'error': 'Failed to read SSH public key'} # Read pillar data for soqemussh password hash @@ -785,11 +785,11 @@ def create_vm(vm_name: str, disk_size: str = '220G'): password_hash = pillar_data.get('vm', {}).get('user', {}).get('soqemussh', {}).get('passwordHash') if password_hash: passwd_line = f" passwd: {password_hash}\n" - log.info("CREATEVM: Found soqemussh password hash in pillar.") + log.info("Found soqemussh password hash in pillar.") else: - log.info("CREATEVM: No soqemussh password hash found in pillar, omitting passwd line.") + log.info("No soqemussh password hash found in pillar, omitting passwd line.") except Exception as e: - log.warning(f"CREATEVM: Error reading or parsing pillar file {pillar_path}: {str(e)}. Omitting passwd line.") + log.warning(f"Error reading or parsing pillar file {pillar_path}: {str(e)}. Omitting passwd line.") # Read and encode GPG keys keys_dir = '/opt/so/saltstack/default/salt/repo/client/files/oracle/keys' @@ -809,7 +809,7 @@ local-hostname: {vm_name} _set_ownership_and_perms(meta_data_path, mode=0o640) with salt.utils.files.fopen(meta_data_path, 'w') as f: f.write(meta_data) - log.info("CREATEVM: Created meta-data") + log.info("Created meta-data") # Create network-data network_data = """network: @@ -820,7 +820,7 @@ local-hostname: {vm_name} _set_ownership_and_perms(network_data_path, mode=0o640) with salt.utils.files.fopen(network_data_path, 'w') as f: f.write(network_data) - log.info("CREATEVM: Created network-data") + log.info("Created network-data") # Create user-data user_data = f"""#cloud-config @@ -913,7 +913,7 @@ power_state: _set_ownership_and_perms(user_data_path, mode=0o640) with salt.utils.files.fopen(user_data_path, 'w') as f: f.write(user_data) - log.info("CREATEVM: Created user-data") + log.info("Created user-data") # Copy and resize base image base_image = IMAGE_PATH @@ -921,11 +921,11 @@ power_state: # Copy base image with progress logging import shutil - log.info("CREATEVM: Copying base image to %s", vm_image) + log.info("Copying base image to %s", vm_image) shutil.copy2(base_image, vm_image) # Set ownership and permissions for the copied image _set_ownership_and_perms(vm_image, mode=0o640) - log.info("CREATEVM: Base image copy complete") + log.info("Base image copy complete") # Get current image size import subprocess @@ -939,26 +939,26 @@ power_state: # Only resize if requested size is larger if requested_size > current_size: - log.info("CREATEVM: Resizing image to %s", disk_size) + log.info("Resizing image to %s", disk_size) try: result = subprocess.run(['qemu-img', 'resize', '-f', 'qcow2', vm_image, disk_size], check=True, capture_output=True, text=True) - log.info("CREATEVM: Image resize complete") + log.info("Image resize complete") except subprocess.CalledProcessError as e: - log.error("CREATEVM: Failed to resize image: %s", e.stderr) + log.error("Failed to resize image: %s", e.stderr) raise else: - log.info("CREATEVM: Image already at or larger than requested size") + log.info("Image already at or larger than requested size") except subprocess.CalledProcessError as e: - log.error("CREATEVM: Failed to get image info: %s", e.stderr) + log.error("Failed to get image info: %s", e.stderr) raise except json.JSONDecodeError as e: - log.error("CREATEVM: Failed to parse image info: %s", str(e)) + log.error("Failed to parse image info: %s", str(e)) raise # Compress image temp_image = f"{vm_image}.temp" - log.info("CREATEVM: Compressing image") + log.info("Compressing image") # Start compression in a subprocess process = subprocess.Popen(['qemu-img', 'convert', '-O', 'qcow2', '-c', vm_image, temp_image], @@ -974,7 +974,7 @@ power_state: if os.path.exists(temp_image): compressed_size = os.path.getsize(temp_image) progress = (compressed_size / source_size) * 100 - log.info("CREATEVM: Compression progress - %.1f%% (%d/%d bytes)", + log.info("Compression progress - %.1f%% (%d/%d bytes)", progress, compressed_size, source_size) last_log_time = current_time @@ -983,10 +983,10 @@ power_state: os.replace(temp_image, vm_image) # Set ownership and permissions for the compressed image _set_ownership_and_perms(vm_image, mode=0o640) - log.info("CREATEVM: Image compression complete") + log.info("Image compression complete") else: error = process.stderr.read().decode('utf-8') - log.error("CREATEVM: Failed to compress image: %s", error) + log.error("Failed to compress image: %s", error) if os.path.exists(temp_image): os.unlink(temp_image) raise subprocess.CalledProcessError(process.returncode, 'qemu-img convert', stderr=error) @@ -998,7 +998,7 @@ power_state: check=True, capture_output=True) # Set ownership and permissions for the created ISO _set_ownership_and_perms(cidata_iso, mode=0o640) - log.info("CREATEVM: Created cidata ISO") + log.info("Created cidata ISO") # Generate SHA256 hash of the qcow2 image sha256_hash = hashlib.sha256() @@ -1013,7 +1013,7 @@ power_state: # Set ownership and permissions for the hash file _set_ownership_and_perms(hash_file, mode=0o640) - log.info("CREATEVM: Generated SHA256 hash for %s", vm_image) + log.info("Generated SHA256 hash for %s", vm_image) return { 'success': True, @@ -1021,7 +1021,7 @@ power_state: } except Exception as e: - log.error("CREATEVM: Error creating VM: %s", str(e)) + log.error("Error creating VM: %s", str(e)) return {'success': False, 'error': str(e)} def regenerate_ssh_keys(): @@ -1058,11 +1058,11 @@ def regenerate_ssh_keys(): else: print("Failed to regenerate SSH keys") """ - log.info("MAIN: Starting SSH key regeneration") + log.info("Starting SSH key regeneration") try: # Verify current state if not _check_ssh_keys_exist(): - log.warning("MAIN: No existing SSH keys found to regenerate") + log.warning("No existing SSH keys found to regenerate") return _setup_ssh_keys() # Remove existing keys @@ -1075,18 +1075,18 @@ def regenerate_ssh_keys(): for path in [key_path, pub_key_path, dest_path]: try: os.unlink(path) - log.info("MAIN: Removed existing key: %s", path) + log.info("Removed existing key: %s", path) except FileNotFoundError: - log.warning("MAIN: Key file not found: %s", path) + log.warning("Key file not found: %s", path) # Generate new keys if _setup_ssh_keys(): - log.info("MAIN: SSH keys regenerated successfully") + log.info("SSH keys regenerated successfully") return True - log.error("MAIN: Failed to regenerate SSH keys") + log.error("Failed to regenerate SSH keys") return False except Exception as e: - log.error("MAIN: Error regenerating SSH keys: %s", str(e)) + log.error("Error regenerating SSH keys: %s", str(e)) return False From 4c9773c68d7f99b50e4f458d6d4d9c48d701ca0e Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Mon, 9 Jun 2025 14:37:06 -0400 Subject: [PATCH 203/315] reenable sslverify --- salt/repo/client/oracle.sls | 2 -- 1 file changed, 2 deletions(-) diff --git a/salt/repo/client/oracle.sls b/salt/repo/client/oracle.sls index 2f421b700..70f529830 100644 --- a/salt/repo/client/oracle.sls +++ b/salt/repo/client/oracle.sls @@ -53,12 +53,10 @@ so_repo: - baseurl: file:///nsm/repo/ {% else %} - baseurl: https://{{ GLOBALS.repo_host }}/repo - - sslverify: 0 {% endif %} - enabled: 1 - gpgcheck: 1 - {% endif %} # TODO: Add a pillar entry for custom repos From 1e2453eddfe8a7ab084139c971f23ad888298446 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Mon, 9 Jun 2025 14:47:53 -0400 Subject: [PATCH 204/315] debug loglevel --- salt/hypervisor/map.jinja | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/salt/hypervisor/map.jinja b/salt/hypervisor/map.jinja index da8716415..dae3985d4 100644 --- a/salt/hypervisor/map.jinja +++ b/salt/hypervisor/map.jinja @@ -19,12 +19,12 @@ {# Build enhanced HYPERVISORS structure #} {% set HYPERVISORS = {} %} -{% do salt.log.info('salt/hypervisor/map.jinja: NODES content: ' ~ NODES | tojson) %} +{% do salt.log.debug('salt/hypervisor/map.jinja: NODES content: ' ~ NODES | tojson) %} {% for role, hypervisors in NODES.items() %} - {% do salt.log.info('salt/hypervisor/map.jinja: Processing role: ' ~ role) %} + {% do salt.log.debug('salt/hypervisor/map.jinja: Processing role: ' ~ role) %} {% do HYPERVISORS.update({role: {}}) %} {% for hypervisor, config in hypervisors.items() %} - {% do salt.log.info('salt/hypervisor/map.jinja: Processing hypervisor: ' ~ hypervisor ~ ' with config: ' ~ config | tojson) %} + {% do salt.log.debug('salt/hypervisor/map.jinja: Processing hypervisor: ' ~ hypervisor ~ ' with config: ' ~ config | tojson) %} {# Get model from cached grains using Salt runner #} {% set grains = salt.saltutil.runner('cache.grains', tgt=hypervisor ~ '_*', tgt_type='glob') %} {% set model = '' %} @@ -38,15 +38,15 @@ {% set vms = {} %} {% set vm_list = [] %} {% set vm_list_file = 'hypervisor/hosts/' ~ hypervisor ~ 'VMs' %} - {% do salt.log.info('salt/hypervisor/map.jinja: VM list file: ' ~ vm_list_file) %} + {% do salt.log.debug('salt/hypervisor/map.jinja: VM list file: ' ~ vm_list_file) %} {% if salt['file.file_exists']('/opt/so/saltstack/local/salt/' ~ vm_list_file) %} {% import_json vm_list_file as vm_list %} {% endif %} {% if vm_list %} - {% do salt.log.info('salt/hypervisor/map.jinja: VM list content: ' ~ vm_list | tojson) %} + {% do salt.log.debug('salt/hypervisor/map.jinja: VM list content: ' ~ vm_list | tojson) %} {% else %} {# we won't get here if the vm_list_file doesn't exist because we will get TemplateNotFound on the import_json #} - {% do salt.log.info('salt/hypervisor/map.jinja: VM list empty: ' ~ vm_list_file) %} + {% do salt.log.debug('salt/hypervisor/map.jinja: VM list empty: ' ~ vm_list_file) %} {% endif %} {# Load status and configuration for each VM #} @@ -54,25 +54,25 @@ {# Get VM details from list entry #} {% set hostname = vm.get('hostname', '') %} {% set role = vm.get('role', '') %} - {% do salt.log.info('salt/hypervisor/map.jinja: Processing VM - hostname: ' ~ hostname ~ ', role: ' ~ role) %} + {% do salt.log.debug('salt/hypervisor/map.jinja: Processing VM - hostname: ' ~ hostname ~ ', role: ' ~ role) %} {# Load VM configuration from config file #} {% set vm_file = 'hypervisor/hosts/' ~ hypervisor ~ '/' ~ hostname ~ '_' ~ role %} - {% do salt.log.info('salt/hypervisor/map.jinja: VM config file: ' ~ vm_file) %} + {% do salt.log.debug('salt/hypervisor/map.jinja: VM config file: ' ~ vm_file) %} {% import_json vm_file as vm_state %} {% if vm_state %} - {% do salt.log.info('salt/hypervisor/map.jinja: VM config content: ' ~ vm_state | tojson) %} + {% do salt.log.debug('salt/hypervisor/map.jinja: VM config content: ' ~ vm_state | tojson) %} {% set vm_data = {'config': vm_state.config} %} {# Load VM status from status file #} {% set status_file = vm_file ~ '.status' %} - {% do salt.log.info('salt/hypervisor/map.jinja: VM status file: ' ~ status_file) %} + {% do salt.log.debug('salt/hypervisor/map.jinja: VM status file: ' ~ status_file) %} {% import_json status_file as status_data %} {% if status_data %} - {% do salt.log.info('salt/hypervisor/map.jinja: VM status content: ' ~ status_data | tojson) %} + {% do salt.log.debug('salt/hypervisor/map.jinja: VM status content: ' ~ status_data | tojson) %} {% do vm_data.update({'status': status_data}) %} {% else %} - {% do salt.log.info('salt/hypervisor/map.jinja: Status file empty: ' ~ status_file) %} + {% do salt.log.debug('salt/hypervisor/map.jinja: Status file empty: ' ~ status_file) %} {% do vm_data.update({ 'status': { 'status': '', @@ -83,7 +83,7 @@ {% endif %} {% do vms.update({hostname ~ '_' ~ role: vm_data}) %} {% else %} - {% do salt.log.info('salt/hypervisor/map.jinja: Config file empty: ' ~ vm_file) %} + {% do salt.log.debug('salt/hypervisor/map.jinja: Config file empty: ' ~ vm_file) %} {% endif %} {% endfor %} @@ -96,11 +96,11 @@ {# Find all status files for this hypervisor #} {% set relative_path = 'hypervisor/hosts/' ~ hypervisor %} {% set absolute_path = '/opt/so/saltstack/local/salt/' ~ relative_path %} - {% do salt.log.info('salt/hypervisor/map.jinja: Scanning for status files in: ' ~ absolute_path) %} + {% do salt.log.debug('salt/hypervisor/map.jinja: Scanning for status files in: ' ~ absolute_path) %} {# Try to find status files using file.find with absolute path #} {% set status_files = salt['file.find'](absolute_path, name='*_*.status', type='f') %} - {% do salt.log.info('salt/hypervisor/map.jinja: Found status files: ' ~ status_files | tojson) %} + {% do salt.log.debug('salt/hypervisor/map.jinja: Found status files: ' ~ status_files | tojson) %} {# Convert absolute paths back to relative paths for processing #} {% set relative_status_files = [] %} @@ -110,7 +110,7 @@ {% endfor %} {% set status_files = relative_status_files %} - {% do salt.log.info('salt/hypervisor/map.jinja: Converted to relative paths: ' ~ status_files | tojson) %} + {% do salt.log.debug('salt/hypervisor/map.jinja: Converted to relative paths: ' ~ status_files | tojson) %} {% for status_file in status_files %} {# Extract the VM name from the filename #} @@ -124,12 +124,12 @@ {% endif %} {# Read the status file #} - {% do salt.log.info('salt/hypervisor/map.jinja: Processing potential destroyed VM status file: ' ~ status_file) %} + {% do salt.log.debug('salt/hypervisor/map.jinja: Processing potential destroyed VM status file: ' ~ status_file) %} {% import_json status_file as status_data %} {# Only process files with "Destroyed Instance" status #} {% if status_data and status_data.status == 'Destroyed Instance' %} - {% do salt.log.info('salt/hypervisor/map.jinja: Found VM with Destroyed Instance status: ' ~ vm_name) %} + {% do salt.log.debug('salt/hypervisor/map.jinja: Found VM with Destroyed Instance status: ' ~ vm_name) %} {# Add to vms with minimal config #} {% do vms.update({ From 849f8f13bc8a45f78400959a420d5224db077639 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Tue, 10 Jun 2025 13:08:42 -0400 Subject: [PATCH 205/315] create virt feature pillars 160 to 170 soup --- salt/manager/tools/sbin/soup | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/salt/manager/tools/sbin/soup b/salt/manager/tools/sbin/soup index aa030bcdb..bb6a83d86 100755 --- a/salt/manager/tools/sbin/soup +++ b/salt/manager/tools/sbin/soup @@ -418,6 +418,7 @@ preupgrade_changes() { [[ "$INSTALLEDVERSION" == 2.4.140 ]] && up_to_2.4.141 [[ "$INSTALLEDVERSION" == 2.4.141 ]] && up_to_2.4.150 [[ "$INSTALLEDVERSION" == 2.4.150 ]] && up_to_2.4.160 + [[ "$INSTALLEDVERSION" == 2.4.160 ]] && up_to_2.4.170 true } @@ -446,6 +447,7 @@ postupgrade_changes() { [[ "$POSTVERSION" == 2.4.140 ]] && post_to_2.4.141 [[ "$POSTVERSION" == 2.4.141 ]] && post_to_2.4.150 [[ "$POSTVERSION" == 2.4.150 ]] && post_to_2.4.160 + [[ "$POSTVERSION" == 2.4.160 ]] && post_to_2.4.170 true } @@ -586,6 +588,11 @@ post_to_2.4.160() { POSTVERSION=2.4.160 } +post_to_2.4.170() { + echo "Nothing to apply" + POSTVERSION=2.4.170 +} + repo_sync() { echo "Sync the local repo." su socore -c '/usr/sbin/so-repo-sync' || fail "Unable to complete so-repo-sync." @@ -829,6 +836,20 @@ up_to_2.4.160() { INSTALLEDVERSION=2.4.160 } +up_to_2.4.170() { + echo "Creating pillar files for virtualization feature" + + states=("hypervisor" "vm" "libvirt") + + # Create pillar files for each state + for state in "${states[@]}"; do + mkdir -p /opt/so/saltstack/local/pillar/$state + touch /opt/so/saltstack/local/pillar/$state/adv_$state.sls /opt/so/saltstack/local/pillar/$state/soc_$state.sls + done + + INSTALLEDVERSION=2.4.170 +} + add_hydra_pillars() { mkdir -p /opt/so/saltstack/local/pillar/hydra touch /opt/so/saltstack/local/pillar/hydra/soc_hydra.sls From 48dfcab9f0c9ba1fa571d3785b6f28014edf91a8 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Tue, 10 Jun 2025 13:44:24 -0400 Subject: [PATCH 206/315] ensure salt-minion is running, salt-master if manager before mine update --- salt/salt/mine_functions.sls | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/salt/salt/mine_functions.sls b/salt/salt/mine_functions.sls index 305fe2ce4..ed786e997 100644 --- a/salt/salt/mine_functions.sls +++ b/salt/salt/mine_functions.sls @@ -18,7 +18,7 @@ mine_functions: mine_functions: network.ip_addrs: - interface: {{ interface }} - {% if role in ['so-eval','so-import','so-manager','so-managerhype','so-managersearch','so-standalone'] %} + {%- if role in ['so-eval','so-import','so-manager','so-managerhype','so-managersearch','so-standalone'] %} x509.get_pem_entries: - glob_path: '/etc/pki/ca.crt' {% endif %} @@ -28,3 +28,8 @@ mine_update_mine_functions: - mine.update: [] - onchanges: - file: mine_functions + - onlyif: + - systemctl is-active --quiet salt-minion + {%- if role in ['so-eval','so-import','so-manager','so-managerhype','so-managersearch','so-standalone'] %} + - systemctl is-active --quiet salt-master + {% endif %} From bd4f2093db796948acbcba7ab7e9eafde7a7da15 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Wed, 11 Jun 2025 09:39:15 -0400 Subject: [PATCH 207/315] add vm delete warning for ui element --- salt/soc/dyanno/hypervisor/hypervisor.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/salt/soc/dyanno/hypervisor/hypervisor.yaml b/salt/soc/dyanno/hypervisor/hypervisor.yaml index a629aebfd..d13c928ec 100644 --- a/salt/soc/dyanno/hypervisor/hypervisor.yaml +++ b/salt/soc/dyanno/hypervisor/hypervisor.yaml @@ -6,6 +6,7 @@ hypervisor: syntax: json file: true global: true + uiElementsDeleteMessage: "Warning: Following the actions below will permanently destroy the virtual machine." uiElements: - field: hostname label: "Hostname" From 0b65021f755e6ccc7d1ee14720137c025de6a748 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Thu, 12 Jun 2025 16:49:56 -0400 Subject: [PATCH 208/315] exit 1 if vm is not destroyed --- salt/manager/tools/sbin_jinja/so-salt-cloud | 23 +++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/salt/manager/tools/sbin_jinja/so-salt-cloud b/salt/manager/tools/sbin_jinja/so-salt-cloud index bf15efcc2..b56038613 100644 --- a/salt/manager/tools/sbin_jinja/so-salt-cloud +++ b/salt/manager/tools/sbin_jinja/so-salt-cloud @@ -336,20 +336,39 @@ def delete_vm(profile, vm_name, assume_yes=False): text=True ) + # Pattern to detect when no machines were found to be destroyed + no_machines_string = 'No machines were found to be destroyed' + no_machines_pattern = re.compile(re.escape(no_machines_string)) + machines_destroyed = False + # Monitor output for line in iter(process.stdout.readline, ''): if line: logger.info(line.rstrip('\n')) + # Check if no machines were found to be destroyed + if no_machines_pattern.search(line): + machines_destroyed = False + break + # If we see destruction messages, mark as successful + elif 'destroyed' in line.lower() and vm_name in line: + machines_destroyed = True + process.stdout.close() process.wait() - if process.returncode == 0: - # Start cleanup tasks + # Check success criteria: returncode == 0 AND machines were actually destroyed + if process.returncode == 0 and machines_destroyed: + # Start cleanup tasks only when actual deletion occurred cleanup_deleted_vm(ip, role) logger.info(f"Successfully deleted VM {vm_name}") + elif process.returncode == 0 and not machines_destroyed: + # Command succeeded but no machines were destroyed + logger.error(f"VM {vm_name} was not found to be destroyed") + sys.exit(1) else: logger.error(f"Failed to delete VM {vm_name}") + sys.exit(1) except Exception as e: logger.error(f"Failed to delete VM {vm_name}: {e}") From ab6060c48452d02fd0d6d6e801e0b561d0ef7572 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Thu, 12 Jun 2025 16:50:38 -0400 Subject: [PATCH 209/315] restore VM to VMs file so that it is still seen in soc if vm destroy fails --- .../engines/master/virtual_node_manager.py | 87 +++++++++++++++++-- 1 file changed, 78 insertions(+), 9 deletions(-) diff --git a/salt/salt/engines/master/virtual_node_manager.py b/salt/salt/engines/master/virtual_node_manager.py index e7c28ef6a..a0e0e38f0 100644 --- a/salt/salt/engines/master/virtual_node_manager.py +++ b/salt/salt/engines/master/virtual_node_manager.py @@ -763,13 +763,31 @@ def process_vm_deletion(hypervisor_path: str, vm_name: str) -> None: This function handles the deletion of an existing VM. All operations are protected by the engine-wide lock that is acquired at engine start. + If so-salt-cloud fails during VM deletion, the function will restore the VM + configuration back to the VMs file to maintain consistency. + Args: hypervisor_path: Path to the hypervisor directory vm_name: Name of the VM to delete """ + vm_config = None + hypervisor = os.path.basename(hypervisor_path) + try: - # Get the actual hypervisor name (last directory in path) - hypervisor = os.path.basename(hypervisor_path) + # Read VM configuration from tracking file before attempting deletion + vm_file = os.path.join(hypervisor_path, vm_name) + if os.path.exists(vm_file): + try: + vm_data = read_json_file(vm_file) + vm_config = vm_data.get('config') if isinstance(vm_data, dict) else None + if vm_config: + log.debug("Read VM config for %s before deletion", vm_name) + else: + log.warning("No config found in tracking file for %s", vm_name) + except Exception as e: + log.warning("Failed to read VM config from tracking file %s: %s", vm_file, str(e)) + + # Attempt VM deletion with so-salt-cloud cmd = ['so-salt-cloud', '-p', f'sool9-{hypervisor}', vm_name, '-yd'] log.info("Executing: %s", ' '.join(cmd)) @@ -781,20 +799,73 @@ def process_vm_deletion(hypervisor_path: str, vm_name: str) -> None: if result.stderr: log.warning("Command stderr: %s", result.stderr) - # Remove VM tracking file - vm_file = os.path.join(hypervisor_path, vm_name) + # Remove VM tracking file on successful deletion if os.path.exists(vm_file): os.remove(vm_file) - log.info("Successfully removed VM tracking file") + log.info("Successfully removed VM tracking file for %s", vm_name) except subprocess.CalledProcessError as e: error_msg = f"so-salt-cloud deletion failed (code {e.returncode}): {e.stderr}" - log.error(error_msg) + log.error("%s", error_msg) + log.error("Esnure all hypervisors are online. salt-cloud will fail to destroy VMs if any hypervisors are offline.") + + # Attempt to restore VM configuration to VMs file if we have the config + if vm_config: + try: + _restore_vm_to_vms_file(hypervisor_path, hypervisor, vm_config) + except Exception as restore_error: + log.error("Failed to restore VM config after deletion failure: %s", str(restore_error)) + raise except Exception as e: log.error("Error processing VM deletion: %s", str(e)) raise + +def _restore_vm_to_vms_file(hypervisor_path: str, hypervisor: str, vm_config: dict) -> None: + """ + Restore VM configuration to the VMs file after failed deletion. + + Args: + hypervisor_path: Path to the hypervisor directory + hypervisor: Name of the hypervisor + vm_config: VM configuration to restore + """ + try: + # Construct VMs file path + vms_file = os.path.join(os.path.dirname(hypervisor_path), f"{hypervisor}VMs") + + # Read current VMs file + current_vms = [] + if os.path.exists(vms_file): + try: + current_vms = read_json_file(vms_file) + if not isinstance(current_vms, list): + log.warning("VMs file contains non-array data, initializing as empty array") + current_vms = [] + except Exception as e: + log.warning("Failed to read VMs file %s, initializing as empty: %s", vms_file, str(e)) + current_vms = [] + + # Check if VM already exists in VMs file (prevent duplicates) + vm_hostname = vm_config.get('hostname') + if vm_hostname: + for existing_vm in current_vms: + if isinstance(existing_vm, dict) and existing_vm.get('hostname') == vm_hostname: + log.info("VM with hostname %s already exists in VMs file, skipping restoration", vm_hostname) + return + + # Add VM configuration back to VMs file + current_vms.append(vm_config) + + # Write updated VMs file + write_json_file(vms_file, current_vms) + log.info("Successfully restored VM config for %s to VMs file %s", vm_hostname or 'unknown', vms_file) + + except Exception as e: + log.error("Failed to restore VM configuration: %s", str(e)) + raise + def process_hypervisor(hypervisor_path: str) -> None: """ Process VM configurations for a single hypervisor. @@ -876,7 +947,6 @@ def start(interval: int = DEFAULT_INTERVAL, instance of the virtual node manager runs at a time. The lock is: - Acquired at start - Released after processing completes - - Maintained if error occurs Args: interval: Time in seconds between engine runs (managed by salt-master) @@ -911,6 +981,5 @@ def start(interval: int = DEFAULT_INTERVAL, log.debug("Virtual node manager completed successfully") except Exception as e: - log.error("Error in virtual node manager - lock will remain until cleared: %s", str(e)) - # Don't release lock on error - requires admin intervention + log.error("Error in virtual node manager: %s", str(e)) return From 4729e194a049dc0eb3fbb5bdf68d1b5f73fa37c5 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Thu, 12 Jun 2025 17:01:23 -0400 Subject: [PATCH 210/315] spell ensure --- salt/salt/engines/master/virtual_node_manager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/salt/engines/master/virtual_node_manager.py b/salt/salt/engines/master/virtual_node_manager.py index a0e0e38f0..bc098d075 100644 --- a/salt/salt/engines/master/virtual_node_manager.py +++ b/salt/salt/engines/master/virtual_node_manager.py @@ -807,7 +807,7 @@ def process_vm_deletion(hypervisor_path: str, vm_name: str) -> None: except subprocess.CalledProcessError as e: error_msg = f"so-salt-cloud deletion failed (code {e.returncode}): {e.stderr}" log.error("%s", error_msg) - log.error("Esnure all hypervisors are online. salt-cloud will fail to destroy VMs if any hypervisors are offline.") + log.error("Ensure all hypervisors are online. salt-cloud will fail to destroy VMs if any hypervisors are offline.") # Attempt to restore VM configuration to VMs file if we have the config if vm_config: From d3b1a4f92886bda2cd5375f9437150d437761e30 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Fri, 13 Jun 2025 15:21:23 -0400 Subject: [PATCH 211/315] use state file to only send highstate initiated event once --- salt/vm/status/init.sls | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/salt/vm/status/init.sls b/salt/vm/status/init.sls index 64124aa85..d4051e50c 100644 --- a/salt/vm/status/init.sls +++ b/salt/vm/status/init.sls @@ -20,7 +20,17 @@ vm_highstate_trigger: status: Highstate Initiated vm_name: {{ grains.id }} hypervisor: {{ salt['grains.get']('salt-cloud:profile', '').split('-')[1] }} - - order: 1 # Ensure this runs early in the highstate process + - unless: test -f /opt/so/state/highstate_trigger.txt + - order: 1 # Ensure this runs early in the highstate process + +# Check if the trigger has already run +vm_highstate_trigger_file: + file.managed: + - name: /opt/so/state/highstate_trigger.txt + - contents: | + VM Highstate Trigger executed at: {{ salt['cmd.run']('date') }} + - onchanges: + - event: vm_highstate_trigger {% else %} From 19fb081fa09d26722efaa1da517724c6c5b682bc Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Fri, 13 Jun 2025 15:21:38 -0400 Subject: [PATCH 212/315] additional log info --- salt/manager/tools/sbin_jinja/so-salt-cloud | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/manager/tools/sbin_jinja/so-salt-cloud b/salt/manager/tools/sbin_jinja/so-salt-cloud index b56038613..c8d61e2f3 100644 --- a/salt/manager/tools/sbin_jinja/so-salt-cloud +++ b/salt/manager/tools/sbin_jinja/so-salt-cloud @@ -364,7 +364,7 @@ def delete_vm(profile, vm_name, assume_yes=False): logger.info(f"Successfully deleted VM {vm_name}") elif process.returncode == 0 and not machines_destroyed: # Command succeeded but no machines were destroyed - logger.error(f"VM {vm_name} was not found to be destroyed") + logger.error(f"VM {vm_name} was not found to be destroyed. Verify that all configured hypervisors are online.") sys.exit(1) else: logger.error(f"Failed to delete VM {vm_name}") From 480e248131c8512cdfcd2e84649497b8e4e7ed19 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Fri, 20 Jun 2025 16:24:54 -0400 Subject: [PATCH 213/315] ensure bond and interfaces only added once --- salt/sensor/vm/network.sls | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/salt/sensor/vm/network.sls b/salt/sensor/vm/network.sls index 9e25bca65..3e388adf6 100644 --- a/salt/sensor/vm/network.sls +++ b/salt/sensor/vm/network.sls @@ -35,6 +35,7 @@ bond0_interface: connection.autoconnect yes nmcli con mod bond0 ethernet.mtu 9000 nmcli con up bond0 + - unless: nmcli con show bond0 {% if non_enp1s0_interfaces|length > 0 %} - require_in: {% for iface in non_enp1s0_interfaces %} @@ -55,7 +56,7 @@ bond0_interface: slave-type bond \ ethernet.mtu 9000 nmcli con up bond0-slave-{{ iface }} - + - unless: nmcli con show bond0-slave-{{ iface }} {% endfor %} {% endif %} From fbb6d8146a3887d838370ec834bb7a958de7dda9 Mon Sep 17 00:00:00 2001 From: reyesj2 <94730068+reyesj2@users.noreply.github.com> Date: Wed, 25 Jun 2025 00:21:49 -0500 Subject: [PATCH 214/315] regen installers --- salt/manager/tools/sbin/soup | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/salt/manager/tools/sbin/soup b/salt/manager/tools/sbin/soup index d27239228..8c94bd6cb 100755 --- a/salt/manager/tools/sbin/soup +++ b/salt/manager/tools/sbin/soup @@ -576,13 +576,13 @@ post_to_2.4.141() { } post_to_2.4.150() { - echo "Regenerating Elastic Agent Installers" - /sbin/so-elastic-agent-gen-installers + echo "Nothing to apply" POSTVERSION=2.4.150 } post_to_2.4.160() { - echo "Nothing to apply" + echo "Regenerating Elastic Agent Installers" + /sbin/so-elastic-agent-gen-installers POSTVERSION=2.4.160 } From 38c74b46b613662b03d926ece6797faaa60b6005 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Wed, 25 Jun 2025 11:05:28 -0400 Subject: [PATCH 215/315] change salt upgrade process --- salt/salt/minion.sls | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/salt/salt/minion.sls b/salt/salt/minion.sls index 9f2a6f3fa..57bb27694 100644 --- a/salt/salt/minion.sls +++ b/salt/salt/minion.sls @@ -39,11 +39,17 @@ unhold_salt_packages: install_salt_minion: cmd.run: - - name: | - exec 0>&- # close stdin - exec 1>&- # close stdout - exec 2>&- # close stderr - nohup /bin/sh -c '{{ UPGRADECOMMAND }}' & + - name: /bin/sh -c '{{ UPGRADECOMMAND }}' + +# minion service is in failed state after upgrade. this command will start it after the state run for the upgrade completes +start_minion: + cmd.run: + - name: nohup /bin/sh -c 'sleep 30; systemctl start salt-minion' & + - require: + - cmd: install_salt_minion + - watch: + - cmd: install_salt_minion + - order: last {% endif %} From bc24a6c574065b38656a5869b4be65d9eeb77551 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Wed, 25 Jun 2025 12:19:45 -0400 Subject: [PATCH 216/315] Revert "change salt upgrade process" --- salt/salt/minion.sls | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/salt/salt/minion.sls b/salt/salt/minion.sls index 57bb27694..9f2a6f3fa 100644 --- a/salt/salt/minion.sls +++ b/salt/salt/minion.sls @@ -39,17 +39,11 @@ unhold_salt_packages: install_salt_minion: cmd.run: - - name: /bin/sh -c '{{ UPGRADECOMMAND }}' - -# minion service is in failed state after upgrade. this command will start it after the state run for the upgrade completes -start_minion: - cmd.run: - - name: nohup /bin/sh -c 'sleep 30; systemctl start salt-minion' & - - require: - - cmd: install_salt_minion - - watch: - - cmd: install_salt_minion - - order: last + - name: | + exec 0>&- # close stdin + exec 1>&- # close stdout + exec 2>&- # close stderr + nohup /bin/sh -c '{{ UPGRADECOMMAND }}' & {% endif %} From 7e746b87c5a822fca75e737ce99067cbe3a029c7 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Wed, 25 Jun 2025 13:00:26 -0400 Subject: [PATCH 217/315] 2.4.160 --- DOWNLOAD_AND_VERIFY_ISO.md | 22 ++++++++++---------- sigs/securityonion-2.4.160-20250625.iso.sig | Bin 0 -> 566 bytes 2 files changed, 11 insertions(+), 11 deletions(-) create mode 100644 sigs/securityonion-2.4.160-20250625.iso.sig diff --git a/DOWNLOAD_AND_VERIFY_ISO.md b/DOWNLOAD_AND_VERIFY_ISO.md index 0e726eaeb..2e0b2aa5d 100644 --- a/DOWNLOAD_AND_VERIFY_ISO.md +++ b/DOWNLOAD_AND_VERIFY_ISO.md @@ -1,17 +1,17 @@ -### 2.4.150-20250522 ISO image released on 2025/05/22 +### 2.4.160-20250625 ISO image released on 2025/06/25 ### Download and Verify -2.4.150-20250522 ISO image: -https://download.securityonion.net/file/securityonion/securityonion-2.4.150-20250522.iso +2.4.160-20250625 ISO image: +https://download.securityonion.net/file/securityonion/securityonion-2.4.160-20250625.iso -MD5: 239E69B83072BBF2602D4043FE53A160 -SHA1: C62893D3C7F5592665BFDCBC9A45BB20A926F9A8 -SHA256: 2ADE037C7FD34591030B1FAC10392C4E6613F152DD24BFBD897E57EE300895B9 +MD5: 78CF5602EFFAB84174C56AD2826E6E4E +SHA1: FC7EEC3EC95D97D3337501BAA7CA8CAE7C0E15EA +SHA256: 0ED965E8BEC80EE16AE90A0F0F96A3046CEF2D92720A587278DDDE3B656C01C2 Signature for ISO image: -https://github.com/Security-Onion-Solutions/securityonion/raw/2.4/main/sigs/securityonion-2.4.150-20250522.iso.sig +https://github.com/Security-Onion-Solutions/securityonion/raw/2.4/main/sigs/securityonion-2.4.160-20250625.iso.sig Signing key: https://raw.githubusercontent.com/Security-Onion-Solutions/securityonion/2.4/main/KEYS @@ -25,22 +25,22 @@ wget https://raw.githubusercontent.com/Security-Onion-Solutions/securityonion/2. Download the signature file for the ISO: ``` -wget https://github.com/Security-Onion-Solutions/securityonion/raw/2.4/main/sigs/securityonion-2.4.150-20250522.iso.sig +wget https://github.com/Security-Onion-Solutions/securityonion/raw/2.4/main/sigs/securityonion-2.4.160-20250625.iso.sig ``` Download the ISO image: ``` -wget https://download.securityonion.net/file/securityonion/securityonion-2.4.150-20250522.iso +wget https://download.securityonion.net/file/securityonion/securityonion-2.4.160-20250625.iso ``` Verify the downloaded ISO image using the signature file: ``` -gpg --verify securityonion-2.4.150-20250522.iso.sig securityonion-2.4.150-20250522.iso +gpg --verify securityonion-2.4.160-20250625.iso.sig securityonion-2.4.160-20250625.iso ``` The output should show "Good signature" and the Primary key fingerprint should match what's shown below: ``` -gpg: Signature made Thu 22 May 2025 11:15:06 AM EDT using RSA key ID FE507013 +gpg: Signature made Wed 25 Jun 2025 10:13:33 AM EDT using RSA key ID FE507013 gpg: Good signature from "Security Onion Solutions, LLC " gpg: WARNING: This key is not certified with a trusted signature! gpg: There is no indication that the signature belongs to the owner. diff --git a/sigs/securityonion-2.4.160-20250625.iso.sig b/sigs/securityonion-2.4.160-20250625.iso.sig new file mode 100644 index 0000000000000000000000000000000000000000..0145af053164dc7b1cbd40b9a2978a1140aaeb66 GIT binary patch literal 566 zcmV-60?GY}0y6{v0SEvc79j-41gSkXz6^6dp_W8^5Ma0dP;e6k0%%+W4FC!W5PT3| zxBgIY6Cy|t|5BF?^=?}sFeF9#Kk!gQ5#*(!ZvGydNg&f^^0EsGaXs z^N^s0KDu5#@4cMe1Ajik?ax+|5ZCmeU&di=c&@L^yy6wp3!yLk{K8iFi-Qb7gTmK< zGB45)?0)bJ8o#EE;|)w}yksi%0{=T(!PB4eD$)BzZz6M$n|&z|;llTXY!FQSsMeoO zN7uo-MU!fzFdMDexJSjG{v;Qa8Bc3gX4A)8Sovj0OGWxqqaHGyH6NKoqlAIpmlOT9 zPRc?~se3-Mmg6NQB*+#Fs5_6ogK0?hN~4g=KlL*jj%KLgTlf#B%rHk>^mVp0Qp*%! z8#{gov}O=#gx0;7MyGu4_fXvpCAT7O4mq?IP$<$y#GF+yWL^Cx8v$(EqY#zw_;4`L zE>Q^IU~~?Yd2jM5A~!2iCbJW8I0#)wU39OdvhMaR1 z&*LZa*C!(IEvJRUhf88o6BzkJ{ANqtZ^qAdwHQojD=i)^vcq>0D2Qd&kB_E};8;heM4M)OW7@fqMM~-;}wBSv>UwC9Z EkVcdVQvd(} literal 0 HcmV?d00001 From 373ef9fe91f9ccf918011ccfd083a879affba76b Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Wed, 25 Jun 2025 13:58:25 -0400 Subject: [PATCH 218/315] Update VERSION --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 3fe7dce73..032d0bb01 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.4.160 +2.4.170 From 5e62d3ecb230f1a2afbce32fab147e30dec15d90 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Wed, 25 Jun 2025 13:58:57 -0400 Subject: [PATCH 219/315] Update 2-4.yml --- .github/DISCUSSION_TEMPLATE/2-4.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/DISCUSSION_TEMPLATE/2-4.yml b/.github/DISCUSSION_TEMPLATE/2-4.yml index d192a0eec..dca40818a 100644 --- a/.github/DISCUSSION_TEMPLATE/2-4.yml +++ b/.github/DISCUSSION_TEMPLATE/2-4.yml @@ -29,6 +29,7 @@ body: - 2.4.141 - 2.4.150 - 2.4.160 + - 2.4.170 - Other (please provide detail below) validations: required: true From 34e561f358e82cea5292ecb3a26bd66c3fcf7a53 Mon Sep 17 00:00:00 2001 From: reyesj2 <94730068+reyesj2@users.noreply.github.com> Date: Wed, 25 Jun 2025 13:47:44 -0500 Subject: [PATCH 220/315] soup 2.4.170 --- salt/manager/tools/sbin/soup | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/salt/manager/tools/sbin/soup b/salt/manager/tools/sbin/soup index 8c94bd6cb..9fd8171bd 100755 --- a/salt/manager/tools/sbin/soup +++ b/salt/manager/tools/sbin/soup @@ -418,6 +418,7 @@ preupgrade_changes() { [[ "$INSTALLEDVERSION" == 2.4.140 ]] && up_to_2.4.141 [[ "$INSTALLEDVERSION" == 2.4.141 ]] && up_to_2.4.150 [[ "$INSTALLEDVERSION" == 2.4.150 ]] && up_to_2.4.160 + [[ "$INSTALLEDVERSION" == 2.4.160 ]] && up_to_2.4.170 true } @@ -446,6 +447,7 @@ postupgrade_changes() { [[ "$POSTVERSION" == 2.4.140 ]] && post_to_2.4.141 [[ "$POSTVERSION" == 2.4.141 ]] && post_to_2.4.150 [[ "$POSTVERSION" == 2.4.150 ]] && post_to_2.4.160 + [[ "$POSTVERSION" == 2.4.160 ]] && post_to_2.4.170 true } @@ -581,9 +583,14 @@ post_to_2.4.150() { } post_to_2.4.160() { + echo "Nothing to apply" + POSTVERSION=2.4.160 +} + +post_to_2.4.170() { echo "Regenerating Elastic Agent Installers" /sbin/so-elastic-agent-gen-installers - POSTVERSION=2.4.160 + POSTVERSION=2.4.170 } repo_sync() { @@ -829,6 +836,12 @@ up_to_2.4.160() { INSTALLEDVERSION=2.4.160 } +up_to_2.4.170() { + echo "Nothing to do for 2.4.170" + + INSTALLEDVERSION=2.4.170 +} + add_hydra_pillars() { mkdir -p /opt/so/saltstack/local/pillar/hydra touch /opt/so/saltstack/local/pillar/hydra/soc_hydra.sls From b2acf2f8078f99c573266889e8db7bddf368dfec Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Wed, 25 Jun 2025 15:05:49 -0400 Subject: [PATCH 221/315] change logic for determining if vm was destroyed --- salt/manager/tools/sbin_jinja/so-salt-cloud | 33 ++++++++++++++++----- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/salt/manager/tools/sbin_jinja/so-salt-cloud b/salt/manager/tools/sbin_jinja/so-salt-cloud index c8d61e2f3..daa92fa67 100644 --- a/salt/manager/tools/sbin_jinja/so-salt-cloud +++ b/salt/manager/tools/sbin_jinja/so-salt-cloud @@ -339,33 +339,50 @@ def delete_vm(profile, vm_name, assume_yes=False): # Pattern to detect when no machines were found to be destroyed no_machines_string = 'No machines were found to be destroyed' no_machines_pattern = re.compile(re.escape(no_machines_string)) + + # Track if we found any successful destruction machines_destroyed = False + output_lines = [] # Monitor output for line in iter(process.stdout.readline, ''): if line: logger.info(line.rstrip('\n')) + output_lines.append(line.strip()) # Check if no machines were found to be destroyed if no_machines_pattern.search(line): machines_destroyed = False break - # If we see destruction messages, mark as successful - elif 'destroyed' in line.lower() and vm_name in line: - machines_destroyed = True process.stdout.close() process.wait() - # Check success criteria: returncode == 0 AND machines were actually destroyed + # If we hit the "No machines were found" case, it's a failure + if no_machines_pattern.search('\n'.join(output_lines)): + logger.error(f"VM {vm_name} was not found to be destroyed. Verify that all configured hypervisors are online.") + sys.exit(1) + + # Check for successful destruction patterns in the output + # Look for the VM name appearing in libvirt section - this indicates successful processing + full_output = '\n'.join(output_lines) + if vm_name in full_output and 'libvirt:' in full_output: + # VM was processed by libvirt, which means destruction was attempted + # If we reach here and didn't hit the "No machines found" case, it's success + machines_destroyed = True + + # Check success criteria: returncode == 0 AND we found evidence of destruction if process.returncode == 0 and machines_destroyed: # Start cleanup tasks only when actual deletion occurred cleanup_deleted_vm(ip, role) logger.info(f"Successfully deleted VM {vm_name}") - elif process.returncode == 0 and not machines_destroyed: - # Command succeeded but no machines were destroyed - logger.error(f"VM {vm_name} was not found to be destroyed. Verify that all configured hypervisors are online.") - sys.exit(1) + elif process.returncode == 0: + # Command succeeded but we couldn't confirm destruction - this is the edge case we're fixing + # If salt-cloud returned 0 and we didn't hit the "No machines found" case, + # but we also don't see clear destruction evidence, we should still consider it success + # because salt-cloud returning 0 means it completed successfully + cleanup_deleted_vm(ip, role) + logger.info(f"Successfully deleted VM {vm_name} (salt-cloud completed successfully)") else: logger.error(f"Failed to delete VM {vm_name}") sys.exit(1) From daaad3699c7c2ea531f3b707398dace61d08a02d Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Wed, 25 Jun 2025 17:20:17 -0400 Subject: [PATCH 222/315] allow wheel files --- .github/.gitleaks.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/.gitleaks.toml b/.github/.gitleaks.toml index 2111ed7bc..32c27b355 100644 --- a/.github/.gitleaks.toml +++ b/.github/.gitleaks.toml @@ -542,4 +542,5 @@ paths = [ '''(.*?)(jpg|gif|doc|pdf|bin|svg|socket)$''', '''(go.mod|go.sum)$''', '''salt/nginx/files/enterprise-attack.json''' + '''(.*?)whl$ ] From 8fdc7049f939e7b40ca18d87d2b5376a9d6c4439 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Fri, 27 Jun 2025 10:53:03 -0400 Subject: [PATCH 223/315] add missing , --- .github/.gitleaks.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/.gitleaks.toml b/.github/.gitleaks.toml index 32c27b355..40e6ccabf 100644 --- a/.github/.gitleaks.toml +++ b/.github/.gitleaks.toml @@ -541,6 +541,6 @@ paths = [ '''gitleaks.toml''', '''(.*?)(jpg|gif|doc|pdf|bin|svg|socket)$''', '''(go.mod|go.sum)$''', - '''salt/nginx/files/enterprise-attack.json''' + '''salt/nginx/files/enterprise-attack.json''', '''(.*?)whl$ ] From b0f521877511af728634ab0672fbc7494dadf55f Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Fri, 27 Jun 2025 10:58:14 -0400 Subject: [PATCH 224/315] add quotes --- .github/.gitleaks.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/.gitleaks.toml b/.github/.gitleaks.toml index 40e6ccabf..009f1c613 100644 --- a/.github/.gitleaks.toml +++ b/.github/.gitleaks.toml @@ -542,5 +542,5 @@ paths = [ '''(.*?)(jpg|gif|doc|pdf|bin|svg|socket)$''', '''(go.mod|go.sum)$''', '''salt/nginx/files/enterprise-attack.json''', - '''(.*?)whl$ + '''(.*?)whl$''' ] From 493359e5a2dc5efb82f549a6a3d7799cbedcb062 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Fri, 27 Jun 2025 11:00:35 -0400 Subject: [PATCH 225/315] cleanup --- .gitignore | 8 -------- 1 file changed, 8 deletions(-) diff --git a/.gitignore b/.gitignore index fc9d41531..fb154cae7 100644 --- a/.gitignore +++ b/.gitignore @@ -67,11 +67,3 @@ __pycache__ # Analyzer dev/test config files *_dev.yaml site-packages - -# Project Scope Directory -.projectScope/ -.clinerules -cline_docs/ - -# vscode settings -.vscode/ From b93c6c02702e721c43abaeb548bf4a5dc7d8343b Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Mon, 30 Jun 2025 09:51:40 -0400 Subject: [PATCH 226/315] allow standalone and managersearch to run salt.cloud state --- salt/allowed_states.map.jinja | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/salt/allowed_states.map.jinja b/salt/allowed_states.map.jinja index 3edda8a4c..2f65b9213 100644 --- a/salt/allowed_states.map.jinja +++ b/salt/allowed_states.map.jinja @@ -116,7 +116,7 @@ 'so-managersearch': ( ssl_states + manager_states + - ['strelka.manager'] + + ['salt.cloud', 'strelka.manager'] + stig_states + kafka_states + elastic_stack_states @@ -129,6 +129,7 @@ 'so-standalone': ( ssl_states + manager_states + + ['salt.cloud'] + sensor_states + stig_states + kafka_states + From 5035ec25397071fb4ca5f11e57a40217d7054e88 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Mon, 30 Jun 2025 11:21:45 -0400 Subject: [PATCH 227/315] allow libvirt states --- salt/allowed_states.map.jinja | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/salt/allowed_states.map.jinja b/salt/allowed_states.map.jinja index 2f65b9213..068722ca2 100644 --- a/salt/allowed_states.map.jinja +++ b/salt/allowed_states.map.jinja @@ -116,7 +116,7 @@ 'so-managersearch': ( ssl_states + manager_states + - ['salt.cloud', 'strelka.manager'] + + ['salt.cloud', 'libvirt.packages', 'libvirt.ssh.users', 'strelka.manager'] + stig_states + kafka_states + elastic_stack_states @@ -129,7 +129,7 @@ 'so-standalone': ( ssl_states + manager_states + - ['salt.cloud'] + + ['salt.cloud', 'libvirt.packages', 'libvirt.ssh.users'] + sensor_states + stig_states + kafka_states + From 33c23c30d32c27ad8ced37f9932e6031998d69bc Mon Sep 17 00:00:00 2001 From: Corey Ogburn Date: Mon, 30 Jun 2025 11:43:02 -0600 Subject: [PATCH 228/315] Refactors playbook repo configuration Replaces individual playbook repo fields with an array of repos to support multiple playbook sources. Refactor Jinja. --- salt/soc/defaults.yaml | 14 +++++++++----- salt/soc/merged.map.jinja | 6 +++--- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/salt/soc/defaults.yaml b/salt/soc/defaults.yaml index 66355fa24..42e07a7c0 100644 --- a/salt/soc/defaults.yaml +++ b/salt/soc/defaults.yaml @@ -1464,12 +1464,16 @@ soc: autoUpdateEnabled: true playbookImportFrequencySeconds: 86400 playbookImportErrorSeconds: 600 - playbookRepoUrl: - default: https://github.com/Security-Onion-Solutions/securityonion-resources-playbooks - airgap: file:///nsm/airgap-resources/playbooks/securityonion-resources-playbooks - playbookRepoBranch: main playbookRepoPath: /opt/sensoroni/playbooks/ - playbookPathInRepo: securityonion-normalized + playbookRepos: + default: + - repo: https://github.com/Security-Onion-Solutions/securityonion-resources-playbooks + branch: main + folder: securityonion-normalized + airgap: + - repo: file:///nsm/airgap-resources/playbooks/securityonion-resources-playbooks + branch: main + folder: securityonion-normalized salt: queueDir: /opt/sensoroni/queue timeoutMs: 45000 diff --git a/salt/soc/merged.map.jinja b/salt/soc/merged.map.jinja index c950d8a60..e053ce63f 100644 --- a/salt/soc/merged.map.jinja +++ b/salt/soc/merged.map.jinja @@ -61,11 +61,11 @@ {% do SOCMERGED.config.server.update({'airgapEnabled': false}) %} {% endif %} -{# set playbookRepoUrl based on airgap or not #} +{# set playbookRepos based on airgap or not #} {% if GLOBALS.airgap %} -{% do SOCMERGED.config.server.modules.playbook.update({'playbookRepoUrl': SOCMERGED.config.server.modules.playbook.playbookRepoUrl.airgap}) %} +{% do SOCMERGED.config.server.modules.playbook.update({'playbookRepos': SOCMERGED.config.server.modules.playbook.playbookRepos.airgap}) %} {% else %} -{% do SOCMERGED.config.server.modules.playbook.update({'playbookRepoUrl': SOCMERGED.config.server.modules.playbook.playbookRepoUrl.default}) %} +{% do SOCMERGED.config.server.modules.playbook.update({'playbookRepos': SOCMERGED.config.server.modules.playbook.playbookRepos.default}) %} {% endif %} {# remove these modules if detections is disabled #} From a86105294b9ef7f4f8270bd59f43d13df719fccd Mon Sep 17 00:00:00 2001 From: Corey Ogburn Date: Mon, 30 Jun 2025 12:50:56 -0600 Subject: [PATCH 229/315] Playbook Annotations --- salt/soc/soc_soc.yaml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/salt/soc/soc_soc.yaml b/salt/soc/soc_soc.yaml index 58560e89e..bbe963ec8 100644 --- a/salt/soc/soc_soc.yaml +++ b/salt/soc/soc_soc.yaml @@ -552,6 +552,23 @@ soc: description: How far back to search for ATT&CK-tagged alerts. (days) global: True helpLink: attack-navigator.html + playbook: + playbookRepos: + default: &pbRepos + description: "Custom Git repositories to pull Playbooks from. Playbooks are pulled when SOC starts and automatically refreshed every 24 hours. If this grid is airgapped then edit the airgap repos. Otherwise edit the default repos." + global: True + advanced: True + forcedType: "[]{}" + syntax: json + uiElements: + - field: repo + label: Repo URL + required: True + - field: branch + label: Branch + - field: folder + label: Folder + airgap: *pbRepos client: enableReverseLookup: description: Set to true to enable reverse DNS lookups for IP addresses in the SOC UI. From dea9c149d78b9b728d4a0c82193bfef07ce7ca28 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Mon, 30 Jun 2025 15:30:39 -0400 Subject: [PATCH 230/315] only run storage state if box has nvme --- salt/storage/init.sls | 6 ++++++ salt/storage/nsm_mount.sls | 2 +- salt/storage/{files => tools/sbin}/so-nsm-cleanup | 0 salt/storage/{files => tools/sbin}/so-nsm-mount | 0 4 files changed, 7 insertions(+), 1 deletion(-) rename salt/storage/{files => tools/sbin}/so-nsm-cleanup (100%) rename salt/storage/{files => tools/sbin}/so-nsm-mount (100%) diff --git a/salt/storage/init.sls b/salt/storage/init.sls index 5bce7e71a..533366fd0 100644 --- a/salt/storage/init.sls +++ b/salt/storage/init.sls @@ -3,5 +3,11 @@ # https://securityonion.net/license; you may not use this file except in compliance with the # Elastic License 2.0. + +{% set nvme_devices = salt['cmd.shell']("find /dev -name 'nvme*n1' 2>/dev/null") %} +{% if nvme_devices %} + include: - storage.nsm_mount + +{% endif %} diff --git a/salt/storage/nsm_mount.sls b/salt/storage/nsm_mount.sls index b0476e054..ed9e97c33 100644 --- a/salt/storage/nsm_mount.sls +++ b/salt/storage/nsm_mount.sls @@ -23,7 +23,7 @@ storage_nsm_mount_logdir: storage_nsm_mount_script: file.managed: - name: /usr/sbin/so-nsm-mount - - source: salt://storage/files/so-nsm-mount + - source: salt://storage/tools/sbin/so-nsm-mount - mode: 755 - user: root - group: root diff --git a/salt/storage/files/so-nsm-cleanup b/salt/storage/tools/sbin/so-nsm-cleanup similarity index 100% rename from salt/storage/files/so-nsm-cleanup rename to salt/storage/tools/sbin/so-nsm-cleanup diff --git a/salt/storage/files/so-nsm-mount b/salt/storage/tools/sbin/so-nsm-mount similarity index 100% rename from salt/storage/files/so-nsm-mount rename to salt/storage/tools/sbin/so-nsm-mount From d003e1380f0e7dc2b648aea30bcc4241c58cfc39 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Wed, 2 Jul 2025 16:14:43 -0400 Subject: [PATCH 231/315] ensure hypervisor is remove from salt cloud profiles when key is deleted --- salt/orch/delete_hypervisor.sls | 17 +++++++++++++++++ salt/reactor/check_hypervisor.sls | 16 +++++++++++++++- 2 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 salt/orch/delete_hypervisor.sls diff --git a/salt/orch/delete_hypervisor.sls b/salt/orch/delete_hypervisor.sls new file mode 100644 index 000000000..3249d11b5 --- /dev/null +++ b/salt/orch/delete_hypervisor.sls @@ -0,0 +1,17 @@ +{% set hypervisor = pillar.minion_id %} + +ensure_hypervisor_mine_deleted: + salt.function: + - name: file.remove + - tgt: 'G@role:so-manager or G@role:so-managerhype or G@role:so-managersearch or G@role:so-standalone or G@role:so-eval' + - tgt_type: compound + - arg: + - /var/cache/salt/master/minions/{{hypervisor}} + +update_salt_cloud_profile: + salt.state: + - tgt: 'G@role:so-manager or G@role:so-managerhype or G@role:so-managersearch or G@role:so-standalone or G@role:so-eval' + - tgt_type: compound + - sls: + - salt.cloud.config + - concurrent: True diff --git a/salt/reactor/check_hypervisor.sls b/salt/reactor/check_hypervisor.sls index 889656b36..2f3831471 100644 --- a/salt/reactor/check_hypervisor.sls +++ b/salt/reactor/check_hypervisor.sls @@ -1,5 +1,19 @@ -{% if data['act'] == 'accept' and data['id'].endswith(('_hypervisor', '_managerhyper')) and data['result'] == True %} +{% if data['id'].endswith('_hypervisor') and data['result'] == True %} + +{% if data['act'] == 'accept' %} check_and_trigger: runner.setup_hypervisor.setup_environment: - minion_id: {{ data['id'] }} +{% endif %} + +{% if data['act'] == 'delete' %} +delete_hypervisor: + runner.state.orchestrate: + - args: + - mods: orch.delete_hypervisor + - pillar: + minion_id: {{ data['id'] }} +{% endif %} + {% endif %} + From 6d7066c38162316e8286f3290c33049e2640ae97 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Wed, 2 Jul 2025 16:20:30 -0400 Subject: [PATCH 232/315] add license --- salt/orch/delete_hypervisor.sls | 5 +++++ salt/reactor/check_hypervisor.sls | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/salt/orch/delete_hypervisor.sls b/salt/orch/delete_hypervisor.sls index 3249d11b5..3f0bd02b6 100644 --- a/salt/orch/delete_hypervisor.sls +++ b/salt/orch/delete_hypervisor.sls @@ -1,3 +1,8 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + {% set hypervisor = pillar.minion_id %} ensure_hypervisor_mine_deleted: diff --git a/salt/reactor/check_hypervisor.sls b/salt/reactor/check_hypervisor.sls index 2f3831471..91b7c0c02 100644 --- a/salt/reactor/check_hypervisor.sls +++ b/salt/reactor/check_hypervisor.sls @@ -1,3 +1,8 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + {% if data['id'].endswith('_hypervisor') and data['result'] == True %} {% if data['act'] == 'accept' %} From d8be6e42e13a427e3acaa9d02f7a8f72bc908691 Mon Sep 17 00:00:00 2001 From: reyesj2 <94730068+reyesj2@users.noreply.github.com> Date: Mon, 7 Jul 2025 12:58:00 -0500 Subject: [PATCH 233/315] es 8.18.3 --- VERSION | 2 +- salt/elasticsearch/defaults.yaml | 2 +- salt/kibana/defaults.yaml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/VERSION b/VERSION index 032d0bb01..452820224 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.4.170 +2.4.0-foxtrot \ No newline at end of file diff --git a/salt/elasticsearch/defaults.yaml b/salt/elasticsearch/defaults.yaml index 1f81e95d2..73c29c8c6 100644 --- a/salt/elasticsearch/defaults.yaml +++ b/salt/elasticsearch/defaults.yaml @@ -1,6 +1,6 @@ elasticsearch: enabled: false - version: 8.17.3 + version: 8.18.3 index_clean: true config: action: diff --git a/salt/kibana/defaults.yaml b/salt/kibana/defaults.yaml index 2446821f1..a636f9b79 100644 --- a/salt/kibana/defaults.yaml +++ b/salt/kibana/defaults.yaml @@ -22,7 +22,7 @@ kibana: - default - file migrations: - discardCorruptObjects: "8.17.3" + discardCorruptObjects: "8.18.3" telemetry: enabled: False security: From 4bf2c931e9e7279b64f79da589c6000a58506d14 Mon Sep 17 00:00:00 2001 From: reyesj2 <94730068+reyesj2@users.noreply.github.com> Date: Tue, 8 Jul 2025 08:43:24 -0500 Subject: [PATCH 234/315] make sure required file exists to generate ADDON_INTEGRATION_DEFAULTS --- salt/manager/managed_soc_annotations.sls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/manager/managed_soc_annotations.sls b/salt/manager/managed_soc_annotations.sls index 17621f973..9ef0b1ea1 100644 --- a/salt/manager/managed_soc_annotations.sls +++ b/salt/manager/managed_soc_annotations.sls @@ -5,7 +5,7 @@ {# Managed elasticsearch/soc_elasticsearch.yaml file for adding integration configuration items to UI #} {% set managed_integrations = salt['pillar.get']('elasticsearch:managed_integrations', []) %} -{% if managed_integrations %} +{% if managed_integrations and salt['file.file_exists']('/opt/so/state/esfleet_package_components.json') %} {% from 'elasticfleet/integration-defaults.map.jinja' import ADDON_INTEGRATION_DEFAULTS %} {% set addon_integration_keys = ADDON_INTEGRATION_DEFAULTS.keys() %} {% set matched_integration_names = [] %} From 42552810fb1ce3b217deef9573495becce365044 Mon Sep 17 00:00:00 2001 From: Josh Brower Date: Tue, 8 Jul 2025 09:50:08 -0400 Subject: [PATCH 235/315] Add user.name to kratos query --- salt/soc/defaults.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/soc/defaults.yaml b/salt/soc/defaults.yaml index 42e07a7c0..cb12671f8 100644 --- a/salt/soc/defaults.yaml +++ b/salt/soc/defaults.yaml @@ -1910,7 +1910,7 @@ soc: query: 'event.dataset:kratos.audit AND msg:*authenticated* | groupby http_request.headers.x-real-ip | groupby -sankey http_request.headers.x-real-ip user.name | groupby user.name | groupby http_request.headers.user-agent' - name: SOC Login Failures description: SOC (Security Onion Console) login failures - query: 'event.dataset:kratos.audit AND msg:*Encountered*self-service*login*error* | groupby http_request.headers.x-real-ip | groupby -sankey http_request.headers.x-real-ip http_request.headers.user-agent | groupby http_request.headers.user-agent' + query: 'event.dataset:kratos.audit AND msg:*Encountered*self-service*login*error* | groupby user.name | groupby http_request.headers.x-real-ip | groupby -sankey http_request.headers.x-real-ip http_request.headers.user-agent | groupby http_request.headers.user-agent' - name: Alerts description: Overview of all alerts query: 'tags:alert | groupby event.module* | groupby source.ip | groupby -sankey source.ip destination.ip | groupby destination.ip | groupby destination.port | groupby rule.name | groupby event.severity | groupby destination_geo.organization_name' From d4f0cbcb677b80407e70d940d7a5a4f153429495 Mon Sep 17 00:00:00 2001 From: reyesj2 <94730068+reyesj2@users.noreply.github.com> Date: Tue, 8 Jul 2025 15:23:46 -0500 Subject: [PATCH 236/315] changes for 'generic' integrations with no compoent templates assigned. Default to using the logs-filestream.generic@package componet template --- .../integration-defaults.map.jinja | 132 ++++++++++-------- ...o-elastic-fleet-optional-integrations-load | 4 + .../so-elasticsearch-templates-load | 2 +- 3 files changed, 81 insertions(+), 57 deletions(-) diff --git a/salt/elasticfleet/integration-defaults.map.jinja b/salt/elasticfleet/integration-defaults.map.jinja index 5449e791e..62e37b229 100644 --- a/salt/elasticfleet/integration-defaults.map.jinja +++ b/salt/elasticfleet/integration-defaults.map.jinja @@ -4,6 +4,7 @@ {% import_json '/opt/so/state/esfleet_package_components.json' as ADDON_PACKAGE_COMPONENTS %} +{% import_json '/opt/so/state/esfleet_package_components.json' as INSTALLED_COMPONENT_TEMPLATES %} {% import_yaml 'elasticfleet/defaults.yaml' as ELASTICFLEETDEFAULTS %} {% set CORE_ESFLEET_PACKAGES = ELASTICFLEETDEFAULTS.get('elasticfleet', {}).get('packages', {}) %} @@ -62,70 +63,89 @@ {% else %} {% set integration_type = "" %} {% endif %} -{% set component_name = pkg.name ~ "." ~ pattern.title %} -{# fix weirdly named components #} -{% if component_name in WEIRD_INTEGRATIONS %} -{% set component_name = WEIRD_INTEGRATIONS[component_name] %} -{% endif %} +{% set component_name = pkg.name ~ "." ~ pattern.title %} +{% set index_pattern = pattern.name %} + +{# fix weirdly named components #} +{% if component_name in WEIRD_INTEGRATIONS %} +{% set component_name = WEIRD_INTEGRATIONS[component_name] %} +{% endif %} + +{# create duplicate of component_name, so we can split generics from @custom component templates in the index template below and overwrite the default @package when needed + eg. having to replace unifiedlogs.generic@package with filestream.generic@package, but keep the ability to customize unifiedlogs.generic@custom and its ILM policy #} +{% set custom_component_name = component_name %} + +{# duplicate integration_type to assist with sometimes needing to overwrite component templates with 'logs-filestream.generic@package' (there is no metrics-filestream.generic@package) #} +{% set generic_integration_type = integration_type %} + {# component_name_x maintains the functionality of merging local pillar changes with generated 'defaults' via SOC UI #} {% set component_name_x = component_name.replace(".","_x_") %} {# pillar overrides/merge expects the key names to follow the naming in elasticsearch/defaults.yaml eg. so-logs-1password_x_item_usages . The _x_ is replaced later on in elasticsearch/template.map.jinja #} {% set integration_key = "so-" ~ integration_type ~ component_name_x %} +{% if ".generic" in component_name and component_name not in INSTALLED_COMPONENT_TEMPLATES %} +{# these generic templates by default are directed to index_pattern of 'logs-generic-*', overwrite that here to point to eg gcp_pubsub.generic-* #} +{% set index_pattern = integration_type ~ component_name ~ "-*" %} +{# includes use of .generic component template, but it doesn't exist in installed component templates. Redirect it to filestream.generic@package #} +{% set component_name = "filestream.generic" %} +{% set generic_integration_type = "logs-" %} +{% endif %} + {# Default integration settings #} {% set integration_defaults = { - "index_sorting": false, - "index_template": { - "composed_of": [integration_type ~ component_name ~ "@package", integration_type ~ component_name ~ "@custom", "so-fleet_integrations.ip_mappings-1", "so-fleet_globals-1", "so-fleet_agent_id_verification-1"], - "data_stream": { - "allow_custom_routing": false, - "hidden": false - }, - "ignore_missing_component_templates": [integration_type ~ component_name ~ "@custom"], - "index_patterns": [pattern.name], - "priority": 501, - "template": { - "settings": { - "index": { - "lifecycle": {"name": "so-" ~ integration_type ~ component_name ~ "-logs"}, - "number_of_replicas": 0 - } - } - } - }, - "policy": { - "phases": { - "cold": { - "actions": { - "set_priority": {"priority": 0} - }, - "min_age": "60d" + "index_sorting": false, + "index_template": { + "composed_of": [generic_integration_type ~ component_name ~ "@package", integration_type ~ custom_component_name ~ "@custom", "so-fleet_integrations.ip_mappings-1", "so-fleet_globals-1", "so-fleet_agent_id_verification-1"], + "data_stream": { + "allow_custom_routing": false, + "hidden": false + }, + "ignore_missing_component_templates": [integration_type ~ custom_component_name ~ "@custom"], + "index_patterns": [index_pattern], + "priority": 501, + "template": { + "settings": { + "index": { + "lifecycle": {"name": "so-" ~ integration_type ~ custom_component_name ~ "-logs"}, + "number_of_replicas": 0 + } + } + } + }, + "policy": { + "phases": { + "cold": { + "actions": { + "set_priority": {"priority": 0} + }, + "min_age": "60d" + }, + "delete": { + "actions": { + "delete": {} + }, + "min_age": "365d" + }, + "hot": { + "actions": { + "rollover": { + "max_age": "30d", + "max_primary_shard_size": "50gb" + }, + "set_priority": {"priority": 100} }, - "delete": { - "actions": { - "delete": {} - }, - "min_age": "365d" - }, - "hot": { - "actions": { - "rollover": { - "max_age": "30d", - "max_primary_shard_size": "50gb" - }, - "set_priority": {"priority": 100} - }, - "min_age": "0ms" - }, - "warm": { - "actions": { - "set_priority": {"priority": 50} - }, - "min_age": "30d" - } - } - } - } %} + "min_age": "0ms" + }, + "warm": { + "actions": { + "set_priority": {"priority": 50} + }, + "min_age": "30d" + } + } + } + } %} + {% do ADDON_INTEGRATION_DEFAULTS.update({integration_key: integration_defaults}) %} {% endfor %} {% endif %} diff --git a/salt/elasticfleet/tools/sbin_jinja/so-elastic-fleet-optional-integrations-load b/salt/elasticfleet/tools/sbin_jinja/so-elastic-fleet-optional-integrations-load index 26d775e82..df01608f5 100644 --- a/salt/elasticfleet/tools/sbin_jinja/so-elastic-fleet-optional-integrations-load +++ b/salt/elasticfleet/tools/sbin_jinja/so-elastic-fleet-optional-integrations-load @@ -19,6 +19,7 @@ BULK_INSTALL_PACKAGE_LIST=/tmp/esfleet_bulk_install.json BULK_INSTALL_PACKAGE_TMP=/tmp/esfleet_bulk_install_tmp.json BULK_INSTALL_OUTPUT=/opt/so/state/esfleet_bulk_install_results.json PACKAGE_COMPONENTS=/opt/so/state/esfleet_package_components.json +COMPONENT_TEMPLATES=/opt/so/state/esfleet_component_templates.txt PENDING_UPDATE=false @@ -155,6 +156,9 @@ if [[ -f $STATE_FILE_SUCCESS ]]; then # Write out file for generating index/component/ilm templates latest_installed_package_list=$(elastic_fleet_installed_packages) echo $latest_installed_package_list | jq '[.items[] | {name: .name, es_index_patterns: .dataStreams}]' > $PACKAGE_COMPONENTS + # Refresh installed component template list + latest_component_templates_list=$(so-elasticsearch-query _component_template | jq '.component_templates[] | .name' | jq -s '.') + echo $latest_component_templates_list > $COMPONENT_TEMPLATES else # This is the installation of add-on integrations and upgrade of existing integrations. Exiting without error, next highstate will attempt to re-run. diff --git a/salt/elasticsearch/tools/sbin_jinja/so-elasticsearch-templates-load b/salt/elasticsearch/tools/sbin_jinja/so-elasticsearch-templates-load index 758f601eb..ba5767255 100755 --- a/salt/elasticsearch/tools/sbin_jinja/so-elasticsearch-templates-load +++ b/salt/elasticsearch/tools/sbin_jinja/so-elasticsearch-templates-load @@ -136,7 +136,7 @@ if [ ! -f $STATE_FILE_SUCCESS ]; then TEMPLATE=${i::-14} COMPONENT_PATTERN=${TEMPLATE:3} MATCH=$(echo "$TEMPLATE" | grep -E "^so-logs-|^so-metrics" | grep -vE "detections|osquery") - if [[ -n "$MATCH" && ! "$COMPONENT_LIST" =~ "$COMPONENT_PATTERN" && ! "$COMPONENT_PATTERN" =~ logs-http_endpoint\.generic|logs-winlog\.winlog ]]; then + if [[ -n "$MATCH" && ! "$COMPONENT_LIST" =~ "$COMPONENT_PATTERN" && ! "$COMPONENT_PATTERN" =~ *\.generic|logs-winlog\.winlog ]]; then load_failures=$((load_failures+1)) echo "Component template does not exist for $COMPONENT_PATTERN. The index template will not be loaded. Load failures: $load_failures" else From bef2fa9e8d5b06c13f045cb7436da05e16c64b1b Mon Sep 17 00:00:00 2001 From: reyesj2 <94730068+reyesj2@users.noreply.github.com> Date: Tue, 8 Jul 2025 16:09:16 -0500 Subject: [PATCH 237/315] 8.18.3 pipeline updates --- .../grid-nodes_general/import-evtx-logs.json | 2 +- ...nse.log-1.21.0 => logs-pfsense.log-1.23.0} | 28 +++++++------------ ...icata => logs-pfsense.log-1.23.0-suricata} | 0 3 files changed, 11 insertions(+), 19 deletions(-) rename salt/elasticsearch/files/ingest/{logs-pfsense.log-1.21.0 => logs-pfsense.log-1.23.0} (93%) rename salt/elasticsearch/files/ingest/{logs-pfsense.log-1.21.0-suricata => logs-pfsense.log-1.23.0-suricata} (100%) diff --git a/salt/elasticfleet/files/integrations/grid-nodes_general/import-evtx-logs.json b/salt/elasticfleet/files/integrations/grid-nodes_general/import-evtx-logs.json index 46717f3e1..415e333e7 100644 --- a/salt/elasticfleet/files/integrations/grid-nodes_general/import-evtx-logs.json +++ b/salt/elasticfleet/files/integrations/grid-nodes_general/import-evtx-logs.json @@ -20,7 +20,7 @@ ], "data_stream.dataset": "import", "custom": "", - "processors": "- dissect:\n tokenizer: \"/nsm/import/%{import.id}/evtx/%{import.file}\"\n field: \"log.file.path\"\n target_prefix: \"\"\n- decode_json_fields:\n fields: [\"message\"]\n target: \"\"\n- drop_fields:\n fields: [\"host\"]\n ignore_missing: true\n- add_fields:\n target: data_stream\n fields:\n type: logs\n dataset: system.security\n- add_fields:\n target: event\n fields:\n dataset: system.security\n module: system\n imported: true\n- add_fields:\n target: \"@metadata\"\n fields:\n pipeline: logs-system.security-1.67.0\n- if:\n equals:\n winlog.channel: 'Microsoft-Windows-Sysmon/Operational'\n then: \n - add_fields:\n target: data_stream\n fields:\n dataset: windows.sysmon_operational\n - add_fields:\n target: event\n fields:\n dataset: windows.sysmon_operational\n module: windows\n imported: true\n - add_fields:\n target: \"@metadata\"\n fields:\n pipeline: logs-windows.sysmon_operational-2.5.0\n- if:\n equals:\n winlog.channel: 'Application'\n then: \n - add_fields:\n target: data_stream\n fields:\n dataset: system.application\n - add_fields:\n target: event\n fields:\n dataset: system.application\n - add_fields:\n target: \"@metadata\"\n fields:\n pipeline: logs-system.application-1.67.0\n- if:\n equals:\n winlog.channel: 'System'\n then: \n - add_fields:\n target: data_stream\n fields:\n dataset: system.system\n - add_fields:\n target: event\n fields:\n dataset: system.system\n - add_fields:\n target: \"@metadata\"\n fields:\n pipeline: logs-system.system-1.67.0\n \n- if:\n equals:\n winlog.channel: 'Microsoft-Windows-PowerShell/Operational'\n then: \n - add_fields:\n target: data_stream\n fields:\n dataset: windows.powershell_operational\n - add_fields:\n target: event\n fields:\n dataset: windows.powershell_operational\n module: windows\n - add_fields:\n target: \"@metadata\"\n fields:\n pipeline: logs-windows.powershell_operational-2.5.0\n- add_fields:\n target: data_stream\n fields:\n dataset: import", + "processors": "- dissect:\n tokenizer: \"/nsm/import/%{import.id}/evtx/%{import.file}\"\n field: \"log.file.path\"\n target_prefix: \"\"\n- decode_json_fields:\n fields: [\"message\"]\n target: \"\"\n- drop_fields:\n fields: [\"host\"]\n ignore_missing: true\n- add_fields:\n target: data_stream\n fields:\n type: logs\n dataset: system.security\n- add_fields:\n target: event\n fields:\n dataset: system.security\n module: system\n imported: true\n- add_fields:\n target: \"@metadata\"\n fields:\n pipeline: logs-system.security-2.3.1\n- if:\n equals:\n winlog.channel: 'Microsoft-Windows-Sysmon/Operational'\n then: \n - add_fields:\n target: data_stream\n fields:\n dataset: windows.sysmon_operational\n - add_fields:\n target: event\n fields:\n dataset: windows.sysmon_operational\n module: windows\n imported: true\n - add_fields:\n target: \"@metadata\"\n fields:\n pipeline: logs-windows.sysmon_operational-3.0.0\n- if:\n equals:\n winlog.channel: 'Application'\n then: \n - add_fields:\n target: data_stream\n fields:\n dataset: system.application\n - add_fields:\n target: event\n fields:\n dataset: system.application\n - add_fields:\n target: \"@metadata\"\n fields:\n pipeline: logs-system.application-2.3.1\n- if:\n equals:\n winlog.channel: 'System'\n then: \n - add_fields:\n target: data_stream\n fields:\n dataset: system.system\n - add_fields:\n target: event\n fields:\n dataset: system.system\n - add_fields:\n target: \"@metadata\"\n fields:\n pipeline: logs-system.system-2.3.1\n \n- if:\n equals:\n winlog.channel: 'Microsoft-Windows-PowerShell/Operational'\n then: \n - add_fields:\n target: data_stream\n fields:\n dataset: windows.powershell_operational\n - add_fields:\n target: event\n fields:\n dataset: windows.powershell_operational\n module: windows\n - add_fields:\n target: \"@metadata\"\n fields:\n pipeline: logs-windows.powershell_operational-3.0.0\n- add_fields:\n target: data_stream\n fields:\n dataset: import", "tags": [ "import" ] diff --git a/salt/elasticsearch/files/ingest/logs-pfsense.log-1.21.0 b/salt/elasticsearch/files/ingest/logs-pfsense.log-1.23.0 similarity index 93% rename from salt/elasticsearch/files/ingest/logs-pfsense.log-1.21.0 rename to salt/elasticsearch/files/ingest/logs-pfsense.log-1.23.0 index 7c4f2575f..e79b91b26 100644 --- a/salt/elasticsearch/files/ingest/logs-pfsense.log-1.21.0 +++ b/salt/elasticsearch/files/ingest/logs-pfsense.log-1.23.0 @@ -107,61 +107,61 @@ }, { "pipeline": { - "name": "logs-pfsense.log-1.21.0-firewall", + "name": "logs-pfsense.log-1.23.0-firewall", "if": "ctx.event.provider == 'filterlog'" } }, { "pipeline": { - "name": "logs-pfsense.log-1.21.0-openvpn", + "name": "logs-pfsense.log-1.23.0-openvpn", "if": "ctx.event.provider == 'openvpn'" } }, { "pipeline": { - "name": "logs-pfsense.log-1.21.0-ipsec", + "name": "logs-pfsense.log-1.23.0-ipsec", "if": "ctx.event.provider == 'charon'" } }, { "pipeline": { - "name": "logs-pfsense.log-1.21.0-dhcp", + "name": "logs-pfsense.log-1.23.0-dhcp", "if": "[\"dhcpd\", \"dhclient\", \"dhcp6c\"].contains(ctx.event.provider)" } }, { "pipeline": { - "name": "logs-pfsense.log-1.21.0-unbound", + "name": "logs-pfsense.log-1.23.0-unbound", "if": "ctx.event.provider == 'unbound'" } }, { "pipeline": { - "name": "logs-pfsense.log-1.21.0-haproxy", + "name": "logs-pfsense.log-1.23.0-haproxy", "if": "ctx.event.provider == 'haproxy'" } }, { "pipeline": { - "name": "logs-pfsense.log-1.21.0-php-fpm", + "name": "logs-pfsense.log-1.23.0-php-fpm", "if": "ctx.event.provider == 'php-fpm'" } }, { "pipeline": { - "name": "logs-pfsense.log-1.21.0-squid", + "name": "logs-pfsense.log-1.23.0-squid", "if": "ctx.event.provider == 'squid'" } }, { "pipeline": { - "name": "logs-pfsense.log-1.21.0-snort", + "name": "logs-pfsense.log-1.23.0-snort", "if": "ctx.event.provider == 'snort'" } }, { "pipeline": { - "name": "logs-pfsense.log-1.21.0-suricata", + "name": "logs-pfsense.log-1.23.0-suricata", "if": "ctx.event.provider == 'suricata'" } }, @@ -358,14 +358,6 @@ "source": "void handleMap(Map map) {\n for (def x : map.values()) {\n if (x instanceof Map) {\n handleMap(x);\n } else if (x instanceof List) {\n handleList(x);\n }\n }\n map.values().removeIf(v -> v == null || (v instanceof String && v == \"-\"));\n}\nvoid handleList(List list) {\n for (def x : list) {\n if (x instanceof Map) {\n handleMap(x);\n } else if (x instanceof List) {\n handleList(x);\n }\n }\n}\nhandleMap(ctx);\n" } }, - { - "remove": { - "field": "event.original", - "if": "ctx.tags == null || !(ctx.tags.contains('preserve_original_event'))", - "ignore_failure": true, - "ignore_missing": true - } - }, { "pipeline": { "name": "global@custom", diff --git a/salt/elasticsearch/files/ingest/logs-pfsense.log-1.21.0-suricata b/salt/elasticsearch/files/ingest/logs-pfsense.log-1.23.0-suricata similarity index 100% rename from salt/elasticsearch/files/ingest/logs-pfsense.log-1.21.0-suricata rename to salt/elasticsearch/files/ingest/logs-pfsense.log-1.23.0-suricata From 59628ec8b76f0f713fc8eb55ff407edce9b413fd Mon Sep 17 00:00:00 2001 From: reyesj2 <94730068+reyesj2@users.noreply.github.com> Date: Tue, 8 Jul 2025 16:15:18 -0500 Subject: [PATCH 238/315] revert foxtrot change --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 452820224..c3344819a 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.4.0-foxtrot \ No newline at end of file +2.4.170 \ No newline at end of file From 47bbc9987e509d20d913163b66d91b48034878b3 Mon Sep 17 00:00:00 2001 From: reyesj2 <94730068+reyesj2@users.noreply.github.com> Date: Tue, 8 Jul 2025 16:39:48 -0500 Subject: [PATCH 239/315] elastic agent upgrade prereq --- salt/manager/tools/sbin/soup | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/salt/manager/tools/sbin/soup b/salt/manager/tools/sbin/soup index f361da688..0c6ebfd26 100755 --- a/salt/manager/tools/sbin/soup +++ b/salt/manager/tools/sbin/soup @@ -802,9 +802,6 @@ up_to_2.4.130() { # Remove any old Elastic Defend config files rm -f /opt/so/conf/elastic-fleet/integrations/endpoints-initial/elastic-defend-endpoints.json - # Elastic Update for this release, so download Elastic Agent files - determine_elastic_agent_upgrade - # Ensure override exists to allow nmcli access to other devices touch /etc/NetworkManager/conf.d/10-globally-managed-devices.conf @@ -847,6 +844,9 @@ up_to_2.4.170() { touch /opt/so/saltstack/local/pillar/$state/adv_$state.sls /opt/so/saltstack/local/pillar/$state/soc_$state.sls done + # Elastic Update for this release, so download Elastic Agent files + determine_elastic_agent_upgrade + INSTALLEDVERSION=2.4.170 } From 76ab0eac03ce8e2fc1f726e5e561c1425edf89bd Mon Sep 17 00:00:00 2001 From: reyesj2 <94730068+reyesj2@users.noreply.github.com> Date: Tue, 8 Jul 2025 16:45:27 -0500 Subject: [PATCH 240/315] foxtrot Signed-off-by: reyesj2 <94730068+reyesj2@users.noreply.github.com> --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index c3344819a..7d52aac7f 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.4.170 \ No newline at end of file +2.4.0-foxtrot From b9d813cef2b67325e7aa253e66b06da33a111191 Mon Sep 17 00:00:00 2001 From: reyesj2 <94730068+reyesj2@users.noreply.github.com> Date: Tue, 8 Jul 2025 18:26:46 -0500 Subject: [PATCH 241/315] typo --- .../tools/sbin_jinja/so-elasticsearch-templates-load | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/elasticsearch/tools/sbin_jinja/so-elasticsearch-templates-load b/salt/elasticsearch/tools/sbin_jinja/so-elasticsearch-templates-load index ba5767255..4ac1b4d5f 100755 --- a/salt/elasticsearch/tools/sbin_jinja/so-elasticsearch-templates-load +++ b/salt/elasticsearch/tools/sbin_jinja/so-elasticsearch-templates-load @@ -136,7 +136,7 @@ if [ ! -f $STATE_FILE_SUCCESS ]; then TEMPLATE=${i::-14} COMPONENT_PATTERN=${TEMPLATE:3} MATCH=$(echo "$TEMPLATE" | grep -E "^so-logs-|^so-metrics" | grep -vE "detections|osquery") - if [[ -n "$MATCH" && ! "$COMPONENT_LIST" =~ "$COMPONENT_PATTERN" && ! "$COMPONENT_PATTERN" =~ *\.generic|logs-winlog\.winlog ]]; then + if [[ -n "$MATCH" && ! "$COMPONENT_LIST" =~ "$COMPONENT_PATTERN" && ! "$COMPONENT_PATTERN" =~ \.generic|logs-winlog\.winlog ]]; then load_failures=$((load_failures+1)) echo "Component template does not exist for $COMPONENT_PATTERN. The index template will not be loaded. Load failures: $load_failures" else From 07a22a0b4b22ad8f1eaee2d0647c0c12a4a9184c Mon Sep 17 00:00:00 2001 From: reyesj2 <94730068+reyesj2@users.noreply.github.com> Date: Tue, 8 Jul 2025 18:32:14 -0500 Subject: [PATCH 242/315] version --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 7d52aac7f..c3344819a 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.4.0-foxtrot +2.4.170 \ No newline at end of file From f1cbe23f575ab80c7952212b63269c82291e9662 Mon Sep 17 00:00:00 2001 From: reyesj2 <94730068+reyesj2@users.noreply.github.com> Date: Tue, 8 Jul 2025 21:17:57 -0500 Subject: [PATCH 243/315] update default kibana space --- salt/kibana/tools/sbin_jinja/so-kibana-space-defaults | 2 +- salt/manager/tools/sbin/soup | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/salt/kibana/tools/sbin_jinja/so-kibana-space-defaults b/salt/kibana/tools/sbin_jinja/so-kibana-space-defaults index a22aba066..cbd16a2de 100755 --- a/salt/kibana/tools/sbin_jinja/so-kibana-space-defaults +++ b/salt/kibana/tools/sbin_jinja/so-kibana-space-defaults @@ -13,6 +13,6 @@ echo "Setting up default Space:" {% if HIGHLANDER %} curl -K /opt/so/conf/elasticsearch/curl.config -b "sid=$SESSIONCOOKIE" -L -X PUT "localhost:5601/api/spaces/space/default" -H 'kbn-xsrf: true' -H 'Content-Type: application/json' -d' {"id":"default","name":"Default","disabledFeatures":["enterpriseSearch"]} ' >> /opt/so/log/kibana/misc.log {% else %} -curl -K /opt/so/conf/elasticsearch/curl.config -b "sid=$SESSIONCOOKIE" -L -X PUT "localhost:5601/api/spaces/space/default" -H 'kbn-xsrf: true' -H 'Content-Type: application/json' -d' {"id":"default","name":"Default","disabledFeatures":["ml","enterpriseSearch","logs","infrastructure","apm","uptime","monitoring","stackAlerts","actions","securitySolutionCasesV2","inventory","dataQuality","actions"]} ' >> /opt/so/log/kibana/misc.log +curl -K /opt/so/conf/elasticsearch/curl.config -b "sid=$SESSIONCOOKIE" -L -X PUT "localhost:5601/api/spaces/space/default" -H 'kbn-xsrf: true' -H 'Content-Type: application/json' -d' {"id":"default","name":"Default","disabledFeatures":["ml","enterpriseSearch","logs","infrastructure","apm","uptime","monitoring","stackAlerts","actions","securitySolutionCasesV3","inventory","dataQuality","searchSynonyms","enterpriseSearchApplications","enterpriseSearchAnalytics","securitySolutionTimeline","securitySolutionNotes","entityManager"]} ' >> /opt/so/log/kibana/misc.log {% endif %} echo diff --git a/salt/manager/tools/sbin/soup b/salt/manager/tools/sbin/soup index 0c6ebfd26..e37ccbfda 100755 --- a/salt/manager/tools/sbin/soup +++ b/salt/manager/tools/sbin/soup @@ -590,6 +590,12 @@ post_to_2.4.160() { post_to_2.4.170() { echo "Regenerating Elastic Agent Installers" /sbin/so-elastic-agent-gen-installers + + # Update kibana default space + salt-call state.apply kibana.config queue=True + echo "Updating Kibana default space" + /usr/sbin/so-kibana-space-defaults + POSTVERSION=2.4.170 } From 3fb703cd22797e8a641627de65377540821ba258 Mon Sep 17 00:00:00 2001 From: reyesj2 <94730068+reyesj2@users.noreply.github.com> Date: Wed, 9 Jul 2025 11:59:25 -0500 Subject: [PATCH 244/315] check if generic template exists in installed component templates before defaulting to logs-filestream.generic@package --- salt/elasticfleet/integration-defaults.map.jinja | 5 +++-- .../sbin_jinja/so-elastic-fleet-optional-integrations-load | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/salt/elasticfleet/integration-defaults.map.jinja b/salt/elasticfleet/integration-defaults.map.jinja index 62e37b229..d385c15aa 100644 --- a/salt/elasticfleet/integration-defaults.map.jinja +++ b/salt/elasticfleet/integration-defaults.map.jinja @@ -4,7 +4,7 @@ {% import_json '/opt/so/state/esfleet_package_components.json' as ADDON_PACKAGE_COMPONENTS %} -{% import_json '/opt/so/state/esfleet_package_components.json' as INSTALLED_COMPONENT_TEMPLATES %} +{% import_json '/opt/so/state/esfleet_component_templates.json' as INSTALLED_COMPONENT_TEMPLATES %} {% import_yaml 'elasticfleet/defaults.yaml' as ELASTICFLEETDEFAULTS %} {% set CORE_ESFLEET_PACKAGES = ELASTICFLEETDEFAULTS.get('elasticfleet', {}).get('packages', {}) %} @@ -83,7 +83,8 @@ {# pillar overrides/merge expects the key names to follow the naming in elasticsearch/defaults.yaml eg. so-logs-1password_x_item_usages . The _x_ is replaced later on in elasticsearch/template.map.jinja #} {% set integration_key = "so-" ~ integration_type ~ component_name_x %} -{% if ".generic" in component_name and component_name not in INSTALLED_COMPONENT_TEMPLATES %} +{# if its a .generic template make sure that a .generic@package for the integration exists. Else default to logs-filestream.generic@package #} +{% if ".generic" in component_name and integration_type ~ component_name ~ "@package" not in INSTALLED_COMPONENT_TEMPLATES %} {# these generic templates by default are directed to index_pattern of 'logs-generic-*', overwrite that here to point to eg gcp_pubsub.generic-* #} {% set index_pattern = integration_type ~ component_name ~ "-*" %} {# includes use of .generic component template, but it doesn't exist in installed component templates. Redirect it to filestream.generic@package #} diff --git a/salt/elasticfleet/tools/sbin_jinja/so-elastic-fleet-optional-integrations-load b/salt/elasticfleet/tools/sbin_jinja/so-elastic-fleet-optional-integrations-load index df01608f5..e877a9e37 100644 --- a/salt/elasticfleet/tools/sbin_jinja/so-elastic-fleet-optional-integrations-load +++ b/salt/elasticfleet/tools/sbin_jinja/so-elastic-fleet-optional-integrations-load @@ -19,7 +19,7 @@ BULK_INSTALL_PACKAGE_LIST=/tmp/esfleet_bulk_install.json BULK_INSTALL_PACKAGE_TMP=/tmp/esfleet_bulk_install_tmp.json BULK_INSTALL_OUTPUT=/opt/so/state/esfleet_bulk_install_results.json PACKAGE_COMPONENTS=/opt/so/state/esfleet_package_components.json -COMPONENT_TEMPLATES=/opt/so/state/esfleet_component_templates.txt +COMPONENT_TEMPLATES=/opt/so/state/esfleet_component_templates.json PENDING_UPDATE=false From a03764d95678625a29b682e21b20ef43da1eeadb Mon Sep 17 00:00:00 2001 From: reyesj2 <94730068+reyesj2@users.noreply.github.com> Date: Wed, 9 Jul 2025 12:34:53 -0500 Subject: [PATCH 245/315] additional weird integration --- salt/elasticfleet/integration-defaults.map.jinja | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/salt/elasticfleet/integration-defaults.map.jinja b/salt/elasticfleet/integration-defaults.map.jinja index d385c15aa..182dc95a3 100644 --- a/salt/elasticfleet/integration-defaults.map.jinja +++ b/salt/elasticfleet/integration-defaults.map.jinja @@ -46,7 +46,10 @@ 'synthetics.browser_screenshot': 'synthetics-browser.screenshot', 'synthetics.http': 'synthetics-http', 'synthetics.icmp': 'synthetics-icmp', - 'synthetics.tcp': 'synthetics-tcp' + 'synthetics.tcp': 'synthetics-tcp', + 'swimlane.swimlane_api': 'swimlane.api', + 'swimlane.tenant_api': 'swimlane.tenant', + 'swimlane.turbine_api': 'turbine.api' } %} {% for pkg in ADDON_PACKAGE_COMPONENTS %} From 33e2d18aa7094272b59a50b1af9d1729381b1279 Mon Sep 17 00:00:00 2001 From: reyesj2 <94730068+reyesj2@users.noreply.github.com> Date: Wed, 9 Jul 2025 13:59:01 -0500 Subject: [PATCH 246/315] endpoint policy update --- .../elastic-defend-endpoints.json | 64 ++++++++++--------- 1 file changed, 33 insertions(+), 31 deletions(-) diff --git a/salt/elasticfleet/files/integrations/elastic-defend/elastic-defend-endpoints.json b/salt/elasticfleet/files/integrations/elastic-defend/elastic-defend-endpoints.json index 87870c7bc..ee55551e3 100644 --- a/salt/elasticfleet/files/integrations/elastic-defend/elastic-defend-endpoints.json +++ b/salt/elasticfleet/files/integrations/elastic-defend/elastic-defend-endpoints.json @@ -1,32 +1,34 @@ { - "name": "elastic-defend-endpoints", - "namespace": "default", - "description": "", - "package": { - "name": "endpoint", - "title": "Elastic Defend", - "version": "8.17.0", - "requires_root": true - }, - "enabled": true, - "policy_id": "endpoints-initial", - "vars": {}, - "inputs": [ - { - "type": "endpoint", - "enabled": true, - "config": { - "integration_config": { - "value": { - "type": "endpoint", - "endpointConfig": { - "preset": "DataCollection" - } - } - } - }, - "streams": [] - } - ] - } - \ No newline at end of file + "name": "elastic-defend-endpoints", + "namespace": "default", + "description": "", + "package": { + "name": "endpoint", + "title": "Elastic Defend", + "version": "8.18.1", + "requires_root": true + }, + "enabled": true, + "policy_ids": [ + "endpoints-initial" + ], + "vars": {}, + "inputs": [ + { + "type": "ENDPOINT_INTEGRATION_CONFIG", + "enabled": true, + "config": { + "_config": { + "value": { + "type": "endpoint", + "endpointConfig": { + "preset": "DataCollection" + } + } + } + }, + "streams": [] + } + ], + "force": false +} \ No newline at end of file From fa6f4100dd350b10cdb98314d48343d46e50990c Mon Sep 17 00:00:00 2001 From: reyesj2 <94730068+reyesj2@users.noreply.github.com> Date: Wed, 9 Jul 2025 14:48:15 -0500 Subject: [PATCH 247/315] ensure elasticsearch is up --- .../so-elastic-fleet-optional-integrations-load | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/salt/elasticfleet/tools/sbin_jinja/so-elastic-fleet-optional-integrations-load b/salt/elasticfleet/tools/sbin_jinja/so-elastic-fleet-optional-integrations-load index e877a9e37..8a2c388b1 100644 --- a/salt/elasticfleet/tools/sbin_jinja/so-elastic-fleet-optional-integrations-load +++ b/salt/elasticfleet/tools/sbin_jinja/so-elastic-fleet-optional-integrations-load @@ -156,9 +156,11 @@ if [[ -f $STATE_FILE_SUCCESS ]]; then # Write out file for generating index/component/ilm templates latest_installed_package_list=$(elastic_fleet_installed_packages) echo $latest_installed_package_list | jq '[.items[] | {name: .name, es_index_patterns: .dataStreams}]' > $PACKAGE_COMPONENTS - # Refresh installed component template list - latest_component_templates_list=$(so-elasticsearch-query _component_template | jq '.component_templates[] | .name' | jq -s '.') - echo $latest_component_templates_list > $COMPONENT_TEMPLATES + if retry 3 1 "so-elasticsearch-query / --fail --output /dev/null"; then + # Refresh installed component template list + latest_component_templates_list=$(so-elasticsearch-query _component_template | jq '.component_templates[] | .name' | jq -s '.') + echo $latest_component_templates_list > $COMPONENT_TEMPLATES + fi else # This is the installation of add-on integrations and upgrade of existing integrations. Exiting without error, next highstate will attempt to re-run. From 3b2942651e9890726d1a040086b69d519790a736 Mon Sep 17 00:00:00 2001 From: Jorge Reyes <94730068+reyesj2@users.noreply.github.com> Date: Wed, 9 Jul 2025 15:14:24 -0500 Subject: [PATCH 248/315] Update salt/elasticfleet/files/integrations/elastic-defend/elastic-defend-endpoints.json --- .../integrations/elastic-defend/elastic-defend-endpoints.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/elasticfleet/files/integrations/elastic-defend/elastic-defend-endpoints.json b/salt/elasticfleet/files/integrations/elastic-defend/elastic-defend-endpoints.json index ee55551e3..27162669d 100644 --- a/salt/elasticfleet/files/integrations/elastic-defend/elastic-defend-endpoints.json +++ b/salt/elasticfleet/files/integrations/elastic-defend/elastic-defend-endpoints.json @@ -30,5 +30,5 @@ "streams": [] } ], - "force": false +} } \ No newline at end of file From d846fe55e14d93666dfd7e13ff1411863d2b1abb Mon Sep 17 00:00:00 2001 From: reyesj2 <94730068+reyesj2@users.noreply.github.com> Date: Wed, 9 Jul 2025 15:40:36 -0500 Subject: [PATCH 249/315] typos --- .../integrations/elastic-defend/elastic-defend-endpoints.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/salt/elasticfleet/files/integrations/elastic-defend/elastic-defend-endpoints.json b/salt/elasticfleet/files/integrations/elastic-defend/elastic-defend-endpoints.json index 27162669d..fb9069e83 100644 --- a/salt/elasticfleet/files/integrations/elastic-defend/elastic-defend-endpoints.json +++ b/salt/elasticfleet/files/integrations/elastic-defend/elastic-defend-endpoints.json @@ -29,6 +29,5 @@ }, "streams": [] } - ], -} + ] } \ No newline at end of file From 317d7dea7d7c5561a42662cbb546cd4c7424c6f9 Mon Sep 17 00:00:00 2001 From: reyesj2 <94730068+reyesj2@users.noreply.github.com> Date: Wed, 9 Jul 2025 17:25:36 -0500 Subject: [PATCH 250/315] check required files exist before loading map file Signed-off-by: reyesj2 <94730068+reyesj2@users.noreply.github.com> --- salt/elasticsearch/template.map.jinja | 2 +- salt/manager/managed_soc_annotations.sls | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/salt/elasticsearch/template.map.jinja b/salt/elasticsearch/template.map.jinja index aa90cb81b..414d8a6b4 100644 --- a/salt/elasticsearch/template.map.jinja +++ b/salt/elasticsearch/template.map.jinja @@ -15,7 +15,7 @@ {% set ES_INDEX_SETTINGS_ORIG = ELASTICSEARCHDEFAULTS.elasticsearch.index_settings %} {# start generation of integration default index_settings #} -{% if salt['file.file_exists']('/opt/so/state/esfleet_package_components.json') %} +{% if salt['file.file_exists']('/opt/so/state/esfleet_package_components.json') and salt['file.file_exists']('/opt/so/state/esfleet_component_templates.json') %} {% set check_package_components = salt['file.stats']('/opt/so/state/esfleet_package_components.json') %} {% if check_package_components.size > 1 %} {% from 'elasticfleet/integration-defaults.map.jinja' import ADDON_INTEGRATION_DEFAULTS %} diff --git a/salt/manager/managed_soc_annotations.sls b/salt/manager/managed_soc_annotations.sls index 9ef0b1ea1..d8f175df6 100644 --- a/salt/manager/managed_soc_annotations.sls +++ b/salt/manager/managed_soc_annotations.sls @@ -5,7 +5,7 @@ {# Managed elasticsearch/soc_elasticsearch.yaml file for adding integration configuration items to UI #} {% set managed_integrations = salt['pillar.get']('elasticsearch:managed_integrations', []) %} -{% if managed_integrations and salt['file.file_exists']('/opt/so/state/esfleet_package_components.json') %} +{% if managed_integrations and salt['file.file_exists']('/opt/so/state/esfleet_package_components.json') and salt['file.file_exists']('/opt/so/state/esfleet_component_templates.json') %} {% from 'elasticfleet/integration-defaults.map.jinja' import ADDON_INTEGRATION_DEFAULTS %} {% set addon_integration_keys = ADDON_INTEGRATION_DEFAULTS.keys() %} {% set matched_integration_names = [] %} From 95ba327eb3e9eab2b031cf80c49658cedb0b5b79 Mon Sep 17 00:00:00 2001 From: reyesj2 <94730068+reyesj2@users.noreply.github.com> Date: Thu, 10 Jul 2025 11:08:46 -0500 Subject: [PATCH 251/315] cribl metrics template rename --- salt/elasticfleet/integration-defaults.map.jinja | 1 + 1 file changed, 1 insertion(+) diff --git a/salt/elasticfleet/integration-defaults.map.jinja b/salt/elasticfleet/integration-defaults.map.jinja index 182dc95a3..500a9e63c 100644 --- a/salt/elasticfleet/integration-defaults.map.jinja +++ b/salt/elasticfleet/integration-defaults.map.jinja @@ -15,6 +15,7 @@ 'awsfirehose.logs': 'awsfirehose', 'awsfirehose.metrics': 'aws.cloudwatch', 'cribl.logs': 'cribl', + 'cribl.metrics': 'cribl', 'sentinel_one_cloud_funnel.logins': 'sentinel_one_cloud_funnel.login', 'azure_application_insights.app_insights': 'azure.app_insights', 'azure_application_insights.app_state': 'azure.app_state', From a4e8e7ea535251d9aeb826a5fd97c9ef18fe977e Mon Sep 17 00:00:00 2001 From: reyesj2 <94730068+reyesj2@users.noreply.github.com> Date: Thu, 10 Jul 2025 13:12:26 -0500 Subject: [PATCH 252/315] update syslog-tcp-514 policy --- .../integrations/grid-nodes_general/syslog-tcp-514.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/salt/elasticfleet/files/integrations/grid-nodes_general/syslog-tcp-514.json b/salt/elasticfleet/files/integrations/grid-nodes_general/syslog-tcp-514.json index 4088f5a87..f284ede06 100644 --- a/salt/elasticfleet/files/integrations/grid-nodes_general/syslog-tcp-514.json +++ b/salt/elasticfleet/files/integrations/grid-nodes_general/syslog-tcp-514.json @@ -11,7 +11,7 @@ "tcp-tcp": { "enabled": true, "streams": { - "tcp.generic": { + "tcp.tcp": { "enabled": true, "vars": { "listen_address": "0.0.0.0", @@ -23,7 +23,8 @@ "syslog" ], "syslog_options": "field: message\n#format: auto\n#timezone: Local", - "ssl": "" + "ssl": "", + "custom": "" } } } From 8a57b79b779f60fa04b22cdd8226bbd1f1eb07c7 Mon Sep 17 00:00:00 2001 From: reyesj2 <94730068+reyesj2@users.noreply.github.com> Date: Thu, 10 Jul 2025 15:52:59 -0500 Subject: [PATCH 253/315] make package installs go in groups of 25 or less --- ...so-elastic-fleet-optional-integrations-load | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/salt/elasticfleet/tools/sbin_jinja/so-elastic-fleet-optional-integrations-load b/salt/elasticfleet/tools/sbin_jinja/so-elastic-fleet-optional-integrations-load index 8a2c388b1..886bbf75c 100644 --- a/salt/elasticfleet/tools/sbin_jinja/so-elastic-fleet-optional-integrations-load +++ b/salt/elasticfleet/tools/sbin_jinja/so-elastic-fleet-optional-integrations-load @@ -148,8 +148,22 @@ if [[ -f $STATE_FILE_SUCCESS ]]; then done <<< "$(jq -c '.packages[]' "$INSTALLED_PACKAGE_LIST")" if [ "$PENDING_UPDATE" = true ]; then - # Run bulk install of packages - elastic_fleet_bulk_package_install $BULK_INSTALL_PACKAGE_LIST > $BULK_INSTALL_OUTPUT + # Run chunked install of packages + echo "" > $BULK_INSTALL_OUTPUT + pkg_group=1 + pkg_filename="${BULK_INSTALL_PACKAGE_LIST%.json}" + + jq -c '.packages | _nwise(25)' $BULK_INSTALL_PACKAGE_LIST | while read -r line; do + echo "$line" | jq '{ "packages": . }' > "${pkg_filename}_${pkg_group}.json" + pkg_group=$((pkg_group + 1)) + done + + for file in "${pkg_filename}_"*.json; do + [ -e "$file" ] || continue + elastic_fleet_bulk_package_install $file >> $BULK_INSTALL_OUTPUT + done + # cleanup any temp files for chunked package install + rm -f ${pkg_filename}_*.json $BULK_INSTALL_PACKAGE_LIST else echo "Elastic integrations don't appear to need installation/updating..." fi From 415f456661fd24b846c68159000c882993d4c9de Mon Sep 17 00:00:00 2001 From: reyesj2 <94730068+reyesj2@users.noreply.github.com> Date: Sat, 12 Jul 2025 08:30:04 -0500 Subject: [PATCH 254/315] ignore composable templates with error in the name --- salt/common/tools/sbin/so-log-check | 1 + 1 file changed, 1 insertion(+) diff --git a/salt/common/tools/sbin/so-log-check b/salt/common/tools/sbin/so-log-check index c84fc7803..72ece1919 100755 --- a/salt/common/tools/sbin/so-log-check +++ b/salt/common/tools/sbin/so-log-check @@ -159,6 +159,7 @@ if [[ $EXCLUDE_FALSE_POSITIVE_ERRORS == 'Y' ]]; then EXCLUDED_ERRORS="$EXCLUDED_ERRORS|adding ingest pipeline" # false positive (elasticsearch ingest pipeline names contain 'error') EXCLUDED_ERRORS="$EXCLUDED_ERRORS|updating index template" # false positive (elasticsearch index or template names contain 'error') EXCLUDED_ERRORS="$EXCLUDED_ERRORS|updating component template" # false positive (elasticsearch index or template names contain 'error') + EXCLUDED_ERRORS="$EXCLUDED_ERRORS|upgrading composable template" # false positive (elasticsearch composable template names contain 'error') fi if [[ $EXCLUDE_KNOWN_ERRORS == 'Y' ]]; then From f8108e93d5a9a99c16c471d9132d1a225a9f4f2c Mon Sep 17 00:00:00 2001 From: Doug Burks Date: Mon, 14 Jul 2025 12:04:46 -0400 Subject: [PATCH 255/315] FEATURE: Add SOC default fields for iptables logs #14836 --- salt/soc/defaults.yaml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/salt/soc/defaults.yaml b/salt/soc/defaults.yaml index cb12671f8..35eb22ab0 100644 --- a/salt/soc/defaults.yaml +++ b/salt/soc/defaults.yaml @@ -1336,6 +1336,13 @@ soc: - soc.fields.statusCode - event.action - soc.fields.error + ':iptables:': + - soc_timestamp + - source.ip + - source.port + - destination.ip + - destination.port + - message server: bindAddress: 0.0.0.0:9822 baseUrl: / From 10bf3e8fab0681d0f9f2f11fa7a23666f7fc5fe9 Mon Sep 17 00:00:00 2001 From: Doug Burks Date: Mon, 14 Jul 2025 12:07:02 -0400 Subject: [PATCH 256/315] FEATURE: Add SOC default fields for CEF logs #14837 --- salt/soc/defaults.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/salt/soc/defaults.yaml b/salt/soc/defaults.yaml index 35eb22ab0..e84a5b017 100644 --- a/salt/soc/defaults.yaml +++ b/salt/soc/defaults.yaml @@ -1343,6 +1343,14 @@ soc: - destination.ip - destination.port - message + ':cef:': + - soc_timestamp + - cef.device.event_class_id + - cef.device.vendor + - cef.device.product + - cef.device.version + - log.source.address + - message server: bindAddress: 0.0.0.0:9822 baseUrl: / From ab9d03bc2e7cd4b38f08e596ab14e4ad205007d2 Mon Sep 17 00:00:00 2001 From: Doug Burks Date: Mon, 14 Jul 2025 12:21:08 -0400 Subject: [PATCH 257/315] FEATURE: Add SOC Dashboards for UniFi logs #14838 --- salt/soc/defaults.yaml | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/salt/soc/defaults.yaml b/salt/soc/defaults.yaml index e84a5b017..23c966bb4 100644 --- a/salt/soc/defaults.yaml +++ b/salt/soc/defaults.yaml @@ -2142,15 +2142,6 @@ soc: - name: ICS S7 description: S7 (Siemens) network metadata query: 'tags:s7* | groupby event.dataset | groupby -sankey event.dataset source.ip | groupby source.ip | groupby -sankey source.ip destination.ip | groupby destination.ip | groupby destination.port' - - name: NetFlow - description: NetFlow records - query: 'event.module:netflow | groupby source.ip | groupby -sankey source.ip destination.ip | groupby destination.ip | groupby destination.port | groupby network.type | groupby network.transport | groupby network.direction | groupby netflow.type | groupby netflow.exporter.version | groupby observer.ip | groupby source.as.organization.name | groupby source.geo.country_name | groupby destination.as.organization.name | groupby destination.geo.country_name' - - name: Firewall - description: Firewall logs - query: 'observer.type:firewall | groupby event.action | groupby -sankey event.action observer.ingress.interface.name | groupby observer.ingress.interface.name | groupby network.type | groupby network.transport | groupby source.ip | groupby destination.ip | groupby destination.port' - - name: Firewall Auth - description: Firewall authentication logs - query: 'observer.type:firewall AND event.category:authentication | groupby user.name | groupby -sankey user.name source.ip | groupby source.ip | table soc_timestamp user.name source.ip message' - name: VLAN description: VLAN (Virtual Local Area Network) tagged logs query: '* AND _exists_:network.vlan.id | groupby network.vlan.id | groupby -sankey network.vlan.id source.ip | groupby source.ip | groupby destination.ip | groupby destination.port | groupby event.dataset | groupby event.module | groupby observer.name | groupby source.geo.country_name | groupby destination.geo.country_name' @@ -2166,6 +2157,27 @@ soc: - name: GeoIP - Source Organizations description: GeoIP tagged logs visualized by source organizations query: '* AND _exists_:source_geo.organization_name | groupby source_geo.organization_name | groupby source.ip | groupby -sankey source.ip destination.ip | groupby destination.ip | groupby destination.port | groupby source.geo.country_name | groupby event.dataset | groupby event.module' + - name: NetFlow + description: NetFlow records + query: 'event.module:netflow | groupby source.ip | groupby -sankey source.ip destination.ip | groupby destination.ip | groupby destination.port | groupby network.type | groupby network.transport | groupby network.direction | groupby netflow.type | groupby netflow.exporter.version | groupby observer.ip | groupby source.as.organization.name | groupby source.geo.country_name | groupby destination.as.organization.name | groupby destination.geo.country_name' + - name: Firewall - pfSense/OPNsense + description: pfSense/OPNsense firewall logs + query: 'observer.type:firewall | groupby event.action | groupby -sankey event.action observer.ingress.interface.name | groupby observer.ingress.interface.name | groupby network.type | groupby network.transport | groupby source.ip | groupby destination.ip | groupby destination.port' + - name: Firewall - pfSense/OPNsense Auth + description: pfSense/OPNsense firewall authentication logs + query: 'observer.type:firewall AND event.category:authentication | groupby user.name | groupby -sankey user.name source.ip | groupby source.ip | table soc_timestamp user.name source.ip message' + - name: Firewall - UniFi Firewall Overview + description: All network traffic logged by UniFi firewall + query: 'event.module:iptables AND event.type:connection | groupby source.ip | groupby -sankey source.ip destination.ip | groupby destination.ip | groupby -sankey destination.ip destination.port | groupby destination.port' + - name: Firewall - UniFi Firewall Blocks + description: Network traffic blocked by UniFi firewall + query: 'event.module:iptables AND event.type:connection AND (message:iptables-dropped OR message:block) | groupby source.ip | groupby -sankey source.ip destination.ip | groupby destination.ip | groupby -sankey destination.ip destination.port | groupby destination.port' + - name: Firewall - UniFi Firewall Allows + description: Network traffic allowed by UniFi firewall + query: 'event.module:iptables AND event.type:connection AND NOT (message:iptables-dropped OR message:block) | groupby source.ip | groupby -sankey source.ip destination.ip | groupby destination.ip | groupby -sankey destination.ip destination.port | groupby destination.port' + - name: Firewall - UniFi Auth + description: UniFi authentication logs + query: 'event.module:cef | groupby cef.device.event_class_id | groupby -sankey cef.device.event_class_id cef.device.vendor | groupby cef.device.vendor | groupby cef.device.product | groupby cef.device.version | groupby log.source.address' - name: Kismet - WiFi Devices description: WiFi devices seen by Kismet sensors query: 'event.module: kismet | groupby network.wireless.ssid | groupby device.manufacturer | groupby -pie device.manufacturer | groupby event.dataset' From 4f8bd16910050c973d2dfc8e65fb1c599516e3fa Mon Sep 17 00:00:00 2001 From: Doug Burks Date: Mon, 14 Jul 2025 15:37:10 -0400 Subject: [PATCH 258/315] FEATURE: Add SOC Dashboards for CEF, iptables, and UniFi logs #14838 --- salt/soc/defaults.yaml | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/salt/soc/defaults.yaml b/salt/soc/defaults.yaml index 23c966bb4..0c5967753 100644 --- a/salt/soc/defaults.yaml +++ b/salt/soc/defaults.yaml @@ -2166,6 +2166,9 @@ soc: - name: Firewall - pfSense/OPNsense Auth description: pfSense/OPNsense firewall authentication logs query: 'observer.type:firewall AND event.category:authentication | groupby user.name | groupby -sankey user.name source.ip | groupby source.ip | table soc_timestamp user.name source.ip message' + - name: Firewall - iptables + description: All network traffic logged by Elastic integration for iptables + query: 'event.module:iptables AND event.type:connection | groupby source.ip | groupby -sankey source.ip destination.ip | groupby destination.ip | groupby -sankey destination.ip destination.port | groupby destination.port' - name: Firewall - UniFi Firewall Overview description: All network traffic logged by UniFi firewall query: 'event.module:iptables AND event.type:connection | groupby source.ip | groupby -sankey source.ip destination.ip | groupby destination.ip | groupby -sankey destination.ip destination.port | groupby destination.port' @@ -2175,8 +2178,11 @@ soc: - name: Firewall - UniFi Firewall Allows description: Network traffic allowed by UniFi firewall query: 'event.module:iptables AND event.type:connection AND NOT (message:iptables-dropped OR message:block) | groupby source.ip | groupby -sankey source.ip destination.ip | groupby destination.ip | groupby -sankey destination.ip destination.port | groupby destination.port' - - name: Firewall - UniFi Auth - description: UniFi authentication logs + - name: Firewall - UniFi System + description: UniFi system logs + query: 'event.module:cef | groupby cef.device.event_class_id | groupby -sankey cef.device.event_class_id cef.device.vendor | groupby cef.device.vendor | groupby cef.device.product | groupby cef.device.version | groupby log.source.address' + - name: CEF + description: Logs handled by the Elastic integration for CEF query: 'event.module:cef | groupby cef.device.event_class_id | groupby -sankey cef.device.event_class_id cef.device.vendor | groupby cef.device.vendor | groupby cef.device.product | groupby cef.device.version | groupby log.source.address' - name: Kismet - WiFi Devices description: WiFi devices seen by Kismet sensors @@ -2184,9 +2190,6 @@ soc: - name: SOC Detections - Runtime Status description: Runtime Status of Detections query: 'event.dataset:soc.detections | groupby soc.detection_type soc.error_type | groupby soc.error_analysis | groupby soc.rule.name | groupby soc.error_message' - - - job: alerts: advanced: false From 81d2c5286727e7ab7033213d7a307aeed1f28ac2 Mon Sep 17 00:00:00 2001 From: reyesj2 <94730068+reyesj2@users.noreply.github.com> Date: Mon, 14 Jul 2025 16:08:11 -0500 Subject: [PATCH 259/315] kibana listingLimit --- salt/kibana/files/config_saved_objects.ndjson.jinja | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/kibana/files/config_saved_objects.ndjson.jinja b/salt/kibana/files/config_saved_objects.ndjson.jinja index 4902a1445..b1c2f0fb7 100644 --- a/salt/kibana/files/config_saved_objects.ndjson.jinja +++ b/salt/kibana/files/config_saved_objects.ndjson.jinja @@ -1,3 +1,3 @@ {% import_yaml 'elasticsearch/defaults.yaml' as ELASTICSEARCHDEFAULTS -%} -{"attributes": {"buildNum": 39457,"defaultIndex": "logs-*","defaultRoute": "/app/dashboards#/view/a8411b30-6d03-11ea-b301-3d6c35840645","discover:sampleSize": 100,"theme:darkMode": true,"timepicker:timeDefaults": "{\n \"from\": \"now-24h\",\n \"to\": \"now\"\n}"},"coreMigrationVersion": "{{ ELASTICSEARCHDEFAULTS.elasticsearch.version }}","id": "{{ ELASTICSEARCHDEFAULTS.elasticsearch.version }}","references": [],"type": "config","updated_at": "2021-10-10T10:10:10.105Z","version": "WzI5NzUsMl0="} +{"attributes": {"buildNum": 39457,"defaultIndex": "logs-*","defaultRoute": "/app/dashboards#/view/a8411b30-6d03-11ea-b301-3d6c35840645","discover:sampleSize": 100,"savedObjects:listingLimit":1500,"theme:darkMode": true,"timepicker:timeDefaults": "{\n \"from\": \"now-24h\",\n \"to\": \"now\"\n}"},"coreMigrationVersion": "{{ ELASTICSEARCHDEFAULTS.elasticsearch.version }}","id": "{{ ELASTICSEARCHDEFAULTS.elasticsearch.version }}","references": [],"type": "config","version": "WzI5NzUsMl0="} From 6bb6c24641d26f96585050df531f0dc8bdcf9d3a Mon Sep 17 00:00:00 2001 From: Doug Burks Date: Wed, 16 Jul 2025 07:20:39 -0400 Subject: [PATCH 260/315] Simplify UniFi dashboards #14838 --- salt/soc/defaults.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/salt/soc/defaults.yaml b/salt/soc/defaults.yaml index 0c5967753..ad7d51f68 100644 --- a/salt/soc/defaults.yaml +++ b/salt/soc/defaults.yaml @@ -2174,10 +2174,10 @@ soc: query: 'event.module:iptables AND event.type:connection | groupby source.ip | groupby -sankey source.ip destination.ip | groupby destination.ip | groupby -sankey destination.ip destination.port | groupby destination.port' - name: Firewall - UniFi Firewall Blocks description: Network traffic blocked by UniFi firewall - query: 'event.module:iptables AND event.type:connection AND (message:iptables-dropped OR message:block) | groupby source.ip | groupby -sankey source.ip destination.ip | groupby destination.ip | groupby -sankey destination.ip destination.port | groupby destination.port' + query: 'event.module:iptables AND event.type:connection AND message:block | groupby source.ip | groupby -sankey source.ip destination.ip | groupby destination.ip | groupby -sankey destination.ip destination.port | groupby destination.port' - name: Firewall - UniFi Firewall Allows description: Network traffic allowed by UniFi firewall - query: 'event.module:iptables AND event.type:connection AND NOT (message:iptables-dropped OR message:block) | groupby source.ip | groupby -sankey source.ip destination.ip | groupby destination.ip | groupby -sankey destination.ip destination.port | groupby destination.port' + query: 'event.module:iptables AND event.type:connection AND NOT message:block | groupby source.ip | groupby -sankey source.ip destination.ip | groupby destination.ip | groupby -sankey destination.ip destination.port | groupby destination.port' - name: Firewall - UniFi System description: UniFi system logs query: 'event.module:cef | groupby cef.device.event_class_id | groupby -sankey cef.device.event_class_id cef.device.vendor | groupby cef.device.vendor | groupby cef.device.product | groupby cef.device.version | groupby log.source.address' From 98a67530f5d01f3b665bbccf48fc4565fb2397ef Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Wed, 16 Jul 2025 12:14:25 -0400 Subject: [PATCH 261/315] update qcow2 hosted location --- salt/_runners/setup_hypervisor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/_runners/setup_hypervisor.py b/salt/_runners/setup_hypervisor.py index 6ddd571c9..9d7116d59 100644 --- a/salt/_runners/setup_hypervisor.py +++ b/salt/_runners/setup_hypervisor.py @@ -165,7 +165,7 @@ def _validate_image_checksum(path, expected_sha256): return True # Constants -IMAGE_URL = "https://yum.oracle.com/templates/OracleLinux/OL9/u5/x86_64/OL9U5_x86_64-kvm-b253.qcow2" +IMAGE_URL = "https://download.securityonion.net/file/securityonion/OL9U5_x86_64-kvm-b253.qcow2" IMAGE_SHA256 = "3b00bbbefc8e78dd28d9f538834fb9e2a03d5ccdc2cadf2ffd0036c0a8f02021" IMAGE_PATH = "/nsm/libvirt/boot/OL9U5_x86_64-kvm-b253.qcow2" MANAGER_HOSTNAME = socket.gethostname() From cd5de5cd0516799d310569c70cda3d348cb52aea Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Wed, 16 Jul 2025 12:14:54 -0400 Subject: [PATCH 262/315] add sos hw models --- salt/hypervisor/defaults.yaml | 122 +++++++++++++++++++++++++--------- 1 file changed, 92 insertions(+), 30 deletions(-) diff --git a/salt/hypervisor/defaults.yaml b/salt/hypervisor/defaults.yaml index 06509828c..8cf754193 100644 --- a/salt/hypervisor/defaults.yaml +++ b/salt/hypervisor/defaults.yaml @@ -17,42 +17,104 @@ hypervisor: 6: pci_0000_02_00_1 7: pci_0000_41_00_0 8: pci_0000_41_00_1 - model1: + SOSSNNV: hardware: cpu: 128 - memory: 128 + memory: 256 disk: - 1: pci_0000_c7_00_0 - 2: pci_0000_c8_00_0 + 1: pci_0000_42_00_0 + 2: pci_0000_43_00_0 + 3: pci_0000_44_00_0 + 4: pci_0000_45_00_0 copper: - 1: pci_0000_c4_00_0 - 2: pci_0000_c4_00_1 - 3: pci_0000_c4_00_2 - 4: pci_0000_c4_00_3 + sfp: + 1: pci_0000_02_00_0 + 2: pci_0000_02_00_1 + 3: pci_0000_41_00_0 + 4: pci_0000_41_00_1 + SOSSNNV-DE02: + cpu: 128 + memory: 384 + disk: + 1: pci_0000_41_00_0 + 2: pci_0000_42_00_0 + 3: pci_0000_81_00_0 + 4: pci_0000_82_00_0 + 5: pci_0000_83_00_0 + 6: pci_0000_84_00_0 + copper: + 1: pci_0000_85_00_0 + 2: pci_0000_85_00_1 + 3: pci_0000_85_00_2 + 4: pci_0000_85_00_3 + sfp: + 5: pci_0000_c4_00_0 + 6: pci_0000_c4_00_1 + 7: pci_0000_c5_00_0 + 8: pci_0000_c5_00_1 + 9: pci_0000_c5_00_2 + 10: pci_0000_c5_00_3 + SOSSN7200: + cpu: 128 + memory: 256 + copper: + 1: pci_0000_03_00_0 + 2: pci_0000_03_00_1 + 3: pci_0000_03_00_2 + 4: pci_0000_03_00_3 sfp: 5: pci_0000_02_00_0 6: pci_0000_02_00_1 - 7: pci_0000_41_00_0 - 8: pci_0000_41_00_1 - model2: - cpu: 256 - memory: 256 - disk: - 1: pci_0000_c7_00_0 - 2: pci_0000_c8_00_0 - 3: pci_0000_c9_00_0 - 4: pci_0000_c10_00_0 + 7: pci_0000_81_00_0 + 8: pci_0000_81_00_1 + 9: pci_0000_81_00_2 + 10: pci_0000_81_00_3 + SOSSN7200-DE02: + cpu: 128 + memory: 384 copper: - 1: pci_0000_c4_00_0 - 2: pci_0000_c4_00_1 - 3: pci_0000_c4_00_2 - 4: pci_0000_c4_00_3 - 5: pci_0000_c5_00_0 - 6: pci_0000_c5_00_1 - 7: pci_0000_c5_00_2 - 8: pci_0000_c5_00_3 + 1: pci_0000_82_00_0 + 2: pci_0000_82_00_1 + 3: pci_0000_82_00_2 + 4: pci_0000_82_00_3 sfp: - 9: pci_0000_02_00_0 - 10: pci_0000_02_00_1 - 11: pci_0000_41_00_0 - 12: pci_0000_41_00_1 \ No newline at end of file + 5: pci_0000_c4_00_0 + 6: pci_0000_c4_00_1 + 7: pci_0000_c5_00_0 + 8: pci_0000_c5_00_1 + 9: pci_0000_c6_00_0 + 10: pci_0000_c6_00_1 + 11: pci_0000_c6_00_2 + 12: pci_0000_c6_00_3 + SOS4000: + cpu: 128 + memory: 256 + copper: + 1: pci_0000_03_00_0 + 2: pci_0000_03_00_1 + 3: pci_0000_03_00_2 + 4: pci_0000_03_00_3 + sfp: + 5: pci_0000_02_00_0 + 6: pci_0000_02_00_1 + 7: pci_0000_81_00_0 + 8: pci_0000_81_00_1 + 9: pci_0000_81_00_2 + 10: pci_0000_81_00_3 + SOS5000-DE02: + cpu: 128 + memory: 384 + copper: + 1: pci_0000_82_00_0 + 2: pci_0000_82_00_1 + 3: pci_0000_82_00_2 + 4: pci_0000_82_00_3 + sfp: + 5: pci_0000_c4_00_0 + 6: pci_0000_c4_00_1 + 7: pci_0000_c5_00_0 + 8: pci_0000_c5_00_1 + 9: pci_0000_c6_00_0 + 10: pci_0000_c6_00_1 + 11: pci_0000_c6_00_2 + 12: pci_0000_c6_00_3 From a3fb2f13be3848c906f53511c2c73fc41c4a8ef7 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Wed, 16 Jul 2025 14:14:16 -0400 Subject: [PATCH 263/315] dont show state changes for user-data --- salt/libvirt/images/init.sls | 1 + 1 file changed, 1 insertion(+) diff --git a/salt/libvirt/images/init.sls b/salt/libvirt/images/init.sls index b6a5baf04..21ab0553d 100644 --- a/salt/libvirt/images/init.sls +++ b/salt/libvirt/images/init.sls @@ -48,6 +48,7 @@ manage_userdata_sool9: file.managed: - name: /nsm/libvirt/images/sool9/user-data - source: salt://libvirt/images/sool9/user-data + - show_changes: False # Manage qcow2 image manage_qcow2_sool9: From 1aa876f4ebe601790acebc75d22e38b64e19bb4b Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Wed, 16 Jul 2025 14:20:55 -0400 Subject: [PATCH 264/315] add missing hardware key --- salt/hypervisor/defaults.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/salt/hypervisor/defaults.yaml b/salt/hypervisor/defaults.yaml index 8cf754193..938fa8bb2 100644 --- a/salt/hypervisor/defaults.yaml +++ b/salt/hypervisor/defaults.yaml @@ -33,6 +33,7 @@ hypervisor: 3: pci_0000_41_00_0 4: pci_0000_41_00_1 SOSSNNV-DE02: + hardware: cpu: 128 memory: 384 disk: @@ -55,6 +56,7 @@ hypervisor: 9: pci_0000_c5_00_2 10: pci_0000_c5_00_3 SOSSN7200: + hardware: cpu: 128 memory: 256 copper: @@ -70,6 +72,7 @@ hypervisor: 9: pci_0000_81_00_2 10: pci_0000_81_00_3 SOSSN7200-DE02: + hardware: cpu: 128 memory: 384 copper: @@ -87,6 +90,7 @@ hypervisor: 11: pci_0000_c6_00_2 12: pci_0000_c6_00_3 SOS4000: + hardware: cpu: 128 memory: 256 copper: @@ -102,6 +106,7 @@ hypervisor: 9: pci_0000_81_00_2 10: pci_0000_81_00_3 SOS5000-DE02: + hardware: cpu: 128 memory: 384 copper: From e61e2f04b3e645645f05ce2b6c3ff1a5a5374479 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Wed, 16 Jul 2025 15:24:43 -0400 Subject: [PATCH 265/315] handle hw not having sfp,disk or copper. show none for total if that is the case --- .../hypervisor/soc_hypervisor.yaml.jinja | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja b/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja index 4222ff6b2..07577a1fb 100644 --- a/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja +++ b/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja @@ -22,7 +22,7 @@ | | CPU Cores | Memory (GB) | Disk | Copper | SFP | |-----------|-----------|-------------|-------------|-------------|-------------| | Available | {{ cpu_free }} | {{ mem_free }} | {{ disk_free | replace('\n', ',') if disk_free else 'None' }} | {{ copper_free | replace('\n', ',') if copper_free else 'None' }} | {{ sfp_free | replace('\n', ',') if sfp_free else 'None' }} | -| Total | {{ cpu_total }} | {{ mem_total }} | {{ disk_total | replace('\n', ',') }} | {{ copper_total | replace('\n', ',') }} | {{ sfp_total | replace('\n', ',') }} | +| Total | {{ cpu_total }} | {{ mem_total }} | {{ disk_total | replace('\n', ',') if disk_total else 'None' }} | {{ copper_total | replace('\n', ',') if copper_total else 'None' }} | {{ sfp_total | replace('\n', ',') if sfp_total else 'None' }} | {%- if baseDomainStatus == 'Initialized' %} {%- if vm_list %} @@ -60,7 +60,8 @@ Base domain has not been initialized. {%- macro get_available_pci(hw_config, device_type, used_indices) -%} {%- set available = [] -%} -{%- for idx in hw_config.get(device_type, {}).keys() -%} +{%- set device_config = hw_config.get(device_type, {}) or {} -%} +{%- for idx in device_config.keys() -%} {%- if idx | string not in used_indices -%} {%- do available.append(idx) -%} {%- endif -%} @@ -155,9 +156,9 @@ Base domain has not been initialized. {# Get total resources #} {%- set cpu_total = hw_config.cpu -%} {%- set mem_total = hw_config.memory -%} -{%- set disk_total = hw_config.disk.keys() | join('\n') -%} -{%- set copper_total = hw_config.copper.keys() | join('\n') -%} -{%- set sfp_total = hw_config.sfp.keys() | join('\n') -%} +{%- set disk_total = (hw_config.get('disk', {}) or {}).keys() | join('\n') if hw_config.get('disk', {}) else '' -%} +{%- set copper_total = (hw_config.get('copper', {}) or {}).keys() | join('\n') if hw_config.get('copper', {}) else '' -%} +{%- set sfp_total = (hw_config.get('sfp', {}) or {}).keys() | join('\n') if hw_config.get('sfp', {}) else '' -%} {# Update field labels with total and free values #} {%- set updated_template = TEMPLATE.copy() -%} @@ -170,20 +171,26 @@ Base domain has not been initialized. {%- do update_resource_field(updated_field, mem_free, mem_total, 'GB') -%} {%- elif field.field == 'disk' -%} {%- set disk_free_list = disk_free.split(',') if disk_free else [] -%} +{%- set disk_free_safe = disk_free if disk_free is defined else '' -%} +{%- set disk_total_safe = disk_total if disk_total is defined else '' -%} {%- do updated_field.update({ - 'label': field.label | replace('FREE', disk_free) | replace('TOTAL', disk_total | replace('\n', ',')), + 'label': field.label | replace('FREE', disk_free_safe) | replace('TOTAL', disk_total_safe | replace('\n', ',')), 'options': disk_free_list }) -%} {%- elif field.field == 'copper' -%} {%- set copper_free_list = copper_free.split(',') if copper_free else [] -%} +{%- set copper_free_safe = copper_free if copper_free is defined else '' -%} +{%- set copper_total_safe = copper_total if copper_total is defined else '' -%} {%- do updated_field.update({ - 'label': field.label | replace('FREE', copper_free) | replace('TOTAL', copper_total | replace('\n', ',')), + 'label': field.label | replace('FREE', copper_free_safe) | replace('TOTAL', copper_total_safe | replace('\n', ',')), 'options': copper_free_list }) -%} {%- elif field.field == 'sfp' -%} {%- set sfp_free_list = sfp_free.split(',') if sfp_free else [] -%} +{%- set sfp_free_safe = sfp_free if sfp_free is defined else '' -%} +{%- set sfp_total_safe = sfp_total if sfp_total is defined else '' -%} {%- do updated_field.update({ - 'label': field.label | replace('FREE', sfp_free) | replace('TOTAL', sfp_total | replace('\n', ',')), + 'label': field.label | replace('FREE', sfp_free_safe) | replace('TOTAL', sfp_total_safe | replace('\n', ',')), 'options': sfp_free_list }) -%} {%- endif -%} From b3eb06f53e839ac9792d842836a21706e8e42ff8 Mon Sep 17 00:00:00 2001 From: reyesj2 <94730068+reyesj2@users.noreply.github.com> Date: Wed, 16 Jul 2025 15:56:34 -0500 Subject: [PATCH 266/315] ja4 Signed-off-by: reyesj2 <94730068+reyesj2@users.noreply.github.com> --- salt/elasticsearch/defaults.yaml | 5 ++ salt/elasticsearch/files/ingest/zeek.conn | 4 ++ salt/elasticsearch/files/ingest/zeek.http | 1 + salt/elasticsearch/files/ingest/zeek.http2 | 1 + salt/elasticsearch/files/ingest/zeek.ja4ssh | 10 +++ salt/elasticsearch/files/ingest/zeek.ssl | 2 + salt/elasticsearch/files/ingest/zeek.x509 | 1 + .../templates/component/ecs/hash.json | 69 +++++++++++++++++++ 8 files changed, 93 insertions(+) create mode 100644 salt/elasticsearch/files/ingest/zeek.ja4ssh create mode 100644 salt/elasticsearch/templates/component/ecs/hash.json diff --git a/salt/elasticsearch/defaults.yaml b/salt/elasticsearch/defaults.yaml index 73c29c8c6..4046cf146 100644 --- a/salt/elasticsearch/defaults.yaml +++ b/salt/elasticsearch/defaults.yaml @@ -567,6 +567,7 @@ elasticsearch: - common-settings - common-dynamic-mappings - winlog-mappings + - hash-mappings data_stream: {} ignore_missing_component_templates: [] index_patterns: @@ -3874,6 +3875,7 @@ elasticsearch: - vulnerability-mappings - common-settings - common-dynamic-mappings + - hash-mappings data_stream: {} ignore_missing_component_templates: [] index_patterns: @@ -3987,6 +3989,7 @@ elasticsearch: - vulnerability-mappings - common-settings - common-dynamic-mappings + - hash-mappings data_stream: {} ignore_missing_component_templates: [] index_patterns: @@ -4100,6 +4103,7 @@ elasticsearch: - vulnerability-mappings - common-settings - common-dynamic-mappings + - hash-mappings data_stream: {} ignore_missing_component_templates: [] index_patterns: @@ -4329,6 +4333,7 @@ elasticsearch: - zeek-mappings - common-settings - common-dynamic-mappings + - hash-mappings data_stream: {} ignore_missing_component_templates: [] index_patterns: diff --git a/salt/elasticsearch/files/ingest/zeek.conn b/salt/elasticsearch/files/ingest/zeek.conn index 6051d93a1..fe3d3b832 100644 --- a/salt/elasticsearch/files/ingest/zeek.conn +++ b/salt/elasticsearch/files/ingest/zeek.conn @@ -24,6 +24,10 @@ { "rename": { "field": "message2.resp_cc", "target_field": "server.country_code", "ignore_missing": true } }, { "rename": { "field": "message2.sensorname", "target_field": "observer.name", "ignore_missing": true } }, { "rename": { "field": "message2.vlan", "target_field": "network.vlan.id", "ignore_missing": true } }, + { "rename": { "field": "message2.ja4l", "target_field": "hash.ja4l", "ignore_missing" : true }}, + { "rename": { "field": "message2.ja4ls", "target_field": "hash.ja4ls", "ignore_missing" : true }}, + { "rename": { "field": "message2.ja4t", "target_field": "hash.ja4t", "ignore_missing" : true }}, + { "rename": { "field": "message2.ja4ts", "target_field": "hash.ja4ts", "ignore_missing" : true }}, { "script": { "lang": "painless", "source": "ctx.network.bytes = (ctx.client.bytes + ctx.server.bytes)", "ignore_failure": true } }, { "set": { "if": "ctx.connection?.state == 'S0'", "field": "connection.state_description", "value": "Connection attempt seen, no reply" } }, { "set": { "if": "ctx.connection?.state == 'S1'", "field": "connection.state_description", "value": "Connection established, not terminated" } }, diff --git a/salt/elasticsearch/files/ingest/zeek.http b/salt/elasticsearch/files/ingest/zeek.http index 2224da2f7..8b2a320f9 100644 --- a/salt/elasticsearch/files/ingest/zeek.http +++ b/salt/elasticsearch/files/ingest/zeek.http @@ -27,6 +27,7 @@ { "rename": { "field": "message2.resp_fuids", "target_field": "log.id.resp_fuids", "ignore_missing": true } }, { "rename": { "field": "message2.resp_filenames", "target_field": "file.resp_filenames", "ignore_missing": true } }, { "rename": { "field": "message2.resp_mime_types", "target_field": "file.resp_mime_types", "ignore_missing": true } }, + { "rename": { "field": "message2.ja4h", "target_field": "hash.ja4h", "ignore_missing": true } }, { "script": { "lang": "painless", "source": "ctx.uri_length = ctx.uri.length()", "ignore_failure": true } }, { "script": { "lang": "painless", "source": "ctx.useragent_length = ctx.useragent.length()", "ignore_failure": true } }, { "script": { "lang": "painless", "source": "ctx.virtual_host_length = ctx.virtual_host.length()", "ignore_failure": true } }, diff --git a/salt/elasticsearch/files/ingest/zeek.http2 b/salt/elasticsearch/files/ingest/zeek.http2 index eeeecef8c..e72259dda 100644 --- a/salt/elasticsearch/files/ingest/zeek.http2 +++ b/salt/elasticsearch/files/ingest/zeek.http2 @@ -27,6 +27,7 @@ { "rename": { "field": "message2.resp_filenames", "target_field": "file.resp_filenames", "ignore_missing": true } }, { "rename": { "field": "message2.resp_mime_types", "target_field": "file.resp_mime_types", "ignore_missing": true } }, { "rename": { "field": "message2.stream_id", "target_field": "http2.stream_id", "ignore_missing": true } }, + { "rename": { "field": "message2.ja4h", "target_field": "hash.ja4h", "ignore_missing": true } }, { "remove": { "field": "message2.tags", "ignore_failure": true } }, { "remove": { "field": ["host"], "ignore_failure": true } }, { "script": { "lang": "painless", "source": "ctx.uri_length = ctx.uri.length()", "ignore_failure": true } }, diff --git a/salt/elasticsearch/files/ingest/zeek.ja4ssh b/salt/elasticsearch/files/ingest/zeek.ja4ssh new file mode 100644 index 000000000..45a569792 --- /dev/null +++ b/salt/elasticsearch/files/ingest/zeek.ja4ssh @@ -0,0 +1,10 @@ +{ + "description": "zeek.ja4ssh", + "processors": [ + {"set": {"field": "event.dataset","value": "ja4ssh"}}, + {"remove": {"field": "host","ignore_missing": true,"ignore_failure": true}}, + {"json": {"field": "message","target_field": "message2","ignore_failure": true}}, + {"rename": {"field": "message2.ja4ssh", "target_field": "ja4.ja4ssh", "ignore_missing": true}}, + {"pipeline": {"name": "zeek.common"}} + ] +} \ No newline at end of file diff --git a/salt/elasticsearch/files/ingest/zeek.ssl b/salt/elasticsearch/files/ingest/zeek.ssl index 87174d3d2..c694ab333 100644 --- a/salt/elasticsearch/files/ingest/zeek.ssl +++ b/salt/elasticsearch/files/ingest/zeek.ssl @@ -23,6 +23,8 @@ { "rename": { "field": "message2.validation_status","target_field": "ssl.validation_status", "ignore_missing": true } }, { "rename": { "field": "message2.ja3", "target_field": "hash.ja3", "ignore_missing": true } }, { "rename": { "field": "message2.ja3s", "target_field": "hash.ja3s", "ignore_missing": true } }, + { "rename": { "field": "message2.ja4", "target_field": "hash.ja4", "ignore_missing": true } }, + { "rename": { "field": "message2.ja4s", "target_field": "hash.ja4s", "ignore_missing": true } }, { "foreach": { "if": "ctx?.tls?.client?.hash?.sha256 !=null", diff --git a/salt/elasticsearch/files/ingest/zeek.x509 b/salt/elasticsearch/files/ingest/zeek.x509 index 64d06131a..daec96245 100644 --- a/salt/elasticsearch/files/ingest/zeek.x509 +++ b/salt/elasticsearch/files/ingest/zeek.x509 @@ -42,6 +42,7 @@ { "dot_expander": { "field": "basic_constraints.path_length", "path": "message2", "ignore_failure": true } }, { "rename": { "field": "message2.basic_constraints.path_length", "target_field": "x509.basic_constraints.path_length", "ignore_missing": true } }, { "rename": { "field": "message2.fingerprint", "target_field": "hash.sha256", "ignore_missing": true } }, + { "rename": { "field": "message2.ja4x", "target_field": "hash.ja4x", "ignore_missing": true } }, { "pipeline": { "name": "zeek.common_ssl" } } ] } diff --git a/salt/elasticsearch/templates/component/ecs/hash.json b/salt/elasticsearch/templates/component/ecs/hash.json new file mode 100644 index 000000000..c9d1f5a5d --- /dev/null +++ b/salt/elasticsearch/templates/component/ecs/hash.json @@ -0,0 +1,69 @@ +{ + "template": { + "mappings": { + "properties": { + "hash": { + "type": "object", + "properties": { + "ja3": { + "type": "keyword", + "ignore_above": 1024 + }, + "ja3s": { + "type": "keyword", + "ignore_above": 1024 + }, + "hassh": { + "type": "keyword", + "ignore_above": 1024 + }, + "md5": { + "type": "keyword", + "ignore_above": 1024 + }, + "sha1": { + "type": "keyword", + "ignore_above": 1024 + }, + "sha256": { + "type": "keyword", + "ignore_above": 1024 + }, + "ja4": { + "type": "keyword", + "ignore_above": 1024 + }, + "ja4l": { + "type": "keyword", + "ignore_above": 1024 + }, + "ja4ls": { + "type": "keyword", + "ignore_above": 1024 + }, + "ja4t": { + "type": "keyword", + "ignore_above": 1024 + }, + "ja4ts": { + "type": "keyword", + "ignore_above": 1024 + }, + "ja4ssh": { + "type": "keyword", + "ignore_above": 1024 + }, + "ja4h": { + "type": "keyword", + "ignore_above": 1024 + }, + "ja4x": { + "type": "keyword", + "ignore_above": 1024 + } + } + } + } + } + } +} \ No newline at end of file From c29f11863e96b86540fae76386c5e5ec3b8fe7d4 Mon Sep 17 00:00:00 2001 From: reyesj2 <94730068+reyesj2@users.noreply.github.com> Date: Thu, 17 Jul 2025 10:47:00 -0500 Subject: [PATCH 267/315] ja4 ignore empty strings --- salt/elasticsearch/files/ingest/zeek.conn | 8 ++++---- salt/elasticsearch/files/ingest/zeek.http | 2 +- salt/elasticsearch/files/ingest/zeek.http2 | 2 +- salt/elasticsearch/files/ingest/zeek.ja4ssh | 2 +- salt/elasticsearch/files/ingest/zeek.ssl | 4 ++-- salt/elasticsearch/files/ingest/zeek.x509 | 2 +- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/salt/elasticsearch/files/ingest/zeek.conn b/salt/elasticsearch/files/ingest/zeek.conn index fe3d3b832..57558e863 100644 --- a/salt/elasticsearch/files/ingest/zeek.conn +++ b/salt/elasticsearch/files/ingest/zeek.conn @@ -24,10 +24,10 @@ { "rename": { "field": "message2.resp_cc", "target_field": "server.country_code", "ignore_missing": true } }, { "rename": { "field": "message2.sensorname", "target_field": "observer.name", "ignore_missing": true } }, { "rename": { "field": "message2.vlan", "target_field": "network.vlan.id", "ignore_missing": true } }, - { "rename": { "field": "message2.ja4l", "target_field": "hash.ja4l", "ignore_missing" : true }}, - { "rename": { "field": "message2.ja4ls", "target_field": "hash.ja4ls", "ignore_missing" : true }}, - { "rename": { "field": "message2.ja4t", "target_field": "hash.ja4t", "ignore_missing" : true }}, - { "rename": { "field": "message2.ja4ts", "target_field": "hash.ja4ts", "ignore_missing" : true }}, + { "rename": { "field": "message2.ja4l", "target_field": "hash.ja4l", "ignore_missing" : true, "if": "ctx.message2?.ja4l != null && ctx.message2.ja4l.length() > 0" }}, + { "rename": { "field": "message2.ja4ls", "target_field": "hash.ja4ls", "ignore_missing" : true, "if": "ctx.message2?.ja4ls != null && ctx.message2.ja4ls.length() > 0" }}, + { "rename": { "field": "message2.ja4t", "target_field": "hash.ja4t", "ignore_missing" : true, "if": "ctx.message2?.ja4t != null && ctx.message2.ja4t.length() > 0" }}, + { "rename": { "field": "message2.ja4ts", "target_field": "hash.ja4ts", "ignore_missing" : true, "if": "ctx.message2?.ja4ts != null && ctx.message2.ja4ts.length() > 0" }}, { "script": { "lang": "painless", "source": "ctx.network.bytes = (ctx.client.bytes + ctx.server.bytes)", "ignore_failure": true } }, { "set": { "if": "ctx.connection?.state == 'S0'", "field": "connection.state_description", "value": "Connection attempt seen, no reply" } }, { "set": { "if": "ctx.connection?.state == 'S1'", "field": "connection.state_description", "value": "Connection established, not terminated" } }, diff --git a/salt/elasticsearch/files/ingest/zeek.http b/salt/elasticsearch/files/ingest/zeek.http index 8b2a320f9..40642052a 100644 --- a/salt/elasticsearch/files/ingest/zeek.http +++ b/salt/elasticsearch/files/ingest/zeek.http @@ -27,7 +27,7 @@ { "rename": { "field": "message2.resp_fuids", "target_field": "log.id.resp_fuids", "ignore_missing": true } }, { "rename": { "field": "message2.resp_filenames", "target_field": "file.resp_filenames", "ignore_missing": true } }, { "rename": { "field": "message2.resp_mime_types", "target_field": "file.resp_mime_types", "ignore_missing": true } }, - { "rename": { "field": "message2.ja4h", "target_field": "hash.ja4h", "ignore_missing": true } }, + { "rename": { "field": "message2.ja4h", "target_field": "hash.ja4h", "ignore_missing": true, "if": "ctx?.message2?.ja4h != null && ctx.message2.ja4h.length() > 0" } }, { "script": { "lang": "painless", "source": "ctx.uri_length = ctx.uri.length()", "ignore_failure": true } }, { "script": { "lang": "painless", "source": "ctx.useragent_length = ctx.useragent.length()", "ignore_failure": true } }, { "script": { "lang": "painless", "source": "ctx.virtual_host_length = ctx.virtual_host.length()", "ignore_failure": true } }, diff --git a/salt/elasticsearch/files/ingest/zeek.http2 b/salt/elasticsearch/files/ingest/zeek.http2 index e72259dda..34cce0f7b 100644 --- a/salt/elasticsearch/files/ingest/zeek.http2 +++ b/salt/elasticsearch/files/ingest/zeek.http2 @@ -27,7 +27,7 @@ { "rename": { "field": "message2.resp_filenames", "target_field": "file.resp_filenames", "ignore_missing": true } }, { "rename": { "field": "message2.resp_mime_types", "target_field": "file.resp_mime_types", "ignore_missing": true } }, { "rename": { "field": "message2.stream_id", "target_field": "http2.stream_id", "ignore_missing": true } }, - { "rename": { "field": "message2.ja4h", "target_field": "hash.ja4h", "ignore_missing": true } }, + { "rename": { "field": "message2.ja4h", "target_field": "hash.ja4h", "ignore_missing": true, "if": "ctx?.message2?.ja4h != null && ctx.message2.ja4h.length() > 0" } }, { "remove": { "field": "message2.tags", "ignore_failure": true } }, { "remove": { "field": ["host"], "ignore_failure": true } }, { "script": { "lang": "painless", "source": "ctx.uri_length = ctx.uri.length()", "ignore_failure": true } }, diff --git a/salt/elasticsearch/files/ingest/zeek.ja4ssh b/salt/elasticsearch/files/ingest/zeek.ja4ssh index 45a569792..5901e65f1 100644 --- a/salt/elasticsearch/files/ingest/zeek.ja4ssh +++ b/salt/elasticsearch/files/ingest/zeek.ja4ssh @@ -4,7 +4,7 @@ {"set": {"field": "event.dataset","value": "ja4ssh"}}, {"remove": {"field": "host","ignore_missing": true,"ignore_failure": true}}, {"json": {"field": "message","target_field": "message2","ignore_failure": true}}, - {"rename": {"field": "message2.ja4ssh", "target_field": "ja4.ja4ssh", "ignore_missing": true}}, + {"rename": {"field": "message2.ja4ssh", "target_field": "hash.ja4ssh", "ignore_missing": true, "if": "ctx?.message2?.ja4ssh != null && ctx.message2.ja4ssh.length() > 0" }}, {"pipeline": {"name": "zeek.common"}} ] } \ No newline at end of file diff --git a/salt/elasticsearch/files/ingest/zeek.ssl b/salt/elasticsearch/files/ingest/zeek.ssl index c694ab333..0bd6fedb2 100644 --- a/salt/elasticsearch/files/ingest/zeek.ssl +++ b/salt/elasticsearch/files/ingest/zeek.ssl @@ -23,8 +23,8 @@ { "rename": { "field": "message2.validation_status","target_field": "ssl.validation_status", "ignore_missing": true } }, { "rename": { "field": "message2.ja3", "target_field": "hash.ja3", "ignore_missing": true } }, { "rename": { "field": "message2.ja3s", "target_field": "hash.ja3s", "ignore_missing": true } }, - { "rename": { "field": "message2.ja4", "target_field": "hash.ja4", "ignore_missing": true } }, - { "rename": { "field": "message2.ja4s", "target_field": "hash.ja4s", "ignore_missing": true } }, + { "rename": { "field": "message2.ja4", "target_field": "hash.ja4", "ignore_missing": true, "if": "ctx?.message2?.ja4 != null && ctx.message2.ja4.length() > 0" } }, + { "rename": { "field": "message2.ja4s", "target_field": "hash.ja4s", "ignore_missing": true, "if": "ctx?.message2?.ja4s != null && ctx.message2.ja4s.length() > 0" } }, { "foreach": { "if": "ctx?.tls?.client?.hash?.sha256 !=null", diff --git a/salt/elasticsearch/files/ingest/zeek.x509 b/salt/elasticsearch/files/ingest/zeek.x509 index daec96245..b639cb417 100644 --- a/salt/elasticsearch/files/ingest/zeek.x509 +++ b/salt/elasticsearch/files/ingest/zeek.x509 @@ -42,7 +42,7 @@ { "dot_expander": { "field": "basic_constraints.path_length", "path": "message2", "ignore_failure": true } }, { "rename": { "field": "message2.basic_constraints.path_length", "target_field": "x509.basic_constraints.path_length", "ignore_missing": true } }, { "rename": { "field": "message2.fingerprint", "target_field": "hash.sha256", "ignore_missing": true } }, - { "rename": { "field": "message2.ja4x", "target_field": "hash.ja4x", "ignore_missing": true } }, + { "rename": { "field": "message2.ja4x", "target_field": "hash.ja4x", "ignore_missing": true, "if": "ctx?.message2?.ja4x != null && ctx.message2.ja4x.length() > 0" } }, { "pipeline": { "name": "zeek.common_ssl" } } ] } From 0b1f2252ee6c07964c9321ebf5379d641d292d8b Mon Sep 17 00:00:00 2001 From: reyesj2 <94730068+reyesj2@users.noreply.github.com> Date: Thu, 17 Jul 2025 13:27:54 -0500 Subject: [PATCH 268/315] elasticsearch troubleshoot script --- .../tools/sbin/so-elasticsearch-troubleshoot | 194 ++++++++++++++++++ 1 file changed, 194 insertions(+) create mode 100644 salt/elasticsearch/tools/sbin/so-elasticsearch-troubleshoot diff --git a/salt/elasticsearch/tools/sbin/so-elasticsearch-troubleshoot b/salt/elasticsearch/tools/sbin/so-elasticsearch-troubleshoot new file mode 100644 index 000000000..b6b201c3c --- /dev/null +++ b/salt/elasticsearch/tools/sbin/so-elasticsearch-troubleshoot @@ -0,0 +1,194 @@ +#!/bin/bash + +. /usr/sbin/so-common + +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +BOLD='\033[1;37m' +NC='\033[0m' + +log_title() { + if [ $1 == "LOG" ]; then + echo -e "\n${BOLD}================ $2 ================${NC}\n" + elif [ $1 == "OK" ]; then + echo -e "${GREEN} $2 ${NC}" + elif [ $1 == "WARN" ]; then + echo -e "${YELLOW} $2 ${NC}" + elif [ $1 == "ERROR" ]; then + echo -e "${RED} $2 ${NC}" + fi +} + +health_report() { + if ! health_report_output=$(so-elasticsearch-query _health_report?format=json --fail 2>/dev/null); then + log_title "ERROR" "Failed to retrieve health report from Elasticsearch" + return 1 + fi + non_green_count=$(echo "$health_report_output" | jq '[.indicators | to_entries[] | select(.value.status != "green")] | length') + + if [ "$non_green_count" -gt 0 ]; then + echo "$health_report_output" | jq -r '.indicators | to_entries[] | select(.value.status != "green") | .key' | while read -r indicator_name; do + indicator=$(echo "$health_report_output" | jq -r ".indicators.\"$indicator_name\"") + status=$(echo "$indicator" | jq -r '.status') + symptom=$(echo "$indicator" | jq -r '.symptom // "No symptom available"') + + # reormat indicator name + display_name=$(echo "$indicator_name" | tr '_' ' ' | sed 's/\b\(.\)/\u\1/g') + + if [ "$status" = "yellow" ]; then + log_title "WARN" "$display_name: $symptom" + else + log_title "ERROR" "$display_name: $symptom" + fi + + # diagnosis if available + echo "$indicator" | jq -c '.diagnosis[]? // empty' | while read -r diagnosis; do + cause=$(echo "$diagnosis" | jq -r '.cause // "Unknown"') + action=$(echo "$diagnosis" | jq -r '.action // "No action specified"') + + echo -e " ${BOLD}Cause:${NC} $cause\n" + echo -e " ${BOLD}Action:${NC} $action\n" + + # Check for affected indices + affected_indices=$(echo "$diagnosis" | jq -r '.affected_resources.indices[]? // empty') + if [ -n "$affected_indices" ]; then + echo -e " ${BOLD}Affected indices:${NC}" + total_indices=$(echo "$affected_indices" | wc -l) + echo "$affected_indices" | head -10 | while read -r index; do + echo " - $index" + done + if [ "$total_indices" -gt 10 ]; then + remaining=$((total_indices - 10)) + echo " ... and $remaining more indices (truncated for readability)" + fi + fi + echo + done + done + else + log_title "OK" "All health indicators are green" + fi +} + +elasticsearch_status() { + log_title "LOG" "Elasticsearch Status" + if so-elasticsearch-query / --fail --output /dev/null; then + health_report + else + log_title "ERROR" "Elasticsearch API is not accessible" + so-status + log_title "ERROR" "Make sure Elasticsearch is running. Addtionally, check for startup errors in /opt/so/log/elasticsearch/securityonion.log${NC}\n" + + exit 1 + fi + +} + +indices_by_age() { + log_title "LOG" "Indices by Creation Date - Size > 1KB" + log_title "WARN" "Since high/flood watermark has been reached consider updating ILM policies.\n" + if ! indices_output=$(so-elasticsearch-query '_cat/indices?v&s=creation.date:asc&h=creation.date.string,index,status,health,docs.count,pri.store.size&bytes=b&format=json' --fail 2>/dev/null); then + log_title "ERROR" "Failed to retrieve indices list from Elasticsearch" + return 1 + fi + + # Filter for indices with size > 1KB (1024 bytes) and format output + echo -e "${BOLD}Creation Date Name Size${NC}" + echo -e "${BOLD}--------------------------------------------------------------------------------------------------------------${NC}" + + # Create list of indices excluding .internal, so-detection*, so-case* + echo "$indices_output" | jq -r '.[] | select((."pri.store.size" | tonumber) > 1024) | select(.index | (startswith(".internal") or startswith("so-detection") or startswith("so-case")) | not ) | "\(."creation.date.string") | \(.index) | \(."pri.store.size")"' | while IFS='|' read -r creation_date index_name size_bytes; do + # Convert bytes to GB / MB + if [ "$size_bytes" -gt 1073741824 ]; then + size_human=$(echo "scale=2; $size_bytes / 1073741824" | bc)GB + else + size_human=$(echo "scale=2; $size_bytes / 1048576" | bc)MB + fi + + creation_date=$(date -d "$creation_date" '+%Y-%m-%dT%H:%MZ' ) + + # Format output with spacing + printf "%-19s %-76s %10s\n" "$creation_date" "$index_name" "$size_human" + done +} + +watermark_settings() { + watermark_path=".defaults.cluster.routing.allocation.disk.watermark" + if ! watermark_output=$(so-elasticsearch-query _cluster/settings?include_defaults=true\&filter_path=*.cluster.routing.allocation.disk.* --fail 2>/dev/null); then + log_title "ERROR" "Failed to retrieve watermark settings from Elasticsearch" + return 1 + fi + + if ! disk_allocation_output=$(so-elasticsearch-query _cat/nodes?v\&h=name,ip,disk.used_percent,disk.avail,disk.total\&format=json --fail 2>/dev/null); then + log_title "ERROR" "Failed to retrieve disk allocation data from Elasticsearch" + return 1 + fi + + flood=$(echo $watermark_output | jq -r "$watermark_path.flood_stage" ) + high=$(echo $watermark_output | jq -r "$watermark_path.high" ) + low=$(echo $watermark_output | jq -r "$watermark_path.low" ) + + # Strip percentage signs for comparison + flood_num=${flood%\%} + high_num=${high%\%} + low_num=${low%\%} + + # Check each nodes disk usage + log_title "LOG" "Disk Usage Check" + echo -e "${BOLD}LOW:${GREEN}$low${NC}${BOLD} HIGH:${YELLOW}${high}${NC}${BOLD} FLOOD:${RED}${flood}${NC}\n" + + echo "$disk_allocation_output" | jq -r '.[] | "\(.name)|\(.["disk.used_percent"])"' | while IFS='|' read -r node_name disk_used; do + disk_used_num=$(echo $disk_used | bc) + + if (( $(echo "$disk_used_num >= $flood_num" | bc -l) )); then + log_title "ERROR" "$node_name is at or above the flood watermark ($flood)! Disk usage: ${disk_used}%" + touch /tmp/watermark_reached + elif (( $(echo "$disk_used_num >= $high_num" | bc -l) )); then + log_title "ERROR" "$node_name is at or above the high watermark ($high)! Disk usage: ${disk_used}%" + touch /tmp/watermark_reached + else + log_title "OK" "$node_name disk usage: ${disk_used}%" + fi + done + + # Check if we need to show indices by age + if [ -f /tmp/watermark_reached ]; then + indices_by_age + rm -f /tmp/watermark_reached + fi + +} + +unassigned_shards() { + + if ! unassigned_shards_output=$(so-elasticsearch-query _cat/shards?v\&h=index,shard,prirep,state,unassigned.reason,unassigned.details\&s=state\&format=json --fail 2>/dev/null); then + log_title "ERROR" "Failed to retrieve shard data from Elasticsearch" + return 1 + fi + + log_title "LOG" "Unassigned Shards Check" + # Check if there are any UNASSIGNED shards + unassigned_count=$(echo "$unassigned_shards_output" | jq '[.[] | select(.state == "UNASSIGNED")] | length') + + if [ "$unassigned_count" -gt 0 ]; then + echo "$unassigned_shards_output" | jq -r '.[] | select(.state == "UNASSIGNED") | "\(.index)|\(.shard)|\(.prirep)|\(."unassigned.reason")"' | while IFS='|' read -r index shard prirep reason; do + if [ "$prirep" = "r" ]; then + log_title "WARN" "Replica shard for index $index is unassigned. Reason: $reason" + elif [ "$prirep" = "p" ]; then + log_title "ERROR" "Primary shard for index $index is unassigned. Reason: $reason" + fi + done + else + log_title "OK" "All shards are assigned" + fi +} + +main() { + elasticsearch_status + watermark_settings + unassigned_shards +} + +main From f27714890a08a9a16ad24deedab6945c157571a3 Mon Sep 17 00:00:00 2001 From: reyesj2 <94730068+reyesj2@users.noreply.github.com> Date: Fri, 18 Jul 2025 09:35:51 -0500 Subject: [PATCH 269/315] update file ownership to socore --- salt/idh/config.sls | 2 +- salt/idstools/config.sls | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/salt/idh/config.sls b/salt/idh/config.sls index 91f809f9e..2e6315007 100644 --- a/salt/idh/config.sls +++ b/salt/idh/config.sls @@ -86,7 +86,7 @@ idh_sbin: file.recurse: - name: /usr/sbin - source: salt://idh/tools/sbin - - user: 934 + - user: 939 - group: 939 - file_mode: 755 diff --git a/salt/idstools/config.sls b/salt/idstools/config.sls index a44b02807..cea75ab9a 100644 --- a/salt/idstools/config.sls +++ b/salt/idstools/config.sls @@ -20,7 +20,7 @@ idstools_sbin: file.recurse: - name: /usr/sbin - source: salt://idstools/tools/sbin - - user: 934 + - user: 939 - group: 939 - file_mode: 755 @@ -29,7 +29,7 @@ idstools_sbin: # file.recurse: # - name: /usr/sbin # - source: salt://idstools/tools/sbin_jinja -# - user: 934 +# - user: 939 # - group: 939 # - file_mode: 755 # - template: jinja @@ -38,7 +38,7 @@ idstools_so-rule-update: file.managed: - name: /usr/sbin/so-rule-update - source: salt://idstools/tools/sbin_jinja/so-rule-update - - user: 934 + - user: 939 - group: 939 - mode: 755 - template: jinja From 246161018cb7a63d30af8ff258b8f9de0786fec5 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Fri, 18 Jul 2025 14:17:38 -0400 Subject: [PATCH 270/315] upgrade and start salt process change --- salt/salt/minion.sls | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/salt/salt/minion.sls b/salt/salt/minion.sls index 3ae7ded9a..4dfa54391 100644 --- a/salt/salt/minion.sls +++ b/salt/salt/minion.sls @@ -38,25 +38,33 @@ unhold_salt_packages: {% endfor %} install_salt_minion: + cmd.run: + - name: /bin/sh -c '{{ UPGRADECOMMAND }}' + +# minion service is in failed state after upgrade. this command will start it after the state run for the upgrade completes +start_minion: cmd.run: - name: | exec 0>&- # close stdin exec 1>&- # close stdout exec 2>&- # close stderr - nohup /bin/sh -c '{{ UPGRADECOMMAND }}' & + nohup /bin/sh -c 'sleep 30; systemctl start salt-minion' & + - require: + - cmd: install_salt_minion + - watch: + - cmd: install_salt_minion + - order: last {% endif %} {% if INSTALLEDSALTVERSION|string == SALTVERSION|string %} -# only hold the package if it is already installed + hold_salt_packages: pkg.held: - pkgs: -{% for package in SALTPACKAGES %} -{% if salt['pkg.version'](package) %} +{% for package in SALTPACKAGES %} - {{ package }}: {{SALTVERSION}}-0.* -{% endif %} -{% endfor %} +{% endfor %} remove_error_log_level_logfile: file.line: From 05a368681a6d76f085357fe37de3a5635d4a8e06 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Mon, 21 Jul 2025 10:53:54 -0400 Subject: [PATCH 271/315] Create config.zeek.ja4 --- salt/zeek/files/config.zeek.ja4 | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 salt/zeek/files/config.zeek.ja4 diff --git a/salt/zeek/files/config.zeek.ja4 b/salt/zeek/files/config.zeek.ja4 new file mode 100644 index 000000000..e3dd08a48 --- /dev/null +++ b/salt/zeek/files/config.zeek.ja4 @@ -0,0 +1,25 @@ +module FINGERPRINT; + +export { + option delimiter: string = "_"; + + # BSD licensed + option JA4_enabled: bool = T; + option JA4_raw: bool = F; + + # FoxIO license required for JA4+ + option JA4S_enabled: bool = F; + option JA4S_raw: bool = F; + + option JA4H_enabled: bool = F; + option JA4H_raw: bool = F; + + option JA4L_enabled: bool = F; + + option JA4SSH_enabled: bool = F; + + option JA4T_enabled: bool = F; + option JA4TS_enabled: bool = F; + + option JA4X_enabled: bool = F; +} From 93024738d31715f9b613520e9adbc0d7b1d4d262 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Mon, 21 Jul 2025 10:57:45 -0400 Subject: [PATCH 272/315] Update config.sls --- salt/zeek/config.sls | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/salt/zeek/config.sls b/salt/zeek/config.sls index 7fdbd8560..761c6f7d3 100644 --- a/salt/zeek/config.sls +++ b/salt/zeek/config.sls @@ -150,6 +150,13 @@ plcronscript: - source: salt://zeek/cron/packetloss.sh - mode: 755 +zeekja4cfg: + file.managed: + - name: /opt/so/conf/zeek/config.zeek + - source: salt://zeek/files/config.zeek.ja4 + - user: 937 + - group: 939 + # BPF compilation and configuration {% if ZEEKBPF %} {% set BPF_CALC = salt['cmd.script']('salt://common/tools/sbin/so-bpf-compile', GLOBALS.sensor.interface + ' ' + ZEEKBPF|join(" "),cwd='/root') %} From 5dac3ff2a672fde5d7faaef2774bcf4d489bfeea Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Mon, 21 Jul 2025 10:58:25 -0400 Subject: [PATCH 273/315] Update enabled.sls --- salt/zeek/enabled.sls | 1 + 1 file changed, 1 insertion(+) diff --git a/salt/zeek/enabled.sls b/salt/zeek/enabled.sls index 7d444ff43..ff090428f 100644 --- a/salt/zeek/enabled.sls +++ b/salt/zeek/enabled.sls @@ -34,6 +34,7 @@ so-zeek: - /opt/so/conf/zeek/policy/cve-2020-0601:/opt/zeek/share/zeek/policy/cve-2020-0601:ro - /opt/so/conf/zeek/policy/intel:/opt/zeek/share/zeek/policy/intel:rw - /opt/so/conf/zeek/bpf:/opt/zeek/etc/bpf:ro + - /opt/so/conf/zeek/config.zeek:/opt/zeek/share/zeek/site/packages/ja4/config.zeek:ro {% if DOCKER.containers['so-zeek'].custom_bind_mounts %} {% for BIND in DOCKER.containers['so-zeek'].custom_bind_mounts %} - {{ BIND }} From eabca5df1897c9330e641bf71d4854430e2497b8 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Mon, 21 Jul 2025 11:01:33 -0400 Subject: [PATCH 274/315] Update defaults.yaml --- salt/zeek/defaults.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/salt/zeek/defaults.yaml b/salt/zeek/defaults.yaml index 1daf77102..d87a67ac6 100644 --- a/salt/zeek/defaults.yaml +++ b/salt/zeek/defaults.yaml @@ -52,6 +52,7 @@ zeek: - policy/frameworks/notice/community-id - policy/protocols/conn/community-id-logging - ja3 + - ja4 - hassh - intel - cve-2020-0601 From beda0bc89ce04d6a6f18cf76b47592e01ec836a8 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Mon, 21 Jul 2025 15:40:36 -0400 Subject: [PATCH 275/315] new state name. no longer need to close stdin, stderr stdout --- salt/salt/minion.sls | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/salt/salt/minion.sls b/salt/salt/minion.sls index 4dfa54391..ba1613b82 100644 --- a/salt/salt/minion.sls +++ b/salt/salt/minion.sls @@ -42,13 +42,9 @@ install_salt_minion: - name: /bin/sh -c '{{ UPGRADECOMMAND }}' # minion service is in failed state after upgrade. this command will start it after the state run for the upgrade completes -start_minion: +start_minion_post_upgrade: cmd.run: - - name: | - exec 0>&- # close stdin - exec 1>&- # close stdout - exec 2>&- # close stderr - nohup /bin/sh -c 'sleep 30; systemctl start salt-minion' & + - name: nohup /bin/sh -c 'sleep 30; systemctl start salt-minion' & - require: - cmd: install_salt_minion - watch: From 442aecb9f47adbc1e792d258642997ce8c221f38 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Tue, 22 Jul 2025 10:30:59 -0400 Subject: [PATCH 276/315] bootstrap dont start daemon, use state to start it --- salt/salt/map.jinja | 4 ++-- salt/salt/minion.sls | 6 +++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/salt/salt/map.jinja b/salt/salt/map.jinja index 55b3a7ffb..1e3b200f4 100644 --- a/salt/salt/map.jinja +++ b/salt/salt/map.jinja @@ -26,9 +26,9 @@ {% if INSTALLEDSALTVERSION != SALTVERSION %} {% if grains.os_family|lower == 'redhat' %} - {% set UPGRADECOMMAND = 'yum clean all ; /usr/sbin/bootstrap-salt.sh -s 120 -r -F stable ' ~ SALTVERSION %} + {% set UPGRADECOMMAND = 'yum clean all ; /usr/sbin/bootstrap-salt.sh -X -r -F stable ' ~ SALTVERSION %} {% elif grains.os_family|lower == 'debian' %} - {% set UPGRADECOMMAND = '/usr/sbin/bootstrap-salt.sh -s 120 -F stable ' ~ SALTVERSION %} + {% set UPGRADECOMMAND = '/usr/sbin/bootstrap-salt.sh -X -F stable ' ~ SALTVERSION %} {% endif %} {% else %} {% set UPGRADECOMMAND = 'echo Already running Salt Minion version ' ~ SALTVERSION %} diff --git a/salt/salt/minion.sls b/salt/salt/minion.sls index ba1613b82..8736f4eb2 100644 --- a/salt/salt/minion.sls +++ b/salt/salt/minion.sls @@ -44,7 +44,11 @@ install_salt_minion: # minion service is in failed state after upgrade. this command will start it after the state run for the upgrade completes start_minion_post_upgrade: cmd.run: - - name: nohup /bin/sh -c 'sleep 30; systemctl start salt-minion' & + - name: | + exec 0>&- # close stdin + exec 1>&- # close stdout + exec 2>&- # close stderr + nohup /bin/sh -c 'sleep 30; systemctl start salt-minion' & - require: - cmd: install_salt_minion - watch: From 669d219fdc6e30eeddd648d676119b5edeb1ac48 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Tue, 22 Jul 2025 11:52:50 -0400 Subject: [PATCH 277/315] splay highstate schedule 2minutes for non managers --- salt/schedule.sls | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/salt/schedule.sls b/salt/schedule.sls index 74c9acb56..c3b5d85ae 100644 --- a/salt/schedule.sls +++ b/salt/schedule.sls @@ -1,5 +1,10 @@ +{% from 'vars/globals.map.jinja' import GLOBALS %} + highstate_schedule: schedule.present: - function: state.highstate - minutes: 15 - maxrunning: 1 +{% if not GLOBALS.is_manager %} + - splay: 120 +{% endif %} From af49a8e4ef72f4b9a6c9bfa376c14bddc71e151d Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Tue, 22 Jul 2025 13:22:50 -0400 Subject: [PATCH 278/315] add back comment --- salt/salt/minion.sls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/salt/minion.sls b/salt/salt/minion.sls index 8736f4eb2..b6db9d046 100644 --- a/salt/salt/minion.sls +++ b/salt/salt/minion.sls @@ -58,7 +58,7 @@ start_minion_post_upgrade: {% endif %} {% if INSTALLEDSALTVERSION|string == SALTVERSION|string %} - +# only hold the package if it is already installed hold_salt_packages: pkg.held: - pkgs: From 2a166af52400a4ce2e21c7fd0483c8858fff70aa Mon Sep 17 00:00:00 2001 From: Doug Burks Date: Tue, 22 Jul 2025 16:10:44 -0400 Subject: [PATCH 279/315] UPGRADE: Zeek Ethercat plugin #14783 --- salt/zeek/defaults.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/salt/zeek/defaults.yaml b/salt/zeek/defaults.yaml index d87a67ac6..81bfa3d9d 100644 --- a/salt/zeek/defaults.yaml +++ b/salt/zeek/defaults.yaml @@ -116,7 +116,6 @@ zeek: excluded: - broker - capture_loss - - ecat_arp_info - known_hosts - known_services - loaded_scripts From 4728b96c51991a888738e0c1f9162405e79401d9 Mon Sep 17 00:00:00 2001 From: reyesj2 <94730068+reyesj2@users.noreply.github.com> Date: Tue, 22 Jul 2025 16:16:28 -0500 Subject: [PATCH 280/315] add a retry to so-elastic-fleet-integration-upgrade when response isn't what was expected that way the error message isn't throwin into sosetup / soup log --- .../tools/sbin/so-elastic-fleet-common | 18 ++++++++++++++---- .../so-elastic-fleet-integration-upgrade | 16 ++++++++++++---- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/salt/elasticfleet/tools/sbin/so-elastic-fleet-common b/salt/elasticfleet/tools/sbin/so-elastic-fleet-common index d8d0bdb1e..9780c8b12 100644 --- a/salt/elasticfleet/tools/sbin/so-elastic-fleet-common +++ b/salt/elasticfleet/tools/sbin/so-elastic-fleet-common @@ -88,7 +88,13 @@ elastic_fleet_package_version_check() { elastic_fleet_package_latest_version_check() { PACKAGE=$1 - curl -s -K /opt/so/conf/elasticsearch/curl.config -b "sid=$SESSIONCOOKIE" -L -X GET "localhost:5601/api/fleet/epm/packages/$PACKAGE" | jq -r '.item.latestVersion' + if output=$(curl -s -K /opt/so/conf/elasticsearch/curl.config -b "sid=$SESSIONCOOKIE" -L -X GET "localhost:5601/api/fleet/epm/packages/$PACKAGE" --fail); then + if version=$(jq -e -r '.item.latestVersion' <<< $output); then + echo "$version" + fi + else + echo "Error: Failed to get latest version for $PACKAGE" + fi } elastic_fleet_package_install() { @@ -149,9 +155,13 @@ elastic_fleet_integration_policy_package_name() { elastic_fleet_integration_policy_package_version() { AGENT_POLICY=$1 INTEGRATION=$2 - curl -s -K /opt/so/conf/elasticsearch/curl.config -b "sid=$SESSIONCOOKIE" -L -X GET "localhost:5601/api/fleet/agent_policies/$AGENT_POLICY" | jq -r --arg INTEGRATION "$INTEGRATION" '.item.package_policies[] | select(.name==$INTEGRATION)| .package.version' - if [ $? -ne 0 ]; then - echo "Error: Failed to retrieve package version for '$INTEGRATION' in '$AGENT_POLICY'." + + if output=$(curl -s -K /opt/so/conf/elasticsearch/curl.config -L -X GET "localhost:5601/api/fleet/agent_policies/$AGENT_POLICY" --fail); then + if version=$(jq -e -r --arg INTEGRATION "$INTEGRATION" '.item.package_policies[] | select(.name==$INTEGRATION)| .package.version' <<< $output); then + echo "$version" + fi + else + echo "Error: Failed to retrieve agent policy $AGENT_POLICY" exit 1 fi } diff --git a/salt/elasticfleet/tools/sbin_jinja/so-elastic-fleet-integration-upgrade b/salt/elasticfleet/tools/sbin_jinja/so-elastic-fleet-integration-upgrade index 54540ba33..68a644798 100644 --- a/salt/elasticfleet/tools/sbin_jinja/so-elastic-fleet-integration-upgrade +++ b/salt/elasticfleet/tools/sbin_jinja/so-elastic-fleet-integration-upgrade @@ -34,10 +34,18 @@ for AGENT_POLICY in $agent_policies; do if [[ " ${default_packages[@]} " =~ " $PACKAGE_NAME " ]]; then {%- endif %} # Get currently installed version of package - PACKAGE_VERSION=$(elastic_fleet_integration_policy_package_version "$AGENT_POLICY" "$INTEGRATION") - - # Get latest available version of package - AVAILABLE_VERSION=$(elastic_fleet_package_latest_version_check "$PACKAGE_NAME") + attempt=0 + max_attempts=3 + while [ $attempt -lt $max_attempts ]; do + if PACKAGE_VERSION=$(elastic_fleet_integration_policy_package_version "$AGENT_POLICY" "$INTEGRATION") && AVAILABLE_VERSION=$(elastic_fleet_package_latest_version_check "$PACKAGE_NAME"); then + break + fi + attempt=$((attempt + 1)) + done + if [ $attempt -eq $max_attempts ]; then + echo "Error: Failed getting $PACKAGE_VERSION or $AVAILABLE_VERSION" + exit 1 + fi # Get integration ID INTEGRATION_ID=$(elastic_fleet_integration_id "$AGENT_POLICY" "$INTEGRATION") From 3fc244ee854297e09138954d7a5cf661bd2442e9 Mon Sep 17 00:00:00 2001 From: reyesj2 <94730068+reyesj2@users.noreply.github.com> Date: Tue, 22 Jul 2025 16:56:51 -0500 Subject: [PATCH 281/315] 8.18.4 --- VERSION | 2 +- salt/elasticsearch/defaults.yaml | 2 +- salt/kibana/defaults.yaml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/VERSION b/VERSION index c3344819a..7d52aac7f 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.4.170 \ No newline at end of file +2.4.0-foxtrot diff --git a/salt/elasticsearch/defaults.yaml b/salt/elasticsearch/defaults.yaml index 4046cf146..e08978e0d 100644 --- a/salt/elasticsearch/defaults.yaml +++ b/salt/elasticsearch/defaults.yaml @@ -1,6 +1,6 @@ elasticsearch: enabled: false - version: 8.18.3 + version: 8.18.4 index_clean: true config: action: diff --git a/salt/kibana/defaults.yaml b/salt/kibana/defaults.yaml index a636f9b79..29d9b9bf6 100644 --- a/salt/kibana/defaults.yaml +++ b/salt/kibana/defaults.yaml @@ -22,7 +22,7 @@ kibana: - default - file migrations: - discardCorruptObjects: "8.18.3" + discardCorruptObjects: "8.18.4" telemetry: enabled: False security: From 56748ea6e76fcd83083498206fd9e473cf2ceb21 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Wed, 23 Jul 2025 10:16:12 -0400 Subject: [PATCH 282/315] add pack only holding package if installed. remove redundant hold on salt-master package --- salt/salt/master.sls | 5 ----- salt/salt/minion.sls | 13 ++++++++----- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/salt/salt/master.sls b/salt/salt/master.sls index fce702932..6486e9126 100644 --- a/salt/salt/master.sls +++ b/salt/salt/master.sls @@ -23,11 +23,6 @@ sync_runners: - name: saltutil.sync_runners {% endif %} -hold_salt_master_package: - module.run: - - pkg.hold: - - name: salt-master - # prior to 2.4.30 this engine ran on the manager with salt-minion # this has changed to running with the salt-master in 2.4.30 remove_engines_config: diff --git a/salt/salt/minion.sls b/salt/salt/minion.sls index b6db9d046..b0e078e79 100644 --- a/salt/salt/minion.sls +++ b/salt/salt/minion.sls @@ -58,12 +58,15 @@ start_minion_post_upgrade: {% endif %} {% if INSTALLEDSALTVERSION|string == SALTVERSION|string %} -# only hold the package if it is already installed -hold_salt_packages: - pkg.held: - - pkgs: + {% for package in SALTPACKAGES %} - - {{ package }}: {{SALTVERSION}}-0.* +# only hold the package if it is already installed +{% if salt['pkg.version'](package) %} +hold_{{ package }}_package: + pkg.held: + - name: {{ package }} + - version: {{SALTVERSION}}-0.* +{% endif %} {% endfor %} remove_error_log_level_logfile: From 2e5682f11c7412342999ebbb0cad1fc4f6ae6935 Mon Sep 17 00:00:00 2001 From: reyesj2 <94730068+reyesj2@users.noreply.github.com> Date: Wed, 23 Jul 2025 09:53:04 -0500 Subject: [PATCH 283/315] 8.18.4 import evtx pipelines --- .../files/integrations/grid-nodes_general/import-evtx-logs.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/elasticfleet/files/integrations/grid-nodes_general/import-evtx-logs.json b/salt/elasticfleet/files/integrations/grid-nodes_general/import-evtx-logs.json index 415e333e7..059e4b8cc 100644 --- a/salt/elasticfleet/files/integrations/grid-nodes_general/import-evtx-logs.json +++ b/salt/elasticfleet/files/integrations/grid-nodes_general/import-evtx-logs.json @@ -20,7 +20,7 @@ ], "data_stream.dataset": "import", "custom": "", - "processors": "- dissect:\n tokenizer: \"/nsm/import/%{import.id}/evtx/%{import.file}\"\n field: \"log.file.path\"\n target_prefix: \"\"\n- decode_json_fields:\n fields: [\"message\"]\n target: \"\"\n- drop_fields:\n fields: [\"host\"]\n ignore_missing: true\n- add_fields:\n target: data_stream\n fields:\n type: logs\n dataset: system.security\n- add_fields:\n target: event\n fields:\n dataset: system.security\n module: system\n imported: true\n- add_fields:\n target: \"@metadata\"\n fields:\n pipeline: logs-system.security-2.3.1\n- if:\n equals:\n winlog.channel: 'Microsoft-Windows-Sysmon/Operational'\n then: \n - add_fields:\n target: data_stream\n fields:\n dataset: windows.sysmon_operational\n - add_fields:\n target: event\n fields:\n dataset: windows.sysmon_operational\n module: windows\n imported: true\n - add_fields:\n target: \"@metadata\"\n fields:\n pipeline: logs-windows.sysmon_operational-3.0.0\n- if:\n equals:\n winlog.channel: 'Application'\n then: \n - add_fields:\n target: data_stream\n fields:\n dataset: system.application\n - add_fields:\n target: event\n fields:\n dataset: system.application\n - add_fields:\n target: \"@metadata\"\n fields:\n pipeline: logs-system.application-2.3.1\n- if:\n equals:\n winlog.channel: 'System'\n then: \n - add_fields:\n target: data_stream\n fields:\n dataset: system.system\n - add_fields:\n target: event\n fields:\n dataset: system.system\n - add_fields:\n target: \"@metadata\"\n fields:\n pipeline: logs-system.system-2.3.1\n \n- if:\n equals:\n winlog.channel: 'Microsoft-Windows-PowerShell/Operational'\n then: \n - add_fields:\n target: data_stream\n fields:\n dataset: windows.powershell_operational\n - add_fields:\n target: event\n fields:\n dataset: windows.powershell_operational\n module: windows\n - add_fields:\n target: \"@metadata\"\n fields:\n pipeline: logs-windows.powershell_operational-3.0.0\n- add_fields:\n target: data_stream\n fields:\n dataset: import", + "processors": "- dissect:\n tokenizer: \"/nsm/import/%{import.id}/evtx/%{import.file}\"\n field: \"log.file.path\"\n target_prefix: \"\"\n- decode_json_fields:\n fields: [\"message\"]\n target: \"\"\n- drop_fields:\n fields: [\"host\"]\n ignore_missing: true\n- add_fields:\n target: data_stream\n fields:\n type: logs\n dataset: system.security\n- add_fields:\n target: event\n fields:\n dataset: system.security\n module: system\n imported: true\n- add_fields:\n target: \"@metadata\"\n fields:\n pipeline: logs-system.security-2.3.3\n- if:\n equals:\n winlog.channel: 'Microsoft-Windows-Sysmon/Operational'\n then: \n - add_fields:\n target: data_stream\n fields:\n dataset: windows.sysmon_operational\n - add_fields:\n target: event\n fields:\n dataset: windows.sysmon_operational\n module: windows\n imported: true\n - add_fields:\n target: \"@metadata\"\n fields:\n pipeline: logs-windows.sysmon_operational-3.1.0\n- if:\n equals:\n winlog.channel: 'Application'\n then: \n - add_fields:\n target: data_stream\n fields:\n dataset: system.application\n - add_fields:\n target: event\n fields:\n dataset: system.application\n - add_fields:\n target: \"@metadata\"\n fields:\n pipeline: logs-system.application-2.3.3\n- if:\n equals:\n winlog.channel: 'System'\n then: \n - add_fields:\n target: data_stream\n fields:\n dataset: system.system\n - add_fields:\n target: event\n fields:\n dataset: system.system\n - add_fields:\n target: \"@metadata\"\n fields:\n pipeline: logs-system.system-2.3.3\n \n- if:\n equals:\n winlog.channel: 'Microsoft-Windows-PowerShell/Operational'\n then: \n - add_fields:\n target: data_stream\n fields:\n dataset: windows.powershell_operational\n - add_fields:\n target: event\n fields:\n dataset: windows.powershell_operational\n module: windows\n - add_fields:\n target: \"@metadata\"\n fields:\n pipeline: logs-windows.powershell_operational-3.1.0\n- add_fields:\n target: data_stream\n fields:\n dataset: import", "tags": [ "import" ] From 7ae0369a3b4542779d553245b9a888d87d71911d Mon Sep 17 00:00:00 2001 From: reyesj2 <94730068+reyesj2@users.noreply.github.com> Date: Wed, 23 Jul 2025 09:58:55 -0500 Subject: [PATCH 284/315] VERSION --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 7d52aac7f..032d0bb01 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.4.0-foxtrot +2.4.170 From e8c25d157fd55c200704030d7c5ded9eb7a714d1 Mon Sep 17 00:00:00 2001 From: reyesj2 <94730068+reyesj2@users.noreply.github.com> Date: Wed, 23 Jul 2025 15:52:50 -0500 Subject: [PATCH 285/315] drop empty ip fields when its a opencanary startup log (1001) to prevent elasticsearch doc ingest error --- .../files/integrations/grid-nodes_general/idh-logs.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/elasticfleet/files/integrations/grid-nodes_general/idh-logs.json b/salt/elasticfleet/files/integrations/grid-nodes_general/idh-logs.json index db4b1a8f6..9f66c1937 100644 --- a/salt/elasticfleet/files/integrations/grid-nodes_general/idh-logs.json +++ b/salt/elasticfleet/files/integrations/grid-nodes_general/idh-logs.json @@ -19,7 +19,7 @@ ], "data_stream.dataset": "idh", "tags": [], - "processors": "\n- decode_json_fields:\n fields: [\"message\"]\n target: \"\"\n add_error_key: true\n- drop_fields:\n when:\n equals:\n logtype: \"1001\"\n fields: [\"src_host\", \"src_port\", \"dst_host\", \"dst_port\" ]\n ignore_missing: true\n- rename:\n fields:\n - from: \"src_host\"\n to: \"source.ip\"\n - from: \"src_port\"\n to: \"source.port\"\n - from: \"dst_host\"\n to: \"destination.host\"\n - from: \"dst_port\"\n to: \"destination.port\"\n ignore_missing: true\n- convert:\n fields:\n - {from: \"logtype\", to: \"event.code\", type: \"string\"}\n ignore_missing: true\n- drop_fields:\n fields: '[\"prospector\", \"input\", \"offset\", \"beat\"]'\n- add_fields:\n target: event\n fields:\n category: host\n module: opencanary", + "processors": "\n- decode_json_fields:\n fields: [\"message\"]\n target: \"\"\n add_error_key: true\n- convert:\n fields:\n - {from: \"logtype\", to: \"event.code\", type: \"string\"}\n- drop_fields:\n when:\n equals:\n event.code: \"1001\"\n fields: [\"src_host\", \"src_port\", \"dst_host\", \"dst_port\" ]\n ignore_missing: true\n- rename:\n fields:\n - from: \"src_host\"\n to: \"source.ip\"\n - from: \"src_port\"\n to: \"source.port\"\n - from: \"dst_host\"\n to: \"destination.host\"\n - from: \"dst_port\"\n to: \"destination.port\"\n ignore_missing: true\n- drop_fields:\n fields: '[\"prospector\", \"input\", \"offset\", \"beat\"]'\n- add_fields:\n target: event\n fields:\n category: host\n module: opencanary", "custom": "pipeline: common" } } From 84b38daf6282b0e7053da7ba906eb373d0d01454 Mon Sep 17 00:00:00 2001 From: reyesj2 <94730068+reyesj2@users.noreply.github.com> Date: Fri, 25 Jul 2025 16:17:22 -0500 Subject: [PATCH 286/315] name destination_geo & source_geo to destination.as and source.as better aligning with ECS and linking other log sources already using .as for ASN geo data. Signed-off-by: reyesj2 <94730068+reyesj2@users.noreply.github.com> --- salt/common/tools/sbin_jinja/so-import-pcap | 2 +- .../elasticsearch/files/ingest-dynamic/common | 8 ++- salt/soc/defaults.yaml | 68 +++++++++---------- salt/soc/files/soc/motd.md | 2 +- 4 files changed, 42 insertions(+), 38 deletions(-) diff --git a/salt/common/tools/sbin_jinja/so-import-pcap b/salt/common/tools/sbin_jinja/so-import-pcap index 5f2370a4a..e8c2b84c8 100755 --- a/salt/common/tools/sbin_jinja/so-import-pcap +++ b/salt/common/tools/sbin_jinja/so-import-pcap @@ -248,7 +248,7 @@ fi START_OLDEST_SLASH=$(echo $START_OLDEST | sed -e 's/-/%2F/g') END_NEWEST_SLASH=$(echo $END_NEWEST | sed -e 's/-/%2F/g') if [[ $VALID_PCAPS_COUNT -gt 0 ]] || [[ $SKIPPED_PCAPS_COUNT -gt 0 ]]; then - URL="https://{{ URLBASE }}/#/dashboards?q=$HASH_FILTERS%20%7C%20groupby%20event.module*%20%7C%20groupby%20-sankey%20event.module*%20event.dataset%20%7C%20groupby%20event.dataset%20%7C%20groupby%20source.ip%20%7C%20groupby%20destination.ip%20%7C%20groupby%20destination.port%20%7C%20groupby%20network.protocol%20%7C%20groupby%20rule.name%20rule.category%20event.severity_label%20%7C%20groupby%20dns.query.name%20%7C%20groupby%20file.mime_type%20%7C%20groupby%20http.virtual_host%20http.uri%20%7C%20groupby%20notice.note%20notice.message%20notice.sub_message%20%7C%20groupby%20ssl.server_name%20%7C%20groupby%20source_geo.organization_name%20source.geo.country_name%20%7C%20groupby%20destination_geo.organization_name%20destination.geo.country_name&t=${START_OLDEST_SLASH}%2000%3A00%3A00%20AM%20-%20${END_NEWEST_SLASH}%2000%3A00%3A00%20AM&z=UTC" + URL="https://{{ URLBASE }}/#/dashboards?q=$HASH_FILTERS%20%7C%20groupby%20event.module*%20%7C%20groupby%20-sankey%20event.module*%20event.dataset%20%7C%20groupby%20event.dataset%20%7C%20groupby%20source.ip%20%7C%20groupby%20destination.ip%20%7C%20groupby%20destination.port%20%7C%20groupby%20network.protocol%20%7C%20groupby%20rule.name%20rule.category%20event.severity_label%20%7C%20groupby%20dns.query.name%20%7C%20groupby%20file.mime_type%20%7C%20groupby%20http.virtual_host%20http.uri%20%7C%20groupby%20notice.note%20notice.message%20notice.sub_message%20%7C%20groupby%20ssl.server_name%20%7C%20groupby%20source.as.organization.name%20source.geo.country_name%20%7C%20groupby%20destination.as.organization.name%20destination.geo.country_name&t=${START_OLDEST_SLASH}%2000%3A00%3A00%20AM%20-%20${END_NEWEST_SLASH}%2000%3A00%3A00%20AM&z=UTC" status "Import complete!" status diff --git a/salt/elasticsearch/files/ingest-dynamic/common b/salt/elasticsearch/files/ingest-dynamic/common index e84702909..814d8d4d5 100644 --- a/salt/elasticsearch/files/ingest-dynamic/common +++ b/salt/elasticsearch/files/ingest-dynamic/common @@ -26,7 +26,7 @@ { "geoip": { "field": "destination.ip", - "target_field": "destination_geo", + "target_field": "destination.as", "database_file": "GeoLite2-ASN.mmdb", "ignore_missing": true, "ignore_failure": true, @@ -36,13 +36,17 @@ { "geoip": { "field": "source.ip", - "target_field": "source_geo", + "target_field": "source.as", "database_file": "GeoLite2-ASN.mmdb", "ignore_missing": true, "ignore_failure": true, "properties": ["ip", "asn", "organization_name", "network"] } }, + { "rename": { "field": "destination.as.organization_name", "target_field": "destination.as.organization.name", "ignore_failure": true, "ignore_missing": true } }, + { "rename": { "field": "source.as.organization_name", "target_field": "source.as.organization.name", "ignore_failure": true, "ignore_missing": true } }, + { "rename": { "field": "destination.as.asn", "target_field": "destination.as.number", "ignore_failure": true, "ignore_missing": true } }, + { "rename": { "field": "source.as.asn", "target_field": "source.as.number", "ignore_failure": true, "ignore_missing": true } }, { "set": { "if": "ctx.event?.severity == 1", "field": "event.severity_label", "value": "low", "override": true } }, { "set": { "if": "ctx.event?.severity == 2", "field": "event.severity_label", "value": "medium", "override": true } }, { "set": { "if": "ctx.event?.severity == 3", "field": "event.severity_label", "value": "high", "override": true } }, diff --git a/salt/soc/defaults.yaml b/salt/soc/defaults.yaml index ad7d51f68..0e3e50240 100644 --- a/salt/soc/defaults.yaml +++ b/salt/soc/defaults.yaml @@ -10,7 +10,7 @@ soc: icon: fa-crosshairs target: links: - - '/#/hunt?q="{value|escape}" | groupby event.module* | groupby -sankey event.module* event.dataset | groupby event.dataset | groupby source.ip source.port destination.ip destination.port | groupby network.protocol | groupby source_geo.organization_name source.geo.country_name | groupby destination_geo.organization_name destination.geo.country_name | groupby rule.name rule.category event.severity_label | groupby dns.query.name | groupby file.mime_type | groupby http.virtual_host http.uri | groupby notice.note notice.message notice.sub_message | groupby ssl.server_name | groupby source.ip host.hostname user.name event.action event.type process.executable process.pid&gridId={gridId}' + - '/#/hunt?q="{value|escape}" | groupby event.module* | groupby -sankey event.module* event.dataset | groupby event.dataset | groupby source.ip source.port destination.ip destination.port | groupby network.protocol | groupby source.as.organization.name source.geo.country_name | groupby destination.as.organization.name destination.geo.country_name | groupby rule.name rule.category event.severity_label | groupby dns.query.name | groupby file.mime_type | groupby http.virtual_host http.uri | groupby notice.note notice.message notice.sub_message | groupby ssl.server_name | groupby source.ip host.hostname user.name event.action event.type process.executable process.pid&gridId={gridId}' - name: actionAddToCase description: actionAddToCaseHelp icon: fa-briefcase @@ -24,13 +24,13 @@ soc: icon: fa-magnifying-glass-arrow-right target: '' links: - - '/#/hunt?q=("{:log.id.fuid}" OR "{:log.id.uid}" OR "{:network.community_id}") | groupby event.module* | groupby -sankey event.module* event.dataset | groupby event.dataset | groupby source.ip source.port destination.ip destination.port | groupby network.protocol | groupby source_geo.organization_name source.geo.country_name | groupby destination_geo.organization_name destination.geo.country_name | groupby rule.name rule.category event.severity_label | groupby dns.query.name | groupby file.mime_type | groupby http.virtual_host http.uri | groupby notice.note notice.message notice.sub_message | groupby ssl.server_name | groupby source.ip host.hostname user.name event.action event.type process.executable process.pid&gridId={gridId}' - - '/#/hunt?q=("{:log.id.fuid}" OR "{:log.id.uid}") | groupby event.module* | groupby -sankey event.module* event.dataset | groupby event.dataset | groupby source.ip source.port destination.ip destination.port | groupby network.protocol | groupby source_geo.organization_name source.geo.country_name | groupby destination_geo.organization_name destination.geo.country_name | groupby rule.name rule.category event.severity_label | groupby dns.query.name | groupby file.mime_type | groupby http.virtual_host http.uri | groupby notice.note notice.message notice.sub_message | groupby ssl.server_name | groupby source.ip host.hostname user.name event.action event.type process.executable process.pid&gridId={gridId}' - - '/#/hunt?q=("{:log.id.fuid}" OR "{:network.community_id}") | groupby event.module* | groupby -sankey event.module* event.dataset | groupby event.dataset | groupby source.ip source.port destination.ip destination.port | groupby network.protocol | groupby source_geo.organization_name source.geo.country_name | groupby destination_geo.organization_name destination.geo.country_name | groupby rule.name rule.category event.severity_label | groupby dns.query.name | groupby file.mime_type | groupby http.virtual_host http.uri | groupby notice.note notice.message notice.sub_message | groupby ssl.server_name | groupby source.ip host.hostname user.name event.action event.type process.executable process.pid&gridId={gridId}' - - '/#/hunt?q=("{:log.id.uid}" OR "{:network.community_id}") | groupby event.module* | groupby -sankey event.module* event.dataset | groupby event.dataset | groupby source.ip source.port destination.ip destination.port | groupby network.protocol | groupby source_geo.organization_name source.geo.country_name | groupby destination_geo.organization_name destination.geo.country_name | groupby rule.name rule.category event.severity_label | groupby dns.query.name | groupby file.mime_type | groupby http.virtual_host http.uri | groupby notice.note notice.message notice.sub_message | groupby ssl.server_name | groupby source.ip host.hostname user.name event.action event.type process.executable process.pid&gridId={gridId}' - - '/#/hunt?q="{:log.id.fuid}" | groupby event.module* | groupby -sankey event.module* event.dataset | groupby event.dataset | groupby source.ip source.port destination.ip destination.port | groupby network.protocol | groupby source_geo.organization_name source.geo.country_name | groupby destination_geo.organization_name destination.geo.country_name | groupby rule.name rule.category event.severity_label | groupby dns.query.name | groupby file.mime_type | groupby http.virtual_host http.uri | groupby notice.note notice.message notice.sub_message | groupby ssl.server_name | groupby source.ip host.hostname user.name event.action event.type process.executable process.pid&gridId={gridId}' - - '/#/hunt?q="{:log.id.uid}" | groupby event.module* | groupby -sankey event.module* event.dataset | groupby event.dataset | groupby source.ip source.port destination.ip destination.port | groupby network.protocol | groupby source_geo.organization_name source.geo.country_name | groupby destination_geo.organization_name destination.geo.country_name | groupby rule.name rule.category event.severity_label | groupby dns.query.name | groupby file.mime_type | groupby http.virtual_host http.uri | groupby notice.note notice.message notice.sub_message | groupby ssl.server_name | groupby source.ip host.hostname user.name event.action event.type process.executable process.pid&gridId={gridId}' - - '/#/hunt?q="{:network.community_id}" | groupby event.module* | groupby -sankey event.module* event.dataset | groupby event.dataset | groupby source.ip source.port destination.ip destination.port | groupby network.protocol | groupby source_geo.organization_name source.geo.country_name | groupby destination_geo.organization_name destination.geo.country_name | groupby rule.name rule.category event.severity_label | groupby dns.query.name | groupby file.mime_type | groupby http.virtual_host http.uri | groupby notice.note notice.message notice.sub_message | groupby ssl.server_name | groupby source.ip host.hostname user.name event.action event.type process.executable process.pid&gridId={gridId}' + - '/#/hunt?q=("{:log.id.fuid}" OR "{:log.id.uid}" OR "{:network.community_id}") | groupby event.module* | groupby -sankey event.module* event.dataset | groupby event.dataset | groupby source.ip source.port destination.ip destination.port | groupby network.protocol | groupby source.as.organization.name source.geo.country_name | groupby destination.as.organization.name destination.geo.country_name | groupby rule.name rule.category event.severity_label | groupby dns.query.name | groupby file.mime_type | groupby http.virtual_host http.uri | groupby notice.note notice.message notice.sub_message | groupby ssl.server_name | groupby source.ip host.hostname user.name event.action event.type process.executable process.pid&gridId={gridId}' + - '/#/hunt?q=("{:log.id.fuid}" OR "{:log.id.uid}") | groupby event.module* | groupby -sankey event.module* event.dataset | groupby event.dataset | groupby source.ip source.port destination.ip destination.port | groupby network.protocol | groupby source.as.organization.name source.geo.country_name | groupby destination.as.organization.name destination.geo.country_name | groupby rule.name rule.category event.severity_label | groupby dns.query.name | groupby file.mime_type | groupby http.virtual_host http.uri | groupby notice.note notice.message notice.sub_message | groupby ssl.server_name | groupby source.ip host.hostname user.name event.action event.type process.executable process.pid&gridId={gridId}' + - '/#/hunt?q=("{:log.id.fuid}" OR "{:network.community_id}") | groupby event.module* | groupby -sankey event.module* event.dataset | groupby event.dataset | groupby source.ip source.port destination.ip destination.port | groupby network.protocol | groupby source.as.organization.name source.geo.country_name | groupby destination.as.organization.name destination.geo.country_name | groupby rule.name rule.category event.severity_label | groupby dns.query.name | groupby file.mime_type | groupby http.virtual_host http.uri | groupby notice.note notice.message notice.sub_message | groupby ssl.server_name | groupby source.ip host.hostname user.name event.action event.type process.executable process.pid&gridId={gridId}' + - '/#/hunt?q=("{:log.id.uid}" OR "{:network.community_id}") | groupby event.module* | groupby -sankey event.module* event.dataset | groupby event.dataset | groupby source.ip source.port destination.ip destination.port | groupby network.protocol | groupby source.as.organization.name source.geo.country_name | groupby destination.as.organization.name destination.geo.country_name | groupby rule.name rule.category event.severity_label | groupby dns.query.name | groupby file.mime_type | groupby http.virtual_host http.uri | groupby notice.note notice.message notice.sub_message | groupby ssl.server_name | groupby source.ip host.hostname user.name event.action event.type process.executable process.pid&gridId={gridId}' + - '/#/hunt?q="{:log.id.fuid}" | groupby event.module* | groupby -sankey event.module* event.dataset | groupby event.dataset | groupby source.ip source.port destination.ip destination.port | groupby network.protocol | groupby source.as.organization.name source.geo.country_name | groupby destination.as.organization.name destination.geo.country_name | groupby rule.name rule.category event.severity_label | groupby dns.query.name | groupby file.mime_type | groupby http.virtual_host http.uri | groupby notice.note notice.message notice.sub_message | groupby ssl.server_name | groupby source.ip host.hostname user.name event.action event.type process.executable process.pid&gridId={gridId}' + - '/#/hunt?q="{:log.id.uid}" | groupby event.module* | groupby -sankey event.module* event.dataset | groupby event.dataset | groupby source.ip source.port destination.ip destination.port | groupby network.protocol | groupby source.as.organization.name source.geo.country_name | groupby destination.as.organization.name destination.geo.country_name | groupby rule.name rule.category event.severity_label | groupby dns.query.name | groupby file.mime_type | groupby http.virtual_host http.uri | groupby notice.note notice.message notice.sub_message | groupby ssl.server_name | groupby source.ip host.hostname user.name event.action event.type process.executable process.pid&gridId={gridId}' + - '/#/hunt?q="{:network.community_id}" | groupby event.module* | groupby -sankey event.module* event.dataset | groupby event.dataset | groupby source.ip source.port destination.ip destination.port | groupby network.protocol | groupby source.as.organization.name source.geo.country_name | groupby destination.as.organization.name destination.geo.country_name | groupby rule.name rule.category event.severity_label | groupby dns.query.name | groupby file.mime_type | groupby http.virtual_host http.uri | groupby notice.note notice.message notice.sub_message | groupby ssl.server_name | groupby source.ip host.hostname user.name event.action event.type process.executable process.pid&gridId={gridId}' - name: actionPcap description: actionPcapHelp icon: fa-stream @@ -1928,10 +1928,10 @@ soc: query: 'event.dataset:kratos.audit AND msg:*Encountered*self-service*login*error* | groupby user.name | groupby http_request.headers.x-real-ip | groupby -sankey http_request.headers.x-real-ip http_request.headers.user-agent | groupby http_request.headers.user-agent' - name: Alerts description: Overview of all alerts - query: 'tags:alert | groupby event.module* | groupby source.ip | groupby -sankey source.ip destination.ip | groupby destination.ip | groupby destination.port | groupby rule.name | groupby event.severity | groupby destination_geo.organization_name' + query: 'tags:alert | groupby event.module* | groupby source.ip | groupby -sankey source.ip destination.ip | groupby destination.ip | groupby destination.port | groupby rule.name | groupby event.severity | groupby destination.as.organization.name' - name: NIDS Alerts description: NIDS (Network Intrusion Detection System) alerts - query: 'event.category:network AND tags:alert | groupby rule.category | groupby source.ip | groupby -sankey source.ip destination.ip | groupby destination.ip | groupby destination.port | groupby rule.name | groupby rule.uuid | groupby rule.gid | groupby destination_geo.organization_name' + query: 'event.category:network AND tags:alert | groupby rule.category | groupby source.ip | groupby -sankey source.ip destination.ip | groupby destination.ip | groupby destination.port | groupby rule.name | groupby rule.uuid | groupby rule.gid | groupby destination.as.organization.name' - name: Elastic Agent Overview description: Overview of all events from Elastic Agents query: 'event.module:endpoint | groupby event.dataset | groupby host.name | groupby -sankey host.name user.name | groupby user.name | groupby -sankey user.name process.name | groupby process.name' @@ -1982,34 +1982,34 @@ soc: query: 'event.module:strelka | groupby file.mime_type | groupby -sankey file.mime_type file.source | groupby file.source | groupby -sankey file.source file.name | groupby file.name' - name: Zeek Notice description: Zeek notice logs - query: 'event.dataset:zeek.notice | groupby notice.note | groupby -sankey notice.note source.ip | groupby source.ip | groupby -sankey source.ip destination.ip | groupby destination.ip | groupby destination.port | groupby notice.message | groupby notice.sub_message | groupby source_geo.organization_name | groupby destination_geo.organization_name' + query: 'event.dataset:zeek.notice | groupby notice.note | groupby -sankey notice.note source.ip | groupby source.ip | groupby -sankey source.ip destination.ip | groupby destination.ip | groupby destination.port | groupby notice.message | groupby notice.sub_message | groupby source.as.organization.name | groupby destination.as.organization.name' - name: Connections and Metadata with Community ID description: Network connections that include network.community_id - query: '_exists_:network.community_id | groupby event.module* | groupby -sankey event.module* event.dataset | groupby event.dataset | groupby source.ip | groupby destination.ip | groupby destination.port | groupby network.protocol | groupby source_geo.organization_name | groupby source.geo.country_name | groupby destination_geo.organization_name | groupby destination.geo.country_name | groupby rule.name rule.category event.severity_label | groupby dns.query.name | groupby http.virtual_host http.uri | groupby notice.note notice.message notice.sub_message | groupby source.ip host.hostname user.name event.action event.type process.executable process.pid' + query: '_exists_:network.community_id | groupby event.module* | groupby -sankey event.module* event.dataset | groupby event.dataset | groupby source.ip | groupby destination.ip | groupby destination.port | groupby network.protocol | groupby source.as.organization.name | groupby source.geo.country_name | groupby destination.as.organization.name | groupby destination.geo.country_name | groupby rule.name rule.category event.severity_label | groupby dns.query.name | groupby http.virtual_host http.uri | groupby notice.note notice.message notice.sub_message | groupby source.ip host.hostname user.name event.action event.type process.executable process.pid' - name: Connections seen by Zeek or Suricata description: Network connections logged by Zeek or Suricata query: 'tags:conn | groupby source.ip | groupby destination.ip | groupby destination.port | groupby -sankey destination.port network.protocol | groupby network.protocol | groupby network.transport | groupby connection.history | groupby connection.state | groupby connection.state_description | groupby source.geo.country_name | groupby destination.geo.country_name | groupby client.ip_bytes | groupby server.ip_bytes | groupby client.oui' - name: DCE_RPC description: DCE_RPC (Distributed Computing Environment / Remote Procedure Calls) network metadata - query: 'tags:dce_rpc | groupby dce_rpc.endpoint | groupby -sankey dce_rpc.endpoint dce_rpc.operation | groupby dce_rpc.operation | groupby -sankey dce_rpc.operation dce_rpc.named_pipe | groupby dce_rpc.named_pipe | groupby source.ip | groupby -sankey source.ip destination.ip | groupby destination.ip | groupby destination.port | groupby destination_geo.organization_name' + query: 'tags:dce_rpc | groupby dce_rpc.endpoint | groupby -sankey dce_rpc.endpoint dce_rpc.operation | groupby dce_rpc.operation | groupby -sankey dce_rpc.operation dce_rpc.named_pipe | groupby dce_rpc.named_pipe | groupby source.ip | groupby -sankey source.ip destination.ip | groupby destination.ip | groupby destination.port | groupby destination.as.organization.name' - name: DHCP description: DHCP (Dynamic Host Configuration Protocol) leases query: 'tags:dhcp | groupby host.hostname | groupby -sankey host.hostname client.address | groupby client.address | groupby -sankey client.address server.address | groupby server.address | groupby dhcp.message_types | groupby host.domain' - name: DNS description: DNS (Domain Name System) queries - query: 'tags:dns | groupby dns.query.name | groupby source.ip | groupby -sankey source.ip destination.ip | groupby destination.ip | groupby destination.port | groupby dns.highest_registered_domain | groupby dns.parent_domain | groupby dns.query.type_name | groupby dns.response.code_name | groupby dns.answers.name | groupby destination_geo.organization_name' + query: 'tags:dns | groupby dns.query.name | groupby source.ip | groupby -sankey source.ip destination.ip | groupby destination.ip | groupby destination.port | groupby dns.highest_registered_domain | groupby dns.parent_domain | groupby dns.query.type_name | groupby dns.response.code_name | groupby dns.answers.name | groupby destination.as.organization.name' - name: DPD description: DPD (Dynamic Protocol Detection) errors - query: 'tags:dpd | groupby error.reason | groupby -sankey error.reason source.ip | groupby source.ip | groupby -sankey source.ip destination.ip | groupby destination.ip | groupby destination.port | groupby network.protocol | groupby destination_geo.organization_name' + query: 'tags:dpd | groupby error.reason | groupby -sankey error.reason source.ip | groupby source.ip | groupby -sankey source.ip destination.ip | groupby destination.ip | groupby destination.port | groupby network.protocol | groupby destination.as.organization.name' - name: Files description: Files seen in network traffic - query: 'tags:file | groupby file.mime_type | groupby -sankey file.mime_type file.source | groupby file.source | groupby file.bytes.total | groupby source.ip | groupby destination.ip | groupby destination_geo.organization_name' + query: 'tags:file | groupby file.mime_type | groupby -sankey file.mime_type file.source | groupby file.source | groupby file.bytes.total | groupby source.ip | groupby destination.ip | groupby destination.as.organization.name' - name: FTP description: FTP (File Transfer Protocol) network metadata - query: 'tags:ftp | groupby ftp.command | groupby -sankey ftp.command source.ip | groupby source.ip | groupby -sankey source.ip destination.ip | groupby destination.ip | groupby destination.port | groupby destination_geo.organization_name | groupby ftp.argument | groupby ftp.user' + query: 'tags:ftp | groupby ftp.command | groupby -sankey ftp.command source.ip | groupby source.ip | groupby -sankey source.ip destination.ip | groupby destination.ip | groupby destination.port | groupby destination.as.organization.name | groupby ftp.argument | groupby ftp.user' - name: HTTP description: HTTP (Hyper Text Transport Protocol) network metadata - query: '(tags:http OR tags:http2) | groupby http.method | groupby -sankey http.method http.virtual_host | groupby http.virtual_host | groupby http.uri | groupby http.useragent | groupby http.status_code | groupby http.status_message | groupby file.resp_mime_types | groupby source.ip | groupby destination.ip | groupby destination.port | groupby destination_geo.organization_name' + query: '(tags:http OR tags:http2) | groupby http.method | groupby -sankey http.method http.virtual_host | groupby http.virtual_host | groupby http.uri | groupby http.useragent | groupby http.status_code | groupby http.status_message | groupby file.resp_mime_types | groupby source.ip | groupby destination.ip | groupby destination.port | groupby destination.as.organization.name' - name: Intel description: Zeek Intel framework hits query: 'tags:intel | groupby intel.indicator | groupby -sankey intel.indicator source.ip | groupby source.ip | groupby -sankey source.ip destination.ip | groupby destination.ip | groupby destination.port | groupby intel.indicator_type | groupby intel.seen_where' @@ -2018,7 +2018,7 @@ soc: query: 'tags:ipsec | groupby source.ip | groupby -sankey source.ip destination.ip | groupby destination.ip | groupby destination.port | groupby destination.geo.country_name | groupby ipsec.version' - name: IRC description: IRC (Internet Relay Chat) network metadata - query: 'tags:irc | groupby irc.command.type | groupby -sankey irc.command.type irc.username | groupby irc.username | groupby irc.nickname | groupby irc.command.value | groupby irc.command.info | groupby source.ip | groupby destination.ip | groupby destination.port | groupby destination_geo.organization_name' + query: 'tags:irc | groupby irc.command.type | groupby -sankey irc.command.type irc.username | groupby irc.username | groupby irc.nickname | groupby irc.command.value | groupby irc.command.info | groupby source.ip | groupby destination.ip | groupby destination.port | groupby destination.as.organization.name' - name: Kerberos description: Kerberos network metadata query: 'tags:kerberos | groupby kerberos.service | groupby -sankey kerberos.service source.ip | groupby source.ip | groupby -sankey source.ip destination.ip | groupby destination.ip | groupby destination.port | groupby kerberos.client | groupby kerberos.request_type' @@ -2042,22 +2042,22 @@ soc: query: 'tags:pe | groupby file.machine | groupby -sankey file.machine file.os | groupby file.os | groupby -sankey file.os file.subsystem | groupby file.subsystem | groupby file.section_names | groupby file.is_exe | groupby file.is_64bit' - name: QUIC description: QUIC network metadata - query: 'tags:quic | groupby quic.server_name | groupby -sankey quic.server_name source.ip | groupby source.ip | groupby -sankey source.ip destination.ip | groupby destination.ip | groupby destination.port | groupby destination_geo.organization_name | groupby quic.server_scid | groupby quic.version | groupby quic.client_protocol' + query: 'tags:quic | groupby quic.server_name | groupby -sankey quic.server_name source.ip | groupby source.ip | groupby -sankey source.ip destination.ip | groupby destination.ip | groupby destination.port | groupby destination.as.organization.name | groupby quic.server_scid | groupby quic.version | groupby quic.client_protocol' - name: RADIUS description: RADIUS (Remote Authentication Dial-In User Service) network metadata - query: 'tags:radius | groupby user.name | groupby -sankey user.name source.ip | groupby source.ip | groupby -sankey source.ip destination.ip | groupby destination.ip | groupby destination.port | groupby destination_geo.organization_name' + query: 'tags:radius | groupby user.name | groupby -sankey user.name source.ip | groupby source.ip | groupby -sankey source.ip destination.ip | groupby destination.ip | groupby destination.port | groupby destination.as.organization.name' - name: RDP description: RDP (Remote Desktop Protocol) network metadata - query: 'tags:rdp | groupby client.name | groupby -sankey client.name source.ip | groupby source.ip | groupby -sankey source.ip destination.ip | groupby destination.ip | groupby destination.port | groupby destination_geo.organization_name' + query: 'tags:rdp | groupby client.name | groupby -sankey client.name source.ip | groupby source.ip | groupby -sankey source.ip destination.ip | groupby destination.ip | groupby destination.port | groupby destination.as.organization.name' - name: RFB description: RFB (Remote Frame Buffer) network metadata - query: 'tags:rfb | groupby rfb.desktop.name | groupby source.ip | groupby -sankey source.ip destination.ip | groupby destination.ip | groupby destination.port | groupby destination_geo.organization_name' + query: 'tags:rfb | groupby rfb.desktop.name | groupby source.ip | groupby -sankey source.ip destination.ip | groupby destination.ip | groupby destination.port | groupby destination.as.organization.name' - name: Signatures description: Zeek signatures query: 'event.dataset:zeek.signatures | groupby signature_id' - name: SIP description: SIP (Session Initiation Protocol) network metadata - query: 'tags:sip | groupby sip.method | groupby -sankey sip.method source.ip | groupby source.ip | groupby -sankey source.ip destination.ip | groupby destination.ip | groupby destination.port | groupby destination_geo.organization_name | groupby client.user_agent | groupby sip.method | groupby sip.uri' + query: 'tags:sip | groupby sip.method | groupby -sankey sip.method source.ip | groupby source.ip | groupby -sankey source.ip destination.ip | groupby destination.ip | groupby destination.port | groupby destination.as.organization.name | groupby client.user_agent | groupby sip.method | groupby sip.uri' - name: SMB_Files description: Files transferred via SMB (Server Message Block) query: 'tags:smb_files | groupby file.action | groupby -sankey file.action source.ip | groupby source.ip | groupby -sankey source.ip destination.ip | groupby destination.ip | groupby destination.port | groupby file.path | groupby file.name' @@ -2066,7 +2066,7 @@ soc: query: 'tags:smb_mapping | groupby smb.share_type | groupby -sankey smb.share_type smb.path | groupby smb.path | groupby -sankey smb.path smb.service | groupby smb.service | groupby source.ip | groupby -sankey source.ip destination.ip | groupby destination.ip | groupby destination.port' - name: SMTP description: SMTP (Simple Mail Transfer Protocol) network metadata - query: 'tags:smtp | groupby smtp.mail_from | groupby -sankey smtp.mail_from smtp.recipient_to | groupby smtp.recipient_to | groupby source.ip | groupby -sankey source.ip destination.ip | groupby destination.ip | groupby destination.port | groupby smtp.subject | groupby destination_geo.organization_name' + query: 'tags:smtp | groupby smtp.mail_from | groupby -sankey smtp.mail_from smtp.recipient_to | groupby smtp.recipient_to | groupby source.ip | groupby -sankey source.ip destination.ip | groupby destination.ip | groupby destination.port | groupby smtp.subject | groupby destination.as.organization.name' - name: SNMP description: SNMP (Simple Network Management Protocol) network metadat query: 'tags:snmp | groupby snmp.community | groupby -sankey snmp.community source.ip | groupby source.ip | groupby -sankey source.ip destination.ip | groupby destination.ip | groupby destination.port | groupby snmp.version' @@ -2075,16 +2075,16 @@ soc: query: 'tags:software | groupby software.type | groupby -sankey software.type source.ip | groupby source.ip | groupby software.name' - name: SSH description: SSH (Secure Shell) connections seen by Zeek - query: 'tags:ssh | groupby ssh.client | groupby -sankey ssh.client source.ip | groupby source.ip | groupby -sankey source.ip destination.ip | groupby destination.ip | groupby destination.port | groupby ssh.server | groupby ssh.version | groupby ssh.hassh_version | groupby ssh.direction | groupby source_geo.organization_name | groupby destination_geo.organization_name' + query: 'tags:ssh | groupby ssh.client | groupby -sankey ssh.client source.ip | groupby source.ip | groupby -sankey source.ip destination.ip | groupby destination.ip | groupby destination.port | groupby ssh.server | groupby ssh.version | groupby ssh.hassh_version | groupby ssh.direction | groupby source.as.organization.name | groupby destination.as.organization.name' - name: SSL description: SSL/TLS network metadata - query: 'tags:ssl | groupby ssl.version | groupby -sankey ssl.version ssl.server_name | groupby ssl.server_name | groupby source.ip | groupby destination.ip | groupby destination.port | groupby destination_geo.organization_name' + query: 'tags:ssl | groupby ssl.version | groupby -sankey ssl.version ssl.server_name | groupby ssl.server_name | groupby source.ip | groupby destination.ip | groupby destination.port | groupby destination.as.organization.name' - name: SSL - Suricata description: SSL/TLS network metadata from Suricata - query: 'event.dataset:suricata.ssl | groupby ssl.version | groupby -sankey ssl.version ssl.server_name | groupby ssl.server_name | groupby source.ip | groupby destination.ip | groupby destination.port | groupby destination_geo.organization_name | groupby ssl.certificate.issuer | groupby ssl.certificate.subject' + query: 'event.dataset:suricata.ssl | groupby ssl.version | groupby -sankey ssl.version ssl.server_name | groupby ssl.server_name | groupby source.ip | groupby destination.ip | groupby destination.port | groupby destination.as.organization.name | groupby ssl.certificate.issuer | groupby ssl.certificate.subject' - name: SSL - Zeek description: SSL/TLS network metadata from Zeek - query: 'event.dataset:zeek.ssl | groupby ssl.version | groupby ssl.validation_status | groupby -sankey ssl.validation_status ssl.server_name | groupby ssl.server_name | groupby source.ip | groupby destination.ip | groupby destination.port | groupby destination_geo.organization_name' + query: 'event.dataset:zeek.ssl | groupby ssl.version | groupby ssl.validation_status | groupby -sankey ssl.validation_status ssl.server_name | groupby ssl.server_name | groupby source.ip | groupby destination.ip | groupby destination.port | groupby destination.as.organization.name' - name: STUN description: STUN (Session Traversal Utilities for NAT) network metadata query: 'tags:stun* | groupby source.ip | groupby -sankey source.ip destination.ip | groupby destination.ip | groupby destination.port | groupby destination.geo.country_name | groupby stun.class | groupby -sankey stun.class stun.method | groupby stun.method | groupby stun.attribute.types' @@ -2099,7 +2099,7 @@ soc: query: 'tags:tunnel | groupby source.ip | groupby -sankey source.ip destination.ip | groupby destination.ip | groupby destination.port | groupby tunnel.type | groupby event.action | groupby destination.geo.country_name' - name: Weird description: Weird network traffic seen by Zeek - query: 'event.dataset:zeek.weird | groupby weird.name | groupby -sankey weird.name source.ip | groupby source.ip | groupby destination.ip | groupby destination.port | groupby destination_geo.organization_name' + query: 'event.dataset:zeek.weird | groupby weird.name | groupby -sankey weird.name source.ip | groupby source.ip | groupby destination.ip | groupby destination.port | groupby destination.as.organization.name' - name: WireGuard description: WireGuard VPN network metadata query: 'tags:wireguard | groupby source.ip | groupby -sankey source.ip destination.ip | groupby destination.ip | groupby destination.port | groupby destination.geo.country_name' @@ -2147,16 +2147,16 @@ soc: query: '* AND _exists_:network.vlan.id | groupby network.vlan.id | groupby -sankey network.vlan.id source.ip | groupby source.ip | groupby destination.ip | groupby destination.port | groupby event.dataset | groupby event.module | groupby observer.name | groupby source.geo.country_name | groupby destination.geo.country_name' - name: GeoIP - Destination Countries description: GeoIP tagged logs visualized by destination countries - query: '* AND _exists_:destination.geo.country_name | groupby destination.geo.country_name | groupby source.ip | groupby -sankey source.ip destination.ip | groupby destination.ip | groupby destination.port | groupby destination_geo.organization_name | groupby event.dataset | groupby event.module' + query: '* AND _exists_:destination.geo.country_name | groupby destination.geo.country_name | groupby source.ip | groupby -sankey source.ip destination.ip | groupby destination.ip | groupby destination.port | groupby destination.as.organization.name | groupby event.dataset | groupby event.module' - name: GeoIP - Destination Organizations description: GeoIP tagged logs visualized by destination organizations - query: '* AND _exists_:destination_geo.organization_name | groupby destination_geo.organization_name | groupby source.ip | groupby -sankey source.ip destination.ip | groupby destination.ip | groupby destination.port | groupby destination.geo.country_name | groupby event.dataset | groupby event.module' + query: '* AND _exists_:destination.as.organization.name | groupby destination.as.organization.name | groupby source.ip | groupby -sankey source.ip destination.ip | groupby destination.ip | groupby destination.port | groupby destination.geo.country_name | groupby event.dataset | groupby event.module' - name: GeoIP - Source Countries description: GeoIP tagged logs visualized by source countries - query: '* AND _exists_:source.geo.country_name | groupby source.geo.country_name | groupby source.ip | groupby -sankey source.ip destination.ip | groupby destination.ip | groupby destination.port | groupby source_geo.organization_name | groupby event.dataset | groupby event.module' + query: '* AND _exists_:source.geo.country_name | groupby source.geo.country_name | groupby source.ip | groupby -sankey source.ip destination.ip | groupby destination.ip | groupby destination.port | groupby source.as.organization.name | groupby event.dataset | groupby event.module' - name: GeoIP - Source Organizations description: GeoIP tagged logs visualized by source organizations - query: '* AND _exists_:source_geo.organization_name | groupby source_geo.organization_name | groupby source.ip | groupby -sankey source.ip destination.ip | groupby destination.ip | groupby destination.port | groupby source.geo.country_name | groupby event.dataset | groupby event.module' + query: '* AND _exists_:source.as.organization.name | groupby source.as.organization.name | groupby source.ip | groupby -sankey source.ip destination.ip | groupby destination.ip | groupby destination.port | groupby source.geo.country_name | groupby event.dataset | groupby event.module' - name: NetFlow description: NetFlow records query: 'event.module:netflow | groupby source.ip | groupby -sankey source.ip destination.ip | groupby destination.ip | groupby destination.port | groupby network.type | groupby network.transport | groupby network.direction | groupby netflow.type | groupby netflow.exporter.version | groupby observer.ip | groupby source.as.organization.name | groupby source.geo.country_name | groupby destination.as.organization.name | groupby destination.geo.country_name' diff --git a/salt/soc/files/soc/motd.md b/salt/soc/files/soc/motd.md index 91c603851..69b3145fa 100644 --- a/salt/soc/files/soc/motd.md +++ b/salt/soc/files/soc/motd.md @@ -6,7 +6,7 @@ If you're ready to dive in, take a look at the [Alerts](/#/alerts) interface to Next, go to the [Dashboards](/#/dashboards) interface for a general overview of all logs collected. Here are a few overview dashboards to get you started: -[Overview Dashboard](/#/dashboards) | [Elastic Agent Overview](/#/dashboards?q=event.module%3Aendpoint%20%7C%20groupby%20event.dataset%20%7C%20groupby%20host.name%20%7C%20groupby%20-sankey%20host.name%20user.name%20%7C%20groupby%20user.name%20%7C%20groupby%20-sankey%20user.name%20process.name%20%7C%20groupby%20process.name) | [Network Connection Overview](/#/dashboards?q=tags%3Aconn%20%7C%20groupby%20source.ip%20%7C%20groupby%20destination.ip%20%7C%20groupby%20destination.port%20%7C%20groupby%20-sankey%20destination.port%20network.protocol%20%7C%20groupby%20network.protocol%20%7C%20groupby%20network.transport%20%7C%20groupby%20connection.history%20%7C%20groupby%20connection.state%20%7C%20groupby%20connection.state_description%20%7C%20groupby%20source.geo.country_name%20%7C%20groupby%20destination.geo.country_name%20%7C%20groupby%20client.ip_bytes%20%7C%20groupby%20server.ip_bytes%20%7C%20groupby%20client.oui) | [DNS](/#/dashboards?q=tags%3Adns%20%7C%20groupby%20dns.query.name%20%7C%20groupby%20source.ip%20%7C%20groupby%20-sankey%20source.ip%20destination.ip%20%7C%20groupby%20destination.ip%20%7C%20groupby%20destination.port%20%7C%20groupby%20dns.highest_registered_domain%20%7C%20groupby%20dns.parent_domain%20%7C%20groupby%20dns.query.type_name%20%7C%20groupby%20dns.response.code_name%20%7C%20groupby%20dns.answers.name%20%7C%20groupby%20destination_geo.organization_name) | [Files](/#/dashboards?q=tags%3Afile%20%7C%20groupby%20file.mime_type%20%7C%20groupby%20-sankey%20file.mime_type%20file.source%20%7C%20groupby%20file.source%20%7C%20groupby%20file.bytes.total%20%7C%20groupby%20source.ip%20%7C%20groupby%20destination.ip%20%7C%20groupby%20destination_geo.organization_name) | [HTTP](/#/dashboards?q=tags%3Ahttp%20%7C%20groupby%20http.method%20%7C%20groupby%20-sankey%20http.method%20http.virtual_host%20%7C%20groupby%20http.virtual_host%20%7C%20groupby%20http.uri%20%7C%20groupby%20http.useragent%20%7C%20groupby%20http.status_code%20%7C%20groupby%20http.status_message%20%7C%20groupby%20file.resp_mime_types%20%7C%20groupby%20source.ip%20%7C%20groupby%20destination.ip%20%7C%20groupby%20destination.port%20%7C%20groupby%20destination_geo.organization_name) | [SSL](/#/dashboards?q=tags%3Assl%20%7C%20groupby%20ssl.version%20%7C%20groupby%20-sankey%20ssl.version%20ssl.server_name%20%7C%20groupby%20ssl.server_name%20%7C%20groupby%20source.ip%20%7C%20groupby%20destination.ip%20%7C%20groupby%20destination.port%20%7C%20groupby%20destination_geo.organization_name) +[Overview Dashboard](/#/dashboards) | [Elastic Agent Overview](/#/dashboards?q=event.module%3Aendpoint%20%7C%20groupby%20event.dataset%20%7C%20groupby%20host.name%20%7C%20groupby%20-sankey%20host.name%20user.name%20%7C%20groupby%20user.name%20%7C%20groupby%20-sankey%20user.name%20process.name%20%7C%20groupby%20process.name) | [Network Connection Overview](/#/dashboards?q=tags%3Aconn%20%7C%20groupby%20source.ip%20%7C%20groupby%20destination.ip%20%7C%20groupby%20destination.port%20%7C%20groupby%20-sankey%20destination.port%20network.protocol%20%7C%20groupby%20network.protocol%20%7C%20groupby%20network.transport%20%7C%20groupby%20connection.history%20%7C%20groupby%20connection.state%20%7C%20groupby%20connection.state_description%20%7C%20groupby%20source.geo.country_name%20%7C%20groupby%20destination.geo.country_name%20%7C%20groupby%20client.ip_bytes%20%7C%20groupby%20server.ip_bytes%20%7C%20groupby%20client.oui) | [DNS](/#/dashboards?q=tags%3Adns%20%7C%20groupby%20dns.query.name%20%7C%20groupby%20source.ip%20%7C%20groupby%20-sankey%20source.ip%20destination.ip%20%7C%20groupby%20destination.ip%20%7C%20groupby%20destination.port%20%7C%20groupby%20dns.highest_registered_domain%20%7C%20groupby%20dns.parent_domain%20%7C%20groupby%20dns.query.type_name%20%7C%20groupby%20dns.response.code_name%20%7C%20groupby%20dns.answers.name%20%7C%20groupby%20destination.as.organization.name) | [Files](/#/dashboards?q=tags%3Afile%20%7C%20groupby%20file.mime_type%20%7C%20groupby%20-sankey%20file.mime_type%20file.source%20%7C%20groupby%20file.source%20%7C%20groupby%20file.bytes.total%20%7C%20groupby%20source.ip%20%7C%20groupby%20destination.ip%20%7C%20groupby%20destination.as.organization.name) | [HTTP](/#/dashboards?q=tags%3Ahttp%20%7C%20groupby%20http.method%20%7C%20groupby%20-sankey%20http.method%20http.virtual_host%20%7C%20groupby%20http.virtual_host%20%7C%20groupby%20http.uri%20%7C%20groupby%20http.useragent%20%7C%20groupby%20http.status_code%20%7C%20groupby%20http.status_message%20%7C%20groupby%20file.resp_mime_types%20%7C%20groupby%20source.ip%20%7C%20groupby%20destination.ip%20%7C%20groupby%20destination.port%20%7C%20groupby%20destination.as.organization.name) | [SSL](/#/dashboards?q=tags%3Assl%20%7C%20groupby%20ssl.version%20%7C%20groupby%20-sankey%20ssl.version%20ssl.server_name%20%7C%20groupby%20ssl.server_name%20%7C%20groupby%20source.ip%20%7C%20groupby%20destination.ip%20%7C%20groupby%20destination.port%20%7C%20groupby%20destination.as.organization.name) Click the drop-down menu in Dashboards to find many more dashboards. You might also want to explore the [Hunt](/#/hunt) interface for more focused threat hunting. From d49cd3cb85583c4aebecf7323976808168830aae Mon Sep 17 00:00:00 2001 From: reyesj2 <94730068+reyesj2@users.noreply.github.com> Date: Mon, 28 Jul 2025 15:14:12 -0500 Subject: [PATCH 287/315] increased timeout for so-elasticsearch-roles-load from default of 30s --- salt/elasticsearch/tools/sbin/so-elasticsearch-roles-load | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/elasticsearch/tools/sbin/so-elasticsearch-roles-load b/salt/elasticsearch/tools/sbin/so-elasticsearch-roles-load index 90b262989..93f9d88c2 100755 --- a/salt/elasticsearch/tools/sbin/so-elasticsearch-roles-load +++ b/salt/elasticsearch/tools/sbin/so-elasticsearch-roles-load @@ -21,7 +21,7 @@ while [[ "$COUNT" -le 240 ]]; do ELASTICSEARCH_CONNECTED="yes" echo "connected!" # Check cluster health once connected - so-elasticsearch-query _cluster/health?wait_for_status=yellow > /dev/null 2>&1 + so-elasticsearch-query _cluster/health?wait_for_status=yellow\&timeout=600s > /dev/null 2>&1 break else ((COUNT+=1)) From fbf5bafae760c37eb452bf5642b41394d891a93a Mon Sep 17 00:00:00 2001 From: reyesj2 <94730068+reyesj2@users.noreply.github.com> Date: Mon, 28 Jul 2025 15:17:04 -0500 Subject: [PATCH 288/315] set 2m timeout --- salt/elasticsearch/tools/sbin/so-elasticsearch-roles-load | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/elasticsearch/tools/sbin/so-elasticsearch-roles-load b/salt/elasticsearch/tools/sbin/so-elasticsearch-roles-load index 93f9d88c2..d1111fe2f 100755 --- a/salt/elasticsearch/tools/sbin/so-elasticsearch-roles-load +++ b/salt/elasticsearch/tools/sbin/so-elasticsearch-roles-load @@ -21,7 +21,7 @@ while [[ "$COUNT" -le 240 ]]; do ELASTICSEARCH_CONNECTED="yes" echo "connected!" # Check cluster health once connected - so-elasticsearch-query _cluster/health?wait_for_status=yellow\&timeout=600s > /dev/null 2>&1 + so-elasticsearch-query _cluster/health?wait_for_status=yellow\&timeout=120s > /dev/null 2>&1 break else ((COUNT+=1)) From 07305d87992a83ab343aebe13080510d3f4eda26 Mon Sep 17 00:00:00 2001 From: reyesj2 <94730068+reyesj2@users.noreply.github.com> Date: Tue, 29 Jul 2025 14:15:43 -0500 Subject: [PATCH 289/315] only show data nodes in disk usage output --- salt/elasticsearch/tools/sbin/so-elasticsearch-troubleshoot | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/salt/elasticsearch/tools/sbin/so-elasticsearch-troubleshoot b/salt/elasticsearch/tools/sbin/so-elasticsearch-troubleshoot index b6b201c3c..1f59610e9 100644 --- a/salt/elasticsearch/tools/sbin/so-elasticsearch-troubleshoot +++ b/salt/elasticsearch/tools/sbin/so-elasticsearch-troubleshoot @@ -121,7 +121,7 @@ watermark_settings() { return 1 fi - if ! disk_allocation_output=$(so-elasticsearch-query _cat/nodes?v\&h=name,ip,disk.used_percent,disk.avail,disk.total\&format=json --fail 2>/dev/null); then + if ! disk_allocation_output=$(so-elasticsearch-query _cat/nodes?v\&h=name,ip,disk.used_percent,disk.avail,disk.total,node.role\&format=json --fail 2>/dev/null); then log_title "ERROR" "Failed to retrieve disk allocation data from Elasticsearch" return 1 fi @@ -139,7 +139,8 @@ watermark_settings() { log_title "LOG" "Disk Usage Check" echo -e "${BOLD}LOW:${GREEN}$low${NC}${BOLD} HIGH:${YELLOW}${high}${NC}${BOLD} FLOOD:${RED}${flood}${NC}\n" - echo "$disk_allocation_output" | jq -r '.[] | "\(.name)|\(.["disk.used_percent"])"' | while IFS='|' read -r node_name disk_used; do + # Only show data nodes (d=data, h=hot, w=warm, c=cold, f=frozen, s=content) + echo "$disk_allocation_output" | jq -r '.[] | select(.["node.role"] | test("[dhwcfs]")) | "\(.name)|\(.["disk.used_percent"])"' | while IFS='|' read -r node_name disk_used; do disk_used_num=$(echo $disk_used | bc) if (( $(echo "$disk_used_num >= $flood_num" | bc -l) )); then From adb1e01c7aa07e2a9b9d3fedc687ff78571bb0fd Mon Sep 17 00:00:00 2001 From: reyesj2 <94730068+reyesj2@users.noreply.github.com> Date: Tue, 29 Jul 2025 15:31:53 -0500 Subject: [PATCH 290/315] exclude so_agent_installer dir from config backups --- salt/backup/tools/sbin/so-config-backup.jinja | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/salt/backup/tools/sbin/so-config-backup.jinja b/salt/backup/tools/sbin/so-config-backup.jinja index 23e407653..7f65bbba3 100755 --- a/salt/backup/tools/sbin/so-config-backup.jinja +++ b/salt/backup/tools/sbin/so-config-backup.jinja @@ -11,6 +11,10 @@ TODAY=$(date '+%Y_%m_%d') BACKUPDIR={{ DESTINATION }} BACKUPFILE="$BACKUPDIR/so-config-backup-$TODAY.tar" MAXBACKUPS=7 +EXCLUSIONS=( + "--exclude=/opt/so/saltstack/local/salt/elasticfleet/files/so_agent-installers" +) + # Create backup dir if it does not exist mkdir -p /nsm/backup @@ -23,7 +27,7 @@ if [ ! -f $BACKUPFILE ]; then # Loop through all paths defined in global.sls, and append them to backup file {%- for LOCATION in BACKUPLOCATIONS %} - tar -rf $BACKUPFILE {{ LOCATION }} + tar -rf $BACKUPFILE "${EXCLUSIONS[@]}" {{ LOCATION }} {%- endfor %} fi From c98042fa80fb621aa1bc99300ac367a3701126c6 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Wed, 30 Jul 2025 09:44:58 -0400 Subject: [PATCH 291/315] match user soqemussh for ssh config. allow for user edits to not be overwritten in ssh config. --- salt/libvirt/ssh/files/config | 2 +- salt/libvirt/ssh/users.sls | 11 +++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/salt/libvirt/ssh/files/config b/salt/libvirt/ssh/files/config index 360d5c182..de6cb7b34 100644 --- a/salt/libvirt/ssh/files/config +++ b/salt/libvirt/ssh/files/config @@ -1,2 +1,2 @@ -Host * +Match user soqemussh IdentityFile /etc/ssh/auth_keys/soqemussh/id_ed25519 diff --git a/salt/libvirt/ssh/users.sls b/salt/libvirt/ssh/users.sls index 0e9c045a0..173a3e095 100644 --- a/salt/libvirt/ssh/users.sls +++ b/salt/libvirt/ssh/users.sls @@ -16,10 +16,17 @@ {% if GLOBALS.is_manager %} -qemu_ssh_client_config: - file.managed: +root_ssh_config: + file.touch: - name: /root/.ssh/config + +qemu_ssh_client_config: + file.blockreplace: + - name: /root/.ssh/config + - marker_start: "# START of block managed by Salt - soqemussh config" + - marker_end: "# END of block managed by Salt - soqemussh config" - source: salt://libvirt/ssh/files/config + - prepend_if_not_found: True {% endif %} From 7b5980bfe54e9bbc73e1f871296ab5e7e0bae205 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Wed, 30 Jul 2025 16:04:10 -0400 Subject: [PATCH 292/315] setup bridge for hypervisor using $MNIC --- setup/so-functions | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/setup/so-functions b/setup/so-functions index c2eb0b349..91d717c11 100755 --- a/setup/so-functions +++ b/setup/so-functions @@ -1187,14 +1187,18 @@ get_minion_type() { } hypervisor_local_states() { - # these states need to run before the first highstate so that we dont deal with the salt-minion restarting - # and we need these setup prior to the highstate - if [ $is_hypervisor ] || [ $is_managerhype ]; then - salt-call state.apply libvirt.64962 --local --file-root=../salt/ -l info - salt-call state.apply libvirt.bridge --local --file-root=../salt/ -l info pillar='{"host": {"mainint": "enp1s0"}}' - fi + # these states need to run before the first highstate so that we dont deal with the salt-minion restarting + # and we need these setup prior to the highstate + info "Check if hypervisor or managerhype" + if [ $is_hypervisor ] || [ $is_managerhype ]; then + info "Running libvirt states for hypervisor" + logCmd "salt-call state.apply libvirt.64962 --local --file-root=../salt/ -l info" + info "Setting up bridge for $MNIC" + salt-call state.apply libvirt.bridge --local --file-root=../salt/ -l info pillar="{\"host\": {\"mainint\": \"$MNIC\"}}" + fi } + install_cleanup() { if [ -f "$temp_install_dir" ]; then info "Installer removing the following files:" From 8720a4540a4cfa8dade196554609fd6dd1ae74c0 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Wed, 30 Jul 2025 16:36:40 -0400 Subject: [PATCH 293/315] remove extra line --- setup/so-functions | 1 - 1 file changed, 1 deletion(-) diff --git a/setup/so-functions b/setup/so-functions index 91d717c11..522446be4 100755 --- a/setup/so-functions +++ b/setup/so-functions @@ -1198,7 +1198,6 @@ hypervisor_local_states() { fi } - install_cleanup() { if [ -f "$temp_install_dir" ]; then info "Installer removing the following files:" From 15cbc626c4fba7a3c9f91bf4fddba548436c340c Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Wed, 30 Jul 2025 16:37:19 -0400 Subject: [PATCH 294/315] resolve for already configured RAID --- salt/hypervisor/tools/sbin/so-nvme-raid1.sh | 120 ++++++++++++++------ 1 file changed, 88 insertions(+), 32 deletions(-) diff --git a/salt/hypervisor/tools/sbin/so-nvme-raid1.sh b/salt/hypervisor/tools/sbin/so-nvme-raid1.sh index 79ccbb33c..ab97e3c88 100644 --- a/salt/hypervisor/tools/sbin/so-nvme-raid1.sh +++ b/salt/hypervisor/tools/sbin/so-nvme-raid1.sh @@ -12,7 +12,7 @@ # - Detects and reports existing RAID configurations # - Thoroughly cleans target drives of any existing data/configurations # - Creates GPT partition tables with RAID-type partitions -# - Establishes RAID-1 array (/dev/md0) for data redundancy +# - Establishes RAID-1 array (${RAID_DEVICE}) for data redundancy # - Formats the array with XFS filesystem for performance # - Automatically mounts at /nsm and configures for boot persistence # - Provides monitoring information for resync operations @@ -37,6 +37,11 @@ # Exit on any error set -e +# Configuration variables +RAID_ARRAY_NAME="md0" +RAID_DEVICE="/dev/${RAID_ARRAY_NAME}" +MOUNT_POINT="/nsm" + # Function to log messages log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" @@ -50,36 +55,68 @@ check_root() { fi } +# Function to find MD arrays using specific devices +find_md_arrays_using_devices() { + local target_devices=("$@") + local found_arrays=() + + # Parse /proc/mdstat to find arrays using our target devices + if [ -f "/proc/mdstat" ]; then + while IFS= read -r line; do + if [[ $line =~ ^(md[0-9]+) ]]; then + local array_name="${BASH_REMATCH[1]}" + local array_path="/dev/$array_name" + + # Check if this array uses any of our target devices + for device in "${target_devices[@]}"; do + if echo "$line" | grep -q "${device##*/}"; then + found_arrays+=("$array_path") + break + fi + done + fi + done < /proc/mdstat + fi + + printf '%s\n' "${found_arrays[@]}" +} + # Function to check if RAID is already set up check_existing_raid() { - if [ -e "/dev/md0" ]; then - if mdadm --detail /dev/md0 &>/dev/null; then - local raid_state=$(mdadm --detail /dev/md0 | grep "State" | awk '{print $3}') - local mount_point="/nsm" - - log "Found existing RAID array /dev/md0 (State: $raid_state)" - - if mountpoint -q "$mount_point"; then - log "RAID is already mounted at $mount_point" - log "Current RAID details:" - mdadm --detail /dev/md0 + local target_devices=("/dev/nvme0n1p1" "/dev/nvme1n1p1") + local found_arrays=($(find_md_arrays_using_devices "${target_devices[@]}")) + + # Check if we found any arrays using our target devices + if [ ${#found_arrays[@]} -gt 0 ]; then + for array_path in "${found_arrays[@]}"; do + if mdadm --detail "$array_path" &>/dev/null; then + local raid_state=$(mdadm --detail "$array_path" | grep "State" | awk '{print $3}') + local mount_point="/nsm" - # Check if resyncing - if grep -q "resync" /proc/mdstat; then - log "RAID is currently resyncing:" - grep resync /proc/mdstat - log "You can monitor progress with: watch -n 60 cat /proc/mdstat" - else - log "RAID is fully synced and operational" + log "Found existing RAID array $array_path (State: $raid_state)" + + if mountpoint -q "$mount_point"; then + log "RAID is already mounted at $mount_point" + log "Current RAID details:" + mdadm --detail "$array_path" + + # Check if resyncing + if grep -q "resync" /proc/mdstat; then + log "RAID is currently resyncing:" + grep resync /proc/mdstat + log "You can monitor progress with: watch -n 60 cat /proc/mdstat" + else + log "RAID is fully synced and operational" + fi + + # Show disk usage + log "Current disk usage:" + df -h "$mount_point" + + exit 0 fi - - # Show disk usage - log "Current disk usage:" - df -h "$mount_point" - - exit 0 fi - fi + done fi # Check if any of the target devices are in use @@ -90,10 +127,29 @@ check_existing_raid() { fi if mdadm --examine "$device" &>/dev/null || mdadm --examine "${device}p1" &>/dev/null; then + # Find the actual array name for this device + local device_arrays=($(find_md_arrays_using_devices "${device}p1")) + local array_name="" + + if [ ${#device_arrays[@]} -gt 0 ]; then + array_name="${device_arrays[0]}" + else + # Fallback: try to find array name from /proc/mdstat + local partition_name="${device##*/}p1" + array_name=$(grep -l "$partition_name" /proc/mdstat 2>/dev/null | head -1) + if [ -n "$array_name" ]; then + array_name=$(grep "^md[0-9]" /proc/mdstat | grep "$partition_name" | awk '{print "/dev/" $1}' | head -1) + fi + # Final fallback + if [ -z "$array_name" ]; then + array_name="$RAID_DEVICE" + fi + fi + log "Error: $device appears to be part of an existing RAID array" log "To reuse this device, you must first:" log "1. Unmount any filesystems" - log "2. Stop the RAID array: mdadm --stop /dev/md0" + log "2. Stop the RAID array: mdadm --stop $array_name" log "3. Zero the superblock: mdadm --zero-superblock ${device}p1" exit 1 fi @@ -183,20 +239,20 @@ main() { fi log "Creating RAID array" - mdadm --create /dev/md0 --level=1 --raid-devices=2 \ + mdadm --create "$RAID_DEVICE" --level=1 --raid-devices=2 \ --metadata=1.2 \ /dev/nvme0n1p1 /dev/nvme1n1p1 \ --force --run log "Creating XFS filesystem" - mkfs.xfs -f /dev/md0 + mkfs.xfs -f "$RAID_DEVICE" log "Creating mount point" mkdir -p /nsm log "Updating fstab" - sed -i '/\/dev\/md0/d' /etc/fstab - echo "/dev/md0 /nsm xfs defaults,nofail 0 0" >> /etc/fstab + sed -i "\|${RAID_DEVICE}|d" /etc/fstab + echo "${RAID_DEVICE} ${MOUNT_POINT} xfs defaults,nofail 0 0" >> /etc/fstab log "Reloading systemd daemon" systemctl daemon-reload @@ -209,7 +265,7 @@ main() { log "RAID setup complete" log "RAID array details:" - mdadm --detail /dev/md0 + mdadm --detail "$RAID_DEVICE" if grep -q "resync" /proc/mdstat; then log "RAID is currently resyncing. You can monitor progress with:" From 930c8147e79a17bf576e410156e08b95398bfb53 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Fri, 1 Aug 2025 08:52:21 -0400 Subject: [PATCH 295/315] simplify cpu and memory regex --- .../hypervisor/soc_hypervisor.yaml.jinja | 36 +------------------ 1 file changed, 1 insertion(+), 35 deletions(-) diff --git a/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja b/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja index 07577a1fb..926263b9d 100644 --- a/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja +++ b/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja @@ -70,41 +70,7 @@ Base domain has not been initialized. {%- endmacro -%} {%- macro update_resource_field(field, free_value, total_value, unit_label) -%} -{%- set resource_regex = '' -%} -{%- if free_value < 10 -%} -{%- set resource_regex = '^[1-' ~ free_value ~ ']$' -%} -{%- elif free_value < 100 -%} -{%- set tens_digit = free_value // 10 -%} -{%- set ones_digit = free_value % 10 -%} -{%- if ones_digit == 0 -%} -{%- set resource_regex = '^([1-9]|[1-' ~ (tens_digit-1) ~ '][0-9]|' ~ tens_digit ~ '0)$' -%} -{%- else -%} -{%- set resource_regex = '^([1-9]|[1-' ~ (tens_digit-1) ~ '][0-9]|' ~ tens_digit ~ '[0-' ~ ones_digit ~ '])$' -%} -{%- endif -%} -{%- elif free_value < 1000 -%} -{%- set hundreds_digit = free_value // 100 -%} -{%- set tens_digit = (free_value % 100) // 10 -%} -{%- set ones_digit = free_value % 10 -%} -{%- if hundreds_digit == 1 -%} -{%- if tens_digit == 0 and ones_digit == 0 -%} -{%- set resource_regex = '^([1-9]|[1-9][0-9]|100)$' -%} -{%- elif tens_digit == 0 -%} -{%- set resource_regex = '^([1-9]|[1-9][0-9]|10[0-' ~ ones_digit ~ '])$' -%} -{%- elif ones_digit == 0 -%} -{%- set resource_regex = '^([1-9]|[1-9][0-9]|10[0-9]|1[1-' ~ tens_digit ~ ']0)$' -%} -{%- else -%} -{%- set resource_regex = '^([1-9]|[1-9][0-9]|10[0-9]|1[1-' ~ (tens_digit-1) ~ '][0-9]|1' ~ tens_digit ~ '[0-' ~ ones_digit ~ '])$' -%} -{%- endif -%} -{%- else -%} -{%- if tens_digit == 0 and ones_digit == 0 -%} -{%- set resource_regex = '^([1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-' ~ (hundreds_digit-1) ~ '][0-9][0-9]|' ~ hundreds_digit ~ '00)$' -%} -{%- elif ones_digit == 0 -%} -{%- set resource_regex = '^([1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-' ~ (hundreds_digit-1) ~ '][0-9][0-9]|' ~ hundreds_digit ~ '[0-' ~ tens_digit ~ ']0)$' -%} -{%- else -%} -{%- set resource_regex = '^([1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-' ~ (hundreds_digit-1) ~ '][0-9][0-9]|' ~ hundreds_digit ~ '[0-' ~ (tens_digit-1) ~ '][0-9]|' ~ hundreds_digit ~ tens_digit ~ '[0-' ~ ones_digit ~ '])$' -%} -{%- endif -%} -{%- endif -%} -{%- endif -%} +{%- set resource_regex = '^[0-9]{1,3}$' -%} {%- do field.update({ 'label': field.label | replace('FREE', free_value | string) | replace('TOTAL', total_value | string), 'regex': resource_regex, From e9e3252bb5114ed5ddd7996fe1f2fcbfbbfadef4 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Fri, 1 Aug 2025 08:53:45 -0400 Subject: [PATCH 296/315] nvme script move nsm if mounted --- salt/hypervisor/tools/sbin/so-nvme-raid1.sh | 92 +++++++++++++++++---- 1 file changed, 75 insertions(+), 17 deletions(-) diff --git a/salt/hypervisor/tools/sbin/so-nvme-raid1.sh b/salt/hypervisor/tools/sbin/so-nvme-raid1.sh index ab97e3c88..9b9fcba2b 100644 --- a/salt/hypervisor/tools/sbin/so-nvme-raid1.sh +++ b/salt/hypervisor/tools/sbin/so-nvme-raid1.sh @@ -95,20 +95,83 @@ check_existing_raid() { log "Found existing RAID array $array_path (State: $raid_state)" - if mountpoint -q "$mount_point"; then - log "RAID is already mounted at $mount_point" + # Check what's currently mounted at /nsm + local current_mount=$(findmnt -n -o SOURCE "$mount_point" 2>/dev/null || echo "") + + if [ -n "$current_mount" ]; then + if [ "$current_mount" = "$array_path" ]; then + log "RAID array $array_path is already correctly mounted at $mount_point" + log "Current RAID details:" + mdadm --detail "$array_path" + + # Check if resyncing + if grep -q "resync" /proc/mdstat; then + log "RAID is currently resyncing:" + grep resync /proc/mdstat + log "You can monitor progress with: watch -n 60 cat /proc/mdstat" + else + log "RAID is fully synced and operational" + fi + + # Show disk usage + log "Current disk usage:" + df -h "$mount_point" + + exit 0 + else + log "Found $mount_point mounted on $current_mount, but RAID array $array_path exists" + log "Will unmount current filesystem and remount on RAID array" + + # Unmount current filesystem + log "Unmounting $mount_point" + umount "$mount_point" + + # Remove old fstab entry + log "Removing old fstab entry for $current_mount" + sed -i "\|$current_mount|d" /etc/fstab + + # Mount the RAID array + log "Mounting RAID array $array_path at $mount_point" + mount "$array_path" "$mount_point" + + # Update fstab + log "Updating fstab for RAID array" + sed -i "\|${array_path}|d" /etc/fstab + echo "${array_path} ${mount_point} xfs defaults,nofail 0 0" >> /etc/fstab + + log "RAID array is now mounted at $mount_point" + log "Current RAID details:" + mdadm --detail "$array_path" + + # Check if resyncing + if grep -q "resync" /proc/mdstat; then + log "RAID is currently resyncing:" + grep resync /proc/mdstat + log "You can monitor progress with: watch -n 60 cat /proc/mdstat" + else + log "RAID is fully synced and operational" + fi + + # Show disk usage + log "Current disk usage:" + df -h "$mount_point" + + exit 0 + fi + else + # /nsm not mounted, mount the RAID array + log "Mounting RAID array $array_path at $mount_point" + mount "$array_path" "$mount_point" + + # Update fstab + log "Updating fstab for RAID array" + sed -i "\|${array_path}|d" /etc/fstab + echo "${array_path} ${mount_point} xfs defaults,nofail 0 0" >> /etc/fstab + + log "RAID array is now mounted at $mount_point" log "Current RAID details:" mdadm --detail "$array_path" - # Check if resyncing - if grep -q "resync" /proc/mdstat; then - log "RAID is currently resyncing:" - grep resync /proc/mdstat - log "You can monitor progress with: watch -n 60 cat /proc/mdstat" - else - log "RAID is fully synced and operational" - fi - # Show disk usage log "Current disk usage:" df -h "$mount_point" @@ -120,12 +183,7 @@ check_existing_raid() { fi # Check if any of the target devices are in use - for device in "/dev/nvme0n1" "/dev/nvme1n1"; do - if lsblk -o NAME,MOUNTPOINT "$device" | grep -q "nsm"; then - log "Error: $device is already mounted at /nsm" - exit 1 - fi - + for device in "/dev/nvme0n1" "/dev/nvme1n1"; do if mdadm --examine "$device" &>/dev/null || mdadm --examine "${device}p1" &>/dev/null; then # Find the actual array name for this device local device_arrays=($(find_md_arrays_using_devices "${device}p1")) From 9d96a117530ea07334304606d3c648e163177bb8 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Fri, 1 Aug 2025 08:55:38 -0400 Subject: [PATCH 297/315] update usage --- salt/hypervisor/tools/sbin/so-nvme-raid1.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/hypervisor/tools/sbin/so-nvme-raid1.sh b/salt/hypervisor/tools/sbin/so-nvme-raid1.sh index 9b9fcba2b..cc9916a4c 100644 --- a/salt/hypervisor/tools/sbin/so-nvme-raid1.sh +++ b/salt/hypervisor/tools/sbin/so-nvme-raid1.sh @@ -30,7 +30,7 @@ # # WARNING: This script will DESTROY all data on the target drives! # -# USAGE: sudo ./raid_setup.sh +# USAGE: sudo ./so-nvme-raid1.sh # ################################################################# From 453c32df0d937361aeab57a240509043a9fea388 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Mon, 4 Aug 2025 15:25:26 -0400 Subject: [PATCH 298/315] handle - in hypervisor hostname --- salt/manager/tools/sbin_jinja/so-salt-cloud | 28 +++++++++---------- salt/orch/dyanno_hypervisor.sls | 4 +-- .../cloud/cloud.profiles.d/socloud.conf.jinja | 2 +- .../engines/master/virtual_node_manager.py | 4 +-- salt/setup/virt/soinstall.map.jinja | 2 +- salt/vm/status/init.sls | 2 +- 6 files changed, 21 insertions(+), 21 deletions(-) diff --git a/salt/manager/tools/sbin_jinja/so-salt-cloud b/salt/manager/tools/sbin_jinja/so-salt-cloud index daa92fa67..0c98750f4 100644 --- a/salt/manager/tools/sbin_jinja/so-salt-cloud +++ b/salt/manager/tools/sbin_jinja/so-salt-cloud @@ -77,10 +77,10 @@ Examples: 1. Static IP Configuration with Multiple PCI Devices: Command: - so-salt-cloud -p sool9-hyper1 vm1_sensor --static4 --ip4 192.168.1.10/24 --gw4 192.168.1.1 \ + so-salt-cloud -p sool9_hyper1 vm1_sensor --static4 --ip4 192.168.1.10/24 --gw4 192.168.1.1 \ --dns4 192.168.1.1,192.168.1.2 --search4 example.local -c 4 -m 8192 -P 0000:c7:00.0 -P 0000:c4:00.0 - This command provisions a VM named vm1_sensor using the sool9-hyper1 profile with the following settings: + This command provisions a VM named vm1_sensor using the sool9_hyper1 profile with the following settings: - Static IPv4 configuration: - IP Address: 192.168.1.10/24 @@ -95,21 +95,21 @@ Examples: 2. DHCP Configuration with Default Hardware Settings: Command: - so-salt-cloud -p sool9-hyper1 vm2_master --dhcp4 + so-salt-cloud -p sool9_hyper1 vm2_master --dhcp4 - This command provisions a VM named vm2_master using the sool9-hyper1 profile with DHCP for network configuration and default hardware settings. + This command provisions a VM named vm2_master using the sool9_hyper1 profile with DHCP for network configuration and default hardware settings. 3. Static IP Configuration without Hardware Specifications: Command: - so-salt-cloud -p sool9-hyper1 vm3_search --static4 --ip4 192.168.1.20/24 --gw4 192.168.1.1 + so-salt-cloud -p sool9_hyper1 vm3_search --static4 --ip4 192.168.1.20/24 --gw4 192.168.1.1 This command provisions a VM named vm3_search with a static IP configuration and default hardware settings. 4. DHCP Configuration with Custom Hardware Specifications and Multiple PCI Devices: Command: - so-salt-cloud -p sool9-hyper1 vm4_node --dhcp4 -c 8 -m 16384 -P 0000:c7:00.0 -P 0000:c4:00.0 -P 0000:c4:00.1 + so-salt-cloud -p sool9_hyper1 vm4_node --dhcp4 -c 8 -m 16384 -P 0000:c7:00.0 -P 0000:c4:00.0 -P 0000:c4:00.1 This command provisions a VM named vm4_node using DHCP for network configuration and custom hardware settings: @@ -120,9 +120,9 @@ Examples: 5. Static IP Configuration with DNS and Search Domain: Command: - so-salt-cloud -p sool9-hyper1 vm1_sensor --static4 --ip4 192.168.1.10/24 --gw4 192.168.1.1 --dns4 192.168.1.1 --search4 example.local + so-salt-cloud -p sool9_hyper1 vm1_sensor --static4 --ip4 192.168.1.10/24 --gw4 192.168.1.1 --dns4 192.168.1.1 --search4 example.local - This command provisions a VM named vm1_sensor using the sool9-hyper1 profile with static IPv4 configuration: + This command provisions a VM named vm1_sensor using the sool9_hyper1 profile with static IPv4 configuration: - Static IPv4 configuration: - IP Address: 192.168.1.10/24 @@ -133,14 +133,14 @@ Examples: 6. Delete a VM with Confirmation: Command: - so-salt-cloud -p sool9-hyper1 vm1_sensor -d + so-salt-cloud -p sool9_hyper1 vm1_sensor -d This command deletes the VM named vm1_sensor and will prompt for confirmation before proceeding. 7. Delete a VM without Confirmation: Command: - so-salt-cloud -p sool9-hyper1 vm1_sensor -yd + so-salt-cloud -p sool9_hyper1 vm1_sensor -yd This command deletes the VM named vm1_sensor without prompting for confirmation. @@ -439,8 +439,8 @@ def call_salt_cloud(profile, vm_name, destroy=False, assume_yes=False): delete_vm(profile, vm_name, assume_yes) return - # Extract hypervisor hostname from profile (e.g., sool9-jpphype1 -> jpphype1) - hypervisor = profile.split('-', 1)[1] if '-' in profile else None + # Extract hypervisor hostname from profile (e.g., sool9_hype1 -> hype1) + hypervisor = profile.split('_', 1)[1] if '_' in profile else None if hypervisor: logger.info("Ensuring host key exists for hypervisor %s", hypervisor) if not _add_hypervisor_host_key(hypervisor): @@ -512,7 +512,7 @@ def format_qcow2_output(operation, result): logger.info(f"{operation} result from {host}: {host_result}") def run_qcow2_modify_hardware_config(profile, vm_name, cpu=None, memory=None, pci_list=None, start=False): - hv_name = profile.split('-')[1] + hv_name = profile.split('_')[1] target = hv_name + "_*" try: @@ -534,7 +534,7 @@ def run_qcow2_modify_hardware_config(profile, vm_name, cpu=None, memory=None, pc logger.error(f"An error occurred while running qcow2.modify_hardware_config: {e}") def run_qcow2_modify_network_config(profile, vm_name, mode, ip=None, gateway=None, dns=None, search_domain=None): - hv_name = profile.split('-')[1] + hv_name = profile.split('_')[1] target = hv_name + "_*" image = '/nsm/libvirt/images/sool9/sool9.qcow2' interface = 'enp1s0' diff --git a/salt/orch/dyanno_hypervisor.sls b/salt/orch/dyanno_hypervisor.sls index a47e3c1b6..9ef8f7252 100644 --- a/salt/orch/dyanno_hypervisor.sls +++ b/salt/orch/dyanno_hypervisor.sls @@ -70,13 +70,13 @@ {% set vm_name = tag.split('/')[2] %} {% do salt.log.debug('dyanno_hypervisor_orch: Got vm_name from tag: ' ~ vm_name) %} {% if tag.endswith('/deploying') %} -{% set hypervisor = data.get('kwargs').get('cloud_grains').get('profile').split('-')[1] %} +{% set hypervisor = data.get('kwargs').get('cloud_grains').get('profile').split('_')[1] %} {% endif %} {# Set the hypervisor #} {# First try to get it from the event #} {% if data.get('profile', False) %} {% do salt.log.debug('dyanno_hypervisor_orch: Did not get cache.grains.') %} -{% set hypervisor = data.profile.split('-')[1] %} +{% set hypervisor = data.profile.split('_')[1] %} {% do salt.log.debug('dyanno_hypervisor_orch: Got hypervisor from data: ' ~ hypervisor) %} {% else %} {% set hypervisor = find_hypervisor_from_status(vm_name) %} diff --git a/salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja b/salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja index 0b795a8ab..94cc85117 100644 --- a/salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja +++ b/salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja @@ -6,7 +6,7 @@ {%- for role, hosts in HYPERVISORS.items() %} {%- for host in hosts.keys() %} -sool9-{{host}}: +sool9_{{host}}: provider: kvm-ssh-{{host}} base_domain: sool9 ip_source: qemu-agent diff --git a/salt/salt/engines/master/virtual_node_manager.py b/salt/salt/engines/master/virtual_node_manager.py index bc098d075..88ccede9c 100644 --- a/salt/salt/engines/master/virtual_node_manager.py +++ b/salt/salt/engines/master/virtual_node_manager.py @@ -650,7 +650,7 @@ def process_vm_creation(hypervisor_path: str, vm_config: dict) -> None: create_vm_tracking_file(hypervisor_path, vm_name, vm_config) # Build and execute so-salt-cloud command - cmd = ['so-salt-cloud', '-p', f'sool9-{hypervisor}', vm_name] + cmd = ['so-salt-cloud', '-p', f'sool9_{hypervisor}', vm_name] # Add network configuration if vm_config['network_mode'] == 'static4': @@ -788,7 +788,7 @@ def process_vm_deletion(hypervisor_path: str, vm_name: str) -> None: log.warning("Failed to read VM config from tracking file %s: %s", vm_file, str(e)) # Attempt VM deletion with so-salt-cloud - cmd = ['so-salt-cloud', '-p', f'sool9-{hypervisor}', vm_name, '-yd'] + cmd = ['so-salt-cloud', '-p', f'sool9_{hypervisor}', vm_name, '-yd'] log.info("Executing: %s", ' '.join(cmd)) result = subprocess.run(cmd, capture_output=True, text=True, check=True) diff --git a/salt/setup/virt/soinstall.map.jinja b/salt/setup/virt/soinstall.map.jinja index d839235b0..45aa503da 100644 --- a/salt/setup/virt/soinstall.map.jinja +++ b/salt/setup/virt/soinstall.map.jinja @@ -4,7 +4,7 @@ Elastic License 2.0. #} {% set nodetype = grains.id.split("_") | last %} -{% set hypervisor = salt['grains.get']('salt-cloud:profile').split('-')[1] %} +{% set hypervisor = salt['grains.get']('salt-cloud:profile').split('_')[1] %} {# Import hardware details from VM hardware tracking file #} {% import_json 'hypervisor/hosts/' ~ hypervisor ~ '/' ~ grains.id as vm_hardware %} diff --git a/salt/vm/status/init.sls b/salt/vm/status/init.sls index d4051e50c..4e530f827 100644 --- a/salt/vm/status/init.sls +++ b/salt/vm/status/init.sls @@ -19,7 +19,7 @@ vm_highstate_trigger: - data: status: Highstate Initiated vm_name: {{ grains.id }} - hypervisor: {{ salt['grains.get']('salt-cloud:profile', '').split('-')[1] }} + hypervisor: {{ salt['grains.get']('salt-cloud:profile', '').split('_')[1] }} - unless: test -f /opt/so/state/highstate_trigger.txt - order: 1 # Ensure this runs early in the highstate process From 4a4146f515a5885705f158199b6354553ea5b6de Mon Sep 17 00:00:00 2001 From: reyesj2 <94730068+reyesj2@users.noreply.github.com> Date: Tue, 5 Aug 2025 13:02:44 -0500 Subject: [PATCH 299/315] ol9 profile update --- salt/stig/files/sos-oscap.xml | 343146 ++++++++++++++++--------------- 1 file changed, 181283 insertions(+), 161863 deletions(-) diff --git a/salt/stig/files/sos-oscap.xml b/salt/stig/files/sos-oscap.xml index cceeee44c..f1e17bcbd 100644 --- a/salt/stig/files/sos-oscap.xml +++ b/salt/stig/files/sos-oscap.xml @@ -1,50 +1,51 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Oracle Linux 9 - oval:ssg-installed_OS_is_ol9_family:def:1 - - - - - - draft - Guide to the Secure Configuration of Oracle Linux 9 - This guide presents a catalog of security-relevant + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Oracle Linux 9 + oval:ssg-installed_OS_is_ol9:def:1 + + + + + + draft + Guide to the Secure Configuration of Oracle Linux 9 + This guide presents a catalog of security-relevant configuration settings for Oracle Linux 9. It is a rendering of content structured in the eXtensible Configuration Checklist Description Format (XCCDF) in order to support security automation. The SCAP content is is available in the scap-security-guide package which is developed at https://www.open-scap.org/security-policies/scap-security-guide. - + + Providing system administrators with such guidance informs them how to securely configure systems under their control in a variety of network roles. Policy makers and baseline creators can use this catalog of settings, with its @@ -62,281 +63,489 @@ processed, in an automated fashion, with tools that support the Security Content Automation Protocol (SCAP). The DISA STIG, which provides required settings for US Department of Defense systems, is one example of a baseline created from this guidance. - - Do not attempt to implement any of the settings in + + Do not attempt to implement any of the settings in this guide without first testing them in a non-operational environment. The creators of this guidance assume no responsibility whatsoever for its use by other parties, and makes no guarantees, expressed or implied, about its quality, reliability, or any other characteristic. - - The SCAP Security Guide Project - + + The SCAP Security Guide Project https://www.open-scap.org/security-policies/scap-security-guide - - Red Hat and Red Hat Enterprise Linux are either registered + + Red Hat and Red Hat Enterprise Linux are either registered trademarks or trademarks of Red Hat, Inc. in the United States and other countries. All other names are registered trademarks or trademarks of their -respective companies. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 0.1.69 - +respective companies. + anssi + app-srg + app-srg-ctr + bsi + ccn + cis + cis-csc + cjis + cobit5 + cui + dcid + disa + hipaa + isa-62443-2009 + isa-62443-2013 + ism + iso27001-2013 + nerc-cip + nist + nist-csf + os-srg + ospp + pcidss + pcidss4 + stigid + stigref + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0.1.76 + SCAP Security Guide Project SCAP Security Guide Project Frank J Cameron (CAM1244) <cameron@ctc.com> 0x66656c6978 <0x66656c6978@users.noreply.github.com> Håvard F. Aasen <havard.f.aasen@pfft.no> + Armando Acosta <armando.acosta@oracle.com> Jack Adolph <jack.adolph@gmail.com> Edgar Aguilar <edgar.aguilar@oracle.com> + akuster <akuster808@gmail.com> Gabe Alford <redhatrises@gmail.com> Firas AlShafei <firas.alshafei@us.abb.com> Rodrigo Alvares <ralvares@redhat.com> @@ -345,16 +554,20 @@ respective companies. angystardust <angystardust@users.noreply.github.com> anivan-suse <anastasija.ivanovic@suse.com> anixon-rh <55244503+anixon-rh@users.noreply.github.com> + Steve Arnold <sarnold@vctlabs.com> Ikko Ashimine <eltociear@gmail.com> Chuck Atkins <chuck.atkins@kitware.com> Bharath B <bhb@redhat.com> Ryan Ballanger <root@rballang-admin-2.fastenal.com> Alex Baranowski <alex@euro-linux.com> Eduardo Barretto <eduardo.barretto@canonical.com> + Paul Bastide <pbastide@us.ibm.com> Molly Jo Bault <Molly.Jo.Bault@ballardtech.com> Andrew Becker <A-Beck@users.noreply.github.com> Gabriel Becker <ggasparb@redhat.com> + BenGui <benoit.guillon1@etu.unilim.fr> Alexander Bergmann <abergmann@suse.com> + Eric Berry <eric@approvedworkman.com> Dale Bewley <dale@bewley.net> Jose Luis BG <bgjoseluis@gmail.com> binyanling <binyanling@uniontech.com> @@ -375,16 +588,21 @@ respective companies. Eric Christensen <echriste@redhat.com> Dan Clark <danclark@redhat.com> Jayson Cofell <1051437+70k10@users.noreply.github.com> + David du Colombier <djc@datadoghq.com> + Commandcracker <lukas.fricke.dev@gmail.com> Caleb Cooper <coopercd@ornl.gov> + CoreyCook8 <129206271+CoreyCook8@users.noreply.github.com> cortesana <acortes@redhat.com> Richard Maciel Costa <richard.maciel.costa@canonical.com> Xavier Coulon <xavier.coulon@suse.com> Deric Crago <deric.crago@gmail.com> crleekwc <crleekwc@gmail.com> + cueball23 <christoph.alms@westnetz.de> cyarbrough76 <42849651+cyarbrough76@users.noreply.github.com> Maura Dailey <maura@eclipse.ncsc.mil> Klaas Demter <demter@atix.de> denknorr <dennis.knorr@suse.com> + dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> dhanushkar-wso2 <dhanushkar@wso2.com> Andrew DiPrinzio <andrew.diprinzio@jhuapl.edu> dom <dominique.blaze@devinci.fr> @@ -396,9 +614,11 @@ respective companies. François Duthilleul <francoisduthilleul@gmail.com> Greg Elin <gregelin@gitmachines.com> eradot4027 <jrtonmac@gmail.com> + ermeratos <manuel.ermer@eviden.net> Alexis Facques <alexis.facques@mythalesgroup.io> Henry Finucane <hfinucane@zscaler.com> Leah Fisher <lfisher047@gmail.com> + Marco Fortina <marco_fortina@hotmail.it> Yavor Georgiev <strandjata@gmail.com> Alijohn Ghassemlouei <alijohn@secureagc.com> Swarup Ghosh <swghosh@redhat.com> @@ -420,8 +640,10 @@ respective companies. Trey Henefield <thenefield@gmail.com> Henning Henkel <henning.henkel@helvetia.ch> hex2a <hex2a@users.noreply.github.com> + hipponix <mirco.santori@gmail.com> John Hooks <jhooks@starscream.pa.jhbcomputers.com> Jakub Hrozek <jhrozek@redhat.com> + Donald Hunter <donald.hunter@gmail.com> De Huo <De.Huo@windriver.com> Robin Price II <robin@redhat.com> Yasir Imam <yimam@redhat.com> @@ -432,6 +654,7 @@ respective companies. Jakub Jelen <jjelen@redhat.com> Jessicahfy <Jessicahfy@users.noreply.github.com> Stephan Joerrens <Stephan.Joerrens@fiduciagad.de> + Simon John <sjohn@tuxcare.com> Hunter Jones <hjones2199@gmail.com> Jono <jono@ubuntu-18.localdomain> justchris1 <justchris1@justchris1.email> @@ -457,13 +680,17 @@ respective companies. Ian Lee <lee1001@llnl.gov> Jarrett Lee <jarrettl@umd.edu> Joseph Lenox <joseph.lenox@collins.com> + lichtblaugue <guenther.lichtblau@eviden.com> Jan Lieskovsky <jlieskov@redhat.com> Markus Linnala <Markus.Linnala@knowit.fi> Flos Lonicerae <lonicerae@gmail.com> Simon Lukasik <slukasik@redhat.com> Milan Lysonek <mlysonek@redhat.com> Fredrik Lysén <fredrik@pipemore.se> + Mab879 <207087+Mab879@users.noreply.github.com> + Mackemania <8738793+Mackemania@users.noreply.github.com> Caitlin Macleod <caitelatte@gmail.com> + Dmitry Makovey <dmakovey@yahoo.com> Nick Maludy <nmaludy@gmail.com> Lokesh Mandvekar <lsm5@fedoraproject.org> Matus Marhefka <mmarhefk@redhat.com> @@ -480,11 +707,16 @@ respective companies. Takuya Mishina <tmishina@jp.ibm.com> Mixer9 <35545791+Mixer9@users.noreply.github.com> mmosel <mmosel@kde.example.com> + Thomas Montague <montague.thomas@gmail.com> + Alan Moore <alan.moore@canonical.com> Zbynek Moravec <zmoravec@redhat.com> Kazuo Moriwaka <moriwaka@users.noreply.github.com> Michael Moseley <michael@eclipse.ncsc.mil> + Nathan Moyer <nmoyer@spectric.com> + Ross Murphy <RossMurphy@ibm.com> Renaud Métrich <rmetrich@redhat.com> Joe Nall <joe@nall.com> + namoyer10 <48189779+namoyer10@users.noreply.github.com> Neiloy <neiloy@redhat.com> Axel Nennker <axel@nennker.de> Michele Newman <mnewman@redhat.com> @@ -506,10 +738,12 @@ respective companies. piggyvenus <piggyvenus@gmail.com> Vojtech Polasek <vpolasek@redhat.com> Orion Poplawski <orion@nwra.com> + Jennifer Power <barnabei.jennifer@gmail.com> Nick Poyant <npoyant@redhat.com> Martin Preisler <mpreisle@redhat.com> Wesley Ceraso Prudencio <wcerasop@redhat.com> Raphael Sanchez Prudencio <rsprudencio@redhat.com> + Miha Purg <miha.purg@canonical.com> T.O. Radzy Radzykewycz <radzy@windriver.com> rain-Qing <yangyuqing6@qq.com> Kenyon Ralph <kenyon@kenyonralph.com> @@ -517,21 +751,27 @@ respective companies. Federico Ramirez <federico.r.ramirez@oracle.com> rchikov <rumen.chikov@suse.com> Rick Renshaw <Richard_Renshaw@xtoenergy.com> + Paul Rensing <prensing@cimetrics.com> Chris Reynolds <c.reynolds82@gmail.com> rhayes <rhayes@rivierautilities.com> Pat Riehecky <riehecky@fnal.gov> rlucente-se-jboss <rlucente@redhat.com> Juan Antonio Osorio Robles <juan.osoriorobles@eu.equinix.com> + Paul Roche <paul.roche@menlosecurity.com> + Jan Rodak <hony.com@seznam.cz> Matt Rogers <mrogers@redhat.com> Jesse Roland <jesse.roland@onyxpoint.com> Joshua Roys <roysjosh@gmail.com> rrenshaw <bofh69@yahoo.com> Chris Ruffalo <chris.ruffalo@gmail.com> + Benjamin Ruland <benjamin.ruland@gmail.com> rumch-se <77793453+rumch-se@users.noreply.github.com> - rutvik23 <rutksh@gmail.com> + Rutvik <rutksh@gmail.com> Ray Shaw (Cont ARL/CISD) rvshaw <rvshaw@esme.arl.army.mil> + Nicolas SAID <nicolas.said@atos.net> Earl Sampson <ESampson@suse.com> sampsone <esampson@suse.com> + Mirco Santori <mirco.santori@roche.com> Willy Santos <wsantos@redhat.com> Nagarjuna Sarvepalli <snagarju@redhat.com> Anderson Sasaki <33833274+ansasaki@users.noreply.github.com> @@ -540,6 +780,7 @@ respective companies. Satoru SATOH <satoru.satoh@gmail.com> Alexander Scheel <alexander.m.scheel@gmail.com> Bryan Schneiders <pschneiders@trisept.com> + Robert Schweikert <rjschwei@suse.com> shaneboulden <shane.boulden@gmail.com> Vincent Shen <wenshen@redhat.com> Dhriti Shikhar <dhriti.shikhar.rokz@gmail.com> @@ -549,13 +790,16 @@ respective companies. THOBY Simon <Simon.THOBY@viveris.fr> Thomas Sjögren <konstruktoid@users.noreply.github.com> Jindrich Skacel <102800748+jskacel@users.noreply.github.com> + Alexandre Skrzyniarz <alexandre.skrzyniarz@laposte.net> Francisco Slavin <fslavin@tresys.com> + sluetze <13255307+sluetze@users.noreply.github.com> Dave Smith <dsmith@eclipse.ncsc.mil> David Smith <dsmith@fornax.eclipse.ncsc.mil> Kevin Spargur <kspargur@redhat.com> Kenneth Stailey <kstailey.lists@gmail.com> Leland Steinke <leland.j.steinke.ctr@mail.mil> Justin Stephenson <jstephen@redhat.com> + steven.y.gui <steven_ygui@163.com> Brian Stinson <brian@bstinson.com> Jake Stookey <jakestookey@gmail.com> Jonathan Sturges <jsturges@redhat.com> @@ -581,766 +825,1251 @@ respective companies. vtrubovics <82443408+vtrubovics@users.noreply.github.com> Samuel Warren <swarren@redhat.com> wcushen <54533890+wcushen@users.noreply.github.com> - Shawn Wells <shawn@shawndwells.io> + Shawn Wells <shawn@redhat.com> + Whidix <31294015+Whidix@users.noreply.github.com> Daniel E. White <linuxdan@users.noreply.github.com> Bernhard M. Wiedemann <bwiedemann@suse.de> Roy Williams <roywilli@roywilli.redhat.com> Willumpie <willumpie@xs4all.nl> Rob Wilmoth <rwilmoth@redhat.com> win97pro <win97pro@protonmail.com> + xcfxr <xucee@qq.com> Lucas Yamanishi <lucas.yamanishi@onyxpoint.com> Xirui Yang <xirui.yang@oracle.com> + Yuqing Yang <yyq01323329@alibaba-inc.com> yarunachalam <yarunachalam@suse.com> Guang Yee <guang.yee@suse.com> Achilleas John Yfantis <ayfantis@redhat.com> YiLin.Li <YiLin.Li@linux.alibaba.com> + yunimoo <yunimoo@nekocake.cafe> YuQing <yyq0391@163.com> + zhaoyun <zhaoyun@kylinos.cn> Kevin Zimmerman <kevin.zimmerman@kitware.com> Luigi Mario Zuccarelli <luzuccar@redhat.com> Jan Černý <jcerny@redhat.com> Michal Šrubař <msrubar@redhat.com> https://github.com/ComplianceAsCode/content/releases/latest - - - [DRAFT] DISA STIG for Oracle Linux 9 - Beta Security Onion Solutions profile - This is a draft profile based on its OL8 version for experimental purposes. -It is not based on the DISA STIG for OL9, because this one was not available at time of -the release. Additionally, the original security profile has been modified by Security Onion Solutions as an experimental implementation of STIGs on a Security Onion grid. - https://public.cyber.mil/stigs/downloads/?_dl_facet_stigs=operating-systems%2Cunix-linux - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - System Settings - Contains rules that check correct system settings. - - Installing and Maintaining Software - The following sections contain information on + + + V1R1 + DISA STIG for Oracle Linux 9 + This profile contains configuration checks that align to the +DISA STIG for Oracle Linux 9 V1R1. + https://public.cyber.mil/stigs/downloads/?_dl_facet_stigs=operating-systems%2Cunix-linux + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + V1R1 + DISA STIG with GUI for Oracle Linux 9 + This profile contains configuration checks that align to the +DISA STIG for Oracle Linux 9 V1R1. + +Warning: The installation and use of a Graphical User Interface (GUI) +increases your attack vector and decreases your overall security posture. If +your Information Systems Security Officer (ISSO) lacks a documented operational +requirement for a graphical user interface, please consider using the +standard DISA STIG for Oracle Linux 9 profile. + https://public.cyber.mil/stigs/downloads/?_dl_facet_stigs=operating-systems%2Cunix-linux + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + System Settings + Contains rules that check correct system settings. + + Installing and Maintaining Software + The following sections contain information on security-relevant choices during the initial operating system installation process and the setup of software -updates. - - Prefer to use a 64-bit Operating System when supported - Prefer installation of 64-bit operating systems when the CPU supports it. - There is no remediation besides installing a 64-bit operating system. - BP28(R10) - Use of a 64-bit operating system offers a few advantages, like a larger address space range for -Address Space Layout Randomization (ASLR) and systematic presence of No eXecute and Execute Disable (NX/XD) protection bits. - - - - - - - - - System and Software Integrity - System and software integrity can be gained by installing antivirus, increasing +updates. + + Prefer to use a 64-bit Operating System when supported + Prefer installation of 64-bit operating systems when the CPU supports it. + There is no remediation besides installing a 64-bit operating system. + R1 + Use of a 64-bit operating system offers a few advantages, like a larger address space range for +Address Space Layout Randomization (ASLR) and systematic presence of No eXecute and Execute Disable (NX/XD) protection bits. + + + + + + + + + System and Software Integrity + System and software integrity can be gained by installing antivirus, increasing system encryption strength with FIPS, verifying installed software, enabling SELinux, installing an Intrusion Prevention System, etc. However, installing or enabling integrity checking tools cannot prevent intrusions, but they can detect that an intrusion may have occurred. Requirements for integrity checking may be highly dependent on the environment in which the system will be used. Snapshot-based approaches such -as AIDE may induce considerable overhead in the presence of frequent software updates. - - Software Integrity Checking - Both the AIDE (Advanced Intrusion Detection Environment) +as AIDE may induce considerable overhead in the presence of frequent software updates. + + Software Integrity Checking + Both the AIDE (Advanced Intrusion Detection Environment) software and the RPM package management system provide mechanisms for verifying the integrity of installed software. AIDE uses snapshots of file metadata (such as hashes) and compares these to current system files in order to detect changes. - + + The RPM package management system can conduct integrity checks by comparing information in its metadata database with -files installed on the system. - - Integrity Scan Notification Email Address - Specify the email address for designated personnel if baseline -configurations are changed in an unauthorized manner. - root@localhost - - - Verify Integrity with RPM - The RPM package management system includes the ability +files installed on the system. + + Integrity Scan Notification Email Address + Specify the email address for designated personnel if baseline +configurations are changed in an unauthorized manner. + root@localhost + + + Verify Integrity with RPM + The RPM package management system includes the ability to verify the integrity of installed packages by comparing the installed files with information about the files taken from the package metadata stored in the RPM database. Although an attacker @@ -1348,100 +2077,119 @@ could corrupt the RPM database (analogous to attacking the AIDE database as described above), this check can still reveal modification of important files. To list which files on the system differ from what is expected by the RPM database: $ rpm -qVa -See the man page for rpm to see a complete explanation of each column. - - Verify File Hashes with RPM - Without cryptographic integrity protections, system -executables and files can be altered by unauthorized users without -detection. -The RPM package management system can check the hashes of -installed software packages, including many that are important to system -security. -To verify that the cryptographic hash of system files and commands matches vendor -values, run the following command to list which files on the system -have hashes that differ from what is expected by the RPM database: +See the man page for rpm to see a complete explanation of each column. + + + Verify File Hashes with RPM + Without cryptographic integrity protections, system executables and files can be altered by +unauthorized users without detection. The RPM package management system can check the hashes +of installed software packages, including many that are important to system security. + +To verify that the cryptographic hash of system files and commands matches vendor values, run +the following command to list which files on the system have hashes that differ from what is +expected by the RPM database: $ rpm -Va --noconfig | grep '^..5' -A "c" in the second column indicates that a file is a configuration file, which -may appropriately be expected to change. If the file was not expected to -change, investigate the cause of the change using audit logs or other means. -The package can then be reinstalled to restore the file. -Run the following command to determine which package owns the file: -$ rpm -qf FILENAME + +If the file was not expected to change, investigate the cause of the change using audit logs +or other means. The package can then be reinstalled to restore the file. Run the following +command to determine which package owns the file: +$ rpm -qf FILENAME + + The package can be reinstalled from a yum repository using the command: -$ sudo yum reinstall PACKAGENAME +$ sudo yum reinstall PACKAGENAME + + Alternatively, the package can be reinstalled from trusted media using the command: -$ sudo rpm -Uvh PACKAGENAME - 11 - 2 - 3 - 9 - 5.10.4.1 - APO01.06 - BAI03.05 - BAI06.01 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS06.02 - 3.3.8 - 3.4.1 - CCI-000366 - CCI-001749 - 164.308(a)(1)(ii)(D) - 164.312(b) - 164.312(c)(1) - 164.312(c)(2) - 164.312(e)(2)(i) - 4.3.4.3.2 - 4.3.4.3.3 - 4.3.4.4.4 - SR 3.1 - SR 3.3 - SR 3.4 - SR 3.8 - SR 7.6 - A.11.2.4 - A.12.1.2 - A.12.2.1 - A.12.5.1 - A.12.6.2 - A.14.1.2 - A.14.1.3 - A.14.2.2 - A.14.2.3 - A.14.2.4 - CM-6(d) - CM-6(c) - SI-7 - SI-7(1) - SI-7(6) - AU-9(3) - PR.DS-6 - PR.DS-8 - PR.IP-1 - Req-11.5 - 11.5.2 - SRG-OS-000480-GPOS-00227 - The hashes of important files like system executables should match the +$ sudo rpm -Uvh PACKAGENAME + + + This rule can take a long time to perform the check and might consume a considerable +amount of resources depending on the number of packages present on the system. It is not a +problem in most cases, but especially systems with a large number of installed packages +can be affected. + 11 + 2 + 3 + 9 + 5.10.4.1 + APO01.06 + BAI03.05 + BAI06.01 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS06.02 + 3.3.8 + 3.4.1 + CCI-000366 + CCI-001749 + 164.308(a)(1)(ii)(D) + 164.312(b) + 164.312(c)(1) + 164.312(c)(2) + 164.312(e)(2)(i) + 4.3.4.3.2 + 4.3.4.3.3 + 4.3.4.4.4 + SR 3.1 + SR 3.3 + SR 3.4 + SR 3.8 + SR 7.6 + A.11.2.4 + A.12.1.2 + A.12.2.1 + A.12.5.1 + A.12.6.2 + A.14.1.2 + A.14.1.3 + A.14.2.2 + A.14.2.3 + A.14.2.4 + CM-6(d) + CM-6(c) + SI-7 + SI-7(1) + SI-7(6) + AU-9(3) + PR.DS-6 + PR.DS-8 + PR.IP-1 + Req-11.5 + SRG-OS-000480-GPOS-00227 + 11.5.2 + OL09-00-000243 + SV-271480r1091152_rule + The hashes of important files like system executables should match the information given by the RPM database. Executables with erroneous hashes could -be a sign of nefarious activity on the system. - +be a sign of nefarious activity on the system. + # Remediation is applicable only in certain platforms +if ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ); then + # Find which files have incorrect hash (not in /etc, because of the system related config files) and then get files names files_with_incorrect_hash="$(rpm -Va --noconfig | grep -E '^..5' | awk '{print $NF}' )" -# From files names get package names and change newline to space, because rpm writes each package to new line -packages_to_reinstall="$(rpm -qf $files_with_incorrect_hash | tr '\n' ' ')" +if [ -n "$files_with_incorrect_hash" ]; then + # From files names get package names and change newline to space, because rpm writes each package to new line + packages_to_reinstall="$(rpm -qf $files_with_incorrect_hash | tr '\n' ' ')" + + yum reinstall -y $packages_to_reinstall + +fi -yum reinstall -y $packages_to_reinstall - - - name: 'Set fact: Package manager reinstall command (dnf)' - set_fact: - package_manager_reinstall_cmd: dnf reinstall -y - when: ansible_distribution == "Fedora" +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto tags: - CJIS-5.10.4.1 + - DISA-STIG-OL09-00-000243 - NIST-800-171-3.3.8 - NIST-800-171-3.4.1 - NIST-800-53-AU-9(3) @@ -1459,13 +2207,17 @@ yum reinstall -y $packages_to_reinstall - restrict_strategy - rpm_verify_hashes -- name: 'Set fact: Package manager reinstall command (yum)' +- name: 'Set fact: Package manager reinstall command' set_fact: package_manager_reinstall_cmd: yum reinstall -y - when: (ansible_distribution == "RedHat" or ansible_distribution == "CentOS" or ansible_distribution - == "OracleLinux") + when: + - not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) + - ansible_distribution in [ "Fedora", "RedHat", "CentOS", "OracleLinux" ] tags: - CJIS-5.10.4.1 + - DISA-STIG-OL09-00-000243 - NIST-800-171-3.3.8 - NIST-800-171-3.4.1 - NIST-800-53-AU-9(3) @@ -1486,9 +2238,14 @@ yum reinstall -y $packages_to_reinstall - name: 'Set fact: Package manager reinstall command (zypper)' set_fact: package_manager_reinstall_cmd: zypper in -f -y - when: ansible_distribution == "SLES" + when: + - not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) + - ansible_distribution == "SLES" tags: - CJIS-5.10.4.1 + - DISA-STIG-OL09-00-000243 - NIST-800-171-3.3.8 - NIST-800-171-3.4.1 - NIST-800-53-AU-9(3) @@ -1513,9 +2270,14 @@ yum reinstall -y $packages_to_reinstall changed_when: false failed_when: files_with_incorrect_hash.rc > 1 check_mode: false - when: (package_manager_reinstall_cmd is defined) + when: + - not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) + - (package_manager_reinstall_cmd is defined) tags: - CJIS-5.10.4.1 + - DISA-STIG-OL09-00-000243 - NIST-800-171-3.3.8 - NIST-800-171-3.4.1 - NIST-800-53-AU-9(3) @@ -1542,10 +2304,14 @@ yum reinstall -y $packages_to_reinstall changed_when: false check_mode: false when: + - not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) - files_with_incorrect_hash.stdout_lines is defined - (files_with_incorrect_hash.stdout_lines | length > 0) tags: - CJIS-5.10.4.1 + - DISA-STIG-OL09-00-000243 - NIST-800-171-3.3.8 - NIST-800-171-3.4.1 - NIST-800-53-AU-9(3) @@ -1568,11 +2334,15 @@ yum reinstall -y $packages_to_reinstall with_items: '{{ list_of_packages.results | map(attribute=''stdout_lines'') | list | unique }}' when: + - not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) - files_with_incorrect_hash.stdout_lines is defined - (package_manager_reinstall_cmd is defined and (files_with_incorrect_hash.stdout_lines | length > 0)) tags: - CJIS-5.10.4.1 + - DISA-STIG-OL09-00-000243 - NIST-800-171-3.3.8 - NIST-800-171-3.4.1 - NIST-800-53-AU-9(3) @@ -1589,134 +2359,139 @@ yum reinstall -y $packages_to_reinstall - no_reboot_needed - restrict_strategy - rpm_verify_hashes - - - - - - - - - - Verify and Correct Ownership with RPM - The RPM package management system can check file ownership -permissions of installed software packages, including many that are -important to system security. After locating a file with incorrect -permissions, which can be found with + + + + + + + + + + Verify and Correct Ownership with RPM + The RPM package management system can check file ownership permissions of installed software +packages, including many that are important to system security. After locating a file with +incorrect permissions, which can be found with: rpm -Va | awk '{ if (substr($0,6,1)=="U" || substr($0,7,1)=="G") print $NF }' run the following command to determine which package owns it: -$ rpm -qf FILENAME -Next, run the following command to reset its permissions to -the correct values: -$ sudo rpm --setugids PACKAGENAME - Profiles may require that specific files be owned by root while the default owner defined -by the vendor is different. -Such files will be reported as a finding and need to be evaluated according to your policy -and deployment environment. - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - 6 - 9 - 5.10.4.1 - APO01.06 - APO11.04 - BAI03.05 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS05.04 - DSS05.07 - DSS06.02 - MEA02.01 - 3.3.8 - 3.4.1 - CCI-001494 - CCI-001496 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.3.7.3 - 4.3.4.3.2 - 4.3.4.3.3 - 4.3.4.4.7 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 2.1 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.8 - SR 2.9 - SR 5.2 - SR 7.6 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.12.1.2 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.5.1 - A.12.6.2 - A.12.7.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CIP-003-8 R4.2 - CIP-003-8 R6 - CIP-007-3 R4 - CIP-007-3 R4.1 - CIP-007-3 R4.2 - CM-6(d) - CM-6(c) - SI-7 - SI-7(1) - SI-7(6) - AU-9(3) - PR.AC-4 - PR.DS-5 - PR.IP-1 - PR.PT-1 - Req-11.5 - 11.5.2 - SRG-OS-000256-GPOS-00097 - SRG-OS-000257-GPOS-00098 - SRG-OS-000278-GPOS-00108 - Ownership of binaries and configuration files that is incorrect -could allow an unauthorized user to gain privileges that they should -not have. The ownership set by the vendor should be maintained. Any -deviations from this baseline should be investigated. - +$ rpm -qf FILENAME + +Next, run the following command to reset its permissions to the correct values: +$ sudo rpm --restore PACKAGENAME + + + Profiles may require that specific files be owned by root while the default owner defined +by the vendor is different. Such files will be reported as a finding and need to be +evaluated according to your policy and deployment environment. + This rule can take a long time to perform the check and might consume a considerable +amount of resources depending on the number of packages present on the system. It is not a +problem in most cases, but especially systems with a large number of installed packages +can be affected. + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + 6 + 9 + 5.10.4.1 + APO01.06 + APO11.04 + BAI03.05 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS05.04 + DSS05.07 + DSS06.02 + MEA02.01 + 3.3.8 + 3.4.1 + CCI-001494 + CCI-001496 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.3.7.3 + 4.3.4.3.2 + 4.3.4.3.3 + 4.3.4.4.7 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 2.1 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.8 + SR 2.9 + SR 5.2 + SR 7.6 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.12.1.2 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.5.1 + A.12.6.2 + A.12.7.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CIP-003-8 R4.2 + CIP-003-8 R6 + CIP-007-3 R4 + CIP-007-3 R4.1 + CIP-007-3 R4.2 + CM-6(d) + CM-6(c) + SI-7 + SI-7(1) + SI-7(6) + AU-9(3) + PR.AC-4 + PR.DS-5 + PR.IP-1 + PR.PT-1 + Req-11.5 + SRG-OS-000256-GPOS-00097 + SRG-OS-000257-GPOS-00098 + SRG-OS-000278-GPOS-00108 + 11.5.2 + Ownership of binaries and configuration files that is incorrect could allow an unauthorized +user to gain privileges that they should not have. The ownership set by the vendor should be +maintained. Any deviations from this baseline should be investigated. + # Remediation is applicable only in certain platforms +if ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ); then + # Declare array to hold set of RPM packages we need to correct permissions for declare -A SETPERMS_RPM_DICT @@ -1735,16 +2510,45 @@ done # correct values for RPM_PACKAGE in "${!SETPERMS_RPM_DICT[@]}" do - rpm --setugids "${RPM_PACKAGE}" + rpm --restore "${RPM_PACKAGE}" done - - - name: Read list of files with incorrect ownership + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - CJIS-5.10.4.1 + - NIST-800-171-3.3.8 + - NIST-800-171-3.4.1 + - NIST-800-53-AU-9(3) + - NIST-800-53-CM-6(c) + - NIST-800-53-CM-6(d) + - NIST-800-53-SI-7 + - NIST-800-53-SI-7(1) + - NIST-800-53-SI-7(6) + - PCI-DSS-Req-11.5 + - PCI-DSSv4-11.5.2 + - high_complexity + - high_severity + - medium_disruption + - no_reboot_needed + - restrict_strategy + - rpm_verify_ownership + +- name: Read list of files with incorrect ownership command: rpm -Va --nodeps --nosignature --nofiledigest --nosize --nomtime --nordev --nocaps --nolinkto --nomode register: files_with_incorrect_ownership failed_when: files_with_incorrect_ownership.rc > 1 changed_when: false check_mode: false + when: not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) tags: - CJIS-5.10.4.1 - NIST-800-171-3.3.8 @@ -1772,7 +2576,11 @@ done register: list_of_packages changed_when: false check_mode: false - when: (files_with_incorrect_ownership.stdout_lines | length > 0) + when: + - not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) + - (files_with_incorrect_ownership.stdout_lines | length > 0) tags: - CJIS-5.10.4.1 - NIST-800-171-3.3.8 @@ -1793,10 +2601,14 @@ done - rpm_verify_ownership - name: Correct file ownership with RPM - command: rpm --setugids '{{ item }}' + command: rpm --restore '{{ item }}' with_items: '{{ list_of_packages.results | map(attribute=''stdout_lines'') | list | unique }}' - when: (files_with_incorrect_ownership.stdout_lines | length > 0) + when: + - not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) + - (files_with_incorrect_ownership.stdout_lines | length > 0) tags: - CJIS-5.10.4.1 - NIST-800-171-3.3.8 @@ -1815,148 +2627,153 @@ done - no_reboot_needed - restrict_strategy - rpm_verify_ownership - - - - - - - - - - Verify and Correct File Permissions with RPM - The RPM package management system can check file access permissions -of installed software packages, including many that are important -to system security. -Verify that the file permissions of system files -and commands match vendor values. Check the file permissions -with the following command: + + + + + + + + + + Verify and Correct File Permissions with RPM + The RPM package management system can check file access permissions of installed software +packages, including many that are important to system security. Verify that the file +permissions of system files and commands match vendor values. Check the file permissions with +the following command: $ sudo rpm -Va | awk '{ if (substr($0,2,1)=="M") print $NF }' Output indicates files that do not match vendor defaults. -After locating a file with incorrect permissions, -run the following command to determine which package owns it: -$ rpm -qf FILENAME - -Next, run the following command to reset its permissions to -the correct values: -$ sudo rpm --setperms PACKAGENAME - Profiles may require that specific files have stricter file permissions than defined by the -vendor. -Such files will be reported as a finding and need to be evaluated according to your policy -and deployment environment. - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - 6 - 9 - 5.10.4.1 - APO01.06 - APO11.04 - BAI03.05 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS05.04 - DSS05.07 - DSS06.02 - MEA02.01 - 3.3.8 - 3.4.1 - CCI-001493 - CCI-001494 - CCI-001495 - CCI-001496 - 164.308(a)(1)(ii)(D) - 164.312(b) - 164.312(c)(1) - 164.312(c)(2) - 164.312(e)(2)(i) - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.3.7.3 - 4.3.4.3.2 - 4.3.4.3.3 - 4.3.4.4.7 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 2.1 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.8 - SR 2.9 - SR 5.2 - SR 7.6 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.12.1.2 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.5.1 - A.12.6.2 - A.12.7.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CIP-003-8 R4.2 - CIP-003-8 R6 - CIP-007-3 R4 - CIP-007-3 R4.1 - CIP-007-3 R4.2 - CM-6(d) - CM-6(c) - SI-7 - SI-7(1) - SI-7(6) - AU-9(3) - CM-6(a) - PR.AC-4 - PR.DS-5 - PR.IP-1 - PR.PT-1 - Req-11.5 - 11.5.2 - SRG-OS-000256-GPOS-00097 - SRG-OS-000257-GPOS-00098 - SRG-OS-000258-GPOS-00099 - SRG-OS-000278-GPOS-00108 - Permissions on system binaries and configuration files that are too generous -could allow an unauthorized user to gain privileges that they should not have. -The permissions set by the vendor should be maintained. Any deviations from -this baseline should be investigated. - + +After locating a file with incorrect permissions, run the following command to determine which +package owns it: +$ rpm -qf FILENAME + + +Next, run the following command to reset its permissions to the correct values: +$ sudo rpm --restore PACKAGENAME + + + Profiles may require that specific files have stricter file permissions than defined by +the vendor. Such files will be reported as a finding and need to be evaluated according to +your policy and deployment environment. + This rule can take a long time to perform the check and might consume a considerable +amount of resources depending on the number of packages present on the system. It is not a +problem in most cases, but especially systems with a large number of installed packages +can be affected. + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + 6 + 9 + 5.10.4.1 + APO01.06 + APO11.04 + BAI03.05 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS05.04 + DSS05.07 + DSS06.02 + MEA02.01 + 3.3.8 + 3.4.1 + CCI-001493 + CCI-001494 + CCI-001495 + CCI-001496 + 164.308(a)(1)(ii)(D) + 164.312(b) + 164.312(c)(1) + 164.312(c)(2) + 164.312(e)(2)(i) + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.3.7.3 + 4.3.4.3.2 + 4.3.4.3.3 + 4.3.4.4.7 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 2.1 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.8 + SR 2.9 + SR 5.2 + SR 7.6 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.12.1.2 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.5.1 + A.12.6.2 + A.12.7.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CIP-003-8 R4.2 + CIP-003-8 R6 + CIP-007-3 R4 + CIP-007-3 R4.1 + CIP-007-3 R4.2 + CM-6(d) + CM-6(c) + SI-7 + SI-7(1) + SI-7(6) + AU-9(3) + CM-6(a) + PR.AC-4 + PR.DS-5 + PR.IP-1 + PR.PT-1 + Req-11.5 + SRG-OS-000256-GPOS-00097 + SRG-OS-000257-GPOS-00098 + SRG-OS-000258-GPOS-00099 + SRG-OS-000278-GPOS-00108 + 11.5.2 + Permissions on system binaries and configuration files that are too generous could allow an +unauthorized user to gain privileges that they should not have. The permissions set by the +vendor should be maintained. Any deviations from this baseline should be investigated. + # Remediation is applicable only in certain platforms +if ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ); then + # Declare array to hold set of RPM packages we need to correct permissions for declare -A SETPERMS_RPM_DICT @@ -1981,14 +2798,44 @@ for RPM_PACKAGE in "${!SETPERMS_RPM_DICT[@]}" do rpm --restore "${RPM_PACKAGE}" done - - - name: Read list of files with incorrect permissions + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - CJIS-5.10.4.1 + - NIST-800-171-3.3.8 + - NIST-800-171-3.4.1 + - NIST-800-53-AU-9(3) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-6(c) + - NIST-800-53-CM-6(d) + - NIST-800-53-SI-7 + - NIST-800-53-SI-7(1) + - NIST-800-53-SI-7(6) + - PCI-DSS-Req-11.5 + - PCI-DSSv4-11.5.2 + - high_complexity + - high_severity + - medium_disruption + - no_reboot_needed + - restrict_strategy + - rpm_verify_permissions + +- name: Read list of files with incorrect permissions command: rpm -Va --nodeps --nosignature --nofiledigest --nosize --nomtime --nordev --nocaps --nolinkto --nouser --nogroup register: files_with_incorrect_permissions failed_when: files_with_incorrect_permissions.rc > 1 changed_when: false check_mode: false + when: not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) tags: - CJIS-5.10.4.1 - NIST-800-171-3.3.8 @@ -2017,7 +2864,11 @@ done register: list_of_packages changed_when: false check_mode: false - when: (files_with_incorrect_permissions.stdout_lines | length > 0) + when: + - not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) + - (files_with_incorrect_permissions.stdout_lines | length > 0) tags: - CJIS-5.10.4.1 - NIST-800-171-3.3.8 @@ -2039,10 +2890,14 @@ done - rpm_verify_permissions - name: Correct file permissions with RPM - command: rpm --setperms '{{ item }}' + command: rpm --restore '{{ item }}' with_items: '{{ list_of_packages.results | map(attribute=''stdout_lines'') | list | unique }}' - when: (files_with_incorrect_permissions.stdout_lines | length > 0) + when: + - not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) + - (files_with_incorrect_permissions.stdout_lines | length > 0) tags: - CJIS-5.10.4.1 - NIST-800-171-3.3.8 @@ -2062,106 +2917,110 @@ done - no_reboot_needed - restrict_strategy - rpm_verify_permissions - - - - - - - - - - - Verify Integrity with AIDE - AIDE conducts integrity checks by comparing information about + + + + + + + + + + + Verify Integrity with AIDE + AIDE conducts integrity checks by comparing information about files with previously-gathered information. Ideally, the AIDE database is created immediately after initial system configuration, and then again after any software update. AIDE is highly configurable, with further configuration -information located in /usr/share/doc/aide-VERSION. - - - Install AIDE - The aide package can be installed with the following command: +information located in /usr/share/doc/aide-VERSION + . + + + Install AIDE + The aide package can be installed with the following command: -$ sudo yum install aide - BP28(R51) - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 2 - 3 - 5 - 7 - 8 - 9 - 5.10.1.3 - APO01.06 - BAI01.06 - BAI02.01 - BAI03.05 - BAI06.01 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS01.03 - DSS03.05 - DSS04.07 - DSS05.02 - DSS05.03 - DSS05.05 - DSS05.07 - DSS06.02 - DSS06.06 - CCI-002696 - CCI-002699 - CCI-001744 - 4.3.4.3.2 - 4.3.4.3.3 - 4.3.4.4.4 - SR 3.1 - SR 3.3 - SR 3.4 - SR 3.8 - SR 4.1 - SR 6.2 - SR 7.6 - 1034 - 1288 - 1341 - 1417 - A.11.2.4 - A.12.1.2 - A.12.2.1 - A.12.4.1 - A.12.5.1 - A.12.6.2 - A.14.1.2 - A.14.1.3 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.14.2.7 - A.15.2.1 - A.8.2.3 - CM-6(a) - DE.CM-1 - DE.CM-7 - PR.DS-1 - PR.DS-6 - PR.DS-8 - PR.IP-1 - PR.IP-3 - Req-11.5 - 11.5.2 - SRG-OS-000445-GPOS-00199 - The AIDE package must be installed if it is to be available for integrity checking. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then +$ sudo yum install aide + + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 2 + 3 + 5 + 7 + 8 + 9 + 5.10.1.3 + APO01.06 + BAI01.06 + BAI02.01 + BAI03.05 + BAI06.01 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS01.03 + DSS03.05 + DSS04.07 + DSS05.02 + DSS05.03 + DSS05.05 + DSS05.07 + DSS06.02 + DSS06.06 + CCI-002696 + CCI-001744 + 4.3.4.3.2 + 4.3.4.3.3 + 4.3.4.4.4 + SR 3.1 + SR 3.3 + SR 3.4 + SR 3.8 + SR 4.1 + SR 6.2 + SR 7.6 + 1034 + 1288 + 1341 + 1417 + A.11.2.4 + A.12.1.2 + A.12.2.1 + A.12.4.1 + A.12.5.1 + A.12.6.2 + A.14.1.2 + A.14.1.3 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.14.2.7 + A.15.2.1 + A.8.2.3 + CM-6(a) + DE.CM-1 + DE.CM-7 + PR.DS-1 + PR.DS-6 + PR.DS-8 + PR.IP-1 + PR.IP-3 + Req-11.5 + SRG-OS-000445-GPOS-00199 + R76 + R79 + 11.5.2 + OL09-00-000300 + SV-271496r1091200_rule + The AIDE package must be installed if it is to be available for integrity checking. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then if ! rpm -q --quiet "aide" ; then yum install -y "aide" @@ -2170,14 +3029,13 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Ensure aide is installed - package: - name: aide - state: present - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + + - name: Gather the package facts + package_facts: + manager: auto tags: - CJIS-5.10.1.3 + - DISA-STIG-OL09-00-000300 - NIST-800-53-CM-6(a) - PCI-DSS-Req-11.5 - PCI-DSSv4-11.5.2 @@ -2187,33 +3045,51 @@ fi - medium_severity - no_reboot_needed - package_aide_installed - - include install_aide + +- name: Ensure aide is installed + package: + name: aide + state: present + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.10.1.3 + - DISA-STIG-OL09-00-000300 + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-11.5 + - PCI-DSSv4-11.5.2 + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - package_aide_installed + + include install_aide class install_aide { package { 'aide': ensure => 'installed', } } - - + + package --add=aide - - + + [[packages]] name = "aide" version = "*" - - - - - - - - - - Build and Test AIDE Database - Run the following command to generate a new database: + + + + + + + + + + Build and Test AIDE Database + Run the following command to generate a new database: $ sudo /usr/sbin/aide --init @@ -2230,79 +3106,82 @@ The newly-generated database can be installed as follows: To initiate a manual check, run the following command: $ sudo /usr/sbin/aide --check -If this check produces any unexpected output, investigate. - BP28(R51) - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 2 - 3 - 5 - 7 - 8 - 9 - 5.10.1.3 - APO01.06 - BAI01.06 - BAI02.01 - BAI03.05 - BAI06.01 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS01.03 - DSS03.05 - DSS04.07 - DSS05.02 - DSS05.03 - DSS05.05 - DSS05.07 - DSS06.02 - DSS06.06 - 4.3.4.3.2 - 4.3.4.3.3 - 4.3.4.4.4 - SR 3.1 - SR 3.3 - SR 3.4 - SR 3.8 - SR 4.1 - SR 6.2 - SR 7.6 - A.11.2.4 - A.12.1.2 - A.12.2.1 - A.12.4.1 - A.12.5.1 - A.12.6.2 - A.14.1.2 - A.14.1.3 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.14.2.7 - A.15.2.1 - A.8.2.3 - CM-6(a) - DE.CM-1 - DE.CM-7 - PR.DS-1 - PR.DS-6 - PR.DS-8 - PR.IP-1 - PR.IP-3 - Req-11.5 - 11.5.2 - SRG-OS-000445-GPOS-00199 - For AIDE to be effective, an initial database of "known-good" information about files -must be captured and it should be able to be verified against the installed files. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then +If this check produces any unexpected output, investigate. + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 2 + 3 + 5 + 7 + 8 + 9 + 5.10.1.3 + APO01.06 + BAI01.06 + BAI02.01 + BAI03.05 + BAI06.01 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS01.03 + DSS03.05 + DSS04.07 + DSS05.02 + DSS05.03 + DSS05.05 + DSS05.07 + DSS06.02 + DSS06.06 + CCI-002696 + CCI-001744 + 4.3.4.3.2 + 4.3.4.3.3 + 4.3.4.4.4 + SR 3.1 + SR 3.3 + SR 3.4 + SR 3.8 + SR 4.1 + SR 6.2 + SR 7.6 + A.11.2.4 + A.12.1.2 + A.12.2.1 + A.12.4.1 + A.12.5.1 + A.12.6.2 + A.14.1.2 + A.14.1.3 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.14.2.7 + A.15.2.1 + A.8.2.3 + CM-6(a) + DE.CM-1 + DE.CM-7 + PR.DS-1 + PR.DS-6 + PR.DS-8 + PR.IP-1 + PR.IP-3 + Req-11.5 + SRG-OS-000445-GPOS-00199 + R76 + R79 + 11.5.2 + For AIDE to be effective, an initial database of "known-good" information about files +must be captured and it should be able to be verified against the installed files. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then if ! rpm -q --quiet "aide" ; then yum install -y "aide" @@ -2314,14 +3193,29 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Ensure AIDE is installed - package: + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - CJIS-5.10.1.3 + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-11.5 + - PCI-DSSv4-11.5.2 + - aide_build_database + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Build and Test AIDE Database - Ensure AIDE Is Installed + ansible.builtin.package: name: '{{ item }}' state: present with_items: - aide - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.10.1.3 - NIST-800-53-CM-6(a) @@ -2334,10 +3228,10 @@ fi - no_reboot_needed - restrict_strategy -- name: Build and Test AIDE Database - command: /usr/sbin/aide --init +- name: Build and Test AIDE Database - Build and Test AIDE Database + ansible.builtin.command: /usr/sbin/aide --init changed_when: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.10.1.3 - NIST-800-53-CM-6(a) @@ -2350,11 +3244,11 @@ fi - no_reboot_needed - restrict_strategy -- name: Check whether the stock AIDE Database exists - stat: +- name: Build and Test AIDE Database - Check Whether the Stock AIDE Database Exists + ansible.builtin.stat: path: /var/lib/aide/aide.db.new.gz register: aide_database_stat - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.10.1.3 - NIST-800-53-CM-6(a) @@ -2367,14 +3261,14 @@ fi - no_reboot_needed - restrict_strategy -- name: Stage AIDE Database - copy: +- name: Build and Test AIDE Database - Stage AIDE Database + ansible.builtin.copy: src: /var/lib/aide/aide.db.new.gz dest: /var/lib/aide/aide.db.gz backup: true remote_src: true when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - (aide_database_stat.stat.exists is defined and aide_database_stat.stat.exists) tags: - CJIS-5.10.1.3 @@ -2387,22 +3281,27 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Configure AIDE to Verify the Audit Tools - The operating system file integrity tool must be configured to protect the integrity of the audit tools. - CCI-001496 - AU-9(3) - AU-9(3).1 - SRG-OS-000278-GPOS-00108 - Protecting the integrity of the tools used for auditing purposes is a + + + + + + + + + + Configure AIDE to Verify the Audit Tools + The operating system file integrity tool must be configured to protect the integrity of the audit tools. + CCI-001496 + CCI-001494 + CCI-001495 + CCI-001493 + AU-9(3) + AU-9(3).1 + SRG-OS-000278-GPOS-00108 + OL09-00-000710 + SV-271569r1091419_rule + Protecting the integrity of the tools used for auditing purposes is a critical step toward ensuring the integrity of audit information. Audit information includes all information (e.g., audit records, audit settings, and audit reports) needed to successfully audit information system @@ -2420,9 +3319,9 @@ activity from the audit logs. To address this risk, audit tools must be cryptographically signed to provide the capability to identify when the audit tools have been modified, manipulated, or replaced. An example is a checksum hash of the file or -files. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then +files. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then if ! rpm -q --quiet "aide" ; then yum install -y "aide" @@ -2482,15 +3381,46 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Ensure aide is installed + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-000710 + - NIST-800-53-AU-9(3) + - NIST-800-53-AU-9(3).1 + - aide_check_audit_tools + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Configure AIDE to Verify the Audit Tools - Gather List of Packages + tags: + - DISA-STIG-OL09-00-000710 + - NIST-800-53-AU-9(3) + - NIST-800-53-AU-9(3).1 + - aide_check_audit_tools + - aide_check_audit_tools + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + ansible.builtin.package_facts: + manager: auto + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + +- name: Ensure aide is installed package: name: '{{ item }}' state: present with_items: - aide - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-000710 - NIST-800-53-AU-9(3) - NIST-800-53-AU-9(3).1 - aide_check_audit_tools @@ -2510,8 +3440,9 @@ fi - /usr/sbin/ausearch - /usr/sbin/autrace - /usr/sbin/rsyslogd - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-000710 - NIST-800-53-AU-9(3) - NIST-800-53-AU-9(3).1 - aide_check_audit_tools @@ -2527,8 +3458,9 @@ fi regexp: ^{{ item }}\s line: '{{ item }} p+i+n+u+g+s+b+acl+xattrs+sha512' with_items: '{{ audit_tools }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-000710 - NIST-800-53-AU-9(3) - NIST-800-53-AU-9(3).1 - aide_check_audit_tools @@ -2543,8 +3475,9 @@ fi path: /etc/aide.conf line: '{{ item }} p+i+n+u+g+s+b+acl+xattrs+sha512' with_items: '{{ audit_tools }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-000710 - NIST-800-53-AU-9(3) - NIST-800-53-AU-9(3).1 - aide_check_audit_tools @@ -2553,114 +3486,118 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Configure Periodic Execution of AIDE - At a minimum, AIDE should be configured to run a weekly scan. + + + + + + + + + + Configure Periodic Execution of AIDE + At a minimum, AIDE should be configured to run a weekly scan. To implement a daily execution of AIDE at 4:05am using cron, add the following line to /etc/crontab: 05 4 * * * root /usr/sbin/aide --check To implement a weekly execution of AIDE at 4:05am using cron, add the following line to /etc/crontab: 05 4 * * 0 root /usr/sbin/aide --check AIDE can be executed periodically through other means; this is merely one example. The usage of cron's special time codes, such as @daily and -@weekly is acceptable. - BP28(R51) - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 2 - 3 - 5 - 7 - 8 - 9 - 5.10.1.3 - APO01.06 - BAI01.06 - BAI02.01 - BAI03.05 - BAI06.01 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS01.03 - DSS03.05 - DSS04.07 - DSS05.02 - DSS05.03 - DSS05.05 - DSS05.07 - DSS06.02 - DSS06.06 - CCI-001744 - CCI-002699 - CCI-002702 - 4.3.4.3.2 - 4.3.4.3.3 - 4.3.4.4.4 - SR 3.1 - SR 3.3 - SR 3.4 - SR 3.8 - SR 4.1 - SR 6.2 - SR 7.6 - A.11.2.4 - A.12.1.2 - A.12.2.1 - A.12.4.1 - A.12.5.1 - A.12.6.2 - A.14.1.2 - A.14.1.3 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.14.2.7 - A.15.2.1 - A.8.2.3 - SI-7 - SI-7(1) - CM-6(a) - DE.CM-1 - DE.CM-7 - PR.DS-1 - PR.DS-6 - PR.DS-8 - PR.IP-1 - PR.IP-3 - Req-11.5 - 11.5.2 - SRG-OS-000363-GPOS-00150 - SRG-OS-000446-GPOS-00200 - SRG-OS-000447-GPOS-00201 - By default, AIDE does not install itself for periodic execution. Periodically +@weekly is acceptable. + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 2 + 3 + 5 + 7 + 8 + 9 + 5.10.1.3 + APO01.06 + BAI01.06 + BAI02.01 + BAI03.05 + BAI06.01 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS01.03 + DSS03.05 + DSS04.07 + DSS05.02 + DSS05.03 + DSS05.05 + DSS05.07 + DSS06.02 + DSS06.06 + CCI-002702 + CCI-001744 + CCI-002699 + 4.3.4.3.2 + 4.3.4.3.3 + 4.3.4.4.4 + SR 3.1 + SR 3.3 + SR 3.4 + SR 3.8 + SR 4.1 + SR 6.2 + SR 7.6 + A.11.2.4 + A.12.1.2 + A.12.2.1 + A.12.4.1 + A.12.5.1 + A.12.6.2 + A.14.1.2 + A.14.1.3 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.14.2.7 + A.15.2.1 + A.8.2.3 + SI-7 + SI-7(1) + CM-6(a) + DE.CM-1 + DE.CM-7 + PR.DS-1 + PR.DS-6 + PR.DS-8 + PR.IP-1 + PR.IP-3 + Req-11.5 + SRG-OS-000363-GPOS-00150 + SRG-OS-000446-GPOS-00200 + SRG-OS-000447-GPOS-00201 + R76 + 11.5.2 + OL09-00-000301 + SV-271497r1092471_rule + By default, AIDE does not install itself for periodic execution. Periodically running AIDE is necessary to reveal unexpected changes in installed files. - + + Unauthorized changes to the baseline configuration could make the system vulnerable to various attacks or allow unauthorized access to the operating system. Changes to operating system configurations can have unintended side effects, some of which may be relevant to security. - + + Detecting such changes and providing an automated response can help avoid unintended, negative consequences that could ultimately affect the security state of the operating system. The operating system's Information Management Officer (IMO)/Information System Security Officer (ISSO) and System Administrators (SAs) must be notified via email and/or -monitoring system trap when there is an unauthorized modification of a configuration item. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then +monitoring system trap when there is an unauthorized modification of a configuration item. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then if ! rpm -q --quiet "aide" ; then yum install -y "aide" @@ -2676,16 +3613,35 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Ensure AIDE is installed + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - CJIS-5.10.1.3 + - DISA-STIG-OL09-00-000301 + - NIST-800-53-CM-6(a) + - NIST-800-53-SI-7 + - NIST-800-53-SI-7(1) + - PCI-DSS-Req-11.5 + - PCI-DSSv4-11.5.2 + - aide_periodic_cron_checking + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure AIDE is installed package: name: '{{ item }}' state: present with_items: - aide - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.10.1.3 + - DISA-STIG-OL09-00-000301 - NIST-800-53-CM-6(a) - NIST-800-53-SI-7 - NIST-800-53-SI-7(1) @@ -2702,10 +3658,11 @@ fi set_fact: cron_pkg_name: cronie when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - ansible_os_family == "RedHat" or ansible_os_family == "Suse" tags: - CJIS-5.10.1.3 + - DISA-STIG-OL09-00-000301 - NIST-800-53-CM-6(a) - NIST-800-53-SI-7 - NIST-800-53-SI-7(1) @@ -2722,10 +3679,11 @@ fi set_fact: cron_pkg_name: cron when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - ansible_os_family == "Debian" tags: - CJIS-5.10.1.3 + - DISA-STIG-OL09-00-000301 - NIST-800-53-CM-6(a) - NIST-800-53-SI-7 - NIST-800-53-SI-7(1) @@ -2742,9 +3700,10 @@ fi package: name: '{{ cron_pkg_name }}' state: present - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.10.1.3 + - DISA-STIG-OL09-00-000301 - NIST-800-53-CM-6(a) - NIST-800-53-SI-7 - NIST-800-53-SI-7(1) @@ -2765,9 +3724,10 @@ fi weekday: 0 user: root job: /usr/sbin/aide --check - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.10.1.3 + - DISA-STIG-OL09-00-000301 - NIST-800-53-CM-6(a) - NIST-800-53-SI-7 - NIST-800-53-SI-7(1) @@ -2779,89 +3739,93 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Configure Notification of Post-AIDE Scan Details - AIDE should notify appropriate personnel of the details of a scan after the scan has been run. + + + + + + + + + + Configure Notification of Post-AIDE Scan Details + AIDE should notify appropriate personnel of the details of a scan after the scan has been run. If AIDE has already been configured for periodic execution in /etc/crontab, append the following line to the existing AIDE line: | /bin/mail -s "$(hostname) - AIDE Integrity Check" root@localhost Otherwise, add the following line to /etc/crontab: 05 4 * * * root /usr/sbin/aide --check | /bin/mail -s "$(hostname) - AIDE Integrity Check" root@localhost -AIDE can be executed periodically through other means; this is merely one example. - BP28(R51) - 1 - 11 - 12 - 13 - 15 - 16 - 2 - 3 - 5 - 7 - 8 - 9 - BAI01.06 - BAI06.01 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS01.03 - DSS03.05 - DSS05.02 - DSS05.05 - DSS05.07 - CCI-001744 - CCI-002699 - CCI-002702 - 4.3.4.3.2 - 4.3.4.3.3 - SR 6.2 - SR 7.6 - A.12.1.2 - A.12.4.1 - A.12.5.1 - A.12.6.2 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.14.2.7 - A.15.2.1 - CM-6(a) - CM-3(5) - DE.CM-1 - DE.CM-7 - PR.IP-1 - PR.IP-3 - SRG-OS-000363-GPOS-00150 - SRG-OS-000446-GPOS-00200 - SRG-OS-000447-GPOS-00201 - Unauthorized changes to the baseline configuration could make the system vulnerable +AIDE can be executed periodically through other means; this is merely one example. + 1 + 11 + 12 + 13 + 15 + 16 + 2 + 3 + 5 + 7 + 8 + 9 + BAI01.06 + BAI06.01 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS01.03 + DSS03.05 + DSS05.02 + DSS05.05 + DSS05.07 + CCI-002702 + CCI-001744 + CCI-002699 + 4.3.4.3.2 + 4.3.4.3.3 + SR 6.2 + SR 7.6 + A.12.1.2 + A.12.4.1 + A.12.5.1 + A.12.6.2 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.14.2.7 + A.15.2.1 + CM-6(a) + CM-3(5) + DE.CM-1 + DE.CM-7 + PR.IP-1 + PR.IP-3 + SRG-OS-000363-GPOS-00150 + SRG-OS-000446-GPOS-00200 + SRG-OS-000447-GPOS-00201 + R76 + OL09-00-000301 + SV-271497r1092471_rule + Unauthorized changes to the baseline configuration could make the system vulnerable to various attacks or allow unauthorized access to the operating system. Changes to operating system configurations can have unintended side effects, some of which may be relevant to security. - + + Detecting such changes and providing an automated response can help avoid unintended, negative consequences that could ultimately affect the security state of the operating system. The operating system's Information Management Officer (IMO)/Information System Security Officer (ISSO) and System Administrators (SAs) must be notified via email and/or -monitoring system trap when there is an unauthorized modification of a configuration item. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then +monitoring system trap when there is an unauthorized modification of a configuration item. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then if ! rpm -q --quiet "aide" ; then yum install -y "aide" fi -var_aide_scan_notification_email='' +var_aide_scan_notification_email='' + CRONTAB=/etc/crontab @@ -2883,10 +3847,23 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: XCCDF Value var_aide_scan_notification_email # promote to variable + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-000301 + - NIST-800-53-CM-3(5) + - NIST-800-53-CM-6(a) + - aide_scan_notification + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy +- name: XCCDF Value var_aide_scan_notification_email # promote to variable set_fact: - var_aide_scan_notification_email: !!str + var_aide_scan_notification_email: !!str tags: - always @@ -2896,8 +3873,9 @@ fi state: present with_items: - aide - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-000301 - NIST-800-53-CM-3(5) - NIST-800-53-CM-6(a) - aide_scan_notification @@ -2916,8 +3894,9 @@ fi user: root job: /usr/sbin/aide --check | /bin/mail -s "$(hostname) - AIDE Integrity Check" {{ var_aide_scan_notification_email }} - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-000301 - NIST-800-53-CM-3(5) - NIST-800-53-CM-6(a) - aide_scan_notification @@ -2926,17 +3905,216 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Configure AIDE to Verify Access Control Lists (ACLs) - By default, the acl option is added to the FIPSR ruleset in AIDE. + + + + + + + + + + Configure AIDE to Use FIPS 140-2 for Validating Hashes + By default, the sha512 option is added to the NORMAL ruleset in AIDE. +If using a custom ruleset or the sha512 option is missing, add sha512 +to the appropriate ruleset. +For example, add sha512 to the following line in /etc/aide.conf: +NORMAL = FIPSR+sha512 +AIDE rules can be configured in multiple ways; this is merely one example that is already +configured by default. + System Crypto Modules must be provided by a vendor that undergoes +FIPS-140 certifications. +FIPS-140 is applicable to all Federal agencies that use +cryptographic-based security systems to protect sensitive information +in computer and telecommunication systems (including voice systems) as +defined in Section 5131 of the Information Technology Management Reform +Act of 1996, Public Law 104-106. This standard shall be used in +designing and implementing cryptographic modules that Federal +departments and agencies operate or are operated for them under +contract. See https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.140-2.pdf +To meet this, the system has to have cryptographic software provided by +a vendor that has undergone this certification. This means providing +documentation, test results, design information, and independent third +party review by an accredited lab. While open source software is +capable of meeting this, it does not meet FIPS-140 unless the vendor +submits to this process. + 2 + 3 + APO01.06 + BAI03.05 + BAI06.01 + DSS06.02 + 3.13.11 + CCI-000366 + 4.3.4.4.4 + SR 3.1 + SR 3.3 + SR 3.4 + SR 3.8 + A.11.2.4 + A.12.2.1 + A.12.5.1 + A.14.1.2 + A.14.1.3 + A.14.2.4 + SI-7 + SI-7(1) + CM-6(a) + PR.DS-6 + PR.DS-8 + SRG-OS-000480-GPOS-00227 + OL09-00-000302 + SV-271498r1091206_rule + File integrity tools use cryptographic hashes for verifying file contents and directories +have not been altered. These hashes must be FIPS 140-2 approved cryptographic hashes. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +if ! rpm -q --quiet "aide" ; then + yum install -y "aide" +fi + +aide_conf="/etc/aide.conf" +forbidden_hashes=(sha1 rmd160 sha256 whirlpool tiger haval gost crc32) + +groups=$(LC_ALL=C grep "^[A-Z][A-Za-z_]*" $aide_conf | cut -f1 -d ' ' | tr -d ' ' | sort -u) + +for group in $groups +do + config=$(grep "^$group\s*=" $aide_conf | cut -f2 -d '=' | tr -d ' ') + + if ! [[ $config = *sha512* ]] + then + config=$config"+sha512" + fi + + for hash in "${forbidden_hashes[@]}" + do + config=$(echo $config | sed "s/$hash//") + done + + config=$(echo $config | sed "s/^\+*//") + config=$(echo $config | sed "s/\+\++/+/") + config=$(echo $config | sed "s/\+$//") + + sed -i "s/^$group\s*=.*/$group = $config/g" $aide_conf +done + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-000302 + - NIST-800-171-3.13.11 + - NIST-800-53-CM-6(a) + - NIST-800-53-SI-7 + - NIST-800-53-SI-7(1) + - aide_use_fips_hashes + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Configure AIDE to Use FIPS 140-2 for Validating Hashes - Ensure aide is installed + ansible.builtin.package: + name: aide + state: present + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-000302 + - NIST-800-171-3.13.11 + - NIST-800-53-CM-6(a) + - NIST-800-53-SI-7 + - NIST-800-53-SI-7(1) + - aide_use_fips_hashes + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Configure AIDE to Use FIPS 140-2 for Validating Hashes - Set-fact aide config + file and forbidden hashes + ansible.builtin.set_fact: + aide_conf: /etc/aide.conf + forbidden_hashes: + - sha1 + - rmd160 + - sha256 + - whirlpool + - tiger + - haval + - gost + - crc32 + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-000302 + - NIST-800-171-3.13.11 + - NIST-800-53-CM-6(a) + - NIST-800-53-SI-7 + - NIST-800-53-SI-7(1) + - aide_use_fips_hashes + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Configure AIDE to Use FIPS 140-2 for Validating Hashes - Remove forbidden + hashes + ansible.builtin.replace: + path: '{{ aide_conf }}' + regexp: (^\s*[A-Z][A-Za-z_]*\s*=.*?)({{ item }}\+|\+?{{ item }})(.*) + replace: \1\3 + loop: '{{ forbidden_hashes }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-000302 + - NIST-800-171-3.13.11 + - NIST-800-53-CM-6(a) + - NIST-800-53-SI-7 + - NIST-800-53-SI-7(1) + - aide_use_fips_hashes + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Configure AIDE to Use FIPS 140-2 for Validating Hashes - Set sha512 + ansible.builtin.replace: + path: '{{ aide_conf }}' + regexp: (^\s*[A-Z][A-Za-z_]*\s*=)((?:(?!\+?sha512).)*)\s*$ + replace: \1\2+sha512 + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-000302 + - NIST-800-171-3.13.11 + - NIST-800-53-CM-6(a) + - NIST-800-53-SI-7 + - NIST-800-53-SI-7(1) + - aide_use_fips_hashes + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Configure AIDE to Verify Access Control Lists (ACLs) + By default, the acl option is added to the FIPSR ruleset in AIDE. If using a custom ruleset or the acl option is missing, add acl to the appropriate ruleset. For example, add acl to the following line in /etc/aide.conf: @@ -2944,37 +4122,41 @@ For example, add acl to the following line in AIDE rules can be configured in multiple ways; this is merely one example that is already configured by default. + The remediation provided with this rule adds acl to all rule sets available in -/etc/aide.conf - BP28(R51) - 2 - 3 - APO01.06 - BAI03.05 - BAI06.01 - DSS06.02 - CCI-000366 - 4.3.4.4.4 - SR 3.1 - SR 3.3 - SR 3.4 - SR 3.8 - A.11.2.4 - A.12.2.1 - A.12.5.1 - A.14.1.2 - A.14.1.3 - A.14.2.4 - SI-7 - SI-7(1) - CM-6(a) - PR.DS-6 - PR.DS-8 - SRG-OS-000480-GPOS-00227 - ACLs can provide permissions beyond those permitted through the file mode and must be -verified by the file integrity tools. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then +/etc/aide.conf + + 2 + 3 + APO01.06 + BAI03.05 + BAI06.01 + DSS06.02 + CCI-000366 + 4.3.4.4.4 + SR 3.1 + SR 3.3 + SR 3.4 + SR 3.8 + A.11.2.4 + A.12.2.1 + A.12.5.1 + A.14.1.2 + A.14.1.3 + A.14.2.4 + SI-7 + SI-7(1) + CM-6(a) + PR.DS-6 + PR.DS-8 + SRG-OS-000480-GPOS-00227 + R76 + OL09-00-000303 + SV-271499r1091209_rule + ACLs can provide permissions beyond those permitted through the file mode and must be +verified by the file integrity tools. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then if ! rpm -q --quiet "aide" ; then yum install -y "aide" @@ -2982,8 +4164,10 @@ fi aide_conf="/etc/aide.conf" + groups=$(LC_ALL=C grep "^[A-Z][A-Za-z_]*" $aide_conf | grep -v "^ALLXTRAHASHES" | cut -f1 -d '=' | tr -d ' ' | sort -u) + for group in $groups do config=$(grep "^$group\s*=" $aide_conf | cut -f2 -d '=' | tr -d ' ') @@ -3003,14 +4187,12 @@ done else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather list of packages + + - name: Gather list of packages package_facts: manager: auto - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - '' tags: + - DISA-STIG-OL09-00-000303 - NIST-800-53-CM-6(a) - NIST-800-53-SI-7 - NIST-800-53-SI-7(1) @@ -3026,10 +4208,11 @@ fi set -o pipefail LC_ALL=C grep "^[A-Z][A-Za-z_]*" /etc/aide.conf | grep -v "^ALLXTRAHASHES" | cut -f1 -d '=' | tr -d ' ' | sort -u || true when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '''aide'' in ansible_facts.packages' register: find_rules_groups_results tags: + - DISA-STIG-OL09-00-000303 - NIST-800-53-CM-6(a) - NIST-800-53-SI-7 - NIST-800-53-SI-7(1) @@ -3046,10 +4229,11 @@ fi regexp: (^\s*{{ item }}\s*=\s*)(?!.*acl)([^\s]*) replace: \g<1>\g<2>+acl when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - '''aide'' in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_rules_groups_results is not skipped and "'aide' in ansible_facts.packages" with_items: '{{ find_rules_groups_results.stdout_lines | map(''trim'') | list }}' tags: + - DISA-STIG-OL09-00-000303 - NIST-800-53-CM-6(a) - NIST-800-53-SI-7 - NIST-800-53-SI-7(1) @@ -3059,17 +4243,17 @@ fi - low_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Configure AIDE to Verify Extended Attributes - By default, the xattrs option is added to the FIPSR ruleset in AIDE. + + + + + + + + + + Configure AIDE to Verify Extended Attributes + By default, the xattrs option is added to the FIPSR ruleset in AIDE. If using a custom ruleset or the xattrs option is missing, add xattrs to the appropriate ruleset. For example, add xattrs to the following line in /etc/aide.conf: @@ -3077,37 +4261,41 @@ For example, add xattrs to the following line in xattrs to all rule sets available in -/etc/aide.conf - BP28(R51) - 2 - 3 - APO01.06 - BAI03.05 - BAI06.01 - DSS06.02 - CCI-000366 - 4.3.4.4.4 - SR 3.1 - SR 3.3 - SR 3.4 - SR 3.8 - A.11.2.4 - A.12.2.1 - A.12.5.1 - A.14.1.2 - A.14.1.3 - A.14.2.4 - SI-7 - SI-7(1) - CM-6(a) - PR.DS-6 - PR.DS-8 - SRG-OS-000480-GPOS-00227 - Extended attributes in file systems are used to contain arbitrary data and file metadata -with security implications. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then +/etc/aide.conf + + 2 + 3 + APO01.06 + BAI03.05 + BAI06.01 + DSS06.02 + CCI-000366 + 4.3.4.4.4 + SR 3.1 + SR 3.3 + SR 3.4 + SR 3.8 + A.11.2.4 + A.12.2.1 + A.12.5.1 + A.14.1.2 + A.14.1.3 + A.14.2.4 + SI-7 + SI-7(1) + CM-6(a) + PR.DS-6 + PR.DS-8 + SRG-OS-000480-GPOS-00227 + R76 + OL09-00-000304 + SV-271500r1091212_rule + Extended attributes in file systems are used to contain arbitrary data and file metadata +with security implications. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then if ! rpm -q --quiet "aide" ; then yum install -y "aide" @@ -3115,8 +4303,10 @@ fi aide_conf="/etc/aide.conf" + groups=$(LC_ALL=C grep "^[A-Z][A-Za-z_]*" $aide_conf | grep -v "^ALLXTRAHASHES" | cut -f1 -d '=' | tr -d ' ' | sort -u) + for group in $groups do config=$(grep "^$group\s*=" $aide_conf | cut -f2 -d '=' | tr -d ' ') @@ -3136,14 +4326,12 @@ done else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather list of packages + + - name: Gather list of packages package_facts: manager: auto - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - '' tags: + - DISA-STIG-OL09-00-000304 - NIST-800-53-CM-6(a) - NIST-800-53-SI-7 - NIST-800-53-SI-7(1) @@ -3159,10 +4347,11 @@ fi set -o pipefail LC_ALL=C grep "^[A-Z][A-Za-z_]*" /etc/aide.conf | grep -v "^ALLXTRAHASHES" | cut -f1 -d '=' | tr -d ' ' | sort -u || true when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '''aide'' in ansible_facts.packages' register: find_rules_groups_results tags: + - DISA-STIG-OL09-00-000304 - NIST-800-53-CM-6(a) - NIST-800-53-SI-7 - NIST-800-53-SI-7(1) @@ -3179,10 +4368,11 @@ fi regexp: (^\s*{{ item }}\s*=\s*)(?!.*xattrs)([^\s]*) replace: \g<1>\g<2>+xattrs when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - '''aide'' in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_rules_groups_results is not skipped and "'aide' in ansible_facts.packages" with_items: '{{ find_rules_groups_results.stdout_lines | map(''trim'') | list }}' tags: + - DISA-STIG-OL09-00-000304 - NIST-800-53-CM-6(a) - NIST-800-53-SI-7 - NIST-800-53-SI-7(1) @@ -3192,32 +4382,32 @@ fi - low_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Audit Tools Must Be Group-owned by Root - Oracle Linux 9 systems providing tools to interface with audit information will leverage user permissions and roles identifying the user accessing the tools, and the corresponding rights the user enjoys, to make access decisions regarding the access to audit tools. + + + + + + + + + + Audit Tools Must Be Group-owned by Root + Oracle Linux 9 systems providing tools to interface with audit information will leverage user permissions and roles identifying the user accessing the tools, and the corresponding rights the user enjoys, to make access decisions regarding the access to audit tools. Audit tools include, but are not limited to, vendor-provided and open source audit tools needed to successfully view and manipulate audit information system activity and records. Audit tools include custom queries and report generators. -Audit tools must have the correct group owner. - CCI-001493 - CCI-001494 - CCI-001495 - AU-9 - SRG-OS-000256-GPOS-00097 - SRG-OS-000257-GPOS-00098 - SRG-OS-000258-GPOS-00099 - Protecting audit information also includes identifying and protecting the tools used to view and manipulate log data. -Therefore, protecting audit tools is necessary to prevent unauthorized operations on audit information. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then +Audit tools must have the correct group owner. + CCI-001493 + AU-9 + SRG-OS-000256-GPOS-00097 + SRG-OS-000257-GPOS-00098 + SRG-OS-000258-GPOS-00099 + OL09-00-002570 + SV-271824r1092184_rule + Protecting audit information also includes identifying and protecting the tools used to view and manipulate log data. +Therefore, protecting audit tools is necessary to prevent unauthorized operations on audit information. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then chgrp 0 /sbin/auditctl chgrp 0 /sbin/aureport @@ -3230,13 +4420,27 @@ chgrp 0 /sbin/augenrules else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Test for existence /sbin/auditctl + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002570 + - NIST-800-53-AU-9 + - configure_strategy + - file_audit_tools_group_ownership + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /sbin/auditctl stat: path: /sbin/auditctl register: file_exists - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-002570 - NIST-800-53-AU-9 - configure_strategy - file_audit_tools_group_ownership @@ -3250,9 +4454,10 @@ fi path: /sbin/auditctl group: '0' when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - file_exists.stat is defined and file_exists.stat.exists tags: + - DISA-STIG-OL09-00-002570 - NIST-800-53-AU-9 - configure_strategy - file_audit_tools_group_ownership @@ -3265,8 +4470,9 @@ fi stat: path: /sbin/aureport register: file_exists - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-002570 - NIST-800-53-AU-9 - configure_strategy - file_audit_tools_group_ownership @@ -3280,9 +4486,10 @@ fi path: /sbin/aureport group: '0' when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - file_exists.stat is defined and file_exists.stat.exists tags: + - DISA-STIG-OL09-00-002570 - NIST-800-53-AU-9 - configure_strategy - file_audit_tools_group_ownership @@ -3295,8 +4502,9 @@ fi stat: path: /sbin/ausearch register: file_exists - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-002570 - NIST-800-53-AU-9 - configure_strategy - file_audit_tools_group_ownership @@ -3310,9 +4518,10 @@ fi path: /sbin/ausearch group: '0' when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - file_exists.stat is defined and file_exists.stat.exists tags: + - DISA-STIG-OL09-00-002570 - NIST-800-53-AU-9 - configure_strategy - file_audit_tools_group_ownership @@ -3325,8 +4534,9 @@ fi stat: path: /sbin/autrace register: file_exists - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-002570 - NIST-800-53-AU-9 - configure_strategy - file_audit_tools_group_ownership @@ -3340,9 +4550,10 @@ fi path: /sbin/autrace group: '0' when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - file_exists.stat is defined and file_exists.stat.exists tags: + - DISA-STIG-OL09-00-002570 - NIST-800-53-AU-9 - configure_strategy - file_audit_tools_group_ownership @@ -3355,8 +4566,9 @@ fi stat: path: /sbin/auditd register: file_exists - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-002570 - NIST-800-53-AU-9 - configure_strategy - file_audit_tools_group_ownership @@ -3370,9 +4582,10 @@ fi path: /sbin/auditd group: '0' when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - file_exists.stat is defined and file_exists.stat.exists tags: + - DISA-STIG-OL09-00-002570 - NIST-800-53-AU-9 - configure_strategy - file_audit_tools_group_ownership @@ -3385,8 +4598,9 @@ fi stat: path: /sbin/rsyslogd register: file_exists - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-002570 - NIST-800-53-AU-9 - configure_strategy - file_audit_tools_group_ownership @@ -3400,9 +4614,10 @@ fi path: /sbin/rsyslogd group: '0' when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - file_exists.stat is defined and file_exists.stat.exists tags: + - DISA-STIG-OL09-00-002570 - NIST-800-53-AU-9 - configure_strategy - file_audit_tools_group_ownership @@ -3415,8 +4630,9 @@ fi stat: path: /sbin/augenrules register: file_exists - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-002570 - NIST-800-53-AU-9 - configure_strategy - file_audit_tools_group_ownership @@ -3430,9 +4646,10 @@ fi path: /sbin/augenrules group: '0' when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - file_exists.stat is defined and file_exists.stat.exists tags: + - DISA-STIG-OL09-00-002570 - NIST-800-53-AU-9 - configure_strategy - file_audit_tools_group_ownership @@ -3440,32 +4657,32 @@ fi - low_disruption - medium_severity - no_reboot_needed - - - - - - - - - - Audit Tools Must Be Owned by Root - Oracle Linux 9 systems providing tools to interface with audit information will leverage user permissions and roles identifying the user accessing the tools, and the corresponding rights the user enjoys, to make access decisions regarding the access to audit tools. + + + + + + + + + + Audit Tools Must Be Owned by Root + Oracle Linux 9 systems providing tools to interface with audit information will leverage user permissions and roles identifying the user accessing the tools, and the corresponding rights the user enjoys, to make access decisions regarding the access to audit tools. Audit tools include, but are not limited to, vendor-provided and open source audit tools needed to successfully view and manipulate audit information system activity and records. Audit tools include custom queries and report generators. -Audit tools must have the correct owner. - CCI-001493 - CCI-001494 - CCI-001495 - AU-9 - SRG-OS-000256-GPOS-00097 - SRG-OS-000257-GPOS-00098 - SRG-OS-000258-GPOS-00099 - Protecting audit information also includes identifying and protecting the tools used to view and manipulate log data. -Therefore, protecting audit tools is necessary to prevent unauthorized operations on audit information. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then +Audit tools must have the correct owner. + CCI-001493 + AU-9 + SRG-OS-000256-GPOS-00097 + SRG-OS-000257-GPOS-00098 + SRG-OS-000258-GPOS-00099 + OL09-00-002571 + SV-271825r1092187_rule + Protecting audit information also includes identifying and protecting the tools used to view and manipulate log data. +Therefore, protecting audit tools is necessary to prevent unauthorized operations on audit information. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then chown 0 /sbin/auditctl chown 0 /sbin/aureport @@ -3478,13 +4695,27 @@ chown 0 /sbin/augenrules else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Test for existence /sbin/auditctl + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002571 + - NIST-800-53-AU-9 + - configure_strategy + - file_audit_tools_ownership + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /sbin/auditctl stat: path: /sbin/auditctl register: file_exists - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-002571 - NIST-800-53-AU-9 - configure_strategy - file_audit_tools_ownership @@ -3498,9 +4729,10 @@ fi path: /sbin/auditctl owner: '0' when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - file_exists.stat is defined and file_exists.stat.exists tags: + - DISA-STIG-OL09-00-002571 - NIST-800-53-AU-9 - configure_strategy - file_audit_tools_ownership @@ -3513,8 +4745,9 @@ fi stat: path: /sbin/aureport register: file_exists - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-002571 - NIST-800-53-AU-9 - configure_strategy - file_audit_tools_ownership @@ -3528,9 +4761,10 @@ fi path: /sbin/aureport owner: '0' when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - file_exists.stat is defined and file_exists.stat.exists tags: + - DISA-STIG-OL09-00-002571 - NIST-800-53-AU-9 - configure_strategy - file_audit_tools_ownership @@ -3543,8 +4777,9 @@ fi stat: path: /sbin/ausearch register: file_exists - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-002571 - NIST-800-53-AU-9 - configure_strategy - file_audit_tools_ownership @@ -3558,9 +4793,10 @@ fi path: /sbin/ausearch owner: '0' when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - file_exists.stat is defined and file_exists.stat.exists tags: + - DISA-STIG-OL09-00-002571 - NIST-800-53-AU-9 - configure_strategy - file_audit_tools_ownership @@ -3573,8 +4809,9 @@ fi stat: path: /sbin/autrace register: file_exists - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-002571 - NIST-800-53-AU-9 - configure_strategy - file_audit_tools_ownership @@ -3588,9 +4825,10 @@ fi path: /sbin/autrace owner: '0' when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - file_exists.stat is defined and file_exists.stat.exists tags: + - DISA-STIG-OL09-00-002571 - NIST-800-53-AU-9 - configure_strategy - file_audit_tools_ownership @@ -3603,8 +4841,9 @@ fi stat: path: /sbin/auditd register: file_exists - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-002571 - NIST-800-53-AU-9 - configure_strategy - file_audit_tools_ownership @@ -3618,9 +4857,10 @@ fi path: /sbin/auditd owner: '0' when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - file_exists.stat is defined and file_exists.stat.exists tags: + - DISA-STIG-OL09-00-002571 - NIST-800-53-AU-9 - configure_strategy - file_audit_tools_ownership @@ -3633,8 +4873,9 @@ fi stat: path: /sbin/rsyslogd register: file_exists - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-002571 - NIST-800-53-AU-9 - configure_strategy - file_audit_tools_ownership @@ -3648,9 +4889,10 @@ fi path: /sbin/rsyslogd owner: '0' when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - file_exists.stat is defined and file_exists.stat.exists tags: + - DISA-STIG-OL09-00-002571 - NIST-800-53-AU-9 - configure_strategy - file_audit_tools_ownership @@ -3663,8 +4905,9 @@ fi stat: path: /sbin/augenrules register: file_exists - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-002571 - NIST-800-53-AU-9 - configure_strategy - file_audit_tools_ownership @@ -3678,9 +4921,10 @@ fi path: /sbin/augenrules owner: '0' when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - file_exists.stat is defined and file_exists.stat.exists tags: + - DISA-STIG-OL09-00-002571 - NIST-800-53-AU-9 - configure_strategy - file_audit_tools_ownership @@ -3688,30 +4932,32 @@ fi - low_disruption - medium_severity - no_reboot_needed - - - - - - - - - - Audit Tools Must Have a Mode of 0755 or Less Permissive - Oracle Linux 9 systems providing tools to interface with audit information will leverage user permissions and roles identifying the user accessing the tools, and the corresponding rights the user enjoys, to make access decisions regarding the access to audit tools. + + + + + + + + + + Audit Tools Must Have a Mode of 0755 or Less Permissive + Oracle Linux 9 systems providing tools to interface with audit information will leverage user permissions and roles identifying the user accessing the tools, and the corresponding rights the user enjoys, to make access decisions regarding the access to audit tools. Audit tools include, but are not limited to, vendor-provided and open source audit tools needed to successfully view and manipulate audit information system activity and records. Audit tools include custom queries and report generators. -Audit tools must have a mode of 0755 or less permissive. - CCI-001493 - AU-9 - SRG-OS-000256-GPOS-00097 - SRG-OS-000257-GPOS-00098 - SRG-OS-000258-GPOS-00099 - Protecting audit information also includes identifying and protecting the tools used to view and manipulate log data. -Therefore, protecting audit tools is necessary to prevent unauthorized operations on audit information. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then +Audit tools must have a mode of 0755 or less permissive. + CCI-001493 + AU-9 + SRG-OS-000256-GPOS-00097 + SRG-OS-000257-GPOS-00098 + SRG-OS-000258-GPOS-00099 + OL09-00-002572 + SV-271826r1092190_rule + Protecting audit information also includes identifying and protecting the tools used to view and manipulate log data. +Therefore, protecting audit tools is necessary to prevent unauthorized operations on audit information. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then chmod u-s,g-ws,o-wt /sbin/auditctl @@ -3730,13 +4976,27 @@ chmod u-s,g-ws,o-wt /sbin/augenrules else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Test for existence /sbin/auditctl + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002572 + - NIST-800-53-AU-9 + - configure_strategy + - file_audit_tools_permissions + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /sbin/auditctl stat: path: /sbin/auditctl register: file_exists - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-002572 - NIST-800-53-AU-9 - configure_strategy - file_audit_tools_permissions @@ -3750,9 +5010,10 @@ fi path: /sbin/auditctl mode: u-s,g-ws,o-wt when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - file_exists.stat is defined and file_exists.stat.exists tags: + - DISA-STIG-OL09-00-002572 - NIST-800-53-AU-9 - configure_strategy - file_audit_tools_permissions @@ -3765,8 +5026,9 @@ fi stat: path: /sbin/aureport register: file_exists - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-002572 - NIST-800-53-AU-9 - configure_strategy - file_audit_tools_permissions @@ -3780,9 +5042,10 @@ fi path: /sbin/aureport mode: u-s,g-ws,o-wt when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - file_exists.stat is defined and file_exists.stat.exists tags: + - DISA-STIG-OL09-00-002572 - NIST-800-53-AU-9 - configure_strategy - file_audit_tools_permissions @@ -3795,8 +5058,9 @@ fi stat: path: /sbin/ausearch register: file_exists - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-002572 - NIST-800-53-AU-9 - configure_strategy - file_audit_tools_permissions @@ -3810,9 +5074,10 @@ fi path: /sbin/ausearch mode: u-s,g-ws,o-wt when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - file_exists.stat is defined and file_exists.stat.exists tags: + - DISA-STIG-OL09-00-002572 - NIST-800-53-AU-9 - configure_strategy - file_audit_tools_permissions @@ -3825,8 +5090,9 @@ fi stat: path: /sbin/autrace register: file_exists - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-002572 - NIST-800-53-AU-9 - configure_strategy - file_audit_tools_permissions @@ -3840,9 +5106,10 @@ fi path: /sbin/autrace mode: u-s,g-ws,o-wt when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - file_exists.stat is defined and file_exists.stat.exists tags: + - DISA-STIG-OL09-00-002572 - NIST-800-53-AU-9 - configure_strategy - file_audit_tools_permissions @@ -3855,8 +5122,9 @@ fi stat: path: /sbin/auditd register: file_exists - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-002572 - NIST-800-53-AU-9 - configure_strategy - file_audit_tools_permissions @@ -3870,9 +5138,10 @@ fi path: /sbin/auditd mode: u-s,g-ws,o-wt when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - file_exists.stat is defined and file_exists.stat.exists tags: + - DISA-STIG-OL09-00-002572 - NIST-800-53-AU-9 - configure_strategy - file_audit_tools_permissions @@ -3885,8 +5154,9 @@ fi stat: path: /sbin/rsyslogd register: file_exists - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-002572 - NIST-800-53-AU-9 - configure_strategy - file_audit_tools_permissions @@ -3900,9 +5170,10 @@ fi path: /sbin/rsyslogd mode: u-s,g-ws,o-wt when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - file_exists.stat is defined and file_exists.stat.exists tags: + - DISA-STIG-OL09-00-002572 - NIST-800-53-AU-9 - configure_strategy - file_audit_tools_permissions @@ -3915,8 +5186,9 @@ fi stat: path: /sbin/augenrules register: file_exists - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-002572 - NIST-800-53-AU-9 - configure_strategy - file_audit_tools_permissions @@ -3930,9 +5202,10 @@ fi path: /sbin/augenrules mode: u-s,g-ws,o-wt when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - file_exists.stat is defined and file_exists.stat.exists tags: + - DISA-STIG-OL09-00-002572 - NIST-800-53-AU-9 - configure_strategy - file_audit_tools_permissions @@ -3940,38 +5213,44 @@ fi - low_disruption - medium_severity - no_reboot_needed - - - - - - - - - - - - Federal Information Processing Standard (FIPS) - The Federal Information Processing Standard (FIPS) is a computer security standard which + + + + + + + + + + + + Federal Information Processing Standard (FIPS) + The Federal Information Processing Standard (FIPS) is a computer security standard which is developed by the U.S. Government and industry working groups to validate the quality of cryptographic modules. The FIPS standard provides four security levels to ensure adequate coverage of different industries, implementation of cryptographic modules, and organizational sizes and requirements. - + + FIPS 140-2 is the current standard for validating that mechanisms used to access cryptographic modules utilize authentication that meets industry and government requirements. For government systems, this allows Security Levels 1, 2, 3, or 4 for use on Oracle Linux 9. - -See http://csrc.nist.gov/publications/PubsFIPS.html for more information. - - - Enable Dracut FIPS Module - To enable FIPS mode, run the following command: + + +See http://csrc.nist.gov/publications/PubsFIPS.html for more information. + + + Enable Dracut FIPS Module + +To enable FIPS mode, run the following command: fips-mode-setup --enable + To enable FIPS, the system requires that the fips module is added in dracut configuration. -Check if /etc/dracut.conf.d/40-fips.conf contain add_dracutmodules+=" fips " - The system needs to be rebooted for these changes to take effect. - System Crypto Modules must be provided by a vendor that undergoes FIPS-140 certifications. +Check if /etc/dracut.conf.d/40-fips.conf contain add_dracutmodules+=" fips " + + +The system needs to be rebooted for these changes to take effect. + System Crypto Modules must be provided by a vendor that undergoes FIPS-140 certifications. FIPS-140 is applicable to all Federal agencies that use cryptographic-based security systems to protect sensitive information in computer and telecommunication systems (including voice systems) as defined in Section 5131 of the Information Technology @@ -3983,27 +5262,31 @@ To meet this, the system has to have cryptographic software provided by a vendor undergone this certification. This means providing documentation, test results, design information, and independent third party review by an accredited lab. While open source software is capable of meeting this, it does not meet FIPS-140 unless the vendor submits to -this process. - CCI-000068 - CCI-000803 - CCI-002450 - 1446 - CIP-003-8 R4.2 - CIP-007-3 R5.1 - SC-12(2) - SC-12(3) - IA-7 - SC-13 - CM-6(a) - SC-12 - FCS_RBG_EXT.1 - SRG-OS-000478-GPOS-00223 - Use of weak or untested encryption algorithms undermines the purposes of utilizing encryption to +this process. + CCI-002450 + CCI-000068 + CCI-002418 + CCI-000877 + 1446 + CIP-003-8 R4.2 + CIP-007-3 R5.1 + SC-12(2) + SC-12(3) + IA-7 + SC-13 + CM-6(a) + SC-12 + FCS_RBG_EXT.1 + SRG-OS-000478-GPOS-00223 + OL09-00-000070 + SV-271454r1092458_rule + Use of weak or untested encryption algorithms undermines the purposes of utilizing encryption to protect data. The operating system must implement cryptographic modules adhering to the higher standards approved by the federal government since this provides assurance they have been tested -and validated. - # Remediation is applicable only in certain platforms -if ( [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && ! ( [ "${container:-}" == "bwrap-osbuild" ] ) ); then +and validated. + + # Remediation is applicable only in certain platforms +if ( ! ( [ "${container:-}" == "bwrap-osbuild" ] ) && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ) && { ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ); }; then fips-mode-setup --enable FIPS_CONF="/etc/dracut.conf.d/40-fips.conf" @@ -4014,15 +5297,38 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Check to see the current status of FIPS mode + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-000070 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-7 + - NIST-800-53-SC-12 + - NIST-800-53-SC-12(2) + - NIST-800-53-SC-12(3) + - NIST-800-53-SC-13 + - enable_dracut_fips_module + - high_severity + - medium_complexity + - medium_disruption + - reboot_required + - restrict_strategy + +- name: Check to see the current status of FIPS mode command: /usr/bin/fips-mode-setup --check register: is_fips_enabled changed_when: false failed_when: false - when: ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", - "container"] and not ( lookup("env", "container") == "bwrap-osbuild" ) ) + when: + - ( not ( lookup("env", "container") == "bwrap-osbuild" ) and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + - not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) tags: + - DISA-STIG-OL09-00-000070 - NIST-800-53-CM-6(a) - NIST-800-53-IA-7 - NIST-800-53-SC-12 @@ -4039,10 +5345,14 @@ fi - name: Enable FIPS mode command: /usr/bin/fips-mode-setup --enable when: - - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - and not ( lookup("env", "container") == "bwrap-osbuild" ) ) + - ( not ( lookup("env", "container") == "bwrap-osbuild" ) and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + - not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) - is_fips_enabled.stdout.find('FIPS mode is enabled.') == -1 tags: + - DISA-STIG-OL09-00-000070 - NIST-800-53-CM-6(a) - NIST-800-53-IA-7 - NIST-800-53-SC-12 @@ -4060,9 +5370,14 @@ fi lineinfile: path: /etc/dracut.conf.d/40-fips.conf line: add_dracutmodules+=" fips " - when: ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", - "container"] and not ( lookup("env", "container") == "bwrap-osbuild" ) ) + when: + - ( not ( lookup("env", "container") == "bwrap-osbuild" ) and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + - not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) tags: + - DISA-STIG-OL09-00-000070 - NIST-800-53-CM-6(a) - NIST-800-53-IA-7 - NIST-800-53-SC-12 @@ -4075,98 +5390,99 @@ fi - medium_disruption - reboot_required - restrict_strategy - - - - - - - - - - Enable FIPS Mode - + + + + + + + + + + Enable FIPS Mode + To enable FIPS mode, run the following command: fips-mode-setup --enable - + The fips-mode-setup command will configure the system in FIPS mode by automatically configuring the following: -Setting the kernel FIPS mode flag (/proc/sys/crypto/fips_enabled) to 1Creating /etc/system-fipsSetting the system crypto policy in /etc/crypto-policies/config to Loading the Dracut fips module - The system needs to be rebooted for these changes to take effect. - This rule DOES NOT CHECK if the components of the operating system are FIPS certified. +Setting the kernel FIPS mode flag (/proc/sys/crypto/fips_enabled) to 1 + Creating /etc/system-fips + Setting the system crypto policy in /etc/crypto-policies/config to + Loading the Dracut fips module + + To configure Oracle Linux 9 to run in FIPS 140 mode, the kernel parameter "fips=1" needs to be added during its installation. +Only enabling FIPS 140 mode during the Oracle Linux 9 installation ensures that the system generates all keys with FIPS-approved algorithms and continuous monitoring tests in place. +Enabling FIPS mode on a preexisting system involves a number of modifications to it and therefore is not supported. + This rule DOES NOT CHECK if the components of the operating system are FIPS certified. You can find the list of FIPS certified modules at https://csrc.nist.gov/projects/cryptographic-module-validation-program/validated-modules/search. -This rule checks if the system is running in FIPS mode. See the rule description for more information about what it means. - CCI-000068 - CCI-000803 - CCI-002450 - 1446 - CIP-003-8 R4.2 - CIP-007-3 R5.1 - CM-3(6) - SC-12(2) - SC-12(3) - IA-7 - SC-13 - CM-6(a) - SC-12 - FCS_COP.1(1) - FCS_COP.1(2) - FCS_COP.1(3) - FCS_COP.1(4) - FCS_CKM.1 - FCS_CKM.2 - FCS_TLSC_EXT.1 - FCS_RBG_EXT.1 - SRG-OS-000478-GPOS-00223 - SRG-OS-000396-GPOS-00176 - Use of weak or untested encryption algorithms undermines the purposes of utilizing encryption to +This rule checks if the system is running in FIPS mode. + CCI-002450 + CCI-000068 + CCI-002418 + CCI-000877 + 1446 + CIP-003-8 R4.2 + CIP-007-3 R5.1 + CM-3(6) + SC-12(2) + SC-12(3) + IA-7 + SC-13 + CM-6(a) + SC-12 + FCS_COP.1(1) + FCS_COP.1(2) + FCS_COP.1(3) + FCS_COP.1(4) + FCS_CKM.1 + FCS_CKM.2 + FCS_TLSC_EXT.1 + FCS_RBG_EXT.1 + SRG-OS-000478-GPOS-00223 + SRG-OS-000396-GPOS-00176 + OL09-00-000070 + SV-271454r1092458_rule + Use of weak or untested encryption algorithms undermines the purposes of utilizing encryption to protect data. The operating system must implement cryptographic modules adhering to the higher standards approved by the federal government since this provides assurance they have been tested -and validated. - - # Remediation is applicable only in certain platforms -if ( [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && ! ( [ "${container:-}" == "bwrap-osbuild" ] ) ) && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then +and validated. + # Remediation is applicable only in certain platforms +if ( ! ( [ "${container:-}" == "bwrap-osbuild" ] ) && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ); then -var_system_crypto_policy='' - - -fips-mode-setup --enable - -stderr_of_call=$(update-crypto-policies --set ${var_system_crypto_policy} 2>&1 > /dev/null) -rc=$? - -if test "$rc" = 127; then - echo "$stderr_of_call" >&2 - echo "Make sure that the script is installed on the remediated system." >&2 - echo "See output of the 'dnf provides update-crypto-policies' command" >&2 - echo "to see what package to (re)install" >&2 - - false # end with an error code -elif test "$rc" != 0; then - echo "Error invoking the update-crypto-policies script: $stderr_of_call" >&2 - false # end with an error code +if [[ "$OSCAP_BOOTC_BUILD" == "YES" ]]; then + cat > /usr/lib/bootc/kargs.d/01-fips.toml << EOF +kargs = ["fips=1"] +EOF fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - - - - - - - - - Ensure '/etc/system-fips' exists - On a system where FIPS mode is enabled, /etc/system-fips must exist. + + +[customizations] +fips = true + + + + + + + + + + + Ensure '/etc/system-fips' exists + On a system where FIPS mode is enabled, /etc/system-fips must exist. + To enable FIPS mode, run the following command: -fips-mode-setup --enable - The system needs to be rebooted for these changes to take effect. - System Crypto Modules must be provided by a vendor that undergoes +fips-mode-setup --enable + + +The system needs to be rebooted for these changes to take effect. + System Crypto Modules must be provided by a vendor that undergoes FIPS-140 certifications. FIPS-140 is applicable to all Federal agencies that use cryptographic-based security systems to protect sensitive information @@ -4181,41 +5497,44 @@ a vendor that has undergone this certification. This means providing documentation, test results, design information, and independent third party review by an accredited lab. While open source software is capable of meeting this, it does not meet FIPS-140 unless the vendor -submits to this process. - CCI-000068 - CCI-000803 - CCI-002450 - CIP-003-8 R4.2 - CIP-007-3 R5.1 - SC-12(2) - SC-12(3) - IA-7 - SC-13 - CM-6(a) - SC-12 - Use of weak or untested encryption algorithms undermines the purposes of utilizing encryption to +submits to this process. + CCI-000068 + CCI-000803 + CCI-002450 + CIP-003-8 R4.2 + CIP-007-3 R5.1 + SC-12(2) + SC-12(3) + IA-7 + SC-13 + CM-6(a) + SC-12 + Use of weak or untested encryption algorithms undermines the purposes of utilizing encryption to protect data. The operating system must implement cryptographic modules adhering to the higher standards approved by the federal government since this provides assurance they have been tested -and validated. - - - - - - - - - Set kernel parameter 'crypto.fips_enabled' to 1 - System running in FIPS mode is indicated by kernel parameter +and validated. + + + + + + + + + Set kernel parameter 'crypto.fips_enabled' to 1 + System running in FIPS mode is indicated by kernel parameter 'crypto.fips_enabled'. This parameter should be set to 1 in FIPS mode. + To enable FIPS mode, run the following command: fips-mode-setup --enable + + To enable strict FIPS compliance, the fips=1 kernel option needs to be added to the kernel boot parameters during system installation so key generation is done with FIPS-approved algorithms -and continuous monitoring tests in place. - The system needs to be rebooted for these changes to take effect. - System Crypto Modules must be provided by a vendor that undergoes FIPS-140 certifications. +and continuous monitoring tests in place. + The system needs to be rebooted for these changes to take effect. + System Crypto Modules must be provided by a vendor that undergoes FIPS-140 certifications. FIPS-140 is applicable to all Federal agencies that use cryptographic-based security systems to protect sensitive information in computer and telecommunication systems (including voice systems) as defined in Section 5131 of the Information Technology @@ -4227,47 +5546,44 @@ To meet this, the system has to have cryptographic software provided by a vendor undergone this certification. This means providing documentation, test results, design information, and independent third party review by an accredited lab. While open source software is capable of meeting this, it does not meet FIPS-140 unless the vendor submits to -this process. - CCI-000068 - CCI-000803 - CCI-000877 - CCI-001453 - CCI-002418 - CCI-002450 - CCI-002890 - CCI-003123 - CIP-003-8 R4.2 - CIP-007-3 R5.1 - SC-12(2) - SC-12(3) - IA-7 - SC-13 - CM-6(a) - SC-12 - SRG-OS-000033-GPOS-00014 - SRG-OS-000125-GPOS-00065 - SRG-OS-000250-GPOS-00093 - SRG-OS-000393-GPOS-00173 - SRG-OS-000394-GPOS-00174 - SRG-OS-000396-GPOS-00176 - SRG-OS-000423-GPOS-00187 - SRG-OS-000478-GPOS-00223 - Use of weak or untested encryption algorithms undermines the purposes of utilizing encryption to +this process. + CCI-002450 + CCI-000068 + CCI-002418 + CCI-000877 + CIP-003-8 R4.2 + CIP-007-3 R5.1 + SC-12(2) + SC-12(3) + IA-7 + SC-13 + CM-6(a) + SC-12 + SRG-OS-000033-GPOS-00014 + SRG-OS-000125-GPOS-00065 + SRG-OS-000250-GPOS-00093 + SRG-OS-000393-GPOS-00173 + SRG-OS-000394-GPOS-00174 + SRG-OS-000396-GPOS-00176 + SRG-OS-000423-GPOS-00187 + SRG-OS-000478-GPOS-00223 + OL09-00-000070 + SV-271454r1092458_rule + Use of weak or untested encryption algorithms undermines the purposes of utilizing encryption to protect data. The operating system must implement cryptographic modules adhering to the higher standards approved by the federal government since this provides assurance they have been tested -and validated. - - - - - - - - - - - System Cryptographic Policies - Linux has the capability to centrally configure cryptographic polices. The command +and validated. + + + + + + + + + + System Cryptographic Policies + Linux has the capability to centrally configure cryptographic polices. The command update-crypto-policies is used to set the policy applicable for the various cryptographic back-ends, such as SSL/TLS libraries. The configured cryptographic policies will be the default policy used by these backends unless the application @@ -4279,100 +5595,107 @@ configured profile. Currently the supported backends are: GnuTLS libraryOpenSSL libraryNSS libraryOpenJDKLibkrb5BINDOpenSSH Applications and languages which rely on any of these backends will follow the -system policies as well. Examples are apache httpd, nginx, php, and others. - - SSH client RekeyLimit - size - Specify the size component of the rekey limit. This limit signifies amount +system policies as well. Examples are apache httpd, nginx, php, and others. + + SSH client RekeyLimit - size + Specify the size component of the rekey limit. This limit signifies amount of data. After this amount of data is transferred through the connection, the session key is renegotiated. The number is followed by K, M or G for kilobytes, megabytes or gigabytes. Note that the RekeyLimit can be also -configured according to elapsed time. - 512M - 512M - 1G - - - SSH client RekeyLimit - time - Specify the time component of the rekey limit. The session key is +configured according to elapsed time. + 512M + 512M + 1G + + + SSH client RekeyLimit - time + Specify the time component of the rekey limit. The session key is renegotiated after the defined amount of time passes. The number is followed by units such as H or M for hours or minutes. Note that the RekeyLimit can -be also configured according to amount of transfered data. - 1h - 1h - - - The system-provided crypto policies - Specify the crypto policy for the system. - DEFAULT - DEFAULT - DEFAULT:NO-SHA1 - FIPS - FIPS:OSPP - LEGACY - FUTURE - NEXT - - - Install crypto-policies package - The crypto-policies package can be installed with the following command: +be also configured according to amount of transfered data. + 1h + 1h + + + The system-provided crypto policies + Specify the crypto policy for the system. + DEFAULT + DEFAULT + DEFAULT:NO-SHA1 + FIPS + FIPS:OSPP + LEGACY + FUTURE + NEXT + + + Install crypto-policies package + The crypto-policies package can be installed with the following command: -$ sudo yum install crypto-policies - FCS_COP.1(1) - FCS_COP.1(2) - FCS_COP.1(3) - FCS_COP.1(4) - FCS_CKM.1 - FCS_CKM.2 - FCS_TLSC_EXT.1 - SRG-OS-000396-GPOS-00176 - SRG-OS-000393-GPOS-00173 - SRG-OS-000394-GPOS-00174 - Centralized cryptographic policies simplify applying secure ciphers across an operating system and +$ sudo yum install crypto-policies + + CCI-002890 + CCI-002450 + CCI-003123 + FCS_COP.1(1) + FCS_COP.1(2) + FCS_COP.1(3) + FCS_COP.1(4) + FCS_CKM.1 + FCS_CKM.2 + FCS_TLSC_EXT.1 + SRG-OS-000396-GPOS-00176 + SRG-OS-000393-GPOS-00173 + SRG-OS-000394-GPOS-00174 + OL09-00-000240 + SV-271477r1091143_rule + Centralized cryptographic policies simplify applying secure ciphers across an operating system and the applications that run on that operating system. Use of weak or untested encryption algorithms -undermines the purposes of utilizing encryption to protect data. - +undermines the purposes of utilizing encryption to protect data. + if ! rpm -q --quiet "crypto-policies" ; then yum install -y "crypto-policies" fi - - - name: Ensure crypto-policies is installed + + - name: Ensure crypto-policies is installed package: name: crypto-policies state: present tags: + - DISA-STIG-OL09-00-000240 - enable_strategy - low_complexity - low_disruption - medium_severity - no_reboot_needed - package_crypto-policies_installed - - include install_crypto-policies + + include install_crypto-policies class install_crypto-policies { package { 'crypto-policies': ensure => 'installed', } } - - + + package --add=crypto-policies - - + + [[packages]] name = "crypto-policies" version = "*" - - - - - - - - - - Configure BIND to use System Crypto Policy - Crypto Policies provide a centralized control over crypto algorithms usage of many packages. + + + + + + + + + + Configure BIND to use System Crypto Policy + Crypto Policies provide a centralized control over crypto algorithms usage of many packages. BIND is supported by crypto policy, but the BIND configuration may be set up to ignore it. @@ -4380,17 +5703,25 @@ To check that Crypto Policies settings are configured correctly, ensure that the includes the appropriate configuration: In the options section of /etc/named.conf, make sure that the following line is not commented out or superseded by later includes: -include "/etc/crypto-policies/back-ends/bind.config"; - CIP-003-8 R4.2 - CIP-007-3 R5.1 - SC-13 - SC-12(2) - SC-12(3) - SRG-OS-000423-GPOS-00187 - SRG-OS-000426-GPOS-00190 - Overriding the system crypto policy makes the behavior of the BIND service violate expectations, -and makes system configuration more fragmented. - +include "/etc/crypto-policies/back-ends/bind.config"; + + CCI-002418 + CCI-002422 + CIP-003-8 R4.2 + CIP-007-3 R5.1 + SC-13 + SC-12(2) + SC-12(3) + SRG-OS-000423-GPOS-00187 + SRG-OS-000426-GPOS-00190 + OL09-00-002421 + SV-271759r1091989_rule + Overriding the system crypto policy makes the behavior of the BIND service violate expectations, +and makes system configuration more fragmented. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q bind; then + function remediate_bind_crypto_policy() { CONFIG_FILE="/etc/named.conf" if test -f "$CONFIG_FILE"; then @@ -4403,23 +5734,102 @@ function remediate_bind_crypto_policy() { } remediate_bind_crypto_policy - - - - - - - - - - Configure System Cryptography Policy - To configure the system cryptography policy to use ciphers only from the + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002421 + - NIST-800-53-SC-12(2) + - NIST-800-53-SC-12(3) + - NIST-800-53-SC-13 + - configure_bind_crypto_policy + - configure_strategy + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + +- name: Configure BIND to use System Crypto Policy - Check BIND configuration file + exists + ansible.builtin.stat: + path: /etc/named.conf + register: bind_config_file + when: '"bind" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-002421 + - NIST-800-53-SC-12(2) + - NIST-800-53-SC-12(3) + - NIST-800-53-SC-13 + - configure_bind_crypto_policy + - configure_strategy + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + +- name: Configure BIND to use System Crypto Policy - Aborting remediation, file not + found + ansible.builtin.debug: + msg: Aborting remediation as '/etc/named.conf' was not found. + when: + - '"bind" in ansible_facts.packages' + - not bind_config_file.stat.exists + tags: + - DISA-STIG-OL09-00-002421 + - NIST-800-53-SC-12(2) + - NIST-800-53-SC-12(3) + - NIST-800-53-SC-13 + - configure_bind_crypto_policy + - configure_strategy + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + +- name: Configure BIND to use System Crypto Policy - Insert crypto-policy into BIND + config + ansible.builtin.lineinfile: + path: /etc/named.conf + insertafter: ^\s*options\s*{ + line: ' include "/etc/crypto-policies/back-ends/bind.config";' + state: present + when: + - '"bind" in ansible_facts.packages' + - bind_config_file.stat.exists + tags: + - DISA-STIG-OL09-00-002421 + - NIST-800-53-SC-12(2) + - NIST-800-53-SC-12(3) + - NIST-800-53-SC-13 + - configure_bind_crypto_policy + - configure_strategy + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + + + + + + + + + + Configure System Cryptography Policy + To configure the system cryptography policy to use ciphers only from the policy, run the following command: -$ sudo update-crypto-policies --set +$ sudo update-crypto-policies --set + The rule checks if settings for selected crypto policy are configured as expected. Configuration files in the /etc/crypto-policies/back-ends are either symlinks to correct files provided by Crypto-policies package or they are regular files in case crypto policy customizations are applied. -Crypto policies may be customized by crypto policy modules, in which case it is delimited from the base policy using a colon. - The system needs to be rebooted for these changes to take effect. - System Crypto Modules must be provided by a vendor that undergoes +Crypto policies may be customized by crypto policy modules, in which case it is delimited from the base policy using a colon. + The system needs to be rebooted for these changes to take effect. + System Crypto Modules must be provided by a vendor that undergoes FIPS-140 certifications. FIPS-140 is applicable to all Federal agencies that use cryptographic-based security systems to protect sensitive information @@ -4434,38 +5844,52 @@ a vendor that has undergone this certification. This means providing documentation, test results, design information, and independent third party review by an accredited lab. While open source software is capable of meeting this, it does not meet FIPS-140 unless the vendor -submits to this process. - 164.308(a)(4)(i) - 164.308(b)(1) - 164.308(b)(3) - 164.312(e)(1) - 164.312(e)(2)(ii) - 1446 - CIP-003-8 R4.2 - CIP-007-3 R5.1 - CIP-007-3 R7.1 - AC-17(a) - AC-17(2) - CM-6(a) - MA-4(6) - SC-13 - SC-12(2) - SC-12(3) - FCS_COP.1(1) - FCS_COP.1(2) - FCS_COP.1(3) - FCS_COP.1(4) - FCS_CKM.1 - FCS_CKM.2 - FCS_TLSC_EXT.1 - SRG-OS-000396-GPOS-00176 - SRG-OS-000393-GPOS-00173 - SRG-OS-000394-GPOS-00174 - Centralized cryptographic policies simplify applying secure ciphers across an operating system and +submits to this process. + CCI-000068 + CCI-003123 + CCI-002450 + CCI-000877 + CCI-002418 + CCI-001453 + CCI-002890 + 164.308(a)(4)(i) + 164.308(b)(1) + 164.308(b)(3) + 164.312(e)(1) + 164.312(e)(2)(ii) + 1446 + CIP-003-8 R4.2 + CIP-007-3 R5.1 + CIP-007-3 R7.1 + AC-17(a) + AC-17(2) + CM-6(a) + MA-4(6) + SC-13 + SC-12(2) + SC-12(3) + FCS_COP.1(1) + FCS_COP.1(2) + FCS_COP.1(3) + FCS_COP.1(4) + FCS_CKM.1 + FCS_CKM.2 + FCS_TLSC_EXT.1 + SRG-OS-000396-GPOS-00176 + SRG-OS-000393-GPOS-00173 + SRG-OS-000394-GPOS-00174 + A.5.SEC-OL4 + 2.2.7 + 2.2 + OL09-00-000070 + OL09-00-000241 + SV-271454r1092458_rule + SV-271478r1092620_rule + Centralized cryptographic policies simplify applying secure ciphers across an operating system and the applications that run on that operating system. Use of weak or untested encryption algorithms -undermines the purposes of utilizing encryption to protect data. - -var_system_crypto_policy='' +undermines the purposes of utilizing encryption to protect data. + +var_system_crypto_policy='' stderr_of_call=$(update-crypto-policies --set ${var_system_crypto_policy} 2>&1 > /dev/null) @@ -4482,10 +5906,10 @@ elif test "$rc" != 0; then echo "Error invoking the update-crypto-policies script: $stderr_of_call" >&2 false # end with an error code fi - - - name: XCCDF Value var_system_crypto_policy # promote to variable + + - name: XCCDF Value var_system_crypto_policy # promote to variable set_fact: - var_system_crypto_policy: !!str + var_system_crypto_policy: !!str tags: - always @@ -4496,6 +5920,8 @@ fi line: '{{ var_system_crypto_policy }}' create: true tags: + - DISA-STIG-OL09-00-000070 + - DISA-STIG-OL09-00-000241 - NIST-800-53-AC-17(2) - NIST-800-53-AC-17(a) - NIST-800-53-CM-6(a) @@ -4503,6 +5929,8 @@ fi - NIST-800-53-SC-12(2) - NIST-800-53-SC-12(3) - NIST-800-53-SC-13 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.7 - configure_crypto_policy - high_severity - low_complexity @@ -4513,6 +5941,8 @@ fi - name: Verify that Crypto Policy is Set (runtime) command: /usr/bin/update-crypto-policies --set {{ var_system_crypto_policy }} tags: + - DISA-STIG-OL09-00-000070 + - DISA-STIG-OL09-00-000241 - NIST-800-53-AC-17(2) - NIST-800-53-AC-17(a) - NIST-800-53-CM-6(a) @@ -4520,50 +5950,56 @@ fi - NIST-800-53-SC-12(2) - NIST-800-53-SC-12(3) - NIST-800-53-SC-13 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.7 - configure_crypto_policy - high_severity - low_complexity - low_disruption - no_reboot_needed - restrict_strategy - - - - - - - - - - - Configure Kerberos to use System Crypto Policy - Crypto Policies provide a centralized control over crypto algorithms usage of many packages. + + + + + + + + + + + Configure Kerberos to use System Crypto Policy + Crypto Policies provide a centralized control over crypto algorithms usage of many packages. Kerberos is supported by crypto policy, but it's configuration may be set up to ignore it. To check that Crypto Policies settings for Kerberos are configured correctly, examine that there is a symlink at /etc/krb5.conf.d/crypto-policies targeting /etc/cypto-policies/back-ends/krb5.config. -If the symlink exists, Kerberos is configured to use the system-wide crypto policy settings. - 0418 - 1055 - 1402 - CIP-003-8 R4.2 - CIP-007-3 R5.1 - SC-13 - SC-12(2) - SC-12(3) - SRG-OS-000120-GPOS-00061 - Overriding the system crypto policy makes the behavior of Kerberos violate expectations, -and makes system configuration more fragmented. - +If the symlink exists, Kerberos is configured to use the system-wide crypto policy settings. + CCI-000803 + 0418 + 1055 + 1402 + CIP-003-8 R4.2 + CIP-007-3 R5.1 + SC-13 + SC-12(2) + SC-12(3) + SRG-OS-000120-GPOS-00061 + OL09-00-002424 + SV-271762r1091998_rule + Overriding the system crypto policy makes the behavior of Kerberos violate expectations, +and makes system configuration more fragmented. + rm -f /etc/krb5.conf.d/crypto-policies ln -s /etc/crypto-policies/back-ends/krb5.config /etc/krb5.conf.d/crypto-policies - - - name: Configure Kerberos to use System Crypto Policy + + - name: Configure Kerberos to use System Crypto Policy file: src: /etc/crypto-policies/back-ends/krb5.config path: /etc/krb5.conf.d/crypto-policies state: link tags: + - DISA-STIG-OL09-00-002424 - NIST-800-53-SC-12(2) - NIST-800-53-SC-12(3) - NIST-800-53-SC-13 @@ -4573,17 +6009,17 @@ ln -s /etc/crypto-policies/back-ends/krb5.config /etc/krb5.conf.d/crypto-policie - low_complexity - low_disruption - reboot_required - - - - - - - - - - Configure Libreswan to use System Crypto Policy - Crypto Policies provide a centralized control over crypto algorithms usage of many packages. + + + + + + + + + + Configure Libreswan to use System Crypto Policy + Crypto Policies provide a centralized control over crypto algorithms usage of many packages. Libreswan is supported by system crypto policy, but the Libreswan configuration may be set up to ignore it. @@ -4591,23 +6027,24 @@ To check that Crypto Policies settings are configured correctly, ensure that the includes the appropriate configuration file. In /etc/ipsec.conf, make sure that the following line is not commented out or superseded by later includes: -include /etc/crypto-policies/back-ends/libreswan.config - CIP-003-8 R4.2 - CIP-007-3 R5.1 - CM-6(a) - MA-4(6) - SC-13 - SC-12(2) - SC-12(3) - FCS_IPSEC_EXT.1.4 - FCS_IPSEC_EXT.1.6 - Req-2.2 - 2.2 - SRG-OS-000033-GPOS-00014 - Overriding the system crypto policy makes the behavior of the Libreswan +include /etc/crypto-policies/back-ends/libreswan.config + + CCI-000068 + CIP-003-8 R4.2 + CIP-007-3 R5.1 + CM-6(a) + MA-4(6) + SC-13 + SC-12(2) + SC-12(3) + Req-2.2 + SRG-OS-000033-GPOS-00014 + OL09-00-002404 + SV-271743r1092635_rule + Overriding the system crypto policy makes the behavior of the Libreswan service violate expectations, and makes system configuration more -fragmented. - +fragmented. + function remediate_libreswan_crypto_policy() { CONFIG_FILE="/etc/ipsec.conf" if ! grep -qP "^\s*include\s+/etc/crypto-policies/back-ends/libreswan.config\s*(?:#.*)?$" "$CONFIG_FILE" ; then @@ -4618,60 +6055,68 @@ function remediate_libreswan_crypto_policy() { } remediate_libreswan_crypto_policy - - - name: Configure Libreswan to use System Crypto Policy + + - name: Configure Libreswan to use System Crypto Policy lineinfile: path: /etc/ipsec.conf line: include /etc/crypto-policies/back-ends/libreswan.config create: true tags: + - DISA-STIG-OL09-00-002404 - NIST-800-53-CM-6(a) - NIST-800-53-MA-4(6) - NIST-800-53-SC-12(2) - NIST-800-53-SC-12(3) - NIST-800-53-SC-13 - PCI-DSS-Req-2.2 - - PCI-DSSv4-2.2 - configure_libreswan_crypto_policy - high_severity - low_complexity - low_disruption - no_reboot_needed - restrict_strategy - - - - - - - - - - Configure OpenSSL library to use System Crypto Policy - Crypto Policies provide a centralized control over crypto algorithms usage of many packages. + + + + + + + + + + Configure OpenSSL library to use System Crypto Policy + Crypto Policies provide a centralized control over crypto algorithms usage of many packages. OpenSSL is supported by crypto policy, but the OpenSSL configuration may be set up to ignore it. To check that Crypto Policies settings are configured correctly, you have to examine the OpenSSL config file available under /etc/pki/tls/openssl.cnf. This file has the ini format, and it enables crypto policy support -if there is a [ crypto_policy ] section that contains the .include = /etc/crypto-policies/back-ends/opensslcnf.config directive. - CCI-001453 - CIP-003-8 R4.2 - CIP-007-3 R5.1 - CIP-007-3 R7.1 - AC-17(a) - AC-17(2) - CM-6(a) - MA-4(6) - SC-13 - SC-12(2) - SC-12(3) - Req-2.2 - 2.2 - SRG-OS-000250-GPOS-00093 - Overriding the system crypto policy makes the behavior of the Java runtime violates expectations, -and makes system configuration more fragmented. - +if there is a [ crypto_policy ] section that contains the .include = /etc/crypto-policies/back-ends/opensslcnf.config directive. + CCI-001453 + CIP-003-8 R4.2 + CIP-007-3 R5.1 + CIP-007-3 R7.1 + AC-17(a) + AC-17(2) + CM-6(a) + MA-4(6) + SC-13 + SC-12(2) + SC-12(3) + FCS_CKM.1 + FCS_CKM.1.1 + FCS_CKM.2 + FCS_COP.1/ENCRYPT + FCS_COP.1/HASH + FCS_COP.1/SIGN + FCS_COP.1/KEYHMAC + FCS_TLSC_EXT.1 + FCS_TLSC_EXT.1.1 + Req-2.2 + SRG-OS-000250-GPOS-00093 + Overriding the system crypto policy makes the behavior of the Java runtime violates expectations, +and makes system configuration more fragmented. + OPENSSL_CRYPTO_POLICY_SECTION='[ crypto_policy ]' OPENSSL_CRYPTO_POLICY_SECTION_REGEX='\[\s*crypto_policy\s*\]' @@ -4701,8 +6146,8 @@ function remediate_openssl_crypto_policy() { } remediate_openssl_crypto_policy - - - name: Configure OpenSSL library to use System Crypto Policy - Search for crypto_policy + + - name: Configure OpenSSL library to use System Crypto Policy - Search for crypto_policy Section ansible.builtin.find: paths: /etc/pki/tls @@ -4718,7 +6163,6 @@ remediate_openssl_crypto_policy - NIST-800-53-SC-12(3) - NIST-800-53-SC-13 - PCI-DSS-Req-2.2 - - PCI-DSSv4-2.2 - configure_openssl_crypto_policy - low_complexity - medium_disruption @@ -4742,7 +6186,6 @@ remediate_openssl_crypto_policy - NIST-800-53-SC-12(3) - NIST-800-53-SC-13 - PCI-DSS-Req-2.2 - - PCI-DSSv4-2.2 - configure_openssl_crypto_policy - low_complexity - medium_disruption @@ -4750,8 +6193,8 @@ remediate_openssl_crypto_policy - no_reboot_needed - unknown_strategy -- name: '{{ rule_title }} - Add .include Line for opensslcnf.config File in crypto_policy - Section' +- name: Configure OpenSSL library to use System Crypto Policy - Add .include Line + for opensslcnf.config File in crypto_policy Section ansible.builtin.lineinfile: create: true insertafter: ^\s*\[\s*crypto_policy\s*]\s* @@ -4769,7 +6212,6 @@ remediate_openssl_crypto_policy - NIST-800-53-SC-12(3) - NIST-800-53-SC-13 - PCI-DSS-Req-2.2 - - PCI-DSSv4-2.2 - configure_openssl_crypto_policy - low_complexity - medium_disruption @@ -4795,105 +6237,62 @@ remediate_openssl_crypto_policy - NIST-800-53-SC-12(3) - NIST-800-53-SC-13 - PCI-DSS-Req-2.2 - - PCI-DSSv4-2.2 - configure_openssl_crypto_policy - low_complexity - medium_disruption - medium_severity - no_reboot_needed - unknown_strategy - - - - - - - - - - Configure OpenSSL library to use TLS Encryption - Crypto Policies are means of enforcing certain cryptographic settings for -selected applications including OpenSSL. OpenSSL is by default configured to -modify its configuration based on currently configured Crypto Policy. -Editing the Crypto Policy back-end is not recommended. - -Check the crypto-policies(7) man page and choose a policy that configures TLS -protocol to version 1.2 or higher, for example DEFAULT, FUTURE or FIPS policy. -Or create and apply a custom policy that restricts minimum TLS version to 1.2. - -For example for versions prior to crypto-policies-20210617-1.gitc776d3e.el8.noarch -this is expected: - -$ sudo grep -i MinProtocol /etc/crypto-policies/back-ends/opensslcnf.config - -MinProtocol = TLSv1.2 - - -Or for version crypto-policies-20210617-1.gitc776d3e.el8.noarch and newer this is -expected: - -$ sudo grep -i MinProtocol /etc/crypto-policies/back-ends/opensslcnf.config - -TLS.MinProtocol = TLSv1.2 -DTLS.MinProtocol = DTLSv1.2 - This rule doesn't come with a remediation, automatically changing the crypto-policies may be too disruptive. -Ensure the variable xccdf_org.ssgproject.content_value_var_system_crypto_policy is set to a -Crypto Policy that satisfies OpenSSL minimum TLS protocol version 1.2. Custom policies may be applied too. - CCI-001453 - AC-17(2) - SRG-OS-000125-GPOS-00065 - SRG-OS-000250-GPOS-00093 - SRG-OS-000393-GPOS-00173 - SRG-OS-000394-GPOS-00174 - Without cryptographic integrity protections, information can be altered by -unauthorized users without detection. - - - - - - - - - Configure SSH to use System Crypto Policy - Crypto Policies provide a centralized control over crypto algorithms usage of many packages. + + + + + + + + + + Configure SSH to use System Crypto Policy + Crypto Policies provide a centralized control over crypto algorithms usage of many packages. SSH is supported by crypto policy, but the SSH configuration may be set up to ignore it. To check that Crypto Policies settings are configured correctly, ensure that the CRYPTO_POLICY variable is either commented or not set at all -in the /etc/sysconfig/sshd. - CCI-001453 - 164.308(a)(4)(i) - 164.308(b)(1) - 164.308(b)(3) - 164.312(e)(1) - 164.312(e)(2)(ii) - CIP-003-8 R4.2 - CIP-007-3 R5.1 - CIP-007-3 R7.1 - AC-17(a) - AC-17(2) - CM-6(a) - MA-4(6) - SC-13 - FCS_SSH_EXT.1 - FCS_SSHS_EXT.1 - FCS_SSHC_EXT.1 - Req-2.2 - 2.2 - SRG-OS-000250-GPOS-00093 - Overriding the system crypto policy makes the behavior of the SSH service violate expectations, -and makes system configuration more fragmented. - +in the /etc/sysconfig/sshd. + CCI-001453 + 164.308(a)(4)(i) + 164.308(b)(1) + 164.308(b)(3) + 164.312(e)(1) + 164.312(e)(2)(ii) + CIP-003-8 R4.2 + CIP-007-3 R5.1 + CIP-007-3 R7.1 + AC-17(a) + AC-17(2) + CM-6(a) + MA-4(6) + SC-13 + FCS_SSH_EXT.1 + FCS_SSHS_EXT.1 + FCS_SSHC_EXT.1 + Req-2.2 + SRG-OS-000250-GPOS-00093 + A.5.SEC-OL6 + 2.2.7 + 2.2 + Overriding the system crypto policy makes the behavior of the SSH service violate expectations, +and makes system configuration more fragmented. + SSH_CONF="/etc/sysconfig/sshd" sed -i "/^\s*CRYPTO_POLICY.*$/Id" $SSH_CONF - - - name: Configure SSH to use System Crypto Policy + + - name: Configure SSH to use System Crypto Policy lineinfile: dest: /etc/sysconfig/sshd state: absent - regexp: ^\s*(?i)CRYPTO_POLICY.*$ + regexp: (?i)^\s*CRYPTO_POLICY.*$ tags: - NIST-800-53-AC-17(2) - NIST-800-53-AC-17(a) @@ -4902,41 +6301,41 @@ sed -i "/^\s*CRYPTO_POLICY.*$/Id" $SSH_CONF - NIST-800-53-SC-13 - PCI-DSS-Req-2.2 - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.7 - configure_ssh_crypto_policy - disable_strategy - low_complexity - medium_disruption - medium_severity - reboot_required - - - - - - - - - - Harden SSH client Crypto Policy - Crypto Policies are means of enforcing certain cryptographic settings for selected applications including OpenSSH client. + + + + + + + + + + Harden SSH client Crypto Policy + Crypto Policies are means of enforcing certain cryptographic settings for selected applications including OpenSSH client. To override the system wide crypto policy for Openssh client, place a file in the /etc/ssh/ssh_config.d/ so that it is loaded before the 05-redhat.conf. In this case it is file named 02-ospp.conf containing parameters which need to be changed with respect to the crypto policy. This rule checks if the file exists and if it contains required parameters and values which modify the Crypto Policy. -During the parsing process, as soon as Openssh client parses some configuration option and its value, it remembers it and ignores any subsequent overrides. The customization mechanism provided by crypto policies appends eventual customizations at the end of the system wide crypto policy. Therefore, if the crypto policy customization overrides some parameter which is already configured in the system wide crypto policy, the SSH client will not honor that customized parameter. - CIP-003-8 R4.2 - CIP-007-3 R5.1 - CIP-007-3 R7.1 - AC-17(a) - AC-17(2) - CM-6(a) - MA-4(6) - SC-13 - FCS_SSHC_EXT.1 - SRG-OS-000033-GPOS-00014 - SRG-OS-000250-GPOS-00093 - SRG-OS-000393-GPOS-00173 - SRG-OS-000394-GPOS-00174 - The Common Criteria requirements specify how certain parameters for OpenSSH Client are configured. Particular parameters are RekeyLimit, GSSAPIAuthentication, Ciphers, PubkeyAcceptedKeyTypes, MACs and KexAlgorithms. Currently particular requirements specified by CC are stricter compared to any existing Crypto Policy. - +During the parsing process, as soon as Openssh client parses some configuration option and its value, it remembers it and ignores any subsequent overrides. The customization mechanism provided by crypto policies appends eventual customizations at the end of the system wide crypto policy. Therefore, if the crypto policy customization overrides some parameter which is already configured in the system wide crypto policy, the SSH client will not honor that customized parameter. + CIP-003-8 R4.2 + CIP-007-3 R5.1 + CIP-007-3 R7.1 + AC-17(a) + AC-17(2) + CM-6(a) + MA-4(6) + SC-13 + SRG-OS-000033-GPOS-00014 + SRG-OS-000250-GPOS-00093 + SRG-OS-000393-GPOS-00173 + SRG-OS-000394-GPOS-00174 + The Common Criteria requirements specify how certain parameters for OpenSSH Client are configured. Particular parameters are RekeyLimit, GSSAPIAuthentication, Ciphers, PubkeyAcceptedKeyTypes, MACs and KexAlgorithms. Currently particular requirements specified by CC are stricter compared to any existing Crypto Policy. + #the file starts with 02 so that it is loaded before the 05-redhat.conf which activates configuration provided by system vide crypto policy file="/etc/ssh/ssh_config.d/02-ospp.conf" echo -e "Match final all\n\ @@ -4946,26 +6345,28 @@ Ciphers aes256-ctr,aes256-cbc,aes128-ctr,aes128-cbc\n\ PubkeyAcceptedKeyTypes ssh-rsa,ecdsa-sha2-nistp384,ecdsa-sha2-nistp256\n\ MACs hmac-sha2-512,hmac-sha2-256\n\ KexAlgorithms ecdh-sha2-nistp521,ecdh-sha2-nistp384,ecdh-sha2-nistp256,diffie-hellman-group14-sha1\n" > "$file" - - - - - - - - - - Configure SSH Client to Use FIPS 140-2 Validated Ciphers: openssh.config - Crypto Policies provide a centralized control over crypto algorithms usage of many packages. + + + + + + + + + + Configure SSH Client to Use FIPS 140 Validated Ciphers: openssh.config + Crypto Policies provide a centralized control over crypto algorithms usage of many packages. OpenSSH is supported by system crypto policy, but the OpenSSH configuration may be set up incorrectly. To check that Crypto Policies settings for ciphers are configured correctly, ensure that /etc/crypto-policies/back-ends/openssh.config contains the following line and is not commented out: -Ciphers - The system needs to be rebooted for these changes to take effect. - System Crypto Modules must be provided by a vendor that undergoes +Ciphers + + + The system needs to be rebooted for these changes to take effect. + System Crypto Modules must be provided by a vendor that undergoes FIPS-140 certifications. FIPS-140 is applicable to all Federal agencies that use cryptographic-based security systems to protect sensitive information @@ -4974,51 +6375,94 @@ defined in Section 5131 of the Information Technology Management Reform Act of 1996, Public Law 104-106. This standard shall be used in designing and implementing cryptographic modules that Federal departments and agencies operate or are operated for them under -contract. See https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.140-2.pdf +contract. To meet this, the system has to have cryptographic software provided by a vendor that has undergone this certification. This means providing documentation, test results, design information, and independent third party review by an accredited lab. While open source software is capable of meeting this, it does not meet FIPS-140 unless the vendor -submits to this process. - CCI-000068 - CCI-000877 - CCI-001453 - CCI-002418 - CCI-002890 - CCI-003123 - AC-17(2) - SRG-OS-000033-GPOS-00014 - SRG-OS-000125-GPOS-00065 - SRG-OS-000250-GPOS-00093 - SRG-OS-000393-GPOS-00173 - SRG-OS-000394-GPOS-00174 - SRG-OS-000423-GPOS-00187 - Overriding the system crypto policy makes the behavior of the OpenSSH client +submits to this process. + CCI-001453 + AC-17(2) + SRG-OS-000033-GPOS-00014 + SRG-OS-000125-GPOS-00065 + SRG-OS-000250-GPOS-00093 + SRG-OS-000393-GPOS-00173 + SRG-OS-000394-GPOS-00174 + SRG-OS-000423-GPOS-00187 + OL09-00-000261 + SV-271489r1092627_rule + Overriding the system crypto policy makes the behavior of the OpenSSH client violate expectations, and makes system configuration more fragmented. By specifying a cipher list with the order of ciphers being in a “strongest to weakest” orientation, the system will automatically attempt to use the -strongest cipher for securing SSH connections. - - - - - - - - - - Configure SSH Server to Use FIPS 140-2 Validated Ciphers: opensshserver.config - Crypto Policies provide a centralized control over crypto algorithms usage of many packages. +strongest cipher for securing SSH connections. + - name: XCCDF Value sshd_approved_ciphers # promote to variable + set_fact: + sshd_approved_ciphers: !!str + tags: + - always + +- name: 'Configure SSH Daemon to Use FIPS 140-2 Validated Ciphers: openssh.config' + block: + + - name: Check for duplicate values + lineinfile: + path: /etc/crypto-policies/back-ends/openssh.config + create: true + regexp: (?i)^.*Ciphers\s+ + state: absent + check_mode: true + changed_when: false + register: dupes + + - name: Deduplicate values from /etc/crypto-policies/back-ends/openssh.config + lineinfile: + path: /etc/crypto-policies/back-ends/openssh.config + create: true + regexp: (?i)^.*Ciphers\s+ + state: absent + when: dupes.found is defined and dupes.found > 1 + + - name: Insert correct line to /etc/crypto-policies/back-ends/openssh.config + lineinfile: + path: /etc/crypto-policies/back-ends/openssh.config + create: true + regexp: (?i)^.*Ciphers\s+ + line: Ciphers {{ sshd_approved_ciphers }} + state: present + tags: + - DISA-STIG-OL09-00-000261 + - NIST-800-53-AC-17(2) + - harden_sshd_ciphers_openssh_conf_crypto_policy + - high_severity + - low_complexity + - low_disruption + - reboot_required + - restrict_strategy + + + + + + + + + + + Configure SSH Server to Use FIPS 140-2 Validated Ciphers: opensshserver.config + Crypto Policies provide a centralized control over crypto algorithms usage of many packages. OpenSSH is supported by system crypto policy, but the OpenSSH configuration may be set up incorrectly. To check that Crypto Policies settings for ciphers are configured correctly, ensure that /etc/crypto-policies/back-ends/opensshserver.config contains the following text and is not commented out: --oCiphers= - The system needs to be rebooted for these changes to take effect. - System Crypto Modules must be provided by a vendor that undergoes +-oCiphers= + + + The system needs to be rebooted for these changes to take effect. + System Crypto Modules must be provided by a vendor that undergoes FIPS-140 certifications. FIPS-140 is applicable to all Federal agencies that use cryptographic-based security systems to protect sensitive information @@ -5033,37 +6477,40 @@ a vendor that has undergone this certification. This means providing documentation, test results, design information, and independent third party review by an accredited lab. While open source software is capable of meeting this, it does not meet FIPS-140 unless the vendor -submits to this process. - CCI-000877 - CCI-001453 - AC-17(2) - SRG-OS-000125-GPOS-00065 - SRG-OS-000250-GPOS-00093 - Overriding the system crypto policy makes the behavior of the OpenSSH server +submits to this process. + CCI-001453 + AC-17(2) + SRG-OS-000125-GPOS-00065 + SRG-OS-000250-GPOS-00093 + OL09-00-000254 + SV-271485r1092625_rule + Overriding the system crypto policy makes the behavior of the OpenSSH server violate expectations, and makes system configuration more fragmented. By specifying a cipher list with the order of ciphers being in a “strongest to weakest” orientation, the system will automatically attempt to use the -strongest cipher for securing SSH connections. - - - - - - - - - - Configure SSH Client to Use FIPS 140-2 Validated MACs: openssh.config - Crypto Policies provide a centralized control over crypto algorithms usage of many packages. +strongest cipher for securing SSH connections. + + + + + + + + + + Configure SSH Client to Use FIPS 140-2 Validated MACs: openssh.config + Crypto Policies provide a centralized control over crypto algorithms usage of many packages. OpenSSH is supported by system crypto policy, but the OpenSSH configuration may be set up incorrectly. To check that Crypto Policies settings are configured correctly, ensure that /etc/crypto-policies/back-ends/openssh.config contains the following line and is not commented out: -MACs hmac-sha2-512,hmac-sha2-256 - The system needs to be rebooted for these changes to take effect. - System Crypto Modules must be provided by a vendor that undergoes +MACs + + + The system needs to be rebooted for these changes to take effect. + System Crypto Modules must be provided by a vendor that undergoes FIPS-140 certifications. FIPS-140 is applicable to all Federal agencies that use cryptographic-based security systems to protect sensitive information @@ -5078,35 +6525,37 @@ a vendor that has undergone this certification. This means providing documentation, test results, design information, and independent third party review by an accredited lab. While open source software is capable of meeting this, it does not meet FIPS-140 unless the vendor -submits to this process. - CCI-000877 - CCI-001453 - AC-17(2) - SRG-OS-000125-GPOS-00065 - SRG-OS-000250-GPOS-00093 - Overriding the system crypto policy makes the behavior of the OpenSSH +submits to this process. + CCI-000877 + CCI-001453 + AC-17(2) + SRG-OS-000125-GPOS-00065 + SRG-OS-000250-GPOS-00093 + Overriding the system crypto policy makes the behavior of the OpenSSH client violate expectations, and makes system configuration more -fragmented. - - - - - - - - - - Configure SSH Server to Use FIPS 140-2 Validated MACs: opensshserver.config - Crypto Policies provide a centralized control over crypto algorithms usage of many packages. +fragmented. + + + + + + + + + + Configure SSH Server to Use FIPS 140-2 Validated MACs: opensshserver.config + Crypto Policies provide a centralized control over crypto algorithms usage of many packages. OpenSSH is supported by system crypto policy, but the OpenSSH configuration may be set up incorrectly. To check that Crypto Policies settings are configured correctly, ensure that /etc/crypto-policies/back-ends/opensshserver.config contains the following text and is not commented out: --oMACS=hmac-sha2-512,hmac-sha2-256,hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com - The system needs to be rebooted for these changes to take effect. - System Crypto Modules must be provided by a vendor that undergoes +-oMACS= + + + The system needs to be rebooted for these changes to take effect. + System Crypto Modules must be provided by a vendor that undergoes FIPS-140 certifications. FIPS-140 is applicable to all Federal agencies that use cryptographic-based security systems to protect sensitive information @@ -5121,439 +6570,162 @@ a vendor that has undergone this certification. This means providing documentation, test results, design information, and independent third party review by an accredited lab. While open source software is capable of meeting this, it does not meet FIPS-140 unless the vendor -submits to this process. - CCI-000877 - CCI-001453 - AC-17(2) - SRG-OS-000125-GPOS-00065 - SRG-OS-000250-GPOS-00093 - Overriding the system crypto policy makes the behavior of the OpenSSH +submits to this process. + CCI-000877 + CCI-001453 + AC-17(2) + SRG-OS-000125-GPOS-00065 + SRG-OS-000250-GPOS-00093 + Overriding the system crypto policy makes the behavior of the OpenSSH server violate expectations, and makes system configuration more -fragmented. - - - - - - - - - - - Operating System Vendor Support and Certification - The assurance of a vendor to provide operating system support and maintenance +fragmented. + + + + + + + + + + + Operating System Vendor Support and Certification + The assurance of a vendor to provide operating system support and maintenance for their product is an important criterion to ensure product stability and security over the life of the product. A certified product that follows the necessary standards and government certification requirements guarantees that known software vulnerabilities will be remediated, and proper guidance for -protecting and securing the operating system will be given. - - The Installed Operating System Is Vendor Supported - The installed operating system must be maintained by a vendor. +protecting and securing the operating system will be given. + + The Installed Operating System Is Vendor Supported + The installed operating system must be maintained by a vendor. Oracle Linux is supported by Oracle Corporation. As the Oracle -Linux vendor, Oracle Corporation is responsible for providing security patches. - There is no remediation besides switching to a different operating system. - 18 - 20 - 4 - APO12.01 - APO12.02 - APO12.03 - APO12.04 - BAI03.10 - DSS05.01 - DSS05.02 - CCI-000366 - 4.2.3 - 4.2.3.12 - 4.2.3.7 - 4.2.3.9 - A.12.6.1 - A.14.2.3 - A.16.1.3 - A.18.2.2 - A.18.2.3 - CM-6(a) - MA-6 - SA-13(a) - ID.RA-1 - PR.IP-12 - SRG-OS-000480-GPOS-00227 - An operating system is considered "supported" if the vendor continues to +Linux vendor, Oracle Corporation is responsible for providing security patches. + There is no remediation besides switching to a different operating system. + 18 + 20 + 4 + APO12.01 + APO12.02 + APO12.03 + APO12.04 + BAI03.10 + DSS05.01 + DSS05.02 + CCI-000366 + 4.2.3 + 4.2.3.12 + 4.2.3.7 + 4.2.3.9 + A.12.6.1 + A.14.2.3 + A.16.1.3 + A.18.2.2 + A.18.2.3 + CM-6(a) + MA-6 + SA-13(a) + ID.RA-1 + PR.IP-12 + SRG-OS-000480-GPOS-00227 + OL09-00-000010 + SV-271438r1091026_rule + An operating system is considered "supported" if the vendor continues to provide security patches for the product. With an unsupported release, it will not be possible to resolve any security issue discovered in the system -software. - - - - - - - - - - Endpoint Protection Software - Endpoint protection security software that is not provided or supported +software. + + + + + + + + + + Endpoint Protection Software + Endpoint protection security software that is not provided or supported by Oracle Corporation can be installed to provide complementary or duplicative security capabilities to those provided by the base platform. Add-on -software may not be appropriate for some specialized systems. - - Configure Backups of User Data - The operating system must conduct backups of user data contained +software may not be appropriate for some specialized systems. + + Configure Backups of User Data + The operating system must conduct backups of user data contained in the operating system. The operating system provides utilities for automating backups of user data. Commercial and open-source products -are also available. - Operating system backup is a critical step in maintaining data assurance and +are also available. + Operating system backup is a critical step in maintaining data assurance and availability. User-level information is data generated by information system and/or application users. Backups shall be consistent with organizational -recovery time and recovery point objectives. - - - - - - Install Intrusion Detection Software - The base Oracle Linux 9 platform already includes a sophisticated auditing system that -can detect intruder activity, as well as SELinux, which provides host-based -intrusion prevention capabilities by confining privileged programs and user -sessions which may become compromised. - In DoD environments, supplemental intrusion detection and antivirus tools, -such as the McAfee Host-based Security System, are available to integrate with -existing infrastructure. Per DISA guidance, when these supplemental tools interfere -with proper functioning of SELinux, SELinux takes precedence. Should further -clarification be required, DISA contact information is published publicly at -https://public.cyber.mil/stigs/ - 1 - 12 - 13 - 14 - 15 - 16 - 18 - 7 - 8 - 9 - APO01.06 - APO13.01 - DSS01.03 - DSS01.05 - DSS03.05 - DSS05.02 - DSS05.04 - DSS05.07 - DSS06.02 - CCI-001263 - 4.3.3.4 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 6.2 - SR 7.1 - SR 7.6 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CM-6(a) - DE.CM-1 - PR.AC-5 - PR.DS-5 - PR.PT-4 - Req-11.4 - 11.5.1.1 - Host-based intrusion detection tools provide a system-level defense when an -intruder gains access to a system or network. - - - - - - - - - - - McAfee Endpoint Security Software - In DoD environments, McAfee Host-based Security System (HBSS) and -VirusScan Enterprise for Linux (VSEL) is required to be installed on all systems. - - The age of McAfee defintion file before requiring updating - Specify the amount of time (in seconds) before McAfee definition files need to be -updated. - 2592000 - 86400 - 604800 - 2592000 - - - McAfee Endpoint Security for Linux (ENSL) - McAfee Endpoint Security for Linux (ENSL) is a suite of software applications -used to monitor, detect, and defend computer networks and systems. - - - Install McAfee Endpoint Security for Linux (ENSL) - Install McAfee Endpoint Security for Linux antivirus software +recovery time and recovery point objectives. + + + + + + McAfee Endpoint Security Software + In DoD environments, McAfee Host-based Security System (HBSS) and +VirusScan Enterprise for Linux (VSEL) is required to be installed on all systems. + + McAfee Endpoint Security for Linux (ENSL) + McAfee Endpoint Security for Linux (ENSL) is a suite of software applications +used to monitor, detect, and defend computer networks and systems. + + + Install McAfee Endpoint Security for Linux (ENSL) + Install McAfee Endpoint Security for Linux antivirus software which is provided for DoD systems and uses signatures to search for the presence of viruses on the filesystem. The McAfeeTP package can be installed with the following command: -$ sudo yum install McAfeeTP - Due to McAfee Endpoint Security for Linux (ENSL) being 3rd party software, -automated remediation is not available for this configuration check. - CCI-001263 - CCI-000366 - SI-2(2) - SRG-OS-000191-GPOS-00080 - Virus scanning software can be used to detect if a system has been compromised by -computer viruses, as well as to limit their spread to other systems. - - - - - - - - - Ensure McAfee Endpoint Security for Linux (ENSL) is running - Install McAfee Endpoint Security for Linux antivirus software +$ sudo yum install McAfeeTP + + Due to McAfee Endpoint Security for Linux (ENSL) being 3rd party software, +automated remediation is not available for this configuration check. + CCI-001263 + CCI-000366 + SI-2(2) + SRG-OS-000191-GPOS-00080 + Virus scanning software can be used to detect if a system has been compromised by +computer viruses, as well as to limit their spread to other systems. + + + + + + + + + Ensure McAfee Endpoint Security for Linux (ENSL) is running + Install McAfee Endpoint Security for Linux antivirus software which is provided for DoD systems and uses signatures to search for the -presence of viruses on the filesystem. - Due to McAfee Endpoint Security for Linux (ENSL) being 3rd party software, -automated remediation is not available for this configuration check. - CCI-001263 - CCI-000366 - SI-2(2) - SRG-OS-000191-GPOS-00080 - Virus scanning software can be used to detect if a system has been compromised by -computer viruses, as well as to limit their spread to other systems. - - - - - - - - - - McAfee Host-Based Intrusion Detection Software (HBSS) - McAfee Host-based Security System (HBSS) is a suite of software applications -used to monitor, detect, and defend computer networks and systems. - - Install the Host Intrusion Prevention System (HIPS) Module - Install the McAfee Host Intrusion Prevention System (HIPS) Module if it is absolutely -necessary. If SELinux is enabled, do not install or enable this module. - Installing and enabling this module conflicts with SELinux. -Per DoD/DISA guidance, SELinux takes precedence over this module. - Due to McAfee HIPS being 3rd party software, automated -remediation is not available for this configuration check. - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 18 - 19 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - APO01.06 - APO07.06 - APO08.04 - APO10.05 - APO11.06 - APO12.01 - APO12.02 - APO12.03 - APO12.04 - APO12.06 - APO13.01 - APO13.02 - BAI08.02 - BAI08.04 - DSS01.03 - DSS01.05 - DSS02.04 - DSS02.05 - DSS02.07 - DSS03.01 - DSS03.04 - DSS03.05 - DSS04.05 - DSS05.01 - DSS05.02 - DSS05.04 - DSS05.05 - DSS05.07 - DSS06.01 - DSS06.02 - MEA03.03 - MEA03.04 - CCI-000366 - CCI-001233 - CCI-001263 - 4.2.3 - 4.2.3.12 - 4.2.3.7 - 4.2.3.9 - 4.3.3.4 - 4.3.4.5.2 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.3.4.5.9 - 4.4.3.2 - 4.4.3.3 - 4.4.3.4 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.4 - SR 2.8 - SR 2.9 - SR 3.1 - SR 3.3 - SR 3.5 - SR 3.8 - SR 3.9 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 6.1 - SR 6.2 - SR 7.1 - SR 7.6 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.12.1.1 - A.12.1.2 - A.12.4.1 - A.12.4.3 - A.12.5.1 - A.12.6.1 - A.12.6.2 - A.13.1.1 - A.13.1.2 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.14.2.7 - A.14.2.8 - A.15.2.1 - A.16.1.1 - A.16.1.2 - A.16.1.3 - A.16.1.4 - A.16.1.5 - A.16.1.6 - A.16.1.7 - A.18.1.4 - A.18.2.2 - A.18.2.3 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - Clause 16.1.2 - Clause 7.4 - CM-6(a) - DE.AE-1 - DE.AE-2 - DE.AE-3 - DE.AE-4 - DE.CM-1 - DE.CM-5 - DE.CM-6 - DE.CM-7 - DE.DP-2 - DE.DP-3 - DE.DP-4 - DE.DP-5 - ID.RA-1 - PR.AC-5 - PR.DS-5 - PR.IP-8 - PR.PT-4 - RS.AN-1 - RS.CO-3 - Req-11.4 - 11.5.1.1 - SRG-OS-000191-GPOS-00080 - SRG-OS-000196 - SRG-OS-000480-GPOS-00227 - Without a host-based intrusion detection tool, there is no system-level defense -when an intruder gains access to a system or network. Additionally, a host-based -intrusion prevention tool can provide methods to immediately lock out detected -intrusion attempts. - - -[[packages]] -name = "MFEhiplsm" -version = "*" - - - - - - - - - - - - - - Disk Partitioning - To ensure separation and protection of data, there +presence of viruses on the filesystem. + Due to McAfee Endpoint Security for Linux (ENSL) being 3rd party software, +automated remediation is not available for this configuration check. + CCI-001263 + CCI-000366 + SI-2(2) + SRG-OS-000191-GPOS-00080 + Virus scanning software can be used to detect if a system has been compromised by +computer viruses, as well as to limit their spread to other systems. + + + + + + + + + + + + + Disk Partitioning + To ensure separation and protection of data, there are top-level system directories which should be placed on their own physical partition or logical volume. The installer's default partitioning scheme creates separate logical volumes for @@ -5571,528 +6743,609 @@ If a system has already been installed, and the default partitioning scheme was used, it is possible but nontrivial to modify it to create separate logical volumes for the directories -listed above. The Logical Volume Manager (LVM) makes this possible. -See the LVM HOWTO at - http://tldp.org/HOWTO/LVM-HOWTO/ -for more detailed information on LVM. - - Encrypt Partitions - Oracle Linux 9 natively supports partition encryption through the +listed above. The Logical Volume Manager (LVM) makes this possible. + + + Encrypt Partitions + Oracle Linux 9 natively supports partition encryption through the Linux Unified Key Setup-on-disk-format (LUKS) technology. The easiest way to encrypt a partition is during installation time. - + + For manual installations, select the Encrypt checkbox during partition creation to encrypt the partition. When this option is selected the system will prompt for a passphrase to use in decrypting the partition. The passphrase will subsequently need to be entered manually every time the system boots. - + + For automated/unattended installations, it is possible to use Kickstart by adding the --encrypted and --passphrase= options to the definition of each partition to be encrypted. For example, the following line would encrypt the root partition: -part / --fstype=ext4 --size=100 --onpart=hda1 --encrypted --passphrase=PASSPHRASE +part / --fstype=ext4 --size=100 --onpart=hda1 --encrypted --passphrase=PASSPHRASE + Any PASSPHRASE is stored in the Kickstart in plaintext, and the Kickstart must then be protected accordingly. Omitting the --passphrase= option from the partition definition will cause the installer to pause and interactively ask for the passphrase during installation. - + + By default, the Anaconda installer uses aes-xts-plain64 cipher with a minimum 512 bit key size which should be compatible with FIPS enabled. - + + Detailed information on encrypting partitions using LUKS or LUKS ciphers can be found on -the Oracle Linux 9 Documentation web site: - - - https://docs.oracle.com/en/operating-systems/oracle-linux/9/install/install-InstallingOracleLinuxManually.html#system-options -. - 13 - 14 - APO01.06 - BAI02.01 - BAI06.01 - DSS04.07 - DSS05.03 - DSS05.04 - DSS05.07 - DSS06.02 - DSS06.06 - 3.13.16 - CCI-001199 - CCI-002475 - CCI-002476 - 164.308(a)(1)(ii)(D) - 164.308(b)(1) - 164.310(d) - 164.312(a)(1) - 164.312(a)(2)(iii) - 164.312(a)(2)(iv) - 164.312(b) - 164.312(c) - 164.314(b)(2)(i) - 164.312(d) - SR 3.4 - SR 4.1 - SR 5.2 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CIP-003-8 R4.2 - CIP-007-3 R5.1 - CM-6(a) - SC-28 - SC-28(1) - SC-13 - AU-9(3) - PR.DS-1 - PR.DS-5 - SRG-OS-000405-GPOS-00184 - SRG-OS-000185-GPOS-00079 - SRG-OS-000404-GPOS-00183 - The risk of a system's physical compromise, particularly mobile systems such as +the Oracle Linux 9 Documentation web site: + https://docs.oracle.com/en/operating-systems/oracle-linux/9/install/install-InstallingOracleLinuxManually.html#system-options +. + 13 + 14 + APO01.06 + BAI02.01 + BAI06.01 + DSS04.07 + DSS05.03 + DSS05.04 + DSS05.07 + DSS06.02 + DSS06.06 + 3.13.16 + CCI-002476 + CCI-001199 + CCI-002475 + 164.308(a)(1)(ii)(D) + 164.308(b)(1) + 164.310(d) + 164.312(a)(1) + 164.312(a)(2)(iii) + 164.312(a)(2)(iv) + 164.312(b) + 164.312(c) + 164.314(b)(2)(i) + 164.312(d) + SR 3.4 + SR 4.1 + SR 5.2 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CIP-003-8 R4.2 + CIP-007-3 R5.1 + CM-6(a) + SC-28 + SC-28(1) + SC-13 + AU-9(3) + PR.DS-1 + PR.DS-5 + SRG-OS-000405-GPOS-00184 + SRG-OS-000185-GPOS-00079 + SRG-OS-000404-GPOS-00183 + A.25.SEC-OL1 + OL09-00-000001 + OL09-00-002418 + SV-271431r1092616_rule + SV-271756r1091980_rule + The risk of a system's physical compromise, particularly mobile systems such as laptops, places its data at risk of compromise. Encrypting this data mitigates -the risk of its loss if the system is lost. - - - - - - - Ensure /dev/shm is configured - The /dev/shm is a traditional shared memory concept. -One program will create a memory portion, which other processes -(if permitted) can access. If /dev/shm is not configured, -tmpfs will be mounted to /dev/shm by systemd. - Any user can upload and execute files inside the /dev/shm similar to -the /tmp partition. Configuring /dev/shm allows an administrator -to set the noexec option on the mount, making /dev/shm useless for an attacker to -install executable code. It would also prevent an attacker from establishing a -hardlink to a system setuid program and wait for it to be updated. Once the program -was updated, the hardlink would be broken and the attacker would have his own copy -of the program. If the program happened to have a security vulnerability, the attacker -could continue to exploit the known flaw. - - -part /dev/shm - - - - - - - - - - Ensure /home Located On Separate Partition - If user home directories will be stored locally, create a separate partition +the risk of its loss if the system is lost. + + + + + + Ensure /dev/shm is configured + The /dev/shm is a traditional shared memory concept. +One program will create a memory portion, which other processes +(if permitted) can access. If /dev/shm is not configured, +tmpfs will be mounted to /dev/shm by systemd. + This rule does not have a remedation. +It is expected that this will be managed by systemd and will be a tmpfs partition. + Any user can upload and execute files inside the /dev/shm similar to +the /tmp partition. Configuring /dev/shm allows an administrator +to set the noexec option on the mount, making /dev/shm useless for an attacker to +install executable code. It would also prevent an attacker from establishing a +hardlink to a system setuid program and wait for it to be updated. Once the program +was updated, the hardlink would be broken and the attacker would have his own copy +of the program. If the program happened to have a security vulnerability, the attacker +could continue to exploit the known flaw. + + + + + + + + + Ensure /home Located On Separate Partition + If user home directories will be stored locally, create a separate partition for /home at installation time (or migrate it later using LVM). If /home will be mounted from another system such as an NFS server, then creating a separate partition is not necessary at installation time, and the -mountpoint can instead be configured later. - BP28(R12) - 12 - 15 - 8 - APO13.01 - DSS05.02 - CCI-000366 - CCI-001208 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 7.1 - SR 7.6 - A.13.1.1 - A.13.2.1 - A.14.1.3 - CM-6(a) - SC-5(2) - PR.PT-4 - SRG-OS-000480-GPOS-00227 - Ensuring that /home is mounted on its own partition enables the +mountpoint can instead be configured later. + 12 + 15 + 8 + APO13.01 + DSS05.02 + CCI-000366 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 7.1 + SR 7.6 + A.13.1.1 + A.13.2.1 + A.14.1.3 + CM-6(a) + SC-5(2) + PR.PT-4 + SRG-OS-000480-GPOS-00227 + R28 + OL09-00-000003 + SV-271433r1091011_rule + Ensuring that /home is mounted on its own partition enables the setting of more restrictive mount options, and also helps ensure that -users cannot trivially fill partitions used for log or audit data storage. - - +users cannot trivially fill partitions used for log or audit data storage. + part /home - - - - - - - - - - Ensure /srv Located On Separate Partition - If a file server (FTP, TFTP...) is hosted locally, create a separate partition + + + + + + + + + + Ensure /srv Located On Separate Partition + If a file server (FTP, TFTP...) is hosted locally, create a separate partition for /srv at installation time (or migrate it later using LVM). If /srv will be mounted from another system such as an NFS server, then creating a separate partition is not necessary at installation time, and the -mountpoint can instead be configured later. - BP28(R12) - Srv deserves files for local network file server such as FTP. Ensuring +mountpoint can instead be configured later. + R28 + Srv deserves files for local network file server such as FTP. Ensuring that /srv is mounted on its own partition enables the setting of more restrictive mount options, and also helps ensure that -users cannot trivially fill partitions used for log or audit data storage. - - +users cannot trivially fill partitions used for log or audit data storage. + part /srv - - - - - - - - - - Ensure /tmp Located On Separate Partition - The /tmp directory is a world-writable directory used + + + + + + + + + + Ensure /tmp Located On Separate Partition + The /tmp directory is a world-writable directory used for temporary file storage. Ensure it has its own partition or -logical volume at installation time, or migrate it using LVM. - BP28(R12) - 12 - 15 - 8 - APO13.01 - DSS05.02 - CCI-000366 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 7.1 - SR 7.6 - A.13.1.1 - A.13.2.1 - A.14.1.3 - CM-6(a) - SC-5(2) - PR.PT-4 - SRG-OS-000480-GPOS-00227 - The /tmp partition is used as temporary storage by many programs. +logical volume at installation time, or migrate it using LVM. + 12 + 15 + 8 + APO13.01 + DSS05.02 + CCI-000366 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 7.1 + SR 7.6 + A.13.1.1 + A.13.2.1 + A.14.1.3 + CM-6(a) + SC-5(2) + PR.PT-4 + SRG-OS-000480-GPOS-00227 + OL09-00-000004 + SV-271434r1091014_rule + The /tmp partition is used as temporary storage by many programs. Placing /tmp in its own partition enables the setting of more -restrictive mount options, which can help protect programs which use it. - - +restrictive mount options, which can help protect programs which use it. + part /tmp - - - - - - - - - - Ensure /var Located On Separate Partition - The /var directory is used by daemons and other system + + + + + + + + + + Ensure /var Located On Separate Partition + The /var directory is used by daemons and other system services to store frequently-changing data. Ensure that /var has its own partition -or logical volume at installation time, or migrate it using LVM. - BP28(R12) - 12 - 15 - 8 - APO13.01 - DSS05.02 - CCI-000366 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 7.1 - SR 7.6 - A.13.1.1 - A.13.2.1 - A.14.1.3 - CM-6(a) - SC-5(2) - PR.PT-4 - SRG-OS-000480-GPOS-00227 - Ensuring that /var is mounted on its own partition enables the +or logical volume at installation time, or migrate it using LVM. + 12 + 15 + 8 + APO13.01 + DSS05.02 + CCI-000366 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 7.1 + SR 7.6 + A.13.1.1 + A.13.2.1 + A.14.1.3 + CM-6(a) + SC-5(2) + PR.PT-4 + SRG-OS-000480-GPOS-00227 + R28 + OL09-00-000005 + SV-271435r1091017_rule + Ensuring that /var is mounted on its own partition enables the setting of more restrictive mount options. This helps protect system services such as daemons or other programs which use it. It is not uncommon for the /var directory to contain -world-writable directories installed by other software packages. - - +world-writable directories installed by other software packages. + part /var - - - - - - - - - - Ensure /var/log Located On Separate Partition - System logs are stored in the /var/log directory. + + + + + + + + + + Ensure /var/log Located On Separate Partition + System logs are stored in the /var/log directory. Ensure that /var/log has its own partition or logical -volume at installation time, or migrate it using LVM. - BP28(R12) - BP28(R47) - 1 - 12 - 14 - 15 - 16 - 3 - 5 - 6 - 8 - APO11.04 - APO13.01 - BAI03.05 - DSS05.02 - DSS05.04 - DSS05.07 - MEA02.01 - CCI-000366 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.4.4.7 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.8 - SR 2.9 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 7.1 - SR 7.6 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.13.1.1 - A.13.2.1 - A.14.1.3 - CIP-007-3 R6.5 - CM-6(a) - AU-4 - SC-5(2) - PR.PT-1 - PR.PT-4 - SRG-OS-000480-GPOS-00227 - Placing /var/log in its own partition +volume at installation time, or migrate it using LVM. + 1 + 12 + 14 + 15 + 16 + 3 + 5 + 6 + 8 + APO11.04 + APO13.01 + BAI03.05 + DSS05.02 + DSS05.04 + DSS05.07 + MEA02.01 + CCI-000366 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.4.4.7 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.8 + SR 2.9 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 7.1 + SR 7.6 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.13.1.1 + A.13.2.1 + A.14.1.3 + CIP-007-3 R6.5 + CM-6(a) + AU-4 + SC-5(2) + PR.PT-1 + PR.PT-4 + SRG-OS-000480-GPOS-00227 + R28 + OL09-00-000006 + SV-271436r1091020_rule + Placing /var/log in its own partition enables better separation between log files -and other files in /var/. - - +and other files in /var/. + part /var/log - - - - - - - - - - Ensure /var/log/audit Located On Separate Partition - Audit logs are stored in the /var/log/audit directory. + + + + + + + + + + Ensure /var/log/audit Located On Separate Partition + Audit logs are stored in the /var/log/audit directory. Ensure that /var/log/audit has its own partition or logical volume at installation time, or migrate it using LVM. Make absolutely certain that it is large enough to store all -audit logs that will be created by the auditing daemon. - BP28(R43) - 1 - 12 - 13 - 14 - 15 - 16 - 2 - 3 - 5 - 6 - 8 - APO11.04 - APO13.01 - BAI03.05 - BAI04.04 - DSS05.02 - DSS05.04 - DSS05.07 - MEA02.01 - CCI-000366 - CCI-001849 - 164.312(a)(2)(ii) - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.4.4.7 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.8 - SR 2.9 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 7.1 - SR 7.2 - SR 7.6 - A.12.1.3 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.17.2.1 - CIP-007-3 R6.5 - CM-6(a) - AU-4 - SC-5(2) - PR.DS-4 - PR.PT-1 - PR.PT-4 - FMT_SMF_EXT.1 - SRG-OS-000341-GPOS-00132 - SRG-OS-000480-GPOS-00227 - Placing /var/log/audit in its own partition +audit logs that will be created by the auditing daemon. + 1 + 12 + 13 + 14 + 15 + 16 + 2 + 3 + 5 + 6 + 8 + APO11.04 + APO13.01 + BAI03.05 + BAI04.04 + DSS05.02 + DSS05.04 + DSS05.07 + MEA02.01 + CCI-000366 + CCI-001849 + 164.312(a)(2)(ii) + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.4.4.7 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.8 + SR 2.9 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 7.1 + SR 7.2 + SR 7.6 + A.12.1.3 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.13.1.1 + A.13.2.1 + A.14.1.3 + A.17.2.1 + CIP-007-3 R6.5 + CM-6(a) + AU-4 + SC-5(2) + PR.DS-4 + PR.PT-1 + PR.PT-4 + FMT_SMF_EXT.1 + SRG-OS-000341-GPOS-00132 + SRG-OS-000480-GPOS-00227 + SRG-APP-000357-CTR-000800 + R71 + OL09-00-000002 + SV-271432r1091008_rule + Placing /var/log/audit in its own partition enables better separation between audit files and other files, and helps ensure that auditing cannot be halted due to the partition running out -of space. - - +of space. + part /var/log/audit - - - - - - - - - - Ensure /var/tmp Located On Separate Partition - The /var/tmp directory is a world-writable directory used + + + + + + + + + + Ensure /var/tmp Located On Separate Partition + The /var/tmp directory is a world-writable directory used for temporary file storage. Ensure it has its own partition or -logical volume at installation time, or migrate it using LVM. - BP28(R12) - SRG-OS-000480-GPOS-00227 - The /var/tmp partition is used as temporary storage by many programs. +logical volume at installation time, or migrate it using LVM. + CCI-000366 + SRG-OS-000480-GPOS-00227 + R28 + OL09-00-000007 + SV-271437r1091023_rule + The /var/tmp partition is used as temporary storage by many programs. Placing /var/tmp in its own partition enables the setting of more -restrictive mount options, which can help protect programs which use it. - - +restrictive mount options, which can help protect programs which use it. + part /var/tmp - - - - - - - - - - - GNOME Desktop Environment - GNOME is a graphical desktop environment bundled with many Linux distributions that + + + + + + + + + + Ensure tmp.mount Unit Is Enabled + The /tmp directory is a world-writable directory used +for temporary file storage. This directory is managed by systemd-tmpfiles. +Ensure that the tmp.mount systemd unit is enabled. + R28 + The /tmp directory is used as temporary storage by many programs. +Placing /tmp in a tmpfs filesystem enables the setting of more +restrictive mount options, which can help protect programs which use it. +The tmp.mount unit configures the tmpfs filesystem and ensures +the /tmp directory is wiped during reboot. + # Remediation is applicable only in certain platforms +if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ); then + +SYSTEMCTL_EXEC='/usr/bin/systemctl' +"$SYSTEMCTL_EXEC" unmask 'tmp.mount' +if [[ $("$SYSTEMCTL_EXEC" is-system-running) != "offline" ]]; then + "$SYSTEMCTL_EXEC" start 'tmp.mount' +fi +"$SYSTEMCTL_EXEC" enable 'tmp.mount' + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - enable_strategy + - low_complexity + - low_disruption + - low_severity + - no_reboot_needed + - systemd_tmp_mount_enabled + +- name: Enable mount tmp + ansible.builtin.systemd: + name: tmp.mount + enabled: 'yes' + state: started + masked: 'false' + when: ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + tags: + - enable_strategy + - low_complexity + - low_disruption + - low_severity + - no_reboot_needed + - systemd_tmp_mount_enabled + + +services --enabled=tmp.mount + + + + + + + + + + + GNOME Desktop Environment + GNOME is a graphical desktop environment bundled with many Linux distributions that allow users to easily interact with the operating system graphically rather than textually. The GNOME Graphical Display Manager (GDM) provides login, logout, and user switching contexts as well as display server management. - + + GNOME is developed by the GNOME Project and is considered the default Oracle Linux Graphical environment. - -For more information on GNOME and the GNOME Project, see https://www.gnome.org. - - - Make sure that the dconf databases are up-to-date with regards to respective keyfiles - By default, DConf uses a binary database as a data backend. + + +For more information on GNOME and the GNOME Project, see https://www.gnome.org. + + + Make sure that the dconf databases are up-to-date with regards to respective keyfiles + By default, DConf uses a binary database as a data backend. The system-level database is compiled from keyfiles in the /etc/dconf/db/ directory by the dconf update command. More specifically, content present in the following directories: -/etc/dconf/db/gdm.d -/etc/dconf/db/local.d - 164.308(a)(1)(ii)(B) - 164.308(a)(5)(ii)(A) - Req-6.2 - 6.3.3 - SRG-OS-000480-GPOS-00227 - Unlike text-based keyfiles, the binary database is impossible to check by OVAL. +/etc/dconf/db/local.d + /etc/dconf/db/local.d + + CCI-000366 + 164.308(a)(1)(ii)(B) + 164.308(a)(5)(ii)(A) + Req-6.2 + SRG-OS-000480-GPOS-00227 + reload_dconf_db + 8.2.8 + 8.2 + OL09-00-002162 + SV-271692r1091788_rule + Unlike text-based keyfiles, the binary database is impossible to check by OVAL. Therefore, in order to evaluate dconf configuration, both have to be true at the same time - configuration files have to be compliant, and the database needs to be more recent than those keyfiles, -which gives confidence that it reflects them. - - # Remediation is applicable only in certain platforms -if rpm --quiet -q gdm && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then +which gives confidence that it reflects them. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q gdm && { rpm --quiet -q kernel || rpm --quiet -q kernel-uek; }; then dconf update else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-002162 - PCI-DSS-Req-6.2 - - PCI-DSSv4-6.3.3 + - PCI-DSSv4-8.2 + - PCI-DSSv4-8.2.8 - dconf_db_up_to_date - high_severity - low_complexity @@ -6105,31 +7358,34 @@ fi cmd: dconf update when: - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-002162 - PCI-DSS-Req-6.2 - - PCI-DSSv4-6.3.3 + - PCI-DSSv4-8.2 + - PCI-DSSv4-8.2.8 - dconf_db_up_to_date - high_severity - low_complexity - medium_disruption - no_reboot_needed - unknown_strategy - - - - - - - - - - Configure GNOME3 DConf User Profile - By default, DConf provides a standard user profile. This profile contains a list + + + + + + + + + + Configure GNOME3 DConf User Profile + By default, DConf provides a standard user profile. This profile contains a list of DConf configuration databases. The user profile and database always take the highest priority. As such the DConf User profile should always exist and be configured correctly. - + + To make sure that the user profile is configured correctly, the /etc/dconf/profile/user should be set as follows: @@ -6137,105 +7393,112 @@ should be set as follows: system-db:local system-db:site system-db:distro - - Failure to have a functional DConf profile prevents GNOME3 configuration settings -from being enforced for all users and allows various security risks. - - - - - - - - - - Configure GNOME Login Screen - In the default GNOME desktop, the login is displayed after system boot + + + Failure to have a functional DConf profile prevents GNOME3 configuration settings +from being enforced for all users and allows various security risks. + + + + + + + + + + Configure GNOME Login Screen + In the default GNOME desktop, the login is displayed after system boot and can display user accounts, allow users to reboot the system, and allow users to login automatically and/or with a guest account. The login screen should be configured to prevent such behavior. - + + For more information about enforcing preferences in the GNOME3 environment using the DConf configuration system, see http://wiki.gnome.org/dconf and -the man page dconf(1). - - Disable the GNOME3 Login Restart and Shutdown Buttons - In the default graphical environment, users logging directly into the +the man page dconf(1). + + Disable the GNOME3 Login Restart and Shutdown Buttons + In the default graphical environment, users logging directly into the system are greeted with a login screen that allows any user, known or unknown, the ability the ability to shutdown or restart the system. This functionality should be disabled by setting disable-restart-buttons to true. - + + To disable, add or edit disable-restart-buttons to -/etc/dconf/db/gdm.d/00-security-settings. For example: +/etc/dconf/db/local.d/00-security-settings. For example: [org/gnome/login-screen] disable-restart-buttons=true Once the setting has been added, add a lock to -/etc/dconf/db/gdm.d/locks/00-security-settings-lock to prevent +/etc/dconf/db/local.d/locks/00-security-settings-lock to prevent user modification. For example: /org/gnome/login-screen/disable-restart-buttons -After the settings have been set, run dconf update. - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - APO01.06 - DSS05.04 - DSS05.07 - DSS06.02 - 3.1.2 - CCI-000366 - 4.3.3.7.3 - SR 2.1 - SR 5.2 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CM-6(a) - AC-6(1) - CM-7(b) - PR.AC-4 - PR.DS-5 - SRG-OS-000480-GPOS-00227 - A user who is at the console can reboot the system at the login screen. If restart or shutdown buttons +After the settings have been set, run dconf update. + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + APO01.06 + DSS05.04 + DSS05.07 + DSS06.02 + 3.1.2 + CCI-000366 + 4.3.3.7.3 + SR 2.1 + SR 5.2 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CM-6(a) + AC-6(1) + CM-7(b) + PR.AC-4 + PR.DS-5 + SRG-OS-000480-GPOS-00227 + OL09-00-002127 + OL09-00-002128 + SV-271685r1091767_rule + SV-271686r1091770_rule + A user who is at the console can reboot the system at the login screen. If restart or shutdown buttons are pressed at the login screen, this can create the risk of short-term loss of availability of systems -due to reboot. - - # Remediation is applicable only in certain platforms +due to reboot. + + # Remediation is applicable only in certain platforms if rpm --quiet -q gdm && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then # Check for setting in any of the DConf db directories # If files contain ibus or distro, ignore them. # The assignment assumes that individual filenames don't contain : readarray -t SETTINGSFILES < <(grep -r "\\[org/gnome/login-screen\\]" "/etc/dconf/db/" \ - | grep -v 'distro\|ibus\|gdm.d' | cut -d":" -f1) -DCONFFILE="/etc/dconf/db/gdm.d/00-security-settings" -DBDIR="/etc/dconf/db/gdm.d" + | grep -v 'distro\|ibus\|local.d' | cut -d":" -f1) +DCONFFILE="/etc/dconf/db/local.d/00-security-settings" +DBDIR="/etc/dconf/db/local.d" mkdir -p "${DBDIR}" @@ -6249,7 +7512,6 @@ then fi fi - [ ! -z "${DCONFFILE}" ] && echo "" >> "${DCONFFILE}" if ! grep -q "\\[org/gnome/login-screen\\]" "${DCONFFILE}" then @@ -6263,12 +7525,11 @@ then else sed -i "\\|\\[org/gnome/login-screen\\]|a\\disable-restart-buttons=${escaped_value}" "${DCONFFILE}" fi - dconf update # Check for setting in any of the DConf db directories LOCKFILES=$(grep -r "^/org/gnome/login-screen/disable-restart-buttons$" "/etc/dconf/db/" \ - | grep -v 'distro\|ibus\|gdm.d' | grep ":" | cut -d":" -f1) -LOCKSFOLDER="/etc/dconf/db/gdm.d/locks" + | grep -v 'distro\|ibus\|local.d' | grep ":" | cut -d":" -f1) +LOCKSFOLDER="/etc/dconf/db/local.d/locks" mkdir -p "${LOCKSFOLDER}" @@ -6278,21 +7539,22 @@ then sed -i -E "s|^/org/gnome/login-screen/disable-restart-buttons$|#&|" "${LOCKFILES[@]}" fi -if ! grep -qr "^/org/gnome/login-screen/disable-restart-buttons$" /etc/dconf/db/gdm.d/ +if ! grep -qr "^/org/gnome/login-screen/disable-restart-buttons$" /etc/dconf/db/local.d/ then - echo "/org/gnome/login-screen/disable-restart-buttons" >> "/etc/dconf/db/gdm.d/locks/00-security-settings-lock" + echo "/org/gnome/login-screen/disable-restart-buttons" >> "/etc/dconf/db/local.d/locks/00-security-settings-lock" fi - dconf update else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-002127 + - DISA-STIG-OL09-00-002128 - NIST-800-171-3.1.2 - NIST-800-53-AC-6(1) - NIST-800-53-CM-6(a) @@ -6306,7 +7568,7 @@ fi - name: Disable the GNOME3 Login Restart and Shutdown Buttons ini_file: - dest: /etc/dconf/db/gdm.d/00-security-settings + dest: /etc/dconf/db/local.d/00-security-settings section: org/gnome/login-screen option: disable-restart-buttons value: 'true' @@ -6316,6 +7578,8 @@ fi - '"gdm" in ansible_facts.packages' - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] tags: + - DISA-STIG-OL09-00-002127 + - DISA-STIG-OL09-00-002128 - NIST-800-171-3.1.2 - NIST-800-53-AC-6(1) - NIST-800-53-CM-6(a) @@ -6330,7 +7594,7 @@ fi - name: Prevent user modification of GNOME disablement of Login Restart and Shutdown Buttons lineinfile: - path: /etc/dconf/db/gdm.d/locks/00-security-settings-lock + path: /etc/dconf/db/local.d/locks/00-security-settings-lock regexp: ^/org/gnome/login-screen/disable-restart-buttons line: /org/gnome/login-screen/disable-restart-buttons create: true @@ -6338,6 +7602,8 @@ fi - '"gdm" in ansible_facts.packages' - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] tags: + - DISA-STIG-OL09-00-002127 + - DISA-STIG-OL09-00-002128 - NIST-800-171-3.1.2 - NIST-800-53-AC-6(1) - NIST-800-53-CM-6(a) @@ -6355,6 +7621,8 @@ fi - '"gdm" in ansible_facts.packages' - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] tags: + - DISA-STIG-OL09-00-002127 + - DISA-STIG-OL09-00-002128 - NIST-800-171-3.1.2 - NIST-800-53-AC-6(1) - NIST-800-53-CM-6(a) @@ -6365,47 +7633,52 @@ fi - medium_disruption - no_reboot_needed - unknown_strategy - - - - - - - - - - Disable the GNOME3 Login User List - In the default graphical environment, users logging directly into the + + + + + + + + + + Disable the GNOME3 Login User List + In the default graphical environment, users logging directly into the system are greeted with a login screen that displays all known users. This functionality should be disabled by setting disable-user-list to true. - + + To disable, add or edit disable-user-list to -/etc/dconf/db/gdm.d/00-security-settings. For example: +/etc/dconf/db/local.d/00-security-settings. For example: [org/gnome/login-screen] disable-user-list=true Once the setting has been added, add a lock to -/etc/dconf/db/gdm.d/locks/00-security-settings-lock to prevent +/etc/dconf/db/local.d/locks/00-security-settings-lock to prevent user modification. For example: /org/gnome/login-screen/disable-user-list -After the settings have been set, run dconf update. - CM-6(a) - AC-23 - SRG-OS-000480-GPOS-00227 - Leaving the user list enabled is a security risk since it allows anyone +After the settings have been set, run dconf update. + CCI-000366 + CM-6(a) + AC-23 + SRG-OS-000480-GPOS-00227 + A.11.SEC-OL9 + OL09-00-002102 + SV-271672r1092631_rule + Leaving the user list enabled is a security risk since it allows anyone with physical access to the system to quickly enumerate known user accounts -without logging in. - - # Remediation is applicable only in certain platforms +without logging in. + + # Remediation is applicable only in certain platforms if rpm --quiet -q gdm && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then # Check for setting in any of the DConf db directories # If files contain ibus or distro, ignore them. # The assignment assumes that individual filenames don't contain : readarray -t SETTINGSFILES < <(grep -r "\\[org/gnome/login-screen\\]" "/etc/dconf/db/" \ - | grep -v 'distro\|ibus\|gdm.d' | cut -d":" -f1) -DCONFFILE="/etc/dconf/db/gdm.d/00-security-settings" -DBDIR="/etc/dconf/db/gdm.d" + | grep -v 'distro\|ibus\|local.d' | cut -d":" -f1) +DCONFFILE="/etc/dconf/db/local.d/00-security-settings" +DBDIR="/etc/dconf/db/local.d" mkdir -p "${DBDIR}" @@ -6419,7 +7692,6 @@ then fi fi - [ ! -z "${DCONFFILE}" ] && echo "" >> "${DCONFFILE}" if ! grep -q "\\[org/gnome/login-screen\\]" "${DCONFFILE}" then @@ -6433,12 +7705,11 @@ then else sed -i "\\|\\[org/gnome/login-screen\\]|a\\disable-user-list=${escaped_value}" "${DCONFFILE}" fi - dconf update # Check for setting in any of the DConf db directories LOCKFILES=$(grep -r "^/org/gnome/login-screen/disable-user-list$" "/etc/dconf/db/" \ - | grep -v 'distro\|ibus\|gdm.d' | grep ":" | cut -d":" -f1) -LOCKSFOLDER="/etc/dconf/db/gdm.d/locks" + | grep -v 'distro\|ibus\|local.d' | grep ":" | cut -d":" -f1) +LOCKSFOLDER="/etc/dconf/db/local.d/locks" mkdir -p "${LOCKSFOLDER}" @@ -6448,21 +7719,21 @@ then sed -i -E "s|^/org/gnome/login-screen/disable-user-list$|#&|" "${LOCKFILES[@]}" fi -if ! grep -qr "^/org/gnome/login-screen/disable-user-list$" /etc/dconf/db/gdm.d/ +if ! grep -qr "^/org/gnome/login-screen/disable-user-list$" /etc/dconf/db/local.d/ then - echo "/org/gnome/login-screen/disable-user-list" >> "/etc/dconf/db/gdm.d/locks/00-security-settings-lock" + echo "/org/gnome/login-screen/disable-user-list" >> "/etc/dconf/db/local.d/locks/00-security-settings-lock" fi - dconf update else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-002102 - NIST-800-53-AC-23 - NIST-800-53-CM-6(a) - dconf_gnome_disable_user_list @@ -6474,7 +7745,7 @@ fi - name: Disable the GNOME3 Login User List ini_file: - dest: /etc/dconf/db/gdm.d/00-security-settings + dest: /etc/dconf/db/local.d/00-security-settings section: org/gnome/login-screen option: disable-user-list value: 'true' @@ -6484,6 +7755,7 @@ fi - '"gdm" in ansible_facts.packages' - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] tags: + - DISA-STIG-OL09-00-002102 - NIST-800-53-AC-23 - NIST-800-53-CM-6(a) - dconf_gnome_disable_user_list @@ -6495,7 +7767,7 @@ fi - name: Prevent user modification of GNOME3 disablement of Login User List lineinfile: - path: /etc/dconf/db/gdm.d/locks/00-security-settings-lock + path: /etc/dconf/db/local.d/locks/00-security-settings-lock regexp: ^/org/gnome/login-screen/disable-user-list$ line: /org/gnome/login-screen/disable-user-list create: true @@ -6503,6 +7775,7 @@ fi - '"gdm" in ansible_facts.packages' - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] tags: + - DISA-STIG-OL09-00-002102 - NIST-800-53-AC-23 - NIST-800-53-CM-6(a) - dconf_gnome_disable_user_list @@ -6518,6 +7791,7 @@ fi - '"gdm" in ansible_facts.packages' - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] tags: + - DISA-STIG-OL09-00-002102 - NIST-800-53-AC-23 - NIST-800-53-CM-6(a) - dconf_gnome_disable_user_list @@ -6526,20 +7800,21 @@ fi - medium_severity - no_reboot_needed - unknown_strategy - - - - - - - - - - Enable the GNOME3 Screen Locking On Smartcard Removal - In the default graphical environment, screen locking on smartcard removal + + + + + + + + + + Enable the GNOME3 Screen Locking On Smartcard Removal + In the default graphical environment, screen locking on smartcard removal can be enabled by setting removal-action to 'lock-screen'. - + + To enable, add or edit removal-action to /etc/dconf/db/local.d/00-security-settings. For example: [org/gnome/settings-daemon/peripherals/smartcard] @@ -6548,15 +7823,19 @@ Once the setting has been added, add a lock to /etc/dconf/db/local.d/locks/00-security-settings-lock to prevent user modification. For example: /org/gnome/settings-daemon/peripherals/smartcard/removal-action -After the settings have been set, run dconf update. - CCI-000056 - CCI-000058 - SRG-OS-000028-GPOS-00009 - SRG-OS-000030-GPOS-00011 - Locking the screen automatically when removing the smartcard can -prevent undesired access to system. - - # Remediation is applicable only in certain platforms +After the settings have been set, run dconf update. + CCI-000057 + CCI-000056 + SRG-OS-000028-GPOS-00009 + SRG-OS-000030-GPOS-00011 + OL09-00-002160 + OL09-00-002126 + SV-271690r1092634_rule + SV-271684r1091764_rule + Locking the screen automatically when removing the smartcard can +prevent undesired access to system. + + # Remediation is applicable only in certain platforms if rpm --quiet -q gdm && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then # Check for setting in any of the DConf db directories @@ -6579,7 +7858,6 @@ then fi fi - [ ! -z "${DCONFFILE}" ] && echo "" >> "${DCONFFILE}" if ! grep -q "\\[org/gnome/settings-daemon/peripherals/smartcard\\]" "${DCONFFILE}" then @@ -6593,7 +7871,6 @@ then else sed -i "\\|\\[org/gnome/settings-daemon/peripherals/smartcard\\]|a\\removal-action=${escaped_value}" "${DCONFFILE}" fi - dconf update # Check for setting in any of the DConf db directories LOCKFILES=$(grep -r "^/org/gnome/settings-daemon/peripherals/smartcard/removal-action$" "/etc/dconf/db/" \ @@ -6612,17 +7889,18 @@ if ! grep -qr "^/org/gnome/settings-daemon/peripherals/smartcard/removal-action$ then echo "/org/gnome/settings-daemon/peripherals/smartcard/removal-action" >> "/etc/dconf/db/local.d/locks/00-security-settings-lock" fi - dconf update else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-002126 + - DISA-STIG-OL09-00-002160 - dconf_gnome_lock_screen_on_smartcard_removal - low_complexity - medium_disruption @@ -6639,6 +7917,8 @@ fi - '"gdm" in ansible_facts.packages' - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] tags: + - DISA-STIG-OL09-00-002126 + - DISA-STIG-OL09-00-002160 - dconf_gnome_lock_screen_on_smartcard_removal - low_complexity - medium_disruption @@ -6659,6 +7939,8 @@ fi - dconf_gnome_lock_screen_on_smartcard_removal_config_files is defined and dconf_gnome_lock_screen_on_smartcard_removal_config_files.matched == 0 tags: + - DISA-STIG-OL09-00-002126 + - DISA-STIG-OL09-00-002160 - dconf_gnome_lock_screen_on_smartcard_removal - low_complexity - medium_disruption @@ -6681,6 +7963,8 @@ fi - dconf_gnome_lock_screen_on_smartcard_removal_config_files is defined and dconf_gnome_lock_screen_on_smartcard_removal_config_files.matched > 0 tags: + - DISA-STIG-OL09-00-002126 + - DISA-STIG-OL09-00-002160 - dconf_gnome_lock_screen_on_smartcard_removal - low_complexity - medium_disruption @@ -6697,6 +7981,8 @@ fi - '"gdm" in ansible_facts.packages' - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] tags: + - DISA-STIG-OL09-00-002126 + - DISA-STIG-OL09-00-002160 - dconf_gnome_lock_screen_on_smartcard_removal - low_complexity - medium_disruption @@ -6716,6 +8002,8 @@ fi - dconf_gnome_lock_screen_on_smartcard_removal_lock_files is defined and dconf_gnome_lock_screen_on_smartcard_removal_lock_files.matched == 0 tags: + - DISA-STIG-OL09-00-002126 + - DISA-STIG-OL09-00-002160 - dconf_gnome_lock_screen_on_smartcard_removal - low_complexity - medium_disruption @@ -6736,6 +8024,8 @@ fi - dconf_gnome_lock_screen_on_smartcard_removal_lock_files is defined and dconf_gnome_lock_screen_on_smartcard_removal_lock_files.matched > 0 tags: + - DISA-STIG-OL09-00-002126 + - DISA-STIG-OL09-00-002160 - dconf_gnome_lock_screen_on_smartcard_removal - low_complexity - medium_disruption @@ -6749,57 +8039,63 @@ fi - '"gdm" in ansible_facts.packages' - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] tags: + - DISA-STIG-OL09-00-002126 + - DISA-STIG-OL09-00-002160 - dconf_gnome_lock_screen_on_smartcard_removal - low_complexity - medium_disruption - medium_severity - no_reboot_needed - unknown_strategy - - - - - - - - - - Disable GDM Automatic Login - The GNOME Display Manager (GDM) can allow users to automatically login without + + + + + + + + + + Disable GDM Automatic Login + The GNOME Display Manager (GDM) can allow users to automatically login without user interaction or credentials. User should always be required to authenticate themselves to the system that they are authorized to use. To disable user ability to automatically login to the system, set the AutomaticLoginEnable to false in the [daemon] section in /etc/gdm/custom.conf. For example: [daemon] -AutomaticLoginEnable=false - 11 - 3 - 9 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - 3.1.1 - CCI-000366 - 4.3.4.3.2 - 4.3.4.3.3 - SR 7.6 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.14.2.2 - A.14.2.3 - A.14.2.4 - CM-6(a) - AC-6(1) - CM-7(b) - PR.IP-1 - FIA_UAU.1 - SRG-OS-000480-GPOS-00229 - Failure to restrict system access to authenticated users negatively impacts operating -system security. - - # Remediation is applicable only in certain platforms +AutomaticLoginEnable=false + + 11 + 3 + 9 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + 3.1.1 + CCI-000366 + 4.3.4.3.2 + 4.3.4.3.3 + SR 7.6 + A.12.1.2 + A.12.5.1 + A.12.6.2 + A.14.2.2 + A.14.2.3 + A.14.2.4 + CM-6(a) + AC-6(1) + CM-7(b) + PR.IP-1 + SRG-OS-000480-GPOS-00229 + 8.3.1 + 8.3 + OL09-00-002161 + SV-271691r1091785_rule + Failure to restrict system access to authenticated users negatively impacts operating +system security. + + # Remediation is applicable only in certain platforms if rpm --quiet -q gdm && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then if rpm --quiet -q gdm @@ -6816,15 +8112,18 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-002161 - NIST-800-171-3.1.1 - NIST-800-53-AC-6(1) - NIST-800-53-CM-6(a) - NIST-800-53-CM-7(b) + - PCI-DSSv4-8.3 + - PCI-DSSv4-8.3.1 - gnome_gdm_disable_automatic_login - high_severity - low_complexity @@ -6844,40 +8143,44 @@ fi - '"gdm" in ansible_facts.packages' - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] tags: + - DISA-STIG-OL09-00-002161 - NIST-800-171-3.1.1 - NIST-800-53-AC-6(1) - NIST-800-53-CM-6(a) - NIST-800-53-CM-7(b) + - PCI-DSSv4-8.3 + - PCI-DSSv4-8.3.1 - gnome_gdm_disable_automatic_login - high_severity - low_complexity - medium_disruption - no_reboot_needed - unknown_strategy - - - - - - - - - - Disable XDMCP in GDM - XDMCP is an unencrypted protocol, and therefore, presents a security risk, see e.g. + + + + + + + + + + Disable XDMCP in GDM + XDMCP is an unencrypted protocol, and therefore, presents a security risk, see e.g. XDMCP Gnome docs. To disable XDMCP support in Gnome, set Enable to false under the [xdmcp] configuration section in /etc/gdm/custom.conf. For example: [xdmcp] Enable=false - - XDMCP provides unencrypted remote access through the Gnome Display Manager (GDM) which does + + + XDMCP provides unencrypted remote access through the Gnome Display Manager (GDM) which does not provide for the confidentiality and integrity of user passwords or the remote session. If a privileged user were to login using XDMCP, the privileged user password could be compromised due to typed XEvents -and keystrokes will traversing over the network in clear text. - # Remediation is applicable only in certain platforms +and keystrokes will traversing over the network in clear text. + # Remediation is applicable only in certain platforms if rpm --quiet -q gdm; then # Try find '[xdmcp]' and 'Enable' in '/etc/gdm/custom.conf', if it exists, set @@ -6898,8 +8201,8 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: @@ -6926,21 +8229,235 @@ fi - medium_disruption - no_reboot_needed - unknown_strategy - - - - - - - - - - - GNOME Media Settings - GNOME media settings that apply to the graphical interface. - - Disable GNOME3 Automount Opening - The system's default desktop environment, GNOME3, will mount + + + + + + + + + + + GNOME Media Settings + GNOME media settings that apply to the graphical interface. + + Disable GNOME3 Automounting + The system's default desktop environment, GNOME3, will mount +devices and removable media (such as DVDs, CDs and USB flash drives) whenever +they are inserted into the system. To disable automount within GNOME3, add or set +automount to false in /etc/dconf/db/local.d/00-security-settings. +For example: +[org/gnome/desktop/media-handling] +automount=false +Once the settings have been added, add a lock to +/etc/dconf/db/local.d/locks/00-security-settings-lock to prevent user modification. +For example: +/org/gnome/desktop/media-handling/automount +After the settings have been set, run dconf update. + 12 + 16 + APO13.01 + DSS01.04 + DSS05.03 + DSS05.04 + DSS05.05 + DSS05.07 + DSS06.03 + 3.1.7 + CCI-000366 + CCI-000778 + CCI-001958 + 4.3.3.2.2 + 4.3.3.5.2 + 4.3.3.6.6 + 4.3.3.7.2 + 4.3.3.7.4 + SR 1.1 + SR 1.13 + SR 1.2 + SR 1.4 + SR 1.5 + SR 1.9 + SR 2.1 + SR 2.6 + A.11.2.6 + A.13.1.1 + A.13.2.1 + A.6.2.1 + A.6.2.2 + A.7.1.1 + A.9.2.1 + CM-7(a) + CM-7(b) + CM-6(a) + PR.AC-3 + PR.AC-6 + SRG-OS-000114-GPOS-00059 + SRG-OS-000378-GPOS-00163 + SRG-OS-000480-GPOS-00227 + A.11.SEC-OL12 + 3.4.2 + 3.4 + Disabling automatic mounting in GNOME3 can prevent +the introduction of malware via removable media. +It will, however, also prevent desktop users from legitimate use +of removable media. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q gdm && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then + +# Check for setting in any of the DConf db directories +# If files contain ibus or distro, ignore them. +# The assignment assumes that individual filenames don't contain : +readarray -t SETTINGSFILES < <(grep -r "\\[org/gnome/desktop/media-handling\\]" "/etc/dconf/db/" \ + | grep -v 'distro\|ibus\|local.d' | cut -d":" -f1) +DCONFFILE="/etc/dconf/db/local.d/00-security-settings" +DBDIR="/etc/dconf/db/local.d" + +mkdir -p "${DBDIR}" + +# Comment out the configurations in databases different from the target one +if [ "${#SETTINGSFILES[@]}" -ne 0 ] +then + if grep -q "^\\s*automount\\s*=" "${SETTINGSFILES[@]}" + then + + sed -Ei "s/(^\s*)automount(\s*=)/#\1automount\2/g" "${SETTINGSFILES[@]}" + fi +fi + +[ ! -z "${DCONFFILE}" ] && echo "" >> "${DCONFFILE}" +if ! grep -q "\\[org/gnome/desktop/media-handling\\]" "${DCONFFILE}" +then + printf '%s\n' "[org/gnome/desktop/media-handling]" >> ${DCONFFILE} +fi + +escaped_value="$(sed -e 's/\\/\\\\/g' <<< "false")" +if grep -q "^\\s*automount\\s*=" "${DCONFFILE}" +then + sed -i "s/\\s*automount\\s*=\\s*.*/automount=${escaped_value}/g" "${DCONFFILE}" + else + sed -i "\\|\\[org/gnome/desktop/media-handling\\]|a\\automount=${escaped_value}" "${DCONFFILE}" +fi +dconf update +# Check for setting in any of the DConf db directories +LOCKFILES=$(grep -r "^/org/gnome/desktop/media-handling/automount$" "/etc/dconf/db/" \ + | grep -v 'distro\|ibus\|local.d' | grep ":" | cut -d":" -f1) +LOCKSFOLDER="/etc/dconf/db/local.d/locks" + +mkdir -p "${LOCKSFOLDER}" + +# Comment out the configurations in databases different from the target one +if [[ ! -z "${LOCKFILES}" ]] +then + sed -i -E "s|^/org/gnome/desktop/media-handling/automount$|#&|" "${LOCKFILES[@]}" +fi + +if ! grep -qr "^/org/gnome/desktop/media-handling/automount$" /etc/dconf/db/local.d/ +then + echo "/org/gnome/desktop/media-handling/automount" >> "/etc/dconf/db/local.d/locks/00-security-settings-lock" +fi +dconf update + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-171-3.1.7 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - PCI-DSSv4-3.4 + - PCI-DSSv4-3.4.2 + - dconf_gnome_disable_automount + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - unknown_strategy + +- name: Disable GNOME3 Automounting - automount + ini_file: + dest: /etc/dconf/db/local.d/00-security-settings + section: org/gnome/desktop/media-handling + option: automount + value: 'false' + create: true + no_extra_spaces: true + when: + - '"gdm" in ansible_facts.packages' + - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + tags: + - NIST-800-171-3.1.7 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - PCI-DSSv4-3.4 + - PCI-DSSv4-3.4.2 + - dconf_gnome_disable_automount + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - unknown_strategy + +- name: Prevent user modification of GNOME3 Automounting - automount + lineinfile: + path: /etc/dconf/db/local.d/locks/00-security-settings-lock + regexp: ^/org/gnome/desktop/media-handling/automount$ + line: /org/gnome/desktop/media-handling/automount + create: true + when: + - '"gdm" in ansible_facts.packages' + - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + tags: + - NIST-800-171-3.1.7 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - PCI-DSSv4-3.4 + - PCI-DSSv4-3.4.2 + - dconf_gnome_disable_automount + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - unknown_strategy + +- name: Dconf Update + command: dconf update + when: + - '"gdm" in ansible_facts.packages' + - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + tags: + - NIST-800-171-3.1.7 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - PCI-DSSv4-3.4 + - PCI-DSSv4-3.4.2 + - dconf_gnome_disable_automount + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - unknown_strategy + + + + + + + + + + Disable GNOME3 Automount Opening + The system's default desktop environment, GNOME3, will mount devices and removable media (such as DVDs, CDs and USB flash drives) whenever they are inserted into the system. To disable automount-open within GNOME3, add or set automount-open to false in /etc/dconf/db/local.d/00-security-settings. @@ -6951,55 +8468,62 @@ Once the settings have been added, add a lock to /etc/dconf/db/local.d/locks/00-security-settings-lock to prevent user modification. For example: /org/gnome/desktop/media-handling/automount-open -After the settings have been set, run dconf update. - 12 - 16 - APO13.01 - DSS01.04 - DSS05.03 - DSS05.04 - DSS05.05 - DSS05.07 - DSS06.03 - 3.1.7 - CCI-000366 - CCI-000778 - CCI-001958 - 4.3.3.2.2 - 4.3.3.5.2 - 4.3.3.6.6 - 4.3.3.7.2 - 4.3.3.7.4 - SR 1.1 - SR 1.13 - SR 1.2 - SR 1.4 - SR 1.5 - SR 1.9 - SR 2.1 - SR 2.6 - A.11.2.6 - A.13.1.1 - A.13.2.1 - A.6.2.1 - A.6.2.2 - A.7.1.1 - A.9.2.1 - CM-7(a) - CM-7(b) - CM-6(a) - PR.AC-3 - PR.AC-6 - SRG-OS-000114-GPOS-00059 - SRG-OS-000378-GPOS-00163 - SRG-OS-000480-GPOS-00227 - Automatically mounting file systems permits easy introduction of unknown devices, thereby facilitating malicious activity. +After the settings have been set, run dconf update. + 12 + 16 + APO13.01 + DSS01.04 + DSS05.03 + DSS05.04 + DSS05.05 + DSS05.07 + DSS06.03 + 3.1.7 + CCI-000778 + CCI-000366 + CCI-001958 + 4.3.3.2.2 + 4.3.3.5.2 + 4.3.3.6.6 + 4.3.3.7.2 + 4.3.3.7.4 + SR 1.1 + SR 1.13 + SR 1.2 + SR 1.4 + SR 1.5 + SR 1.9 + SR 2.1 + SR 2.6 + A.11.2.6 + A.13.1.1 + A.13.2.1 + A.6.2.1 + A.6.2.2 + A.7.1.1 + A.9.2.1 + CM-7(a) + CM-7(b) + CM-6(a) + PR.AC-3 + PR.AC-6 + SRG-OS-000114-GPOS-00059 + SRG-OS-000378-GPOS-00163 + SRG-OS-000480-GPOS-00227 + A.11.SEC-OL12 + 3.4.2 + 3.4 + OL09-00-002100 + OL09-00-002120 + SV-271670r1091722_rule + SV-271678r1091746_rule + Automatically mounting file systems permits easy introduction of unknown devices, thereby facilitating malicious activity. Disabling automatic mounting in GNOME3 can prevent the introduction of malware via removable media. It will, however, also prevent desktop users from legitimate use -of removable media. - - # Remediation is applicable only in certain platforms +of removable media. + + # Remediation is applicable only in certain platforms if rpm --quiet -q gdm && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then # Check for setting in any of the DConf db directories @@ -7022,7 +8546,6 @@ then fi fi - [ ! -z "${DCONFFILE}" ] && echo "" >> "${DCONFFILE}" if ! grep -q "\\[org/gnome/desktop/media-handling\\]" "${DCONFFILE}" then @@ -7036,7 +8559,6 @@ then else sed -i "\\|\\[org/gnome/desktop/media-handling\\]|a\\automount-open=${escaped_value}" "${DCONFFILE}" fi - dconf update # Check for setting in any of the DConf db directories LOCKFILES=$(grep -r "^/org/gnome/desktop/media-handling/automount-open$" "/etc/dconf/db/" \ @@ -7055,21 +8577,24 @@ if ! grep -qr "^/org/gnome/desktop/media-handling/automount-open$" /etc/dconf/db then echo "/org/gnome/desktop/media-handling/automount-open" >> "/etc/dconf/db/local.d/locks/00-security-settings-lock" fi - dconf update else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-002100 + - DISA-STIG-OL09-00-002120 - NIST-800-171-3.1.7 - NIST-800-53-CM-6(a) - NIST-800-53-CM-7(a) - NIST-800-53-CM-7(b) + - PCI-DSSv4-3.4 + - PCI-DSSv4-3.4.2 - dconf_gnome_disable_automount_open - low_complexity - medium_disruption @@ -7089,10 +8614,14 @@ fi - '"gdm" in ansible_facts.packages' - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] tags: + - DISA-STIG-OL09-00-002100 + - DISA-STIG-OL09-00-002120 - NIST-800-171-3.1.7 - NIST-800-53-CM-6(a) - NIST-800-53-CM-7(a) - NIST-800-53-CM-7(b) + - PCI-DSSv4-3.4 + - PCI-DSSv4-3.4.2 - dconf_gnome_disable_automount_open - low_complexity - medium_disruption @@ -7110,10 +8639,14 @@ fi - '"gdm" in ansible_facts.packages' - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] tags: + - DISA-STIG-OL09-00-002100 + - DISA-STIG-OL09-00-002120 - NIST-800-171-3.1.7 - NIST-800-53-CM-6(a) - NIST-800-53-CM-7(a) - NIST-800-53-CM-7(b) + - PCI-DSSv4-3.4 + - PCI-DSSv4-3.4.2 - dconf_gnome_disable_automount_open - low_complexity - medium_disruption @@ -7127,27 +8660,31 @@ fi - '"gdm" in ansible_facts.packages' - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] tags: + - DISA-STIG-OL09-00-002100 + - DISA-STIG-OL09-00-002120 - NIST-800-171-3.1.7 - NIST-800-53-CM-6(a) - NIST-800-53-CM-7(a) - NIST-800-53-CM-7(b) + - PCI-DSSv4-3.4 + - PCI-DSSv4-3.4.2 - dconf_gnome_disable_automount_open - low_complexity - medium_disruption - medium_severity - no_reboot_needed - unknown_strategy - - - - - - - - - - Disable GNOME3 Automount running - The system's default desktop environment, GNOME3, will mount + + + + + + + + + + Disable GNOME3 Automount running + The system's default desktop environment, GNOME3, will mount devices and removable media (such as DVDs, CDs and USB flash drives) whenever they are inserted into the system. To disable autorun-never within GNOME3, add or set autorun-never to true in /etc/dconf/db/local.d/00-security-settings. @@ -7158,55 +8695,61 @@ Once the settings have been added, add a lock to /etc/dconf/db/local.d/locks/00-security-settings-lock to prevent user modification. For example: /org/gnome/desktop/media-handling/autorun-never -After the settings have been set, run dconf update. - 12 - 16 - APO13.01 - DSS01.04 - DSS05.03 - DSS05.04 - DSS05.05 - DSS05.07 - DSS06.03 - 3.1.7 - CCI-000366 - CCI-000778 - CCI-001958 - 4.3.3.2.2 - 4.3.3.5.2 - 4.3.3.6.6 - 4.3.3.7.2 - 4.3.3.7.4 - SR 1.1 - SR 1.13 - SR 1.2 - SR 1.4 - SR 1.5 - SR 1.9 - SR 2.1 - SR 2.6 - A.11.2.6 - A.13.1.1 - A.13.2.1 - A.6.2.1 - A.6.2.2 - A.7.1.1 - A.9.2.1 - CM-7(a) - CM-7(b) - CM-6(a) - PR.AC-3 - PR.AC-6 - SRG-OS-000114-GPOS-00059 - SRG-OS-000378-GPOS-00163 - SRG-OS-000480-GPOS-00227 - Automatically mounting file systems permits easy introduction of unknown devices, thereby facilitating malicious activity. +After the settings have been set, run dconf update. + 12 + 16 + APO13.01 + DSS01.04 + DSS05.03 + DSS05.04 + DSS05.05 + DSS05.07 + DSS06.03 + 3.1.7 + CCI-000366 + CCI-001764 + CCI-001958 + CCI-000778 + 4.3.3.2.2 + 4.3.3.5.2 + 4.3.3.6.6 + 4.3.3.7.2 + 4.3.3.7.4 + SR 1.1 + SR 1.13 + SR 1.2 + SR 1.4 + SR 1.5 + SR 1.9 + SR 2.1 + SR 2.6 + A.11.2.6 + A.13.1.1 + A.13.2.1 + A.6.2.1 + A.6.2.2 + A.7.1.1 + A.9.2.1 + CM-7(a) + CM-7(b) + CM-6(a) + PR.AC-3 + PR.AC-6 + SRG-OS-000114-GPOS-00059 + SRG-OS-000378-GPOS-00163 + SRG-OS-000480-GPOS-00227 + A.11.SEC-OL12 + OL09-00-002101 + OL09-00-002121 + SV-271671r1091725_rule + SV-271679r1091749_rule + Automatically mounting file systems permits easy introduction of unknown devices, thereby facilitating malicious activity. Disabling automatic mount running in GNOME3 can prevent the introduction of malware via removable media. It will, however, also prevent desktop users from legitimate use -of removable media. - - # Remediation is applicable only in certain platforms +of removable media. + + # Remediation is applicable only in certain platforms if rpm --quiet -q gdm && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then # Check for setting in any of the DConf db directories @@ -7229,7 +8772,6 @@ then fi fi - [ ! -z "${DCONFFILE}" ] && echo "" >> "${DCONFFILE}" if ! grep -q "\\[org/gnome/desktop/media-handling\\]" "${DCONFFILE}" then @@ -7243,7 +8785,6 @@ then else sed -i "\\|\\[org/gnome/desktop/media-handling\\]|a\\autorun-never=${escaped_value}" "${DCONFFILE}" fi - dconf update # Check for setting in any of the DConf db directories LOCKFILES=$(grep -r "^/org/gnome/desktop/media-handling/autorun-never$" "/etc/dconf/db/" \ @@ -7262,17 +8803,18 @@ if ! grep -qr "^/org/gnome/desktop/media-handling/autorun-never$" /etc/dconf/db/ then echo "/org/gnome/desktop/media-handling/autorun-never" >> "/etc/dconf/db/local.d/locks/00-security-settings-lock" fi - dconf update else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-002101 + - DISA-STIG-OL09-00-002121 - NIST-800-171-3.1.7 - NIST-800-53-CM-6(a) - NIST-800-53-CM-7(a) @@ -7296,6 +8838,8 @@ fi - '"gdm" in ansible_facts.packages' - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] tags: + - DISA-STIG-OL09-00-002101 + - DISA-STIG-OL09-00-002121 - NIST-800-171-3.1.7 - NIST-800-53-CM-6(a) - NIST-800-53-CM-7(a) @@ -7317,6 +8861,8 @@ fi - '"gdm" in ansible_facts.packages' - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] tags: + - DISA-STIG-OL09-00-002101 + - DISA-STIG-OL09-00-002121 - NIST-800-171-3.1.7 - NIST-800-53-CM-6(a) - NIST-800-53-CM-7(a) @@ -7334,6 +8880,8 @@ fi - '"gdm" in ansible_facts.packages' - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] tags: + - DISA-STIG-OL09-00-002101 + - DISA-STIG-OL09-00-002121 - NIST-800-171-3.1.7 - NIST-800-53-CM-6(a) - NIST-800-53-CM-7(a) @@ -7344,25 +8892,21 @@ fi - medium_disruption - no_reboot_needed - unknown_strategy - - - - - - - - - - - GNOME Network Settings - GNOME network settings that apply to the graphical interface. - - - GNOME Remote Access Settings - GNOME remote access settings that apply to the graphical interface. - - Require Credential Prompting for Remote Access in GNOME3 - By default, GNOME does not require credentials when using Vino for + + + + + + + + + + + GNOME Remote Access Settings + GNOME remote access settings that apply to the graphical interface. + + Require Credential Prompting for Remote Access in GNOME3 + By default, GNOME does not require credentials when using Vino for remote access. To configure the system to require remote credentials, add or set authentication-methods to ['vnc'] in /etc/dconf/db/local.d/00-security-settings. For example: @@ -7373,18 +8917,18 @@ Once the settings have been added, add a lock to /etc/dconf/db/local.d/locks/00-security-settings-lock to prevent user modification. For example: /org/gnome/Vino/authentication-methods -After the settings have been set, run dconf update. - 3.1.12 - 164.308(a)(4)(i) - 164.308(b)(1) - 164.308(b)(3) - 164.310(b) - 164.312(e)(1) - 164.312(e)(2)(ii) - Username and password prompting is required for remote access. Otherwise, non-authorized -and nefarious users can access the system freely. - - # Remediation is applicable only in certain platforms +After the settings have been set, run dconf update. + 3.1.12 + 164.308(a)(4)(i) + 164.308(b)(1) + 164.308(b)(3) + 164.310(b) + 164.312(e)(1) + 164.312(e)(2)(ii) + Username and password prompting is required for remote access. Otherwise, non-authorized +and nefarious users can access the system freely. + + # Remediation is applicable only in certain platforms if rpm --quiet -q gdm && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then # Check for setting in any of the DConf db directories @@ -7407,7 +8951,6 @@ then fi fi - [ ! -z "${DCONFFILE}" ] && echo "" >> "${DCONFFILE}" if ! grep -q "\\[org/gnome/Vino\\]" "${DCONFFILE}" then @@ -7421,7 +8964,6 @@ then else sed -i "\\|\\[org/gnome/Vino\\]|a\\authentication-methods=${escaped_value}" "${DCONFFILE}" fi - dconf update # Check for setting in any of the DConf db directories LOCKFILES=$(grep -r "^/org/gnome/Vino/authentication-methods$" "/etc/dconf/db/" \ @@ -7440,14 +8982,13 @@ if ! grep -qr "^/org/gnome/Vino/authentication-methods$" /etc/dconf/db/local.d/ then echo "/org/gnome/Vino/authentication-methods" >> "/etc/dconf/db/local.d/locks/00-security-settings-lock" fi - dconf update else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: @@ -7510,17 +9051,17 @@ fi - medium_severity - no_reboot_needed - unknown_strategy - - - - - - - - - - Require Encryption for Remote Access in GNOME3 - By default, GNOME requires encryption when using Vino for remote access. + + + + + + + + + + Require Encryption for Remote Access in GNOME3 + By default, GNOME requires encryption when using Vino for remote access. To prevent remote access encryption from being disabled, add or set require-encryption to true in /etc/dconf/db/local.d/00-security-settings. For example: @@ -7531,59 +9072,59 @@ Once the settings have been added, add a lock to /etc/dconf/db/local.d/locks/00-security-settings-lock to prevent user modification. For example: /org/gnome/Vino/require-encryption -After the settings have been set, run dconf update. - 1 - 11 - 12 - 13 - 15 - 16 - 18 - 20 - 3 - 4 - 6 - 9 - BAI03.08 - BAI07.04 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS03.01 - 3.1.13 - CCI-000366 - 164.308(a)(4)(i) - 164.308(b)(1) - 164.308(b)(3) - 164.310(b) - 164.312(e)(1) - 164.312(e)(2)(ii) - 4.3.4.3.2 - 4.3.4.3.3 - 4.4.3.3 - SR 7.6 - A.12.1.1 - A.12.1.2 - A.12.1.4 - A.12.5.1 - A.12.6.2 - A.13.1.1 - A.13.1.2 - A.14.2.2 - A.14.2.3 - A.14.2.4 - CM-6(a) - AC-17(a) - AC-17(2) - DE.AE-1 - PR.DS-7 - PR.IP-1 - SRG-OS-000480-GPOS-00227 - Open X displays allow an attacker to capture keystrokes and to execute commands -remotely. - - # Remediation is applicable only in certain platforms +After the settings have been set, run dconf update. + 1 + 11 + 12 + 13 + 15 + 16 + 18 + 20 + 3 + 4 + 6 + 9 + BAI03.08 + BAI07.04 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS03.01 + 3.1.13 + CCI-000366 + 164.308(a)(4)(i) + 164.308(b)(1) + 164.308(b)(3) + 164.310(b) + 164.312(e)(1) + 164.312(e)(2)(ii) + 4.3.4.3.2 + 4.3.4.3.3 + 4.4.3.3 + SR 7.6 + A.12.1.1 + A.12.1.2 + A.12.1.4 + A.12.5.1 + A.12.6.2 + A.13.1.1 + A.13.1.2 + A.14.2.2 + A.14.2.3 + A.14.2.4 + CM-6(a) + AC-17(a) + AC-17(2) + DE.AE-1 + PR.DS-7 + PR.IP-1 + SRG-OS-000480-GPOS-00227 + Open X displays allow an attacker to capture keystrokes and to execute commands +remotely. + + # Remediation is applicable only in certain platforms if rpm --quiet -q gdm && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then # Check for setting in any of the DConf db directories @@ -7606,7 +9147,6 @@ then fi fi - [ ! -z "${DCONFFILE}" ] && echo "" >> "${DCONFFILE}" if ! grep -q "\\[org/gnome/Vino\\]" "${DCONFFILE}" then @@ -7620,7 +9160,6 @@ then else sed -i "\\|\\[org/gnome/Vino\\]|a\\require-encryption=${escaped_value}" "${DCONFFILE}" fi - dconf update # Check for setting in any of the DConf db directories LOCKFILES=$(grep -r "^/org/gnome/Vino/require-encryption$" "/etc/dconf/db/" \ @@ -7639,14 +9178,13 @@ if ! grep -qr "^/org/gnome/Vino/require-encryption$" /etc/dconf/db/local.d/ then echo "/org/gnome/Vino/require-encryption" >> "/etc/dconf/db/local.d/locks/00-security-settings-lock" fi - dconf update else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: @@ -7721,55 +9259,59 @@ fi - medium_severity - no_reboot_needed - unknown_strategy - - - - - - - - - - - Configure GNOME Screen Locking - In the default GNOME3 desktop, the screen can be locked + + + + + + + + + + + Configure GNOME Screen Locking + In the default GNOME3 desktop, the screen can be locked by selecting the user name in the far right corner of the main panel and selecting Lock. - + + The following sections detail commands to enforce idle activation of the screensaver, screen locking, a blank-screen screensaver, and an idle activation time. - + + Because users should be trained to lock the screen when they step away from the computer, the automatic locking feature is only meant as a backup. - + + The root account can be screen-locked; however, the root account should never be used to log into an X Windows environment and should only be used to for direct login via console in emergency circumstances. - + + For more information about enforcing preferences in the GNOME3 environment using the DConf configuration system, see http://wiki.gnome.org/dconf and -the man page dconf(1). - - Screensaver Inactivity timeout - Choose allowed duration (in seconds) of inactive graphical sessions - 600 - 900 - 1800 - 300 - 900 - - - Screensaver Lock Delay - Choose allowed duration (in seconds) after a screensaver becomes active before displaying an authentication prompt - 10 - 5 - 0 - 0 - - - Enable GNOME3 Screensaver Idle Activation - To activate the screensaver in the GNOME3 desktop after a period of inactivity, +the man page dconf(1). + + Screensaver Inactivity timeout + Choose allowed duration (in seconds) of inactive graphical sessions + 600 + 900 + 1800 + 300 + 900 + + + Screensaver Lock Delay + Choose allowed duration (in seconds) after a screensaver becomes active before displaying an authentication prompt + 10 + 5 + 0 + 0 + + + Enable GNOME3 Screensaver Idle Activation + To activate the screensaver in the GNOME3 desktop after a period of inactivity, add or set idle-activation-enabled to true in /etc/dconf/db/local.d/00-security-settings. For example: [org/gnome/desktop/screensaver] @@ -7778,59 +9320,60 @@ Once the setting has been added, add a lock to /etc/dconf/db/local.d/locks/00-security-settings-lock to prevent user modification. For example: /org/gnome/desktop/screensaver/idle-activation-enabled -After the settings have been set, run dconf update. - 1 - 12 - 15 - 16 - 5.5.5 - DSS05.04 - DSS05.10 - DSS06.10 - 3.1.10 - CCI-000057 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - SR 1.1 - SR 1.10 - SR 1.2 - SR 1.5 - SR 1.7 - SR 1.8 - SR 1.9 - A.18.1.4 - A.9.2.1 - A.9.2.4 - A.9.3.1 - A.9.4.2 - A.9.4.3 - CM-6(a) - AC-11(a) - PR.AC-7 - FMT_MOF_EXT.1 - Req-8.1.8 - 8.2.8 - SRG-OS-000029-GPOS-00010 - A session time-out lock is a temporary action taken when a user stops work and moves away from the immediate +After the settings have been set, run dconf update. + 1 + 12 + 15 + 16 + 5.5.5 + DSS05.04 + DSS05.10 + DSS06.10 + 3.1.10 + CCI-000057 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + SR 1.1 + SR 1.10 + SR 1.2 + SR 1.5 + SR 1.7 + SR 1.8 + SR 1.9 + A.18.1.4 + A.9.2.1 + A.9.2.4 + A.9.3.1 + A.9.4.2 + A.9.4.3 + CM-6(a) + AC-11(a) + PR.AC-7 + Req-8.1.8 + SRG-OS-000029-GPOS-00010 + 8.2.8 + 8.2 + A session time-out lock is a temporary action taken when a user stops work and moves away from the immediate physical vicinity of the information system but does not logout because of the temporary nature of the absence. Rather than relying on the user to manually lock their operating system session prior to vacating the vicinity, GNOME desktops can be configured to identify when a user's session has idled and take action to initiate the session lock. - + + Enabling idle activation of the screensaver ensures the screensaver will be activated after the idle delay. Applications requiring continuous, real-time screen display (such as network management products) require the login session does not have administrator rights and the display station is located in a -controlled-access area. - - # Remediation is applicable only in certain platforms +controlled-access area. + + # Remediation is applicable only in certain platforms if rpm --quiet -q gdm && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then # Check for setting in any of the DConf db directories @@ -7853,7 +9396,6 @@ then fi fi - [ ! -z "${DCONFFILE}" ] && echo "" >> "${DCONFFILE}" if ! grep -q "\\[org/gnome/desktop/screensaver\\]" "${DCONFFILE}" then @@ -7867,7 +9409,6 @@ then else sed -i "\\|\\[org/gnome/desktop/screensaver\\]|a\\idle-activation-enabled=${escaped_value}" "${DCONFFILE}" fi - dconf update # Check for setting in any of the DConf db directories LOCKFILES=$(grep -r "^/org/gnome/desktop/screensaver/idle-activation-enabled$" "/etc/dconf/db/" \ @@ -7886,14 +9427,13 @@ if ! grep -qr "^/org/gnome/desktop/screensaver/idle-activation-enabled$" /etc/dc then echo "/org/gnome/desktop/screensaver/idle-activation-enabled" >> "/etc/dconf/db/local.d/locks/00-security-settings-lock" fi - dconf update else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: @@ -7902,6 +9442,7 @@ fi - NIST-800-53-AC-11(a) - NIST-800-53-CM-6(a) - PCI-DSS-Req-8.1.8 + - PCI-DSSv4-8.2 - PCI-DSSv4-8.2.8 - dconf_gnome_screensaver_idle_activation_enabled - low_complexity @@ -7927,6 +9468,7 @@ fi - NIST-800-53-AC-11(a) - NIST-800-53-CM-6(a) - PCI-DSS-Req-8.1.8 + - PCI-DSSv4-8.2 - PCI-DSSv4-8.2.8 - dconf_gnome_screensaver_idle_activation_enabled - low_complexity @@ -7950,6 +9492,7 @@ fi - NIST-800-53-AC-11(a) - NIST-800-53-CM-6(a) - PCI-DSS-Req-8.1.8 + - PCI-DSSv4-8.2 - PCI-DSSv4-8.2.8 - dconf_gnome_screensaver_idle_activation_enabled - low_complexity @@ -7969,6 +9512,7 @@ fi - NIST-800-53-AC-11(a) - NIST-800-53-CM-6(a) - PCI-DSS-Req-8.1.8 + - PCI-DSSv4-8.2 - PCI-DSSv4-8.2.8 - dconf_gnome_screensaver_idle_activation_enabled - low_complexity @@ -7976,75 +9520,80 @@ fi - medium_severity - no_reboot_needed - unknown_strategy - - - - - - - - - - Set GNOME3 Screensaver Inactivity Timeout - The idle time-out value for inactivity in the GNOME3 desktop is configured via the idle-delay + + + + + + + + + + Set GNOME3 Screensaver Inactivity Timeout + The idle time-out value for inactivity in the GNOME3 desktop is configured via the idle-delay setting must be set under an appropriate configuration file(s) in the /etc/dconf/db/local.d directory and locked in /etc/dconf/db/local.d/locks directory to prevent user modification. - + + For example, to configure the system for a 15 minute delay, add the following to /etc/dconf/db/local.d/00-security-settings: [org/gnome/desktop/session] -idle-delay=uint32 900 - 1 - 12 - 15 - 16 - 5.5.5 - DSS05.04 - DSS05.10 - DSS06.10 - 3.1.10 - CCI-000057 - CCI-000060 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - SR 1.1 - SR 1.10 - SR 1.2 - SR 1.5 - SR 1.7 - SR 1.8 - SR 1.9 - A.18.1.4 - A.9.2.1 - A.9.2.4 - A.9.3.1 - A.9.4.2 - A.9.4.3 - AC-11(a) - CM-6(a) - PR.AC-7 - FMT_MOF_EXT.1 - Req-8.1.8 - 8.2.8 - SRG-OS-000029-GPOS-00010 - SRG-OS-000031-GPOS-00012 - A session time-out lock is a temporary action taken when a user stops work and moves away from +idle-delay=uint32 900 + + 1 + 12 + 15 + 16 + 5.5.5 + DSS05.04 + DSS05.10 + DSS06.10 + 3.1.10 + CCI-000057 + CCI-000060 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + SR 1.1 + SR 1.10 + SR 1.2 + SR 1.5 + SR 1.7 + SR 1.8 + SR 1.9 + A.18.1.4 + A.9.2.1 + A.9.2.4 + A.9.3.1 + A.9.4.2 + A.9.4.3 + AC-11(a) + CM-6(a) + PR.AC-7 + Req-8.1.8 + SRG-OS-000029-GPOS-00010 + SRG-OS-000031-GPOS-00012 + A.11.SEC-OL7 + 8.2.8 + 8.2 + OL09-00-002104 + SV-271674r1091734_rule + A session time-out lock is a temporary action taken when a user stops work and moves away from the immediate physical vicinity of the information system but does not logout because of the temporary nature of the absence. Rather than relying on the user to manually lock their operating system session prior to vacating the vicinity, GNOME3 can be configured to identify when -a user's session has idled and take action to initiate a session lock. - - # Remediation is applicable only in certain platforms +a user's session has idled and take action to initiate a session lock. + + # Remediation is applicable only in certain platforms if rpm --quiet -q gdm && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then -inactivity_timeout_value='' +inactivity_timeout_value='' # Check for setting in any of the DConf db directories @@ -8067,7 +9616,6 @@ then fi fi - [ ! -z "${DCONFFILE}" ] && echo "" >> "${DCONFFILE}" if ! grep -q "\\[org/gnome/desktop/session\\]" "${DCONFFILE}" then @@ -8081,22 +9629,23 @@ then else sed -i "\\|\\[org/gnome/desktop/session\\]|a\\idle-delay=${escaped_value}" "${DCONFFILE}" fi - dconf update else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: - CJIS-5.5.5 + - DISA-STIG-OL09-00-002104 - NIST-800-171-3.1.10 - NIST-800-53-AC-11(a) - NIST-800-53-CM-6(a) - PCI-DSS-Req-8.1.8 + - PCI-DSSv4-8.2 - PCI-DSSv4-8.2.8 - dconf_gnome_screensaver_idle_delay - low_complexity @@ -8106,7 +9655,7 @@ fi - unknown_strategy - name: XCCDF Value inactivity_timeout_value # promote to variable set_fact: - inactivity_timeout_value: !!str + inactivity_timeout_value: !!str tags: - always @@ -8123,10 +9672,12 @@ fi - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] tags: - CJIS-5.5.5 + - DISA-STIG-OL09-00-002104 - NIST-800-171-3.1.10 - NIST-800-53-AC-11(a) - NIST-800-53-CM-6(a) - PCI-DSS-Req-8.1.8 + - PCI-DSSv4-8.2 - PCI-DSSv4-8.2.8 - dconf_gnome_screensaver_idle_delay - low_complexity @@ -8142,10 +9693,12 @@ fi - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] tags: - CJIS-5.5.5 + - DISA-STIG-OL09-00-002104 - NIST-800-171-3.1.10 - NIST-800-53-AC-11(a) - NIST-800-53-CM-6(a) - PCI-DSS-Req-8.1.8 + - PCI-DSSv4-8.2 - PCI-DSSv4-8.2.8 - dconf_gnome_screensaver_idle_delay - low_complexity @@ -8153,71 +9706,74 @@ fi - medium_severity - no_reboot_needed - unknown_strategy - - - - - - - - - - - Set GNOME3 Screensaver Lock Delay After Activation Period - To activate the locking delay of the screensaver in the GNOME3 desktop when -the screensaver is activated, add or set lock-delay to uint32 in + + + + + + + + + + + Set GNOME3 Screensaver Lock Delay After Activation Period + To activate the locking delay of the screensaver in the GNOME3 desktop when +the screensaver is activated, add or set lock-delay to uint32 + in /etc/dconf/db/local.d/00-security-settings. For example: [org/gnome/desktop/screensaver] -lock-delay=uint32 - -After the settings have been set, run dconf update. - 1 - 12 - 15 - 16 - DSS05.04 - DSS05.10 - DSS06.10 - 3.1.10 - CCI-000056 - CCI-000057 - CCI-000060 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - SR 1.1 - SR 1.10 - SR 1.2 - SR 1.5 - SR 1.7 - SR 1.8 - SR 1.9 - A.18.1.4 - A.9.2.1 - A.9.2.4 - A.9.3.1 - A.9.4.2 - A.9.4.3 - AC-11(a) - CM-6(a) - PR.AC-7 - FMT_MOF_EXT.1 - Req-8.1.8 - SRG-OS-000029-GPOS-00010 - SRG-OS-000031-GPOS-00012 - A session lock is a temporary action taken when a user stops work and moves away from the immediate physical vicinity -of the information system but does not want to logout because of the temporary nature of the absense. - - # Remediation is applicable only in certain platforms +lock-delay=uint32 + +After the settings have been set, run dconf update. + 1 + 12 + 15 + 16 + DSS05.04 + DSS05.10 + DSS06.10 + 3.1.10 + CCI-000057 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + SR 1.1 + SR 1.10 + SR 1.2 + SR 1.5 + SR 1.7 + SR 1.8 + SR 1.9 + A.18.1.4 + A.9.2.1 + A.9.2.4 + A.9.3.1 + A.9.4.2 + A.9.4.3 + AC-11(a) + CM-6(a) + PR.AC-7 + Req-8.1.8 + SRG-OS-000029-GPOS-00010 + SRG-OS-000031-GPOS-00012 + A.11.SEC-OL7 + 8.2.8 + 8.2 + OL09-00-002103 + SV-271673r1091731_rule + A session lock is a temporary action taken when a user stops work and moves away from the immediate physical vicinity +of the information system but does not want to logout because of the temporary nature of the absense. + + # Remediation is applicable only in certain platforms if rpm --quiet -q gdm && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then -var_screensaver_lock_delay='' +var_screensaver_lock_delay='' # Check for setting in any of the DConf db directories @@ -8240,7 +9796,6 @@ then fi fi - [ ! -z "${DCONFFILE}" ] && echo "" >> "${DCONFFILE}" if ! grep -q "\\[org/gnome/desktop/screensaver\\]" "${DCONFFILE}" then @@ -8254,21 +9809,23 @@ then else sed -i "\\|\\[org/gnome/desktop/screensaver\\]|a\\lock-delay=${escaped_value}" "${DCONFFILE}" fi - dconf update else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-002103 - NIST-800-171-3.1.10 - NIST-800-53-AC-11(a) - NIST-800-53-CM-6(a) - PCI-DSS-Req-8.1.8 + - PCI-DSSv4-8.2 + - PCI-DSSv4-8.2.8 - dconf_gnome_screensaver_lock_delay - low_complexity - medium_disruption @@ -8277,7 +9834,7 @@ fi - unknown_strategy - name: XCCDF Value var_screensaver_lock_delay # promote to variable set_fact: - var_screensaver_lock_delay: !!str + var_screensaver_lock_delay: !!str tags: - always @@ -8293,10 +9850,13 @@ fi - '"gdm" in ansible_facts.packages' - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] tags: + - DISA-STIG-OL09-00-002103 - NIST-800-171-3.1.10 - NIST-800-53-AC-11(a) - NIST-800-53-CM-6(a) - PCI-DSS-Req-8.1.8 + - PCI-DSSv4-8.2 + - PCI-DSSv4-8.2.8 - dconf_gnome_screensaver_lock_delay - low_complexity - medium_disruption @@ -8310,28 +9870,31 @@ fi - '"gdm" in ansible_facts.packages' - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] tags: + - DISA-STIG-OL09-00-002103 - NIST-800-171-3.1.10 - NIST-800-53-AC-11(a) - NIST-800-53-CM-6(a) - PCI-DSS-Req-8.1.8 + - PCI-DSSv4-8.2 + - PCI-DSSv4-8.2.8 - dconf_gnome_screensaver_lock_delay - low_complexity - medium_disruption - medium_severity - no_reboot_needed - unknown_strategy - - - - - - - - - - - Enable GNOME3 Screensaver Lock After Idle Period - + + + + + + + + + + + Enable GNOME3 Screensaver Lock After Idle Period + To activate locking of the screensaver in the GNOME3 desktop when it is activated, add or set lock-enabled to true in /etc/dconf/db/local.d/00-security-settings. For example: @@ -8342,52 +9905,53 @@ Once the settings have been added, add a lock to /etc/dconf/db/local.d/locks/00-security-settings-lock to prevent user modification. For example: /org/gnome/desktop/screensaver/lock-enabled -After the settings have been set, run dconf update. - 1 - 12 - 15 - 16 - 5.5.5 - DSS05.04 - DSS05.10 - DSS06.10 - 3.1.10 - CCI-000056 - CCI-000058 - CCI-000060 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - SR 1.1 - SR 1.10 - SR 1.2 - SR 1.5 - SR 1.7 - SR 1.8 - SR 1.9 - A.18.1.4 - A.9.2.1 - A.9.2.4 - A.9.3.1 - A.9.4.2 - A.9.4.3 - CM-6(a) - PR.AC-7 - FMT_MOF_EXT.1 - Req-8.1.8 - 8.2.8 - SRG-OS-000028-GPOS-00009 - SRG-OS-000030-GPOS-00011 - A session lock is a temporary action taken when a user stops work and moves away from the immediate physical vicinity -of the information system but does not want to logout because of the temporary nature of the absense. - - # Remediation is applicable only in certain platforms +After the settings have been set, run dconf update. + 1 + 12 + 15 + 16 + 5.5.5 + DSS05.04 + DSS05.10 + DSS06.10 + 3.1.10 + CCI-000057 + CCI-000056 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + SR 1.1 + SR 1.10 + SR 1.2 + SR 1.5 + SR 1.7 + SR 1.8 + SR 1.9 + A.18.1.4 + A.9.2.1 + A.9.2.4 + A.9.3.1 + A.9.4.2 + A.9.4.3 + CM-6(a) + PR.AC-7 + Req-8.1.8 + SRG-OS-000028-GPOS-00009 + SRG-OS-000030-GPOS-00011 + 8.2.8 + 8.2 + OL09-00-002123 + SV-271681r1091755_rule + A session lock is a temporary action taken when a user stops work and moves away from the immediate physical vicinity +of the information system but does not want to logout because of the temporary nature of the absense. + + # Remediation is applicable only in certain platforms if rpm --quiet -q gdm && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then # Check for setting in any of the DConf db directories @@ -8410,7 +9974,6 @@ then fi fi - [ ! -z "${DCONFFILE}" ] && echo "" >> "${DCONFFILE}" if ! grep -q "\\[org/gnome/desktop/screensaver\\]" "${DCONFFILE}" then @@ -8424,7 +9987,6 @@ then else sed -i "\\|\\[org/gnome/desktop/screensaver\\]|a\\lock-enabled=${escaped_value}" "${DCONFFILE}" fi - dconf update # Check for setting in any of the DConf db directories LOCKFILES=$(grep -r "^/org/gnome/desktop/screensaver/lock-enabled$" "/etc/dconf/db/" \ @@ -8443,21 +10005,22 @@ if ! grep -qr "^/org/gnome/desktop/screensaver/lock-enabled$" /etc/dconf/db/loca then echo "/org/gnome/desktop/screensaver/lock-enabled" >> "/etc/dconf/db/local.d/locks/00-security-settings-lock" fi - dconf update else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: - CJIS-5.5.5 + - DISA-STIG-OL09-00-002123 - NIST-800-171-3.1.10 - NIST-800-53-CM-6(a) - PCI-DSS-Req-8.1.8 + - PCI-DSSv4-8.2 - PCI-DSSv4-8.2.8 - dconf_gnome_screensaver_lock_enabled - low_complexity @@ -8474,9 +10037,11 @@ fi - ansible_distribution == 'SLES' tags: - CJIS-5.5.5 + - DISA-STIG-OL09-00-002123 - NIST-800-171-3.1.10 - NIST-800-53-CM-6(a) - PCI-DSS-Req-8.1.8 + - PCI-DSSv4-8.2 - PCI-DSSv4-8.2.8 - dconf_gnome_screensaver_lock_enabled - low_complexity @@ -8499,9 +10064,11 @@ fi - ansible_distribution != 'SLES' tags: - CJIS-5.5.5 + - DISA-STIG-OL09-00-002123 - NIST-800-171-3.1.10 - NIST-800-53-CM-6(a) - PCI-DSS-Req-8.1.8 + - PCI-DSSv4-8.2 - PCI-DSSv4-8.2.8 - dconf_gnome_screensaver_lock_enabled - low_complexity @@ -8522,9 +10089,11 @@ fi - ansible_distribution != 'SLES' tags: - CJIS-5.5.5 + - DISA-STIG-OL09-00-002123 - NIST-800-171-3.1.10 - NIST-800-53-CM-6(a) - PCI-DSS-Req-8.1.8 + - PCI-DSSv4-8.2 - PCI-DSSv4-8.2.8 - dconf_gnome_screensaver_lock_enabled - low_complexity @@ -8547,9 +10116,11 @@ fi - ansible_distribution == 'SLES' tags: - CJIS-5.5.5 + - DISA-STIG-OL09-00-002123 - NIST-800-171-3.1.10 - NIST-800-53-CM-6(a) - PCI-DSS-Req-8.1.8 + - PCI-DSSv4-8.2 - PCI-DSSv4-8.2.8 - dconf_gnome_screensaver_lock_enabled - low_complexity @@ -8570,9 +10141,11 @@ fi - ansible_distribution == 'SLES' tags: - CJIS-5.5.5 + - DISA-STIG-OL09-00-002123 - NIST-800-171-3.1.10 - NIST-800-53-CM-6(a) - PCI-DSS-Req-8.1.8 + - PCI-DSSv4-8.2 - PCI-DSSv4-8.2.8 - dconf_gnome_screensaver_lock_enabled - low_complexity @@ -8590,9 +10163,11 @@ fi - ansible_distribution == 'SLES' tags: - CJIS-5.5.5 + - DISA-STIG-OL09-00-002123 - NIST-800-171-3.1.10 - NIST-800-53-CM-6(a) - PCI-DSS-Req-8.1.8 + - PCI-DSSv4-8.2 - PCI-DSSv4-8.2.8 - dconf_gnome_screensaver_lock_enabled - low_complexity @@ -8609,9 +10184,11 @@ fi - ansible_distribution == 'SLES' tags: - CJIS-5.5.5 + - DISA-STIG-OL09-00-002123 - NIST-800-171-3.1.10 - NIST-800-53-CM-6(a) - PCI-DSS-Req-8.1.8 + - PCI-DSSv4-8.2 - PCI-DSSv4-8.2.8 - dconf_gnome_screensaver_lock_enabled - low_complexity @@ -8627,9 +10204,11 @@ fi - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] tags: - CJIS-5.5.5 + - DISA-STIG-OL09-00-002123 - NIST-800-171-3.1.10 - NIST-800-53-CM-6(a) - PCI-DSS-Req-8.1.8 + - PCI-DSSv4-8.2 - PCI-DSSv4-8.2.8 - dconf_gnome_screensaver_lock_enabled - low_complexity @@ -8637,149 +10216,17 @@ fi - medium_severity - no_reboot_needed - unknown_strategy - - - - - - - - - - Ensure Users Cannot Change GNOME3 Screensaver Lock After Idle Period - If not already configured, ensure that users cannot change GNOME3 screensaver lock settings -by adding /org/gnome/desktop/screensaver/lock-enabled -to /etc/dconf/db/local.d/locks/00-security-settings. -For example: -/org/gnome/desktop/screensaver/lock-enabled -After the settings have been set, run dconf update. - 1 - 12 - 15 - 16 - 5.5.5 - DSS05.04 - DSS05.10 - DSS06.10 - 3.1.10 - CCI-000056 - CCI-000057 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - SR 1.1 - SR 1.10 - SR 1.2 - SR 1.5 - SR 1.7 - SR 1.8 - SR 1.9 - A.18.1.4 - A.9.2.1 - A.9.2.4 - A.9.3.1 - A.9.4.2 - A.9.4.3 - CM-6(a) - PR.AC-7 - FMT_MOF_EXT.1 - Req-8.1.8 - SRG-OS-000028-GPOS-00009 - SRG-OS-000030-GPOS-00011 - A session lock is a temporary action taken when a user stops work and moves away from the immediate physical vicinity -of the information system but does not want to logout because of the temporary nature of the absense. - # Remediation is applicable only in certain platforms -if rpm --quiet -q gdm; then - -# Check for setting in any of the DConf db directories -LOCKFILES=$(grep -r "^/org/gnome/desktop/screensaver/lock-enabled$" "/etc/dconf/db/" \ - | grep -v 'distro\|ibus\|local.d' | grep ":" | cut -d":" -f1) -LOCKSFOLDER="/etc/dconf/db/local.d/locks" - -mkdir -p "${LOCKSFOLDER}" - -# Comment out the configurations in databases different from the target one -if [[ ! -z "${LOCKFILES}" ]] -then - sed -i -E "s|^/org/gnome/desktop/screensaver/lock-enabled$|#&|" "${LOCKFILES[@]}" -fi - -if ! grep -qr "^/org/gnome/desktop/screensaver/lock-enabled$" /etc/dconf/db/local.d/ -then - echo "/org/gnome/desktop/screensaver/lock-enabled" >> "/etc/dconf/db/local.d/locks/00-security-settings-lock" -fi - -dconf update - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Gather the package facts - package_facts: - manager: auto - tags: - - CJIS-5.5.5 - - NIST-800-171-3.1.10 - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-8.1.8 - - dconf_gnome_screensaver_lock_locked - - low_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - - unknown_strategy - -- name: Prevent user modification of GNOME Screensaver lock-enabled - lineinfile: - path: /etc/dconf/db/local.d/locks/00-security-settings-lock - regexp: ^/org/gnome/desktop/screensaver/lock-enabled$ - line: /org/gnome/desktop/screensaver/lock-enabled - create: true - when: '"gdm" in ansible_facts.packages' - tags: - - CJIS-5.5.5 - - NIST-800-171-3.1.10 - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-8.1.8 - - dconf_gnome_screensaver_lock_locked - - low_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - - unknown_strategy - -- name: Dconf Update - command: dconf update - when: '"gdm" in ansible_facts.packages' - tags: - - CJIS-5.5.5 - - NIST-800-171-3.1.10 - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-8.1.8 - - dconf_gnome_screensaver_lock_locked - - low_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - - unknown_strategy - - - - - - - - - - Implement Blank Screensaver - + + + + + + + + + + Implement Blank Screensaver + To set the screensaver mode in the GNOME3 desktop to a blank screen, @@ -8792,51 +10239,53 @@ Once the settings have been added, add a lock to /etc/dconf/db/local.d/locks/00-security-settings-lock to prevent user modification. For example: /org/gnome/desktop/screensaver/picture-uri -After the settings have been set, run dconf update. - 1 - 12 - 15 - 16 - 5.5.5 - DSS05.04 - DSS05.10 - DSS06.10 - 3.1.10 - CCI-000060 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - SR 1.1 - SR 1.10 - SR 1.2 - SR 1.5 - SR 1.7 - SR 1.8 - SR 1.9 - A.18.1.4 - A.9.2.1 - A.9.2.4 - A.9.3.1 - A.9.4.2 - A.9.4.3 - AC-11(1) - CM-6(a) - AC-11(1).1 - PR.AC-7 - FMT_MOF_EXT.1 - Req-8.1.8 - 8.2.8 - SRG-OS-000031-GPOS-00012 - Setting the screensaver mode to blank-only conceals the -contents of the display from passersby. - - # Remediation is applicable only in certain platforms +After the settings have been set, run dconf update. + 1 + 12 + 15 + 16 + 5.5.5 + DSS05.04 + DSS05.10 + DSS06.10 + 3.1.10 + CCI-000060 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + SR 1.1 + SR 1.10 + SR 1.2 + SR 1.5 + SR 1.7 + SR 1.8 + SR 1.9 + A.18.1.4 + A.9.2.1 + A.9.2.4 + A.9.3.1 + A.9.4.2 + A.9.4.3 + AC-11(1) + CM-6(a) + AC-11(1).1 + PR.AC-7 + Req-8.1.8 + SRG-OS-000031-GPOS-00012 + 8.2.8 + 8.2 + OL09-00-002106 + SV-271676r1091740_rule + Setting the screensaver mode to blank-only conceals the +contents of the display from passersby. + + # Remediation is applicable only in certain platforms if rpm --quiet -q gdm && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then # Check for setting in any of the DConf db directories @@ -8859,7 +10308,6 @@ then fi fi - [ ! -z "${DCONFFILE}" ] && echo "" >> "${DCONFFILE}" if ! grep -q "\\[org/gnome/desktop/screensaver\\]" "${DCONFFILE}" then @@ -8873,7 +10321,6 @@ then else sed -i "\\|\\[org/gnome/desktop/screensaver\\]|a\\picture-uri=${escaped_value}" "${DCONFFILE}" fi - dconf update # Check for setting in any of the DConf db directories LOCKFILES=$(grep -r "^/org/gnome/desktop/screensaver/picture-uri$" "/etc/dconf/db/" \ @@ -8892,23 +10339,24 @@ if ! grep -qr "^/org/gnome/desktop/screensaver/picture-uri$" /etc/dconf/db/local then echo "/org/gnome/desktop/screensaver/picture-uri" >> "/etc/dconf/db/local.d/locks/00-security-settings-lock" fi - dconf update else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: - CJIS-5.5.5 + - DISA-STIG-OL09-00-002106 - NIST-800-171-3.1.10 - NIST-800-53-AC-11(1) - NIST-800-53-AC-11(1).1 - NIST-800-53-CM-6(a) - PCI-DSS-Req-8.1.8 + - PCI-DSSv4-8.2 - PCI-DSSv4-8.2.8 - dconf_gnome_screensaver_mode_blank - low_complexity @@ -8930,11 +10378,13 @@ fi - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] tags: - CJIS-5.5.5 + - DISA-STIG-OL09-00-002106 - NIST-800-171-3.1.10 - NIST-800-53-AC-11(1) - NIST-800-53-AC-11(1).1 - NIST-800-53-CM-6(a) - PCI-DSS-Req-8.1.8 + - PCI-DSSv4-8.2 - PCI-DSSv4-8.2.8 - dconf_gnome_screensaver_mode_blank - low_complexity @@ -8954,11 +10404,13 @@ fi - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] tags: - CJIS-5.5.5 + - DISA-STIG-OL09-00-002106 - NIST-800-171-3.1.10 - NIST-800-53-AC-11(1) - NIST-800-53-AC-11(1).1 - NIST-800-53-CM-6(a) - PCI-DSS-Req-8.1.8 + - PCI-DSSv4-8.2 - PCI-DSSv4-8.2.8 - dconf_gnome_screensaver_mode_blank - low_complexity @@ -8974,11 +10426,13 @@ fi - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] tags: - CJIS-5.5.5 + - DISA-STIG-OL09-00-002106 - NIST-800-171-3.1.10 - NIST-800-53-AC-11(1) - NIST-800-53-AC-11(1).1 - NIST-800-53-CM-6(a) - PCI-DSS-Req-8.1.8 + - PCI-DSSv4-8.2 - PCI-DSSv4-8.2.8 - dconf_gnome_screensaver_mode_blank - low_complexity @@ -8986,66 +10440,66 @@ fi - medium_severity - no_reboot_needed - unknown_strategy - - - - - - - - - - Ensure Users Cannot Change GNOME3 Screensaver Settings - If not already configured, ensure that users cannot change GNOME3 screensaver lock settings + + + + + + + + + + Ensure Users Cannot Change GNOME3 Screensaver Settings + If not already configured, ensure that users cannot change GNOME3 screensaver lock settings by adding /org/gnome/desktop/screensaver/lock-delay to /etc/dconf/db/local.d/locks/00-security-settings-lock to prevent user modification. For example: /org/gnome/desktop/screensaver/lock-delay -After the settings have been set, run dconf update. - 1 - 12 - 15 - 16 - DSS05.04 - DSS05.10 - DSS06.10 - 3.1.10 - CCI-000057 - CCI-000060 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - SR 1.1 - SR 1.10 - SR 1.2 - SR 1.5 - SR 1.7 - SR 1.8 - SR 1.9 - A.18.1.4 - A.9.2.1 - A.9.2.4 - A.9.3.1 - A.9.4.2 - A.9.4.3 - CM-6(a) - PR.AC-7 - FMT_MOF_EXT.1 - SRG-OS-000029-GPOS-00010 - SRG-OS-000031-GPOS-00012 - A session time-out lock is a temporary action taken when a user stops work and moves away from the immediate +After the settings have been set, run dconf update. + 1 + 12 + 15 + 16 + DSS05.04 + DSS05.10 + DSS06.10 + 3.1.10 + CCI-000057 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + SR 1.1 + SR 1.10 + SR 1.2 + SR 1.5 + SR 1.7 + SR 1.8 + SR 1.9 + A.18.1.4 + A.9.2.1 + A.9.2.4 + A.9.3.1 + A.9.4.2 + A.9.4.3 + CM-6(a) + PR.AC-7 + SRG-OS-000029-GPOS-00010 + SRG-OS-000031-GPOS-00012 + OL09-00-002125 + SV-271683r1091761_rule + A session time-out lock is a temporary action taken when a user stops work and moves away from the immediate physical vicinity of the information system but does not logout because of the temporary nature of the absence. Rather than relying on the user to manually lock their operating system session prior to vacating the vicinity, GNOME desktops can be configured to identify when a user's session has idled and take action to initiate the -session lock. As such, users should not be allowed to change session settings. - - # Remediation is applicable only in certain platforms +session lock. As such, users should not be allowed to change session settings. + + # Remediation is applicable only in certain platforms if rpm --quiet -q gdm && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then # Check for setting in any of the DConf db directories @@ -9065,17 +10519,17 @@ if ! grep -qr "^/org/gnome/desktop/screensaver/lock-delay$" /etc/dconf/db/local. then echo "/org/gnome/desktop/screensaver/lock-delay" >> "/etc/dconf/db/local.d/locks/00-security-settings-lock" fi - dconf update else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-002125 - NIST-800-171-3.1.10 - NIST-800-53-CM-6(a) - dconf_gnome_screensaver_user_locks @@ -9095,6 +10549,7 @@ fi - '"gdm" in ansible_facts.packages' - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] tags: + - DISA-STIG-OL09-00-002125 - NIST-800-171-3.1.10 - NIST-800-53-CM-6(a) - dconf_gnome_screensaver_user_locks @@ -9110,6 +10565,7 @@ fi - '"gdm" in ansible_facts.packages' - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] tags: + - DISA-STIG-OL09-00-002125 - NIST-800-171-3.1.10 - NIST-800-53-CM-6(a) - dconf_gnome_screensaver_user_locks @@ -9118,68 +10574,70 @@ fi - medium_severity - no_reboot_needed - unknown_strategy - - - - - - - - - - Ensure Users Cannot Change GNOME3 Session Idle Settings - If not already configured, ensure that users cannot change GNOME3 session idle settings + + + + + + + + + + Ensure Users Cannot Change GNOME3 Session Idle Settings + If not already configured, ensure that users cannot change GNOME3 session idle settings by adding /org/gnome/desktop/session/idle-delay to /etc/dconf/db/local.d/locks/00-security-settings-lock to prevent user modification. For example: /org/gnome/desktop/session/idle-delay -After the settings have been set, run dconf update. - 1 - 12 - 15 - 16 - DSS05.04 - DSS05.10 - DSS06.10 - 3.1.10 - CCI-000057 - CCI-000060 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - SR 1.1 - SR 1.10 - SR 1.2 - SR 1.5 - SR 1.7 - SR 1.8 - SR 1.9 - A.18.1.4 - A.9.2.1 - A.9.2.4 - A.9.3.1 - A.9.4.2 - A.9.4.3 - CM-6(a) - PR.AC-7 - FMT_MOF_EXT.1 - Req-8.1.8 - 8.2.8 - SRG-OS-000029-GPOS-00010 - SRG-OS-000031-GPOS-00012 - A session time-out lock is a temporary action taken when a user stops work and moves away from the immediate +After the settings have been set, run dconf update. + 1 + 12 + 15 + 16 + DSS05.04 + DSS05.10 + DSS06.10 + 3.1.10 + CCI-000057 + CCI-000060 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + SR 1.1 + SR 1.10 + SR 1.2 + SR 1.5 + SR 1.7 + SR 1.8 + SR 1.9 + A.18.1.4 + A.9.2.1 + A.9.2.4 + A.9.3.1 + A.9.4.2 + A.9.4.3 + CM-6(a) + PR.AC-7 + Req-8.1.8 + SRG-OS-000029-GPOS-00010 + SRG-OS-000031-GPOS-00012 + 8.2.8 + 8.2 + OL09-00-002124 + SV-271682r1091758_rule + A session time-out lock is a temporary action taken when a user stops work and moves away from the immediate physical vicinity of the information system but does not logout because of the temporary nature of the absence. Rather than relying on the user to manually lock their operating system session prior to vacating the vicinity, GNOME desktops can be configured to identify when a user's session has idled and take action to initiate the -session lock. As such, users should not be allowed to change session settings. - - # Remediation is applicable only in certain platforms +session lock. As such, users should not be allowed to change session settings. + + # Remediation is applicable only in certain platforms if rpm --quiet -q gdm && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then # Check for setting in any of the DConf db directories @@ -9199,20 +10657,21 @@ if ! grep -qr "^/org/gnome/desktop/session/idle-delay$" /etc/dconf/db/local.d/ then echo "/org/gnome/desktop/session/idle-delay" >> "/etc/dconf/db/local.d/locks/00-security-settings-lock" fi - dconf update else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-002124 - NIST-800-171-3.1.10 - NIST-800-53-CM-6(a) - PCI-DSS-Req-8.1.8 + - PCI-DSSv4-8.2 - PCI-DSSv4-8.2.8 - dconf_gnome_session_idle_user_locks - low_complexity @@ -9231,9 +10690,11 @@ fi - '"gdm" in ansible_facts.packages' - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] tags: + - DISA-STIG-OL09-00-002124 - NIST-800-171-3.1.10 - NIST-800-53-CM-6(a) - PCI-DSS-Req-8.1.8 + - PCI-DSSv4-8.2 - PCI-DSSv4-8.2.8 - dconf_gnome_session_idle_user_locks - low_complexity @@ -9248,9 +10709,11 @@ fi - '"gdm" in ansible_facts.packages' - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] tags: + - DISA-STIG-OL09-00-002124 - NIST-800-171-3.1.10 - NIST-800-53-CM-6(a) - PCI-DSS-Req-8.1.8 + - PCI-DSSv4-8.2 - PCI-DSSv4-8.2.8 - dconf_gnome_session_idle_user_locks - low_complexity @@ -9258,91 +10721,96 @@ fi - medium_severity - no_reboot_needed - unknown_strategy - - - - - - - - - - - GNOME System Settings - GNOME provides configuration and functionality to a graphical desktop environment + + + + + + + + + + + GNOME System Settings + GNOME provides configuration and functionality to a graphical desktop environment that changes grahical configurations or allow a user to perform actions that users normally would not be able to do in non-graphical mode such as remote access configuration, power policies, Geo-location, etc. Configuring such settings in GNOME will prevent accidential graphical configuration -changes by users from taking place. - - Disable Ctrl-Alt-Del Reboot Key Sequence in GNOME3 - By default, GNOME will reboot the system if the +changes by users from taking place. + + Disable Ctrl-Alt-Del Reboot Key Sequence in GNOME3 + By default, GNOME will reboot the system if the Ctrl-Alt-Del key sequence is pressed. - + + To configure the system to ignore the Ctrl-Alt-Del key sequence from the Graphical User Interface (GUI) instead of rebooting the system, -add or set logout to '' in +add or set logout to [''] in /etc/dconf/db/local.d/00-security-settings. For example: [org/gnome/settings-daemon/plugins/media-keys] -logout='' +logout=[''] Once the settings have been added, add a lock to /etc/dconf/db/local.d/locks/00-security-settings-lock to prevent user modification. For example: /org/gnome/settings-daemon/plugins/media-keys/logout -After the settings have been set, run dconf update. - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - APO01.06 - DSS05.04 - DSS05.07 - DSS06.02 - 3.1.2 - CCI-000366 - 4.3.3.7.3 - SR 2.1 - SR 5.2 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CM-6(a) - AC-6(1) - CM-7(b) - PR.AC-4 - PR.DS-5 - SRG-OS-000480-GPOS-00227 - A locally logged-in user who presses Ctrl-Alt-Del, when at the console, +After the settings have been set, run dconf update. + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + APO01.06 + DSS05.04 + DSS05.07 + DSS06.02 + 3.1.2 + CCI-000366 + 4.3.3.7.3 + SR 2.1 + SR 5.2 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CM-6(a) + AC-6(1) + CM-7(b) + PR.AC-4 + PR.DS-5 + SRG-OS-000480-GPOS-00227 + OL09-00-002107 + OL09-00-002129 + SV-271677r1091743_rule + SV-271687r1091773_rule + A locally logged-in user who presses Ctrl-Alt-Del, when at the console, can reboot the system. If accidentally pressed, as could happen in the case of mixed OS environment, this can create the risk of short-term -loss of availability of systems due to unintentional reboot. - - # Remediation is applicable only in certain platforms +loss of availability of systems due to unintentional reboot. + + # Remediation is applicable only in certain platforms if rpm --quiet -q gdm && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then # Check for setting in any of the DConf db directories @@ -9365,21 +10833,19 @@ then fi fi - [ ! -z "${DCONFFILE}" ] && echo "" >> "${DCONFFILE}" if ! grep -q "\\[org/gnome/settings-daemon/plugins/media-keys\\]" "${DCONFFILE}" then printf '%s\n' "[org/gnome/settings-daemon/plugins/media-keys]" >> ${DCONFFILE} fi -escaped_value="$(sed -e 's/\\/\\\\/g' <<< "''")" +escaped_value="$(sed -e 's/\\/\\\\/g' <<< "['']")" if grep -q "^\\s*logout\\s*=" "${DCONFFILE}" then sed -i "s/\\s*logout\\s*=\\s*.*/logout=${escaped_value}/g" "${DCONFFILE}" else sed -i "\\|\\[org/gnome/settings-daemon/plugins/media-keys\\]|a\\logout=${escaped_value}" "${DCONFFILE}" fi - dconf update # Check for setting in any of the DConf db directories LOCKFILES=$(grep -r "^/org/gnome/settings-daemon/plugins/media-keys/logout$" "/etc/dconf/db/" \ @@ -9398,17 +10864,18 @@ if ! grep -qr "^/org/gnome/settings-daemon/plugins/media-keys/logout$" /etc/dcon then echo "/org/gnome/settings-daemon/plugins/media-keys/logout" >> "/etc/dconf/db/local.d/locks/00-security-settings-lock" fi - dconf update else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-002107 + - DISA-STIG-OL09-00-002129 - NIST-800-171-3.1.2 - NIST-800-53-AC-6(1) - NIST-800-53-CM-6(a) @@ -9425,13 +10892,15 @@ fi dest: /etc/dconf/db/local.d/00-security-settings section: org/gnome/settings-daemon/plugins/media-keys option: logout - value: '''''' + value: '['''']' create: true no_extra_spaces: true when: - '"gdm" in ansible_facts.packages' - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] tags: + - DISA-STIG-OL09-00-002107 + - DISA-STIG-OL09-00-002129 - NIST-800-171-3.1.2 - NIST-800-53-AC-6(1) - NIST-800-53-CM-6(a) @@ -9453,6 +10922,8 @@ fi - '"gdm" in ansible_facts.packages' - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] tags: + - DISA-STIG-OL09-00-002107 + - DISA-STIG-OL09-00-002129 - NIST-800-171-3.1.2 - NIST-800-53-AC-6(1) - NIST-800-53-CM-6(a) @@ -9470,6 +10941,8 @@ fi - '"gdm" in ansible_facts.packages' - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] tags: + - DISA-STIG-OL09-00-002107 + - DISA-STIG-OL09-00-002129 - NIST-800-171-3.1.2 - NIST-800-53-AC-6(1) - NIST-800-53-CM-6(a) @@ -9480,100 +10953,89 @@ fi - medium_disruption - no_reboot_needed - unknown_strategy - - - - - - - - - - - - SAP Specific Requirement - SAP (Systems, Applications and Products in Data Processing) is enterprise -software to manage business operations and customer relations. The -following section contains SAP specific requirement that is not part -of standard or common OS setting. - - - Sudo - Sudo, which stands for "su 'do'", provides the ability to delegate authority + + + + + + + + + + + + Sudo + Sudo, which stands for "su 'do'", provides the ability to delegate authority to certain users, groups of users, or system administrators. When configured for system users and/or groups, Sudo can allow a user or group to execute privileged commands that normally only root is allowed to execute. - + + For more information on Sudo and addition Sudo configuration options, see -https://www.sudo.ws. - - Group name dedicated to the use of sudo - Specify the name of the group that should own /usr/bin/sudo. - root - sudogrp - - - Sudo - logfile value - Specify the sudo logfile to use. The default value used here matches the example -location from CIS, which uses /var/log/sudo.log. - /var/log/sudo.log - /var/log/sudo.log - - - Sudo - passwd_timeout value - Defines the number of minutes before the sudo password prompt times out. -Defining 0 means no timeout. The default timeout value is 5 minutes. - 5 - 0 - 1 - 2 - 3 - 5 - - - Sudo - timestamp_timeout value - Defines the number of minutes that can elapse before sudo will ask for a passwd again. +https://www.sudo.ws. + + Group name dedicated to the use of sudo + Specify the name of the group that should own /usr/bin/sudo. + root + root + sudogrp + + + Sudo - logfile value + Specify the sudo logfile to use. The default value used here matches the example +location from CIS, which uses /var/log/sudo.log. + /var/log/sudo.log + /var/log/sudo.log + + + Sudo - timestamp_timeout value + Defines the number of minutes that can elapse before sudo will ask for a passwd again. If set to a value less than 0 the user's time stamp will never expire. Defining 0 means always prompt for a -password. The default timeout value is 5 minutes. - 5 - 0 - 1 - 2 - 3 - 5 - 15 - - - Sudo - umask value - Specify the sudo umask to use. The actual umask value that is used is the union +password. The default timeout value is 5 minutes. + 5 + 0 + 1 + 2 + 3 + 5 + 15 + + + Sudo - umask value + Specify the sudo umask to use. The actual umask value that is used is the union of the user's umask and the sudo umask. The default sudo umask is 0022. This guarantess sudo never lowers the umask when -running a command. - 0022 - 0022 - 0027 - 0077 - - - Install sudo Package - The sudo package can be installed with the following command: +running a command. + 0022 + 0022 + 0027 + 0077 + + + Install sudo Package + The sudo package can be installed with the following command: -$ sudo yum install sudo - BP28(R19) - 1382 - 1384 - 1386 - CM-6(a) - FMT_MOF_EXT.1 - 10.2.1.5 - SRG-OS-000324-GPOS-00125 - sudo is a program designed to allow a system administrator to give +$ sudo yum install sudo + + CCI-002235 + 1382 + 1384 + 1386 + CM-6(a) + FMT_MOF_EXT.1 + SRG-OS-000324-GPOS-00125 + R33 + 2.2.6 + 2.2 + OL09-00-000230 + SV-271474r1091134_rule + sudo is a program designed to allow a system administrator to give limited root privileges to users and log root activity. The basic philosophy is to give as few privileges as possible but still allow system users to -get their work done. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then +get their work done. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then if ! rpm -q --quiet "sudo" ; then yum install -y "sudo" @@ -9582,56 +11044,380 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Ensure sudo is installed - package: - name: sudo - state: present - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + + - name: Gather the package facts + package_facts: + manager: auto tags: + - DISA-STIG-OL09-00-000230 - NIST-800-53-CM-6(a) - - PCI-DSSv4-10.2.1.5 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 - enable_strategy - low_complexity - low_disruption - medium_severity - no_reboot_needed - package_sudo_installed - - include install_sudo + +- name: Ensure sudo is installed + package: + name: sudo + state: present + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-000230 + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - package_sudo_installed + + include install_sudo class install_sudo { package { 'sudo': ensure => 'installed', } } - - + + package --add=sudo - - + + [[packages]] name = "sudo" version = "*" - - - - - - - - - - Ensure Privileged Escalated Commands Cannot Execute Other Commands - sudo NOEXEC - The sudo NOEXEC tag, when specified, prevents user executed + + + + + + + + + + Verify Group Who Owns /etc/sudoers.d Directory + To properly set the group owner of /etc/sudoers.d, run the command: $ sudo chgrp root /etc/sudoers.d + + R50 + The ownership of the /etc/sudoers.d directory by the root group is important +because this directory hosts sudo configuration. Protection of this +directory is critical for system security. Assigning the ownership to root +ensures exclusive control of the sudo configuration. + find -H /etc/sudoers.d/ -maxdepth 1 -type d -exec chgrp -L root {} \; + + - name: Ensure group owner on /etc/sudoers.d/ + file: + path: /etc/sudoers.d/ + state: directory + group: root + tags: + - configure_strategy + - directory_groupowner_etc_sudoersd + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify User Who Owns /etc/sudoers.d Directory + To properly set the owner of /etc/sudoers.d, run the command: $ sudo chown root /etc/sudoers.d + + R50 + The ownership of the /etc/sudoers.d directory by the root user is important +because this directory hosts sudo configuration. Protection of this +directory is critical for system security. Assigning the ownership to root +ensures exclusive control of the sudo configuration. + find -H /etc/sudoers.d/ -maxdepth 1 -type d -exec chown -L 0 {} \; + + - name: Ensure owner on directory /etc/sudoers.d/ + file: + path: /etc/sudoers.d/ + state: directory + owner: '0' + tags: + - configure_strategy + - directory_owner_etc_sudoersd + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify Permissions On /etc/sudoers.d Directory + To properly set the permissions of /etc/sudoers.d, run the command: $ sudo chmod 0750 /etc/sudoers.d + + R50 + Setting correct permissions on the /etc/sudoers.d directory is important +because this directory hosts sudo configuration. Protection of this +directory is critical for system security. Restricting the permissions +ensures exclusive control of the sudo configuration. + + + + +find -H /etc/sudoers.d/ -maxdepth 1 -perm /u+s,g+ws,o+xwrt -type d -exec chmod u-s,g-ws,o-xwrt {} \; + + - name: Find /etc/sudoers.d/ file(s) + command: 'find -H /etc/sudoers.d/ -maxdepth 1 -perm /u+s,g+ws,o+xwrt -type d ' + register: files_found + changed_when: false + failed_when: false + check_mode: false + tags: + - configure_strategy + - directory_permissions_etc_sudoersd + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Set permissions for /etc/sudoers.d/ file(s) + file: + path: '{{ item }}' + mode: u-s,g-ws,o-xwrt + state: directory + with_items: + - '{{ files_found.stdout_lines }}' + tags: + - configure_strategy + - directory_permissions_etc_sudoersd + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify Group Who Owns /etc/sudoers File + To properly set the group owner of /etc/sudoers, run the command: $ sudo chgrp root /etc/sudoers + + R50 + The ownership of the /etc/sudoers file by the root group is important +because this file hosts sudo configuration. Protection of this +file is critical for system security. Assigning the ownership to root +ensures exclusive control of the sudo configuration. + chgrp root /etc/sudoers + + - name: Test for existence /etc/sudoers + stat: + path: /etc/sudoers + register: file_exists + tags: + - configure_strategy + - file_groupowner_etc_sudoers + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure group owner root on /etc/sudoers + file: + path: /etc/sudoers + group: root + when: file_exists.stat is defined and file_exists.stat.exists + tags: + - configure_strategy + - file_groupowner_etc_sudoers + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify User Who Owns /etc/sudoers File + To properly set the owner of /etc/sudoers, run the command: $ sudo chown root /etc/sudoers + + R50 + The ownership of the /etc/sudoers file by the root user is important +because this file hosts sudo configuration. Protection of this +file is critical for system security. Assigning the ownership to root +ensures exclusive control of the sudo configuration. + chown 0 /etc/sudoers + + - name: Test for existence /etc/sudoers + stat: + path: /etc/sudoers + register: file_exists + tags: + - configure_strategy + - file_owner_etc_sudoers + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure owner 0 on /etc/sudoers + file: + path: /etc/sudoers + owner: '0' + when: file_exists.stat is defined and file_exists.stat.exists + tags: + - configure_strategy + - file_owner_etc_sudoers + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify Permissions On /etc/sudoers File + To properly set the permissions of /etc/sudoers, run the command: $ sudo chmod 0440 /etc/sudoers + + R50 + Setting correct permissions on the /etc/sudoers file is important +because this file hosts sudo configuration. Protection of this +file is critical for system security. Restricting the permissions +ensures exclusive control of the sudo configuration. + + + + +chmod u-xws,g-xws,o-xwrt /etc/sudoers + + - name: Test for existence /etc/sudoers + stat: + path: /etc/sudoers + register: file_exists + tags: + - configure_strategy + - file_permissions_etc_sudoers + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure permission u-xws,g-xws,o-xwrt on /etc/sudoers + file: + path: /etc/sudoers + mode: u-xws,g-xws,o-xwrt + when: file_exists.stat is defined and file_exists.stat.exists + tags: + - configure_strategy + - file_permissions_etc_sudoers + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Ensure That the sudo Binary Has the Correct Permissions + +To properly set the permissions of /usr/bin/sudo, run the command: +$ sudo chmod 4111 /usr/bin/sudo + + R38 + The sudoers program should only be usable by people who have the correct permissions. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q sudo; then + +chmod 4110 /usr/bin/sudo + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - configure_strategy + - file_permissions_sudo + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /usr/bin/sudo + stat: + path: /usr/bin/sudo + register: file_exists + when: '"sudo" in ansible_facts.packages' + tags: + - configure_strategy + - file_permissions_sudo + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure permission 4110 on /usr/bin/sudo + file: + path: /usr/bin/sudo + mode: '4110' + when: + - '"sudo" in ansible_facts.packages' + - file_exists.stat is defined and file_exists.stat.exists + tags: + - configure_strategy + - file_permissions_sudo + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + Ensure Privileged Escalated Commands Cannot Execute Other Commands - sudo NOEXEC + The sudo NOEXEC tag, when specified, prevents user executed commands from executing other commands, like a shell for example. This should be enabled by making sure that the NOEXEC tag exists in /etc/sudoers configuration file or any sudo configuration snippets -in /etc/sudoers.d/. - BP28(R58) - Restricting the capability of sudo allowed commands to execute sub-commands -prevents users from running programs with privileges they wouldn't have otherwise. - +in /etc/sudoers.d/. + R39 + Restricting the capability of sudo allowed commands to execute sub-commands +prevents users from running programs with privileges they wouldn't have otherwise. + if /usr/sbin/visudo -qcf /etc/sudoers; then cp /etc/sudoers /etc/sudoers.bak if ! grep -P '^[\s]*Defaults[\s]*\bnoexec\b.*$' /etc/sudoers; then @@ -9651,8 +11437,8 @@ else echo "Skipping remediation, /etc/sudoers failed to validate" false fi - - - name: Ensure noexec is enabled in /etc/sudoers + + - name: Ensure noexec is enabled in /etc/sudoers lineinfile: path: /etc/sudoers regexp: ^[\s]*Defaults.*\bnoexec\b.*$ @@ -9665,25 +11451,25 @@ fi - no_reboot_needed - restrict_strategy - sudo_add_noexec - - - - - - - - - - Ensure Only Users Logged In To Real tty Can Execute Sudo - sudo requiretty - The sudo requiretty tag, when specified, will only execute sudo + + + + + + + + + + Ensure Only Users Logged In To Real tty Can Execute Sudo - sudo requiretty + The sudo requiretty tag, when specified, will only execute sudo commands from users logged in to a real tty. This should be enabled by making sure that the requiretty tag exists in /etc/sudoers configuration file or any sudo configuration snippets -in /etc/sudoers.d/. - BP28(R58) - Restricting the use cases in which a user is allowed to execute sudo commands -reduces the attack surface. - +in /etc/sudoers.d/. + R39 + Restricting the use cases in which a user is allowed to execute sudo commands +reduces the attack surface. + if /usr/sbin/visudo -qcf /etc/sudoers; then cp /etc/sudoers /etc/sudoers.bak if ! grep -P '^[\s]*Defaults[\s]*\brequiretty\b.*$' /etc/sudoers; then @@ -9703,8 +11489,8 @@ else echo "Skipping remediation, /etc/sudoers failed to validate" false fi - - - name: Ensure requiretty is enabled in /etc/sudoers + + - name: Ensure requiretty is enabled in /etc/sudoers lineinfile: path: /etc/sudoers regexp: ^[\s]*Defaults.*\brequiretty\b.*$ @@ -9717,28 +11503,30 @@ fi - no_reboot_needed - restrict_strategy - sudo_add_requiretty - - - - - - - - - - Ensure Only Users Logged In To Real tty Can Execute Sudo - sudo use_pty - The sudo use_pty tag, when specified, will only execute sudo + + + + + + + + + + Ensure Only Users Logged In To Real tty Can Execute Sudo - sudo use_pty + The sudo use_pty tag, when specified, will only execute sudo commands from users logged in to a real tty. This should be enabled by making sure that the use_pty tag exists in /etc/sudoers configuration file or any sudo configuration snippets -in /etc/sudoers.d/. - BP28(R58) - Req-10.2.5 - 10.2.1.5 - Requiring that sudo commands be run in a pseudo-terminal can prevent an attacker from retaining -access to the user's terminal after the main program has finished executing. - - # Remediation is applicable only in certain platforms +in /etc/sudoers.d/. + Req-10.2.5 + R39 + A.5.SEC-OL1 + 2.2.6 + 2.2 + Requiring that sudo commands be run in a pseudo-terminal can prevent an attacker from retaining +access to the user's terminal after the main program has finished executing. + + # Remediation is applicable only in certain platforms if rpm --quiet -q sudo; then if /usr/sbin/visudo -qcf /etc/sudoers; then @@ -9764,13 +11552,14 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: - PCI-DSS-Req-10.2.5 - - PCI-DSSv4-10.2.1.5 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 - low_complexity - low_disruption - medium_severity @@ -9787,39 +11576,41 @@ fi when: '"sudo" in ansible_facts.packages' tags: - PCI-DSS-Req-10.2.5 - - PCI-DSSv4-10.2.1.5 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 - low_complexity - low_disruption - medium_severity - no_reboot_needed - restrict_strategy - sudo_add_use_pty - - - - - - - - - - Ensure Sudo Logfile Exists - sudo logfile - A custom log sudo file can be configured with the 'logfile' tag. This rule configures + + + + + + + + + + Ensure Sudo Logfile Exists - sudo logfile + A custom log sudo file can be configured with the 'logfile' tag. This rule configures a sudo custom logfile at the default location suggested by CIS, which uses -/var/log/sudo.log. - Req-10.2.5 - 10.2.1.5 - A sudo log file simplifies auditing of sudo commands. - - # Remediation is applicable only in certain platforms +/var/log/sudo.log. + Req-10.2.5 + 2.2.6 + 2.2 + A sudo log file simplifies auditing of sudo commands. + + # Remediation is applicable only in certain platforms if rpm --quiet -q sudo; then -var_sudo_logfile='' +var_sudo_logfile='' if /usr/sbin/visudo -qcf /etc/sudoers; then cp /etc/sudoers /etc/sudoers.bak - if ! grep -P '^[\s]*Defaults[\s]*\blogfile=("(?:\\"|\\\\|[^"\\\n])*"\B|[^"](?:(?:\\,|\\"|\\ |\\\\|[^", \\\n])*)\b)\b.*$' /etc/sudoers; then + if ! grep -P '^[\s]*Defaults[\s]*\blogfile\s*=\s*(?:"?([^",\s]+)"?)\b.*$' /etc/sudoers; then # sudoers file doesn't define Option logfile echo "Defaults logfile=${var_sudo_logfile}" >> /etc/sudoers else @@ -9847,13 +11638,14 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: - PCI-DSS-Req-10.2.5 - - PCI-DSSv4-10.2.1.5 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 - low_complexity - low_disruption - low_severity @@ -9862,7 +11654,7 @@ fi - sudo_custom_logfile - name: XCCDF Value var_sudo_logfile # promote to variable set_fact: - var_sudo_logfile: !!str + var_sudo_logfile: !!str tags: - always @@ -9877,7 +11669,8 @@ fi when: '"sudo" in ansible_facts.packages' tags: - PCI-DSS-Req-10.2.5 - - PCI-DSSv4-10.2.1.5 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 - low_complexity - low_disruption - low_severity @@ -9895,81 +11688,101 @@ fi - edit_sudoers_logfile_option is defined and not edit_sudoers_logfile_option.changed tags: - PCI-DSS-Req-10.2.5 - - PCI-DSSv4-10.2.1.5 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 - low_complexity - low_disruption - low_severity - no_reboot_needed - restrict_strategy - sudo_custom_logfile - - - - - - - - - - - Ensure Users Re-Authenticate for Privilege Escalation - sudo !authenticate - The sudo !authenticate option, when specified, allows a user to execute commands using + + + + + + + + + + + Ensure a dedicated group owns sudo + Restrict the execution of privilege escalated commands to a dedicated group of users. +Ensure the group owner of /usr/bin/sudo is . + Changing group owner of /usr/bin/sudo to a group with no member users will prevent +any and all escalatation of privileges. +Additionally, the system may become unmanageable if root logins are not allowed. + This rule doesn't come with a remediation, before remediating the sysadmin needs to add users to the dedicated sudo group. + R38 + Restricting the set of users able to execute commands as privileged user reduces the attack surface. + + + + + + + + + + Ensure Users Re-Authenticate for Privilege Escalation - sudo !authenticate + The sudo !authenticate option, when specified, allows a user to execute commands using sudo without having to authenticate. This should be disabled by making sure that the !authenticate option does not exist in /etc/sudoers configuration file or -any sudo configuration snippets in /etc/sudoers.d/. - BP28(R5) - BP28(R59) - 1 - 12 - 15 - 16 - 5 - DSS05.04 - DSS05.10 - DSS06.03 - DSS06.10 - CCI-002038 - 4.3.3.5.1 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - SR 1.1 - SR 1.10 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.7 - SR 1.8 - SR 1.9 - A.18.1.4 - A.9.2.1 - A.9.2.2 - A.9.2.3 - A.9.2.4 - A.9.2.6 - A.9.3.1 - A.9.4.2 - A.9.4.3 - IA-11 - CM-6(a) - PR.AC-1 - PR.AC-7 - SRG-OS-000373-GPOS-00156 - SRG-OS-000373-GPOS-00157 - SRG-OS-000373-GPOS-00158 - Without re-authentication, users may access resources or perform tasks for which they +any sudo configuration snippets in /etc/sudoers.d/. + 1 + 12 + 15 + 16 + 5 + DSS05.04 + DSS05.10 + DSS06.03 + DSS06.10 + CCI-004895 + 4.3.3.5.1 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + SR 1.1 + SR 1.10 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.7 + SR 1.8 + SR 1.9 + A.18.1.4 + A.9.2.1 + A.9.2.2 + A.9.2.3 + A.9.2.4 + A.9.2.6 + A.9.3.1 + A.9.4.2 + A.9.4.3 + IA-11 + CM-6(a) + PR.AC-1 + PR.AC-7 + SRG-OS-000373-GPOS-00156 + SRG-OS-000373-GPOS-00157 + SRG-OS-000373-GPOS-00158 + OL09-00-002362 + SV-271724r1091884_rule + Without re-authentication, users may access resources or perform tasks for which they do not have authorization. - + + When operating systems provide the capability to escalate a functional capability, it -is critical that the user re-authenticate. - +is critical that the user re-authenticate. + for f in /etc/sudoers /etc/sudoers.d/* ; do if [ ! -e "$f" ] ; then continue @@ -9978,19 +11791,20 @@ for f in /etc/sudoers /etc/sudoers.d/* ; do if ! test -z "$matching_list"; then while IFS= read -r entry; do # comment out "!authenticate" matches to preserve user data - sed -i "s/^${entry}$/# &/g" $f + sed -i "s|^${entry}$|# &|g" $f done <<< "$matching_list" /usr/sbin/visudo -cf $f &> /dev/null || echo "Fail to validate $f with visudo" fi done - - - name: Find /etc/sudoers.d/ files - find: + + - name: Find /etc/sudoers.d/ files + ansible.builtin.find: paths: - /etc/sudoers.d/ register: sudoers tags: + - DISA-STIG-OL09-00-002362 - NIST-800-53-CM-6(a) - NIST-800-53-IA-11 - low_complexity @@ -10001,7 +11815,7 @@ done - sudo_remove_no_authenticate - name: Remove lines containing !authenticate from sudoers files - replace: + ansible.builtin.replace: regexp: (^(?!#).*[\s]+\!authenticate.*$) replace: '# \g<1>' path: '{{ item.path }}' @@ -10010,6 +11824,7 @@ done - path: /etc/sudoers - '{{ sudoers.files }}' tags: + - DISA-STIG-OL09-00-002362 - NIST-800-53-CM-6(a) - NIST-800-53-IA-11 - low_complexity @@ -10018,74 +11833,75 @@ done - no_reboot_needed - restrict_strategy - sudo_remove_no_authenticate - - - - - - - - - - Ensure Users Re-Authenticate for Privilege Escalation - sudo NOPASSWD - The sudo NOPASSWD tag, when specified, allows a user to execute + + + + + + + + + + Ensure Users Re-Authenticate for Privilege Escalation - sudo NOPASSWD + The sudo NOPASSWD tag, when specified, allows a user to execute commands using sudo without having to authenticate. This should be disabled by making sure that the NOPASSWD tag does not exist in /etc/sudoers configuration file or any sudo configuration snippets -in /etc/sudoers.d/. - BP28(R5) - BP28(R59) - 1 - 12 - 15 - 16 - 5 - DSS05.04 - DSS05.10 - DSS06.03 - DSS06.10 - CCI-002038 - 4.3.3.5.1 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - SR 1.1 - SR 1.10 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.7 - SR 1.8 - SR 1.9 - A.18.1.4 - A.9.2.1 - A.9.2.2 - A.9.2.3 - A.9.2.4 - A.9.2.6 - A.9.3.1 - A.9.4.2 - A.9.4.3 - IA-11 - CM-6(a) - PR.AC-1 - PR.AC-7 - SRG-OS-000373-GPOS-00156 - SRG-OS-000373-GPOS-00157 - SRG-OS-000373-GPOS-00158 - Without re-authentication, users may access resources or perform tasks for which they +in /etc/sudoers.d/. + 1 + 12 + 15 + 16 + 5 + DSS05.04 + DSS05.10 + DSS06.03 + DSS06.10 + CCI-004895 + 4.3.3.5.1 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + SR 1.1 + SR 1.10 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.7 + SR 1.8 + SR 1.9 + A.18.1.4 + A.9.2.1 + A.9.2.2 + A.9.2.3 + A.9.2.4 + A.9.2.6 + A.9.3.1 + A.9.4.2 + A.9.4.3 + IA-11 + CM-6(a) + PR.AC-1 + PR.AC-7 + SRG-OS-000373-GPOS-00156 + SRG-OS-000373-GPOS-00157 + SRG-OS-000373-GPOS-00158 + OL09-00-002363 + SV-271725r1091887_rule + Without re-authentication, users may access resources or perform tasks for which they do not have authorization. - + + When operating systems provide the capability to escalate a functional capability, it -is critical that the user re-authenticate. - +is critical that the user re-authenticate. + for f in /etc/sudoers /etc/sudoers.d/* ; do if [ ! -e "$f" ] ; then continue @@ -10094,19 +11910,20 @@ for f in /etc/sudoers /etc/sudoers.d/* ; do if ! test -z "$matching_list"; then while IFS= read -r entry; do # comment out "NOPASSWD" matches to preserve user data - sed -i "s/^${entry}$/# &/g" $f + sed -i "s|^${entry}$|# &|g" $f done <<< "$matching_list" /usr/sbin/visudo -cf $f &> /dev/null || echo "Fail to validate $f with visudo" fi done - - - name: Find /etc/sudoers.d/ files - find: + + - name: Find /etc/sudoers.d/ files + ansible.builtin.find: paths: - /etc/sudoers.d/ register: sudoers tags: + - DISA-STIG-OL09-00-002363 - NIST-800-53-CM-6(a) - NIST-800-53-IA-11 - low_complexity @@ -10117,7 +11934,7 @@ done - sudo_remove_nopasswd - name: Remove lines containing NOPASSWD from sudoers files - replace: + ansible.builtin.replace: regexp: (^(?!#).*[\s]+NOPASSWD[\s]*\:.*$) replace: '# \g<1>' path: '{{ item.path }}' @@ -10126,6 +11943,7 @@ done - path: /etc/sudoers - '{{ sudoers.files }}' tags: + - DISA-STIG-OL09-00-002363 - NIST-800-53-CM-6(a) - NIST-800-53-IA-11 - low_complexity @@ -10134,71 +11952,76 @@ done - no_reboot_needed - restrict_strategy - sudo_remove_nopasswd - - - - - - - - - - Ensure Users Re-Authenticate for Privilege Escalation - sudo - The sudo NOPASSWD and !authenticate option, when + + + + + + + + + + Ensure Users Re-Authenticate for Privilege Escalation - sudo + The sudo NOPASSWD and !authenticate option, when specified, allows a user to execute commands using sudo without having to authenticate. This should be disabled by making sure that NOPASSWD and/or !authenticate do not exist in /etc/sudoers configuration file or any sudo configuration snippets -in /etc/sudoers.d/." - 1 - 12 - 15 - 16 - 5 - DSS05.04 - DSS05.10 - DSS06.03 - DSS06.10 - CCI-002038 - 4.3.3.5.1 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - SR 1.1 - SR 1.10 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.7 - SR 1.8 - SR 1.9 - A.18.1.4 - A.9.2.1 - A.9.2.2 - A.9.2.3 - A.9.2.4 - A.9.2.6 - A.9.3.1 - A.9.4.2 - A.9.4.3 - IA-11 - CM-6(a) - PR.AC-1 - PR.AC-7 - SRG-OS-000373-GPOS-00156 - Without re-authentication, users may access resources or perform tasks for which they +in /etc/sudoers.d/." + 1 + 12 + 15 + 16 + 5 + DSS05.04 + DSS05.10 + DSS06.03 + DSS06.10 + CCI-002038 + CCI-004895 + 4.3.3.5.1 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + SR 1.1 + SR 1.10 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.7 + SR 1.8 + SR 1.9 + A.18.1.4 + A.9.2.1 + A.9.2.2 + A.9.2.3 + A.9.2.4 + A.9.2.6 + A.9.3.1 + A.9.4.2 + A.9.4.3 + IA-11 + CM-6(a) + PR.AC-1 + PR.AC-7 + SRG-OS-000373-GPOS-00156 + A.5.SEC-OL2 + 2.2.6 + 2.2 + Without re-authentication, users may access resources or perform tasks for which they do not have authorization. - + + When operating systems provide the capability to escalate a functional capability, it -is critical that the user re-authenticate. - +is critical that the user re-authenticate. + for f in /etc/sudoers /etc/sudoers.d/* ; do if [ ! -e "$f" ] ; then continue @@ -10207,7 +12030,7 @@ for f in /etc/sudoers /etc/sudoers.d/* ; do if ! test -z "$matching_list"; then while IFS= read -r entry; do # comment out "NOPASSWD" matches to preserve user data - sed -i "s/^${entry}$/# &/g" $f + sed -i "s|^${entry}$|# &|g" $f done <<< "$matching_list" /usr/sbin/visudo -cf $f &> /dev/null || echo "Fail to validate $f with visudo" @@ -10222,21 +12045,23 @@ for f in /etc/sudoers /etc/sudoers.d/* ; do if ! test -z "$matching_list"; then while IFS= read -r entry; do # comment out "!authenticate" matches to preserve user data - sed -i "s/^${entry}$/# &/g" $f + sed -i "s|^${entry}$|# &|g" $f done <<< "$matching_list" /usr/sbin/visudo -cf $f &> /dev/null || echo "Fail to validate $f with visudo" fi done - - - name: Find /etc/sudoers.d/ files - find: + + - name: Find /etc/sudoers.d/ files + ansible.builtin.find: paths: - /etc/sudoers.d/ register: sudoers tags: - NIST-800-53-CM-6(a) - NIST-800-53-IA-11 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 - low_complexity - low_disruption - medium_severity @@ -10245,7 +12070,7 @@ done - sudo_require_authentication - name: Remove lines containing NOPASSWD from sudoers files - replace: + ansible.builtin.replace: regexp: (^(?!#).*[\s]+NOPASSWD[\s]*\:.*$) replace: '# \g<1>' path: '{{ item.path }}' @@ -10256,6 +12081,8 @@ done tags: - NIST-800-53-CM-6(a) - NIST-800-53-IA-11 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 - low_complexity - low_disruption - medium_severity @@ -10264,13 +12091,15 @@ done - sudo_require_authentication - name: Find /etc/sudoers.d/ files - find: + ansible.builtin.find: paths: - /etc/sudoers.d/ register: sudoers tags: - NIST-800-53-CM-6(a) - NIST-800-53-IA-11 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 - low_complexity - low_disruption - medium_severity @@ -10279,7 +12108,7 @@ done - sudo_require_authentication - name: Remove lines containing !authenticate from sudoers files - replace: + ansible.builtin.replace: regexp: (^(?!#).*[\s]+\!authenticate.*$) replace: '# \g<1>' path: '{{ item.path }}' @@ -10290,45 +12119,53 @@ done tags: - NIST-800-53-CM-6(a) - NIST-800-53-IA-11 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 - low_complexity - low_disruption - medium_severity - no_reboot_needed - restrict_strategy - sudo_require_authentication - - - - - - - - - - Require Re-Authentication When Using the sudo Command - The sudo timestamp_timeout tag sets the amount of time sudo password prompt waits. + + + + + + + + + + Require Re-Authentication When Using the sudo Command + The sudo timestamp_timeout tag sets the amount of time sudo password prompt waits. The default timestamp_timeout value is 5 minutes. The timestamp_timeout should be configured by making sure that the timestamp_timeout tag exists in /etc/sudoers configuration file or any sudo configuration snippets in /etc/sudoers.d/. If the value is set to an integer less than 0, the user's time stamp will not expire -and the user will not have to re-authenticate for privileged actions until the user's session is terminated. - CCI-002038 - IA-11 - SRG-OS-000373-GPOS-00156 - SRG-OS-000373-GPOS-00157 - SRG-OS-000373-GPOS-00158 - Without re-authentication, users may access resources or perform tasks for which they +and the user will not have to re-authenticate for privileged actions until the user's session is terminated. + CCI-004895 + IA-11 + SRG-OS-000373-GPOS-00156 + SRG-OS-000373-GPOS-00157 + SRG-OS-000373-GPOS-00158 + A.5.SEC-OL2 + 2.2.6 + 2.2 + OL09-00-002360 + SV-271722r1091878_rule + Without re-authentication, users may access resources or perform tasks for which they do not have authorization. - + + When operating systems provide the capability to escalate a functional capability, it -is critical that the user re-authenticate. - - # Remediation is applicable only in certain platforms +is critical that the user re-authenticate. + + # Remediation is applicable only in certain platforms if rpm --quiet -q sudo; then -var_sudo_timestamp_timeout='' +var_sudo_timestamp_timeout='' if grep -Px '^[\s]*Defaults.*timestamp_timeout[\s]*=.*' /etc/sudoers.d/*; then @@ -10341,9 +12178,8 @@ if /usr/sbin/visudo -qcf /etc/sudoers; then # sudoers file doesn't define Option timestamp_timeout echo "Defaults timestamp_timeout=${var_sudo_timestamp_timeout}" >> /etc/sudoers else - # sudoers file defines Option timestamp_timeout, remediate if appropriate value is not set - if ! grep -P "^[\s]*Defaults.*timestamp_timeout[\s]*=[\s]*${var_sudo_timestamp_timeout}.*$" /etc/sudoers; then - + # sudoers file defines Option timestamp_timeout, remediate wrong values if present + if grep -qP "^[\s]*Defaults\s.*\btimestamp_timeout[\s]*=[\s]*(?!${var_sudo_timestamp_timeout}\b)[-]?\w+\b.*$" /etc/sudoers; then sed -Ei "s/(^[[:blank:]]*Defaults.*timestamp_timeout[[:blank:]]*=)[[:blank:]]*[-]?\w+(.*$)/\1${var_sudo_timestamp_timeout}\2/" /etc/sudoers fi fi @@ -10364,12 +12200,15 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-002360 - NIST-800-53-IA-11 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 - low_complexity - low_disruption - medium_severity @@ -10378,20 +12217,23 @@ fi - sudo_require_reauthentication - name: XCCDF Value var_sudo_timestamp_timeout # promote to variable set_fact: - var_sudo_timestamp_timeout: !!str + var_sudo_timestamp_timeout: !!str tags: - always -- name: Find out if /etc/sudoers.d/* files contain 'Defaults timestamp_timeout' to - be deduplicated - find: +- name: Require Re-Authentication When Using the sudo Command - Find /etc/sudoers.d/* + files containing 'Defaults timestamp_timeout' + ansible.builtin.find: path: /etc/sudoers.d patterns: '*' contains: ^[\s]*Defaults\s.*\btimestamp_timeout[\s]*=.* register: sudoers_d_defaults_timestamp_timeout when: '"sudo" in ansible_facts.packages' tags: + - DISA-STIG-OL09-00-002360 - NIST-800-53-IA-11 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 - low_complexity - low_disruption - medium_severity @@ -10399,16 +12241,19 @@ fi - restrict_strategy - sudo_require_reauthentication -- name: Remove found occurrences of 'Defaults timestamp_timeout' from /etc/sudoers.d/* - files - lineinfile: +- name: Require Re-Authentication When Using the sudo Command - Remove 'Defaults timestamp_timeout' + from /etc/sudoers.d/* files + ansible.builtin.lineinfile: path: '{{ item.path }}' regexp: ^[\s]*Defaults\s.*\btimestamp_timeout[\s]*=.* state: absent with_items: '{{ sudoers_d_defaults_timestamp_timeout.files }}' when: '"sudo" in ansible_facts.packages' tags: + - DISA-STIG-OL09-00-002360 - NIST-800-53-IA-11 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 - low_complexity - low_disruption - medium_severity @@ -10416,8 +12261,9 @@ fi - restrict_strategy - sudo_require_reauthentication -- name: Ensure timestamp_timeout is enabled with the appropriate value in /etc/sudoers - lineinfile: +- name: Require Re-Authentication When Using the sudo Command - Ensure timestamp_timeout + has the appropriate value in /etc/sudoers + ansible.builtin.lineinfile: path: /etc/sudoers regexp: ^[\s]*Defaults\s(.*)\btimestamp_timeout[\s]*=[\s]*[-]?\w+\b(.*)$ line: Defaults \1timestamp_timeout={{ var_sudo_timestamp_timeout }}\2 @@ -10426,7 +12272,10 @@ fi register: edit_sudoers_timestamp_timeout_option when: '"sudo" in ansible_facts.packages' tags: + - DISA-STIG-OL09-00-002360 - NIST-800-53-IA-11 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 - low_complexity - low_disruption - medium_severity @@ -10434,78 +12283,108 @@ fi - restrict_strategy - sudo_require_reauthentication -- name: Enable timestamp_timeout option with appropriate value in /etc/sudoers - lineinfile: +- name: Require Re-Authentication When Using the sudo Command - Enable timestamp_timeout + option with correct value in /etc/sudoers + ansible.builtin.lineinfile: path: /etc/sudoers line: Defaults timestamp_timeout={{ var_sudo_timestamp_timeout }} validate: /usr/sbin/visudo -cf %s when: - '"sudo" in ansible_facts.packages' - - edit_sudoers_timestamp_timeout_option is defined and not edit_sudoers_timestamp_timeout_option.changed + - | + edit_sudoers_timestamp_timeout_option is defined and not edit_sudoers_timestamp_timeout_option.changed tags: + - DISA-STIG-OL09-00-002360 - NIST-800-53-IA-11 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 - low_complexity - low_disruption - medium_severity - no_reboot_needed - restrict_strategy - sudo_require_reauthentication - - - - - - - - - - The operating system must restrict privilege elevation to authorized personnel - The sudo command allows a user to execute programs with elevated + +- name: Require Re-Authentication When Using the sudo Command - Remove timestamp_timeout + wrong values in /etc/sudoers + ansible.builtin.lineinfile: + path: /etc/sudoers + regexp: ^[\s]*Defaults\s.*\btimestamp_timeout[\s]*=[\s]*(?!{{ var_sudo_timestamp_timeout + }}\b)[-]?\w+\b.*$ + state: absent + validate: /usr/sbin/visudo -cf %s + when: '"sudo" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-002360 + - NIST-800-53-IA-11 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sudo_require_reauthentication + + + + + + + + + + The operating system must restrict privilege elevation to authorized personnel + The sudo command allows a user to execute programs with elevated (administrator) privileges. It prompts the user for their password and confirms your request to execute a command by checking a file, called sudoers. Restrict privileged actions by removing the following entries from the sudoers file: ALL ALL=(ALL) ALL -ALL ALL=(ALL:ALL) ALL - This rule doesn't come with a remediation, as the exact requirement allows exceptions, -and removing lines from the sudoers file can make the system non-administrable. - CCI-000366 - CM-6(b) - CM-6(iv) - SRG-OS-000480-GPOS-00227 - If the "sudoers" file is not configured correctly, any user defined -on the system can initiate privileged actions on the target system. - - - - - - - - - - Only the VDSM User Can Use sudo NOPASSWD - The sudo NOPASSWD tag, when specified, allows a user to execute commands using sudo without having to authenticate. Only the vdsm user should have this capability in any sudo configuration snippets in /etc/sudoers.d/. - Without re-authentication, users may access resources or perform tasks for which they + ALL ALL=(ALL:ALL) ALL + + This rule doesn't come with a remediation, as the exact requirement allows exceptions, +and removing lines from the sudoers file can make the system non-administrable. + CCI-000366 + CM-6(b) + CM-6(iv) + SRG-OS-000480-GPOS-00227 + OL09-00-000232 + SV-271476r1091140_rule + If the "sudoers" file is not configured correctly, any user defined +on the system can initiate privileged actions on the target system. + + + + + + + + + + Only the VDSM User Can Use sudo NOPASSWD + The sudo NOPASSWD tag, when specified, allows a user to execute commands using sudo without having to authenticate. Only the vdsm user should have this capability in any sudo configuration snippets in /etc/sudoers.d/. + Without re-authentication, users may access resources or perform tasks for which they do not have authorization. - + + When operating systems provide the capability to escalate a functional capability, it -is critical that the user re-authenticate. - - - - - - - - - Explicit arguments in sudo specifications - All commands in the sudoers file must strictly specify the arguments allowed to be used for a given user. -If the command is supposed to be executed only without arguments, pass "" as an argument in the corresponding user specification. - This rule doesn't come with a remediation, as absence of arguments in the user spec doesn't mean that the command is intended to be executed with no arguments. - The rule can produce false findings when an argument contains a comma - sudoers syntax allows comma escaping using backslash, but the check doesn't support that. For example, root ALL=(ALL) echo 1\,2 allows root to execute echo 1,2, but the check would interpret it as two commands echo 1\ and 2. - BP28(R63) - Any argument can modify quite significantly the behavior of a program, whether regarding the +is critical that the user re-authenticate. + + + + + + + + + Explicit arguments in sudo specifications + All commands in the sudoers file must strictly specify the arguments allowed to be used for a given user. +If the command is supposed to be executed only without arguments, pass "" as an argument in the corresponding user specification. + This rule doesn't come with a remediation, as absence of arguments in the user spec doesn't mean that the command is intended to be executed with no arguments. + The rule can produce false findings when an argument contains a comma - sudoers syntax allows comma escaping using backslash, but the check doesn't support that. For example, root ALL=(ALL) echo 1\,2 allows root to execute echo 1,2, but the check would interpret it as two commands echo 1\ and 2. + R43 + Any argument can modify quite significantly the behavior of a program, whether regarding the realized operation (read, write, delete, etc.) or accessed resources (path in a file system tree). To avoid any possibility of misuse of a command by a user, the ambiguities must be removed at the level of its specification. @@ -10515,79 +12394,83 @@ If a user nevertheless must have the privileges to read them, the argument of th in order to prevent the user from flushing the buffer through the -c option: user ALL = dmesg "" - - - - - - - - - - - Don't define allowed commands in sudoers by means of exclusion - Policies applied by sudo through the sudoers file should not involve negation. + + + + + + + + + + + + Don't define allowed commands in sudoers by means of exclusion + Policies applied by sudo through the sudoers file should not involve negation. Each user specification in the sudoers file contains a comma-delimited list of command specifications. The definition can make use glob patterns, as well as of negations. -Indirect definition of those commands by means of exclusion of a set of commands is trivial to bypass, so it is not allowed to use such constructs. - This rule doesn't come with a remediation, as negations indicate design issues with the sudoers user specifications design. Just removing negations doesn't increase the security - you typically have to rethink the definition of allowed commands to fix the issue. - BP28(R61) - Specifying access right using negation is inefficient and can be easily circumvented. +Indirect definition of those commands by means of exclusion of a set of commands is trivial to bypass, so it is not allowed to use such constructs. + This rule doesn't come with a remediation, as negations indicate design issues with the sudoers user specifications design. Just removing negations doesn't increase the security - you typically have to rethink the definition of allowed commands to fix the issue. + R42 + Specifying access right using negation is inefficient and can be easily circumvented. For example, it is expected that a specification like # To avoid absolutely , this rule can be easily circumvented! user ALL = ALL ,!/ bin/sh prevents the execution of the shell but that’s not the case: just copy the binary /bin/sh to a different name to make it executable -again through the rule keyword ALL. - - - - - - - - - - Don't target root user in the sudoers file - The targeted users of a user specification should be, as much as possible, non privileged users (i.e.: non-root). +again through the rule keyword ALL. + + + + + + + + + + Don't target root user in the sudoers file + The targeted users of a user specification should be, as much as possible, non privileged users (i.e.: non-root). -User specifications have to explicitly list the runas spec (i.e. the list of target users that can be impersonated), and ALL or root should not be used. - This rule doesn't come with a remediation, as the exact requirement allows exceptions, and removing lines from the sudoers file can make the system non-administrable. - It is common that the command to be executed does not require superuser rights (editing a file +User specifications have to explicitly list the runas spec (i.e. the list of target users that can be impersonated), and ALL or root should not be used. + This rule doesn't come with a remediation, as the exact requirement allows exceptions, and removing lines from the sudoers file can make the system non-administrable. + R40 + It is common that the command to be executed does not require superuser rights (editing a file whose the owner is not root, sending a signal to an unprivileged process,etc.). In order to limit -any attempt of privilege escalation through a command, it is better to apply normal user rights. - - - - - - - - - - Ensure invoking users password for privilege escalation when using sudo - The sudoers security policy requires that users authenticate themselves before they can use sudo. +any attempt of privilege escalation through a command, it is better to apply normal user rights. + + + + + + + + + + Ensure invoking users password for privilege escalation when using sudo + The sudoers security policy requires that users authenticate themselves before they can use sudo. When sudoers requires authentication, it validates the invoking user's credentials. The expected output for: sudo cvtsudoers -f sudoers /etc/sudoers | grep -E '^Defaults !?(rootpw|targetpw|runaspw)$' - Defaults !targetpw + Defaults !targetpw Defaults !rootpw Defaults !runaspw or if cvtsudoers not supported: sudo find /etc/sudoers /etc/sudoers.d \( \! -name '*~' -a \! -name '*.*' \) -exec grep -E --with-filename '^[[:blank:]]*Defaults[[:blank:]](.*[[:blank:]])?!?\b(rootpw|targetpw|runaspw)' -- {} \; - /etc/sudoers:Defaults !targetpw + /etc/sudoers:Defaults !targetpw /etc/sudoers:Defaults !rootpw - /etc/sudoers:Defaults !runaspw - CCI-000366 - CCI-002227 - CM-6(b) - CM-6.1(iv) - SRG-OS-000480-GPOS-00227 - If the rootpw, targetpw, or runaspw flags are defined and not disabled, by default the operating system will prompt -the invoking user for the "root" user password. - - # Remediation is applicable only in certain platforms + /etc/sudoers:Defaults !runaspw + + CCI-000366 + CM-6(b) + CM-6.1(iv) + SRG-OS-000480-GPOS-00227 + OL09-00-000231 + SV-271475r1091137_rule + If the rootpw, targetpw, or runaspw flags are defined and not disabled, by default the operating system will prompt +the invoking user for the "root" user password. + + # Remediation is applicable only in certain platforms if rpm --quiet -q sudo; then if grep -x '^Defaults targetpw$' /etc/sudoers; then @@ -10655,11 +12538,12 @@ rm "/etc/sudoers.bak" else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-000231 - NIST-800-53-CM-6(b) - NIST-800-53-CM-6.1(iv) - low_complexity @@ -10677,6 +12561,7 @@ fi register: sudoers_d_defaults when: '"sudo" in ansible_facts.packages' tags: + - DISA-STIG-OL09-00-000231 - NIST-800-53-CM-6(b) - NIST-800-53-CM-6.1(iv) - low_complexity @@ -10694,6 +12579,7 @@ fi with_items: '{{ sudoers_d_defaults.files }}' when: '"sudo" in ansible_facts.packages' tags: + - DISA-STIG-OL09-00-000231 - NIST-800-53-CM-6(b) - NIST-800-53-CM-6.1(iv) - low_complexity @@ -10711,6 +12597,7 @@ fi register: sudoers_d_defaults when: '"sudo" in ansible_facts.packages' tags: + - DISA-STIG-OL09-00-000231 - NIST-800-53-CM-6(b) - NIST-800-53-CM-6.1(iv) - low_complexity @@ -10728,6 +12615,7 @@ fi with_items: '{{ sudoers_d_defaults.files }}' when: '"sudo" in ansible_facts.packages' tags: + - DISA-STIG-OL09-00-000231 - NIST-800-53-CM-6(b) - NIST-800-53-CM-6.1(iv) - low_complexity @@ -10745,6 +12633,7 @@ fi register: sudoers_d_defaults when: '"sudo" in ansible_facts.packages' tags: + - DISA-STIG-OL09-00-000231 - NIST-800-53-CM-6(b) - NIST-800-53-CM-6.1(iv) - low_complexity @@ -10762,6 +12651,7 @@ fi with_items: '{{ sudoers_d_defaults.files }}' when: '"sudo" in ansible_facts.packages' tags: + - DISA-STIG-OL09-00-000231 - NIST-800-53-CM-6(b) - NIST-800-53-CM-6.1(iv) - low_complexity @@ -10780,6 +12670,7 @@ fi register: sudoers_file_defaults when: '"sudo" in ansible_facts.packages' tags: + - DISA-STIG-OL09-00-000231 - NIST-800-53-CM-6(b) - NIST-800-53-CM-6.1(iv) - low_complexity @@ -10798,6 +12689,7 @@ fi register: sudoers_file_defaults when: '"sudo" in ansible_facts.packages' tags: + - DISA-STIG-OL09-00-000231 - NIST-800-53-CM-6(b) - NIST-800-53-CM-6.1(iv) - low_complexity @@ -10816,6 +12708,7 @@ fi register: sudoers_file_defaults when: '"sudo" in ansible_facts.packages' tags: + - DISA-STIG-OL09-00-000231 - NIST-800-53-CM-6(b) - NIST-800-53-CM-6.1(iv) - low_complexity @@ -10836,6 +12729,7 @@ fi register: dupes when: '"sudo" in ansible_facts.packages' tags: + - DISA-STIG-OL09-00-000231 - NIST-800-53-CM-6(b) - NIST-800-53-CM-6.1(iv) - low_complexity @@ -10855,6 +12749,7 @@ fi - '"sudo" in ansible_facts.packages' - dupes.found is defined and dupes.found > 1 tags: + - DISA-STIG-OL09-00-000231 - NIST-800-53-CM-6(b) - NIST-800-53-CM-6.1(iv) - low_complexity @@ -10873,6 +12768,7 @@ fi state: present when: '"sudo" in ansible_facts.packages' tags: + - DISA-STIG-OL09-00-000231 - NIST-800-53-CM-6(b) - NIST-800-53-CM-6.1(iv) - low_complexity @@ -10893,6 +12789,7 @@ fi register: dupes when: '"sudo" in ansible_facts.packages' tags: + - DISA-STIG-OL09-00-000231 - NIST-800-53-CM-6(b) - NIST-800-53-CM-6.1(iv) - low_complexity @@ -10912,6 +12809,7 @@ fi - '"sudo" in ansible_facts.packages' - dupes.found is defined and dupes.found > 1 tags: + - DISA-STIG-OL09-00-000231 - NIST-800-53-CM-6(b) - NIST-800-53-CM-6.1(iv) - low_complexity @@ -10930,6 +12828,7 @@ fi state: present when: '"sudo" in ansible_facts.packages' tags: + - DISA-STIG-OL09-00-000231 - NIST-800-53-CM-6(b) - NIST-800-53-CM-6.1(iv) - low_complexity @@ -10950,6 +12849,7 @@ fi register: dupes when: '"sudo" in ansible_facts.packages' tags: + - DISA-STIG-OL09-00-000231 - NIST-800-53-CM-6(b) - NIST-800-53-CM-6.1(iv) - low_complexity @@ -10969,6 +12869,7 @@ fi - '"sudo" in ansible_facts.packages' - dupes.found is defined and dupes.found > 1 tags: + - DISA-STIG-OL09-00-000231 - NIST-800-53-CM-6(b) - NIST-800-53-CM-6.1(iv) - low_complexity @@ -10987,6 +12888,7 @@ fi state: present when: '"sudo" in ansible_facts.packages' tags: + - DISA-STIG-OL09-00-000231 - NIST-800-53-CM-6(b) - NIST-800-53-CM-6.1(iv) - low_complexity @@ -10995,144 +12897,215 @@ fi - no_reboot_needed - restrict_strategy - sudoers_validate_passwd - - - - - - - - - - - System Tooling / Utilities - The following checks evaluate the system for recommended base packages -- both for installation -and removal. - - Ensure gnutls-utils is installed - The gnutls-utils package can be installed with the following command: + + + + + + + + + + + System Tooling / Utilities + The following checks evaluate the system for recommended base packages -- both for installation +and removal. + + Install cryptsetup Package + The cryptsetup package can be installed with the following command: -$ sudo yum install gnutls-utils - FIA_X509_EXT.1 - FIA_X509_EXT.2 - SRG-OS-000480-GPOS-00227 - GnuTLS is a secure communications library implementing the SSL, TLS and DTLS +$ sudo yum install cryptsetup + + A.25.SEC-OL1 + 3.5.1.2 + 3.5.1 + 3.5 + LUKS is the upcoming standard for Linux hard disk encryption. By providing a standard +on-disk format, it does not only facilitate compatibility among distributions, but also +provide secure management of multiple user passwords. In contrast to existing solution, +LUKS stores all necessary setup information in the partition header, enabling the user +to transport or migrate their data seamlessly. LUKS for dm-crypt is implemented in +cryptsetup. + +if ! rpm -q --quiet "cryptsetup" ; then + yum install -y "cryptsetup" +fi + + - name: Ensure cryptsetup is installed + package: + name: cryptsetup + state: present + tags: + - PCI-DSSv4-3.5 + - PCI-DSSv4-3.5.1 + - PCI-DSSv4-3.5.1.2 + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - package_cryptsetup-luks_installed + + include install_cryptsetup + +class install_cryptsetup { + package { 'cryptsetup': + ensure => 'installed', + } +} + + +package --add=cryptsetup + + +[[packages]] +name = "cryptsetup" +version = "*" + + + + + + + + + + Ensure gnutls-utils is installed + The gnutls-utils package can be installed with the following command: + +$ sudo yum install gnutls-utils + + CCI-000366 + FIA_X509_EXT.1 + FIA_X509_EXT.1.1 + FIA_X509_EXT.2 + SRG-OS-000480-GPOS-00227 + OL09-00-000430 + SV-271518r1091266_rule + GnuTLS is a secure communications library implementing the SSL, TLS and DTLS protocols and technologies around them. It provides a simple C language application programming interface (API) to access the secure communications protocols as well as APIs to parse and write X.509, PKCS #12, OpenPGP and other required structures. This package contains command line TLS client and server and certificate -manipulation tools. - +manipulation tools. + if ! rpm -q --quiet "gnutls-utils" ; then yum install -y "gnutls-utils" fi - - - name: Ensure gnutls-utils is installed + + - name: Ensure gnutls-utils is installed package: name: gnutls-utils state: present tags: + - DISA-STIG-OL09-00-000430 - enable_strategy - low_complexity - low_disruption - medium_severity - no_reboot_needed - package_gnutls-utils_installed - - include install_gnutls-utils + + include install_gnutls-utils class install_gnutls-utils { package { 'gnutls-utils': ensure => 'installed', } } - - + + package --add=gnutls-utils - - + + [[packages]] name = "gnutls-utils" version = "*" - - - - - - - - - - Ensure nss-tools is installed - The nss-tools package can be installed with the following command: + + + + + + + + + + Ensure nss-tools is installed + The nss-tools package can be installed with the following command: -$ sudo yum install nss-tools - FMT_SMF_EXT.1 - SRG-OS-000480-GPOS-00227 - Network Security Services (NSS) is a set of libraries designed to +$ sudo yum install nss-tools + + CCI-000366 + FMT_SMF_EXT.1 + SRG-OS-000480-GPOS-00227 + OL09-00-000380 + SV-271513r1091251_rule + Network Security Services (NSS) is a set of libraries designed to support cross-platform development of security-enabled client and server applications. Install the nss-tools package to install command-line tools to manipulate the NSS certificate -and key database. - +and key database. + if ! rpm -q --quiet "nss-tools" ; then yum install -y "nss-tools" fi - - - name: Ensure nss-tools is installed + + - name: Ensure nss-tools is installed package: name: nss-tools state: present tags: + - DISA-STIG-OL09-00-000380 - enable_strategy - low_complexity - low_disruption - medium_severity - no_reboot_needed - package_nss-tools_installed - - include install_nss-tools + + include install_nss-tools class install_nss-tools { package { 'nss-tools': ensure => 'installed', } } - - + + package --add=nss-tools - - + + [[packages]] name = "nss-tools" version = "*" - - - - - - - - - - Install openscap-scanner Package - The openscap-scanner package can be installed with the following command: + + + + + + + + + + Install openscap-scanner Package + The openscap-scanner package can be installed with the following command: -$ sudo yum install openscap-scanner - AGD_PRE.1 - AGD_OPE.1 - SRG-OS-000480-GPOS-00227 - SRG-OS-000191-GPOS-00080 - openscap-scanner contains the oscap command line tool. This tool is a +$ sudo yum install openscap-scanner + + AGD_PRE.1 + AGD_OPE.1 + SRG-OS-000480-GPOS-00227 + SRG-OS-000191-GPOS-00080 + openscap-scanner contains the oscap command line tool. This tool is a configuration and vulnerability scanner, capable of performing compliance checking using -SCAP content. - +SCAP content. + if ! rpm -q --quiet "openscap-scanner" ; then yum install -y "openscap-scanner" fi - - - name: Ensure openscap-scanner is installed + + - name: Ensure openscap-scanner is installed package: name: openscap-scanner state: present @@ -11143,40 +13116,41 @@ fi - medium_severity - no_reboot_needed - package_openscap-scanner_installed - - include install_openscap-scanner + + include install_openscap-scanner class install_openscap-scanner { package { 'openscap-scanner': ensure => 'installed', } } - - + + package --add=openscap-scanner - - + + [[packages]] name = "openscap-scanner" version = "*" - - - - - - - - - - Install rear Package - The rear package can be installed with the following command: + + + + + + + + + + Install rear Package + The rear package can be installed with the following command: -$ sudo yum install rear - rear contains the Relax-and-Recover (ReaR) utility. ReaR produces a bootable -image of a system and restores from backup using this image. - - # Remediation is applicable only in certain platforms -if ! ( ( ( grep -q aarch64 /proc/sys/kernel/osrelease && grep -qP "^ID=[\"']?ol[\"']?$" "/etc/os-release" && { real="$(grep -P "^VERSION_ID=[\"']?[\w.]+[\"']?$" /etc/os-release | sed "s/^VERSION_ID=[\"']\?\([^\"']\+\)[\"']\?$/\1/")"; expected="9.0"; printf "%s\n%s" "$expected" "$real" | sort -VC; } ) || ( grep -q aarch64 /proc/sys/kernel/osrelease && grep -qP "^ID=[\"']?rhel[\"']?$" "/etc/os-release" && { real="$(grep -P "^VERSION_ID=[\"']?[\w.]+[\"']?$" /etc/os-release | sed "s/^VERSION_ID=[\"']\?\([^\"']\+\)[\"']\?$/\1/")"; expected="9.0"; printf "%s\n%s" "$expected" "$real" | sort -VC; } ) || ( grep -qP "^ID=[\"']?rhel[\"']?$" "/etc/os-release" && { real="$(grep -P "^VERSION_ID=[\"']?[\w.]+[\"']?$" /etc/os-release | sed "s/^VERSION_ID=[\"']\?\([^\"']\+\)[\"']\?$/\1/")"; expected="8.4"; printf "%s\n%s" "$real" "$expected" | sort -VC; } && grep -q s390x /proc/sys/kernel/osrelease ) ) ); then +$ sudo yum install rear + + rear contains the Relax-and-Recover (ReaR) utility. ReaR produces a bootable +image of a system and restores from backup using this image. + + # Remediation is applicable only in certain platforms +if ! ( ( ( ( grep -sqE "^.*\.aarch64$" /proc/sys/kernel/osrelease || grep -sqE "^aarch64$" /proc/sys/kernel/arch; ) && grep -qP "^ID=[\"']?ol[\"']?$" "/etc/os-release" && { real="$(grep -P "^VERSION_ID=[\"']?[\w.]+[\"']?$" /etc/os-release | sed "s/^VERSION_ID=[\"']\?\([^\"']\+\)[\"']\?$/\1/")"; expected="9.0"; printf "%s\n%s" "$expected" "$real" | sort -VC; } ) || ( ( grep -sqE "^.*\.aarch64$" /proc/sys/kernel/osrelease || grep -sqE "^aarch64$" /proc/sys/kernel/arch; ) && grep -qP "^ID=[\"']?rhel[\"']?$" "/etc/os-release" && { real="$(grep -P "^VERSION_ID=[\"']?[\w.]+[\"']?$" /etc/os-release | sed "s/^VERSION_ID=[\"']\?\([^\"']\+\)[\"']\?$/\1/")"; expected="9.0"; printf "%s\n%s" "$expected" "$real" | sort -VC; } ) || ( grep -qP "^ID=[\"']?rhel[\"']?$" "/etc/os-release" && { real="$(grep -P "^VERSION_ID=[\"']?[\w.]+[\"']?$" /etc/os-release | sed "s/^VERSION_ID=[\"']\?\([^\"']\+\)[\"']\?$/\1/")"; expected="8.4"; printf "%s\n%s" "$real" "$expected" | sort -VC; } && ( grep -sqE "^.*\.s390x$" /proc/sys/kernel/osrelease || grep -sqE "^s390x$" /proc/sys/kernel/arch; ) ) ) ); then if ! rpm -q --quiet "rear" ; then yum install -y "rear" @@ -11185,8 +13159,8 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Ensure rear is installed + + - name: Ensure rear is installed package: name: rear state: present @@ -11202,42 +13176,45 @@ fi - medium_severity - no_reboot_needed - package_rear_installed - - include install_rear + + include install_rear class install_rear { package { 'rear': ensure => 'installed', } } - - + + package --add=rear - - + + [[packages]] name = "rear" version = "*" - - - - - - - - - - Install rng-tools Package - The rng-tools package can be installed with the following command: + + + + + + + + + + Install rng-tools Package + The rng-tools package can be installed with the following command: -$ sudo yum install rng-tools - CCI-000366 - SRG-OS-000480-GPOS-00227 - rng-tools provides hardware random number generator tools, -such as those used in the formation of x509/PKI certificates. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then +$ sudo yum install rng-tools + + CCI-000366 + SRG-OS-000480-GPOS-00227 + OL09-00-000370 + SV-271512r1091248_rule + rng-tools provides hardware random number generator tools, +such as those used in the formation of x509/PKI certificates. + + # Remediation is applicable only in certain platforms +if ( ! ( [ "$(sysctl -a | grep -c 'fips_enabled.*1')" -eq 1 ] ) && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ); then if ! rpm -q --quiet "rng-tools" ; then yum install -y "rng-tools" @@ -11246,52 +13223,67 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Ensure rng-tools is installed - package: - name: rng-tools - state: present - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + + - name: Gather the package facts + package_facts: + manager: auto tags: + - DISA-STIG-OL09-00-000370 - enable_strategy - low_complexity - low_disruption - low_severity - no_reboot_needed - package_rng-tools_installed - - include install_rng-tools + +- name: Ensure rng-tools is installed + package: + name: rng-tools + state: present + when: ( ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + ) + tags: + - DISA-STIG-OL09-00-000370 + - enable_strategy + - low_complexity + - low_disruption + - low_severity + - no_reboot_needed + - package_rng-tools_installed + + include install_rng-tools class install_rng-tools { package { 'rng-tools': ensure => 'installed', } } - - + + package --add=rng-tools - - + + [[packages]] name = "rng-tools" version = "*" - - - - - - - - - - Install scap-security-guide Package - The scap-security-guide package can be installed with the following command: + + + + + + + + + + Install scap-security-guide Package + The scap-security-guide package can be installed with the following command: -$ sudo yum install scap-security-guide - AGD_PRE.1 - AGD_OPE.1 - SRG-OS-000480-GPOS-00227 - The scap-security-guide package provides a guide for configuration of the system +$ sudo yum install scap-security-guide + + AGD_PRE.1 + AGD_OPE.1 + SRG-OS-000480-GPOS-00227 + The scap-security-guide package provides a guide for configuration of the system from the final system's security point of view. The guidance is specified in the Security Content Automation Protocol (SCAP) format and constitutes a catalog of practical hardening advice, linked to government requirements where applicable. The SCAP Security Guide project @@ -11299,13 +13291,13 @@ bridges the gap between generalized policy requirements and specific implementat A system administrator can use the oscap CLI tool from the openscap-scanner package, or the SCAP Workbench GUI tool from the scap-workbench package, to verify that the system conforms to provided guidelines. Refer to the scap-security-guide(8) manual -page for futher information. - +page for futher information. + if ! rpm -q --quiet "scap-security-guide" ; then yum install -y "scap-security-guide" fi - - - name: Ensure scap-security-guide is installed + + - name: Ensure scap-security-guide is installed package: name: scap-security-guide state: present @@ -11316,41 +13308,46 @@ fi - medium_severity - no_reboot_needed - package_scap-security-guide_installed - - include install_scap-security-guide + + include install_scap-security-guide class install_scap-security-guide { package { 'scap-security-guide': ensure => 'installed', } } - - + + package --add=scap-security-guide - - + + [[packages]] name = "scap-security-guide" version = "*" - - - - - - - - - - Uninstall gssproxy Package - The gssproxy package can be removed with the following command: + + + + + + + + + + Uninstall gssproxy Package + The gssproxy package can be removed with the following command: -$ sudo yum erase gssproxy - CCI-000381 - CCI-000366 - SRG-OS-000095-GPOS-00049 - SRG-OS-000480-GPOS-00227 - gssproxy is a proxy for GSS API credential handling. - +$ sudo yum erase gssproxy + + CCI-000366 + CCI-000381 + SRG-OS-000095-GPOS-00049 + SRG-OS-000480-GPOS-00227 + OL09-00-000115 + SV-271459r1091089_rule + gssproxy is a proxy for GSS API credential handling. +Kerberos relies on some key derivation functions that may not +be compatible with some site policies such as FIPS 140. + # CAUTION: This remediation script will remove gssproxy # from the system, and may remove any packages # that depend on gssproxy. Execute this @@ -11358,49 +13355,52 @@ $ sudo yum erase gssproxy # system! if rpm -q --quiet "gssproxy" ; then - - yum remove -y "gssproxy" - +yum remove -y "gssproxy" fi - - - name: Ensure gssproxy is removed + + - name: Ensure gssproxy is removed package: name: gssproxy state: absent tags: + - DISA-STIG-OL09-00-000115 - disable_strategy - low_complexity - low_disruption - medium_severity - no_reboot_needed - package_gssproxy_removed - - include remove_gssproxy + + include remove_gssproxy class remove_gssproxy { package { 'gssproxy': ensure => 'purged', } } - - - - - - - - - - Uninstall iprutils Package - The iprutils package can be removed with the following command: + + + + + + + + + + Uninstall iprutils Package + The iprutils package can be removed with the following command: -$ sudo yum erase iprutils - CCI-000366 - SRG-OS-000095-GPOS-00049 - SRG-OS-000480-GPOS-00227 - iprutils provides a suite of utlilities to manage and configure SCSI devices -supported by the ipr SCSI storage device driver. - +$ sudo yum erase iprutils + + CCI-000366 + CCI-000381 + SRG-OS-000095-GPOS-00049 + SRG-OS-000480-GPOS-00227 + OL09-00-000120 + SV-271460r1091092_rule + iprutils provides a suite of utlilities to manage and configure SCSI devices +supported by the ipr SCSI storage device driver. + # CAUTION: This remediation script will remove iprutils # from the system, and may remove any packages # that depend on iprutils. Execute this @@ -11408,108 +13408,57 @@ supported by the ipr SCSI storage device driver. # system! if rpm -q --quiet "iprutils" ; then - - yum remove -y "iprutils" - +yum remove -y "iprutils" fi - - - name: Ensure iprutils is removed + + - name: Ensure iprutils is removed package: name: iprutils state: absent tags: + - DISA-STIG-OL09-00-000120 - disable_strategy - low_complexity - low_disruption - medium_severity - no_reboot_needed - package_iprutils_removed - - include remove_iprutils + + include remove_iprutils class remove_iprutils { package { 'iprutils': ensure => 'purged', } } - - + + package --remove=iprutils - - - - - - - - - - Uninstall krb5-workstation Package - The krb5-workstation package can be removed with the following command: + + + + + + + + + + Uninstall tuned Package + The tuned package can be removed with the following command: -$ sudo yum erase krb5-workstation - CCI-000803 - SRG-OS-000095-GPOS-00049 - SRG-OS-000120-GPOS-00061 - Kerberos is a network authentication system. The krb5-workstation package contains the basic -Kerberos programs (kinit, klist, kdestroy, kpasswd). - - -# CAUTION: This remediation script will remove krb5-workstation -# from the system, and may remove any packages -# that depend on krb5-workstation. Execute this -# remediation AFTER testing on a non-production -# system! - -if rpm -q --quiet "krb5-workstation" ; then - - yum remove -y "krb5-workstation" - -fi - - - name: Ensure krb5-workstation is removed - package: - name: krb5-workstation - state: absent - tags: - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - package_krb5-workstation_removed - - include remove_krb5-workstation - -class remove_krb5-workstation { - package { 'krb5-workstation': - ensure => 'purged', - } -} - - -package --remove=krb5-workstation - - - - - - - - - - Uninstall tuned Package - The tuned package can be removed with the following command: - -$ sudo yum erase tuned - CCI-000366 - SRG-OS-000095-GPOS-00049 - SRG-OS-000480-GPOS-00227 - tuned contains a daemon that tunes the system settings dynamically. +$ sudo yum erase tuned + + CCI-000366 + CCI-000381 + SRG-OS-000095-GPOS-00049 + SRG-OS-000480-GPOS-00227 + OL09-00-000125 + SV-271461r1091095_rule + tuned contains a daemon that tunes the system settings dynamically. It does so by monitoring the usage of several system components periodically. Based on that information, components will then be put into lower or higher power savings -modes to adapt to the current usage. - +modes to adapt to the current usage. + # CAUTION: This remediation script will remove tuned # from the system, and may remove any packages # that depend on tuned. Execute this @@ -11517,72 +13466,83 @@ modes to adapt to the current usage. # system! if rpm -q --quiet "tuned" ; then - - yum remove -y "tuned" - +yum remove -y "tuned" fi - - - name: Ensure tuned is removed + + - name: Ensure tuned is removed package: name: tuned state: absent tags: + - DISA-STIG-OL09-00-000125 - disable_strategy - low_complexity - low_disruption - medium_severity - no_reboot_needed - package_tuned_removed - - include remove_tuned + + include remove_tuned class remove_tuned { package { 'tuned': ensure => 'purged', } } - - + + package --remove=tuned - - - - - - - - - - - Updating Software - The yum command line tool is used to install and + + + + + + + + + + + Updating Software + The yum command line tool is used to install and update software packages. The system also provides a graphical software update tool in the System menu, in the Administration submenu, called Software Update. - + + Oracle Linux 9 systems contain an installed software catalog called the RPM database, which records metadata of installed packages. Consistently using yum or the graphical Software Update for all software installation allows for insight into the current inventory of installed software on the system. - - - Install dnf-automatic Package - The dnf-automatic package can be installed with the following command: + + + + + Install dnf-automatic Package + The dnf-automatic package can be installed with the following command: -$ sudo yum install dnf-automatic - BP28(R8) - SRG-OS-000191-GPOS-00080 - dnf-automatic is an alternative command line interface (CLI) -to dnf upgrade suitable for automatic, regular execution. - +$ sudo yum install dnf-automatic + + FPT_TUD_EXT.1 + FPT_TUD_EXT.2 + SRG-OS-000191-GPOS-00080 + R61 + dnf-automatic is an alternative command line interface (CLI) +to dnf upgrade suitable for automatic, regular execution. + + # Remediation is applicable only in certain platforms +if ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ); then + if ! rpm -q --quiet "dnf-automatic" ; then yum install -y "dnf-automatic" fi - - - name: Ensure dnf-automatic is installed - package: - name: dnf-automatic - state: present + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto tags: - enable_strategy - low_complexity @@ -11590,71 +13550,88 @@ fi - medium_severity - no_reboot_needed - package_dnf-automatic_installed - - include install_dnf-automatic + +- name: Ensure dnf-automatic is installed + package: + name: dnf-automatic + state: present + when: not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) + tags: + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - package_dnf-automatic_installed + + include install_dnf-automatic class install_dnf-automatic { package { 'dnf-automatic': ensure => 'installed', } } - - + + package --add=dnf-automatic - - + + [[packages]] name = "dnf-automatic" version = "*" - - - - - - - - - - Ensure yum Removes Previous Package Versions - yum should be configured to remove previous software components after + + + + + + + + + + Ensure yum Removes Previous Package Versions + yum should be configured to remove previous software components after new versions have been installed. To configure yum to remove the previous software components after updating, set the clean_requirements_on_remove -to 1 in /etc/yum.conf. - 18 - 20 - 4 - APO12.01 - APO12.02 - APO12.03 - APO12.04 - BAI03.10 - DSS05.01 - DSS05.02 - 3.4.8 - CCI-002617 - 4.2.3 - 4.2.3.12 - 4.2.3.7 - 4.2.3.9 - A.12.6.1 - A.14.2.3 - A.16.1.3 - A.18.2.2 - A.18.2.3 - SI-2(6) - CM-11(a) - CM-11(b) - CM-6(a) - ID.RA-1 - PR.IP-12 - SRG-OS-000437-GPOS-00194 - Previous versions of software components that are not removed from the information -system after updates have been installed may be exploited by some adversaries. - - # Remediation is applicable only in certain platforms +to 1 in /etc/yum.conf. + 18 + 20 + 4 + APO12.01 + APO12.02 + APO12.03 + APO12.04 + BAI03.10 + DSS05.01 + DSS05.02 + 3.4.8 + CCI-002617 + 4.2.3 + 4.2.3.12 + 4.2.3.7 + 4.2.3.9 + A.12.6.1 + A.14.2.3 + A.16.1.3 + A.18.2.2 + A.18.2.3 + SI-2(6) + CM-11(a) + CM-11(b) + CM-6(a) + ID.RA-1 + PR.IP-12 + SRG-OS-000437-GPOS-00194 + OL09-00-000495 + SV-271522r1091278_rule + Previous versions of software components that are not removed from the information +system after updates have been installed may be exploited by some adversaries. + + # Remediation is applicable only in certain platforms if rpm --quiet -q yum; then if grep --silent ^clean_requirements_on_remove /etc/yum.conf ; then @@ -11667,11 +13644,12 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-000495 - NIST-800-171-3.4.8 - NIST-800-53-CM-11(a) - NIST-800-53-CM-11(b) @@ -11684,8 +13662,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Ensure YUM Removes Previous Package Versions - lineinfile: +- name: Ensure yum Removes Previous Package Versions - Ensure YUM Removes Previous + Package Versions + ansible.builtin.lineinfile: dest: /etc/yum.conf regexp: ^#?clean_requirements_on_remove line: clean_requirements_on_remove=1 @@ -11693,6 +13672,7 @@ fi create: true when: '"yum" in ansible_facts.packages' tags: + - DISA-STIG-OL09-00-000495 - NIST-800-171-3.4.8 - NIST-800-53-CM-11(a) - NIST-800-53-CM-11(b) @@ -11704,39 +13684,42 @@ fi - low_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Configure dnf-automatic to Install Available Updates Automatically - To ensure that the packages comprising the available updates will be automatically installed by dnf-automatic, set apply_updates to yes under [commands] section in /etc/dnf/automatic.conf. - BP28(R8) - 0940 - 1144 - 1467 - 1472 - 1483 - 1493 - 1494 - 1495 - SI-2(5) - CM-6(a) - SI-2(c) - FMT_SMF_EXT.1 - SRG-OS-000191-GPOS-00080 - Installing software updates is a fundamental mitigation against + + + + + + + + + + Configure dnf-automatic to Install Available Updates Automatically + To ensure that the packages comprising the available updates will be automatically installed by dnf-automatic, set apply_updates to yes under [commands] section in /etc/dnf/automatic.conf. + 0940 + 1144 + 1467 + 1472 + 1483 + 1493 + 1494 + 1495 + SI-2(5) + CM-6(a) + SI-2(c) + FMT_SMF_EXT.1 + SRG-OS-000805-GPOS-00260 + R61 + Installing software updates is a fundamental mitigation against the exploitation of publicly-known vulnerabilities. If the most recent security patches and updates are not installed, unauthorized users may take advantage of weaknesses in the unpatched software. The lack of prompt attention to patching could result in a system compromise. The automated installation of updates ensures that recent security patches -are applied in a timely manner. - +are applied in a timely manner. + + # Remediation is applicable only in certain platforms +if ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ); then + found=false # set value in all files if they contain section or key @@ -11747,12 +13730,16 @@ for f in $(echo -n "/etc/dnf/automatic.conf"); do # find key in section and change value if grep -qzosP "[[:space:]]*\[commands\]([^\n\[]*\n+)+?[[:space:]]*apply_updates" "$f"; then - sed -i "s/apply_updates[^(\n)]*/apply_updates = yes/" "$f" + + sed -i "s/apply_updates[^(\n)]*/apply_updates=yes/" "$f" + found=true # find section and add key = value to it elif grep -qs "[[:space:]]*\[commands\]" "$f"; then - sed -i "/[[:space:]]*\[commands\]/a apply_updates = yes" "$f" + + sed -i "/[[:space:]]*\[commands\]/a apply_updates=yes" "$f" + found=true fi done @@ -11761,31 +13748,39 @@ done if ! $found ; then file=$(echo "/etc/dnf/automatic.conf" | cut -f1 -d ' ') mkdir -p "$(dirname "$file")" - echo -e "[commands]\napply_updates = yes" >> "$file" + + echo -e "[commands]\napply_updates=yes" >> "$file" + fi - - - - - - - - - - Configure dnf-automatic to Install Only Security Updates - To configure dnf-automatic to install only security updates + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + + + + + + + + + Configure dnf-automatic to Install Only Security Updates + To configure dnf-automatic to install only security updates automatically, set upgrade_type to security under -[commands] section in /etc/dnf/automatic.conf. - BP28(R8) - SI-2(5) - CM-6(a) - SI-2(c) - FMT_SMF_EXT.1 - SRG-OS-000191-GPOS-00080 - By default, dnf-automatic installs all available updates. +[commands] section in /etc/dnf/automatic.conf. + SI-2(5) + CM-6(a) + SI-2(c) + SRG-OS-000191-GPOS-00080 + R61 + By default, dnf-automatic installs all available updates. Reducing the amount of updated packages only to updates that were -issued as a part of a security advisory increases the system stability. - +issued as a part of a security advisory increases the system stability. + + # Remediation is applicable only in certain platforms +if ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ); then + found=false # set value in all files if they contain section or key @@ -11796,12 +13791,16 @@ for f in $(echo -n "/etc/dnf/automatic.conf"); do # find key in section and change value if grep -qzosP "[[:space:]]*\[commands\]([^\n\[]*\n+)+?[[:space:]]*upgrade_type" "$f"; then - sed -i "s/upgrade_type[^(\n)]*/upgrade_type = security/" "$f" + + sed -i "s/upgrade_type[^(\n)]*/upgrade_type=security/" "$f" + found=true # find section and add key = value to it elif grep -qs "[[:space:]]*\[commands\]" "$f"; then - sed -i "/[[:space:]]*\[commands\]/a upgrade_type = security" "$f" + + sed -i "/[[:space:]]*\[commands\]/a upgrade_type=security" "$f" + found=true fi done @@ -11810,96 +13809,106 @@ done if ! $found ; then file=$(echo "/etc/dnf/automatic.conf" | cut -f1 -d ' ') mkdir -p "$(dirname "$file")" - echo -e "[commands]\nupgrade_type = security" >> "$file" + + echo -e "[commands]\nupgrade_type=security" >> "$file" + fi - - - - - - - - - - Ensure gpgcheck Enabled In Main yum Configuration - The gpgcheck option controls whether + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + + + + + + + + + Ensure gpgcheck Enabled In Main yum Configuration + The gpgcheck option controls whether RPM packages' signatures are always checked prior to installation. To configure yum to check package signatures before installing them, ensure the following line appears in /etc/yum.conf in the [main] section: -gpgcheck=1 - BP28(R15) - 11 - 2 - 3 - 9 - 5.10.4.1 - APO01.06 - BAI03.05 - BAI06.01 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS06.02 - 3.4.8 - CCI-001749 - 164.308(a)(1)(ii)(D) - 164.312(b) - 164.312(c)(1) - 164.312(c)(2) - 164.312(e)(2)(i) - 4.3.4.3.2 - 4.3.4.3.3 - 4.3.4.4.4 - SR 3.1 - SR 3.3 - SR 3.4 - SR 3.8 - SR 7.6 - A.11.2.4 - A.12.1.2 - A.12.2.1 - A.12.5.1 - A.12.6.2 - A.14.1.2 - A.14.1.3 - A.14.2.2 - A.14.2.3 - A.14.2.4 - CM-5(3) - SI-7 - SC-12 - SC-12(3) - CM-6(a) - SA-12 - SA-12(10) - CM-11(a) - CM-11(b) - PR.DS-6 - PR.DS-8 - PR.IP-1 - FPT_TUD_EXT.1 - FPT_TUD_EXT.2 - Req-6.2 - 6.3.3 - SRG-OS-000366-GPOS-00153 - Changes to any software components can have significant effects on the +gpgcheck=1 + + 11 + 2 + 3 + 9 + 5.10.4.1 + APO01.06 + BAI03.05 + BAI06.01 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS06.02 + 3.4.8 + CCI-003992 + 164.308(a)(1)(ii)(D) + 164.312(b) + 164.312(c)(1) + 164.312(c)(2) + 164.312(e)(2)(i) + 4.3.4.3.2 + 4.3.4.3.3 + 4.3.4.4.4 + SR 3.1 + SR 3.3 + SR 3.4 + SR 3.8 + SR 7.6 + A.11.2.4 + A.12.1.2 + A.12.2.1 + A.12.5.1 + A.12.6.2 + A.14.1.2 + A.14.1.3 + A.14.2.2 + A.14.2.3 + A.14.2.4 + CM-5(3) + SI-7 + SC-12 + SC-12(3) + CM-6(a) + SA-12 + SA-12(10) + CM-11(a) + CM-11(b) + PR.DS-6 + PR.DS-8 + PR.IP-1 + FPT_TUD_EXT.1 + FPT_TUD_EXT.2 + Req-6.2 + SRG-OS-000366-GPOS-00153 + R59 + 6.3.3 + 6.3 + OL09-00-000497 + SV-271524r1091284_rule + Changes to any software components can have significant effects on the overall security of the operating system. This requirement ensures the software has not been tampered with and that it has been provided by a trusted vendor. - + Accordingly, patches, service packs, device drivers, or operating system components must be signed with a certificate recognized and approved by the organization. -Verifying the authenticity of the software prior to installation +Verifying the authenticity of the software prior to installation validates the integrity of the patch or upgrade received from a vendor. This ensures the software has not been tampered with and that it has been provided by a trusted vendor. Self-signed certificates are disallowed by this requirement. Certificates used to verify the software must be from an -approved Certificate Authority (CA). - - # Remediation is applicable only in certain platforms +approved Certificate Authority (CA). + + # Remediation is applicable only in certain platforms if rpm --quiet -q yum; then # Strip any search characters in the key arg so that the key can be replaced without @@ -11925,12 +13934,13 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: - CJIS-5.10.4.1 + - DISA-STIG-OL09-00-000497 - NIST-800-171-3.4.8 - NIST-800-53-CM-11(a) - NIST-800-53-CM-11(b) @@ -11942,6 +13952,7 @@ fi - NIST-800-53-SC-12(3) - NIST-800-53-SI-7 - PCI-DSS-Req-6.2 + - PCI-DSSv4-6.3 - PCI-DSSv4-6.3.3 - configure_strategy - ensure_gpgcheck_globally_activated @@ -11961,6 +13972,7 @@ fi when: '"yum" in ansible_facts.packages' tags: - CJIS-5.10.4.1 + - DISA-STIG-OL09-00-000497 - NIST-800-171-3.4.8 - NIST-800-53-CM-11(a) - NIST-800-53-CM-11(b) @@ -11972,6 +13984,7 @@ fi - NIST-800-53-SC-12(3) - NIST-800-53-SI-7 - PCI-DSS-Req-6.2 + - PCI-DSSv4-6.3 - PCI-DSSv4-6.3.3 - configure_strategy - ensure_gpgcheck_globally_activated @@ -11979,61 +13992,64 @@ fi - low_complexity - medium_disruption - no_reboot_needed - - - - - - - - - - Ensure gpgcheck Enabled for Local Packages - yum should be configured to verify the signature(s) of local packages + + + + + + + + + + Ensure gpgcheck Enabled for Local Packages + yum should be configured to verify the signature(s) of local packages prior to installation. To configure yum to verify signatures of local -packages, set the localpkg_gpgcheck to 1 in /etc/yum.conf. - BP28(R15) - 11 - 3 - 9 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - 3.4.8 - CCI-001749 - 164.308(a)(1)(ii)(D) - 164.312(b) - 164.312(c)(1) - 164.312(c)(2) - 164.312(e)(2)(i) - 4.3.4.3.2 - 4.3.4.3.3 - SR 7.6 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.14.2.2 - A.14.2.3 - A.14.2.4 - CM-11(a) - CM-11(b) - CM-6(a) - CM-5(3) - SA-12 - SA-12(10) - PR.IP-1 - FPT_TUD_EXT.1 - FPT_TUD_EXT.2 - SRG-OS-000366-GPOS-00153 - Changes to any software components can have significant effects to the overall security +packages, set the localpkg_gpgcheck to 1 in /etc/yum.conf. + 11 + 3 + 9 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + 3.4.8 + CCI-003992 + 164.308(a)(1)(ii)(D) + 164.312(b) + 164.312(c)(1) + 164.312(c)(2) + 164.312(e)(2)(i) + 4.3.4.3.2 + 4.3.4.3.3 + SR 7.6 + A.12.1.2 + A.12.5.1 + A.12.6.2 + A.14.2.2 + A.14.2.3 + A.14.2.4 + CM-11(a) + CM-11(b) + CM-6(a) + CM-5(3) + SA-12 + SA-12(10) + PR.IP-1 + FPT_TUD_EXT.1 + FPT_TUD_EXT.2 + SRG-OS-000366-GPOS-00153 + R59 + OL09-00-000496 + SV-271523r1091281_rule + Changes to any software components can have significant effects to the overall security of the operating system. This requirement ensures the software has not been tampered and has been provided by a trusted vendor. - + + Accordingly, patches, service packs, device drivers, or operating system components must -be signed with a certificate recognized and approved by the organization. - - # Remediation is applicable only in certain platforms +be signed with a certificate recognized and approved by the organization. + + # Remediation is applicable only in certain platforms if rpm --quiet -q yum; then # Strip any search characters in the key arg so that the key can be replaced without @@ -12059,11 +14075,12 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-000496 - NIST-800-171-3.4.8 - NIST-800-53-CM-11(a) - NIST-800-53-CM-11(b) @@ -12102,6 +14119,7 @@ fi create: true when: '"yum" in ansible_facts.packages' tags: + - DISA-STIG-OL09-00-000496 - NIST-800-171-3.4.8 - NIST-800-53-CM-11(a) - NIST-800-53-CM-11(b) @@ -12115,85 +14133,89 @@ fi - medium_disruption - no_reboot_needed - unknown_strategy - - - - - - - - - - Ensure gpgcheck Enabled for All yum Package Repositories - To ensure signature checking is not disabled for + + + + + + + + + + Ensure gpgcheck Enabled for All yum Package Repositories + To ensure signature checking is not disabled for any repos, remove any lines from files in /etc/yum.repos.d of the form: -gpgcheck=0 - BP28(R15) - 11 - 2 - 3 - 9 - 5.10.4.1 - APO01.06 - BAI03.05 - BAI06.01 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS06.02 - 3.4.8 - CCI-001749 - 164.308(a)(1)(ii)(D) - 164.312(b) - 164.312(c)(1) - 164.312(c)(2) - 164.312(e)(2)(i) - 4.3.4.3.2 - 4.3.4.3.3 - 4.3.4.4.4 - SR 3.1 - SR 3.3 - SR 3.4 - SR 3.8 - SR 7.6 - A.11.2.4 - A.12.1.2 - A.12.2.1 - A.12.5.1 - A.12.6.2 - A.14.1.2 - A.14.1.3 - A.14.2.2 - A.14.2.3 - A.14.2.4 - CM-5(3) - SI-7 - SC-12 - SC-12(3) - CM-6(a) - SA-12 - SA-12(10) - CM-11(a) - CM-11(b) - PR.DS-6 - PR.DS-8 - PR.IP-1 - FPT_TUD_EXT.1 - FPT_TUD_EXT.2 - Req-6.2 - 6.3.3 - SRG-OS-000366-GPOS-00153 - Verifying the authenticity of the software prior to installation validates +gpgcheck=0 + + 11 + 2 + 3 + 9 + 5.10.4.1 + APO01.06 + BAI03.05 + BAI06.01 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS06.02 + 3.4.8 + CCI-003992 + 164.308(a)(1)(ii)(D) + 164.312(b) + 164.312(c)(1) + 164.312(c)(2) + 164.312(e)(2)(i) + 4.3.4.3.2 + 4.3.4.3.3 + 4.3.4.4.4 + SR 3.1 + SR 3.3 + SR 3.4 + SR 3.8 + SR 7.6 + A.11.2.4 + A.12.1.2 + A.12.2.1 + A.12.5.1 + A.12.6.2 + A.14.1.2 + A.14.1.3 + A.14.2.2 + A.14.2.3 + A.14.2.4 + CM-5(3) + SI-7 + SC-12 + SC-12(3) + CM-6(a) + SA-12 + SA-12(10) + CM-11(a) + CM-11(b) + PR.DS-6 + PR.DS-8 + PR.IP-1 + FPT_TUD_EXT.1 + FPT_TUD_EXT.2 + Req-6.2 + SRG-OS-000366-GPOS-00153 + R59 + 6.3.3 + 6.3 + OL09-00-000498 + SV-271525r1091287_rule + Verifying the authenticity of the software prior to installation validates the integrity of the patch or upgrade received from a vendor. This ensures the software has not been tampered with and that it has been provided by a trusted vendor. Self-signed certificates are disallowed by this requirement. Certificates used to verify the software must be from an -approved Certificate Authority (CA)." - +approved Certificate Authority (CA)." + sed -i 's/gpgcheck\s*=.*/gpgcheck=1/g' /etc/yum.repos.d/* - - - name: Grep for yum repo section names + + - name: Grep for yum repo section names shell: | set -o pipefail grep -HEr '^\[.+\]' -r /etc/yum.repos.d/ @@ -12202,6 +14224,7 @@ sed -i 's/gpgcheck\s*=.*/gpgcheck=1/g' /etc/yum.repos.d/* changed_when: false tags: - CJIS-5.10.4.1 + - DISA-STIG-OL09-00-000498 - NIST-800-171-3.4.8 - NIST-800-53-CM-11(a) - NIST-800-53-CM-11(b) @@ -12213,6 +14236,7 @@ sed -i 's/gpgcheck\s*=.*/gpgcheck=1/g' /etc/yum.repos.d/* - NIST-800-53-SC-12(3) - NIST-800-53-SI-7 - PCI-DSS-Req-6.2 + - PCI-DSSv4-6.3 - PCI-DSSv4-6.3.3 - enable_strategy - ensure_gpgcheck_never_disabled @@ -12228,10 +14252,12 @@ sed -i 's/gpgcheck\s*=.*/gpgcheck=1/g' /etc/yum.repos.d/* option: gpgcheck value: '1' no_extra_spaces: true - loop: '{{ repo_grep_results.stdout | regex_findall( ''(.+\.repo):\[(.+)\]\n?'' ) - }}' + loop: '{{ repo_grep_results.stdout |regex_findall( ''(.+\.repo):\[(.+)\]\n?'' ) + if repo_grep_results is not skipped else [] }}' + when: repo_grep_results is not skipped tags: - CJIS-5.10.4.1 + - DISA-STIG-OL09-00-000498 - NIST-800-171-3.4.8 - NIST-800-53-CM-11(a) - NIST-800-53-CM-11(b) @@ -12243,6 +14269,7 @@ sed -i 's/gpgcheck\s*=.*/gpgcheck=1/g' /etc/yum.repos.d/* - NIST-800-53-SC-12(3) - NIST-800-53-SI-7 - PCI-DSS-Req-6.2 + - PCI-DSSv4-6.3 - PCI-DSSv4-6.3.3 - enable_strategy - ensure_gpgcheck_never_disabled @@ -12250,17 +14277,17 @@ sed -i 's/gpgcheck\s*=.*/gpgcheck=1/g' /etc/yum.repos.d/* - low_complexity - medium_disruption - no_reboot_needed - - - - - - - - - - Ensure Oracle Linux GPG Key Installed - To ensure the system can cryptographically verify base software + + + + + + + + + + Ensure Oracle Linux GPG Key Installed + To ensure the system can cryptographically verify base software packages come from Oracle (and to connect to the Unbreakable Linux Network to receive them), the Oracle GPG key must properly be installed. To install the Oracle GPG key, run: @@ -12274,55 +14301,59 @@ it into the keyring: Alternatively, the key may be pre-loaded during the Oracle installation. In such cases, the key can be installed by running the following command: -sudo rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-oracle - 11 - 2 - 3 - 9 - APO01.06 - BAI03.05 - BAI06.01 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS06.02 - CCI-001749 - 4.3.4.3.2 - 4.3.4.3.3 - 4.3.4.4.4 - SR 3.1 - SR 3.3 - SR 3.4 - SR 3.8 - SR 7.6 - A.11.2.4 - A.12.1.2 - A.12.2.1 - A.12.5.1 - A.12.6.2 - A.14.1.2 - A.14.1.3 - A.14.2.2 - A.14.2.3 - A.14.2.4 - CM-5(3) - SI-7 - SC-12 - SC-12(3) - CM-6(a) - CM-11(a) - CM-11(b) - PR.DS-6 - PR.DS-8 - PR.IP-1 - Req-6.2 - Changes to software components can have significant effects on the +sudo rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-oracle + + 11 + 2 + 3 + 9 + APO01.06 + BAI03.05 + BAI06.01 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS06.02 + CCI-001749 + 4.3.4.3.2 + 4.3.4.3.3 + 4.3.4.4.4 + SR 3.1 + SR 3.3 + SR 3.4 + SR 3.8 + SR 7.6 + A.11.2.4 + A.12.1.2 + A.12.2.1 + A.12.5.1 + A.12.6.2 + A.14.1.2 + A.14.1.3 + A.14.2.2 + A.14.2.3 + A.14.2.4 + CM-5(3) + SI-7 + SC-12 + SC-12(3) + CM-6(a) + CM-11(a) + CM-11(b) + PR.DS-6 + PR.DS-8 + PR.IP-1 + Req-6.2 + R59 + OL09-00-000499 + SV-271526r1092460_rule + Changes to software components can have significant effects on the overall security of the operating system. This requirement ensures the software has not been tampered with and that it has been provided by a trusted vendor. The Oracle GPG key is necessary to -cryptographically verify packages are from Oracle. - # OL fingerprints below retrieved from: https://linux.oracle.com/security/gpg/#gpg +cryptographically verify packages are from Oracle. + # OL fingerprints below retrieved from: https://linux.oracle.com/security/gpg/#gpg readonly OL_RELEASE_FINGERPRINT="3E6D826D3FBAB389C2F38E34BC4D06A08D8B756F" readonly OL_AUXILIARY_FINGERPRINT="982231759C7467065D0CE9B2A7DD07088B4EFBE6" @@ -12358,78 +14389,197 @@ then } fi fi - - - - - - - - - - Ensure Software Patches Installed - + + - name: Ensure Oracle Linux GPG Key Installed - Read GPG key directory permission + ansible.builtin.stat: + path: /etc/pki/rpm-gpg/ + register: gpg_key_directory_permission + check_mode: false + tags: + - DISA-STIG-OL09-00-000499 + - NIST-800-53-CM-11(a) + - NIST-800-53-CM-11(b) + - NIST-800-53-CM-5(3) + - NIST-800-53-CM-6(a) + - NIST-800-53-SC-12 + - NIST-800-53-SC-12(3) + - NIST-800-53-SI-7 + - PCI-DSS-Req-6.2 + - ensure_oracle_gpgkey_installed + - high_severity + - medium_complexity + - medium_disruption + - no_reboot_needed + - restrict_strategy + +- name: Ensure Oracle Linux GPG Key Installed - Retrieve GPG key fingerprints information + ansible.builtin.command: gpg --show-keys --with-fingerprint --with-colons "/etc/pki/rpm-gpg/RPM-GPG-KEY-oracle" + changed_when: false + register: gpg_fingerprints + check_mode: false + tags: + - DISA-STIG-OL09-00-000499 + - NIST-800-53-CM-11(a) + - NIST-800-53-CM-11(b) + - NIST-800-53-CM-5(3) + - NIST-800-53-CM-6(a) + - NIST-800-53-SC-12 + - NIST-800-53-SC-12(3) + - NIST-800-53-SI-7 + - PCI-DSS-Req-6.2 + - ensure_oracle_gpgkey_installed + - high_severity + - medium_complexity + - medium_disruption + - no_reboot_needed + - restrict_strategy + +- name: Ensure Oracle Linux GPG Key Installed - Set fact for installed fingerprints + ansible.builtin.set_fact: + gpg_installed_fingerprints: |- + {{ gpg_fingerprints.stdout | regex_findall('^pub.* + (?:^fpr[:]*)([0-9A-Fa-f]*)', '\1') | list }} + tags: + - DISA-STIG-OL09-00-000499 + - NIST-800-53-CM-11(a) + - NIST-800-53-CM-11(b) + - NIST-800-53-CM-5(3) + - NIST-800-53-CM-6(a) + - NIST-800-53-SC-12 + - NIST-800-53-SC-12(3) + - NIST-800-53-SI-7 + - PCI-DSS-Req-6.2 + - ensure_oracle_gpgkey_installed + - high_severity + - medium_complexity + - medium_disruption + - no_reboot_needed + - restrict_strategy + +- name: Ensure Oracle Linux GPG Key Installed - Set fact for valid fingerprints + ansible.builtin.set_fact: + gpg_valid_fingerprints: + - 3E6D826D3FBAB389C2F38E34BC4D06A08D8B756F + - 982231759C7467065D0CE9B2A7DD07088B4EFBE6 + tags: + - DISA-STIG-OL09-00-000499 + - NIST-800-53-CM-11(a) + - NIST-800-53-CM-11(b) + - NIST-800-53-CM-5(3) + - NIST-800-53-CM-6(a) + - NIST-800-53-SC-12 + - NIST-800-53-SC-12(3) + - NIST-800-53-SI-7 + - PCI-DSS-Req-6.2 + - ensure_oracle_gpgkey_installed + - high_severity + - medium_complexity + - medium_disruption + - no_reboot_needed + - restrict_strategy + +- name: Ensure Oracle Linux GPG Key Installed - Import Oracle GPG key securely + ansible.builtin.rpm_key: + state: present + key: /etc/pki/rpm-gpg/RPM-GPG-KEY-oracle + when: + - gpg_key_directory_permission.stat.mode <= '0755' + - (gpg_installed_fingerprints | difference(gpg_valid_fingerprints)) | length == + 0 + - gpg_installed_fingerprints | length > 0 + tags: + - DISA-STIG-OL09-00-000499 + - NIST-800-53-CM-11(a) + - NIST-800-53-CM-11(b) + - NIST-800-53-CM-5(3) + - NIST-800-53-CM-6(a) + - NIST-800-53-SC-12 + - NIST-800-53-SC-12(3) + - NIST-800-53-SI-7 + - PCI-DSS-Req-6.2 + - ensure_oracle_gpgkey_installed + - high_severity + - medium_complexity + - medium_disruption + - no_reboot_needed + - restrict_strategy + + + + + + + + + + Ensure Software Patches Installed + If the system is joined to the ULN or a yum server, run the following command to install updates: $ sudo yum update If the system is not configured to use one of these sources, updates (in the form of RPM packages) can be manually downloaded from the ULN and installed using rpm. - + + NOTE: U.S. Defense systems are required to be patched within 30 days or sooner as local policy -dictates. - The OVAL feed of Oracle Linux 9 is not a XML file, which may not be understood by all scanners. - BP28(R08) - 18 - 20 - 4 - 5.10.4.1 - APO12.01 - APO12.02 - APO12.03 - APO12.04 - BAI03.10 - DSS05.01 - DSS05.02 - CCI-000366 - CCI-001227 - 4.2.3 - 4.2.3.12 - 4.2.3.7 - 4.2.3.9 - A.12.6.1 - A.14.2.3 - A.16.1.3 - A.18.2.2 - A.18.2.3 - SI-2(5) - SI-2(c) - CM-6(a) - ID.RA-1 - PR.IP-12 - FMT_MOF_EXT.1 - Req-6.2 - 6.3.3 - SRG-OS-000480-GPOS-00227 - Installing software updates is a fundamental mitigation against +dictates. + The OVAL feed of Oracle Linux 9 is not a XML file, which may not be understood by all scanners. + 18 + 20 + 4 + 5.10.4.1 + APO12.01 + APO12.02 + APO12.03 + APO12.04 + BAI03.10 + DSS05.01 + DSS05.02 + CCI-000366 + 4.2.3 + 4.2.3.12 + 4.2.3.7 + 4.2.3.9 + A.12.6.1 + A.14.2.3 + A.16.1.3 + A.18.2.2 + A.18.2.3 + SI-2(5) + SI-2(c) + CM-6(a) + ID.RA-1 + PR.IP-12 + FMT_MOF_EXT.1 + Req-6.2 + SRG-OS-000480-GPOS-00227 + R61 + 6.3.3 + 6.3 + OL09-00-000015 + SV-271439r1091029_rule + Installing software updates is a fundamental mitigation against the exploitation of publicly-known vulnerabilities. If the most recent security patches and updates are not installed, unauthorized users may take advantage of weaknesses in the unpatched software. The -lack of prompt attention to patching could result in a system compromise. - +lack of prompt attention to patching could result in a system compromise. + yum -y update - - - name: Security patches are up to date + + - name: Security patches are up to date package: name: '*' state: latest tags: - CJIS-5.10.4.1 + - DISA-STIG-OL09-00-000015 - NIST-800-53-CM-6(a) - NIST-800-53-SI-2(5) - NIST-800-53-SI-2(c) - PCI-DSS-Req-6.2 + - PCI-DSSv4-6.3 - PCI-DSSv4-6.3.3 - high_disruption - low_complexity @@ -12438,30 +14588,54 @@ yum -y update - reboot_required - security_patches_up_to_date - skip_ansible_lint - - - - - - - Enable dnf-automatic Timer - + + + + + + + Enable dnf-automatic Timer + The dnf-automatic timer can be enabled with the following command: -$ sudo systemctl enable dnf-automatic.timer - BP28(R8) - SI-2(5) - CM-6(a) - SI-2(c) - FMT_SMF_EXT.1 - SRG-OS-000191-GPOS-00080 - The dnf-automatic is an alternative command line interface (CLI) to dnf upgrade with specific facilities to make it suitable to be executed automatically and regularly from systemd timers, cron jobs and similar. -The tool is controlled by dnf-automatic.timer SystemD timer. - +$ sudo systemctl enable dnf-automatic.timer + + SI-2(5) + CM-6(a) + SI-2(c) + FMT_SMF_EXT.1 + SRG-OS-000191-GPOS-00080 + R61 + The dnf-automatic is an alternative command line interface (CLI) to dnf upgrade with specific facilities to make it suitable to be executed automatically and regularly from systemd timers, cron jobs and similar. +The tool is controlled by dnf-automatic.timer SystemD timer. + + # Remediation is applicable only in certain platforms +if ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ); then + SYSTEMCTL_EXEC='/usr/bin/systemctl' -"$SYSTEMCTL_EXEC" start 'dnf-automatic.timer' +if [[ $("$SYSTEMCTL_EXEC" is-system-running) != "offline" ]]; then + "$SYSTEMCTL_EXEC" start 'dnf-automatic.timer' +fi "$SYSTEMCTL_EXEC" enable 'dnf-automatic.timer' - - - name: Enable timer dnf-automatic + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-53-CM-6(a) + - NIST-800-53-SI-2(5) + - NIST-800-53-SI-2(c) + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - timer_dnf-automatic_enabled + +- name: Enable timer dnf-automatic block: - name: Gather the package facts @@ -12475,6 +14649,9 @@ SYSTEMCTL_EXEC='/usr/bin/systemctl' state: started when: - '"dnf-automatic" in ansible_facts.packages' + when: not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) tags: - NIST-800-53-CM-6(a) - NIST-800-53-SI-2(5) @@ -12485,92 +14662,123 @@ SYSTEMCTL_EXEC='/usr/bin/systemctl' - medium_severity - no_reboot_needed - timer_dnf-automatic_enabled - - - - - - - - - - - - Account and Access Control - In traditional Unix security, if an attacker gains + + + + + + + + + + + + Account and Access Control + In traditional Unix security, if an attacker gains shell access to a certain login account, they can perform any action or access any file to which that account has access. Therefore, making it more difficult for unauthorized people to gain shell access to accounts, particularly to privileged accounts, is a necessary part of securing a system. This section introduces mechanisms for restricting access to accounts under -Oracle Linux 9. - - Authselect profile - Specify the authselect profile to select - minimal - minimal - sssd - - - Enable authselect - Configure user authentication setup to use the authselect tool. -If authselect profile is selected, the rule will enable the profile. - If the sudo authselect select command returns an error informing that the chosen +Oracle Linux 9. + + Authselect profile + Specify the authselect profile to select + minimal + minimal + sssd + + + Enable authselect + Configure user authentication setup to use the authselect tool. +If authselect profile is selected, the rule will enable the profile. + If the sudo authselect select command returns an error informing that the chosen profile cannot be selected, it is probably because PAM files have already been modified by the administrator. If this is the case, in order to not overwrite the desired changes made by the administrator, the current PAM settings should be investigated before forcing the -selection of the chosen authselect profile. - BP28(R31) - CCI-000213 - 164.308(a)(1)(ii)(B) - 164.308(a)(7)(i) - 164.308(a)(7)(ii)(A) - 164.310(a)(1) - 164.310(a)(2)(i) - 164.310(a)(2)(ii) - 164.310(a)(2)(iii) - 164.310(b) - 164.310(c) - 164.310(d)(1) - 164.310(d)(2)(iii) - AC-3 - FIA_UAU.1 - FIA_AFL.1 - SRG-OS-000480-GPOS-00227 - Authselect is a successor to authconfig. +selection of the chosen authselect profile. + CCI-000213 + 164.308(a)(1)(ii)(B) + 164.308(a)(7)(i) + 164.308(a)(7)(ii)(A) + 164.310(a)(1) + 164.310(a)(2)(i) + 164.310(a)(2)(ii) + 164.310(a)(2)(iii) + 164.310(b) + 164.310(c) + 164.310(d)(1) + 164.310(d)(2)(iii) + AC-3 + FIA_UAU.1 + FIA_AFL.1 + SRG-OS-000480-GPOS-00227 + R31 + enable_authselect + 8.3.4 + 8.3 + needed_rules + Authselect is a successor to authconfig. It is a tool to select system authentication and identity sources from a list of supported profiles instead of letting the administrator manually build the PAM stack. That way, it avoids potential breakage of configuration, as it ships several tested profiles -that are well tested and supported to solve different use-cases. - -var_authselect_profile='' +that are well tested and supported to solve different use-cases. + +var_authselect_profile='' -authselect select "$var_authselect_profile" +authselect current if test "$?" -ne 0; then - if rpm --quiet --verify pam; then - authselect select --force "$var_authselect_profile" - else - echo "Files in the 'pam' package have been altered, so the authselect configuration won't be forced" >&2 + authselect select "$var_authselect_profile" + + if test "$?" -ne 0; then + if rpm --quiet --verify pam; then + authselect select --force "$var_authselect_profile" + else + echo "authselect is not used but files from the 'pam' package have been altered, so the authselect configuration won't be forced." >&2 + fi fi fi - - - name: XCCDF Value var_authselect_profile # promote to variable + + - name: XCCDF Value var_authselect_profile # promote to variable set_fact: - var_authselect_profile: !!str + var_authselect_profile: !!str tags: - always -- name: Enable authselect - Select authselect profile +- name: Enable authselect - Check Current authselect Profile + ansible.builtin.command: + cmd: authselect current + register: result_authselect_current + changed_when: false + failed_when: false + tags: + - DISA-STIG-needed_rules + - NIST-800-53-AC-3 + - PCI-DSSv4-8.3 + - PCI-DSSv4-8.3.4 + - configure_strategy + - enable_authselect + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + +- name: Enable authselect - Try to Select an authselect Profile ansible.builtin.command: cmd: authselect select "{{ var_authselect_profile }}" register: result_authselect_select + changed_when: result_authselect_select.rc == 0 failed_when: false + when: result_authselect_current.rc != 0 tags: + - DISA-STIG-needed_rules - NIST-800-53-AC-3 + - PCI-DSSv4-8.3 + - PCI-DSSv4-8.3.4 - configure_strategy - enable_authselect - low_complexity @@ -12578,14 +14786,20 @@ fi - medium_severity - no_reboot_needed -- name: Enable authselect - Verify if PAM has been altered +- name: Enable authselect - Verify If pam Has Been Altered ansible.builtin.command: cmd: rpm -qV pam register: result_altered_authselect + changed_when: false failed_when: false - when: result_authselect_select.rc != 0 + when: + - result_authselect_select is not skipped + - result_authselect_select.rc != 0 tags: + - DISA-STIG-needed_rules - NIST-800-53-AC-3 + - PCI-DSSv4-8.3 + - PCI-DSSv4-8.3.4 - configure_strategy - enable_authselect - low_complexity @@ -12593,16 +14807,19 @@ fi - medium_severity - no_reboot_needed -- name: Enable authselect - Informative message based on the authselect integrity - check +- name: Enable authselect - Informative Message Based on authselect Integrity Check ansible.builtin.assert: that: - - result_altered_authselect is skipped or result_altered_authselect.rc == 0 + - result_authselect_current.rc == 0 or result_altered_authselect is skipped or + result_altered_authselect.rc == 0 fail_msg: - - Files in the 'pam' package have been altered, so the authselect configuration - won't be forced. + - authselect is not used but files from the 'pam' package have been altered, so + the authselect configuration won't be forced. tags: + - DISA-STIG-needed_rules - NIST-800-53-AC-3 + - PCI-DSSv4-8.3 + - PCI-DSSv4-8.3.4 - configure_strategy - enable_authselect - low_complexity @@ -12610,33 +14827,38 @@ fi - medium_severity - no_reboot_needed -- name: Enable authselect - Force authselect profile select +- name: Enable authselect - Force authselect Profile Selection ansible.builtin.command: cmd: authselect select --force "{{ var_authselect_profile }}" when: + - result_authselect_current.rc != 0 - result_authselect_select.rc != 0 - - result_altered_authselect is skipped or result_altered_authselect.rc == 0 + - result_altered_authselect.rc == 0 tags: + - DISA-STIG-needed_rules - NIST-800-53-AC-3 + - PCI-DSSv4-8.3 + - PCI-DSSv4-8.3.4 - configure_strategy - enable_authselect - low_complexity - medium_disruption - medium_severity - no_reboot_needed - - - - - - - - - - Warning Banners for System Accesses - Each system should expose as little information about + + + + + + + + + + Warning Banners for System Accesses + Each system should expose as little information about itself as possible. - + + System banners, which are typically displayed just before a login prompt, give out information about the service or the host's operating system. This might include the distribution name and the @@ -12645,140 +14867,147 @@ service. This information can assist intruders in gaining access to the system as it can reveal whether the system is running vulnerable software. Most network services can be configured to limit what information is displayed. - + + Many organizations implement security policies that require a system banner provide notice of the system's ownership, provide warning to unauthorized users, and remind authorized users of their -consent to monitoring. - - Login Banner Verbiage - Enter an appropriate login banner for your organization. Please note that new lines must -be expressed by the '\n' character and special characters like parentheses and quotation marks must be escaped with '\\'. - ^(Authorized[\s\n]+uses[\s\n]+only\.[\s\n]+All[\s\n]+activity[\s\n]+may[\s\n]+be[\s\n]+monitored[\s\n]+and[\s\n]+reported\.|^(?!.*(\\|fedora|rhel|sle|ubuntu)).*)$ - ^Authorized[\s\n]+uses[\s\n]+only\.[\s\n]+All[\s\n]+activity[\s\n]+may[\s\n]+be[\s\n]+monitored[\s\n]+and[\s\n]+reported\.$ - ^(You[\s\n]+are[\s\n]+accessing[\s\n]+a[\s\n]+U\.S\.[\s\n]+Government[\s\n]+\(USG\)[\s\n]+Information[\s\n]+System[\s\n]+\(IS\)[\s\n]+that[\s\n]+is[\s\n]+provided[\s\n]+for[\s\n]+USG\-authorized[\s\n]+use[\s\n]+only\.[\s\n]+By[\s\n]+using[\s\n]+this[\s\n]+IS[\s\n]+\(which[\s\n]+includes[\s\n]+any[\s\n]+device[\s\n]+attached[\s\n]+to[\s\n]+this[\s\n]+IS\),[\s\n]+you[\s\n]+consent[\s\n]+to[\s\n]+the[\s\n]+following[\s\n]+conditions\:(?:[\n]+|(?:\\n)+)\-The[\s\n]+USG[\s\n]+routinely[\s\n]+intercepts[\s\n]+and[\s\n]+monitors[\s\n]+communications[\s\n]+on[\s\n]+this[\s\n]+IS[\s\n]+for[\s\n]+purposes[\s\n]+including,[\s\n]+but[\s\n]+not[\s\n]+limited[\s\n]+to,[\s\n]+penetration[\s\n]+testing,[\s\n]+COMSEC[\s\n]+monitoring,[\s\n]+network[\s\n]+operations[\s\n]+and[\s\n]+defense,[\s\n]+personnel[\s\n]+misconduct[\s\n]+\(PM\),[\s\n]+law[\s\n]+enforcement[\s\n]+\(LE\),[\s\n]+and[\s\n]+counterintelligence[\s\n]+\(CI\)[\s\n]+investigations\.(?:[\n]+|(?:\\n)+)\-At[\s\n]+any[\s\n]+time,[\s\n]+the[\s\n]+USG[\s\n]+may[\s\n]+inspect[\s\n]+and[\s\n]+seize[\s\n]+data[\s\n]+stored[\s\n]+on[\s\n]+this[\s\n]+IS\.(?:[\n]+|(?:\\n)+)\-Communications[\s\n]+using,[\s\n]+or[\s\n]+data[\s\n]+stored[\s\n]+on,[\s\n]+this[\s\n]+IS[\s\n]+are[\s\n]+not[\s\n]+private,[\s\n]+are[\s\n]+subject[\s\n]+to[\s\n]+routine[\s\n]+monitoring,[\s\n]+interception,[\s\n]+and[\s\n]+search,[\s\n]+and[\s\n]+may[\s\n]+be[\s\n]+disclosed[\s\n]+or[\s\n]+used[\s\n]+for[\s\n]+any[\s\n]+USG\-authorized[\s\n]+purpose\.(?:[\n]+|(?:\\n)+)\-This[\s\n]+IS[\s\n]+includes[\s\n]+security[\s\n]+measures[\s\n]+\(e\.g\.,[\s\n]+authentication[\s\n]+and[\s\n]+access[\s\n]+controls\)[\s\n]+to[\s\n]+protect[\s\n]+USG[\s\n]+interests\-\-not[\s\n]+for[\s\n]+your[\s\n]+personal[\s\n]+benefit[\s\n]+or[\s\n]+privacy\.(?:[\n]+|(?:\\n)+)\-Notwithstanding[\s\n]+the[\s\n]+above,[\s\n]+using[\s\n]+this[\s\n]+IS[\s\n]+does[\s\n]+not[\s\n]+constitute[\s\n]+consent[\s\n]+to[\s\n]+PM,[\s\n]+LE[\s\n]+or[\s\n]+CI[\s\n]+investigative[\s\n]+searching[\s\n]+or[\s\n]+monitoring[\s\n]+of[\s\n]+the[\s\n]+content[\s\n]+of[\s\n]+privileged[\s\n]+communications,[\s\n]+or[\s\n]+work[\s\n]+product,[\s\n]+related[\s\n]+to[\s\n]+personal[\s\n]+representation[\s\n]+or[\s\n]+services[\s\n]+by[\s\n]+attorneys,[\s\n]+psychotherapists,[\s\n]+or[\s\n]+clergy,[\s\n]+and[\s\n]+their[\s\n]+assistants\.[\s\n]+Such[\s\n]+communications[\s\n]+and[\s\n]+work[\s\n]+product[\s\n]+are[\s\n]+private[\s\n]+and[\s\n]+confidential\.[\s\n]+See[\s\n]+User[\s\n]+Agreement[\s\n]+for[\s\n]+details\.|I've[\s\n]+read[\s\n]+\&[\s\n]+consent[\s\n]+to[\s\n]+terms[\s\n]+in[\s\n]+IS[\s\n]+user[\s\n]+agreem't\.)$ - ^You[\s\n]+are[\s\n]+accessing[\s\n]+a[\s\n]+U\.S\.[\s\n]+Government[\s\n]+\(USG\)[\s\n]+Information[\s\n]+System[\s\n]+\(IS\)[\s\n]+that[\s\n]+is[\s\n]+provided[\s\n]+for[\s\n]+USG\-authorized[\s\n]+use[\s\n]+only\.[\s\n]+By[\s\n]+using[\s\n]+this[\s\n]+IS[\s\n]+\(which[\s\n]+includes[\s\n]+any[\s\n]+device[\s\n]+attached[\s\n]+to[\s\n]+this[\s\n]+IS\),[\s\n]+you[\s\n]+consent[\s\n]+to[\s\n]+the[\s\n]+following[\s\n]+conditions\:(?:[\n]+|(?:\\n)+)\-The[\s\n]+USG[\s\n]+routinely[\s\n]+intercepts[\s\n]+and[\s\n]+monitors[\s\n]+communications[\s\n]+on[\s\n]+this[\s\n]+IS[\s\n]+for[\s\n]+purposes[\s\n]+including,[\s\n]+but[\s\n]+not[\s\n]+limited[\s\n]+to,[\s\n]+penetration[\s\n]+testing,[\s\n]+COMSEC[\s\n]+monitoring,[\s\n]+network[\s\n]+operations[\s\n]+and[\s\n]+defense,[\s\n]+personnel[\s\n]+misconduct[\s\n]+\(PM\),[\s\n]+law[\s\n]+enforcement[\s\n]+\(LE\),[\s\n]+and[\s\n]+counterintelligence[\s\n]+\(CI\)[\s\n]+investigations\.(?:[\n]+|(?:\\n)+)\-At[\s\n]+any[\s\n]+time,[\s\n]+the[\s\n]+USG[\s\n]+may[\s\n]+inspect[\s\n]+and[\s\n]+seize[\s\n]+data[\s\n]+stored[\s\n]+on[\s\n]+this[\s\n]+IS\.(?:[\n]+|(?:\\n)+)\-Communications[\s\n]+using,[\s\n]+or[\s\n]+data[\s\n]+stored[\s\n]+on,[\s\n]+this[\s\n]+IS[\s\n]+are[\s\n]+not[\s\n]+private,[\s\n]+are[\s\n]+subject[\s\n]+to[\s\n]+routine[\s\n]+monitoring,[\s\n]+interception,[\s\n]+and[\s\n]+search,[\s\n]+and[\s\n]+may[\s\n]+be[\s\n]+disclosed[\s\n]+or[\s\n]+used[\s\n]+for[\s\n]+any[\s\n]+USG\-authorized[\s\n]+purpose\.(?:[\n]+|(?:\\n)+)\-This[\s\n]+IS[\s\n]+includes[\s\n]+security[\s\n]+measures[\s\n]+\(e\.g\.,[\s\n]+authentication[\s\n]+and[\s\n]+access[\s\n]+controls\)[\s\n]+to[\s\n]+protect[\s\n]+USG[\s\n]+interests\-\-not[\s\n]+for[\s\n]+your[\s\n]+personal[\s\n]+benefit[\s\n]+or[\s\n]+privacy\.(?:[\n]+|(?:\\n)+)\-Notwithstanding[\s\n]+the[\s\n]+above,[\s\n]+using[\s\n]+this[\s\n]+IS[\s\n]+does[\s\n]+not[\s\n]+constitute[\s\n]+consent[\s\n]+to[\s\n]+PM,[\s\n]+LE[\s\n]+or[\s\n]+CI[\s\n]+investigative[\s\n]+searching[\s\n]+or[\s\n]+monitoring[\s\n]+of[\s\n]+the[\s\n]+content[\s\n]+of[\s\n]+privileged[\s\n]+communications,[\s\n]+or[\s\n]+work[\s\n]+product,[\s\n]+related[\s\n]+to[\s\n]+personal[\s\n]+representation[\s\n]+or[\s\n]+services[\s\n]+by[\s\n]+attorneys,[\s\n]+psychotherapists,[\s\n]+or[\s\n]+clergy,[\s\n]+and[\s\n]+their[\s\n]+assistants\.[\s\n]+Such[\s\n]+communications[\s\n]+and[\s\n]+work[\s\n]+product[\s\n]+are[\s\n]+private[\s\n]+and[\s\n]+confidential\.[\s\n]+See[\s\n]+User[\s\n]+Agreement[\s\n]+for[\s\n]+details\.$ - ^I've[\s\n]+read[\s\n]+\&[\s\n]+consent[\s\n]+to[\s\n]+terms[\s\n]+in[\s\n]+IS[\s\n]+user[\s\n]+agreem't\.$ - ^Use[\s\n]+of[\s\n]+this[\s\n]+or[\s\n]+any[\s\n]+other[\s\n]+DoD[\s\n]+interest[\s\n]+computer[\s\n]+system[\s\n]+constitutes[\s\n]+consent[\s\n]+to[\s\n]+monitoring[\s\n]+at[\s\n]+all[\s\n]+times\.[\s\n]+This[\s\n]+is[\s\n]+a[\s\n]+DoD[\s\n]+interest[\s\n]+computer[\s\n]+system\.[\s\n]+All[\s\n]+DoD[\s\n]+interest[\s\n]+computer[\s\n]+systems[\s\n]+and[\s\n]+related[\s\n]+equipment[\s\n]+are[\s\n]+intended[\s\n]+for[\s\n]+the[\s\n]+communication,[\s\n]+transmission,[\s\n]+processing,[\s\n]+and[\s\n]+storage[\s\n]+of[\s\n]+official[\s\n]+U\.S\.[\s\n]+Government[\s\n]+or[\s\n]+other[\s\n]+authorized[\s\n]+information[\s\n]+only\.[\s\n]+All[\s\n]+DoD[\s\n]+interest[\s\n]+computer[\s\n]+systems[\s\n]+are[\s\n]+subject[\s\n]+to[\s\n]+monitoring[\s\n]+at[\s\n]+all[\s\n]+times[\s\n]+to[\s\n]+ensure[\s\n]+proper[\s\n]+functioning[\s\n]+of[\s\n]+equipment[\s\n]+and[\s\n]+systems[\s\n]+including[\s\n]+security[\s\n]+devices[\s\n]+and[\s\n]+systems,[\s\n]+to[\s\n]+prevent[\s\n]+unauthorized[\s\n]+use[\s\n]+and[\s\n]+violations[\s\n]+of[\s\n]+statutes[\s\n]+and[\s\n]+security[\s\n]+regulations,[\s\n]+to[\s\n]+deter[\s\n]+criminal[\s\n]+activity,[\s\n]+and[\s\n]+for[\s\n]+other[\s\n]+similar[\s\n]+purposes\.[\s\n]+Any[\s\n]+user[\s\n]+of[\s\n]+a[\s\n]+DoD[\s\n]+interest[\s\n]+computer[\s\n]+system[\s\n]+should[\s\n]+be[\s\n]+aware[\s\n]+that[\s\n]+any[\s\n]+information[\s\n]+placed[\s\n]+in[\s\n]+the[\s\n]+system[\s\n]+is[\s\n]+subject[\s\n]+to[\s\n]+monitoring[\s\n]+and[\s\n]+is[\s\n]+not[\s\n]+subject[\s\n]+to[\s\n]+any[\s\n]+expectation[\s\n]+of[\s\n]+privacy\.[\s\n]+If[\s\n]+monitoring[\s\n]+of[\s\n]+this[\s\n]+or[\s\n]+any[\s\n]+other[\s\n]+DoD[\s\n]+interest[\s\n]+computer[\s\n]+system[\s\n]+reveals[\s\n]+possible[\s\n]+evidence[\s\n]+of[\s\n]+violation[\s\n]+of[\s\n]+criminal[\s\n]+statutes,[\s\n]+this[\s\n]+evidence[\s\n]+and[\s\n]+any[\s\n]+other[\s\n]+related[\s\n]+information,[\s\n]+including[\s\n]+identification[\s\n]+information[\s\n]+about[\s\n]+the[\s\n]+user,[\s\n]+may[\s\n]+be[\s\n]+provided[\s\n]+to[\s\n]+law[\s\n]+enforcement[\s\n]+officials\.[\s\n]+If[\s\n]+monitoring[\s\n]+of[\s\n]+this[\s\n]+or[\s\n]+any[\s\n]+other[\s\n]+DoD[\s\n]+interest[\s\n]+computer[\s\n]+systems[\s\n]+reveals[\s\n]+violations[\s\n]+of[\s\n]+security[\s\n]+regulations[\s\n]+or[\s\n]+unauthorized[\s\n]+use,[\s\n]+employees[\s\n]+who[\s\n]+violate[\s\n]+security[\s\n]+regulations[\s\n]+or[\s\n]+make[\s\n]+unauthorized[\s\n]+use[\s\n]+of[\s\n]+DoD[\s\n]+interest[\s\n]+computer[\s\n]+systems[\s\n]+are[\s\n]+subject[\s\n]+to[\s\n]+appropriate[\s\n]+disciplinary[\s\n]+action\.[\s\n]+Use[\s\n]+of[\s\n]+this[\s\n]+or[\s\n]+any[\s\n]+other[\s\n]+DoD[\s\n]+interest[\s\n]+computer[\s\n]+system[\s\n]+constitutes[\s\n]+consent[\s\n]+to[\s\n]+monitoring[\s\n]+at[\s\n]+all[\s\n]+times\.$ - ^\-\-[\s\n]+WARNING[\s\n]+\-\-[\s\n]+This[\s\n]+system[\s\n]+is[\s\n]+for[\s\n]+the[\s\n]+use[\s\n]+of[\s\n]+authorized[\s\n]+users[\s\n]+only\.[\s\n]+Individuals[\s\n]+using[\s\n]+this[\s\n]+computer[\s\n]+system[\s\n]+without[\s\n]+authority[\s\n]+or[\s\n]+in[\s\n]+excess[\s\n]+of[\s\n]+their[\s\n]+authority[\s\n]+are[\s\n]+subject[\s\n]+to[\s\n]+having[\s\n]+all[\s\n]+their[\s\n]+activities[\s\n]+on[\s\n]+this[\s\n]+system[\s\n]+monitored[\s\n]+and[\s\n]+recorded[\s\n]+by[\s\n]+system[\s\n]+personnel\.[\s\n]+Anyone[\s\n]+using[\s\n]+this[\s\n]+system[\s\n]+expressly[\s\n]+consents[\s\n]+to[\s\n]+such[\s\n]+monitoring[\s\n]+and[\s\n]+is[\s\n]+advised[\s\n]+that[\s\n]+if[\s\n]+such[\s\n]+monitoring[\s\n]+reveals[\s\n]+possible[\s\n]+evidence[\s\n]+of[\s\n]+criminal[\s\n]+activity[\s\n]+system[\s\n]+personal[\s\n]+may[\s\n]+provide[\s\n]+the[\s\n]+evidence[\s\n]+of[\s\n]+such[\s\n]+monitoring[\s\n]+to[\s\n]+law[\s\n]+enforcement[\s\n]+officials\.$ - ^Authorized[\s\n]+uses[\s\n]+only\.[\s\n]+All[\s\n]+activity[\s\n]+may[\s\n]+be[\s\n]+monitored[\s\n]+and[\s\n]+reported\.$ - - - MotD Banner Verbiage - Enter an appropriate login banner for your organization. Please note that new lines must -be expressed by the '\n' character and special characters like parentheses and quotation marks must be escaped with '\\'. - ^(Authorized[\s\n]+uses[\s\n]+only\.[\s\n]+All[\s\n]+activity[\s\n]+may[\s\n]+be[\s\n]+monitored[\s\n]+and[\s\n]+reported\.|^(?!.*(\\|fedora|rhel|sle|ubuntu)).*)$ - ^Authorized[\s\n]+uses[\s\n]+only\.[\s\n]+All[\s\n]+activity[\s\n]+may[\s\n]+be[\s\n]+monitored[\s\n]+and[\s\n]+reported\.$ - ^(You[\s\n]+are[\s\n]+accessing[\s\n]+a[\s\n]+U\.S\.[\s\n]+Government[\s\n]+\(USG\)[\s\n]+Information[\s\n]+System[\s\n]+\(IS\)[\s\n]+that[\s\n]+is[\s\n]+provided[\s\n]+for[\s\n]+USG\-authorized[\s\n]+use[\s\n]+only\.[\s\n]+By[\s\n]+using[\s\n]+this[\s\n]+IS[\s\n]+\(which[\s\n]+includes[\s\n]+any[\s\n]+device[\s\n]+attached[\s\n]+to[\s\n]+this[\s\n]+IS\),[\s\n]+you[\s\n]+consent[\s\n]+to[\s\n]+the[\s\n]+following[\s\n]+conditions\:(?:[\n]+|(?:\\n)+)\-The[\s\n]+USG[\s\n]+routinely[\s\n]+intercepts[\s\n]+and[\s\n]+monitors[\s\n]+communications[\s\n]+on[\s\n]+this[\s\n]+IS[\s\n]+for[\s\n]+purposes[\s\n]+including,[\s\n]+but[\s\n]+not[\s\n]+limited[\s\n]+to,[\s\n]+penetration[\s\n]+testing,[\s\n]+COMSEC[\s\n]+monitoring,[\s\n]+network[\s\n]+operations[\s\n]+and[\s\n]+defense,[\s\n]+personnel[\s\n]+misconduct[\s\n]+\(PM\),[\s\n]+law[\s\n]+enforcement[\s\n]+\(LE\),[\s\n]+and[\s\n]+counterintelligence[\s\n]+\(CI\)[\s\n]+investigations\.(?:[\n]+|(?:\\n)+)\-At[\s\n]+any[\s\n]+time,[\s\n]+the[\s\n]+USG[\s\n]+may[\s\n]+inspect[\s\n]+and[\s\n]+seize[\s\n]+data[\s\n]+stored[\s\n]+on[\s\n]+this[\s\n]+IS\.(?:[\n]+|(?:\\n)+)\-Communications[\s\n]+using,[\s\n]+or[\s\n]+data[\s\n]+stored[\s\n]+on,[\s\n]+this[\s\n]+IS[\s\n]+are[\s\n]+not[\s\n]+private,[\s\n]+are[\s\n]+subject[\s\n]+to[\s\n]+routine[\s\n]+monitoring,[\s\n]+interception,[\s\n]+and[\s\n]+search,[\s\n]+and[\s\n]+may[\s\n]+be[\s\n]+disclosed[\s\n]+or[\s\n]+used[\s\n]+for[\s\n]+any[\s\n]+USG\-authorized[\s\n]+purpose\.(?:[\n]+|(?:\\n)+)\-This[\s\n]+IS[\s\n]+includes[\s\n]+security[\s\n]+measures[\s\n]+\(e\.g\.,[\s\n]+authentication[\s\n]+and[\s\n]+access[\s\n]+controls\)[\s\n]+to[\s\n]+protect[\s\n]+USG[\s\n]+interests\-\-not[\s\n]+for[\s\n]+your[\s\n]+personal[\s\n]+benefit[\s\n]+or[\s\n]+privacy\.(?:[\n]+|(?:\\n)+)\-Notwithstanding[\s\n]+the[\s\n]+above,[\s\n]+using[\s\n]+this[\s\n]+IS[\s\n]+does[\s\n]+not[\s\n]+constitute[\s\n]+consent[\s\n]+to[\s\n]+PM,[\s\n]+LE[\s\n]+or[\s\n]+CI[\s\n]+investigative[\s\n]+searching[\s\n]+or[\s\n]+monitoring[\s\n]+of[\s\n]+the[\s\n]+content[\s\n]+of[\s\n]+privileged[\s\n]+communications,[\s\n]+or[\s\n]+work[\s\n]+product,[\s\n]+related[\s\n]+to[\s\n]+personal[\s\n]+representation[\s\n]+or[\s\n]+services[\s\n]+by[\s\n]+attorneys,[\s\n]+psychotherapists,[\s\n]+or[\s\n]+clergy,[\s\n]+and[\s\n]+their[\s\n]+assistants\.[\s\n]+Such[\s\n]+communications[\s\n]+and[\s\n]+work[\s\n]+product[\s\n]+are[\s\n]+private[\s\n]+and[\s\n]+confidential\.[\s\n]+See[\s\n]+User[\s\n]+Agreement[\s\n]+for[\s\n]+details\.|I've[\s\n]+read[\s\n]+\&[\s\n]+consent[\s\n]+to[\s\n]+terms[\s\n]+in[\s\n]+IS[\s\n]+user[\s\n]+agreem't\.)$ - ^You[\s\n]+are[\s\n]+accessing[\s\n]+a[\s\n]+U\.S\.[\s\n]+Government[\s\n]+\(USG\)[\s\n]+Information[\s\n]+System[\s\n]+\(IS\)[\s\n]+that[\s\n]+is[\s\n]+provided[\s\n]+for[\s\n]+USG\-authorized[\s\n]+use[\s\n]+only\.[\s\n]+By[\s\n]+using[\s\n]+this[\s\n]+IS[\s\n]+\(which[\s\n]+includes[\s\n]+any[\s\n]+device[\s\n]+attached[\s\n]+to[\s\n]+this[\s\n]+IS\),[\s\n]+you[\s\n]+consent[\s\n]+to[\s\n]+the[\s\n]+following[\s\n]+conditions\:(?:[\n]+|(?:\\n)+)\-The[\s\n]+USG[\s\n]+routinely[\s\n]+intercepts[\s\n]+and[\s\n]+monitors[\s\n]+communications[\s\n]+on[\s\n]+this[\s\n]+IS[\s\n]+for[\s\n]+purposes[\s\n]+including,[\s\n]+but[\s\n]+not[\s\n]+limited[\s\n]+to,[\s\n]+penetration[\s\n]+testing,[\s\n]+COMSEC[\s\n]+monitoring,[\s\n]+network[\s\n]+operations[\s\n]+and[\s\n]+defense,[\s\n]+personnel[\s\n]+misconduct[\s\n]+\(PM\),[\s\n]+law[\s\n]+enforcement[\s\n]+\(LE\),[\s\n]+and[\s\n]+counterintelligence[\s\n]+\(CI\)[\s\n]+investigations\.(?:[\n]+|(?:\\n)+)\-At[\s\n]+any[\s\n]+time,[\s\n]+the[\s\n]+USG[\s\n]+may[\s\n]+inspect[\s\n]+and[\s\n]+seize[\s\n]+data[\s\n]+stored[\s\n]+on[\s\n]+this[\s\n]+IS\.(?:[\n]+|(?:\\n)+)\-Communications[\s\n]+using,[\s\n]+or[\s\n]+data[\s\n]+stored[\s\n]+on,[\s\n]+this[\s\n]+IS[\s\n]+are[\s\n]+not[\s\n]+private,[\s\n]+are[\s\n]+subject[\s\n]+to[\s\n]+routine[\s\n]+monitoring,[\s\n]+interception,[\s\n]+and[\s\n]+search,[\s\n]+and[\s\n]+may[\s\n]+be[\s\n]+disclosed[\s\n]+or[\s\n]+used[\s\n]+for[\s\n]+any[\s\n]+USG\-authorized[\s\n]+purpose\.(?:[\n]+|(?:\\n)+)\-This[\s\n]+IS[\s\n]+includes[\s\n]+security[\s\n]+measures[\s\n]+\(e\.g\.,[\s\n]+authentication[\s\n]+and[\s\n]+access[\s\n]+controls\)[\s\n]+to[\s\n]+protect[\s\n]+USG[\s\n]+interests\-\-not[\s\n]+for[\s\n]+your[\s\n]+personal[\s\n]+benefit[\s\n]+or[\s\n]+privacy\.(?:[\n]+|(?:\\n)+)\-Notwithstanding[\s\n]+the[\s\n]+above,[\s\n]+using[\s\n]+this[\s\n]+IS[\s\n]+does[\s\n]+not[\s\n]+constitute[\s\n]+consent[\s\n]+to[\s\n]+PM,[\s\n]+LE[\s\n]+or[\s\n]+CI[\s\n]+investigative[\s\n]+searching[\s\n]+or[\s\n]+monitoring[\s\n]+of[\s\n]+the[\s\n]+content[\s\n]+of[\s\n]+privileged[\s\n]+communications,[\s\n]+or[\s\n]+work[\s\n]+product,[\s\n]+related[\s\n]+to[\s\n]+personal[\s\n]+representation[\s\n]+or[\s\n]+services[\s\n]+by[\s\n]+attorneys,[\s\n]+psychotherapists,[\s\n]+or[\s\n]+clergy,[\s\n]+and[\s\n]+their[\s\n]+assistants\.[\s\n]+Such[\s\n]+communications[\s\n]+and[\s\n]+work[\s\n]+product[\s\n]+are[\s\n]+private[\s\n]+and[\s\n]+confidential\.[\s\n]+See[\s\n]+User[\s\n]+Agreement[\s\n]+for[\s\n]+details\.$ - ^I've[\s\n]+read[\s\n]+\&[\s\n]+consent[\s\n]+to[\s\n]+terms[\s\n]+in[\s\n]+IS[\s\n]+user[\s\n]+agreem't\.$ - ^Use[\s\n]+of[\s\n]+this[\s\n]+or[\s\n]+any[\s\n]+other[\s\n]+DoD[\s\n]+interest[\s\n]+computer[\s\n]+system[\s\n]+constitutes[\s\n]+consent[\s\n]+to[\s\n]+monitoring[\s\n]+at[\s\n]+all[\s\n]+times\.[\s\n]+This[\s\n]+is[\s\n]+a[\s\n]+DoD[\s\n]+interest[\s\n]+computer[\s\n]+system\.[\s\n]+All[\s\n]+DoD[\s\n]+interest[\s\n]+computer[\s\n]+systems[\s\n]+and[\s\n]+related[\s\n]+equipment[\s\n]+are[\s\n]+intended[\s\n]+for[\s\n]+the[\s\n]+communication,[\s\n]+transmission,[\s\n]+processing,[\s\n]+and[\s\n]+storage[\s\n]+of[\s\n]+official[\s\n]+U\.S\.[\s\n]+Government[\s\n]+or[\s\n]+other[\s\n]+authorized[\s\n]+information[\s\n]+only\.[\s\n]+All[\s\n]+DoD[\s\n]+interest[\s\n]+computer[\s\n]+systems[\s\n]+are[\s\n]+subject[\s\n]+to[\s\n]+monitoring[\s\n]+at[\s\n]+all[\s\n]+times[\s\n]+to[\s\n]+ensure[\s\n]+proper[\s\n]+functioning[\s\n]+of[\s\n]+equipment[\s\n]+and[\s\n]+systems[\s\n]+including[\s\n]+security[\s\n]+devices[\s\n]+and[\s\n]+systems,[\s\n]+to[\s\n]+prevent[\s\n]+unauthorized[\s\n]+use[\s\n]+and[\s\n]+violations[\s\n]+of[\s\n]+statutes[\s\n]+and[\s\n]+security[\s\n]+regulations,[\s\n]+to[\s\n]+deter[\s\n]+criminal[\s\n]+activity,[\s\n]+and[\s\n]+for[\s\n]+other[\s\n]+similar[\s\n]+purposes\.[\s\n]+Any[\s\n]+user[\s\n]+of[\s\n]+a[\s\n]+DoD[\s\n]+interest[\s\n]+computer[\s\n]+system[\s\n]+should[\s\n]+be[\s\n]+aware[\s\n]+that[\s\n]+any[\s\n]+information[\s\n]+placed[\s\n]+in[\s\n]+the[\s\n]+system[\s\n]+is[\s\n]+subject[\s\n]+to[\s\n]+monitoring[\s\n]+and[\s\n]+is[\s\n]+not[\s\n]+subject[\s\n]+to[\s\n]+any[\s\n]+expectation[\s\n]+of[\s\n]+privacy\.[\s\n]+If[\s\n]+monitoring[\s\n]+of[\s\n]+this[\s\n]+or[\s\n]+any[\s\n]+other[\s\n]+DoD[\s\n]+interest[\s\n]+computer[\s\n]+system[\s\n]+reveals[\s\n]+possible[\s\n]+evidence[\s\n]+of[\s\n]+violation[\s\n]+of[\s\n]+criminal[\s\n]+statutes,[\s\n]+this[\s\n]+evidence[\s\n]+and[\s\n]+any[\s\n]+other[\s\n]+related[\s\n]+information,[\s\n]+including[\s\n]+identification[\s\n]+information[\s\n]+about[\s\n]+the[\s\n]+user,[\s\n]+may[\s\n]+be[\s\n]+provided[\s\n]+to[\s\n]+law[\s\n]+enforcement[\s\n]+officials\.[\s\n]+If[\s\n]+monitoring[\s\n]+of[\s\n]+this[\s\n]+or[\s\n]+any[\s\n]+other[\s\n]+DoD[\s\n]+interest[\s\n]+computer[\s\n]+systems[\s\n]+reveals[\s\n]+violations[\s\n]+of[\s\n]+security[\s\n]+regulations[\s\n]+or[\s\n]+unauthorized[\s\n]+use,[\s\n]+employees[\s\n]+who[\s\n]+violate[\s\n]+security[\s\n]+regulations[\s\n]+or[\s\n]+make[\s\n]+unauthorized[\s\n]+use[\s\n]+of[\s\n]+DoD[\s\n]+interest[\s\n]+computer[\s\n]+systems[\s\n]+are[\s\n]+subject[\s\n]+to[\s\n]+appropriate[\s\n]+disciplinary[\s\n]+action\.[\s\n]+Use[\s\n]+of[\s\n]+this[\s\n]+or[\s\n]+any[\s\n]+other[\s\n]+DoD[\s\n]+interest[\s\n]+computer[\s\n]+system[\s\n]+constitutes[\s\n]+consent[\s\n]+to[\s\n]+monitoring[\s\n]+at[\s\n]+all[\s\n]+times\.$ - ^\-\-[\s\n]+WARNING[\s\n]+\-\-[\s\n]+This[\s\n]+system[\s\n]+is[\s\n]+for[\s\n]+the[\s\n]+use[\s\n]+of[\s\n]+authorized[\s\n]+users[\s\n]+only\.[\s\n]+Individuals[\s\n]+using[\s\n]+this[\s\n]+computer[\s\n]+system[\s\n]+without[\s\n]+authority[\s\n]+or[\s\n]+in[\s\n]+excess[\s\n]+of[\s\n]+their[\s\n]+authority[\s\n]+are[\s\n]+subject[\s\n]+to[\s\n]+having[\s\n]+all[\s\n]+their[\s\n]+activities[\s\n]+on[\s\n]+this[\s\n]+system[\s\n]+monitored[\s\n]+and[\s\n]+recorded[\s\n]+by[\s\n]+system[\s\n]+personnel\.[\s\n]+Anyone[\s\n]+using[\s\n]+this[\s\n]+system[\s\n]+expressly[\s\n]+consents[\s\n]+to[\s\n]+such[\s\n]+monitoring[\s\n]+and[\s\n]+is[\s\n]+advised[\s\n]+that[\s\n]+if[\s\n]+such[\s\n]+monitoring[\s\n]+reveals[\s\n]+possible[\s\n]+evidence[\s\n]+of[\s\n]+criminal[\s\n]+activity[\s\n]+system[\s\n]+personal[\s\n]+may[\s\n]+provide[\s\n]+the[\s\n]+evidence[\s\n]+of[\s\n]+such[\s\n]+monitoring[\s\n]+to[\s\n]+law[\s\n]+enforcement[\s\n]+officials\.$ - ^Authorized[\s\n]+uses[\s\n]+only\.[\s\n]+All[\s\n]+activity[\s\n]+may[\s\n]+be[\s\n]+monitored[\s\n]+and[\s\n]+reported\.$ - - - Remote Login Banner Verbiage - Enter an appropriate login banner for your organization. Please note that new lines must -be expressed by the '\n' character and special characters like parentheses and quotation marks must be escaped with '\\'. - ^(Authorized[\s\n]+uses[\s\n]+only\.[\s\n]+All[\s\n]+activity[\s\n]+may[\s\n]+be[\s\n]+monitored[\s\n]+and[\s\n]+reported\.|^(?!.*(\\|fedora|rhel|sle|ubuntu)).*)$ - ^Authorized[\s\n]+uses[\s\n]+only\.[\s\n]+All[\s\n]+activity[\s\n]+may[\s\n]+be[\s\n]+monitored[\s\n]+and[\s\n]+reported\.$ - ^(You[\s\n]+are[\s\n]+accessing[\s\n]+a[\s\n]+U\.S\.[\s\n]+Government[\s\n]+\(USG\)[\s\n]+Information[\s\n]+System[\s\n]+\(IS\)[\s\n]+that[\s\n]+is[\s\n]+provided[\s\n]+for[\s\n]+USG\-authorized[\s\n]+use[\s\n]+only\.[\s\n]+By[\s\n]+using[\s\n]+this[\s\n]+IS[\s\n]+\(which[\s\n]+includes[\s\n]+any[\s\n]+device[\s\n]+attached[\s\n]+to[\s\n]+this[\s\n]+IS\),[\s\n]+you[\s\n]+consent[\s\n]+to[\s\n]+the[\s\n]+following[\s\n]+conditions\:(?:[\n]+|(?:\\n)+)\-The[\s\n]+USG[\s\n]+routinely[\s\n]+intercepts[\s\n]+and[\s\n]+monitors[\s\n]+communications[\s\n]+on[\s\n]+this[\s\n]+IS[\s\n]+for[\s\n]+purposes[\s\n]+including,[\s\n]+but[\s\n]+not[\s\n]+limited[\s\n]+to,[\s\n]+penetration[\s\n]+testing,[\s\n]+COMSEC[\s\n]+monitoring,[\s\n]+network[\s\n]+operations[\s\n]+and[\s\n]+defense,[\s\n]+personnel[\s\n]+misconduct[\s\n]+\(PM\),[\s\n]+law[\s\n]+enforcement[\s\n]+\(LE\),[\s\n]+and[\s\n]+counterintelligence[\s\n]+\(CI\)[\s\n]+investigations\.(?:[\n]+|(?:\\n)+)\-At[\s\n]+any[\s\n]+time,[\s\n]+the[\s\n]+USG[\s\n]+may[\s\n]+inspect[\s\n]+and[\s\n]+seize[\s\n]+data[\s\n]+stored[\s\n]+on[\s\n]+this[\s\n]+IS\.(?:[\n]+|(?:\\n)+)\-Communications[\s\n]+using,[\s\n]+or[\s\n]+data[\s\n]+stored[\s\n]+on,[\s\n]+this[\s\n]+IS[\s\n]+are[\s\n]+not[\s\n]+private,[\s\n]+are[\s\n]+subject[\s\n]+to[\s\n]+routine[\s\n]+monitoring,[\s\n]+interception,[\s\n]+and[\s\n]+search,[\s\n]+and[\s\n]+may[\s\n]+be[\s\n]+disclosed[\s\n]+or[\s\n]+used[\s\n]+for[\s\n]+any[\s\n]+USG\-authorized[\s\n]+purpose\.(?:[\n]+|(?:\\n)+)\-This[\s\n]+IS[\s\n]+includes[\s\n]+security[\s\n]+measures[\s\n]+\(e\.g\.,[\s\n]+authentication[\s\n]+and[\s\n]+access[\s\n]+controls\)[\s\n]+to[\s\n]+protect[\s\n]+USG[\s\n]+interests\-\-not[\s\n]+for[\s\n]+your[\s\n]+personal[\s\n]+benefit[\s\n]+or[\s\n]+privacy\.(?:[\n]+|(?:\\n)+)\-Notwithstanding[\s\n]+the[\s\n]+above,[\s\n]+using[\s\n]+this[\s\n]+IS[\s\n]+does[\s\n]+not[\s\n]+constitute[\s\n]+consent[\s\n]+to[\s\n]+PM,[\s\n]+LE[\s\n]+or[\s\n]+CI[\s\n]+investigative[\s\n]+searching[\s\n]+or[\s\n]+monitoring[\s\n]+of[\s\n]+the[\s\n]+content[\s\n]+of[\s\n]+privileged[\s\n]+communications,[\s\n]+or[\s\n]+work[\s\n]+product,[\s\n]+related[\s\n]+to[\s\n]+personal[\s\n]+representation[\s\n]+or[\s\n]+services[\s\n]+by[\s\n]+attorneys,[\s\n]+psychotherapists,[\s\n]+or[\s\n]+clergy,[\s\n]+and[\s\n]+their[\s\n]+assistants\.[\s\n]+Such[\s\n]+communications[\s\n]+and[\s\n]+work[\s\n]+product[\s\n]+are[\s\n]+private[\s\n]+and[\s\n]+confidential\.[\s\n]+See[\s\n]+User[\s\n]+Agreement[\s\n]+for[\s\n]+details\.|I've[\s\n]+read[\s\n]+\&[\s\n]+consent[\s\n]+to[\s\n]+terms[\s\n]+in[\s\n]+IS[\s\n]+user[\s\n]+agreem't\.)$ - ^You[\s\n]+are[\s\n]+accessing[\s\n]+a[\s\n]+U\.S\.[\s\n]+Government[\s\n]+\(USG\)[\s\n]+Information[\s\n]+System[\s\n]+\(IS\)[\s\n]+that[\s\n]+is[\s\n]+provided[\s\n]+for[\s\n]+USG\-authorized[\s\n]+use[\s\n]+only\.[\s\n]+By[\s\n]+using[\s\n]+this[\s\n]+IS[\s\n]+\(which[\s\n]+includes[\s\n]+any[\s\n]+device[\s\n]+attached[\s\n]+to[\s\n]+this[\s\n]+IS\),[\s\n]+you[\s\n]+consent[\s\n]+to[\s\n]+the[\s\n]+following[\s\n]+conditions\:(?:[\n]+|(?:\\n)+)\-The[\s\n]+USG[\s\n]+routinely[\s\n]+intercepts[\s\n]+and[\s\n]+monitors[\s\n]+communications[\s\n]+on[\s\n]+this[\s\n]+IS[\s\n]+for[\s\n]+purposes[\s\n]+including,[\s\n]+but[\s\n]+not[\s\n]+limited[\s\n]+to,[\s\n]+penetration[\s\n]+testing,[\s\n]+COMSEC[\s\n]+monitoring,[\s\n]+network[\s\n]+operations[\s\n]+and[\s\n]+defense,[\s\n]+personnel[\s\n]+misconduct[\s\n]+\(PM\),[\s\n]+law[\s\n]+enforcement[\s\n]+\(LE\),[\s\n]+and[\s\n]+counterintelligence[\s\n]+\(CI\)[\s\n]+investigations\.(?:[\n]+|(?:\\n)+)\-At[\s\n]+any[\s\n]+time,[\s\n]+the[\s\n]+USG[\s\n]+may[\s\n]+inspect[\s\n]+and[\s\n]+seize[\s\n]+data[\s\n]+stored[\s\n]+on[\s\n]+this[\s\n]+IS\.(?:[\n]+|(?:\\n)+)\-Communications[\s\n]+using,[\s\n]+or[\s\n]+data[\s\n]+stored[\s\n]+on,[\s\n]+this[\s\n]+IS[\s\n]+are[\s\n]+not[\s\n]+private,[\s\n]+are[\s\n]+subject[\s\n]+to[\s\n]+routine[\s\n]+monitoring,[\s\n]+interception,[\s\n]+and[\s\n]+search,[\s\n]+and[\s\n]+may[\s\n]+be[\s\n]+disclosed[\s\n]+or[\s\n]+used[\s\n]+for[\s\n]+any[\s\n]+USG\-authorized[\s\n]+purpose\.(?:[\n]+|(?:\\n)+)\-This[\s\n]+IS[\s\n]+includes[\s\n]+security[\s\n]+measures[\s\n]+\(e\.g\.,[\s\n]+authentication[\s\n]+and[\s\n]+access[\s\n]+controls\)[\s\n]+to[\s\n]+protect[\s\n]+USG[\s\n]+interests\-\-not[\s\n]+for[\s\n]+your[\s\n]+personal[\s\n]+benefit[\s\n]+or[\s\n]+privacy\.(?:[\n]+|(?:\\n)+)\-Notwithstanding[\s\n]+the[\s\n]+above,[\s\n]+using[\s\n]+this[\s\n]+IS[\s\n]+does[\s\n]+not[\s\n]+constitute[\s\n]+consent[\s\n]+to[\s\n]+PM,[\s\n]+LE[\s\n]+or[\s\n]+CI[\s\n]+investigative[\s\n]+searching[\s\n]+or[\s\n]+monitoring[\s\n]+of[\s\n]+the[\s\n]+content[\s\n]+of[\s\n]+privileged[\s\n]+communications,[\s\n]+or[\s\n]+work[\s\n]+product,[\s\n]+related[\s\n]+to[\s\n]+personal[\s\n]+representation[\s\n]+or[\s\n]+services[\s\n]+by[\s\n]+attorneys,[\s\n]+psychotherapists,[\s\n]+or[\s\n]+clergy,[\s\n]+and[\s\n]+their[\s\n]+assistants\.[\s\n]+Such[\s\n]+communications[\s\n]+and[\s\n]+work[\s\n]+product[\s\n]+are[\s\n]+private[\s\n]+and[\s\n]+confidential\.[\s\n]+See[\s\n]+User[\s\n]+Agreement[\s\n]+for[\s\n]+details\.$ - ^I've[\s\n]+read[\s\n]+\&[\s\n]+consent[\s\n]+to[\s\n]+terms[\s\n]+in[\s\n]+IS[\s\n]+user[\s\n]+agreem't\.$ - ^Use[\s\n]+of[\s\n]+this[\s\n]+or[\s\n]+any[\s\n]+other[\s\n]+DoD[\s\n]+interest[\s\n]+computer[\s\n]+system[\s\n]+constitutes[\s\n]+consent[\s\n]+to[\s\n]+monitoring[\s\n]+at[\s\n]+all[\s\n]+times\.[\s\n]+This[\s\n]+is[\s\n]+a[\s\n]+DoD[\s\n]+interest[\s\n]+computer[\s\n]+system\.[\s\n]+All[\s\n]+DoD[\s\n]+interest[\s\n]+computer[\s\n]+systems[\s\n]+and[\s\n]+related[\s\n]+equipment[\s\n]+are[\s\n]+intended[\s\n]+for[\s\n]+the[\s\n]+communication,[\s\n]+transmission,[\s\n]+processing,[\s\n]+and[\s\n]+storage[\s\n]+of[\s\n]+official[\s\n]+U\.S\.[\s\n]+Government[\s\n]+or[\s\n]+other[\s\n]+authorized[\s\n]+information[\s\n]+only\.[\s\n]+All[\s\n]+DoD[\s\n]+interest[\s\n]+computer[\s\n]+systems[\s\n]+are[\s\n]+subject[\s\n]+to[\s\n]+monitoring[\s\n]+at[\s\n]+all[\s\n]+times[\s\n]+to[\s\n]+ensure[\s\n]+proper[\s\n]+functioning[\s\n]+of[\s\n]+equipment[\s\n]+and[\s\n]+systems[\s\n]+including[\s\n]+security[\s\n]+devices[\s\n]+and[\s\n]+systems,[\s\n]+to[\s\n]+prevent[\s\n]+unauthorized[\s\n]+use[\s\n]+and[\s\n]+violations[\s\n]+of[\s\n]+statutes[\s\n]+and[\s\n]+security[\s\n]+regulations,[\s\n]+to[\s\n]+deter[\s\n]+criminal[\s\n]+activity,[\s\n]+and[\s\n]+for[\s\n]+other[\s\n]+similar[\s\n]+purposes\.[\s\n]+Any[\s\n]+user[\s\n]+of[\s\n]+a[\s\n]+DoD[\s\n]+interest[\s\n]+computer[\s\n]+system[\s\n]+should[\s\n]+be[\s\n]+aware[\s\n]+that[\s\n]+any[\s\n]+information[\s\n]+placed[\s\n]+in[\s\n]+the[\s\n]+system[\s\n]+is[\s\n]+subject[\s\n]+to[\s\n]+monitoring[\s\n]+and[\s\n]+is[\s\n]+not[\s\n]+subject[\s\n]+to[\s\n]+any[\s\n]+expectation[\s\n]+of[\s\n]+privacy\.[\s\n]+If[\s\n]+monitoring[\s\n]+of[\s\n]+this[\s\n]+or[\s\n]+any[\s\n]+other[\s\n]+DoD[\s\n]+interest[\s\n]+computer[\s\n]+system[\s\n]+reveals[\s\n]+possible[\s\n]+evidence[\s\n]+of[\s\n]+violation[\s\n]+of[\s\n]+criminal[\s\n]+statutes,[\s\n]+this[\s\n]+evidence[\s\n]+and[\s\n]+any[\s\n]+other[\s\n]+related[\s\n]+information,[\s\n]+including[\s\n]+identification[\s\n]+information[\s\n]+about[\s\n]+the[\s\n]+user,[\s\n]+may[\s\n]+be[\s\n]+provided[\s\n]+to[\s\n]+law[\s\n]+enforcement[\s\n]+officials\.[\s\n]+If[\s\n]+monitoring[\s\n]+of[\s\n]+this[\s\n]+or[\s\n]+any[\s\n]+other[\s\n]+DoD[\s\n]+interest[\s\n]+computer[\s\n]+systems[\s\n]+reveals[\s\n]+violations[\s\n]+of[\s\n]+security[\s\n]+regulations[\s\n]+or[\s\n]+unauthorized[\s\n]+use,[\s\n]+employees[\s\n]+who[\s\n]+violate[\s\n]+security[\s\n]+regulations[\s\n]+or[\s\n]+make[\s\n]+unauthorized[\s\n]+use[\s\n]+of[\s\n]+DoD[\s\n]+interest[\s\n]+computer[\s\n]+systems[\s\n]+are[\s\n]+subject[\s\n]+to[\s\n]+appropriate[\s\n]+disciplinary[\s\n]+action\.[\s\n]+Use[\s\n]+of[\s\n]+this[\s\n]+or[\s\n]+any[\s\n]+other[\s\n]+DoD[\s\n]+interest[\s\n]+computer[\s\n]+system[\s\n]+constitutes[\s\n]+consent[\s\n]+to[\s\n]+monitoring[\s\n]+at[\s\n]+all[\s\n]+times\.$ - ^\-\-[\s\n]+WARNING[\s\n]+\-\-[\s\n]+This[\s\n]+system[\s\n]+is[\s\n]+for[\s\n]+the[\s\n]+use[\s\n]+of[\s\n]+authorized[\s\n]+users[\s\n]+only\.[\s\n]+Individuals[\s\n]+using[\s\n]+this[\s\n]+computer[\s\n]+system[\s\n]+without[\s\n]+authority[\s\n]+or[\s\n]+in[\s\n]+excess[\s\n]+of[\s\n]+their[\s\n]+authority[\s\n]+are[\s\n]+subject[\s\n]+to[\s\n]+having[\s\n]+all[\s\n]+their[\s\n]+activities[\s\n]+on[\s\n]+this[\s\n]+system[\s\n]+monitored[\s\n]+and[\s\n]+recorded[\s\n]+by[\s\n]+system[\s\n]+personnel\.[\s\n]+Anyone[\s\n]+using[\s\n]+this[\s\n]+system[\s\n]+expressly[\s\n]+consents[\s\n]+to[\s\n]+such[\s\n]+monitoring[\s\n]+and[\s\n]+is[\s\n]+advised[\s\n]+that[\s\n]+if[\s\n]+such[\s\n]+monitoring[\s\n]+reveals[\s\n]+possible[\s\n]+evidence[\s\n]+of[\s\n]+criminal[\s\n]+activity[\s\n]+system[\s\n]+personal[\s\n]+may[\s\n]+provide[\s\n]+the[\s\n]+evidence[\s\n]+of[\s\n]+such[\s\n]+monitoring[\s\n]+to[\s\n]+law[\s\n]+enforcement[\s\n]+officials\.$ - ^Authorized[\s\n]+uses[\s\n]+only\.[\s\n]+All[\s\n]+activity[\s\n]+may[\s\n]+be[\s\n]+monitored[\s\n]+and[\s\n]+reported\.$ - - - Modify the System Login Banner - +consent to monitoring. + + Login Banner Verbiage + Enter an appropriate login banner for your organization. Please note that new lines must +be expressed by the '\n' character and special characters like parentheses and quotation marks must be escaped with '\\'. + ^(Authorized[\s\n]+users[\s\n]+only\.[\s\n]+All[\s\n]+activity[\s\n]+may[\s\n]+be[\s\n]+monitored[\s\n]+and[\s\n]+reported\.|^(?!.*(\\|fedora|rhel|sle|ubuntu)).*)$ + ^Authorized[\s\n]+users[\s\n]+only\.[\s\n]+All[\s\n]+activity[\s\n]+may[\s\n]+be[\s\n]+monitored[\s\n]+and[\s\n]+reported\.$ + ^(You[\s\n]+are[\s\n]+accessing[\s\n]+a[\s\n]+U\.S\.[\s\n]+Government[\s\n]+\(USG\)[\s\n]+Information[\s\n]+System[\s\n]+\(IS\)[\s\n]+that[\s\n]+is[\s\n]+provided[\s\n]+for[\s\n]+USG\-authorized[\s\n]+use[\s\n]+only\.[\s\n]+By[\s\n]+using[\s\n]+this[\s\n]+IS[\s\n]+\(which[\s\n]+includes[\s\n]+any[\s\n]+device[\s\n]+attached[\s\n]+to[\s\n]+this[\s\n]+IS\),[\s\n]+you[\s\n]+consent[\s\n]+to[\s\n]+the[\s\n]+following[\s\n]+conditions\:(?:[\n]+|(?:\\n)+)\-The[\s\n]+USG[\s\n]+routinely[\s\n]+intercepts[\s\n]+and[\s\n]+monitors[\s\n]+communications[\s\n]+on[\s\n]+this[\s\n]+IS[\s\n]+for[\s\n]+purposes[\s\n]+including,[\s\n]+but[\s\n]+not[\s\n]+limited[\s\n]+to,[\s\n]+penetration[\s\n]+testing,[\s\n]+COMSEC[\s\n]+monitoring,[\s\n]+network[\s\n]+operations[\s\n]+and[\s\n]+defense,[\s\n]+personnel[\s\n]+misconduct[\s\n]+\(PM\),[\s\n]+law[\s\n]+enforcement[\s\n]+\(LE\),[\s\n]+and[\s\n]+counterintelligence[\s\n]+\(CI\)[\s\n]+investigations\.(?:[\n]+|(?:\\n)+)\-At[\s\n]+any[\s\n]+time,[\s\n]+the[\s\n]+USG[\s\n]+may[\s\n]+inspect[\s\n]+and[\s\n]+seize[\s\n]+data[\s\n]+stored[\s\n]+on[\s\n]+this[\s\n]+IS\.(?:[\n]+|(?:\\n)+)\-Communications[\s\n]+using,[\s\n]+or[\s\n]+data[\s\n]+stored[\s\n]+on,[\s\n]+this[\s\n]+IS[\s\n]+are[\s\n]+not[\s\n]+private,[\s\n]+are[\s\n]+subject[\s\n]+to[\s\n]+routine[\s\n]+monitoring,[\s\n]+interception,[\s\n]+and[\s\n]+search,[\s\n]+and[\s\n]+may[\s\n]+be[\s\n]+disclosed[\s\n]+or[\s\n]+used[\s\n]+for[\s\n]+any[\s\n]+USG\-authorized[\s\n]+purpose\.(?:[\n]+|(?:\\n)+)\-This[\s\n]+IS[\s\n]+includes[\s\n]+security[\s\n]+measures[\s\n]+\(e\.g\.,[\s\n]+authentication[\s\n]+and[\s\n]+access[\s\n]+controls\)[\s\n]+to[\s\n]+protect[\s\n]+USG[\s\n]+interests\-\-not[\s\n]+for[\s\n]+your[\s\n]+personal[\s\n]+benefit[\s\n]+or[\s\n]+privacy\.(?:[\n]+|(?:\\n)+)\-Notwithstanding[\s\n]+the[\s\n]+above,[\s\n]+using[\s\n]+this[\s\n]+IS[\s\n]+does[\s\n]+not[\s\n]+constitute[\s\n]+consent[\s\n]+to[\s\n]+PM,[\s\n]+LE[\s\n]+or[\s\n]+CI[\s\n]+investigative[\s\n]+searching[\s\n]+or[\s\n]+monitoring[\s\n]+of[\s\n]+the[\s\n]+content[\s\n]+of[\s\n]+privileged[\s\n]+communications,[\s\n]+or[\s\n]+work[\s\n]+product,[\s\n]+related[\s\n]+to[\s\n]+personal[\s\n]+representation[\s\n]+or[\s\n]+services[\s\n]+by[\s\n]+attorneys,[\s\n]+psychotherapists,[\s\n]+or[\s\n]+clergy,[\s\n]+and[\s\n]+their[\s\n]+assistants\.[\s\n]+Such[\s\n]+communications[\s\n]+and[\s\n]+work[\s\n]+product[\s\n]+are[\s\n]+private[\s\n]+and[\s\n]+confidential\.[\s\n]+See[\s\n]+User[\s\n]+Agreement[\s\n]+for[\s\n]+details\.|I've[\s\n]+read[\s\n]+\&[\s\n]+consent[\s\n]+to[\s\n]+terms[\s\n]+in[\s\n]+IS[\s\n]+user[\s\n]+agreem't\.)$ + ^You[\s\n]+are[\s\n]+accessing[\s\n]+a[\s\n]+U\.S\.[\s\n]+Government[\s\n]+\(USG\)[\s\n]+Information[\s\n]+System[\s\n]+\(IS\)[\s\n]+that[\s\n]+is[\s\n]+provided[\s\n]+for[\s\n]+USG\-authorized[\s\n]+use[\s\n]+only\.[\s\n]+By[\s\n]+using[\s\n]+this[\s\n]+IS[\s\n]+\(which[\s\n]+includes[\s\n]+any[\s\n]+device[\s\n]+attached[\s\n]+to[\s\n]+this[\s\n]+IS\),[\s\n]+you[\s\n]+consent[\s\n]+to[\s\n]+the[\s\n]+following[\s\n]+conditions\:(?:[\n]+|(?:\\n)+)\-The[\s\n]+USG[\s\n]+routinely[\s\n]+intercepts[\s\n]+and[\s\n]+monitors[\s\n]+communications[\s\n]+on[\s\n]+this[\s\n]+IS[\s\n]+for[\s\n]+purposes[\s\n]+including,[\s\n]+but[\s\n]+not[\s\n]+limited[\s\n]+to,[\s\n]+penetration[\s\n]+testing,[\s\n]+COMSEC[\s\n]+monitoring,[\s\n]+network[\s\n]+operations[\s\n]+and[\s\n]+defense,[\s\n]+personnel[\s\n]+misconduct[\s\n]+\(PM\),[\s\n]+law[\s\n]+enforcement[\s\n]+\(LE\),[\s\n]+and[\s\n]+counterintelligence[\s\n]+\(CI\)[\s\n]+investigations\.(?:[\n]+|(?:\\n)+)\-At[\s\n]+any[\s\n]+time,[\s\n]+the[\s\n]+USG[\s\n]+may[\s\n]+inspect[\s\n]+and[\s\n]+seize[\s\n]+data[\s\n]+stored[\s\n]+on[\s\n]+this[\s\n]+IS\.(?:[\n]+|(?:\\n)+)\-Communications[\s\n]+using,[\s\n]+or[\s\n]+data[\s\n]+stored[\s\n]+on,[\s\n]+this[\s\n]+IS[\s\n]+are[\s\n]+not[\s\n]+private,[\s\n]+are[\s\n]+subject[\s\n]+to[\s\n]+routine[\s\n]+monitoring,[\s\n]+interception,[\s\n]+and[\s\n]+search,[\s\n]+and[\s\n]+may[\s\n]+be[\s\n]+disclosed[\s\n]+or[\s\n]+used[\s\n]+for[\s\n]+any[\s\n]+USG\-authorized[\s\n]+purpose\.(?:[\n]+|(?:\\n)+)\-This[\s\n]+IS[\s\n]+includes[\s\n]+security[\s\n]+measures[\s\n]+\(e\.g\.,[\s\n]+authentication[\s\n]+and[\s\n]+access[\s\n]+controls\)[\s\n]+to[\s\n]+protect[\s\n]+USG[\s\n]+interests\-\-not[\s\n]+for[\s\n]+your[\s\n]+personal[\s\n]+benefit[\s\n]+or[\s\n]+privacy\.(?:[\n]+|(?:\\n)+)\-Notwithstanding[\s\n]+the[\s\n]+above,[\s\n]+using[\s\n]+this[\s\n]+IS[\s\n]+does[\s\n]+not[\s\n]+constitute[\s\n]+consent[\s\n]+to[\s\n]+PM,[\s\n]+LE[\s\n]+or[\s\n]+CI[\s\n]+investigative[\s\n]+searching[\s\n]+or[\s\n]+monitoring[\s\n]+of[\s\n]+the[\s\n]+content[\s\n]+of[\s\n]+privileged[\s\n]+communications,[\s\n]+or[\s\n]+work[\s\n]+product,[\s\n]+related[\s\n]+to[\s\n]+personal[\s\n]+representation[\s\n]+or[\s\n]+services[\s\n]+by[\s\n]+attorneys,[\s\n]+psychotherapists,[\s\n]+or[\s\n]+clergy,[\s\n]+and[\s\n]+their[\s\n]+assistants\.[\s\n]+Such[\s\n]+communications[\s\n]+and[\s\n]+work[\s\n]+product[\s\n]+are[\s\n]+private[\s\n]+and[\s\n]+confidential\.[\s\n]+See[\s\n]+User[\s\n]+Agreement[\s\n]+for[\s\n]+details\.$ + ^I've[\s\n]+read[\s\n]+\&[\s\n]+consent[\s\n]+to[\s\n]+terms[\s\n]+in[\s\n]+IS[\s\n]+user[\s\n]+agreem't\.$ + ^Use[\s\n]+of[\s\n]+this[\s\n]+or[\s\n]+any[\s\n]+other[\s\n]+DoD[\s\n]+interest[\s\n]+computer[\s\n]+system[\s\n]+constitutes[\s\n]+consent[\s\n]+to[\s\n]+monitoring[\s\n]+at[\s\n]+all[\s\n]+times\.[\s\n]+This[\s\n]+is[\s\n]+a[\s\n]+DoD[\s\n]+interest[\s\n]+computer[\s\n]+system\.[\s\n]+All[\s\n]+DoD[\s\n]+interest[\s\n]+computer[\s\n]+systems[\s\n]+and[\s\n]+related[\s\n]+equipment[\s\n]+are[\s\n]+intended[\s\n]+for[\s\n]+the[\s\n]+communication,[\s\n]+transmission,[\s\n]+processing,[\s\n]+and[\s\n]+storage[\s\n]+of[\s\n]+official[\s\n]+U\.S\.[\s\n]+Government[\s\n]+or[\s\n]+other[\s\n]+authorized[\s\n]+information[\s\n]+only\.[\s\n]+All[\s\n]+DoD[\s\n]+interest[\s\n]+computer[\s\n]+systems[\s\n]+are[\s\n]+subject[\s\n]+to[\s\n]+monitoring[\s\n]+at[\s\n]+all[\s\n]+times[\s\n]+to[\s\n]+ensure[\s\n]+proper[\s\n]+functioning[\s\n]+of[\s\n]+equipment[\s\n]+and[\s\n]+systems[\s\n]+including[\s\n]+security[\s\n]+devices[\s\n]+and[\s\n]+systems,[\s\n]+to[\s\n]+prevent[\s\n]+unauthorized[\s\n]+use[\s\n]+and[\s\n]+violations[\s\n]+of[\s\n]+statutes[\s\n]+and[\s\n]+security[\s\n]+regulations,[\s\n]+to[\s\n]+deter[\s\n]+criminal[\s\n]+activity,[\s\n]+and[\s\n]+for[\s\n]+other[\s\n]+similar[\s\n]+purposes\.[\s\n]+Any[\s\n]+user[\s\n]+of[\s\n]+a[\s\n]+DoD[\s\n]+interest[\s\n]+computer[\s\n]+system[\s\n]+should[\s\n]+be[\s\n]+aware[\s\n]+that[\s\n]+any[\s\n]+information[\s\n]+placed[\s\n]+in[\s\n]+the[\s\n]+system[\s\n]+is[\s\n]+subject[\s\n]+to[\s\n]+monitoring[\s\n]+and[\s\n]+is[\s\n]+not[\s\n]+subject[\s\n]+to[\s\n]+any[\s\n]+expectation[\s\n]+of[\s\n]+privacy\.[\s\n]+If[\s\n]+monitoring[\s\n]+of[\s\n]+this[\s\n]+or[\s\n]+any[\s\n]+other[\s\n]+DoD[\s\n]+interest[\s\n]+computer[\s\n]+system[\s\n]+reveals[\s\n]+possible[\s\n]+evidence[\s\n]+of[\s\n]+violation[\s\n]+of[\s\n]+criminal[\s\n]+statutes,[\s\n]+this[\s\n]+evidence[\s\n]+and[\s\n]+any[\s\n]+other[\s\n]+related[\s\n]+information,[\s\n]+including[\s\n]+identification[\s\n]+information[\s\n]+about[\s\n]+the[\s\n]+user,[\s\n]+may[\s\n]+be[\s\n]+provided[\s\n]+to[\s\n]+law[\s\n]+enforcement[\s\n]+officials\.[\s\n]+If[\s\n]+monitoring[\s\n]+of[\s\n]+this[\s\n]+or[\s\n]+any[\s\n]+other[\s\n]+DoD[\s\n]+interest[\s\n]+computer[\s\n]+systems[\s\n]+reveals[\s\n]+violations[\s\n]+of[\s\n]+security[\s\n]+regulations[\s\n]+or[\s\n]+unauthorized[\s\n]+use,[\s\n]+employees[\s\n]+who[\s\n]+violate[\s\n]+security[\s\n]+regulations[\s\n]+or[\s\n]+make[\s\n]+unauthorized[\s\n]+use[\s\n]+of[\s\n]+DoD[\s\n]+interest[\s\n]+computer[\s\n]+systems[\s\n]+are[\s\n]+subject[\s\n]+to[\s\n]+appropriate[\s\n]+disciplinary[\s\n]+action\.[\s\n]+Use[\s\n]+of[\s\n]+this[\s\n]+or[\s\n]+any[\s\n]+other[\s\n]+DoD[\s\n]+interest[\s\n]+computer[\s\n]+system[\s\n]+constitutes[\s\n]+consent[\s\n]+to[\s\n]+monitoring[\s\n]+at[\s\n]+all[\s\n]+times\.$ + ^\-\-[\s\n]+WARNING[\s\n]+\-\-[\s\n]+This[\s\n]+system[\s\n]+is[\s\n]+for[\s\n]+the[\s\n]+use[\s\n]+of[\s\n]+authorized[\s\n]+users[\s\n]+only\.[\s\n]+Individuals[\s\n]+using[\s\n]+this[\s\n]+computer[\s\n]+system[\s\n]+without[\s\n]+authority[\s\n]+or[\s\n]+in[\s\n]+excess[\s\n]+of[\s\n]+their[\s\n]+authority[\s\n]+are[\s\n]+subject[\s\n]+to[\s\n]+having[\s\n]+all[\s\n]+their[\s\n]+activities[\s\n]+on[\s\n]+this[\s\n]+system[\s\n]+monitored[\s\n]+and[\s\n]+recorded[\s\n]+by[\s\n]+system[\s\n]+personnel\.[\s\n]+Anyone[\s\n]+using[\s\n]+this[\s\n]+system[\s\n]+expressly[\s\n]+consents[\s\n]+to[\s\n]+such[\s\n]+monitoring[\s\n]+and[\s\n]+is[\s\n]+advised[\s\n]+that[\s\n]+if[\s\n]+such[\s\n]+monitoring[\s\n]+reveals[\s\n]+possible[\s\n]+evidence[\s\n]+of[\s\n]+criminal[\s\n]+activity[\s\n]+system[\s\n]+personal[\s\n]+may[\s\n]+provide[\s\n]+the[\s\n]+evidence[\s\n]+of[\s\n]+such[\s\n]+monitoring[\s\n]+to[\s\n]+law[\s\n]+enforcement[\s\n]+officials\.$ + ^Authorized[\s\n]+users[\s\n]+only\.[\s\n]+All[\s\n]+activity[\s\n]+may[\s\n]+be[\s\n]+monitored[\s\n]+and[\s\n]+reported\.$ + + + MotD Banner Verbiage + Enter an appropriate login banner for your organization. Please note that new lines must +be expressed by the '\n' character and special characters like parentheses and quotation marks must be escaped with '\\'. + ^(Authorized[\s\n]+uses[\s\n]+only\.[\s\n]+All[\s\n]+activity[\s\n]+may[\s\n]+be[\s\n]+monitored[\s\n]+and[\s\n]+reported\.|^(?!.*(\\|fedora|rhel|sle|ubuntu)).*)$ + ^Authorized[\s\n]+uses[\s\n]+only\.[\s\n]+All[\s\n]+activity[\s\n]+may[\s\n]+be[\s\n]+monitored[\s\n]+and[\s\n]+reported\.$ + ^(You[\s\n]+are[\s\n]+accessing[\s\n]+a[\s\n]+U\.S\.[\s\n]+Government[\s\n]+\(USG\)[\s\n]+Information[\s\n]+System[\s\n]+\(IS\)[\s\n]+that[\s\n]+is[\s\n]+provided[\s\n]+for[\s\n]+USG\-authorized[\s\n]+use[\s\n]+only\.[\s\n]+By[\s\n]+using[\s\n]+this[\s\n]+IS[\s\n]+\(which[\s\n]+includes[\s\n]+any[\s\n]+device[\s\n]+attached[\s\n]+to[\s\n]+this[\s\n]+IS\),[\s\n]+you[\s\n]+consent[\s\n]+to[\s\n]+the[\s\n]+following[\s\n]+conditions\:(?:[\n]+|(?:\\n)+)\-The[\s\n]+USG[\s\n]+routinely[\s\n]+intercepts[\s\n]+and[\s\n]+monitors[\s\n]+communications[\s\n]+on[\s\n]+this[\s\n]+IS[\s\n]+for[\s\n]+purposes[\s\n]+including,[\s\n]+but[\s\n]+not[\s\n]+limited[\s\n]+to,[\s\n]+penetration[\s\n]+testing,[\s\n]+COMSEC[\s\n]+monitoring,[\s\n]+network[\s\n]+operations[\s\n]+and[\s\n]+defense,[\s\n]+personnel[\s\n]+misconduct[\s\n]+\(PM\),[\s\n]+law[\s\n]+enforcement[\s\n]+\(LE\),[\s\n]+and[\s\n]+counterintelligence[\s\n]+\(CI\)[\s\n]+investigations\.(?:[\n]+|(?:\\n)+)\-At[\s\n]+any[\s\n]+time,[\s\n]+the[\s\n]+USG[\s\n]+may[\s\n]+inspect[\s\n]+and[\s\n]+seize[\s\n]+data[\s\n]+stored[\s\n]+on[\s\n]+this[\s\n]+IS\.(?:[\n]+|(?:\\n)+)\-Communications[\s\n]+using,[\s\n]+or[\s\n]+data[\s\n]+stored[\s\n]+on,[\s\n]+this[\s\n]+IS[\s\n]+are[\s\n]+not[\s\n]+private,[\s\n]+are[\s\n]+subject[\s\n]+to[\s\n]+routine[\s\n]+monitoring,[\s\n]+interception,[\s\n]+and[\s\n]+search,[\s\n]+and[\s\n]+may[\s\n]+be[\s\n]+disclosed[\s\n]+or[\s\n]+used[\s\n]+for[\s\n]+any[\s\n]+USG\-authorized[\s\n]+purpose\.(?:[\n]+|(?:\\n)+)\-This[\s\n]+IS[\s\n]+includes[\s\n]+security[\s\n]+measures[\s\n]+\(e\.g\.,[\s\n]+authentication[\s\n]+and[\s\n]+access[\s\n]+controls\)[\s\n]+to[\s\n]+protect[\s\n]+USG[\s\n]+interests\-\-not[\s\n]+for[\s\n]+your[\s\n]+personal[\s\n]+benefit[\s\n]+or[\s\n]+privacy\.(?:[\n]+|(?:\\n)+)\-Notwithstanding[\s\n]+the[\s\n]+above,[\s\n]+using[\s\n]+this[\s\n]+IS[\s\n]+does[\s\n]+not[\s\n]+constitute[\s\n]+consent[\s\n]+to[\s\n]+PM,[\s\n]+LE[\s\n]+or[\s\n]+CI[\s\n]+investigative[\s\n]+searching[\s\n]+or[\s\n]+monitoring[\s\n]+of[\s\n]+the[\s\n]+content[\s\n]+of[\s\n]+privileged[\s\n]+communications,[\s\n]+or[\s\n]+work[\s\n]+product,[\s\n]+related[\s\n]+to[\s\n]+personal[\s\n]+representation[\s\n]+or[\s\n]+services[\s\n]+by[\s\n]+attorneys,[\s\n]+psychotherapists,[\s\n]+or[\s\n]+clergy,[\s\n]+and[\s\n]+their[\s\n]+assistants\.[\s\n]+Such[\s\n]+communications[\s\n]+and[\s\n]+work[\s\n]+product[\s\n]+are[\s\n]+private[\s\n]+and[\s\n]+confidential\.[\s\n]+See[\s\n]+User[\s\n]+Agreement[\s\n]+for[\s\n]+details\.|I've[\s\n]+read[\s\n]+\&[\s\n]+consent[\s\n]+to[\s\n]+terms[\s\n]+in[\s\n]+IS[\s\n]+user[\s\n]+agreem't\.)$ + ^You[\s\n]+are[\s\n]+accessing[\s\n]+a[\s\n]+U\.S\.[\s\n]+Government[\s\n]+\(USG\)[\s\n]+Information[\s\n]+System[\s\n]+\(IS\)[\s\n]+that[\s\n]+is[\s\n]+provided[\s\n]+for[\s\n]+USG\-authorized[\s\n]+use[\s\n]+only\.[\s\n]+By[\s\n]+using[\s\n]+this[\s\n]+IS[\s\n]+\(which[\s\n]+includes[\s\n]+any[\s\n]+device[\s\n]+attached[\s\n]+to[\s\n]+this[\s\n]+IS\),[\s\n]+you[\s\n]+consent[\s\n]+to[\s\n]+the[\s\n]+following[\s\n]+conditions\:(?:[\n]+|(?:\\n)+)\-The[\s\n]+USG[\s\n]+routinely[\s\n]+intercepts[\s\n]+and[\s\n]+monitors[\s\n]+communications[\s\n]+on[\s\n]+this[\s\n]+IS[\s\n]+for[\s\n]+purposes[\s\n]+including,[\s\n]+but[\s\n]+not[\s\n]+limited[\s\n]+to,[\s\n]+penetration[\s\n]+testing,[\s\n]+COMSEC[\s\n]+monitoring,[\s\n]+network[\s\n]+operations[\s\n]+and[\s\n]+defense,[\s\n]+personnel[\s\n]+misconduct[\s\n]+\(PM\),[\s\n]+law[\s\n]+enforcement[\s\n]+\(LE\),[\s\n]+and[\s\n]+counterintelligence[\s\n]+\(CI\)[\s\n]+investigations\.(?:[\n]+|(?:\\n)+)\-At[\s\n]+any[\s\n]+time,[\s\n]+the[\s\n]+USG[\s\n]+may[\s\n]+inspect[\s\n]+and[\s\n]+seize[\s\n]+data[\s\n]+stored[\s\n]+on[\s\n]+this[\s\n]+IS\.(?:[\n]+|(?:\\n)+)\-Communications[\s\n]+using,[\s\n]+or[\s\n]+data[\s\n]+stored[\s\n]+on,[\s\n]+this[\s\n]+IS[\s\n]+are[\s\n]+not[\s\n]+private,[\s\n]+are[\s\n]+subject[\s\n]+to[\s\n]+routine[\s\n]+monitoring,[\s\n]+interception,[\s\n]+and[\s\n]+search,[\s\n]+and[\s\n]+may[\s\n]+be[\s\n]+disclosed[\s\n]+or[\s\n]+used[\s\n]+for[\s\n]+any[\s\n]+USG\-authorized[\s\n]+purpose\.(?:[\n]+|(?:\\n)+)\-This[\s\n]+IS[\s\n]+includes[\s\n]+security[\s\n]+measures[\s\n]+\(e\.g\.,[\s\n]+authentication[\s\n]+and[\s\n]+access[\s\n]+controls\)[\s\n]+to[\s\n]+protect[\s\n]+USG[\s\n]+interests\-\-not[\s\n]+for[\s\n]+your[\s\n]+personal[\s\n]+benefit[\s\n]+or[\s\n]+privacy\.(?:[\n]+|(?:\\n)+)\-Notwithstanding[\s\n]+the[\s\n]+above,[\s\n]+using[\s\n]+this[\s\n]+IS[\s\n]+does[\s\n]+not[\s\n]+constitute[\s\n]+consent[\s\n]+to[\s\n]+PM,[\s\n]+LE[\s\n]+or[\s\n]+CI[\s\n]+investigative[\s\n]+searching[\s\n]+or[\s\n]+monitoring[\s\n]+of[\s\n]+the[\s\n]+content[\s\n]+of[\s\n]+privileged[\s\n]+communications,[\s\n]+or[\s\n]+work[\s\n]+product,[\s\n]+related[\s\n]+to[\s\n]+personal[\s\n]+representation[\s\n]+or[\s\n]+services[\s\n]+by[\s\n]+attorneys,[\s\n]+psychotherapists,[\s\n]+or[\s\n]+clergy,[\s\n]+and[\s\n]+their[\s\n]+assistants\.[\s\n]+Such[\s\n]+communications[\s\n]+and[\s\n]+work[\s\n]+product[\s\n]+are[\s\n]+private[\s\n]+and[\s\n]+confidential\.[\s\n]+See[\s\n]+User[\s\n]+Agreement[\s\n]+for[\s\n]+details\.$ + ^I've[\s\n]+read[\s\n]+\&[\s\n]+consent[\s\n]+to[\s\n]+terms[\s\n]+in[\s\n]+IS[\s\n]+user[\s\n]+agreem't\.$ + ^Use[\s\n]+of[\s\n]+this[\s\n]+or[\s\n]+any[\s\n]+other[\s\n]+DoD[\s\n]+interest[\s\n]+computer[\s\n]+system[\s\n]+constitutes[\s\n]+consent[\s\n]+to[\s\n]+monitoring[\s\n]+at[\s\n]+all[\s\n]+times\.[\s\n]+This[\s\n]+is[\s\n]+a[\s\n]+DoD[\s\n]+interest[\s\n]+computer[\s\n]+system\.[\s\n]+All[\s\n]+DoD[\s\n]+interest[\s\n]+computer[\s\n]+systems[\s\n]+and[\s\n]+related[\s\n]+equipment[\s\n]+are[\s\n]+intended[\s\n]+for[\s\n]+the[\s\n]+communication,[\s\n]+transmission,[\s\n]+processing,[\s\n]+and[\s\n]+storage[\s\n]+of[\s\n]+official[\s\n]+U\.S\.[\s\n]+Government[\s\n]+or[\s\n]+other[\s\n]+authorized[\s\n]+information[\s\n]+only\.[\s\n]+All[\s\n]+DoD[\s\n]+interest[\s\n]+computer[\s\n]+systems[\s\n]+are[\s\n]+subject[\s\n]+to[\s\n]+monitoring[\s\n]+at[\s\n]+all[\s\n]+times[\s\n]+to[\s\n]+ensure[\s\n]+proper[\s\n]+functioning[\s\n]+of[\s\n]+equipment[\s\n]+and[\s\n]+systems[\s\n]+including[\s\n]+security[\s\n]+devices[\s\n]+and[\s\n]+systems,[\s\n]+to[\s\n]+prevent[\s\n]+unauthorized[\s\n]+use[\s\n]+and[\s\n]+violations[\s\n]+of[\s\n]+statutes[\s\n]+and[\s\n]+security[\s\n]+regulations,[\s\n]+to[\s\n]+deter[\s\n]+criminal[\s\n]+activity,[\s\n]+and[\s\n]+for[\s\n]+other[\s\n]+similar[\s\n]+purposes\.[\s\n]+Any[\s\n]+user[\s\n]+of[\s\n]+a[\s\n]+DoD[\s\n]+interest[\s\n]+computer[\s\n]+system[\s\n]+should[\s\n]+be[\s\n]+aware[\s\n]+that[\s\n]+any[\s\n]+information[\s\n]+placed[\s\n]+in[\s\n]+the[\s\n]+system[\s\n]+is[\s\n]+subject[\s\n]+to[\s\n]+monitoring[\s\n]+and[\s\n]+is[\s\n]+not[\s\n]+subject[\s\n]+to[\s\n]+any[\s\n]+expectation[\s\n]+of[\s\n]+privacy\.[\s\n]+If[\s\n]+monitoring[\s\n]+of[\s\n]+this[\s\n]+or[\s\n]+any[\s\n]+other[\s\n]+DoD[\s\n]+interest[\s\n]+computer[\s\n]+system[\s\n]+reveals[\s\n]+possible[\s\n]+evidence[\s\n]+of[\s\n]+violation[\s\n]+of[\s\n]+criminal[\s\n]+statutes,[\s\n]+this[\s\n]+evidence[\s\n]+and[\s\n]+any[\s\n]+other[\s\n]+related[\s\n]+information,[\s\n]+including[\s\n]+identification[\s\n]+information[\s\n]+about[\s\n]+the[\s\n]+user,[\s\n]+may[\s\n]+be[\s\n]+provided[\s\n]+to[\s\n]+law[\s\n]+enforcement[\s\n]+officials\.[\s\n]+If[\s\n]+monitoring[\s\n]+of[\s\n]+this[\s\n]+or[\s\n]+any[\s\n]+other[\s\n]+DoD[\s\n]+interest[\s\n]+computer[\s\n]+systems[\s\n]+reveals[\s\n]+violations[\s\n]+of[\s\n]+security[\s\n]+regulations[\s\n]+or[\s\n]+unauthorized[\s\n]+use,[\s\n]+employees[\s\n]+who[\s\n]+violate[\s\n]+security[\s\n]+regulations[\s\n]+or[\s\n]+make[\s\n]+unauthorized[\s\n]+use[\s\n]+of[\s\n]+DoD[\s\n]+interest[\s\n]+computer[\s\n]+systems[\s\n]+are[\s\n]+subject[\s\n]+to[\s\n]+appropriate[\s\n]+disciplinary[\s\n]+action\.[\s\n]+Use[\s\n]+of[\s\n]+this[\s\n]+or[\s\n]+any[\s\n]+other[\s\n]+DoD[\s\n]+interest[\s\n]+computer[\s\n]+system[\s\n]+constitutes[\s\n]+consent[\s\n]+to[\s\n]+monitoring[\s\n]+at[\s\n]+all[\s\n]+times\.$ + ^\-\-[\s\n]+WARNING[\s\n]+\-\-[\s\n]+This[\s\n]+system[\s\n]+is[\s\n]+for[\s\n]+the[\s\n]+use[\s\n]+of[\s\n]+authorized[\s\n]+users[\s\n]+only\.[\s\n]+Individuals[\s\n]+using[\s\n]+this[\s\n]+computer[\s\n]+system[\s\n]+without[\s\n]+authority[\s\n]+or[\s\n]+in[\s\n]+excess[\s\n]+of[\s\n]+their[\s\n]+authority[\s\n]+are[\s\n]+subject[\s\n]+to[\s\n]+having[\s\n]+all[\s\n]+their[\s\n]+activities[\s\n]+on[\s\n]+this[\s\n]+system[\s\n]+monitored[\s\n]+and[\s\n]+recorded[\s\n]+by[\s\n]+system[\s\n]+personnel\.[\s\n]+Anyone[\s\n]+using[\s\n]+this[\s\n]+system[\s\n]+expressly[\s\n]+consents[\s\n]+to[\s\n]+such[\s\n]+monitoring[\s\n]+and[\s\n]+is[\s\n]+advised[\s\n]+that[\s\n]+if[\s\n]+such[\s\n]+monitoring[\s\n]+reveals[\s\n]+possible[\s\n]+evidence[\s\n]+of[\s\n]+criminal[\s\n]+activity[\s\n]+system[\s\n]+personal[\s\n]+may[\s\n]+provide[\s\n]+the[\s\n]+evidence[\s\n]+of[\s\n]+such[\s\n]+monitoring[\s\n]+to[\s\n]+law[\s\n]+enforcement[\s\n]+officials\.$ + ^Authorized[\s\n]+uses[\s\n]+only\.[\s\n]+All[\s\n]+activity[\s\n]+may[\s\n]+be[\s\n]+monitored[\s\n]+and[\s\n]+reported\.$ + + + Remote Login Banner Verbiage + Enter an appropriate login banner for your organization. Please note that new lines must +be expressed by the '\n' character and special characters like parentheses and quotation marks must be escaped with '\\'. + ^(Authorized[\s\n]+uses[\s\n]+only\.[\s\n]+All[\s\n]+activity[\s\n]+may[\s\n]+be[\s\n]+monitored[\s\n]+and[\s\n]+reported\.|^(?!.*(\\|fedora|rhel|sle|ubuntu)).*)$ + ^Authorized[\s\n]+uses[\s\n]+only\.[\s\n]+All[\s\n]+activity[\s\n]+may[\s\n]+be[\s\n]+monitored[\s\n]+and[\s\n]+reported\.$ + ^(You[\s\n]+are[\s\n]+accessing[\s\n]+a[\s\n]+U\.S\.[\s\n]+Government[\s\n]+\(USG\)[\s\n]+Information[\s\n]+System[\s\n]+\(IS\)[\s\n]+that[\s\n]+is[\s\n]+provided[\s\n]+for[\s\n]+USG\-authorized[\s\n]+use[\s\n]+only\.[\s\n]+By[\s\n]+using[\s\n]+this[\s\n]+IS[\s\n]+\(which[\s\n]+includes[\s\n]+any[\s\n]+device[\s\n]+attached[\s\n]+to[\s\n]+this[\s\n]+IS\),[\s\n]+you[\s\n]+consent[\s\n]+to[\s\n]+the[\s\n]+following[\s\n]+conditions\:(?:[\n]+|(?:\\n)+)\-The[\s\n]+USG[\s\n]+routinely[\s\n]+intercepts[\s\n]+and[\s\n]+monitors[\s\n]+communications[\s\n]+on[\s\n]+this[\s\n]+IS[\s\n]+for[\s\n]+purposes[\s\n]+including,[\s\n]+but[\s\n]+not[\s\n]+limited[\s\n]+to,[\s\n]+penetration[\s\n]+testing,[\s\n]+COMSEC[\s\n]+monitoring,[\s\n]+network[\s\n]+operations[\s\n]+and[\s\n]+defense,[\s\n]+personnel[\s\n]+misconduct[\s\n]+\(PM\),[\s\n]+law[\s\n]+enforcement[\s\n]+\(LE\),[\s\n]+and[\s\n]+counterintelligence[\s\n]+\(CI\)[\s\n]+investigations\.(?:[\n]+|(?:\\n)+)\-At[\s\n]+any[\s\n]+time,[\s\n]+the[\s\n]+USG[\s\n]+may[\s\n]+inspect[\s\n]+and[\s\n]+seize[\s\n]+data[\s\n]+stored[\s\n]+on[\s\n]+this[\s\n]+IS\.(?:[\n]+|(?:\\n)+)\-Communications[\s\n]+using,[\s\n]+or[\s\n]+data[\s\n]+stored[\s\n]+on,[\s\n]+this[\s\n]+IS[\s\n]+are[\s\n]+not[\s\n]+private,[\s\n]+are[\s\n]+subject[\s\n]+to[\s\n]+routine[\s\n]+monitoring,[\s\n]+interception,[\s\n]+and[\s\n]+search,[\s\n]+and[\s\n]+may[\s\n]+be[\s\n]+disclosed[\s\n]+or[\s\n]+used[\s\n]+for[\s\n]+any[\s\n]+USG\-authorized[\s\n]+purpose\.(?:[\n]+|(?:\\n)+)\-This[\s\n]+IS[\s\n]+includes[\s\n]+security[\s\n]+measures[\s\n]+\(e\.g\.,[\s\n]+authentication[\s\n]+and[\s\n]+access[\s\n]+controls\)[\s\n]+to[\s\n]+protect[\s\n]+USG[\s\n]+interests\-\-not[\s\n]+for[\s\n]+your[\s\n]+personal[\s\n]+benefit[\s\n]+or[\s\n]+privacy\.(?:[\n]+|(?:\\n)+)\-Notwithstanding[\s\n]+the[\s\n]+above,[\s\n]+using[\s\n]+this[\s\n]+IS[\s\n]+does[\s\n]+not[\s\n]+constitute[\s\n]+consent[\s\n]+to[\s\n]+PM,[\s\n]+LE[\s\n]+or[\s\n]+CI[\s\n]+investigative[\s\n]+searching[\s\n]+or[\s\n]+monitoring[\s\n]+of[\s\n]+the[\s\n]+content[\s\n]+of[\s\n]+privileged[\s\n]+communications,[\s\n]+or[\s\n]+work[\s\n]+product,[\s\n]+related[\s\n]+to[\s\n]+personal[\s\n]+representation[\s\n]+or[\s\n]+services[\s\n]+by[\s\n]+attorneys,[\s\n]+psychotherapists,[\s\n]+or[\s\n]+clergy,[\s\n]+and[\s\n]+their[\s\n]+assistants\.[\s\n]+Such[\s\n]+communications[\s\n]+and[\s\n]+work[\s\n]+product[\s\n]+are[\s\n]+private[\s\n]+and[\s\n]+confidential\.[\s\n]+See[\s\n]+User[\s\n]+Agreement[\s\n]+for[\s\n]+details\.|I've[\s\n]+read[\s\n]+\&[\s\n]+consent[\s\n]+to[\s\n]+terms[\s\n]+in[\s\n]+IS[\s\n]+user[\s\n]+agreem't\.)$ + ^You[\s\n]+are[\s\n]+accessing[\s\n]+a[\s\n]+U\.S\.[\s\n]+Government[\s\n]+\(USG\)[\s\n]+Information[\s\n]+System[\s\n]+\(IS\)[\s\n]+that[\s\n]+is[\s\n]+provided[\s\n]+for[\s\n]+USG\-authorized[\s\n]+use[\s\n]+only\.[\s\n]+By[\s\n]+using[\s\n]+this[\s\n]+IS[\s\n]+\(which[\s\n]+includes[\s\n]+any[\s\n]+device[\s\n]+attached[\s\n]+to[\s\n]+this[\s\n]+IS\),[\s\n]+you[\s\n]+consent[\s\n]+to[\s\n]+the[\s\n]+following[\s\n]+conditions\:(?:[\n]+|(?:\\n)+)\-The[\s\n]+USG[\s\n]+routinely[\s\n]+intercepts[\s\n]+and[\s\n]+monitors[\s\n]+communications[\s\n]+on[\s\n]+this[\s\n]+IS[\s\n]+for[\s\n]+purposes[\s\n]+including,[\s\n]+but[\s\n]+not[\s\n]+limited[\s\n]+to,[\s\n]+penetration[\s\n]+testing,[\s\n]+COMSEC[\s\n]+monitoring,[\s\n]+network[\s\n]+operations[\s\n]+and[\s\n]+defense,[\s\n]+personnel[\s\n]+misconduct[\s\n]+\(PM\),[\s\n]+law[\s\n]+enforcement[\s\n]+\(LE\),[\s\n]+and[\s\n]+counterintelligence[\s\n]+\(CI\)[\s\n]+investigations\.(?:[\n]+|(?:\\n)+)\-At[\s\n]+any[\s\n]+time,[\s\n]+the[\s\n]+USG[\s\n]+may[\s\n]+inspect[\s\n]+and[\s\n]+seize[\s\n]+data[\s\n]+stored[\s\n]+on[\s\n]+this[\s\n]+IS\.(?:[\n]+|(?:\\n)+)\-Communications[\s\n]+using,[\s\n]+or[\s\n]+data[\s\n]+stored[\s\n]+on,[\s\n]+this[\s\n]+IS[\s\n]+are[\s\n]+not[\s\n]+private,[\s\n]+are[\s\n]+subject[\s\n]+to[\s\n]+routine[\s\n]+monitoring,[\s\n]+interception,[\s\n]+and[\s\n]+search,[\s\n]+and[\s\n]+may[\s\n]+be[\s\n]+disclosed[\s\n]+or[\s\n]+used[\s\n]+for[\s\n]+any[\s\n]+USG\-authorized[\s\n]+purpose\.(?:[\n]+|(?:\\n)+)\-This[\s\n]+IS[\s\n]+includes[\s\n]+security[\s\n]+measures[\s\n]+\(e\.g\.,[\s\n]+authentication[\s\n]+and[\s\n]+access[\s\n]+controls\)[\s\n]+to[\s\n]+protect[\s\n]+USG[\s\n]+interests\-\-not[\s\n]+for[\s\n]+your[\s\n]+personal[\s\n]+benefit[\s\n]+or[\s\n]+privacy\.(?:[\n]+|(?:\\n)+)\-Notwithstanding[\s\n]+the[\s\n]+above,[\s\n]+using[\s\n]+this[\s\n]+IS[\s\n]+does[\s\n]+not[\s\n]+constitute[\s\n]+consent[\s\n]+to[\s\n]+PM,[\s\n]+LE[\s\n]+or[\s\n]+CI[\s\n]+investigative[\s\n]+searching[\s\n]+or[\s\n]+monitoring[\s\n]+of[\s\n]+the[\s\n]+content[\s\n]+of[\s\n]+privileged[\s\n]+communications,[\s\n]+or[\s\n]+work[\s\n]+product,[\s\n]+related[\s\n]+to[\s\n]+personal[\s\n]+representation[\s\n]+or[\s\n]+services[\s\n]+by[\s\n]+attorneys,[\s\n]+psychotherapists,[\s\n]+or[\s\n]+clergy,[\s\n]+and[\s\n]+their[\s\n]+assistants\.[\s\n]+Such[\s\n]+communications[\s\n]+and[\s\n]+work[\s\n]+product[\s\n]+are[\s\n]+private[\s\n]+and[\s\n]+confidential\.[\s\n]+See[\s\n]+User[\s\n]+Agreement[\s\n]+for[\s\n]+details\.$ + ^I've[\s\n]+read[\s\n]+\&[\s\n]+consent[\s\n]+to[\s\n]+terms[\s\n]+in[\s\n]+IS[\s\n]+user[\s\n]+agreem't\.$ + ^Use[\s\n]+of[\s\n]+this[\s\n]+or[\s\n]+any[\s\n]+other[\s\n]+DoD[\s\n]+interest[\s\n]+computer[\s\n]+system[\s\n]+constitutes[\s\n]+consent[\s\n]+to[\s\n]+monitoring[\s\n]+at[\s\n]+all[\s\n]+times\.[\s\n]+This[\s\n]+is[\s\n]+a[\s\n]+DoD[\s\n]+interest[\s\n]+computer[\s\n]+system\.[\s\n]+All[\s\n]+DoD[\s\n]+interest[\s\n]+computer[\s\n]+systems[\s\n]+and[\s\n]+related[\s\n]+equipment[\s\n]+are[\s\n]+intended[\s\n]+for[\s\n]+the[\s\n]+communication,[\s\n]+transmission,[\s\n]+processing,[\s\n]+and[\s\n]+storage[\s\n]+of[\s\n]+official[\s\n]+U\.S\.[\s\n]+Government[\s\n]+or[\s\n]+other[\s\n]+authorized[\s\n]+information[\s\n]+only\.[\s\n]+All[\s\n]+DoD[\s\n]+interest[\s\n]+computer[\s\n]+systems[\s\n]+are[\s\n]+subject[\s\n]+to[\s\n]+monitoring[\s\n]+at[\s\n]+all[\s\n]+times[\s\n]+to[\s\n]+ensure[\s\n]+proper[\s\n]+functioning[\s\n]+of[\s\n]+equipment[\s\n]+and[\s\n]+systems[\s\n]+including[\s\n]+security[\s\n]+devices[\s\n]+and[\s\n]+systems,[\s\n]+to[\s\n]+prevent[\s\n]+unauthorized[\s\n]+use[\s\n]+and[\s\n]+violations[\s\n]+of[\s\n]+statutes[\s\n]+and[\s\n]+security[\s\n]+regulations,[\s\n]+to[\s\n]+deter[\s\n]+criminal[\s\n]+activity,[\s\n]+and[\s\n]+for[\s\n]+other[\s\n]+similar[\s\n]+purposes\.[\s\n]+Any[\s\n]+user[\s\n]+of[\s\n]+a[\s\n]+DoD[\s\n]+interest[\s\n]+computer[\s\n]+system[\s\n]+should[\s\n]+be[\s\n]+aware[\s\n]+that[\s\n]+any[\s\n]+information[\s\n]+placed[\s\n]+in[\s\n]+the[\s\n]+system[\s\n]+is[\s\n]+subject[\s\n]+to[\s\n]+monitoring[\s\n]+and[\s\n]+is[\s\n]+not[\s\n]+subject[\s\n]+to[\s\n]+any[\s\n]+expectation[\s\n]+of[\s\n]+privacy\.[\s\n]+If[\s\n]+monitoring[\s\n]+of[\s\n]+this[\s\n]+or[\s\n]+any[\s\n]+other[\s\n]+DoD[\s\n]+interest[\s\n]+computer[\s\n]+system[\s\n]+reveals[\s\n]+possible[\s\n]+evidence[\s\n]+of[\s\n]+violation[\s\n]+of[\s\n]+criminal[\s\n]+statutes,[\s\n]+this[\s\n]+evidence[\s\n]+and[\s\n]+any[\s\n]+other[\s\n]+related[\s\n]+information,[\s\n]+including[\s\n]+identification[\s\n]+information[\s\n]+about[\s\n]+the[\s\n]+user,[\s\n]+may[\s\n]+be[\s\n]+provided[\s\n]+to[\s\n]+law[\s\n]+enforcement[\s\n]+officials\.[\s\n]+If[\s\n]+monitoring[\s\n]+of[\s\n]+this[\s\n]+or[\s\n]+any[\s\n]+other[\s\n]+DoD[\s\n]+interest[\s\n]+computer[\s\n]+systems[\s\n]+reveals[\s\n]+violations[\s\n]+of[\s\n]+security[\s\n]+regulations[\s\n]+or[\s\n]+unauthorized[\s\n]+use,[\s\n]+employees[\s\n]+who[\s\n]+violate[\s\n]+security[\s\n]+regulations[\s\n]+or[\s\n]+make[\s\n]+unauthorized[\s\n]+use[\s\n]+of[\s\n]+DoD[\s\n]+interest[\s\n]+computer[\s\n]+systems[\s\n]+are[\s\n]+subject[\s\n]+to[\s\n]+appropriate[\s\n]+disciplinary[\s\n]+action\.[\s\n]+Use[\s\n]+of[\s\n]+this[\s\n]+or[\s\n]+any[\s\n]+other[\s\n]+DoD[\s\n]+interest[\s\n]+computer[\s\n]+system[\s\n]+constitutes[\s\n]+consent[\s\n]+to[\s\n]+monitoring[\s\n]+at[\s\n]+all[\s\n]+times\.$ + ^\-\-[\s\n]+WARNING[\s\n]+\-\-[\s\n]+This[\s\n]+system[\s\n]+is[\s\n]+for[\s\n]+the[\s\n]+use[\s\n]+of[\s\n]+authorized[\s\n]+users[\s\n]+only\.[\s\n]+Individuals[\s\n]+using[\s\n]+this[\s\n]+computer[\s\n]+system[\s\n]+without[\s\n]+authority[\s\n]+or[\s\n]+in[\s\n]+excess[\s\n]+of[\s\n]+their[\s\n]+authority[\s\n]+are[\s\n]+subject[\s\n]+to[\s\n]+having[\s\n]+all[\s\n]+their[\s\n]+activities[\s\n]+on[\s\n]+this[\s\n]+system[\s\n]+monitored[\s\n]+and[\s\n]+recorded[\s\n]+by[\s\n]+system[\s\n]+personnel\.[\s\n]+Anyone[\s\n]+using[\s\n]+this[\s\n]+system[\s\n]+expressly[\s\n]+consents[\s\n]+to[\s\n]+such[\s\n]+monitoring[\s\n]+and[\s\n]+is[\s\n]+advised[\s\n]+that[\s\n]+if[\s\n]+such[\s\n]+monitoring[\s\n]+reveals[\s\n]+possible[\s\n]+evidence[\s\n]+of[\s\n]+criminal[\s\n]+activity[\s\n]+system[\s\n]+personal[\s\n]+may[\s\n]+provide[\s\n]+the[\s\n]+evidence[\s\n]+of[\s\n]+such[\s\n]+monitoring[\s\n]+to[\s\n]+law[\s\n]+enforcement[\s\n]+officials\.$ + ^Authorized[\s\n]+uses[\s\n]+only\.[\s\n]+All[\s\n]+activity[\s\n]+may[\s\n]+be[\s\n]+monitored[\s\n]+and[\s\n]+reported\.$ + + + Modify the System Login Banner + To configure the system login banner edit /etc/issue. Replace the default text with a message compliant with the local site policy or a legal disclaimer. The DoD required text is either: - -You are accessing a U.S. Government (USG) Information System (IS) that + + + You are accessing a U.S. Government (USG) Information System (IS) that is provided for USG-authorized use only. By using this IS (which includes any device attached to this IS), you consent to the following conditions: --The USG routinely intercepts and monitors communications on this IS +-The USG routinely intercepts and monitors communications on this IS for purposes including, but not limited to, penetration testing, COMSEC monitoring, network operations and defense, personnel misconduct (PM), law enforcement (LE), and counterintelligence (CI) investigations. --At any time, the USG may inspect and seize data stored on this IS. --Communications using, or data stored on, this IS are not private, +-At any time, the USG may inspect and seize data stored on this IS. +-Communications using, or data stored on, this IS are not private, are subject to routine monitoring, interception, and search, and may be disclosed or used for any USG-authorized purpose. --This IS includes security measures (e.g., authentication and access +-This IS includes security measures (e.g., authentication and access controls) to protect USG interests -- not for your personal benefit or privacy. --Notwithstanding the above, using this IS does not constitute consent +-Notwithstanding the above, using this IS does not constitute consent to PM, LE or CI investigative searching or monitoring of the content of privileged communications, or work product, related to personal representation or services by attorneys, psychotherapists, or clergy, and their assistants. Such communications and work product are private and confidential. See User Agreement for details. - + + OR: - -I've read & consent to terms in IS user agreem't. - 1 - 12 - 15 - 16 - DSS05.04 - DSS05.10 - DSS06.10 - 3.1.9 - CCI-000048 - CCI-000050 - CCI-001384 - CCI-001385 - CCI-001386 - CCI-001387 - CCI-001388 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - SR 1.1 - SR 1.10 - SR 1.2 - SR 1.5 - SR 1.7 - SR 1.8 - SR 1.9 - A.18.1.4 - A.9.2.1 - A.9.2.4 - A.9.3.1 - A.9.4.2 - A.9.4.3 - AC-8(a) - AC-8(c) - PR.AC-7 - FMT_MOF_EXT.1 - SRG-OS-000023-GPOS-00006 - SRG-OS-000228-GPOS-00088 - Display of a standardized and approved use notification before granting + + + I've read & consent to terms in IS user agreem't. + + 1 + 12 + 15 + 16 + DSS05.04 + DSS05.10 + DSS06.10 + 3.1.9 + CCI-001387 + CCI-001384 + CCI-000048 + CCI-001386 + CCI-001388 + CCI-001385 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + SR 1.1 + SR 1.10 + SR 1.2 + SR 1.5 + SR 1.7 + SR 1.8 + SR 1.9 + A.18.1.4 + A.9.2.1 + A.9.2.4 + A.9.3.1 + A.9.4.2 + A.9.4.3 + AC-8(a) + AC-8(c) + PR.AC-7 + SRG-OS-000023-GPOS-00006 + SRG-OS-000228-GPOS-00088 + A.11.SEC-OL4 + OL09-00-000090 + SV-271455r1091077_rule + Display of a standardized and approved use notification before granting access to the operating system ensures privacy and security notification verbiage used is consistent with applicable federal laws, Executive Orders, directives, policies, regulations, standards, and guidance. - + + System use notifications are required only for access via login interfaces with human users and are not required when such human interfaces do not -exist. - - - - - - - - - - - - - Modify the System Login Banner for Remote Connections - To configure the system login banner edit /etc/issue.net. Replace the +- name: XCCDF Value login_banner_text # promote to variable + set_fact: + login_banner_text: !!str + tags: + - always + +- name: Modify the System Login Banner - Ensure Correct Banner + copy: + dest: /etc/issue + content: '{{ login_banner_text | regex_replace("^\^(.*)\$$", "\1") | regex_replace("^\((.*\.)\|.*\)$", + "\1") | regex_replace("\[\\s\\n\]\+"," ") | regex_replace("\(\?:\[\\n\]\+\|\(\?:\\\\n\)\+\)", + "\n") | regex_replace("\\", "") | wordwrap() }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-000090 + - NIST-800-171-3.1.9 + - NIST-800-53-AC-8(a) + - NIST-800-53-AC-8(c) + - banner_etc_issue + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - unknown_strategy + + + + + + + + + + + Modify the System Login Banner for Remote Connections + To configure the system login banner edit /etc/issue.net. Replace the default text with a message compliant with the local site policy or a legal disclaimer. The DoD required text is either: - -You are accessing a U.S. Government (USG) Information System (IS) that + + + You are accessing a U.S. Government (USG) Information System (IS) that is provided for USG-authorized use only. By using this IS (which includes any device attached to this IS), you consent to the following conditions: --The USG routinely intercepts and monitors communications on this IS +-The USG routinely intercepts and monitors communications on this IS for purposes including, but not limited to, penetration testing, COMSEC monitoring, network operations and defense, personnel misconduct (PM), law enforcement (LE), and counterintelligence (CI) investigations. --At any time, the USG may inspect and seize data stored on this IS. --Communications using, or data stored on, this IS are not private, +-At any time, the USG may inspect and seize data stored on this IS. +-Communications using, or data stored on, this IS are not private, are subject to routine monitoring, interception, and search, and may be disclosed or used for any USG-authorized purpose. --This IS includes security measures (e.g., authentication and access +-This IS includes security measures (e.g., authentication and access controls) to protect USG interests -- not for your personal benefit or privacy. --Notwithstanding the above, using this IS does not constitute consent +-Notwithstanding the above, using this IS does not constitute consent to PM, LE or CI investigative searching or monitoring of the content of privileged communications, or work product, related to personal representation or services by attorneys, psychotherapists, or clergy, and their assistants. Such communications and work product are private and confidential. See User Agreement for details. - + + OR: - -I've read & consent to terms in IS user agreem't. - CCI-000048 - CCI-001384 - CCI-001385 - CCI-001386 - CCI-001387 - CCI-001388 - SRG-OS-000023-GPOS-00006 - SRG-OS-000228-GPOS-00088 - Display of a standardized and approved use notification before granting + + + I've read & consent to terms in IS user agreem't. + + CCI-000048 + CCI-001384 + CCI-001385 + CCI-001386 + CCI-001387 + CCI-001388 + SRG-OS-000023-GPOS-00006 + SRG-OS-000228-GPOS-00088 + A.11.SEC-OL4 + Display of a standardized and approved use notification before granting access to the operating system ensures privacy and security notification verbiage used is consistent with applicable federal laws, Executive Orders, directives, policies, regulations, standards, and guidance. - + + System use notifications are required only for access via login interfaces with human users and are not required when such human interfaces do not -exist. - - - - - - - - - - - - - Implement a GUI Warning Banner - In the default graphical environment, users logging + + + + + + + + + + + Modify the System Message of the Day Banner + To configure the system message banner edit /etc/motd. Replace the +default text with a message compliant with the local site policy or a legal +disclaimer. + +The DoD required text is either: + + + You are accessing a U.S. Government (USG) Information System (IS) that +is provided for USG-authorized use only. By using this IS (which includes +any device attached to this IS), you consent to the following conditions: +-The USG routinely intercepts and monitors communications on this IS +for purposes including, but not limited to, penetration testing, COMSEC +monitoring, network operations and defense, personnel misconduct (PM), law +enforcement (LE), and counterintelligence (CI) investigations. +-At any time, the USG may inspect and seize data stored on this IS. +-Communications using, or data stored on, this IS are not private, +are subject to routine monitoring, interception, and search, and may be +disclosed or used for any USG-authorized purpose. +-This IS includes security measures (e.g., authentication and access +controls) to protect USG interests -- not for your personal benefit or +privacy. +-Notwithstanding the above, using this IS does not constitute consent +to PM, LE or CI investigative searching or monitoring of the content of +privileged communications, or work product, related to personal +representation or services by attorneys, psychotherapists, or clergy, and +their assistants. Such communications and work product are private and +confidential. See User Agreement for details. + + +OR: + + + I've read & consent to terms in IS user agreem't. + + A.11.SEC-OL4 + Display of a standardized and approved use notification before granting +access to the operating system ensures privacy and security notification +verbiage used is consistent with applicable federal laws, Executive Orders, +directives, policies, regulations, standards, and guidance. + + +System use notifications are required only for access via login interfaces +with human users and are not required when such human interfaces do not +exist. + + + + + + + + + + + + + Verify Group Ownership of System Login Banner for Remote Connections + +To properly set the group owner of /etc/issue.net, run the command: +$ sudo chgrp root /etc/issue.net + + 1.2.8 + 1.2 + Display of a standardized and approved use notification before granting +access to the operating system ensures privacy and security notification +verbiage used is consistent with applicable federal laws, Executive Orders, +directives, policies, regulations, standards, and guidance. +Proper group ownership will ensure that only root user can modify the banner. + chgrp 0 /etc/issue.net + + - name: Test for existence /etc/issue.net + stat: + path: /etc/issue.net + register: file_exists + tags: + - PCI-DSSv4-1.2 + - PCI-DSSv4-1.2.8 + - configure_strategy + - file_groupowner_etc_issue_net + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure group owner 0 on /etc/issue.net + file: + path: /etc/issue.net + group: '0' + when: file_exists.stat is defined and file_exists.stat.exists + tags: + - PCI-DSSv4-1.2 + - PCI-DSSv4-1.2.8 + - configure_strategy + - file_groupowner_etc_issue_net + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify ownership of System Login Banner for Remote Connections + +To properly set the owner of /etc/issue.net, run the command: +$ sudo chown root /etc/issue.net + + 1.2.8 + 1.2 + Display of a standardized and approved use notification before granting +access to the operating system ensures privacy and security notification +verbiage used is consistent with applicable federal laws, Executive Orders, +directives, policies, regulations, standards, and guidance. +Proper ownership will ensure that only root user can modify the banner. + chown 0 /etc/issue.net + + - name: Test for existence /etc/issue.net + stat: + path: /etc/issue.net + register: file_exists + tags: + - PCI-DSSv4-1.2 + - PCI-DSSv4-1.2.8 + - configure_strategy + - file_owner_etc_issue_net + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure owner 0 on /etc/issue.net + file: + path: /etc/issue.net + owner: '0' + when: file_exists.stat is defined and file_exists.stat.exists + tags: + - PCI-DSSv4-1.2 + - PCI-DSSv4-1.2.8 + - configure_strategy + - file_owner_etc_issue_net + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify permissions on System Login Banner for Remote Connections + +To properly set the permissions of /etc/issue.net, run the command: +$ sudo chmod 0644 /etc/issue.net + + 1.2.8 + 1.2 + Display of a standardized and approved use notification before granting +access to the operating system ensures privacy and security notification +verbiage used is consistent with applicable federal laws, Executive Orders, +directives, policies, regulations, standards, and guidance. +Proper permissions will ensure that only root user can modify the banner. + + + + +chmod u-xs,g-xws,o-xwt /etc/issue.net + + - name: Test for existence /etc/issue.net + stat: + path: /etc/issue.net + register: file_exists + tags: + - PCI-DSSv4-1.2 + - PCI-DSSv4-1.2.8 + - configure_strategy + - file_permissions_etc_issue_net + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure permission u-xs,g-xws,o-xwt on /etc/issue.net + file: + path: /etc/issue.net + mode: u-xs,g-xws,o-xwt + when: file_exists.stat is defined and file_exists.stat.exists + tags: + - PCI-DSSv4-1.2 + - PCI-DSSv4-1.2.8 + - configure_strategy + - file_permissions_etc_issue_net + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Implement a GUI Warning Banner + In the default graphical environment, users logging directly into the system are greeted with a login screen provided by the GNOME Display Manager (GDM). The warning banner should be displayed in this graphical environment for these users. The following sections describe how to configure the GDM login -banner. - - - Enable GNOME3 Login Warning Banner - In the default graphical environment, displaying a login warning banner +banner. + + + Enable GNOME3 Login Warning Banner + In the default graphical environment, displaying a login warning banner in the GNOME Display Manager's login screen can be enabled on the login screen by setting banner-message-enable to true. - + + To enable, add or edit banner-message-enable to -/etc/dconf/db/gdm.d/00-security-settings. For example: +/etc/dconf/db/local.d/00-security-settings. For example: [org/gnome/login-screen] banner-message-enable=true Once the setting has been added, add a lock to -/etc/dconf/db/gdm.d/locks/00-security-settings-lock to prevent user modification. +/etc/dconf/db/local.d/locks/00-security-settings-lock to prevent user modification. For example: /org/gnome/login-screen/banner-message-enable After the settings have been set, run dconf update. -The banner text must also be set. - 1 - 12 - 15 - 16 - DSS05.04 - DSS05.10 - DSS06.10 - 3.1.9 - CCI-000048 - CCI-000050 - CCI-001384 - CCI-001385 - CCI-001386 - CCI-001387 - CCI-001388 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - SR 1.1 - SR 1.10 - SR 1.2 - SR 1.5 - SR 1.7 - SR 1.8 - SR 1.9 - A.18.1.4 - A.9.2.1 - A.9.2.4 - A.9.3.1 - A.9.4.2 - A.9.4.3 - AC-8(a) - AC-8(b) - AC-8(c) - PR.AC-7 - FMT_MOF_EXT.1 - SRG-OS-000023-GPOS-00006 - SRG-OS-000228-GPOS-00088 - Display of a standardized and approved use notification before granting access to the operating system +The banner text must also be set. + 1 + 12 + 15 + 16 + DSS05.04 + DSS05.10 + DSS06.10 + 3.1.9 + CCI-001387 + CCI-001384 + CCI-000048 + CCI-001386 + CCI-001388 + CCI-001385 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + SR 1.1 + SR 1.10 + SR 1.2 + SR 1.5 + SR 1.7 + SR 1.8 + SR 1.9 + A.18.1.4 + A.9.2.1 + A.9.2.4 + A.9.3.1 + A.9.4.2 + A.9.4.3 + AC-8(a) + AC-8(b) + AC-8(c) + PR.AC-7 + SRG-OS-000023-GPOS-00006 + SRG-OS-000228-GPOS-00088 + A.11.SEC-OL4 + OL09-00-002150 + OL09-00-002122 + SV-271688r1091776_rule + SV-271680r1091752_rule + Display of a standardized and approved use notification before granting access to the operating system ensures privacy and security notification verbiage used is consistent with applicable federal laws, Executive Orders, directives, policies, regulations, standards, and guidance. - + + For U.S. Government systems, system use notifications are required only for access via login interfaces -with human users and are not required when such human interfaces do not exist. - # Remediation is applicable only in certain platforms +with human users and are not required when such human interfaces do not exist. + # Remediation is applicable only in certain platforms if rpm --quiet -q gdm; then # Check for setting in any of the DConf db directories # If files contain ibus or distro, ignore them. # The assignment assumes that individual filenames don't contain : readarray -t SETTINGSFILES < <(grep -r "\\[org/gnome/login-screen\\]" "/etc/dconf/db/" \ - | grep -v 'distro\|ibus\|gdm.d' | cut -d":" -f1) -DCONFFILE="/etc/dconf/db/gdm.d/00-security-settings" -DBDIR="/etc/dconf/db/gdm.d" + | grep -v 'distro\|ibus\|local.d' | cut -d":" -f1) +DCONFFILE="/etc/dconf/db/local.d/00-security-settings" +DBDIR="/etc/dconf/db/local.d" mkdir -p "${DBDIR}" @@ -13038,7 +15574,6 @@ then fi fi - [ ! -z "${DCONFFILE}" ] && echo "" >> "${DCONFFILE}" if ! grep -q "\\[org/gnome/login-screen\\]" "${DCONFFILE}" then @@ -13052,12 +15587,11 @@ then else sed -i "\\|\\[org/gnome/login-screen\\]|a\\banner-message-enable=${escaped_value}" "${DCONFFILE}" fi - dconf update # Check for setting in any of the DConf db directories LOCKFILES=$(grep -r "^/org/gnome/login-screen/banner-message-enable$" "/etc/dconf/db/" \ - | grep -v 'distro\|ibus\|gdm.d' | grep ":" | cut -d":" -f1) -LOCKSFOLDER="/etc/dconf/db/gdm.d/locks" + | grep -v 'distro\|ibus\|local.d' | grep ":" | cut -d":" -f1) +LOCKSFOLDER="/etc/dconf/db/local.d/locks" mkdir -p "${LOCKSFOLDER}" @@ -13067,21 +15601,22 @@ then sed -i -E "s|^/org/gnome/login-screen/banner-message-enable$|#&|" "${LOCKFILES[@]}" fi -if ! grep -qr "^/org/gnome/login-screen/banner-message-enable$" /etc/dconf/db/gdm.d/ +if ! grep -qr "^/org/gnome/login-screen/banner-message-enable$" /etc/dconf/db/local.d/ then - echo "/org/gnome/login-screen/banner-message-enable" >> "/etc/dconf/db/gdm.d/locks/00-security-settings-lock" + echo "/org/gnome/login-screen/banner-message-enable" >> "/etc/dconf/db/local.d/locks/00-security-settings-lock" fi - dconf update else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-002122 + - DISA-STIG-OL09-00-002150 - NIST-800-171-3.1.9 - NIST-800-53-AC-8(a) - NIST-800-53-AC-8(b) @@ -13095,7 +15630,7 @@ fi - name: Enable GNOME3 Login Warning Banner ini_file: - dest: /etc/dconf/db/gdm.d/00-security-settings + dest: /etc/dconf/db/local.d/00-security-settings section: org/gnome/login-screen option: banner-message-enable value: 'true' @@ -13103,6 +15638,8 @@ fi no_extra_spaces: true when: '"gdm" in ansible_facts.packages' tags: + - DISA-STIG-OL09-00-002122 + - DISA-STIG-OL09-00-002150 - NIST-800-171-3.1.9 - NIST-800-53-AC-8(a) - NIST-800-53-AC-8(b) @@ -13116,12 +15653,14 @@ fi - name: Prevent user modification of GNOME banner-message-enabled lineinfile: - path: /etc/dconf/db/gdm.d/locks/00-security-settings-lock + path: /etc/dconf/db/local.d/locks/00-security-settings-lock regexp: ^/org/gnome/login-screen/banner-message-enable$ line: /org/gnome/login-screen/banner-message-enable create: true when: '"gdm" in ansible_facts.packages' tags: + - DISA-STIG-OL09-00-002122 + - DISA-STIG-OL09-00-002150 - NIST-800-171-3.1.9 - NIST-800-53-AC-8(a) - NIST-800-53-AC-8(b) @@ -13137,6 +15676,8 @@ fi command: dconf update when: '"gdm" in ansible_facts.packages' tags: + - DISA-STIG-OL09-00-002122 + - DISA-STIG-OL09-00-002150 - NIST-800-171-3.1.9 - NIST-800-53-AC-8(a) - NIST-800-53-AC-8(b) @@ -13147,82 +15688,85 @@ fi - medium_severity - no_reboot_needed - unknown_strategy - - - - - - - - - - Set the GNOME3 Login Warning Banner Text - In the default graphical environment, configuring the login warning banner text + + + + + + + + + + Set the GNOME3 Login Warning Banner Text + In the default graphical environment, configuring the login warning banner text in the GNOME Display Manager's login screen can be configured on the login screen by setting banner-message-text to 'APPROVED_BANNER' where APPROVED_BANNER is the approved banner for your environment. - + + To enable, add or edit banner-message-text to -/etc/dconf/db/gdm.d/00-security-settings. For example: +/etc/dconf/db/local.d/00-security-settings. For example: [org/gnome/login-screen] banner-message-text='APPROVED_BANNER' Once the setting has been added, add a lock to -/etc/dconf/db/gdm.d/locks/00-security-settings-lock to prevent user modification. +/etc/dconf/db/local.d/locks/00-security-settings-lock to prevent user modification. For example: /org/gnome/login-screen/banner-message-text After the settings have been set, run dconf update. When entering a warning banner that spans several lines, remember -to begin and end the string with ' and use \n for new lines. - 1 - 12 - 15 - 16 - DSS05.04 - DSS05.10 - DSS06.10 - 3.1.9 - CCI-000048 - CCI-001384 - CCI-001385 - CCI-001386 - CCI-001387 - CCI-001388 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - SR 1.1 - SR 1.10 - SR 1.2 - SR 1.5 - SR 1.7 - SR 1.8 - SR 1.9 - A.18.1.4 - A.9.2.1 - A.9.2.4 - A.9.3.1 - A.9.4.2 - A.9.4.3 - AC-8(a) - AC-8(c) - PR.AC-7 - FMT_MOF_EXT.1 - SRG-OS-000023-GPOS-00006 - SRG-OS-000228-GPOS-00088 - An appropriate warning message reinforces policy awareness during the logon -process and facilitates possible legal action against attackers. - # Remediation is applicable only in certain platforms +to begin and end the string with ' and use \n for new lines. + 1 + 12 + 15 + 16 + DSS05.04 + DSS05.10 + DSS06.10 + 3.1.9 + CCI-000048 + CCI-001384 + CCI-001385 + CCI-001386 + CCI-001387 + CCI-001388 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + SR 1.1 + SR 1.10 + SR 1.2 + SR 1.5 + SR 1.7 + SR 1.8 + SR 1.9 + A.18.1.4 + A.9.2.1 + A.9.2.4 + A.9.3.1 + A.9.4.2 + A.9.4.3 + AC-8(a) + AC-8(c) + PR.AC-7 + SRG-OS-000023-GPOS-00006 + SRG-OS-000228-GPOS-00088 + A.11.SEC-OL4 + OL09-00-002151 + SV-271689r1091779_rule + An appropriate warning message reinforces policy awareness during the logon +process and facilitates possible legal action against attackers. + # Remediation is applicable only in certain platforms if rpm --quiet -q gdm; then -login_banner_text='' +login_banner_text='' # Multiple regexes transform the banner regex into a usable banner @@ -13245,9 +15789,9 @@ login_banner_text=$(echo "$login_banner_text" | sed 's/(n)\*/\\n/g') # If files contain ibus or distro, ignore them. # The assignment assumes that individual filenames don't contain : readarray -t SETTINGSFILES < <(grep -r "\\[org/gnome/login-screen\\]" "/etc/dconf/db/" \ - | grep -v 'distro\|ibus\|gdm.d' | cut -d":" -f1) -DCONFFILE="/etc/dconf/db/gdm.d/00-security-settings" -DBDIR="/etc/dconf/db/gdm.d" + | grep -v 'distro\|ibus\|local.d' | cut -d":" -f1) +DCONFFILE="/etc/dconf/db/local.d/00-security-settings" +DBDIR="/etc/dconf/db/local.d" mkdir -p "${DBDIR}" @@ -13261,7 +15805,6 @@ then fi fi - [ ! -z "${DCONFFILE}" ] && echo "" >> "${DCONFFILE}" if ! grep -q "\\[org/gnome/login-screen\\]" "${DCONFFILE}" then @@ -13275,12 +15818,11 @@ then else sed -i "\\|\\[org/gnome/login-screen\\]|a\\banner-message-text=${escaped_value}" "${DCONFFILE}" fi - dconf update # Check for setting in any of the DConf db directories LOCKFILES=$(grep -r "^/org/gnome/login-screen/banner-message-text$" "/etc/dconf/db/" \ - | grep -v 'distro\|ibus\|gdm.d' | grep ":" | cut -d":" -f1) -LOCKSFOLDER="/etc/dconf/db/gdm.d/locks" + | grep -v 'distro\|ibus\|local.d' | grep ":" | cut -d":" -f1) +LOCKSFOLDER="/etc/dconf/db/local.d/locks" mkdir -p "${LOCKSFOLDER}" @@ -13290,21 +15832,21 @@ then sed -i -E "s|^/org/gnome/login-screen/banner-message-text$|#&|" "${LOCKFILES[@]}" fi -if ! grep -qr "^/org/gnome/login-screen/banner-message-text$" /etc/dconf/db/gdm.d/ +if ! grep -qr "^/org/gnome/login-screen/banner-message-text$" /etc/dconf/db/local.d/ then - echo "/org/gnome/login-screen/banner-message-text" >> "/etc/dconf/db/gdm.d/locks/00-security-settings-lock" + echo "/org/gnome/login-screen/banner-message-text" >> "/etc/dconf/db/local.d/locks/00-security-settings-lock" fi - dconf update else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-002151 - NIST-800-171-3.1.9 - NIST-800-53-AC-8(a) - NIST-800-53-AC-8(c) @@ -13316,7 +15858,7 @@ fi - unknown_strategy - name: XCCDF Value login_banner_text # promote to variable set_fact: - login_banner_text: !!str + login_banner_text: !!str tags: - always @@ -13328,10 +15870,11 @@ fi mode: 493 state: directory with_items: - - gdm.d - - gdm.d/locks + - local.d + - local.d/locks when: '"gdm" in ansible_facts.packages' tags: + - DISA-STIG-OL09-00-002151 - NIST-800-171-3.1.9 - NIST-800-53-AC-8(a) - NIST-800-53-AC-8(c) @@ -13344,7 +15887,7 @@ fi - name: Set the GNOME3 Login Warning Banner Text file: - path: /etc/dconf/db/gdm.d/{{ item }} + path: /etc/dconf/db/local.d/{{ item }} owner: root group: root mode: 420 @@ -13354,6 +15897,7 @@ fi - locks/00-security-settings-lock when: '"gdm" in ansible_facts.packages' tags: + - DISA-STIG-OL09-00-002151 - NIST-800-171-3.1.9 - NIST-800-53-AC-8(a) - NIST-800-53-AC-8(c) @@ -13366,7 +15910,7 @@ fi - name: Set the GNOME3 Login Warning Banner Text ini_file: - dest: /etc/dconf/db/gdm.d/00-security-settings + dest: /etc/dconf/db/local.d/00-security-settings section: org/gnome/login-screen option: banner-message-text value: '''{{ login_banner_text | regex_replace("^\^(.*)\$$", "\1") | regex_replace("^\((.*\.)\|.*\)$", @@ -13376,6 +15920,7 @@ fi no_extra_spaces: true when: '"gdm" in ansible_facts.packages' tags: + - DISA-STIG-OL09-00-002151 - NIST-800-171-3.1.9 - NIST-800-53-AC-8(a) - NIST-800-53-AC-8(c) @@ -13388,13 +15933,14 @@ fi - name: Prevent user modification of the GNOME3 Login Warning Banner Text lineinfile: - path: /etc/dconf/db/gdm.d/locks/00-security-settings-lock + path: /etc/dconf/db/local.d/locks/00-security-settings-lock regexp: ^/org/gnome/login-screen/banner-message-text$ line: /org/gnome/login-screen/banner-message-text create: true state: present when: '"gdm" in ansible_facts.packages' tags: + - DISA-STIG-OL09-00-002151 - NIST-800-171-3.1.9 - NIST-800-53-AC-8(a) - NIST-800-53-AC-8(c) @@ -13409,6 +15955,7 @@ fi command: dconf update when: '"gdm" in ansible_facts.packages' tags: + - DISA-STIG-OL09-00-002151 - NIST-800-171-3.1.9 - NIST-800-53-AC-8(a) - NIST-800-53-AC-8(c) @@ -13418,25 +15965,26 @@ fi - medium_severity - no_reboot_needed - unknown_strategy - - - - - - - - - - - - - Protect Accounts by Configuring PAM - PAM, or Pluggable Authentication Modules, is a system + + + + + + + + + + + + + Protect Accounts by Configuring PAM + PAM, or Pluggable Authentication Modules, is a system which implements modular authentication for Linux programs. PAM provides a flexible and configurable architecture for authentication, and it should be configured to minimize exposure to unnecessary risk. This section contains guidance on how to accomplish that. - + + PAM is implemented as a set of shared objects which are loaded and invoked whenever an application wishes to authenticate a user. Typically, the application must be running as root in order @@ -13447,68 +15995,81 @@ Traditional privileged network listeners requirement. An SUID root application, userhelper, is provided so that programs which are not SUID or privileged themselves can still take advantage of PAM. - + + PAM looks in the directory /etc/pam.d for application-specific configuration information. For instance, if the program login attempts to authenticate a user, then PAM's libraries follow the instructions in the file /etc/pam.d/login to determine what actions should be taken. - + + One very important file in /etc/pam.d is /etc/pam.d/system-auth. This file, which is included by many other PAM configuration files, defines 'default' system authentication measures. Modifying this file is a good way to make far-reaching authentication changes, for instance when implementing a -centralized authentication service. - Be careful when making changes to PAM's configuration files. +centralized authentication service. + Be careful when making changes to PAM's configuration files. The syntax for these files is complex, and modifications can have unexpected consequences. The default configurations shipped -with applications should be sufficient for most users. - Running authconfig or system-config-authentication +with applications should be sufficient for most users. + Running authconfig or system-config-authentication will re-write the PAM configuration files, destroying any manually made changes and replacing them with a series of system defaults. One reference to the configuration file syntax can be found at -https://fossies.org/linux/Linux-PAM-docs/doc/sag/Linux-PAM_SAG.pdf. - - Password Hashing algorithm - Specify the system default encryption algorithm for encrypting passwords. -Defines the value set as ENCRYPT_METHOD in /etc/login.defs. - SHA512 - SHA512 - SHA256 - yescrypt - - - remember - The last n passwords for each user are saved in +https://fossies.org/linux/Linux-PAM-docs/doc/sag/Linux-PAM_SAG.pdf. + + Password Hashing algorithm + Specify the system default encryption algorithm for encrypting passwords. +Defines the value set as ENCRYPT_METHOD in /etc/login.defs. + SHA512 + SHA512 + SHA256 + YESCRYPT + SHA512|YESCRYPT + + + Password Hashing algorithm for pam_unix.so + Specify the system default encryption algorithm for encrypting passwords. +Defines the hashing algorithm to be used in pam_unix.so. + sha512 + sha512 + yescrypt + + + remember + The last n passwords for each user are saved in /etc/security/opasswd in order to force password change history and keep the user from alternating between the same password too -frequently. - 0 - 10 - 24 - 2 - 4 - 5 - 5 - - - Disallow Configuration to Bypass Password Requirements for Privilege Escalation - Verify the operating system is not configured to bypass password requirements for privilege +frequently. + 0 + 10 + 24 + 2 + 4 + 5 + 5 + + + Disallow Configuration to Bypass Password Requirements for Privilege Escalation + Verify the operating system is not configured to bypass password requirements for privilege escalation. Check the configuration of the "/etc/pam.d/sudo" file with the following command: $ sudo grep pam_succeed_if /etc/pam.d/sudo -If any occurrences of "pam_succeed_if" is returned from the command, this is a finding. - CCI-002038 - IA-11 - SRG-OS-000373-GPOS-00156 - SRG-OS-000373-GPOS-00157 - SRG-OS-000373-GPOS-00158 - Without re-authentication, users may access resources or perform tasks for which they do not +If any occurrences of "pam_succeed_if" is returned from the command, this is a finding. + CCI-004895 + IA-11 + SRG-OS-000373-GPOS-00156 + SRG-OS-000373-GPOS-00157 + SRG-OS-000373-GPOS-00158 + OL09-00-002364 + SV-271726r1091890_rule + Without re-authentication, users may access resources or perform tasks for which they do not have authorization. When operating systems provide the capability to escalate a functional -capability, it is critical the user re-authenticate. - - # Remediation is applicable only in certain platforms +capability, it is critical the user re-authenticate. + + # Remediation is applicable only in certain platforms if rpm --quiet -q pam; then sed -i '/pam_succeed_if/d' /etc/pam.d/sudo @@ -13516,11 +16077,12 @@ sed -i '/pam_succeed_if/d' /etc/pam.d/sudo else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-002364 - NIST-800-53-IA-11 - disallow_bypass_password_sudo - low_complexity @@ -13537,6 +16099,7 @@ fi state: absent when: '"pam" in ansible_facts.packages' tags: + - DISA-STIG-OL09-00-002364 - NIST-800-53-IA-11 - disallow_bypass_password_sudo - low_complexity @@ -13544,78 +16107,98 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Ensure PAM Displays Last Logon/Access Notification - To configure the system to notify users of last logon/access -using pam_lastlog, add or correct the pam_lastlog -settings in -/etc/pam.d/postlogin to read as follows: -session required pam_lastlog.so showfailed -And make sure that the silent option is not set for -pam_lastlog module. - 1 - 12 - 15 - 16 - 5.5.2 - DSS05.04 - DSS05.10 - DSS06.10 - CCI-000052 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - SR 1.1 - SR 1.10 - SR 1.2 - SR 1.5 - SR 1.7 - SR 1.8 - SR 1.9 - 0582 - 0584 - 05885 - 0586 - 0846 - 0957 - A.18.1.4 - A.9.2.1 - A.9.2.4 - A.9.3.1 - A.9.4.2 - A.9.4.3 - AC-9 - AC-9(1) - PR.AC-7 - Req-10.2.4 - 10.2.1.4 - SRG-OS-000480-GPOS-00227 - Users need to be aware of activity that occurs regarding -their account. Providing users with information regarding the number -of unsuccessful attempts that were made to login to their account -allows the user to determine if any unauthorized activity has occurred -and gives them an opportunity to notify administrators. - - # Remediation is applicable only in certain platforms + + + + + + + + + + Ensure PAM Displays Last Logon/Access Notification + To configure the system to notify users of last logon/access using pam_lastlog, +add or correct the pam_lastlog settings in /etc/pam.d/postlogin +to include showfailed option, such as: +session required pam_lastlog.so showfailed +And make sure that the silent option is not set for this specific line. + If the system relies on authselect tool to manage PAM settings, the remediation +will also use authselect tool. However, if any manual modification was made in +PAM files, the authselect integrity check will fail and the remediation will be +aborted in order to preserve intentional changes. In this case, an informative message will +be shown in the remediation report. + authselect contains an authselect feature to easily and properly enable Last Logon +notifications with pam_lastlog.so module. If a custom profile was created and used +in the system before this authselect feature was available, the new feature can't be used +with this custom profile and the remediation will fail. In this case, the custom profile +should be recreated or manually updated. + 1 + 12 + 15 + 16 + 5.5.2 + DSS05.04 + DSS05.10 + DSS06.10 + CCI-000366 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + SR 1.1 + SR 1.10 + SR 1.2 + SR 1.5 + SR 1.7 + SR 1.8 + SR 1.9 + 0582 + 0584 + 05885 + 0586 + 0846 + 0957 + A.18.1.4 + A.9.2.1 + A.9.2.4 + A.9.3.1 + A.9.4.2 + A.9.4.3 + AC-9 + AC-9(1) + PR.AC-7 + Req-10.2.4 + SRG-OS-000480-GPOS-00227 + 10.2.1.4 + 10.2.1 + 10.2 + Users need to be aware of activity that occurs regarding their account. Providing users with +information regarding the number of unsuccessful attempts that were made to login to their +account allows the user to determine if any unauthorized activity has occurred and gives them +an opportunity to notify administrators. + + # Remediation is applicable only in certain platforms if rpm --quiet -q pam; then -if [ -e "/etc/pam.d/postlogin" ] ; then - PAM_FILE_PATH="/etc/pam.d/postlogin" - if [ -f /usr/bin/authselect ]; then +if [ -f /usr/bin/authselect ]; then + if authselect list-features sssd | grep -q with-silent-lastlog; then + if ! authselect check; then + echo " + authselect integrity check failed. Remediation aborted! + This remediation could not be applied because an authselect profile was not selected or the selected profile is not intact. + It is not recommended to manually edit the PAM files when authselect tool is available. + In cases where the default authselect profile does not cover a specific demand, a custom authselect profile is recommended." + exit 1 + fi + authselect disable-feature with-silent-lastlog + + authselect apply-changes -b + else if ! authselect check; then echo " @@ -13630,59 +16213,11 @@ if [ -e "/etc/pam.d/postlogin" ] ; then # If not already in use, a custom profile is created preserving the enabled features. if [[ ! $CURRENT_PROFILE == custom/* ]]; then ENABLED_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }') - authselect create-profile hardening -b $CURRENT_PROFILE - CURRENT_PROFILE="custom/hardening" - - authselect apply-changes -b --backup=before-hardening-custom-profile - authselect select $CURRENT_PROFILE - for feature in $ENABLED_FEATURES; do - authselect enable-feature $feature; - done - - authselect apply-changes -b --backup=after-hardening-custom-profile - fi - PAM_FILE_NAME=$(basename "/etc/pam.d/postlogin") - PAM_FILE_PATH="/etc/authselect/$CURRENT_PROFILE/$PAM_FILE_NAME" - - authselect apply-changes -b - fi - if ! grep -qP '^\s*session\s+'"required"'\s+pam_lastlog.so\s*.*' "$PAM_FILE_PATH"; then - # Line matching group + control + module was not found. Check group + module. - if [ "$(grep -cP '^\s*session\s+.*\s+pam_lastlog.so\s*' "$PAM_FILE_PATH")" -eq 1 ]; then - # The control is updated only if one single line matches. - sed -i -E --follow-symlinks 's/^(\s*session\s+).*(\bpam_lastlog.so.*)/\1'"required"' \2/' "$PAM_FILE_PATH" - else - sed -i --follow-symlinks '1i session '"required"' pam_lastlog.so' "$PAM_FILE_PATH" + # The "local" profile does not contain essential security features required by multiple Benchmarks. + # If currently used, it is replaced by "sssd", which is the best option in this case. + if [[ $CURRENT_PROFILE == local ]]; then + CURRENT_PROFILE="sssd" fi - fi - # Check the option - if ! grep -qP '^\s*session\s+'"required"'\s+pam_lastlog.so\s*.*\sshowfailed\b' "$PAM_FILE_PATH"; then - sed -i -E --follow-symlinks '/\s*session\s+'"required"'\s+pam_lastlog.so.*/ s/$/ showfailed/' "$PAM_FILE_PATH" - fi - if [ -f /usr/bin/authselect ]; then - - authselect apply-changes -b - fi -else - echo "/etc/pam.d/postlogin was not found" >&2 -fi -if [ -e "/etc/pam.d/postlogin" ] ; then - PAM_FILE_PATH="/etc/pam.d/postlogin" - if [ -f /usr/bin/authselect ]; then - - if ! authselect check; then - echo " - authselect integrity check failed. Remediation aborted! - This remediation could not be applied because an authselect profile was not selected or the selected profile is not intact. - It is not recommended to manually edit the PAM files when authselect tool is available. - In cases where the default authselect profile does not cover a specific demand, a custom authselect profile is recommended." - exit 1 - fi - - CURRENT_PROFILE=$(authselect current -r | awk '{ print $1 }') - # If not already in use, a custom profile is created preserving the enabled features. - if [[ ! $CURRENT_PROFILE == custom/* ]]; then - ENABLED_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }') authselect create-profile hardening -b $CURRENT_PROFILE CURRENT_PROFILE="custom/hardening" @@ -13698,24 +16233,243 @@ if [ -e "/etc/pam.d/postlogin" ] ; then PAM_FILE_PATH="/etc/authselect/$CURRENT_PROFILE/$PAM_FILE_NAME" authselect apply-changes -b - fi - -if grep -qP '^\s*session\s.*\bpam_lastlog.so\s.*\bsilent\b' "$PAM_FILE_PATH"; then - sed -i -E --follow-symlinks 's/(.*session.*pam_lastlog.so.*)\bsilent\b=?[[:alnum:]]*(.*)/\1\2/g' "$PAM_FILE_PATH" -fi - if [ -f /usr/bin/authselect ]; then - - authselect apply-changes -b + if [ -e "$PAM_FILE_PATH" ] ; then + PAM_FILE_PATH="$PAM_FILE_PATH" + if [ -f /usr/bin/authselect ]; then + + if ! authselect check; then + echo " + authselect integrity check failed. Remediation aborted! + This remediation could not be applied because an authselect profile was not selected or the selected profile is not intact. + It is not recommended to manually edit the PAM files when authselect tool is available. + In cases where the default authselect profile does not cover a specific demand, a custom authselect profile is recommended." + exit 1 + fi + + CURRENT_PROFILE=$(authselect current -r | awk '{ print $1 }') + # If not already in use, a custom profile is created preserving the enabled features. + if [[ ! $CURRENT_PROFILE == custom/* ]]; then + ENABLED_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }') + # The "local" profile does not contain essential security features required by multiple Benchmarks. + # If currently used, it is replaced by "sssd", which is the best option in this case. + if [[ $CURRENT_PROFILE == local ]]; then + CURRENT_PROFILE="sssd" + fi + authselect create-profile hardening -b $CURRENT_PROFILE + CURRENT_PROFILE="custom/hardening" + + authselect apply-changes -b --backup=before-hardening-custom-profile + authselect select $CURRENT_PROFILE + for feature in $ENABLED_FEATURES; do + authselect enable-feature $feature; + done + + authselect apply-changes -b --backup=after-hardening-custom-profile + fi + PAM_FILE_NAME=$(basename "$PAM_FILE_PATH") + PAM_FILE_PATH="/etc/authselect/$CURRENT_PROFILE/$PAM_FILE_NAME" + + authselect apply-changes -b + fi + + + if ! grep -qP "^\s*session\s+required\s+pam_lastlog.so\s*.*" "$PAM_FILE_PATH"; then + # Line matching group + control + module was not found. Check group + module. + if [ "$(grep -cP '^\s*session\s+.*\s+pam_lastlog.so\s*' "$PAM_FILE_PATH")" -eq 1 ]; then + # The control is updated only if one single line matches. + sed -i -E --follow-symlinks "s/^(\s*session\s+).*(\bpam_lastlog.so.*)/\1required \2/" "$PAM_FILE_PATH" + else + LAST_MATCH_LINE=$(grep -nP "^\s*session\s+.*pam_succeed_if\.so.*" "$PAM_FILE_PATH" | tail -n 1 | cut -d: -f 1) + if [ ! -z $LAST_MATCH_LINE ]; then + sed -i --follow-symlinks $LAST_MATCH_LINE" a session required pam_lastlog.so" "$PAM_FILE_PATH" + else + echo "session required pam_lastlog.so" >> "$PAM_FILE_PATH" + fi + fi + fi + # Check the option + if ! grep -qP "^\s*session\s+required\s+pam_lastlog.so\s*.*\sshowfailed\b" "$PAM_FILE_PATH"; then + sed -i -E --follow-symlinks "/\s*session\s+required\s+pam_lastlog.so.*/ s/$/ showfailed/" "$PAM_FILE_PATH" + fi + if [ -f /usr/bin/authselect ]; then + + authselect apply-changes -b + fi + else + echo "$PAM_FILE_PATH was not found" >&2 + fi + if [ -e "$PAM_FILE_PATH" ] ; then + PAM_FILE_PATH="$PAM_FILE_PATH" + if [ -f /usr/bin/authselect ]; then + + if ! authselect check; then + echo " + authselect integrity check failed. Remediation aborted! + This remediation could not be applied because an authselect profile was not selected or the selected profile is not intact. + It is not recommended to manually edit the PAM files when authselect tool is available. + In cases where the default authselect profile does not cover a specific demand, a custom authselect profile is recommended." + exit 1 + fi + + CURRENT_PROFILE=$(authselect current -r | awk '{ print $1 }') + # If not already in use, a custom profile is created preserving the enabled features. + if [[ ! $CURRENT_PROFILE == custom/* ]]; then + ENABLED_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }') + # The "local" profile does not contain essential security features required by multiple Benchmarks. + # If currently used, it is replaced by "sssd", which is the best option in this case. + if [[ $CURRENT_PROFILE == local ]]; then + CURRENT_PROFILE="sssd" + fi + authselect create-profile hardening -b $CURRENT_PROFILE + CURRENT_PROFILE="custom/hardening" + + authselect apply-changes -b --backup=before-hardening-custom-profile + authselect select $CURRENT_PROFILE + for feature in $ENABLED_FEATURES; do + authselect enable-feature $feature; + done + + authselect apply-changes -b --backup=after-hardening-custom-profile + fi + PAM_FILE_NAME=$(basename "$PAM_FILE_PATH") + PAM_FILE_PATH="/etc/authselect/$CURRENT_PROFILE/$PAM_FILE_NAME" + + authselect apply-changes -b + fi + + if grep -qP "^\s*session\s+required\s+pam_lastlog.so\s.*\bsilent\b" "$PAM_FILE_PATH"; then + sed -i -E --follow-symlinks "s/(.*session.*required.*pam_lastlog.so.*)\ssilent=?[[:alnum:]]*(.*)/\1\2/g" "$PAM_FILE_PATH" + fi + if [ -f /usr/bin/authselect ]; then + + authselect apply-changes -b + fi + else + echo "$PAM_FILE_PATH was not found" >&2 + fi fi else - echo "/etc/pam.d/postlogin was not found" >&2 + if [ -e "/etc/pam.d/postlogin" ] ; then + PAM_FILE_PATH="/etc/pam.d/postlogin" + if [ -f /usr/bin/authselect ]; then + + if ! authselect check; then + echo " + authselect integrity check failed. Remediation aborted! + This remediation could not be applied because an authselect profile was not selected or the selected profile is not intact. + It is not recommended to manually edit the PAM files when authselect tool is available. + In cases where the default authselect profile does not cover a specific demand, a custom authselect profile is recommended." + exit 1 + fi + + CURRENT_PROFILE=$(authselect current -r | awk '{ print $1 }') + # If not already in use, a custom profile is created preserving the enabled features. + if [[ ! $CURRENT_PROFILE == custom/* ]]; then + ENABLED_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }') + # The "local" profile does not contain essential security features required by multiple Benchmarks. + # If currently used, it is replaced by "sssd", which is the best option in this case. + if [[ $CURRENT_PROFILE == local ]]; then + CURRENT_PROFILE="sssd" + fi + authselect create-profile hardening -b $CURRENT_PROFILE + CURRENT_PROFILE="custom/hardening" + + authselect apply-changes -b --backup=before-hardening-custom-profile + authselect select $CURRENT_PROFILE + for feature in $ENABLED_FEATURES; do + authselect enable-feature $feature; + done + + authselect apply-changes -b --backup=after-hardening-custom-profile + fi + PAM_FILE_NAME=$(basename "/etc/pam.d/postlogin") + PAM_FILE_PATH="/etc/authselect/$CURRENT_PROFILE/$PAM_FILE_NAME" + + authselect apply-changes -b + fi + + + if ! grep -qP "^\s*session\s+required\s+pam_lastlog.so\s*.*" "$PAM_FILE_PATH"; then + # Line matching group + control + module was not found. Check group + module. + if [ "$(grep -cP '^\s*session\s+.*\s+pam_lastlog.so\s*' "$PAM_FILE_PATH")" -eq 1 ]; then + # The control is updated only if one single line matches. + sed -i -E --follow-symlinks "s/^(\s*session\s+).*(\bpam_lastlog.so.*)/\1required \2/" "$PAM_FILE_PATH" + else + LAST_MATCH_LINE=$(grep -nP "^\s*session\s+.*pam_succeed_if\.so.*" "$PAM_FILE_PATH" | tail -n 1 | cut -d: -f 1) + if [ ! -z $LAST_MATCH_LINE ]; then + sed -i --follow-symlinks $LAST_MATCH_LINE" a session required pam_lastlog.so" "$PAM_FILE_PATH" + else + echo "session required pam_lastlog.so" >> "$PAM_FILE_PATH" + fi + fi + fi + # Check the option + if ! grep -qP "^\s*session\s+required\s+pam_lastlog.so\s*.*\sshowfailed\b" "$PAM_FILE_PATH"; then + sed -i -E --follow-symlinks "/\s*session\s+required\s+pam_lastlog.so.*/ s/$/ showfailed/" "$PAM_FILE_PATH" + fi + if [ -f /usr/bin/authselect ]; then + + authselect apply-changes -b + fi + else + echo "/etc/pam.d/postlogin was not found" >&2 + fi + if [ -e "/etc/pam.d/postlogin" ] ; then + PAM_FILE_PATH="/etc/pam.d/postlogin" + if [ -f /usr/bin/authselect ]; then + + if ! authselect check; then + echo " + authselect integrity check failed. Remediation aborted! + This remediation could not be applied because an authselect profile was not selected or the selected profile is not intact. + It is not recommended to manually edit the PAM files when authselect tool is available. + In cases where the default authselect profile does not cover a specific demand, a custom authselect profile is recommended." + exit 1 + fi + + CURRENT_PROFILE=$(authselect current -r | awk '{ print $1 }') + # If not already in use, a custom profile is created preserving the enabled features. + if [[ ! $CURRENT_PROFILE == custom/* ]]; then + ENABLED_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }') + # The "local" profile does not contain essential security features required by multiple Benchmarks. + # If currently used, it is replaced by "sssd", which is the best option in this case. + if [[ $CURRENT_PROFILE == local ]]; then + CURRENT_PROFILE="sssd" + fi + authselect create-profile hardening -b $CURRENT_PROFILE + CURRENT_PROFILE="custom/hardening" + + authselect apply-changes -b --backup=before-hardening-custom-profile + authselect select $CURRENT_PROFILE + for feature in $ENABLED_FEATURES; do + authselect enable-feature $feature; + done + + authselect apply-changes -b --backup=after-hardening-custom-profile + fi + PAM_FILE_NAME=$(basename "/etc/pam.d/postlogin") + PAM_FILE_PATH="/etc/authselect/$CURRENT_PROFILE/$PAM_FILE_NAME" + + authselect apply-changes -b + fi + + if grep -qP "^\s*session\s+required\s+pam_lastlog.so\s.*\bsilent\b" "$PAM_FILE_PATH"; then + sed -i -E --follow-symlinks "s/(.*session.*required.*pam_lastlog.so.*)\ssilent=?[[:alnum:]]*(.*)/\1\2/g" "$PAM_FILE_PATH" + fi + if [ -f /usr/bin/authselect ]; then + + authselect apply-changes -b + fi + else + echo "/etc/pam.d/postlogin was not found" >&2 + fi fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: @@ -13723,6 +16477,8 @@ fi - NIST-800-53-AC-9 - NIST-800-53-AC-9(1) - PCI-DSS-Req-10.2.4 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.4 - configure_strategy - display_login_attempts @@ -13731,17 +16487,19 @@ fi - low_severity - no_reboot_needed -- name: Ensure PAM Displays Last Logon/Access Notification - Check if /etc/pam.d/postlogin - file is present +- name: Ensure PAM Displays Last Logon/Access Notification - Check if system relies + on authselect tool ansible.builtin.stat: - path: /etc/pam.d/postlogin - register: result_pam_file_present + path: /usr/bin/authselect + register: result_authselect_present when: '"pam" in ansible_facts.packages' tags: - CJIS-5.5.2 - NIST-800-53-AC-9 - NIST-800-53-AC-9(1) - PCI-DSS-Req-10.2.4 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.4 - configure_strategy - display_login_attempts @@ -13750,8 +16508,104 @@ fi - low_severity - no_reboot_needed -- name: Ensure PAM Displays Last Logon/Access Notification - Check the proper remediation - for the system +- name: Ensure PAM Displays Last Logon/Access Notification - Collect the Available + authselect Features + ansible.builtin.command: + cmd: authselect list-features sssd + register: result_authselect_available_features + changed_when: false + when: + - '"pam" in ansible_facts.packages' + - result_authselect_present.stat.exists + tags: + - CJIS-5.5.2 + - NIST-800-53-AC-9 + - NIST-800-53-AC-9(1) + - PCI-DSS-Req-10.2.4 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 + - PCI-DSSv4-10.2.1.4 + - configure_strategy + - display_login_attempts + - low_complexity + - low_disruption + - low_severity + - no_reboot_needed + +- name: Ensure PAM Displays Last Logon/Access Notification - Configure pam_lastlog.so + Using authselect Feature + block: + + - name: Ensure PAM Displays Last Logon/Access Notification - Check integrity of + authselect current profile + ansible.builtin.command: + cmd: authselect check + register: result_authselect_check_cmd + changed_when: false + failed_when: false + + - name: Ensure PAM Displays Last Logon/Access Notification - Informative message + based on the authselect integrity check result + ansible.builtin.assert: + that: + - result_authselect_check_cmd.rc == 0 + fail_msg: + - authselect integrity check failed. Remediation aborted! + - This remediation could not be applied because an authselect profile was not + selected or the selected profile is not intact. + - It is not recommended to manually edit the PAM files when authselect tool + is available. + - In cases where the default authselect profile does not cover a specific demand, + a custom authselect profile is recommended. + success_msg: + - authselect integrity check passed + + - name: Ensure PAM Displays Last Logon/Access Notification - Get authselect Features + Currently Enabled + ansible.builtin.shell: + cmd: authselect current | tail -n+3 | awk '{ print $2 }' + register: result_authselect_features + changed_when: false + when: + - result_authselect_check_cmd is success + + - name: Ensure PAM Displays Last Logon/Access Notification - Ensure "with-silent-lastlog" + Feature is Disabled Using authselect Tool + ansible.builtin.command: + cmd: authselect disable-feature with-silent-lastlog + register: result_authselect_disable_feature_cmd + when: + - result_authselect_check_cmd is success + - result_authselect_features.stdout is search("with-silent-lastlog") + + - name: Ensure PAM Displays Last Logon/Access Notification - Ensure authselect changes + are applied + ansible.builtin.command: + cmd: authselect apply-changes -b + when: + - result_authselect_disable_feature_cmd is not skipped + - result_authselect_disable_feature_cmd is success + when: + - '"pam" in ansible_facts.packages' + - result_authselect_present.stat.exists + - result_authselect_available_features.stdout is search("with-silent-lastlog") + tags: + - CJIS-5.5.2 + - NIST-800-53-AC-9 + - NIST-800-53-AC-9(1) + - PCI-DSS-Req-10.2.4 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 + - PCI-DSSv4-10.2.1.4 + - configure_strategy + - display_login_attempts + - low_complexity + - low_disruption + - low_severity + - no_reboot_needed + +- name: Ensure PAM Displays Last Logon/Access Notification - Configure pam_lastlog.so + in appropriate PAM files block: - name: Ensure PAM Displays Last Logon/Access Notification - Define the PAM file @@ -13846,7 +16700,16 @@ fi }} when: - result_authselect_check_cmd is success - - authselect_current_profile is not match("custom/") + - authselect_current_profile is not match("^(custom/|local)") + - not result_authselect_custom_profile_present.stat.exists + + - name: Ensure PAM Displays Last Logon/Access Notification - Create an authselect + custom profile based on sssd profile + ansible.builtin.command: + cmd: authselect create-profile hardening -b sssd + when: + - result_authselect_check_cmd is success + - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists - name: Ensure PAM Displays Last Logon/Access Notification - Ensure authselect @@ -13898,11 +16761,16 @@ fi when: - result_authselect_present.stat.exists + - name: Ensure PAM Displays Last Logon/Access Notification - Define a fact for control + already filtered in case filters are used + ansible.builtin.set_fact: + pam_module_control: required + - name: Ensure PAM Displays Last Logon/Access Notification - Check if expected PAM module line is present in {{ pam_file_path }} ansible.builtin.lineinfile: path: '{{ pam_file_path }}' - regexp: ^\s*session\s+required\s+pam_lastlog.so\s*.* + regexp: ^\s*session\s+{{ pam_module_control | regex_escape() }}\s+pam_lastlog.so\s*.* state: absent check_mode: true changed_when: false @@ -13927,7 +16795,7 @@ fi ansible.builtin.replace: dest: '{{ pam_file_path }}' regexp: ^(\s*session\s+).*(\bpam_lastlog.so.*) - replace: \1required \2 + replace: \1{{ pam_module_control }} \2 register: result_pam_module_edit when: - result_pam_line_other_control_present.found == 1 @@ -13936,8 +16804,8 @@ fi PAM module line is included in {{ pam_file_path }} ansible.builtin.lineinfile: dest: '{{ pam_file_path }}' - insertafter: BOF - line: session required pam_lastlog.so + insertafter: ^\s*session\s+.*pam_succeed_if\.so.* + line: session {{ pam_module_control }} pam_lastlog.so register: result_pam_module_add when: - result_pam_line_other_control_present.found == 0 or result_pam_line_other_control_present.found @@ -13957,64 +16825,53 @@ fi - result_pam_line_present.found is defined - result_pam_line_present.found == 0 + - name: Ensure PAM Displays Last Logon/Access Notification - Define a fact for control + already filtered in case filters are used + ansible.builtin.set_fact: + pam_module_control: required + - name: Ensure PAM Displays Last Logon/Access Notification - Check if the required PAM module option is present in {{ pam_file_path }} ansible.builtin.lineinfile: path: '{{ pam_file_path }}' - regexp: ^\s*session\s+required\s+pam_lastlog.so\s*.*\sshowfailed\b + regexp: ^\s*session\s+{{ pam_module_control | regex_escape() }}\s+pam_lastlog.so\s*.*\sshowfailed\b state: absent check_mode: true changed_when: false - register: result_pam_module_showfailed_option_present + register: result_pam_module_display_login_attempts_option_present - name: Ensure PAM Displays Last Logon/Access Notification - Ensure the "showfailed" PAM option for "pam_lastlog.so" is included in {{ pam_file_path }} ansible.builtin.lineinfile: path: '{{ pam_file_path }}' backrefs: true - regexp: ^(\s*session\s+required\s+pam_lastlog.so.*) + regexp: ^(\s*session\s+{{ pam_module_control | regex_escape() }}\s+pam_lastlog.so.*) line: \1 showfailed state: present - register: result_pam_showfailed_add + register: result_pam_display_login_attempts_add when: - - result_pam_module_showfailed_option_present.found == 0 + - result_pam_module_display_login_attempts_option_present.found == 0 - - name: Ensure PAM Displays Last Logon/Access Notification - Ensure authselect changes - are applied - ansible.builtin.command: - cmd: authselect apply-changes -b - when: - - result_authselect_present.stat.exists - - |- - (result_pam_showfailed_add is defined and result_pam_showfailed_add.changed) - or (result_pam_showfailed_edit is defined and result_pam_showfailed_edit.changed) - when: - - '"pam" in ansible_facts.packages' - - result_pam_file_present.stat.exists - tags: - - CJIS-5.5.2 - - NIST-800-53-AC-9 - - NIST-800-53-AC-9(1) - - PCI-DSS-Req-10.2.4 - - PCI-DSSv4-10.2.1.4 - - configure_strategy - - display_login_attempts - - low_complexity - - low_disruption - - low_severity - - no_reboot_needed + - name: Ensure PAM Displays Last Logon/Access Notification - Define a fact for control + already filtered in case filters are used + ansible.builtin.set_fact: + pam_module_control: required -- name: Ensure PAM Displays Last Logon/Access Notification - Check if /etc/pam.d/postlogin - file is present - ansible.builtin.stat: - path: /etc/pam.d/postlogin - register: result_pam_file_present + - name: Ensure PAM Displays Last Logon/Access Notification - Ensure the "silent" + option from "pam_lastlog.so" is not present in {{ pam_file_path }} + ansible.builtin.replace: + dest: '{{ pam_file_path }}' + regexp: (.*session.*{{ pam_module_control | regex_escape() }}.*pam_lastlog.so.*)\bsilent\b=?[0-9a-zA-Z]*(.*) + replace: \1\2 + register: result_pam_option_removal when: '"pam" in ansible_facts.packages' tags: - CJIS-5.5.2 - NIST-800-53-AC-9 - NIST-800-53-AC-9(1) - PCI-DSS-Req-10.2.4 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.4 - configure_strategy - display_login_attempts @@ -14022,340 +16879,510 @@ fi - low_disruption - low_severity - no_reboot_needed - -- name: Ensure PAM Displays Last Logon/Access Notification - Check the proper remediation - for the system - block: - - - name: Ensure PAM Displays Last Logon/Access Notification - Define the PAM file - to be edited as a local fact - ansible.builtin.set_fact: - pam_file_path: /etc/pam.d/postlogin - - - name: Ensure PAM Displays Last Logon/Access Notification - Check if system relies - on authselect tool - ansible.builtin.stat: - path: /usr/bin/authselect - register: result_authselect_present - - - name: Ensure PAM Displays Last Logon/Access Notification - Ensure authselect custom - profile is used if authselect is present - block: - - - name: Ensure PAM Displays Last Logon/Access Notification - Check integrity of - authselect current profile - ansible.builtin.command: - cmd: authselect check - register: result_authselect_check_cmd - changed_when: false - failed_when: false - - - name: Ensure PAM Displays Last Logon/Access Notification - Informative message - based on the authselect integrity check result - ansible.builtin.assert: - that: - - result_authselect_check_cmd.rc == 0 - fail_msg: - - authselect integrity check failed. Remediation aborted! - - This remediation could not be applied because an authselect profile was - not selected or the selected profile is not intact. - - It is not recommended to manually edit the PAM files when authselect tool - is available. - - In cases where the default authselect profile does not cover a specific - demand, a custom authselect profile is recommended. - success_msg: - - authselect integrity check passed - - - name: Ensure PAM Displays Last Logon/Access Notification - Get authselect current - profile - ansible.builtin.shell: - cmd: authselect current -r | awk '{ print $1 }' - register: result_authselect_profile - changed_when: false - when: - - result_authselect_check_cmd is success - - - name: Ensure PAM Displays Last Logon/Access Notification - Define the current - authselect profile as a local fact - ansible.builtin.set_fact: - authselect_current_profile: '{{ result_authselect_profile.stdout }}' - authselect_custom_profile: '{{ result_authselect_profile.stdout }}' - when: - - result_authselect_profile is not skipped - - result_authselect_profile.stdout is match("custom/") - - - name: Ensure PAM Displays Last Logon/Access Notification - Define the new authselect - custom profile as a local fact - ansible.builtin.set_fact: - authselect_current_profile: '{{ result_authselect_profile.stdout }}' - authselect_custom_profile: custom/hardening - when: - - result_authselect_profile is not skipped - - result_authselect_profile.stdout is not match("custom/") - - - name: Ensure PAM Displays Last Logon/Access Notification - Get authselect current - features to also enable them in the custom profile - ansible.builtin.shell: - cmd: authselect current | tail -n+3 | awk '{ print $2 }' - register: result_authselect_features - changed_when: false - when: - - result_authselect_profile is not skipped - - authselect_current_profile is not match("custom/") - - - name: Ensure PAM Displays Last Logon/Access Notification - Check if any custom - profile with the same name was already created - ansible.builtin.stat: - path: /etc/authselect/{{ authselect_custom_profile }} - register: result_authselect_custom_profile_present - changed_when: false - when: - - authselect_current_profile is not match("custom/") - - - name: Ensure PAM Displays Last Logon/Access Notification - Create an authselect - custom profile based on the current profile - ansible.builtin.command: - cmd: authselect create-profile hardening -b {{ authselect_current_profile - }} - when: - - result_authselect_check_cmd is success - - authselect_current_profile is not match("custom/") - - not result_authselect_custom_profile_present.stat.exists - - - name: Ensure PAM Displays Last Logon/Access Notification - Ensure authselect - changes are applied - ansible.builtin.command: - cmd: authselect apply-changes -b --backup=before-hardening-custom-profile - when: - - result_authselect_check_cmd is success - - result_authselect_profile is not skipped - - authselect_current_profile is not match("custom/") - - authselect_custom_profile is not match(authselect_current_profile) - - - name: Ensure PAM Displays Last Logon/Access Notification - Ensure the authselect - custom profile is selected - ansible.builtin.command: - cmd: authselect select {{ authselect_custom_profile }} - register: result_pam_authselect_select_profile - when: - - result_authselect_check_cmd is success - - result_authselect_profile is not skipped - - authselect_current_profile is not match("custom/") - - authselect_custom_profile is not match(authselect_current_profile) - - - name: Ensure PAM Displays Last Logon/Access Notification - Restore the authselect - features in the custom profile - ansible.builtin.command: - cmd: authselect enable-feature {{ item }} - loop: '{{ result_authselect_features.stdout_lines }}' - register: result_pam_authselect_restore_features - when: - - result_authselect_profile is not skipped - - result_authselect_features is not skipped - - result_pam_authselect_select_profile is not skipped - - - name: Ensure PAM Displays Last Logon/Access Notification - Ensure authselect - changes are applied - ansible.builtin.command: - cmd: authselect apply-changes -b --backup=after-hardening-custom-profile - when: - - result_authselect_check_cmd is success - - result_authselect_profile is not skipped - - result_pam_authselect_restore_features is not skipped - - - name: Ensure PAM Displays Last Logon/Access Notification - Change the PAM file - to be edited according to the custom authselect profile - ansible.builtin.set_fact: - pam_file_path: /etc/authselect/{{ authselect_custom_profile }}/{{ pam_file_path - | basename }} - when: - - result_authselect_present.stat.exists - - - name: Ensure PAM Displays Last Logon/Access Notification - Ensure the "silent" - option from "pam_lastlog.so" is not present in {{ pam_file_path }} - ansible.builtin.replace: - dest: '{{ pam_file_path }}' - regexp: (.*session.*pam_lastlog.so.*)\bsilent\b=?[0-9a-zA-Z]*(.*) - replace: \1\2 - register: result_pam_option_removal - - - name: Ensure PAM Displays Last Logon/Access Notification - Ensure authselect changes - are applied - ansible.builtin.command: - cmd: authselect apply-changes -b - when: - - result_authselect_present.stat.exists - - result_pam_option_removal is changed - when: - - '"pam" in ansible_facts.packages' - - result_pam_file_present.stat.exists - tags: - - CJIS-5.5.2 - - NIST-800-53-AC-9 - - NIST-800-53-AC-9(1) - - PCI-DSS-Req-10.2.4 - - PCI-DSSv4-10.2.1.4 - - configure_strategy - - display_login_attempts - - low_complexity - - low_disruption - - low_severity - - no_reboot_needed - - - - - - - - - - Set Lockouts for Failed Password Attempts - The pam_faillock PAM module provides the capability to + + + + + + + + + + Set Lockouts for Failed Password Attempts + The pam_faillock PAM module provides the capability to lock out user accounts after a number of failed login attempts. Its documentation is available in /usr/share/doc/pam-VERSION/txts/README.pam_faillock. - - Locking out user accounts presents the + + + + Locking out user accounts presents the risk of a denial-of-service attack. The lockout policy must weigh whether the risk of such a denial-of-service attack outweighs the benefits of thwarting -password guessing attacks. - - fail_deny - Number of failed login attempts before account lockout - 10 - 3 - 4 - 5 - 6 - 8 - 3 - - - faillock directory - The directory where the user files with the failure records are kept - /var/log/faillock - /var/log/faillock - - - fail_interval - Interval for counting failed login attempts before account lockout - 100000000 - 1800 - 3600 - 86400 - 900 - 900 - - - fail_unlock_time - Seconds before automatic unlocking or permanently locking after excessive failed logins - 1800 - 3600 - 600 - 604800 - 86400 - 900 - 0 - 0 - - - tally2_unlock_time - Seconds before automatic unlocking or permanently locking after excessive failed logins - 1800 - 3600 - 600 - 604800 - 86400 - 900 - 0 - 0 - - - faildelay_delay - Delay next login attempt after a failed login - 0 - 4000000 - 4000000 - - - pwhistory_remember - Prevent password re-use using password history lookup - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 5 - - - PAM pwhistory remember - control flag - 'Specify the control flag required for password remember requirement. If multiple +password guessing attacks. + + fail_deny + Number of failed login attempts before account lockout + 10 + 3 + 4 + 5 + 6 + 8 + 3 + + + faillock directory + The directory where the user files with the failure records are kept + /var/log/faillock + /var/log/faillock + /var/run/faillock + + + fail_interval + Interval for counting failed login attempts before account lockout + 100000000 + 1800 + 3600 + 86400 + 900 + 900 + + + fail_unlock_time + Seconds before automatic unlocking or permanently locking after excessive failed logins + 1800 + 3600 + 600 + 604800 + 86400 + 900 + 300 + 0 + 0 + + + tally2_unlock_time + Seconds before automatic unlocking or permanently locking after excessive failed logins + 1800 + 3600 + 600 + 604800 + 86400 + 900 + 0 + 0 + + + pwhistory_remember + Prevent password re-use using password history lookup + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 24 + 5 + + + PAM pwhistory remember - control flag + 'Specify the control flag required for password remember requirement. If multiple values are allowed write them separated by commas as in "required,requisite", -for remediations the first value will be taken' - required - optional - requisite - sufficient - binding - required,requisite - requisite,required - requisite - - - tally2 - Number of failed login attempts - 1 - 2 - 3 - 4 - 5 - 3 - - - Configure the Use of the pam_faillock.so Module in the /etc/pam.d/password-auth File. - The pam_faillock.so module must be loaded in preauth in /etc/pam.d/password-auth. - CCI-000044 - AC-7 (a) - SRG-OS-000021-GPOS-00005 - If the pam_faillock.so module is not loaded the system will not correctly lockout accounts to prevent -password guessing attacks. - - - - - - Configure the Use of the pam_faillock.so Module in the /etc/pam.d/system-auth File. - The pam_faillock.so module must be loaded in preauth in /etc/pam.d/system-auth. - CCI-000044 - AC-7 (a) - SRG-OS-000021-GPOS-00005 - If the pam_faillock.so module is not loaded the system will not correctly lockout accounts to prevent -password guessing attacks. - - - - - - An SELinux Context must be configured for the pam_faillock.so records directory - The dir configuration option in PAM pam_faillock.so module defines where the lockout -records is stored. The configured directory must have the correct SELinux context. - CCI-000044 - AC-7 (a) - SRG-OS-000021-GPOS-00005 - Not having the correct SELinux context on the pam_faillock.so records directory may lead to -unauthorized access to the directory. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then +for remediations the first value will be taken' + required + optional + requisite + sufficient + binding + required,requisite + requisite,required + requisite + + + tally2 + Number of failed login attempts + 1 + 2 + 3 + 4 + 5 + 10 + 3 + + + Configure the Use of the pam_faillock.so Module in the /etc/pam.d/password-auth File. + The pam_faillock.so module must be loaded in preauth in /etc/pam.d/password-auth. + CCI-000044 + AC-7 (a) + SRG-OS-000021-GPOS-00005 + OL09-00-003012 + SV-271838r1092226_rule + If the pam_faillock.so module is not loaded the system will not correctly lockout accounts to prevent +password guessing attacks. + +if [ -f /usr/bin/authselect ]; then + if ! authselect check; then +echo " +authselect integrity check failed. Remediation aborted! +This remediation could not be applied because an authselect profile was not selected or the selected profile is not intact. +It is not recommended to manually edit the PAM files when authselect tool is available. +In cases where the default authselect profile does not cover a specific demand, a custom authselect profile is recommended." +exit 1 +fi +authselect enable-feature with-faillock -#!/bin/bash +authselect apply-changes -b +else + +AUTH_FILES=("/etc/pam.d/system-auth" "/etc/pam.d/password-auth") +for pam_file in "${AUTH_FILES[@]}" +do + if ! grep -qE '^\s*auth\s+required\s+pam_faillock\.so\s+(preauth silent|authfail).*$' "$pam_file" ; then + sed -i --follow-symlinks '/^auth.*sufficient.*pam_unix\.so.*/i auth required pam_faillock.so preauth silent' "$pam_file" + sed -i --follow-symlinks '/^auth.*required.*pam_deny\.so.*/i auth required pam_faillock.so authfail' "$pam_file" + sed -i --follow-symlinks '/^account.*required.*pam_unix\.so.*/i account required pam_faillock.so' "$pam_file" + fi + sed -Ei 's/(auth.*)(\[default=die\])(.*pam_faillock\.so)/\1required \3/g' "$pam_file" +done + +fi + + - name: Configure the Use of the pam_faillock.so Module in the /etc/pam.d/password-auth + File. - Check if system relies on authselect tool + ansible.builtin.stat: + path: /usr/bin/authselect + register: result_authselect_present + tags: + - DISA-STIG-OL09-00-003012 + - NIST-800-53-AC-7 (a) + - account_password_pam_faillock_password_auth + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Configure the Use of the pam_faillock.so Module in the /etc/pam.d/password-auth + File. - Remediation where authselect tool is present + block: + + - name: Configure the Use of the pam_faillock.so Module in the /etc/pam.d/password-auth + File. - Check integrity of authselect current profile + ansible.builtin.command: + cmd: authselect check + register: result_authselect_check_cmd + changed_when: false + failed_when: false + + - name: Configure the Use of the pam_faillock.so Module in the /etc/pam.d/password-auth + File. - Informative message based on the authselect integrity check result + ansible.builtin.assert: + that: + - result_authselect_check_cmd.rc == 0 + fail_msg: + - authselect integrity check failed. Remediation aborted! + - This remediation could not be applied because an authselect profile was not + selected or the selected profile is not intact. + - It is not recommended to manually edit the PAM files when authselect tool + is available. + - In cases where the default authselect profile does not cover a specific demand, + a custom authselect profile is recommended. + success_msg: + - authselect integrity check passed + + - name: Configure the Use of the pam_faillock.so Module in the /etc/pam.d/password-auth + File. - Get authselect current features + ansible.builtin.shell: + cmd: authselect current | tail -n+3 | awk '{ print $2 }' + register: result_authselect_features + changed_when: false + when: + - result_authselect_check_cmd is success + + - name: Configure the Use of the pam_faillock.so Module in the /etc/pam.d/password-auth + File. - Ensure "with-faillock" feature is enabled using authselect tool + ansible.builtin.command: + cmd: authselect enable-feature with-faillock + register: result_authselect_enable_feature_cmd + when: + - result_authselect_check_cmd is success + - result_authselect_features.stdout is not search("with-faillock") + + - name: Configure the Use of the pam_faillock.so Module in the /etc/pam.d/password-auth + File. - Ensure authselect changes are applied + ansible.builtin.command: + cmd: authselect apply-changes -b + when: + - result_authselect_enable_feature_cmd is not skipped + - result_authselect_enable_feature_cmd is success + when: result_authselect_present.stat.exists + tags: + - DISA-STIG-OL09-00-003012 + - NIST-800-53-AC-7 (a) + - account_password_pam_faillock_password_auth + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Configure the Use of the pam_faillock.so Module in the /etc/pam.d/password-auth + File. - Remediation where authselect tool is not present + block: + + - name: Configure the Use of the pam_faillock.so Module in the /etc/pam.d/password-auth + File. - Check if pam_faillock.so is already enabled + ansible.builtin.lineinfile: + path: /etc/pam.d/system-auth + regexp: .*auth.*pam_faillock\.so (preauth|authfail) + state: absent + check_mode: true + changed_when: false + register: result_pam_faillock_is_enabled + + - name: Configure the Use of the pam_faillock.so Module in the /etc/pam.d/password-auth + File. - Enable pam_faillock.so preauth editing PAM files + ansible.builtin.lineinfile: + path: '{{ item }}' + line: auth required pam_faillock.so preauth + insertbefore: ^auth.*sufficient.*pam_unix\.so.* + state: present + loop: + - /etc/pam.d/system-auth + - /etc/pam.d/password-auth + when: + - result_pam_faillock_is_enabled.found == 0 + + - name: Configure the Use of the pam_faillock.so Module in the /etc/pam.d/password-auth + File. - Enable pam_faillock.so authfail editing PAM files + ansible.builtin.lineinfile: + path: '{{ item }}' + line: auth required pam_faillock.so authfail + insertbefore: ^auth.*required.*pam_deny\.so.* + state: present + loop: + - /etc/pam.d/system-auth + - /etc/pam.d/password-auth + when: + - result_pam_faillock_is_enabled.found == 0 + + - name: Configure the Use of the pam_faillock.so Module in the /etc/pam.d/password-auth + File. - Enable pam_faillock.so account section editing PAM files + ansible.builtin.lineinfile: + path: '{{ item }}' + line: account required pam_faillock.so + insertbefore: ^account.*required.*pam_unix\.so.* + state: present + loop: + - /etc/pam.d/system-auth + - /etc/pam.d/password-auth + when: + - result_pam_faillock_is_enabled.found == 0 + when: not result_authselect_present.stat.exists + tags: + - DISA-STIG-OL09-00-003012 + - NIST-800-53-AC-7 (a) + - account_password_pam_faillock_password_auth + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Configure the Use of the pam_faillock.so Module in the /etc/pam.d/system-auth File. + The pam_faillock.so module must be loaded in preauth in /etc/pam.d/system-auth. + CCI-000044 + AC-7 (a) + SRG-OS-000021-GPOS-00005 + OL09-00-003011 + SV-271837r1092223_rule + If the pam_faillock.so module is not loaded the system will not correctly lockout accounts to prevent +password guessing attacks. + +if [ -f /usr/bin/authselect ]; then + if ! authselect check; then +echo " +authselect integrity check failed. Remediation aborted! +This remediation could not be applied because an authselect profile was not selected or the selected profile is not intact. +It is not recommended to manually edit the PAM files when authselect tool is available. +In cases where the default authselect profile does not cover a specific demand, a custom authselect profile is recommended." +exit 1 +fi +authselect enable-feature with-faillock + +authselect apply-changes -b +else + +AUTH_FILES=("/etc/pam.d/system-auth" "/etc/pam.d/password-auth") +for pam_file in "${AUTH_FILES[@]}" +do + if ! grep -qE '^\s*auth\s+required\s+pam_faillock\.so\s+(preauth silent|authfail).*$' "$pam_file" ; then + sed -i --follow-symlinks '/^auth.*sufficient.*pam_unix\.so.*/i auth required pam_faillock.so preauth silent' "$pam_file" + sed -i --follow-symlinks '/^auth.*required.*pam_deny\.so.*/i auth required pam_faillock.so authfail' "$pam_file" + sed -i --follow-symlinks '/^account.*required.*pam_unix\.so.*/i account required pam_faillock.so' "$pam_file" + fi + sed -Ei 's/(auth.*)(\[default=die\])(.*pam_faillock\.so)/\1required \3/g' "$pam_file" +done + +fi + + - name: Configure the Use of the pam_faillock.so Module in the /etc/pam.d/system-auth + File. - Check if system relies on authselect tool + ansible.builtin.stat: + path: /usr/bin/authselect + register: result_authselect_present + tags: + - DISA-STIG-OL09-00-003011 + - NIST-800-53-AC-7 (a) + - account_password_pam_faillock_system_auth + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Configure the Use of the pam_faillock.so Module in the /etc/pam.d/system-auth + File. - Remediation where authselect tool is present + block: + + - name: Configure the Use of the pam_faillock.so Module in the /etc/pam.d/system-auth + File. - Check integrity of authselect current profile + ansible.builtin.command: + cmd: authselect check + register: result_authselect_check_cmd + changed_when: false + failed_when: false + + - name: Configure the Use of the pam_faillock.so Module in the /etc/pam.d/system-auth + File. - Informative message based on the authselect integrity check result + ansible.builtin.assert: + that: + - result_authselect_check_cmd.rc == 0 + fail_msg: + - authselect integrity check failed. Remediation aborted! + - This remediation could not be applied because an authselect profile was not + selected or the selected profile is not intact. + - It is not recommended to manually edit the PAM files when authselect tool + is available. + - In cases where the default authselect profile does not cover a specific demand, + a custom authselect profile is recommended. + success_msg: + - authselect integrity check passed + + - name: Configure the Use of the pam_faillock.so Module in the /etc/pam.d/system-auth + File. - Get authselect current features + ansible.builtin.shell: + cmd: authselect current | tail -n+3 | awk '{ print $2 }' + register: result_authselect_features + changed_when: false + when: + - result_authselect_check_cmd is success + + - name: Configure the Use of the pam_faillock.so Module in the /etc/pam.d/system-auth + File. - Ensure "with-faillock" feature is enabled using authselect tool + ansible.builtin.command: + cmd: authselect enable-feature with-faillock + register: result_authselect_enable_feature_cmd + when: + - result_authselect_check_cmd is success + - result_authselect_features.stdout is not search("with-faillock") + + - name: Configure the Use of the pam_faillock.so Module in the /etc/pam.d/system-auth + File. - Ensure authselect changes are applied + ansible.builtin.command: + cmd: authselect apply-changes -b + when: + - result_authselect_enable_feature_cmd is not skipped + - result_authselect_enable_feature_cmd is success + when: result_authselect_present.stat.exists + tags: + - DISA-STIG-OL09-00-003011 + - NIST-800-53-AC-7 (a) + - account_password_pam_faillock_system_auth + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Configure the Use of the pam_faillock.so Module in the /etc/pam.d/system-auth + File. - Remediation where authselect tool is not present + block: + + - name: Configure the Use of the pam_faillock.so Module in the /etc/pam.d/system-auth + File. - Check if pam_faillock.so is already enabled + ansible.builtin.lineinfile: + path: /etc/pam.d/system-auth + regexp: .*auth.*pam_faillock\.so (preauth|authfail) + state: absent + check_mode: true + changed_when: false + register: result_pam_faillock_is_enabled + + - name: Configure the Use of the pam_faillock.so Module in the /etc/pam.d/system-auth + File. - Enable pam_faillock.so preauth editing PAM files + ansible.builtin.lineinfile: + path: '{{ item }}' + line: auth required pam_faillock.so preauth + insertbefore: ^auth.*sufficient.*pam_unix\.so.* + state: present + loop: + - /etc/pam.d/system-auth + - /etc/pam.d/password-auth + when: + - result_pam_faillock_is_enabled.found == 0 + + - name: Configure the Use of the pam_faillock.so Module in the /etc/pam.d/system-auth + File. - Enable pam_faillock.so authfail editing PAM files + ansible.builtin.lineinfile: + path: '{{ item }}' + line: auth required pam_faillock.so authfail + insertbefore: ^auth.*required.*pam_deny\.so.* + state: present + loop: + - /etc/pam.d/system-auth + - /etc/pam.d/password-auth + when: + - result_pam_faillock_is_enabled.found == 0 + + - name: Configure the Use of the pam_faillock.so Module in the /etc/pam.d/system-auth + File. - Enable pam_faillock.so account section editing PAM files + ansible.builtin.lineinfile: + path: '{{ item }}' + line: account required pam_faillock.so + insertbefore: ^account.*required.*pam_unix\.so.* + state: present + loop: + - /etc/pam.d/system-auth + - /etc/pam.d/password-auth + when: + - result_pam_faillock_is_enabled.found == 0 + when: not result_authselect_present.stat.exists + tags: + - DISA-STIG-OL09-00-003011 + - NIST-800-53-AC-7 (a) + - account_password_pam_faillock_system_auth + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + An SELinux Context must be configured for the pam_faillock.so records directory + The dir configuration option in PAM pam_faillock.so module defines where the lockout +records is stored. The configured directory must have the correct SELinux context. + CCI-000044 + AC-7 (a) + SRG-OS-000021-GPOS-00005 + OL09-00-003010 + SV-271836r1092637_rule + Not having the correct SELinux context on the pam_faillock.so records directory may lead to +unauthorized access to the directory. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then FAILLOCK_CONF_FILES="/etc/security/faillock.conf /etc/pam.d/system-auth /etc/pam.d/password-auth" faillock_dirs=$(grep -oP "^\s*(?:auth.*pam_faillock.so.*)?dir\s*=\s*(\S+)" $FAILLOCK_CONF_FILES \ @@ -14380,24 +17407,147 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - - - - - - - - Account Lockouts Must Be Logged - PAM faillock locks an account due to excessive password failures, this event must be logged. - This rule is deprecated in favor of the accounts_passwords_pam_faillock_audit rule. -Please consider replacing this rule in your files as it is not expected to receive -updates as of version 0.1.65. - CCI-000044 - AC-7 (a) - Without auditing of these events it may be harder or impossible to identify what an attacker did after an attack. - + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-003010 + - NIST-800-53-AC-7 (a) + - account_password_selinux_faillock_dir + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: An SELinux Context must be configured for the pam_faillock.so records directory + - Get directories from faillock + ansible.builtin.shell: grep -oP '^\s*(?:auth.*pam_faillock.so.*)?dir\s*=\s*(\S+)' + "{{ item }}" | sed -r 's/.*=\s*(\S+)/\1/' + register: faillock_output + with_items: + - /etc/security/faillock.conf + - /etc/pam.d/system-auth + - /etc/pam.d/password-auth + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-003010 + - NIST-800-53-AC-7 (a) + - account_password_selinux_faillock_dir + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: An SELinux Context must be configured for the pam_faillock.so records directory + - Create a list directories from faillock + ansible.builtin.set_fact: + list_faillock_dir: '{{ faillock_output.results | map(attribute=''stdout_lines'') + | flatten }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-003010 + - NIST-800-53-AC-7 (a) + - account_password_selinux_faillock_dir + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: An SELinux Context must be configured for the pam_faillock.so records directory + - Create directories for faillock + ansible.builtin.file: + path: '{{ item }}' + state: directory + with_items: '{{ list_faillock_dir }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - item != "" + tags: + - DISA-STIG-OL09-00-003010 + - NIST-800-53-AC-7 (a) + - account_password_selinux_faillock_dir + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: An SELinux Context must be configured for the pam_faillock.so records directory + - Set up SELinux context for faillock + ansible.builtin.shell: |- + if ! semanage fcontext -a -t faillog_t "{{ item }}(/.*)?"; then + semanage fcontext -m -t faillog_t "{{ item }}(/.*)?" + fi + with_items: '{{ list_faillock_dir }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - item != "" + tags: + - DISA-STIG-OL09-00-003010 + - NIST-800-53-AC-7 (a) + - account_password_selinux_faillock_dir + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: An SELinux Context must be configured for the pam_faillock.so records directory + - Restore SELinux context + ansible.builtin.command: restorecon -R -v "{{ item }}" + with_items: '{{ list_faillock_dir }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - item != "" + tags: + - DISA-STIG-OL09-00-003010 + - NIST-800-53-AC-7 (a) + - account_password_selinux_faillock_dir + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: An SELinux Context must be configured for the pam_faillock.so records directory + - Verify pam_faillock.so configuration + ansible.builtin.debug: + msg: |- + "The pam_faillock.so dir option is not set in the system. + If this is not expected, make sure pam_faillock.so is properly configured." + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - list_faillock_dir | length == 0 + tags: + - DISA-STIG-OL09-00-003010 + - NIST-800-53-AC-7 (a) + - account_password_selinux_faillock_dir + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + + + + + + + + + + Account Lockouts Must Be Logged + PAM faillock locks an account due to excessive password failures, this event must be logged. + This rule is deprecated in favor of the accounts_passwords_pam_faillock_audit rule.Please consider replacing this rule in your files as it is not expected to receive +updates as of version 0.1.65. + CCI-000044 + AC-7 (a) + Without auditing of these events it may be harder or impossible to identify what an attacker did after an attack. + if [ -f /usr/bin/authselect ]; then if ! authselect check; then echo " @@ -14426,14 +17576,16 @@ done fi AUTH_FILES=("/etc/pam.d/system-auth" "/etc/pam.d/password-auth") +SKIP_FAILLOCK_CHECK=false FAILLOCK_CONF="/etc/security/faillock.conf" -if [ -f $FAILLOCK_CONF ]; then +if [ -f $FAILLOCK_CONF ] || [ "$SKIP_FAILLOCK_CHECK" = "true" ]; then regex="^\s*audit" line="audit" if ! grep -q $regex $FAILLOCK_CONF; then echo $line >> $FAILLOCK_CONF fi + for pam_file in "${AUTH_FILES[@]}" do if [ -e "$pam_file" ] ; then @@ -14453,6 +17605,11 @@ if [ -f $FAILLOCK_CONF ]; then # If not already in use, a custom profile is created preserving the enabled features. if [[ ! $CURRENT_PROFILE == custom/* ]]; then ENABLED_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }') + # The "local" profile does not contain essential security features required by multiple Benchmarks. + # If currently used, it is replaced by "sssd", which is the best option in this case. + if [[ $CURRENT_PROFILE == local ]]; then + CURRENT_PROFILE="sssd" + fi authselect create-profile hardening -b $CURRENT_PROFILE CURRENT_PROFILE="custom/hardening" @@ -14470,8 +17627,8 @@ if [ -f $FAILLOCK_CONF ]; then authselect apply-changes -b fi - if grep -qP '^\s*auth\s.*\bpam_faillock.so\s.*\baudit\b' "$PAM_FILE_PATH"; then - sed -i -E --follow-symlinks 's/(.*auth.*pam_faillock.so.*)\baudit\b=?[[:alnum:]]*(.*)/\1\2/g' "$PAM_FILE_PATH" + if grep -qP "^\s*auth\s.*\bpam_faillock.so\s.*\baudit\b" "$PAM_FILE_PATH"; then + sed -i -E --follow-symlinks "s/(.*auth.*pam_faillock.so.*)\baudit\b=?[[:alnum:]]*(.*)/\1\2/g" "$PAM_FILE_PATH" fi if [ -f /usr/bin/authselect ]; then @@ -14481,6 +17638,7 @@ if [ -f $FAILLOCK_CONF ]; then echo "$pam_file was not found" >&2 fi done + else for pam_file in "${AUTH_FILES[@]}" do @@ -14489,8 +17647,8 @@ else fi done fi - - - name: Account Lockouts Must Be Logged - Check if system relies on authselect tool + + - name: Account Lockouts Must Be Logged - Check if system relies on authselect tool ansible.builtin.stat: path: /usr/bin/authselect register: result_authselect_present @@ -14759,7 +17917,16 @@ fi }} when: - result_authselect_check_cmd is success - - authselect_current_profile is not match("custom/") + - authselect_current_profile is not match("^(custom/|local)") + - not result_authselect_custom_profile_present.stat.exists + + - name: Account Lockouts Must Be Logged - Create an authselect custom profile + based on sssd profile + ansible.builtin.command: + cmd: authselect create-profile hardening -b sssd + when: + - result_authselect_check_cmd is success + - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists - name: Account Lockouts Must Be Logged - Ensure authselect changes are applied @@ -14809,6 +17976,11 @@ fi when: - result_authselect_present.stat.exists + - name: Account Lockouts Must Be Logged - Define a fact for control already filtered + in case filters are used + ansible.builtin.set_fact: + pam_module_control: '' + - name: Account Lockouts Must Be Logged - Ensure the "audit" option from "pam_faillock.so" is not present in {{ pam_file_path }} ansible.builtin.replace: @@ -14926,7 +18098,16 @@ fi }} when: - result_authselect_check_cmd is success - - authselect_current_profile is not match("custom/") + - authselect_current_profile is not match("^(custom/|local)") + - not result_authselect_custom_profile_present.stat.exists + + - name: Account Lockouts Must Be Logged - Create an authselect custom profile + based on sssd profile + ansible.builtin.command: + cmd: authselect create-profile hardening -b sssd + when: + - result_authselect_check_cmd is success + - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists - name: Account Lockouts Must Be Logged - Ensure authselect changes are applied @@ -14976,6 +18157,11 @@ fi when: - result_authselect_present.stat.exists + - name: Account Lockouts Must Be Logged - Define a fact for control already filtered + in case filters are used + ansible.builtin.set_fact: + pam_module_control: '' + - name: Account Lockouts Must Be Logged - Ensure the "audit" option from "pam_faillock.so" is not present in {{ pam_file_path }} ansible.builtin.replace: @@ -15038,128 +18224,133 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Account Lockouts Must Persist - By setting a `dir` in the faillock configuration account lockouts will persist across reboots. - This rule is deprecated in favor of the accounts_passwords_pam_faillock_dir rule. -Please consider replacing this rule in your files as it is not expected to receive -updates as of version 0.1.65. - CCI-000044 - AC-7 (ia) - Having lockouts persist across reboots ensures that account is only unlocked by an administrator. + + + + + + + + + + Account Lockouts Must Persist + By setting a `dir` in the faillock configuration account lockouts will persist across reboots. + This rule is deprecated in favor of the accounts_passwords_pam_faillock_dir rule.Please consider replacing this rule in your files as it is not expected to receive +updates as of version 0.1.65. + CCI-000044 + AC-7 (ia) + Having lockouts persist across reboots ensures that account is only unlocked by an administrator. If the lockouts did not persist across reboots an attack could simply reboot the system to continue brute force attacks against the accounts on the system. - - - - - - - Limit Password Reuse: password-auth - Do not allow users to reuse recent passwords. This can be accomplished by using the + + + + + + + Limit Password Reuse: password-auth + Do not allow users to reuse recent passwords. This can be accomplished by using the remember option for the pam_pwhistory PAM module. - + + On systems with newer versions of authselect, the pam_pwhistory PAM module can be enabled via authselect feature: authselect enable-feature with-pwhistory Otherwise, it should be enabled using an authselect custom profile. - + + Newer systems also have the /etc/security/pwhistory.conf file for setting pam_pwhistory module options. This file should be used whenever available. Otherwise, the pam_pwhistory module options can be set in PAM files. - + + The value for remember option must be equal or greater than - - If the system relies on authselect tool to manage PAM settings, the remediation + + + If the system relies on authselect tool to manage PAM settings, the remediation will also use authselect tool. However, if any manual modification was made in PAM files, the authselect integrity check will fail and the remediation will be aborted in order to preserve intentional changes. In this case, an informative message will -be shown in the remediation report. - Newer versions of authselect contain an authselect feature to easily and properly +be shown in the remediation report. + Newer versions of authselect contain an authselect feature to easily and properly enable pam_pwhistory.so module. If this feature is not yet available in your system, an authselect custom profile must be used to avoid integrity issues in PAM files. If a custom profile was created and used in the system before this authselect feature was available, the new feature can't be used with this custom profile and the remediation will fail. In this case, the custom profile should be recreated or manually -updated. - 1 - 12 - 15 - 16 - 5 - 5.6.2.1.1 - DSS05.04 - DSS05.05 - DSS05.07 - DSS05.10 - DSS06.03 - DSS06.10 - 3.5.8 - CCI-000200 - 4.3.3.2.2 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.2 - 4.3.3.7.4 - SR 1.1 - SR 1.10 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - A.18.1.4 - A.7.1.1 - A.9.2.1 - A.9.2.2 - A.9.2.3 - A.9.2.4 - A.9.2.6 - A.9.3.1 - A.9.4.2 - A.9.4.3 - IA-5(f) - IA-5(1)(e) - PR.AC-1 - PR.AC-6 - PR.AC-7 - Req-8.2.5 - SRG-OS-000077-GPOS-00045 - Preventing re-use of previous passwords helps ensure that a compromised password is not -re-used by a user. - - # Remediation is applicable only in certain platforms +updated. + 1 + 12 + 15 + 16 + 5 + 5.6.2.1.1 + DSS05.04 + DSS05.05 + DSS05.07 + DSS05.10 + DSS06.03 + DSS06.10 + 3.5.8 + CCI-000200 + 4.3.3.2.2 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.2 + 4.3.3.7.4 + SR 1.1 + SR 1.10 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + A.18.1.4 + A.7.1.1 + A.9.2.1 + A.9.2.2 + A.9.2.3 + A.9.2.4 + A.9.2.6 + A.9.3.1 + A.9.4.2 + A.9.4.3 + IA-5(f) + IA-5(1)(e) + PR.AC-1 + PR.AC-6 + PR.AC-7 + Req-8.2.5 + SRG-OS-000077-GPOS-00045 + 8.3.7 + 8.3 + Preventing re-use of previous passwords helps ensure that a compromised password is not +re-used by a user. + + # Remediation is applicable only in certain platforms if rpm --quiet -q pam; then -var_password_pam_remember='' -var_password_pam_remember_control_flag='' +var_password_pam_remember='' +var_password_pam_remember_control_flag='' var_password_pam_remember_control_flag="$(echo $var_password_pam_remember_control_flag | cut -d \, -f 1)" if [ -f /usr/bin/authselect ]; then - if authselect list-features minimal | grep -q with-pwhistory; then + if authselect list-features sssd | grep -q with-pwhistory; then if ! authselect check; then echo " authselect integrity check failed. Remediation aborted! @@ -15186,6 +18377,11 @@ if [ -f /usr/bin/authselect ]; then # If not already in use, a custom profile is created preserving the enabled features. if [[ ! $CURRENT_PROFILE == custom/* ]]; then ENABLED_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }') + # The "local" profile does not contain essential security features required by multiple Benchmarks. + # If currently used, it is replaced by "sssd", which is the best option in this case. + if [[ $CURRENT_PROFILE == local ]]; then + CURRENT_PROFILE="sssd" + fi authselect create-profile hardening -b $CURRENT_PROFILE CURRENT_PROFILE="custom/hardening" @@ -15201,36 +18397,40 @@ if [ -f /usr/bin/authselect ]; then PAM_FILE_PATH="/etc/authselect/$CURRENT_PROFILE/$PAM_FILE_NAME" authselect apply-changes -b - if ! grep -qP '^\s*password\s+'"$var_password_pam_remember_control_flag"'\s+pam_pwhistory.so\s*.*' "$PAM_FILE_PATH"; then + + if ! grep -qP "^\s*password\s+\$var_password_pam_remember_control_flag\s+pam_pwhistory.so\s*.*" "$PAM_FILE_PATH"; then # Line matching group + control + module was not found. Check group + module. if [ "$(grep -cP '^\s*password\s+.*\s+pam_pwhistory.so\s*' "$PAM_FILE_PATH")" -eq 1 ]; then # The control is updated only if one single line matches. - sed -i -E --follow-symlinks 's/^(\s*password\s+).*(\bpam_pwhistory.so.*)/\1'"$var_password_pam_remember_control_flag"' \2/' "$PAM_FILE_PATH" + sed -i -E --follow-symlinks "s/^(\s*password\s+).*(\bpam_pwhistory.so.*)/\1$var_password_pam_remember_control_flag \2/" "$PAM_FILE_PATH" else LAST_MATCH_LINE=$(grep -nP "^password.*requisite.*pam_pwquality\.so" "$PAM_FILE_PATH" | tail -n 1 | cut -d: -f 1) if [ ! -z $LAST_MATCH_LINE ]; then - sed -i --follow-symlinks $LAST_MATCH_LINE' a password '"$var_password_pam_remember_control_flag"' pam_pwhistory.so' "$PAM_FILE_PATH" + sed -i --follow-symlinks $LAST_MATCH_LINE" a password $var_password_pam_remember_control_flag pam_pwhistory.so" "$PAM_FILE_PATH" else - echo 'password '"$var_password_pam_remember_control_flag"' pam_pwhistory.so' >> "$PAM_FILE_PATH" + echo "password $var_password_pam_remember_control_flag pam_pwhistory.so" >> "$PAM_FILE_PATH" fi fi fi fi else - if ! grep -qP '^\s*password\s+'"$var_password_pam_remember_control_flag"'\s+pam_pwhistory.so\s*.*' "/etc/pam.d/password-auth"; then + + + if ! grep -qP "^\s*password\s+\$var_password_pam_remember_control_flag\s+pam_pwhistory.so\s*.*" "/etc/pam.d/password-auth"; then # Line matching group + control + module was not found. Check group + module. if [ "$(grep -cP '^\s*password\s+.*\s+pam_pwhistory.so\s*' "/etc/pam.d/password-auth")" -eq 1 ]; then # The control is updated only if one single line matches. - sed -i -E --follow-symlinks 's/^(\s*password\s+).*(\bpam_pwhistory.so.*)/\1'"$var_password_pam_remember_control_flag"' \2/' "/etc/pam.d/password-auth" + sed -i -E --follow-symlinks "s/^(\s*password\s+).*(\bpam_pwhistory.so.*)/\1$var_password_pam_remember_control_flag \2/" "/etc/pam.d/password-auth" else LAST_MATCH_LINE=$(grep -nP "^password.*requisite.*pam_pwquality\.so" "/etc/pam.d/password-auth" | tail -n 1 | cut -d: -f 1) if [ ! -z $LAST_MATCH_LINE ]; then - sed -i --follow-symlinks $LAST_MATCH_LINE' a password '"$var_password_pam_remember_control_flag"' pam_pwhistory.so' "/etc/pam.d/password-auth" + sed -i --follow-symlinks $LAST_MATCH_LINE" a password $var_password_pam_remember_control_flag pam_pwhistory.so" "/etc/pam.d/password-auth" else - echo 'password '"$var_password_pam_remember_control_flag"' pam_pwhistory.so' >> "/etc/pam.d/password-auth" + echo "password $var_password_pam_remember_control_flag pam_pwhistory.so" >> "/etc/pam.d/password-auth" fi fi fi + fi PWHISTORY_CONF="/etc/security/pwhistory.conf" @@ -15259,6 +18459,11 @@ if [ -f $PWHISTORY_CONF ]; then # If not already in use, a custom profile is created preserving the enabled features. if [[ ! $CURRENT_PROFILE == custom/* ]]; then ENABLED_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }') + # The "local" profile does not contain essential security features required by multiple Benchmarks. + # If currently used, it is replaced by "sssd", which is the best option in this case. + if [[ $CURRENT_PROFILE == local ]]; then + CURRENT_PROFILE="sssd" + fi authselect create-profile hardening -b $CURRENT_PROFILE CURRENT_PROFILE="custom/hardening" @@ -15276,8 +18481,8 @@ if [ -f $PWHISTORY_CONF ]; then authselect apply-changes -b fi - if grep -qP '^\s*password\s.*\bpam_pwhistory.so\s.*\bremember\b' "$PAM_FILE_PATH"; then - sed -i -E --follow-symlinks 's/(.*password.*pam_pwhistory.so.*)\bremember\b=?[[:alnum:]]*(.*)/\1\2/g' "$PAM_FILE_PATH" + if grep -qP "^\s*password\s.*\bpam_pwhistory.so\s.*\bremember\b" "$PAM_FILE_PATH"; then + sed -i -E --follow-symlinks "s/(.*password.*pam_pwhistory.so.*)\bremember\b=?[[:alnum:]]*(.*)/\1\2/g" "$PAM_FILE_PATH" fi if [ -f /usr/bin/authselect ]; then @@ -15303,6 +18508,11 @@ else # If not already in use, a custom profile is created preserving the enabled features. if [[ ! $CURRENT_PROFILE == custom/* ]]; then ENABLED_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }') + # The "local" profile does not contain essential security features required by multiple Benchmarks. + # If currently used, it is replaced by "sssd", which is the best option in this case. + if [[ $CURRENT_PROFILE == local ]]; then + CURRENT_PROFILE="sssd" + fi authselect create-profile hardening -b $CURRENT_PROFILE CURRENT_PROFILE="custom/hardening" @@ -15319,20 +18529,22 @@ else authselect apply-changes -b fi - if ! grep -qP '^\s*password\s+'"requisite"'\s+pam_pwhistory.so\s*.*' "$PAM_FILE_PATH"; then + + + if ! grep -qP "^\s*password\s+requisite\s+pam_pwhistory.so\s*.*" "$PAM_FILE_PATH"; then # Line matching group + control + module was not found. Check group + module. if [ "$(grep -cP '^\s*password\s+.*\s+pam_pwhistory.so\s*' "$PAM_FILE_PATH")" -eq 1 ]; then # The control is updated only if one single line matches. - sed -i -E --follow-symlinks 's/^(\s*password\s+).*(\bpam_pwhistory.so.*)/\1'"requisite"' \2/' "$PAM_FILE_PATH" + sed -i -E --follow-symlinks "s/^(\s*password\s+).*(\bpam_pwhistory.so.*)/\1requisite \2/" "$PAM_FILE_PATH" else - echo 'password '"requisite"' pam_pwhistory.so' >> "$PAM_FILE_PATH" + echo "password requisite pam_pwhistory.so" >> "$PAM_FILE_PATH" fi fi # Check the option - if ! grep -qP '^\s*password\s+'"requisite"'\s+pam_pwhistory.so\s*.*\sremember\b' "$PAM_FILE_PATH"; then - sed -i -E --follow-symlinks '/\s*password\s+'"requisite"'\s+pam_pwhistory.so.*/ s/$/ remember='"$var_password_pam_remember"'/' "$PAM_FILE_PATH" + if ! grep -qP "^\s*password\s+requisite\s+pam_pwhistory.so\s*.*\sremember\b" "$PAM_FILE_PATH"; then + sed -i -E --follow-symlinks "/\s*password\s+requisite\s+pam_pwhistory.so.*/ s/$/ remember=$var_password_pam_remember/" "$PAM_FILE_PATH" else - sed -i -E --follow-symlinks 's/(\s*password\s+'"requisite"'\s+pam_pwhistory.so\s+.*)('"remember"'=)[[:alnum:]]+\s*(.*)/\1\2'"$var_password_pam_remember"' \3/' "$PAM_FILE_PATH" + sed -i -E --follow-symlinks "s/(\s*password\s+requisite\s+pam_pwhistory.so\s+.*)(remember=)[[:alnum:]]+\s*(.*)/\1\2$var_password_pam_remember \3/" "$PAM_FILE_PATH" fi if [ -f /usr/bin/authselect ]; then @@ -15343,8 +18555,8 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: @@ -15353,6 +18565,8 @@ fi - NIST-800-53-IA-5(1)(e) - NIST-800-53-IA-5(f) - PCI-DSS-Req-8.2.5 + - PCI-DSSv4-8.3 + - PCI-DSSv4-8.3.7 - accounts_password_pam_pwhistory_remember_password_auth - configure_strategy - low_complexity @@ -15361,12 +18575,12 @@ fi - no_reboot_needed - name: XCCDF Value var_password_pam_remember # promote to variable set_fact: - var_password_pam_remember: !!str + var_password_pam_remember: !!str tags: - always - name: XCCDF Value var_password_pam_remember_control_flag # promote to variable set_fact: - var_password_pam_remember_control_flag: !!str + var_password_pam_remember_control_flag: !!str tags: - always @@ -15382,6 +18596,8 @@ fi - NIST-800-53-IA-5(1)(e) - NIST-800-53-IA-5(f) - PCI-DSS-Req-8.2.5 + - PCI-DSSv4-8.3 + - PCI-DSSv4-8.3.7 - accounts_password_pam_pwhistory_remember_password_auth - configure_strategy - low_complexity @@ -15391,7 +18607,7 @@ fi - name: 'Limit Password Reuse: password-auth - Collect the available authselect features' ansible.builtin.command: - cmd: authselect list-features minimal + cmd: authselect list-features sssd register: result_authselect_available_features changed_when: false when: @@ -15403,6 +18619,8 @@ fi - NIST-800-53-IA-5(1)(e) - NIST-800-53-IA-5(f) - PCI-DSS-Req-8.2.5 + - PCI-DSSv4-8.3 + - PCI-DSSv4-8.3.7 - accounts_password_pam_pwhistory_remember_password_auth - configure_strategy - low_complexity @@ -15471,6 +18689,8 @@ fi - NIST-800-53-IA-5(1)(e) - NIST-800-53-IA-5(f) - PCI-DSS-Req-8.2.5 + - PCI-DSSv4-8.3 + - PCI-DSSv4-8.3.7 - accounts_password_pam_pwhistory_remember_password_auth - configure_strategy - low_complexity @@ -15573,7 +18793,16 @@ fi }} when: - result_authselect_check_cmd is success - - authselect_current_profile is not match("custom/") + - authselect_current_profile is not match("^(custom/|local)") + - not result_authselect_custom_profile_present.stat.exists + + - name: 'Limit Password Reuse: password-auth - Create an authselect custom profile + based on sssd profile' + ansible.builtin.command: + cmd: authselect create-profile hardening -b sssd + when: + - result_authselect_check_cmd is success + - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists - name: 'Limit Password Reuse: password-auth - Ensure authselect changes are applied' @@ -15623,12 +18852,17 @@ fi when: - result_authselect_present.stat.exists + - name: 'Limit Password Reuse: password-auth - Define a fact for control already + filtered in case filters are used' + ansible.builtin.set_fact: + pam_module_control: '{{ var_password_pam_remember_control_flag.split(",")[0] + }}' + - name: 'Limit Password Reuse: password-auth - Check if expected PAM module line is present in {{ pam_file_path }}' ansible.builtin.lineinfile: path: '{{ pam_file_path }}' - regexp: ^\s*password\s+{{ var_password_pam_remember_control_flag.split(",")[0] - }}\s+pam_pwhistory.so\s*.* + regexp: ^\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_pwhistory.so\s*.* state: absent check_mode: true changed_when: false @@ -15653,7 +18887,7 @@ fi ansible.builtin.replace: dest: '{{ pam_file_path }}' regexp: ^(\s*password\s+).*(\bpam_pwhistory.so.*) - replace: \1{{ var_password_pam_remember_control_flag.split(",")[0] }} \2 + replace: \1{{ pam_module_control }} \2 register: result_pam_module_edit when: - result_pam_line_other_control_present.found == 1 @@ -15663,8 +18897,7 @@ fi ansible.builtin.lineinfile: dest: '{{ pam_file_path }}' insertafter: ^password.*requisite.*pam_pwquality\.so - line: password {{ var_password_pam_remember_control_flag.split(",")[0] - }} pam_pwhistory.so + line: password {{ pam_module_control }} pam_pwhistory.so register: result_pam_module_add when: - result_pam_line_other_control_present.found == 0 or result_pam_line_other_control_present.found @@ -15692,6 +18925,8 @@ fi - NIST-800-53-IA-5(1)(e) - NIST-800-53-IA-5(f) - PCI-DSS-Req-8.2.5 + - PCI-DSSv4-8.3 + - PCI-DSSv4-8.3.7 - accounts_password_pam_pwhistory_remember_password_auth - configure_strategy - low_complexity @@ -15711,6 +18946,8 @@ fi - NIST-800-53-IA-5(1)(e) - NIST-800-53-IA-5(f) - PCI-DSS-Req-8.2.5 + - PCI-DSSv4-8.3 + - PCI-DSSv4-8.3.7 - accounts_password_pam_pwhistory_remember_password_auth - configure_strategy - low_complexity @@ -15835,7 +19072,16 @@ fi }} when: - result_authselect_check_cmd is success - - authselect_current_profile is not match("custom/") + - authselect_current_profile is not match("^(custom/|local)") + - not result_authselect_custom_profile_present.stat.exists + + - name: 'Limit Password Reuse: password-auth - Create an authselect custom + profile based on sssd profile' + ansible.builtin.command: + cmd: authselect create-profile hardening -b sssd + when: + - result_authselect_check_cmd is success + - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists - name: 'Limit Password Reuse: password-auth - Ensure authselect changes are @@ -15887,6 +19133,11 @@ fi when: - result_authselect_present.stat.exists + - name: 'Limit Password Reuse: password-auth - Define a fact for control already + filtered in case filters are used' + ansible.builtin.set_fact: + pam_module_control: '' + - name: 'Limit Password Reuse: password-auth - Ensure the "remember" option from "pam_pwhistory.so" is not present in {{ pam_file_path }}' ansible.builtin.replace: @@ -15913,6 +19164,8 @@ fi - NIST-800-53-IA-5(1)(e) - NIST-800-53-IA-5(f) - PCI-DSS-Req-8.2.5 + - PCI-DSSv4-8.3 + - PCI-DSSv4-8.3.7 - accounts_password_pam_pwhistory_remember_password_auth - configure_strategy - low_complexity @@ -16015,7 +19268,16 @@ fi }} when: - result_authselect_check_cmd is success - - authselect_current_profile is not match("custom/") + - authselect_current_profile is not match("^(custom/|local)") + - not result_authselect_custom_profile_present.stat.exists + + - name: 'Limit Password Reuse: password-auth - Create an authselect custom profile + based on sssd profile' + ansible.builtin.command: + cmd: authselect create-profile hardening -b sssd + when: + - result_authselect_check_cmd is success + - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists - name: 'Limit Password Reuse: password-auth - Ensure authselect changes are applied' @@ -16065,11 +19327,16 @@ fi when: - result_authselect_present.stat.exists + - name: 'Limit Password Reuse: password-auth - Define a fact for control already + filtered in case filters are used' + ansible.builtin.set_fact: + pam_module_control: requisite + - name: 'Limit Password Reuse: password-auth - Check if expected PAM module line is present in {{ pam_file_path }}' ansible.builtin.lineinfile: path: '{{ pam_file_path }}' - regexp: ^\s*password\s+requisite\s+pam_pwhistory.so\s*.* + regexp: ^\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_pwhistory.so\s*.* state: absent check_mode: true changed_when: false @@ -16094,7 +19361,7 @@ fi ansible.builtin.replace: dest: '{{ pam_file_path }}' regexp: ^(\s*password\s+).*(\bpam_pwhistory.so.*) - replace: \1requisite \2 + replace: \1{{ pam_module_control }} \2 register: result_pam_module_edit when: - result_pam_line_other_control_present.found == 1 @@ -16103,7 +19370,7 @@ fi line is included in {{ pam_file_path }}' ansible.builtin.lineinfile: dest: '{{ pam_file_path }}' - line: password requisite pam_pwhistory.so + line: password {{ pam_module_control }} pam_pwhistory.so register: result_pam_module_add when: - result_pam_line_other_control_present.found == 0 or result_pam_line_other_control_present.found @@ -16122,38 +19389,45 @@ fi - result_pam_line_present.found is defined - result_pam_line_present.found == 0 + - name: 'Limit Password Reuse: password-auth - Define a fact for control already + filtered in case filters are used' + ansible.builtin.set_fact: + pam_module_control: requisite + - name: 'Limit Password Reuse: password-auth - Check if the required PAM module option is present in {{ pam_file_path }}' ansible.builtin.lineinfile: path: '{{ pam_file_path }}' - regexp: ^\s*password\s+requisite\s+pam_pwhistory.so\s*.*\sremember\b + regexp: ^\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_pwhistory.so\s*.*\sremember\b state: absent check_mode: true changed_when: false - register: result_pam_module_remember_option_present + register: result_pam_module_accounts_password_pam_pwhistory_remember_password_auth_option_present - name: 'Limit Password Reuse: password-auth - Ensure the "remember" PAM option for "pam_pwhistory.so" is included in {{ pam_file_path }}' ansible.builtin.lineinfile: path: '{{ pam_file_path }}' backrefs: true - regexp: ^(\s*password\s+requisite\s+pam_pwhistory.so.*) + regexp: ^(\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_pwhistory.so.*) line: \1 remember={{ var_password_pam_remember }} state: present - register: result_pam_remember_add + register: result_pam_accounts_password_pam_pwhistory_remember_password_auth_add when: - - result_pam_module_remember_option_present.found == 0 + - result_pam_module_accounts_password_pam_pwhistory_remember_password_auth_option_present.found + == 0 - name: 'Limit Password Reuse: password-auth - Ensure the required value for "remember" PAM option from "pam_pwhistory.so" in {{ pam_file_path }}' ansible.builtin.lineinfile: path: '{{ pam_file_path }}' backrefs: true - regexp: ^(\s*password\s+requisite\s+pam_pwhistory.so\s+.*)(remember)=[0-9a-zA-Z]+\s*(.*) + regexp: ^(\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_pwhistory.so\s+.*)(remember)=[0-9a-zA-Z]+\s*(.*) line: \1\2={{ var_password_pam_remember }} \3 - register: result_pam_remember_edit + register: result_pam_accounts_password_pam_pwhistory_remember_password_auth_edit when: - - result_pam_module_remember_option_present.found > 0 + - result_pam_module_accounts_password_pam_pwhistory_remember_password_auth_option_present.found + > 0 - name: 'Limit Password Reuse: password-auth - Ensure authselect changes are applied' ansible.builtin.command: @@ -16171,117 +19445,125 @@ fi - NIST-800-53-IA-5(1)(e) - NIST-800-53-IA-5(f) - PCI-DSS-Req-8.2.5 + - PCI-DSSv4-8.3 + - PCI-DSSv4-8.3.7 - accounts_password_pam_pwhistory_remember_password_auth - configure_strategy - low_complexity - medium_disruption - medium_severity - no_reboot_needed - - - - - - - - - - - - Limit Password Reuse: system-auth - Do not allow users to reuse recent passwords. This can be accomplished by using the + + + + + + + + + + + + Limit Password Reuse: system-auth + Do not allow users to reuse recent passwords. This can be accomplished by using the remember option for the pam_pwhistory PAM module. - + + On systems with newer versions of authselect, the pam_pwhistory PAM module can be enabled via authselect feature: authselect enable-feature with-pwhistory Otherwise, it should be enabled using an authselect custom profile. - + + Newer systems also have the /etc/security/pwhistory.conf file for setting pam_pwhistory module options. This file should be used whenever available. Otherwise, the pam_pwhistory module options can be set in PAM files. - + + The value for remember option must be equal or greater than - - If the system relies on authselect tool to manage PAM settings, the remediation + + + If the system relies on authselect tool to manage PAM settings, the remediation will also use authselect tool. However, if any manual modification was made in PAM files, the authselect integrity check will fail and the remediation will be aborted in order to preserve intentional changes. In this case, an informative message will -be shown in the remediation report. - Newer versions of authselect contain an authselect feature to easily and properly +be shown in the remediation report. + Newer versions of authselect contain an authselect feature to easily and properly enable pam_pwhistory.so module. If this feature is not yet available in your -system, an authselect custom profile must be used to avoid integrity issues in PAM files. - 1 - 12 - 15 - 16 - 5 - 5.6.2.1.1 - DSS05.04 - DSS05.05 - DSS05.07 - DSS05.10 - DSS06.03 - DSS06.10 - 3.5.8 - CCI-000200 - 4.3.3.2.2 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.2 - 4.3.3.7.4 - SR 1.1 - SR 1.10 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - A.18.1.4 - A.7.1.1 - A.9.2.1 - A.9.2.2 - A.9.2.3 - A.9.2.4 - A.9.2.6 - A.9.3.1 - A.9.4.2 - A.9.4.3 - IA-5(f) - IA-5(1)(e) - PR.AC-1 - PR.AC-6 - PR.AC-7 - Req-8.2.5 - SRG-OS-000077-GPOS-00045 - Preventing re-use of previous passwords helps ensure that a compromised password is not -re-used by a user. - - # Remediation is applicable only in certain platforms +system, an authselect custom profile must be used to avoid integrity issues in PAM files. + 1 + 12 + 15 + 16 + 5 + 5.6.2.1.1 + DSS05.04 + DSS05.05 + DSS05.07 + DSS05.10 + DSS06.03 + DSS06.10 + 3.5.8 + CCI-000200 + 4.3.3.2.2 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.2 + 4.3.3.7.4 + SR 1.1 + SR 1.10 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + A.18.1.4 + A.7.1.1 + A.9.2.1 + A.9.2.2 + A.9.2.3 + A.9.2.4 + A.9.2.6 + A.9.3.1 + A.9.4.2 + A.9.4.3 + IA-5(f) + IA-5(1)(e) + PR.AC-1 + PR.AC-6 + PR.AC-7 + Req-8.2.5 + SRG-OS-000077-GPOS-00045 + 8.3.7 + 8.3 + Preventing re-use of previous passwords helps ensure that a compromised password is not +re-used by a user. + + # Remediation is applicable only in certain platforms if rpm --quiet -q pam; then -var_password_pam_remember='' -var_password_pam_remember_control_flag='' +var_password_pam_remember='' +var_password_pam_remember_control_flag='' var_password_pam_remember_control_flag="$(echo $var_password_pam_remember_control_flag | cut -d \, -f 1)" if [ -f /usr/bin/authselect ]; then - if authselect list-features minimal | grep -q with-pwhistory; then + if authselect list-features sssd | grep -q with-pwhistory; then if ! authselect check; then echo " authselect integrity check failed. Remediation aborted! @@ -16308,6 +19590,11 @@ if [ -f /usr/bin/authselect ]; then # If not already in use, a custom profile is created preserving the enabled features. if [[ ! $CURRENT_PROFILE == custom/* ]]; then ENABLED_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }') + # The "local" profile does not contain essential security features required by multiple Benchmarks. + # If currently used, it is replaced by "sssd", which is the best option in this case. + if [[ $CURRENT_PROFILE == local ]]; then + CURRENT_PROFILE="sssd" + fi authselect create-profile hardening -b $CURRENT_PROFILE CURRENT_PROFILE="custom/hardening" @@ -16323,36 +19610,40 @@ if [ -f /usr/bin/authselect ]; then PAM_FILE_PATH="/etc/authselect/$CURRENT_PROFILE/$PAM_FILE_NAME" authselect apply-changes -b - if ! grep -qP '^\s*password\s+'"$var_password_pam_remember_control_flag"'\s+pam_pwhistory.so\s*.*' "$PAM_FILE_PATH"; then + + if ! grep -qP "^\s*password\s+\$var_password_pam_remember_control_flag\s+pam_pwhistory.so\s*.*" "$PAM_FILE_PATH"; then # Line matching group + control + module was not found. Check group + module. if [ "$(grep -cP '^\s*password\s+.*\s+pam_pwhistory.so\s*' "$PAM_FILE_PATH")" -eq 1 ]; then # The control is updated only if one single line matches. - sed -i -E --follow-symlinks 's/^(\s*password\s+).*(\bpam_pwhistory.so.*)/\1'"$var_password_pam_remember_control_flag"' \2/' "$PAM_FILE_PATH" + sed -i -E --follow-symlinks "s/^(\s*password\s+).*(\bpam_pwhistory.so.*)/\1$var_password_pam_remember_control_flag \2/" "$PAM_FILE_PATH" else LAST_MATCH_LINE=$(grep -nP "^password.*requisite.*pam_pwquality\.so" "$PAM_FILE_PATH" | tail -n 1 | cut -d: -f 1) if [ ! -z $LAST_MATCH_LINE ]; then - sed -i --follow-symlinks $LAST_MATCH_LINE' a password '"$var_password_pam_remember_control_flag"' pam_pwhistory.so' "$PAM_FILE_PATH" + sed -i --follow-symlinks $LAST_MATCH_LINE" a password $var_password_pam_remember_control_flag pam_pwhistory.so" "$PAM_FILE_PATH" else - echo 'password '"$var_password_pam_remember_control_flag"' pam_pwhistory.so' >> "$PAM_FILE_PATH" + echo "password $var_password_pam_remember_control_flag pam_pwhistory.so" >> "$PAM_FILE_PATH" fi fi fi fi else - if ! grep -qP '^\s*password\s+'"$var_password_pam_remember_control_flag"'\s+pam_pwhistory.so\s*.*' "/etc/pam.d/system-auth"; then + + + if ! grep -qP "^\s*password\s+\$var_password_pam_remember_control_flag\s+pam_pwhistory.so\s*.*" "/etc/pam.d/system-auth"; then # Line matching group + control + module was not found. Check group + module. if [ "$(grep -cP '^\s*password\s+.*\s+pam_pwhistory.so\s*' "/etc/pam.d/system-auth")" -eq 1 ]; then # The control is updated only if one single line matches. - sed -i -E --follow-symlinks 's/^(\s*password\s+).*(\bpam_pwhistory.so.*)/\1'"$var_password_pam_remember_control_flag"' \2/' "/etc/pam.d/system-auth" + sed -i -E --follow-symlinks "s/^(\s*password\s+).*(\bpam_pwhistory.so.*)/\1$var_password_pam_remember_control_flag \2/" "/etc/pam.d/system-auth" else LAST_MATCH_LINE=$(grep -nP "^password.*requisite.*pam_pwquality\.so" "/etc/pam.d/system-auth" | tail -n 1 | cut -d: -f 1) if [ ! -z $LAST_MATCH_LINE ]; then - sed -i --follow-symlinks $LAST_MATCH_LINE' a password '"$var_password_pam_remember_control_flag"' pam_pwhistory.so' "/etc/pam.d/system-auth" + sed -i --follow-symlinks $LAST_MATCH_LINE" a password $var_password_pam_remember_control_flag pam_pwhistory.so" "/etc/pam.d/system-auth" else - echo 'password '"$var_password_pam_remember_control_flag"' pam_pwhistory.so' >> "/etc/pam.d/system-auth" + echo "password $var_password_pam_remember_control_flag pam_pwhistory.so" >> "/etc/pam.d/system-auth" fi fi fi + fi PWHISTORY_CONF="/etc/security/pwhistory.conf" @@ -16381,6 +19672,11 @@ if [ -f $PWHISTORY_CONF ]; then # If not already in use, a custom profile is created preserving the enabled features. if [[ ! $CURRENT_PROFILE == custom/* ]]; then ENABLED_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }') + # The "local" profile does not contain essential security features required by multiple Benchmarks. + # If currently used, it is replaced by "sssd", which is the best option in this case. + if [[ $CURRENT_PROFILE == local ]]; then + CURRENT_PROFILE="sssd" + fi authselect create-profile hardening -b $CURRENT_PROFILE CURRENT_PROFILE="custom/hardening" @@ -16398,8 +19694,8 @@ if [ -f $PWHISTORY_CONF ]; then authselect apply-changes -b fi - if grep -qP '^\s*password\s.*\bpam_pwhistory.so\s.*\bremember\b' "$PAM_FILE_PATH"; then - sed -i -E --follow-symlinks 's/(.*password.*pam_pwhistory.so.*)\bremember\b=?[[:alnum:]]*(.*)/\1\2/g' "$PAM_FILE_PATH" + if grep -qP "^\s*password\s.*\bpam_pwhistory.so\s.*\bremember\b" "$PAM_FILE_PATH"; then + sed -i -E --follow-symlinks "s/(.*password.*pam_pwhistory.so.*)\bremember\b=?[[:alnum:]]*(.*)/\1\2/g" "$PAM_FILE_PATH" fi if [ -f /usr/bin/authselect ]; then @@ -16425,6 +19721,11 @@ else # If not already in use, a custom profile is created preserving the enabled features. if [[ ! $CURRENT_PROFILE == custom/* ]]; then ENABLED_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }') + # The "local" profile does not contain essential security features required by multiple Benchmarks. + # If currently used, it is replaced by "sssd", which is the best option in this case. + if [[ $CURRENT_PROFILE == local ]]; then + CURRENT_PROFILE="sssd" + fi authselect create-profile hardening -b $CURRENT_PROFILE CURRENT_PROFILE="custom/hardening" @@ -16441,20 +19742,22 @@ else authselect apply-changes -b fi - if ! grep -qP '^\s*password\s+'"requisite"'\s+pam_pwhistory.so\s*.*' "$PAM_FILE_PATH"; then + + + if ! grep -qP "^\s*password\s+requisite\s+pam_pwhistory.so\s*.*" "$PAM_FILE_PATH"; then # Line matching group + control + module was not found. Check group + module. if [ "$(grep -cP '^\s*password\s+.*\s+pam_pwhistory.so\s*' "$PAM_FILE_PATH")" -eq 1 ]; then # The control is updated only if one single line matches. - sed -i -E --follow-symlinks 's/^(\s*password\s+).*(\bpam_pwhistory.so.*)/\1'"requisite"' \2/' "$PAM_FILE_PATH" + sed -i -E --follow-symlinks "s/^(\s*password\s+).*(\bpam_pwhistory.so.*)/\1requisite \2/" "$PAM_FILE_PATH" else - echo 'password '"requisite"' pam_pwhistory.so' >> "$PAM_FILE_PATH" + echo "password requisite pam_pwhistory.so" >> "$PAM_FILE_PATH" fi fi # Check the option - if ! grep -qP '^\s*password\s+'"requisite"'\s+pam_pwhistory.so\s*.*\sremember\b' "$PAM_FILE_PATH"; then - sed -i -E --follow-symlinks '/\s*password\s+'"requisite"'\s+pam_pwhistory.so.*/ s/$/ remember='"$var_password_pam_remember"'/' "$PAM_FILE_PATH" + if ! grep -qP "^\s*password\s+requisite\s+pam_pwhistory.so\s*.*\sremember\b" "$PAM_FILE_PATH"; then + sed -i -E --follow-symlinks "/\s*password\s+requisite\s+pam_pwhistory.so.*/ s/$/ remember=$var_password_pam_remember/" "$PAM_FILE_PATH" else - sed -i -E --follow-symlinks 's/(\s*password\s+'"requisite"'\s+pam_pwhistory.so\s+.*)('"remember"'=)[[:alnum:]]+\s*(.*)/\1\2'"$var_password_pam_remember"' \3/' "$PAM_FILE_PATH" + sed -i -E --follow-symlinks "s/(\s*password\s+requisite\s+pam_pwhistory.so\s+.*)(remember=)[[:alnum:]]+\s*(.*)/\1\2$var_password_pam_remember \3/" "$PAM_FILE_PATH" fi if [ -f /usr/bin/authselect ]; then @@ -16465,8 +19768,8 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: @@ -16475,6 +19778,8 @@ fi - NIST-800-53-IA-5(1)(e) - NIST-800-53-IA-5(f) - PCI-DSS-Req-8.2.5 + - PCI-DSSv4-8.3 + - PCI-DSSv4-8.3.7 - accounts_password_pam_pwhistory_remember_system_auth - configure_strategy - low_complexity @@ -16483,12 +19788,12 @@ fi - no_reboot_needed - name: XCCDF Value var_password_pam_remember # promote to variable set_fact: - var_password_pam_remember: !!str + var_password_pam_remember: !!str tags: - always - name: XCCDF Value var_password_pam_remember_control_flag # promote to variable set_fact: - var_password_pam_remember_control_flag: !!str + var_password_pam_remember_control_flag: !!str tags: - always @@ -16504,6 +19809,8 @@ fi - NIST-800-53-IA-5(1)(e) - NIST-800-53-IA-5(f) - PCI-DSS-Req-8.2.5 + - PCI-DSSv4-8.3 + - PCI-DSSv4-8.3.7 - accounts_password_pam_pwhistory_remember_system_auth - configure_strategy - low_complexity @@ -16513,7 +19820,7 @@ fi - name: 'Limit Password Reuse: system-auth - Collect the available authselect features' ansible.builtin.command: - cmd: authselect list-features minimal + cmd: authselect list-features sssd register: result_authselect_available_features changed_when: false when: @@ -16525,6 +19832,8 @@ fi - NIST-800-53-IA-5(1)(e) - NIST-800-53-IA-5(f) - PCI-DSS-Req-8.2.5 + - PCI-DSSv4-8.3 + - PCI-DSSv4-8.3.7 - accounts_password_pam_pwhistory_remember_system_auth - configure_strategy - low_complexity @@ -16593,6 +19902,8 @@ fi - NIST-800-53-IA-5(1)(e) - NIST-800-53-IA-5(f) - PCI-DSS-Req-8.2.5 + - PCI-DSSv4-8.3 + - PCI-DSSv4-8.3.7 - accounts_password_pam_pwhistory_remember_system_auth - configure_strategy - low_complexity @@ -16695,7 +20006,16 @@ fi }} when: - result_authselect_check_cmd is success - - authselect_current_profile is not match("custom/") + - authselect_current_profile is not match("^(custom/|local)") + - not result_authselect_custom_profile_present.stat.exists + + - name: 'Limit Password Reuse: system-auth - Create an authselect custom profile + based on sssd profile' + ansible.builtin.command: + cmd: authselect create-profile hardening -b sssd + when: + - result_authselect_check_cmd is success + - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists - name: 'Limit Password Reuse: system-auth - Ensure authselect changes are applied' @@ -16745,12 +20065,17 @@ fi when: - result_authselect_present.stat.exists + - name: 'Limit Password Reuse: system-auth - Define a fact for control already filtered + in case filters are used' + ansible.builtin.set_fact: + pam_module_control: '{{ var_password_pam_remember_control_flag.split(",")[0] + }}' + - name: 'Limit Password Reuse: system-auth - Check if expected PAM module line is present in {{ pam_file_path }}' ansible.builtin.lineinfile: path: '{{ pam_file_path }}' - regexp: ^\s*password\s+{{ var_password_pam_remember_control_flag.split(",")[0] - }}\s+pam_pwhistory.so\s*.* + regexp: ^\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_pwhistory.so\s*.* state: absent check_mode: true changed_when: false @@ -16775,7 +20100,7 @@ fi ansible.builtin.replace: dest: '{{ pam_file_path }}' regexp: ^(\s*password\s+).*(\bpam_pwhistory.so.*) - replace: \1{{ var_password_pam_remember_control_flag.split(",")[0] }} \2 + replace: \1{{ pam_module_control }} \2 register: result_pam_module_edit when: - result_pam_line_other_control_present.found == 1 @@ -16785,8 +20110,7 @@ fi ansible.builtin.lineinfile: dest: '{{ pam_file_path }}' insertafter: ^password.*requisite.*pam_pwquality\.so - line: password {{ var_password_pam_remember_control_flag.split(",")[0] - }} pam_pwhistory.so + line: password {{ pam_module_control }} pam_pwhistory.so register: result_pam_module_add when: - result_pam_line_other_control_present.found == 0 or result_pam_line_other_control_present.found @@ -16814,6 +20138,8 @@ fi - NIST-800-53-IA-5(1)(e) - NIST-800-53-IA-5(f) - PCI-DSS-Req-8.2.5 + - PCI-DSSv4-8.3 + - PCI-DSSv4-8.3.7 - accounts_password_pam_pwhistory_remember_system_auth - configure_strategy - low_complexity @@ -16833,6 +20159,8 @@ fi - NIST-800-53-IA-5(1)(e) - NIST-800-53-IA-5(f) - PCI-DSS-Req-8.2.5 + - PCI-DSSv4-8.3 + - PCI-DSSv4-8.3.7 - accounts_password_pam_pwhistory_remember_system_auth - configure_strategy - low_complexity @@ -16957,7 +20285,16 @@ fi }} when: - result_authselect_check_cmd is success - - authselect_current_profile is not match("custom/") + - authselect_current_profile is not match("^(custom/|local)") + - not result_authselect_custom_profile_present.stat.exists + + - name: 'Limit Password Reuse: system-auth - Create an authselect custom profile + based on sssd profile' + ansible.builtin.command: + cmd: authselect create-profile hardening -b sssd + when: + - result_authselect_check_cmd is success + - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists - name: 'Limit Password Reuse: system-auth - Ensure authselect changes are @@ -17009,6 +20346,11 @@ fi when: - result_authselect_present.stat.exists + - name: 'Limit Password Reuse: system-auth - Define a fact for control already + filtered in case filters are used' + ansible.builtin.set_fact: + pam_module_control: '' + - name: 'Limit Password Reuse: system-auth - Ensure the "remember" option from "pam_pwhistory.so" is not present in {{ pam_file_path }}' ansible.builtin.replace: @@ -17034,6 +20376,8 @@ fi - NIST-800-53-IA-5(1)(e) - NIST-800-53-IA-5(f) - PCI-DSS-Req-8.2.5 + - PCI-DSSv4-8.3 + - PCI-DSSv4-8.3.7 - accounts_password_pam_pwhistory_remember_system_auth - configure_strategy - low_complexity @@ -17136,7 +20480,16 @@ fi }} when: - result_authselect_check_cmd is success - - authselect_current_profile is not match("custom/") + - authselect_current_profile is not match("^(custom/|local)") + - not result_authselect_custom_profile_present.stat.exists + + - name: 'Limit Password Reuse: system-auth - Create an authselect custom profile + based on sssd profile' + ansible.builtin.command: + cmd: authselect create-profile hardening -b sssd + when: + - result_authselect_check_cmd is success + - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists - name: 'Limit Password Reuse: system-auth - Ensure authselect changes are applied' @@ -17186,11 +20539,16 @@ fi when: - result_authselect_present.stat.exists + - name: 'Limit Password Reuse: system-auth - Define a fact for control already filtered + in case filters are used' + ansible.builtin.set_fact: + pam_module_control: requisite + - name: 'Limit Password Reuse: system-auth - Check if expected PAM module line is present in {{ pam_file_path }}' ansible.builtin.lineinfile: path: '{{ pam_file_path }}' - regexp: ^\s*password\s+requisite\s+pam_pwhistory.so\s*.* + regexp: ^\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_pwhistory.so\s*.* state: absent check_mode: true changed_when: false @@ -17215,7 +20573,7 @@ fi ansible.builtin.replace: dest: '{{ pam_file_path }}' regexp: ^(\s*password\s+).*(\bpam_pwhistory.so.*) - replace: \1requisite \2 + replace: \1{{ pam_module_control }} \2 register: result_pam_module_edit when: - result_pam_line_other_control_present.found == 1 @@ -17224,7 +20582,7 @@ fi is included in {{ pam_file_path }}' ansible.builtin.lineinfile: dest: '{{ pam_file_path }}' - line: password requisite pam_pwhistory.so + line: password {{ pam_module_control }} pam_pwhistory.so register: result_pam_module_add when: - result_pam_line_other_control_present.found == 0 or result_pam_line_other_control_present.found @@ -17243,38 +20601,45 @@ fi - result_pam_line_present.found is defined - result_pam_line_present.found == 0 + - name: 'Limit Password Reuse: system-auth - Define a fact for control already filtered + in case filters are used' + ansible.builtin.set_fact: + pam_module_control: requisite + - name: 'Limit Password Reuse: system-auth - Check if the required PAM module option is present in {{ pam_file_path }}' ansible.builtin.lineinfile: path: '{{ pam_file_path }}' - regexp: ^\s*password\s+requisite\s+pam_pwhistory.so\s*.*\sremember\b + regexp: ^\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_pwhistory.so\s*.*\sremember\b state: absent check_mode: true changed_when: false - register: result_pam_module_remember_option_present + register: result_pam_module_accounts_password_pam_pwhistory_remember_system_auth_option_present - name: 'Limit Password Reuse: system-auth - Ensure the "remember" PAM option for "pam_pwhistory.so" is included in {{ pam_file_path }}' ansible.builtin.lineinfile: path: '{{ pam_file_path }}' backrefs: true - regexp: ^(\s*password\s+requisite\s+pam_pwhistory.so.*) + regexp: ^(\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_pwhistory.so.*) line: \1 remember={{ var_password_pam_remember }} state: present - register: result_pam_remember_add + register: result_pam_accounts_password_pam_pwhistory_remember_system_auth_add when: - - result_pam_module_remember_option_present.found == 0 + - result_pam_module_accounts_password_pam_pwhistory_remember_system_auth_option_present.found + == 0 - name: 'Limit Password Reuse: system-auth - Ensure the required value for "remember" PAM option from "pam_pwhistory.so" in {{ pam_file_path }}' ansible.builtin.lineinfile: path: '{{ pam_file_path }}' backrefs: true - regexp: ^(\s*password\s+requisite\s+pam_pwhistory.so\s+.*)(remember)=[0-9a-zA-Z]+\s*(.*) + regexp: ^(\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_pwhistory.so\s+.*)(remember)=[0-9a-zA-Z]+\s*(.*) line: \1\2={{ var_password_pam_remember }} \3 - register: result_pam_remember_edit + register: result_pam_accounts_password_pam_pwhistory_remember_system_auth_edit when: - - result_pam_module_remember_option_present.found > 0 + - result_pam_module_accounts_password_pam_pwhistory_remember_system_auth_option_present.found + > 0 - name: 'Limit Password Reuse: system-auth - Ensure authselect changes are applied' ansible.builtin.command: @@ -17292,102 +20657,109 @@ fi - NIST-800-53-IA-5(1)(e) - NIST-800-53-IA-5(f) - PCI-DSS-Req-8.2.5 + - PCI-DSSv4-8.3 + - PCI-DSSv4-8.3.7 - accounts_password_pam_pwhistory_remember_system_auth - configure_strategy - low_complexity - medium_disruption - medium_severity - no_reboot_needed - - - - - - - - - - - - Limit Password Reuse - Do not allow users to reuse recent passwords. This can be accomplished by using the -remember option for the pam_unix or pam_pwhistory PAM modules. - If the system relies on authselect tool to manage PAM settings, the remediation + + + + + + + + + + + + Limit Password Reuse + Do not allow users to reuse recent passwords. This can be accomplished by using the +remember option for the pam_unix or pam_pwhistory PAM modules. + If the system relies on authselect tool to manage PAM settings, the remediation will also use authselect tool. However, if any manual modification was made in PAM files, the authselect integrity check will fail and the remediation will be aborted in order to preserve intentional changes. In this case, an informative message will -be shown in the remediation report. - Newer versions of authselect contain an authselect feature to easily and properly +be shown in the remediation report. + Newer versions of authselect contain an authselect feature to easily and properly enable pam_pwhistory.so module. If this feature is not yet available in your -system, an authselect custom profile must be used to avoid integrity issues in PAM files. - BP28(R18) - 1 - 12 - 15 - 16 - 5 - 5.6.2.1.1 - DSS05.04 - DSS05.05 - DSS05.07 - DSS05.10 - DSS06.03 - DSS06.10 - 3.5.8 - CCI-000200 - 4.3.3.2.2 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.2 - 4.3.3.7.4 - SR 1.1 - SR 1.10 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - A.18.1.4 - A.7.1.1 - A.9.2.1 - A.9.2.2 - A.9.2.3 - A.9.2.4 - A.9.2.6 - A.9.3.1 - A.9.4.2 - A.9.4.3 - IA-5(f) - IA-5(1)(e) - PR.AC-1 - PR.AC-6 - PR.AC-7 - Req-8.2.5 - 8.3.7 - SRG-OS-000077-GPOS-00045 - Preventing re-use of previous passwords helps ensure that a compromised password is not -re-used by a user. - - # Remediation is applicable only in certain platforms +system, an authselect custom profile must be used to avoid integrity issues in PAM files. + 1 + 12 + 15 + 16 + 5 + 5.6.2.1.1 + DSS05.04 + DSS05.05 + DSS05.07 + DSS05.10 + DSS06.03 + DSS06.10 + 3.5.8 + CCI-000200 + 4.3.3.2.2 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.2 + 4.3.3.7.4 + SR 1.1 + SR 1.10 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + A.18.1.4 + A.7.1.1 + A.9.2.1 + A.9.2.2 + A.9.2.3 + A.9.2.4 + A.9.2.6 + A.9.3.1 + A.9.4.2 + A.9.4.3 + IA-5(f) + IA-5(1)(e) + PR.AC-1 + PR.AC-6 + PR.AC-7 + Req-8.2.5 + SRG-OS-000077-GPOS-00045 + R31 + 8.3.7 + 8.3 + Preventing re-use of previous passwords helps ensure that a compromised password is not +re-used by a user. + + # Remediation is applicable only in certain platforms if rpm --quiet -q pam; then -var_password_pam_unix_remember='' +var_password_pam_unix_remember='' + + + + if [ -f /usr/bin/authselect ]; then - if authselect list-features minimal | grep -q with-pwhistory; then + if authselect list-features sssd | grep -q with-pwhistory; then if ! authselect check; then echo " authselect integrity check failed. Remediation aborted! @@ -17414,6 +20786,11 @@ if [ -f /usr/bin/authselect ]; then # If not already in use, a custom profile is created preserving the enabled features. if [[ ! $CURRENT_PROFILE == custom/* ]]; then ENABLED_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }') + # The "local" profile does not contain essential security features required by multiple Benchmarks. + # If currently used, it is replaced by "sssd", which is the best option in this case. + if [[ $CURRENT_PROFILE == local ]]; then + CURRENT_PROFILE="sssd" + fi authselect create-profile hardening -b $CURRENT_PROFILE CURRENT_PROFILE="custom/hardening" @@ -17429,36 +20806,40 @@ if [ -f /usr/bin/authselect ]; then PAM_FILE_PATH="/etc/authselect/$CURRENT_PROFILE/$PAM_FILE_NAME" authselect apply-changes -b - if ! grep -qP '^\s*password\s+'"requisite"'\s+pam_pwhistory.so\s*.*' "$PAM_FILE_PATH"; then + + if ! grep -qP "^\s*password\s+requisite\s+pam_pwhistory.so\s*.*" "$PAM_FILE_PATH"; then # Line matching group + control + module was not found. Check group + module. if [ "$(grep -cP '^\s*password\s+.*\s+pam_pwhistory.so\s*' "$PAM_FILE_PATH")" -eq 1 ]; then # The control is updated only if one single line matches. - sed -i -E --follow-symlinks 's/^(\s*password\s+).*(\bpam_pwhistory.so.*)/\1'"requisite"' \2/' "$PAM_FILE_PATH" + sed -i -E --follow-symlinks "s/^(\s*password\s+).*(\bpam_pwhistory.so.*)/\1requisite \2/" "$PAM_FILE_PATH" else LAST_MATCH_LINE=$(grep -nP "^password.*requisite.*pam_pwquality\.so" "$PAM_FILE_PATH" | tail -n 1 | cut -d: -f 1) if [ ! -z $LAST_MATCH_LINE ]; then - sed -i --follow-symlinks $LAST_MATCH_LINE' a password '"requisite"' pam_pwhistory.so' "$PAM_FILE_PATH" + sed -i --follow-symlinks $LAST_MATCH_LINE" a password requisite pam_pwhistory.so" "$PAM_FILE_PATH" else - echo 'password '"requisite"' pam_pwhistory.so' >> "$PAM_FILE_PATH" + echo "password requisite pam_pwhistory.so" >> "$PAM_FILE_PATH" fi fi fi fi else - if ! grep -qP '^\s*password\s+'"requisite"'\s+pam_pwhistory.so\s*.*' "/etc/pam.d/system-auth"; then + + + if ! grep -qP "^\s*password\s+requisite\s+pam_pwhistory.so\s*.*" "/etc/pam.d/system-auth"; then # Line matching group + control + module was not found. Check group + module. if [ "$(grep -cP '^\s*password\s+.*\s+pam_pwhistory.so\s*' "/etc/pam.d/system-auth")" -eq 1 ]; then # The control is updated only if one single line matches. - sed -i -E --follow-symlinks 's/^(\s*password\s+).*(\bpam_pwhistory.so.*)/\1'"requisite"' \2/' "/etc/pam.d/system-auth" + sed -i -E --follow-symlinks "s/^(\s*password\s+).*(\bpam_pwhistory.so.*)/\1requisite \2/" "/etc/pam.d/system-auth" else LAST_MATCH_LINE=$(grep -nP "^password.*requisite.*pam_pwquality\.so" "/etc/pam.d/system-auth" | tail -n 1 | cut -d: -f 1) if [ ! -z $LAST_MATCH_LINE ]; then - sed -i --follow-symlinks $LAST_MATCH_LINE' a password '"requisite"' pam_pwhistory.so' "/etc/pam.d/system-auth" + sed -i --follow-symlinks $LAST_MATCH_LINE" a password requisite pam_pwhistory.so" "/etc/pam.d/system-auth" else - echo 'password '"requisite"' pam_pwhistory.so' >> "/etc/pam.d/system-auth" + echo "password requisite pam_pwhistory.so" >> "/etc/pam.d/system-auth" fi fi fi + fi PWHISTORY_CONF="/etc/security/pwhistory.conf" @@ -17487,6 +20868,11 @@ if [ -f $PWHISTORY_CONF ]; then # If not already in use, a custom profile is created preserving the enabled features. if [[ ! $CURRENT_PROFILE == custom/* ]]; then ENABLED_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }') + # The "local" profile does not contain essential security features required by multiple Benchmarks. + # If currently used, it is replaced by "sssd", which is the best option in this case. + if [[ $CURRENT_PROFILE == local ]]; then + CURRENT_PROFILE="sssd" + fi authselect create-profile hardening -b $CURRENT_PROFILE CURRENT_PROFILE="custom/hardening" @@ -17504,8 +20890,8 @@ if [ -f $PWHISTORY_CONF ]; then authselect apply-changes -b fi - if grep -qP '^\s*password\s.*\bpam_pwhistory.so\s.*\bremember\b' "$PAM_FILE_PATH"; then - sed -i -E --follow-symlinks 's/(.*password.*pam_pwhistory.so.*)\bremember\b=?[[:alnum:]]*(.*)/\1\2/g' "$PAM_FILE_PATH" + if grep -qP "^\s*password\s.*\bpam_pwhistory.so\s.*\bremember\b" "$PAM_FILE_PATH"; then + sed -i -E --follow-symlinks "s/(.*password.*pam_pwhistory.so.*)\bremember\b=?[[:alnum:]]*(.*)/\1\2/g" "$PAM_FILE_PATH" fi if [ -f /usr/bin/authselect ]; then @@ -17531,6 +20917,11 @@ else # If not already in use, a custom profile is created preserving the enabled features. if [[ ! $CURRENT_PROFILE == custom/* ]]; then ENABLED_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }') + # The "local" profile does not contain essential security features required by multiple Benchmarks. + # If currently used, it is replaced by "sssd", which is the best option in this case. + if [[ $CURRENT_PROFILE == local ]]; then + CURRENT_PROFILE="sssd" + fi authselect create-profile hardening -b $CURRENT_PROFILE CURRENT_PROFILE="custom/hardening" @@ -17547,20 +20938,22 @@ else authselect apply-changes -b fi - if ! grep -qP '^\s*password\s+'"requisite"'\s+pam_pwhistory.so\s*.*' "$PAM_FILE_PATH"; then + + + if ! grep -qP "^\s*password\s+requisite\s+pam_pwhistory.so\s*.*" "$PAM_FILE_PATH"; then # Line matching group + control + module was not found. Check group + module. if [ "$(grep -cP '^\s*password\s+.*\s+pam_pwhistory.so\s*' "$PAM_FILE_PATH")" -eq 1 ]; then # The control is updated only if one single line matches. - sed -i -E --follow-symlinks 's/^(\s*password\s+).*(\bpam_pwhistory.so.*)/\1'"requisite"' \2/' "$PAM_FILE_PATH" + sed -i -E --follow-symlinks "s/^(\s*password\s+).*(\bpam_pwhistory.so.*)/\1requisite \2/" "$PAM_FILE_PATH" else - echo 'password '"requisite"' pam_pwhistory.so' >> "$PAM_FILE_PATH" + echo "password requisite pam_pwhistory.so" >> "$PAM_FILE_PATH" fi fi # Check the option - if ! grep -qP '^\s*password\s+'"requisite"'\s+pam_pwhistory.so\s*.*\sremember\b' "$PAM_FILE_PATH"; then - sed -i -E --follow-symlinks '/\s*password\s+'"requisite"'\s+pam_pwhistory.so.*/ s/$/ remember='"$var_password_pam_unix_remember"'/' "$PAM_FILE_PATH" + if ! grep -qP "^\s*password\s+requisite\s+pam_pwhistory.so\s*.*\sremember\b" "$PAM_FILE_PATH"; then + sed -i -E --follow-symlinks "/\s*password\s+requisite\s+pam_pwhistory.so.*/ s/$/ remember=$var_password_pam_unix_remember/" "$PAM_FILE_PATH" else - sed -i -E --follow-symlinks 's/(\s*password\s+'"requisite"'\s+pam_pwhistory.so\s+.*)('"remember"'=)[[:alnum:]]+\s*(.*)/\1\2'"$var_password_pam_unix_remember"' \3/' "$PAM_FILE_PATH" + sed -i -E --follow-symlinks "s/(\s*password\s+requisite\s+pam_pwhistory.so\s+.*)(remember=)[[:alnum:]]+\s*(.*)/\1\2$var_password_pam_unix_remember \3/" "$PAM_FILE_PATH" fi if [ -f /usr/bin/authselect ]; then @@ -17571,8 +20964,8 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: @@ -17581,6 +20974,7 @@ fi - NIST-800-53-IA-5(1)(e) - NIST-800-53-IA-5(f) - PCI-DSS-Req-8.2.5 + - PCI-DSSv4-8.3 - PCI-DSSv4-8.3.7 - accounts_password_pam_unix_remember - configure_strategy @@ -17590,7 +20984,7 @@ fi - no_reboot_needed - name: XCCDF Value var_password_pam_unix_remember # promote to variable set_fact: - var_password_pam_unix_remember: !!str + var_password_pam_unix_remember: !!str tags: - always @@ -17605,6 +20999,7 @@ fi - NIST-800-53-IA-5(1)(e) - NIST-800-53-IA-5(f) - PCI-DSS-Req-8.2.5 + - PCI-DSSv4-8.3 - PCI-DSSv4-8.3.7 - accounts_password_pam_unix_remember - configure_strategy @@ -17615,7 +21010,7 @@ fi - name: Limit Password Reuse - Collect the available authselect features ansible.builtin.command: - cmd: authselect list-features minimal + cmd: authselect list-features sssd register: result_authselect_available_features changed_when: false when: @@ -17627,6 +21022,7 @@ fi - NIST-800-53-IA-5(1)(e) - NIST-800-53-IA-5(f) - PCI-DSS-Req-8.2.5 + - PCI-DSSv4-8.3 - PCI-DSSv4-8.3.7 - accounts_password_pam_unix_remember - configure_strategy @@ -17694,6 +21090,7 @@ fi - NIST-800-53-IA-5(1)(e) - NIST-800-53-IA-5(f) - PCI-DSS-Req-8.2.5 + - PCI-DSSv4-8.3 - PCI-DSSv4-8.3.7 - accounts_password_pam_unix_remember - configure_strategy @@ -17793,7 +21190,16 @@ fi }} when: - result_authselect_check_cmd is success - - authselect_current_profile is not match("custom/") + - authselect_current_profile is not match("^(custom/|local)") + - not result_authselect_custom_profile_present.stat.exists + + - name: Limit Password Reuse - Create an authselect custom profile based on sssd + profile + ansible.builtin.command: + cmd: authselect create-profile hardening -b sssd + when: + - result_authselect_check_cmd is success + - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists - name: Limit Password Reuse - Ensure authselect changes are applied @@ -17841,11 +21247,16 @@ fi when: - result_authselect_present.stat.exists + - name: Limit Password Reuse - Define a fact for control already filtered in case + filters are used + ansible.builtin.set_fact: + pam_module_control: requisite + - name: Limit Password Reuse - Check if expected PAM module line is present in {{ pam_file_path }} ansible.builtin.lineinfile: path: '{{ pam_file_path }}' - regexp: ^\s*password\s+requisite\s+pam_pwhistory.so\s*.* + regexp: ^\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_pwhistory.so\s*.* state: absent check_mode: true changed_when: false @@ -17870,7 +21281,7 @@ fi ansible.builtin.replace: dest: '{{ pam_file_path }}' regexp: ^(\s*password\s+).*(\bpam_pwhistory.so.*) - replace: \1requisite \2 + replace: \1{{ pam_module_control }} \2 register: result_pam_module_edit when: - result_pam_line_other_control_present.found == 1 @@ -17880,7 +21291,7 @@ fi ansible.builtin.lineinfile: dest: '{{ pam_file_path }}' insertafter: ^password.*requisite.*pam_pwquality\.so - line: password requisite pam_pwhistory.so + line: password {{ pam_module_control }} pam_pwhistory.so register: result_pam_module_add when: - result_pam_line_other_control_present.found == 0 or result_pam_line_other_control_present.found @@ -17908,6 +21319,7 @@ fi - NIST-800-53-IA-5(1)(e) - NIST-800-53-IA-5(f) - PCI-DSS-Req-8.2.5 + - PCI-DSSv4-8.3 - PCI-DSSv4-8.3.7 - accounts_password_pam_unix_remember - configure_strategy @@ -17928,6 +21340,7 @@ fi - NIST-800-53-IA-5(1)(e) - NIST-800-53-IA-5(f) - PCI-DSS-Req-8.2.5 + - PCI-DSSv4-8.3 - PCI-DSSv4-8.3.7 - accounts_password_pam_unix_remember - configure_strategy @@ -18048,7 +21461,16 @@ fi }} when: - result_authselect_check_cmd is success - - authselect_current_profile is not match("custom/") + - authselect_current_profile is not match("^(custom/|local)") + - not result_authselect_custom_profile_present.stat.exists + + - name: Limit Password Reuse - Create an authselect custom profile based on + sssd profile + ansible.builtin.command: + cmd: authselect create-profile hardening -b sssd + when: + - result_authselect_check_cmd is success + - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists - name: Limit Password Reuse - Ensure authselect changes are applied @@ -18097,6 +21519,11 @@ fi when: - result_authselect_present.stat.exists + - name: Limit Password Reuse - Define a fact for control already filtered in + case filters are used + ansible.builtin.set_fact: + pam_module_control: '' + - name: Limit Password Reuse - Ensure the "remember" option from "pam_pwhistory.so" is not present in {{ pam_file_path }} ansible.builtin.replace: @@ -18122,6 +21549,7 @@ fi - NIST-800-53-IA-5(1)(e) - NIST-800-53-IA-5(f) - PCI-DSS-Req-8.2.5 + - PCI-DSSv4-8.3 - PCI-DSSv4-8.3.7 - accounts_password_pam_unix_remember - configure_strategy @@ -18221,7 +21649,16 @@ fi }} when: - result_authselect_check_cmd is success - - authselect_current_profile is not match("custom/") + - authselect_current_profile is not match("^(custom/|local)") + - not result_authselect_custom_profile_present.stat.exists + + - name: Limit Password Reuse - Create an authselect custom profile based on sssd + profile + ansible.builtin.command: + cmd: authselect create-profile hardening -b sssd + when: + - result_authselect_check_cmd is success + - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists - name: Limit Password Reuse - Ensure authselect changes are applied @@ -18269,11 +21706,16 @@ fi when: - result_authselect_present.stat.exists + - name: Limit Password Reuse - Define a fact for control already filtered in case + filters are used + ansible.builtin.set_fact: + pam_module_control: requisite + - name: Limit Password Reuse - Check if expected PAM module line is present in {{ pam_file_path }} ansible.builtin.lineinfile: path: '{{ pam_file_path }}' - regexp: ^\s*password\s+requisite\s+pam_pwhistory.so\s*.* + regexp: ^\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_pwhistory.so\s*.* state: absent check_mode: true changed_when: false @@ -18298,7 +21740,7 @@ fi ansible.builtin.replace: dest: '{{ pam_file_path }}' regexp: ^(\s*password\s+).*(\bpam_pwhistory.so.*) - replace: \1requisite \2 + replace: \1{{ pam_module_control }} \2 register: result_pam_module_edit when: - result_pam_line_other_control_present.found == 1 @@ -18307,7 +21749,7 @@ fi in {{ pam_file_path }} ansible.builtin.lineinfile: dest: '{{ pam_file_path }}' - line: password requisite pam_pwhistory.so + line: password {{ pam_module_control }} pam_pwhistory.so register: result_pam_module_add when: - result_pam_line_other_control_present.found == 0 or result_pam_line_other_control_present.found @@ -18326,38 +21768,45 @@ fi - result_pam_line_present.found is defined - result_pam_line_present.found == 0 + - name: Limit Password Reuse - Define a fact for control already filtered in case + filters are used + ansible.builtin.set_fact: + pam_module_control: requisite + - name: Limit Password Reuse - Check if the required PAM module option is present in {{ pam_file_path }} ansible.builtin.lineinfile: path: '{{ pam_file_path }}' - regexp: ^\s*password\s+requisite\s+pam_pwhistory.so\s*.*\sremember\b + regexp: ^\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_pwhistory.so\s*.*\sremember\b state: absent check_mode: true changed_when: false - register: result_pam_module_remember_option_present + register: result_pam_module_accounts_password_pam_unix_remember_option_present - name: Limit Password Reuse - Ensure the "remember" PAM option for "pam_pwhistory.so" is included in {{ pam_file_path }} ansible.builtin.lineinfile: path: '{{ pam_file_path }}' backrefs: true - regexp: ^(\s*password\s+requisite\s+pam_pwhistory.so.*) + regexp: ^(\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_pwhistory.so.*) line: \1 remember={{ var_password_pam_unix_remember }} state: present - register: result_pam_remember_add + register: result_pam_accounts_password_pam_unix_remember_add when: - - result_pam_module_remember_option_present.found == 0 + - result_pam_module_accounts_password_pam_unix_remember_option_present.found == + 0 - name: Limit Password Reuse - Ensure the required value for "remember" PAM option from "pam_pwhistory.so" in {{ pam_file_path }} ansible.builtin.lineinfile: path: '{{ pam_file_path }}' backrefs: true - regexp: ^(\s*password\s+requisite\s+pam_pwhistory.so\s+.*)(remember)=[0-9a-zA-Z]+\s*(.*) + regexp: ^(\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_pwhistory.so\s+.*)(remember)=[0-9a-zA-Z]+\s*(.*) line: \1\2={{ var_password_pam_unix_remember }} \3 - register: result_pam_remember_edit + register: result_pam_accounts_password_pam_unix_remember_edit when: - - result_pam_module_remember_option_present.found > 0 + - result_pam_module_accounts_password_pam_unix_remember_option_present.found > + 0 - name: Limit Password Reuse - Ensure authselect changes are applied ansible.builtin.command: @@ -18375,6 +21824,7 @@ fi - NIST-800-53-IA-5(1)(e) - NIST-800-53-IA-5(f) - PCI-DSS-Req-8.2.5 + - PCI-DSSv4-8.3 - PCI-DSSv4-8.3.7 - accounts_password_pam_unix_remember - configure_strategy @@ -18382,23 +21832,25 @@ fi - medium_disruption - medium_severity - no_reboot_needed - - - - - - - - - - - Account Lockouts Must Be Logged - PAM faillock locks an account due to excessive password failures, this event must be logged. - CCI-000044 - AC-7 (a) - SRG-OS-000021-GPOS-00005 - Without auditing of these events it may be harder or impossible to identify what an attacker did after an attack. - + + + + + + + + + + + Account Lockouts Must Be Logged + PAM faillock locks an account due to excessive password failures, this event must be logged. + CCI-000044 + AC-7 (a) + SRG-OS-000021-GPOS-00005 + OL09-00-003022 + SV-271841r1092235_rule + Without auditing of these events it may be harder or impossible to identify what an attacker did after an attack. + if [ -f /usr/bin/authselect ]; then if ! authselect check; then echo " @@ -18427,14 +21879,16 @@ done fi AUTH_FILES=("/etc/pam.d/system-auth" "/etc/pam.d/password-auth") +SKIP_FAILLOCK_CHECK=false FAILLOCK_CONF="/etc/security/faillock.conf" -if [ -f $FAILLOCK_CONF ]; then +if [ -f $FAILLOCK_CONF ] || [ "$SKIP_FAILLOCK_CHECK" = "true" ]; then regex="^\s*audit" line="audit" if ! grep -q $regex $FAILLOCK_CONF; then echo $line >> $FAILLOCK_CONF fi + for pam_file in "${AUTH_FILES[@]}" do if [ -e "$pam_file" ] ; then @@ -18454,6 +21908,11 @@ if [ -f $FAILLOCK_CONF ]; then # If not already in use, a custom profile is created preserving the enabled features. if [[ ! $CURRENT_PROFILE == custom/* ]]; then ENABLED_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }') + # The "local" profile does not contain essential security features required by multiple Benchmarks. + # If currently used, it is replaced by "sssd", which is the best option in this case. + if [[ $CURRENT_PROFILE == local ]]; then + CURRENT_PROFILE="sssd" + fi authselect create-profile hardening -b $CURRENT_PROFILE CURRENT_PROFILE="custom/hardening" @@ -18471,8 +21930,8 @@ if [ -f $FAILLOCK_CONF ]; then authselect apply-changes -b fi - if grep -qP '^\s*auth\s.*\bpam_faillock.so\s.*\baudit\b' "$PAM_FILE_PATH"; then - sed -i -E --follow-symlinks 's/(.*auth.*pam_faillock.so.*)\baudit\b=?[[:alnum:]]*(.*)/\1\2/g' "$PAM_FILE_PATH" + if grep -qP "^\s*auth\s.*\bpam_faillock.so\s.*\baudit\b" "$PAM_FILE_PATH"; then + sed -i -E --follow-symlinks "s/(.*auth.*pam_faillock.so.*)\baudit\b=?[[:alnum:]]*(.*)/\1\2/g" "$PAM_FILE_PATH" fi if [ -f /usr/bin/authselect ]; then @@ -18482,6 +21941,7 @@ if [ -f $FAILLOCK_CONF ]; then echo "$pam_file was not found" >&2 fi done + else for pam_file in "${AUTH_FILES[@]}" do @@ -18490,12 +21950,13 @@ else fi done fi - - - name: Account Lockouts Must Be Logged - Check if system relies on authselect tool + + - name: Account Lockouts Must Be Logged - Check if system relies on authselect tool ansible.builtin.stat: path: /usr/bin/authselect register: result_authselect_present tags: + - DISA-STIG-OL09-00-003022 - NIST-800-53-AC-7 (a) - accounts_passwords_pam_faillock_audit - low_complexity @@ -18556,6 +22017,7 @@ fi - result_authselect_enable_feature_cmd is success when: result_authselect_present.stat.exists tags: + - DISA-STIG-OL09-00-003022 - NIST-800-53-AC-7 (a) - accounts_passwords_pam_faillock_audit - low_complexity @@ -18617,6 +22079,7 @@ fi - result_pam_faillock_is_enabled.found == 0 when: not result_authselect_present.stat.exists tags: + - DISA-STIG-OL09-00-003022 - NIST-800-53-AC-7 (a) - accounts_passwords_pam_faillock_audit - low_complexity @@ -18631,6 +22094,7 @@ fi path: /etc/security/faillock.conf register: result_faillock_conf_check tags: + - DISA-STIG-OL09-00-003022 - NIST-800-53-AC-7 (a) - accounts_passwords_pam_faillock_audit - low_complexity @@ -18648,6 +22112,7 @@ fi state: present when: result_faillock_conf_check.stat.exists tags: + - DISA-STIG-OL09-00-003022 - NIST-800-53-AC-7 (a) - accounts_passwords_pam_faillock_audit - low_complexity @@ -18760,7 +22225,16 @@ fi }} when: - result_authselect_check_cmd is success - - authselect_current_profile is not match("custom/") + - authselect_current_profile is not match("^(custom/|local)") + - not result_authselect_custom_profile_present.stat.exists + + - name: Account Lockouts Must Be Logged - Create an authselect custom profile + based on sssd profile + ansible.builtin.command: + cmd: authselect create-profile hardening -b sssd + when: + - result_authselect_check_cmd is success + - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists - name: Account Lockouts Must Be Logged - Ensure authselect changes are applied @@ -18810,6 +22284,11 @@ fi when: - result_authselect_present.stat.exists + - name: Account Lockouts Must Be Logged - Define a fact for control already filtered + in case filters are used + ansible.builtin.set_fact: + pam_module_control: '' + - name: Account Lockouts Must Be Logged - Ensure the "audit" option from "pam_faillock.so" is not present in {{ pam_file_path }} ansible.builtin.replace: @@ -18927,7 +22406,16 @@ fi }} when: - result_authselect_check_cmd is success - - authselect_current_profile is not match("custom/") + - authselect_current_profile is not match("^(custom/|local)") + - not result_authselect_custom_profile_present.stat.exists + + - name: Account Lockouts Must Be Logged - Create an authselect custom profile + based on sssd profile + ansible.builtin.command: + cmd: authselect create-profile hardening -b sssd + when: + - result_authselect_check_cmd is success + - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists - name: Account Lockouts Must Be Logged - Ensure authselect changes are applied @@ -18977,6 +22465,11 @@ fi when: - result_authselect_present.stat.exists + - name: Account Lockouts Must Be Logged - Define a fact for control already filtered + in case filters are used + ansible.builtin.set_fact: + pam_module_control: '' + - name: Account Lockouts Must Be Logged - Ensure the "audit" option from "pam_faillock.so" is not present in {{ pam_file_path }} ansible.builtin.replace: @@ -18995,6 +22488,7 @@ fi - result_pam_file_present.stat.exists when: result_faillock_conf_check.stat.exists tags: + - DISA-STIG-OL09-00-003022 - NIST-800-53-AC-7 (a) - accounts_passwords_pam_faillock_audit - low_complexity @@ -19032,6 +22526,7 @@ fi - result_pam_faillock_audit_parameter_is_present.found == 0 when: not result_faillock_conf_check.stat.exists tags: + - DISA-STIG-OL09-00-003022 - NIST-800-53-AC-7 (a) - accounts_passwords_pam_faillock_audit - low_complexity @@ -19039,103 +22534,103 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Lock Accounts After Failed Password Attempts - This rule configures the system to lock out accounts after a number of incorrect login attempts + + + + + + + + + + Lock Accounts After Failed Password Attempts + This rule configures the system to lock out accounts after a number of incorrect login attempts using pam_faillock.so. pam_faillock.so module requires multiple entries in pam files. These entries must be carefully defined to work as expected. - Ensure that the file /etc/security/faillock.conf contains the following entry: deny = <count> -Where count should be less than or equal to - and greater than 0. - +Where count should be less than or equal to + and greater than 0. In order to avoid errors when manually editing these files, it is recommended to use the appropriate tools, such as authselect or authconfig, -depending on the OS version. - If the system relies on authselect tool to manage PAM settings, the remediation +depending on the OS version. + If the system relies on authselect tool to manage PAM settings, the remediation will also use authselect tool. However, if any manual modification was made in PAM files, the authselect integrity check will fail and the remediation will be aborted in order to preserve intentional changes. In this case, an informative message will be shown in the remediation report. If the system supports the /etc/security/faillock.conf file, the pam_faillock -parameters should be defined in faillock.conf file. - BP28(R18) - 1 - 12 - 15 - 16 - 5.5.3 - DSS05.04 - DSS05.10 - DSS06.10 - 3.1.8 - CCI-000044 - CCI-002236 - CCI-002237 - CCI-002238 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - SR 1.1 - SR 1.10 - SR 1.2 - SR 1.5 - SR 1.7 - SR 1.8 - SR 1.9 - 0421 - 0422 - 0431 - 0974 - 1173 - 1401 - 1504 - 1505 - 1546 - 1557 - 1558 - 1559 - 1560 - 1561 - A.18.1.4 - A.9.2.1 - A.9.2.4 - A.9.3.1 - A.9.4.2 - A.9.4.3 - CM-6(a) - AC-7(a) - PR.AC-7 - FIA_AFL.1 - Req-8.1.6 - 8.3.4 - SRG-OS-000329-GPOS-00128 - SRG-OS-000021-GPOS-00005 - By limiting the number of failed logon attempts, the risk of unauthorized system access via +parameters should be defined in faillock.conf file. + 1 + 12 + 15 + 16 + 5.5.3 + DSS05.04 + DSS05.10 + DSS06.10 + 3.1.8 + CCI-000044 + CCI-002238 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + SR 1.1 + SR 1.10 + SR 1.2 + SR 1.5 + SR 1.7 + SR 1.8 + SR 1.9 + 0421 + 0422 + 0431 + 0974 + 1173 + 1401 + 1504 + 1505 + 1546 + 1557 + 1558 + 1559 + 1560 + 1561 + A.18.1.4 + A.9.2.1 + A.9.2.4 + A.9.3.1 + A.9.4.2 + A.9.4.3 + CM-6(a) + AC-7(a) + PR.AC-7 + FIA_AFL.1 + Req-8.1.6 + SRG-OS-000329-GPOS-00128 + SRG-OS-000021-GPOS-00005 + R31 + A.30.SEC-OL1 + 8.3.4 + 8.3 + OL09-00-003020 + SV-271839r1092229_rule + By limiting the number of failed logon attempts, the risk of unauthorized system access via user password guessing, also known as brute-forcing, is reduced. Limits are imposed by locking -the account. - - # Remediation is applicable only in certain platforms +the account. + + # Remediation is applicable only in certain platforms if rpm --quiet -q pam; then -var_accounts_passwords_pam_faillock_deny='' +var_accounts_passwords_pam_faillock_deny='' if [ -f /usr/bin/authselect ]; then @@ -19166,9 +22661,10 @@ done fi AUTH_FILES=("/etc/pam.d/system-auth" "/etc/pam.d/password-auth") +SKIP_FAILLOCK_CHECK=false FAILLOCK_CONF="/etc/security/faillock.conf" -if [ -f $FAILLOCK_CONF ]; then +if [ -f $FAILLOCK_CONF ] || [ "$SKIP_FAILLOCK_CHECK" = "true" ]; then regex="^\s*deny\s*=" line="deny = $var_accounts_passwords_pam_faillock_deny" if ! grep -q $regex $FAILLOCK_CONF; then @@ -19176,6 +22672,7 @@ if [ -f $FAILLOCK_CONF ]; then else sed -i --follow-symlinks 's|^\s*\(deny\s*=\s*\)\(\S\+\)|\1'"$var_accounts_passwords_pam_faillock_deny"'|g' $FAILLOCK_CONF fi + for pam_file in "${AUTH_FILES[@]}" do if [ -e "$pam_file" ] ; then @@ -19195,6 +22692,11 @@ if [ -f $FAILLOCK_CONF ]; then # If not already in use, a custom profile is created preserving the enabled features. if [[ ! $CURRENT_PROFILE == custom/* ]]; then ENABLED_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }') + # The "local" profile does not contain essential security features required by multiple Benchmarks. + # If currently used, it is replaced by "sssd", which is the best option in this case. + if [[ $CURRENT_PROFILE == local ]]; then + CURRENT_PROFILE="sssd" + fi authselect create-profile hardening -b $CURRENT_PROFILE CURRENT_PROFILE="custom/hardening" @@ -19212,8 +22714,8 @@ if [ -f $FAILLOCK_CONF ]; then authselect apply-changes -b fi - if grep -qP '^\s*auth\s.*\bpam_faillock.so\s.*\bdeny\b' "$PAM_FILE_PATH"; then - sed -i -E --follow-symlinks 's/(.*auth.*pam_faillock.so.*)\bdeny\b=?[[:alnum:]]*(.*)/\1\2/g' "$PAM_FILE_PATH" + if grep -qP "^\s*auth\s.*\bpam_faillock.so\s.*\bdeny\b" "$PAM_FILE_PATH"; then + sed -i -E --follow-symlinks "s/(.*auth.*pam_faillock.so.*)\bdeny\b=?[[:alnum:]]*(.*)/\1\2/g" "$PAM_FILE_PATH" fi if [ -f /usr/bin/authselect ]; then @@ -19223,6 +22725,7 @@ if [ -f $FAILLOCK_CONF ]; then echo "$pam_file was not found" >&2 fi done + else for pam_file in "${AUTH_FILES[@]}" do @@ -19239,16 +22742,18 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: - CJIS-5.5.3 + - DISA-STIG-OL09-00-003020 - NIST-800-171-3.1.8 - NIST-800-53-AC-7(a) - NIST-800-53-CM-6(a) - PCI-DSS-Req-8.1.6 + - PCI-DSSv4-8.3 - PCI-DSSv4-8.3.4 - accounts_passwords_pam_faillock_deny - low_complexity @@ -19265,10 +22770,12 @@ fi when: '"pam" in ansible_facts.packages' tags: - CJIS-5.5.3 + - DISA-STIG-OL09-00-003020 - NIST-800-171-3.1.8 - NIST-800-53-AC-7(a) - NIST-800-53-CM-6(a) - PCI-DSS-Req-8.1.6 + - PCI-DSSv4-8.3 - PCI-DSSv4-8.3.4 - accounts_passwords_pam_faillock_deny - low_complexity @@ -19334,10 +22841,12 @@ fi - result_authselect_present.stat.exists tags: - CJIS-5.5.3 + - DISA-STIG-OL09-00-003020 - NIST-800-171-3.1.8 - NIST-800-53-AC-7(a) - NIST-800-53-CM-6(a) - PCI-DSS-Req-8.1.6 + - PCI-DSSv4-8.3 - PCI-DSSv4-8.3.4 - accounts_passwords_pam_faillock_deny - low_complexity @@ -19403,10 +22912,12 @@ fi - not result_authselect_present.stat.exists tags: - CJIS-5.5.3 + - DISA-STIG-OL09-00-003020 - NIST-800-171-3.1.8 - NIST-800-53-AC-7(a) - NIST-800-53-CM-6(a) - PCI-DSS-Req-8.1.6 + - PCI-DSSv4-8.3 - PCI-DSSv4-8.3.4 - accounts_passwords_pam_faillock_deny - low_complexity @@ -19416,7 +22927,7 @@ fi - restrict_strategy - name: XCCDF Value var_accounts_passwords_pam_faillock_deny # promote to variable set_fact: - var_accounts_passwords_pam_faillock_deny: !!str + var_accounts_passwords_pam_faillock_deny: !!str tags: - always @@ -19428,10 +22939,12 @@ fi when: '"pam" in ansible_facts.packages' tags: - CJIS-5.5.3 + - DISA-STIG-OL09-00-003020 - NIST-800-171-3.1.8 - NIST-800-53-AC-7(a) - NIST-800-53-CM-6(a) - PCI-DSS-Req-8.1.6 + - PCI-DSSv4-8.3 - PCI-DSSv4-8.3.4 - accounts_passwords_pam_faillock_deny - low_complexity @@ -19452,10 +22965,12 @@ fi - result_faillock_conf_check.stat.exists tags: - CJIS-5.5.3 + - DISA-STIG-OL09-00-003020 - NIST-800-171-3.1.8 - NIST-800-53-AC-7(a) - NIST-800-53-CM-6(a) - PCI-DSS-Req-8.1.6 + - PCI-DSSv4-8.3 - PCI-DSSv4-8.3.4 - accounts_passwords_pam_faillock_deny - low_complexity @@ -19570,7 +23085,16 @@ fi }} when: - result_authselect_check_cmd is success - - authselect_current_profile is not match("custom/") + - authselect_current_profile is not match("^(custom/|local)") + - not result_authselect_custom_profile_present.stat.exists + + - name: Lock Accounts After Failed Password Attempts - Create an authselect + custom profile based on sssd profile + ansible.builtin.command: + cmd: authselect create-profile hardening -b sssd + when: + - result_authselect_check_cmd is success + - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists - name: Lock Accounts After Failed Password Attempts - Ensure authselect changes @@ -19622,6 +23146,11 @@ fi when: - result_authselect_present.stat.exists + - name: Lock Accounts After Failed Password Attempts - Define a fact for control + already filtered in case filters are used + ansible.builtin.set_fact: + pam_module_control: '' + - name: Lock Accounts After Failed Password Attempts - Ensure the "deny" option from "pam_faillock.so" is not present in {{ pam_file_path }} ansible.builtin.replace: @@ -19742,7 +23271,16 @@ fi }} when: - result_authselect_check_cmd is success - - authselect_current_profile is not match("custom/") + - authselect_current_profile is not match("^(custom/|local)") + - not result_authselect_custom_profile_present.stat.exists + + - name: Lock Accounts After Failed Password Attempts - Create an authselect + custom profile based on sssd profile + ansible.builtin.command: + cmd: authselect create-profile hardening -b sssd + when: + - result_authselect_check_cmd is success + - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists - name: Lock Accounts After Failed Password Attempts - Ensure authselect changes @@ -19794,6 +23332,11 @@ fi when: - result_authselect_present.stat.exists + - name: Lock Accounts After Failed Password Attempts - Define a fact for control + already filtered in case filters are used + ansible.builtin.set_fact: + pam_module_control: '' + - name: Lock Accounts After Failed Password Attempts - Ensure the "deny" option from "pam_faillock.so" is not present in {{ pam_file_path }} ansible.builtin.replace: @@ -19816,10 +23359,12 @@ fi - result_faillock_conf_check.stat.exists tags: - CJIS-5.5.3 + - DISA-STIG-OL09-00-003020 - NIST-800-171-3.1.8 - NIST-800-53-AC-7(a) - NIST-800-53-CM-6(a) - PCI-DSS-Req-8.1.6 + - PCI-DSSv4-8.3 - PCI-DSSv4-8.3.4 - accounts_passwords_pam_faillock_deny - low_complexity @@ -19902,10 +23447,12 @@ fi - not result_faillock_conf_check.stat.exists tags: - CJIS-5.5.3 + - DISA-STIG-OL09-00-003020 - NIST-800-171-3.1.8 - NIST-800-53-AC-7(a) - NIST-800-53-CM-6(a) - PCI-DSS-Req-8.1.6 + - PCI-DSSv4-8.3 - PCI-DSSv4-8.3.4 - accounts_passwords_pam_faillock_deny - low_complexity @@ -19913,89 +23460,90 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - - Configure the root Account for Failed Password Attempts - This rule configures the system to lock out the root account after a number of + + + + + + + + + + + Configure the root Account for Failed Password Attempts + This rule configures the system to lock out the root account after a number of incorrect login attempts using pam_faillock.so. pam_faillock.so module requires multiple entries in pam files. These entries must be carefully defined to work as expected. In order to avoid errors when manually editing these files, it is recommended to use the appropriate tools, such as authselect or authconfig, -depending on the OS version. - If the system relies on authselect tool to manage PAM settings, the remediation +depending on the OS version. + If the system relies on authselect tool to manage PAM settings, the remediation will also use authselect tool. However, if any manual modification was made in PAM files, the authselect integrity check will fail and the remediation will be aborted in order to preserve intentional changes. In this case, an informative message will be shown in the remediation report. If the system supports the /etc/security/faillock.conf file, the pam_faillock -parameters should be defined in faillock.conf file. - BP28(R18) - 1 - 12 - 15 - 16 - DSS05.04 - DSS05.10 - DSS06.10 - CCI-002238 - CCI-000044 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - SR 1.1 - SR 1.10 - SR 1.2 - SR 1.5 - SR 1.7 - SR 1.8 - SR 1.9 - 0421 - 0422 - 0431 - 0974 - 1173 - 1401 - 1504 - 1505 - 1546 - 1557 - 1558 - 1559 - 1560 - 1561 - A.18.1.4 - A.9.2.1 - A.9.2.4 - A.9.3.1 - A.9.4.2 - A.9.4.3 - CM-6(a) - AC-7(b) - IA-5(c) - PR.AC-7 - FMT_MOF_EXT.1 - SRG-OS-000329-GPOS-00128 - SRG-OS-000021-GPOS-00005 - By limiting the number of failed logon attempts, the risk of unauthorized system access via +parameters should be defined in faillock.conf file. + 1 + 12 + 15 + 16 + DSS05.04 + DSS05.10 + DSS06.10 + CCI-000044 + CCI-002238 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + SR 1.1 + SR 1.10 + SR 1.2 + SR 1.5 + SR 1.7 + SR 1.8 + SR 1.9 + 0421 + 0422 + 0431 + 0974 + 1173 + 1401 + 1504 + 1505 + 1546 + 1557 + 1558 + 1559 + 1560 + 1561 + A.18.1.4 + A.9.2.1 + A.9.2.4 + A.9.3.1 + A.9.4.2 + A.9.4.3 + CM-6(a) + AC-7(b) + IA-5(c) + PR.AC-7 + SRG-OS-000329-GPOS-00128 + SRG-OS-000021-GPOS-00005 + R31 + OL09-00-003021 + SV-271840r1092232_rule + By limiting the number of failed logon attempts, the risk of unauthorized system access via user password guessing, also known as brute-forcing, is reduced. Limits are imposed by locking -the account. - - # Remediation is applicable only in certain platforms +the account. + + # Remediation is applicable only in certain platforms if rpm --quiet -q pam; then if [ -f /usr/bin/authselect ]; then @@ -20026,14 +23574,16 @@ done fi AUTH_FILES=("/etc/pam.d/system-auth" "/etc/pam.d/password-auth") +SKIP_FAILLOCK_CHECK=false FAILLOCK_CONF="/etc/security/faillock.conf" -if [ -f $FAILLOCK_CONF ]; then +if [ -f $FAILLOCK_CONF ] || [ "$SKIP_FAILLOCK_CHECK" = "true" ]; then regex="^\s*even_deny_root" line="even_deny_root" if ! grep -q $regex $FAILLOCK_CONF; then echo $line >> $FAILLOCK_CONF fi + for pam_file in "${AUTH_FILES[@]}" do if [ -e "$pam_file" ] ; then @@ -20053,6 +23603,11 @@ if [ -f $FAILLOCK_CONF ]; then # If not already in use, a custom profile is created preserving the enabled features. if [[ ! $CURRENT_PROFILE == custom/* ]]; then ENABLED_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }') + # The "local" profile does not contain essential security features required by multiple Benchmarks. + # If currently used, it is replaced by "sssd", which is the best option in this case. + if [[ $CURRENT_PROFILE == local ]]; then + CURRENT_PROFILE="sssd" + fi authselect create-profile hardening -b $CURRENT_PROFILE CURRENT_PROFILE="custom/hardening" @@ -20070,8 +23625,8 @@ if [ -f $FAILLOCK_CONF ]; then authselect apply-changes -b fi - if grep -qP '^\s*auth\s.*\bpam_faillock.so\s.*\beven_deny_root\b' "$PAM_FILE_PATH"; then - sed -i -E --follow-symlinks 's/(.*auth.*pam_faillock.so.*)\beven_deny_root\b=?[[:alnum:]]*(.*)/\1\2/g' "$PAM_FILE_PATH" + if grep -qP "^\s*auth\s.*\bpam_faillock.so\s.*\beven_deny_root\b" "$PAM_FILE_PATH"; then + sed -i -E --follow-symlinks "s/(.*auth.*pam_faillock.so.*)\beven_deny_root\b=?[[:alnum:]]*(.*)/\1\2/g" "$PAM_FILE_PATH" fi if [ -f /usr/bin/authselect ]; then @@ -20081,6 +23636,7 @@ if [ -f $FAILLOCK_CONF ]; then echo "$pam_file was not found" >&2 fi done + else for pam_file in "${AUTH_FILES[@]}" do @@ -20094,11 +23650,12 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-003021 - NIST-800-53-AC-7(b) - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(c) @@ -20116,6 +23673,7 @@ fi register: result_authselect_present when: '"pam" in ansible_facts.packages' tags: + - DISA-STIG-OL09-00-003021 - NIST-800-53-AC-7(b) - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(c) @@ -20183,6 +23741,7 @@ fi - '"pam" in ansible_facts.packages' - result_authselect_present.stat.exists tags: + - DISA-STIG-OL09-00-003021 - NIST-800-53-AC-7(b) - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(c) @@ -20249,6 +23808,7 @@ fi - '"pam" in ansible_facts.packages' - not result_authselect_present.stat.exists tags: + - DISA-STIG-OL09-00-003021 - NIST-800-53-AC-7(b) - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(c) @@ -20266,6 +23826,7 @@ fi register: result_faillock_conf_check when: '"pam" in ansible_facts.packages' tags: + - DISA-STIG-OL09-00-003021 - NIST-800-53-AC-7(b) - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(c) @@ -20287,6 +23848,7 @@ fi - '"pam" in ansible_facts.packages' - result_faillock_conf_check.stat.exists tags: + - DISA-STIG-OL09-00-003021 - NIST-800-53-AC-7(b) - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(c) @@ -20403,7 +23965,16 @@ fi }} when: - result_authselect_check_cmd is success - - authselect_current_profile is not match("custom/") + - authselect_current_profile is not match("^(custom/|local)") + - not result_authselect_custom_profile_present.stat.exists + + - name: Configure the root Account for Failed Password Attempts - Create an + authselect custom profile based on sssd profile + ansible.builtin.command: + cmd: authselect create-profile hardening -b sssd + when: + - result_authselect_check_cmd is success + - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists - name: Configure the root Account for Failed Password Attempts - Ensure authselect @@ -20455,6 +24026,11 @@ fi when: - result_authselect_present.stat.exists + - name: Configure the root Account for Failed Password Attempts - Define a fact + for control already filtered in case filters are used + ansible.builtin.set_fact: + pam_module_control: '' + - name: Configure the root Account for Failed Password Attempts - Ensure the "even_deny_root" option from "pam_faillock.so" is not present in {{ pam_file_path }} ansible.builtin.replace: @@ -20575,7 +24151,16 @@ fi }} when: - result_authselect_check_cmd is success - - authselect_current_profile is not match("custom/") + - authselect_current_profile is not match("^(custom/|local)") + - not result_authselect_custom_profile_present.stat.exists + + - name: Configure the root Account for Failed Password Attempts - Create an + authselect custom profile based on sssd profile + ansible.builtin.command: + cmd: authselect create-profile hardening -b sssd + when: + - result_authselect_check_cmd is success + - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists - name: Configure the root Account for Failed Password Attempts - Ensure authselect @@ -20627,6 +24212,11 @@ fi when: - result_authselect_present.stat.exists + - name: Configure the root Account for Failed Password Attempts - Define a fact + for control already filtered in case filters are used + ansible.builtin.set_fact: + pam_module_control: '' + - name: Configure the root Account for Failed Password Attempts - Ensure the "even_deny_root" option from "pam_faillock.so" is not present in {{ pam_file_path }} ansible.builtin.replace: @@ -20648,6 +24238,7 @@ fi - '"pam" in ansible_facts.packages' - result_faillock_conf_check.stat.exists tags: + - DISA-STIG-OL09-00-003021 - NIST-800-53-AC-7(b) - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(c) @@ -20703,6 +24294,7 @@ fi - '"pam" in ansible_facts.packages' - not result_faillock_conf_check.stat.exists tags: + - DISA-STIG-OL09-00-003021 - NIST-800-53-AC-7(b) - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(c) @@ -20712,17 +24304,17 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Lock Accounts Must Persist - This rule ensures that the system lock out accounts using pam_faillock.so persist + + + + + + + + + + Lock Accounts Must Persist + This rule ensures that the system lock out accounts using pam_faillock.so persist after system reboot. From "pam_faillock" man pages: Note that the default directory that "pam_faillock" uses is usually cleared on system boot so the access will be reenabled after system reboot. If that is undesirable, a different @@ -20733,29 +24325,30 @@ defined to work as expected. In order to avoid errors when manually editing thes recommended to use the appropriate tools, such as authselect or authconfig, depending on the OS version. -The chosen profile expects the directory to be . - If the system relies on authselect tool to manage PAM settings, the remediation +The chosen profile expects the directory to be . + If the system relies on authselect tool to manage PAM settings, the remediation will also use authselect tool. However, if any manual modification was made in PAM files, the authselect integrity check will fail and the remediation will be aborted in order to preserve intentional changes. In this case, an informative message will be shown in the remediation report. If the system supports the /etc/security/faillock.conf file, the pam_faillock -parameters should be defined in faillock.conf file. - CCI-000044 - CCI-002238 - AC-7(b) - AC-7(a) - AC-7.1(ii) - SRG-OS-000021-GPOS-00005 - SRG-OS-000329-GPOS-00128 - Locking out user accounts after a number of incorrect attempts prevents direct password +parameters should be defined in faillock.conf file. + CCI-000044 + AC-7(b) + AC-7(a) + AC-7.1(ii) + SRG-OS-000021-GPOS-00005 + SRG-OS-000329-GPOS-00128 + OL09-00-003023 + SV-271842r1092238_rule + Locking out user accounts after a number of incorrect attempts prevents direct password guessing attacks. In combination with the silent option, user enumeration attacks -are also mitigated. - - # Remediation is applicable only in certain platforms +are also mitigated. + + # Remediation is applicable only in certain platforms if rpm --quiet -q pam; then -var_accounts_passwords_pam_faillock_dir='' +var_accounts_passwords_pam_faillock_dir='' if [ -f /usr/bin/authselect ]; then @@ -20786,9 +24379,10 @@ done fi AUTH_FILES=("/etc/pam.d/system-auth" "/etc/pam.d/password-auth") +SKIP_FAILLOCK_CHECK=false FAILLOCK_CONF="/etc/security/faillock.conf" -if [ -f $FAILLOCK_CONF ]; then +if [ -f $FAILLOCK_CONF ] || [ "$SKIP_FAILLOCK_CHECK" = "true" ]; then regex="^\s*dir\s*=" line="dir = $var_accounts_passwords_pam_faillock_dir" if ! grep -q $regex $FAILLOCK_CONF; then @@ -20796,6 +24390,7 @@ if [ -f $FAILLOCK_CONF ]; then else sed -i --follow-symlinks 's|^\s*\(dir\s*=\s*\)\(\S\+\)|\1'"$var_accounts_passwords_pam_faillock_dir"'|g' $FAILLOCK_CONF fi + for pam_file in "${AUTH_FILES[@]}" do if [ -e "$pam_file" ] ; then @@ -20815,6 +24410,11 @@ if [ -f $FAILLOCK_CONF ]; then # If not already in use, a custom profile is created preserving the enabled features. if [[ ! $CURRENT_PROFILE == custom/* ]]; then ENABLED_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }') + # The "local" profile does not contain essential security features required by multiple Benchmarks. + # If currently used, it is replaced by "sssd", which is the best option in this case. + if [[ $CURRENT_PROFILE == local ]]; then + CURRENT_PROFILE="sssd" + fi authselect create-profile hardening -b $CURRENT_PROFILE CURRENT_PROFILE="custom/hardening" @@ -20832,8 +24432,8 @@ if [ -f $FAILLOCK_CONF ]; then authselect apply-changes -b fi - if grep -qP '^\s*auth\s.*\bpam_faillock.so\s.*\bdir\b' "$PAM_FILE_PATH"; then - sed -i -E --follow-symlinks 's/(.*auth.*pam_faillock.so.*)\bdir\b=?[[:alnum:]]*(.*)/\1\2/g' "$PAM_FILE_PATH" + if grep -qP "^\s*auth\s.*\bpam_faillock.so\s.*\bdir\b" "$PAM_FILE_PATH"; then + sed -i -E --follow-symlinks "s/(.*auth.*pam_faillock.so.*)\bdir\b=?[[:alnum:]]*(.*)/\1\2/g" "$PAM_FILE_PATH" fi if [ -f /usr/bin/authselect ]; then @@ -20843,6 +24443,7 @@ if [ -f $FAILLOCK_CONF ]; then echo "$pam_file was not found" >&2 fi done + else for pam_file in "${AUTH_FILES[@]}" do @@ -20873,11 +24474,12 @@ restorecon -R -v "$var_accounts_passwords_pam_faillock_dir" else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-003023 - NIST-800-53-AC-7(a) - NIST-800-53-AC-7(b) - NIST-800-53-AC-7.1(ii) @@ -20894,6 +24496,7 @@ fi register: result_authselect_present when: '"pam" in ansible_facts.packages' tags: + - DISA-STIG-OL09-00-003023 - NIST-800-53-AC-7(a) - NIST-800-53-AC-7(b) - NIST-800-53-AC-7.1(ii) @@ -20957,6 +24560,7 @@ fi - '"pam" in ansible_facts.packages' - result_authselect_present.stat.exists tags: + - DISA-STIG-OL09-00-003023 - NIST-800-53-AC-7(a) - NIST-800-53-AC-7(b) - NIST-800-53-AC-7.1(ii) @@ -21021,6 +24625,7 @@ fi - '"pam" in ansible_facts.packages' - not result_authselect_present.stat.exists tags: + - DISA-STIG-OL09-00-003023 - NIST-800-53-AC-7(a) - NIST-800-53-AC-7(b) - NIST-800-53-AC-7.1(ii) @@ -21032,7 +24637,7 @@ fi - no_reboot_needed - name: XCCDF Value var_accounts_passwords_pam_faillock_dir # promote to variable set_fact: - var_accounts_passwords_pam_faillock_dir: !!str + var_accounts_passwords_pam_faillock_dir: !!str tags: - always @@ -21043,6 +24648,7 @@ fi register: result_faillock_conf_check when: '"pam" in ansible_facts.packages' tags: + - DISA-STIG-OL09-00-003023 - NIST-800-53-AC-7(a) - NIST-800-53-AC-7(b) - NIST-800-53-AC-7.1(ii) @@ -21063,6 +24669,7 @@ fi - '"pam" in ansible_facts.packages' - result_faillock_conf_check.stat.exists tags: + - DISA-STIG-OL09-00-003023 - NIST-800-53-AC-7(a) - NIST-800-53-AC-7(b) - NIST-800-53-AC-7.1(ii) @@ -21174,7 +24781,16 @@ fi }} when: - result_authselect_check_cmd is success - - authselect_current_profile is not match("custom/") + - authselect_current_profile is not match("^(custom/|local)") + - not result_authselect_custom_profile_present.stat.exists + + - name: Lock Accounts Must Persist - Create an authselect custom profile based + on sssd profile + ansible.builtin.command: + cmd: authselect create-profile hardening -b sssd + when: + - result_authselect_check_cmd is success + - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists - name: Lock Accounts Must Persist - Ensure authselect changes are applied @@ -21224,6 +24840,11 @@ fi when: - result_authselect_present.stat.exists + - name: Lock Accounts Must Persist - Define a fact for control already filtered + in case filters are used + ansible.builtin.set_fact: + pam_module_control: '' + - name: Lock Accounts Must Persist - Ensure the "dir" option from "pam_faillock.so" is not present in {{ pam_file_path }} ansible.builtin.replace: @@ -21338,7 +24959,16 @@ fi }} when: - result_authselect_check_cmd is success - - authselect_current_profile is not match("custom/") + - authselect_current_profile is not match("^(custom/|local)") + - not result_authselect_custom_profile_present.stat.exists + + - name: Lock Accounts Must Persist - Create an authselect custom profile based + on sssd profile + ansible.builtin.command: + cmd: authselect create-profile hardening -b sssd + when: + - result_authselect_check_cmd is success + - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists - name: Lock Accounts Must Persist - Ensure authselect changes are applied @@ -21388,6 +25018,11 @@ fi when: - result_authselect_present.stat.exists + - name: Lock Accounts Must Persist - Define a fact for control already filtered + in case filters are used + ansible.builtin.set_fact: + pam_module_control: '' + - name: Lock Accounts Must Persist - Ensure the "dir" option from "pam_faillock.so" is not present in {{ pam_file_path }} ansible.builtin.replace: @@ -21408,6 +25043,7 @@ fi - '"pam" in ansible_facts.packages' - result_faillock_conf_check.stat.exists tags: + - DISA-STIG-OL09-00-003023 - NIST-800-53-AC-7(a) - NIST-800-53-AC-7(b) - NIST-800-53-AC-7.1(ii) @@ -21491,6 +25127,7 @@ fi - '"pam" in ansible_facts.packages' - not result_faillock_conf_check.stat.exists tags: + - DISA-STIG-OL09-00-003023 - NIST-800-53-AC-7(a) - NIST-800-53-AC-7(b) - NIST-800-53-AC-7.1(ii) @@ -21511,6 +25148,7 @@ fi - policycoreutils-python-utils when: '"pam" in ansible_facts.packages' tags: + - DISA-STIG-OL09-00-003023 - NIST-800-53-AC-7(a) - NIST-800-53-AC-7(b) - NIST-800-53-AC-7.1(ii) @@ -21528,6 +25166,7 @@ fi setype: faillog_t when: '"pam" in ansible_facts.packages' tags: + - DISA-STIG-OL09-00-003023 - NIST-800-53-AC-7(a) - NIST-800-53-AC-7(b) - NIST-800-53-AC-7.1(ii) @@ -21543,11 +25182,12 @@ fi cmd: semanage fcontext -a -t faillog_t "{{ var_accounts_passwords_pam_faillock_dir }}(/.*)?" register: result_accounts_passwords_pam_faillock_dir_semanage - ignore_errors: true + failed_when: false changed_when: - result_accounts_passwords_pam_faillock_dir_semanage.rc == 0 when: '"pam" in ansible_facts.packages' tags: + - DISA-STIG-OL09-00-003023 - NIST-800-53-AC-7(a) - NIST-800-53-AC-7(b) - NIST-800-53-AC-7.1(ii) @@ -21564,6 +25204,7 @@ fi register: result_accounts_passwords_pam_faillock_dir_restorecon when: '"pam" in ansible_facts.packages' tags: + - DISA-STIG-OL09-00-003023 - NIST-800-53-AC-7(a) - NIST-800-53-AC-7(b) - NIST-800-53-AC-7.1(ii) @@ -21573,96 +25214,96 @@ fi - low_disruption - medium_severity - no_reboot_needed - - - - - - - - - - Set Interval For Counting Failed Password Attempts - Utilizing pam_faillock.so, the fail_interval directive configures the system + + + + + + + + + + Set Interval For Counting Failed Password Attempts + Utilizing pam_faillock.so, the fail_interval directive configures the system to lock out an account after a number of incorrect login attempts within a specified time period. Ensure that the file /etc/security/faillock.conf contains the following entry: -fail_interval = <interval-in-seconds> where interval-in-seconds is or greater. +fail_interval = <interval-in-seconds> where interval-in-seconds is or greater. In order to avoid errors when manually editing these files, it is recommended to use the appropriate tools, such as authselect or authconfig, -depending on the OS version. - If the system relies on authselect tool to manage PAM settings, the remediation +depending on the OS version. + If the system relies on authselect tool to manage PAM settings, the remediation will also use authselect tool. However, if any manual modification was made in PAM files, the authselect integrity check will fail and the remediation will be aborted in order to preserve intentional changes. In this case, an informative message will be shown in the remediation report. If the system supports the /etc/security/faillock.conf file, the pam_faillock -parameters should be defined in faillock.conf file. - BP28(R18) - 1 - 12 - 15 - 16 - DSS05.04 - DSS05.10 - DSS06.10 - CCI-000044 - CCI-002236 - CCI-002237 - CCI-002238 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - SR 1.1 - SR 1.10 - SR 1.2 - SR 1.5 - SR 1.7 - SR 1.8 - SR 1.9 - 0421 - 0422 - 0431 - 0974 - 1173 - 1401 - 1504 - 1505 - 1546 - 1557 - 1558 - 1559 - 1560 - 1561 - A.18.1.4 - A.9.2.1 - A.9.2.4 - A.9.3.1 - A.9.4.2 - A.9.4.3 - CM-6(a) - AC-7(a) - PR.AC-7 - FIA_AFL.1 - SRG-OS-000329-GPOS-00128 - SRG-OS-000021-GPOS-00005 - By limiting the number of failed logon attempts the risk of unauthorized system +parameters should be defined in faillock.conf file. + 1 + 12 + 15 + 16 + DSS05.04 + DSS05.10 + DSS06.10 + CCI-000044 + CCI-002238 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + SR 1.1 + SR 1.10 + SR 1.2 + SR 1.5 + SR 1.7 + SR 1.8 + SR 1.9 + 0421 + 0422 + 0431 + 0974 + 1173 + 1401 + 1504 + 1505 + 1546 + 1557 + 1558 + 1559 + 1560 + 1561 + A.18.1.4 + A.9.2.1 + A.9.2.4 + A.9.3.1 + A.9.4.2 + A.9.4.3 + CM-6(a) + AC-7(a) + PR.AC-7 + FIA_AFL.1 + SRG-OS-000329-GPOS-00128 + SRG-OS-000021-GPOS-00005 + R31 + OL09-00-002416 + SV-271754r1091974_rule + By limiting the number of failed logon attempts the risk of unauthorized system access via user password guessing, otherwise known as brute-forcing, is reduced. -Limits are imposed by locking the account. - - # Remediation is applicable only in certain platforms +Limits are imposed by locking the account. + + # Remediation is applicable only in certain platforms if rpm --quiet -q pam; then -var_accounts_passwords_pam_faillock_fail_interval='' +var_accounts_passwords_pam_faillock_fail_interval='' if [ -f /usr/bin/authselect ]; then @@ -21693,9 +25334,10 @@ done fi AUTH_FILES=("/etc/pam.d/system-auth" "/etc/pam.d/password-auth") +SKIP_FAILLOCK_CHECK=false FAILLOCK_CONF="/etc/security/faillock.conf" -if [ -f $FAILLOCK_CONF ]; then +if [ -f $FAILLOCK_CONF ] || [ "$SKIP_FAILLOCK_CHECK" = "true" ]; then regex="^\s*fail_interval\s*=" line="fail_interval = $var_accounts_passwords_pam_faillock_fail_interval" if ! grep -q $regex $FAILLOCK_CONF; then @@ -21703,6 +25345,7 @@ if [ -f $FAILLOCK_CONF ]; then else sed -i --follow-symlinks 's|^\s*\(fail_interval\s*=\s*\)\(\S\+\)|\1'"$var_accounts_passwords_pam_faillock_fail_interval"'|g' $FAILLOCK_CONF fi + for pam_file in "${AUTH_FILES[@]}" do if [ -e "$pam_file" ] ; then @@ -21722,6 +25365,11 @@ if [ -f $FAILLOCK_CONF ]; then # If not already in use, a custom profile is created preserving the enabled features. if [[ ! $CURRENT_PROFILE == custom/* ]]; then ENABLED_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }') + # The "local" profile does not contain essential security features required by multiple Benchmarks. + # If currently used, it is replaced by "sssd", which is the best option in this case. + if [[ $CURRENT_PROFILE == local ]]; then + CURRENT_PROFILE="sssd" + fi authselect create-profile hardening -b $CURRENT_PROFILE CURRENT_PROFILE="custom/hardening" @@ -21739,8 +25387,8 @@ if [ -f $FAILLOCK_CONF ]; then authselect apply-changes -b fi - if grep -qP '^\s*auth\s.*\bpam_faillock.so\s.*\bfail_interval\b' "$PAM_FILE_PATH"; then - sed -i -E --follow-symlinks 's/(.*auth.*pam_faillock.so.*)\bfail_interval\b=?[[:alnum:]]*(.*)/\1\2/g' "$PAM_FILE_PATH" + if grep -qP "^\s*auth\s.*\bpam_faillock.so\s.*\bfail_interval\b" "$PAM_FILE_PATH"; then + sed -i -E --follow-symlinks "s/(.*auth.*pam_faillock.so.*)\bfail_interval\b=?[[:alnum:]]*(.*)/\1\2/g" "$PAM_FILE_PATH" fi if [ -f /usr/bin/authselect ]; then @@ -21750,6 +25398,7 @@ if [ -f $FAILLOCK_CONF ]; then echo "$pam_file was not found" >&2 fi done + else for pam_file in "${AUTH_FILES[@]}" do @@ -21766,11 +25415,12 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-002416 - NIST-800-53-AC-7(a) - NIST-800-53-CM-6(a) - accounts_passwords_pam_faillock_interval @@ -21787,6 +25437,7 @@ fi register: result_authselect_present when: '"pam" in ansible_facts.packages' tags: + - DISA-STIG-OL09-00-002416 - NIST-800-53-AC-7(a) - NIST-800-53-CM-6(a) - accounts_passwords_pam_faillock_interval @@ -21853,6 +25504,7 @@ fi - '"pam" in ansible_facts.packages' - result_authselect_present.stat.exists tags: + - DISA-STIG-OL09-00-002416 - NIST-800-53-AC-7(a) - NIST-800-53-CM-6(a) - accounts_passwords_pam_faillock_interval @@ -21918,6 +25570,7 @@ fi - '"pam" in ansible_facts.packages' - not result_authselect_present.stat.exists tags: + - DISA-STIG-OL09-00-002416 - NIST-800-53-AC-7(a) - NIST-800-53-CM-6(a) - accounts_passwords_pam_faillock_interval @@ -21928,7 +25581,7 @@ fi - restrict_strategy - name: XCCDF Value var_accounts_passwords_pam_faillock_fail_interval # promote to variable set_fact: - var_accounts_passwords_pam_faillock_fail_interval: !!str + var_accounts_passwords_pam_faillock_fail_interval: !!str tags: - always @@ -21939,6 +25592,7 @@ fi register: result_faillock_conf_check when: '"pam" in ansible_facts.packages' tags: + - DISA-STIG-OL09-00-002416 - NIST-800-53-AC-7(a) - NIST-800-53-CM-6(a) - accounts_passwords_pam_faillock_interval @@ -21959,6 +25613,7 @@ fi - '"pam" in ansible_facts.packages' - result_faillock_conf_check.stat.exists tags: + - DISA-STIG-OL09-00-002416 - NIST-800-53-AC-7(a) - NIST-800-53-CM-6(a) - accounts_passwords_pam_faillock_interval @@ -22074,7 +25729,16 @@ fi }} when: - result_authselect_check_cmd is success - - authselect_current_profile is not match("custom/") + - authselect_current_profile is not match("^(custom/|local)") + - not result_authselect_custom_profile_present.stat.exists + + - name: Set Interval For Counting Failed Password Attempts - Create an authselect + custom profile based on sssd profile + ansible.builtin.command: + cmd: authselect create-profile hardening -b sssd + when: + - result_authselect_check_cmd is success + - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists - name: Set Interval For Counting Failed Password Attempts - Ensure authselect @@ -22126,6 +25790,11 @@ fi when: - result_authselect_present.stat.exists + - name: Set Interval For Counting Failed Password Attempts - Define a fact for + control already filtered in case filters are used + ansible.builtin.set_fact: + pam_module_control: '' + - name: Set Interval For Counting Failed Password Attempts - Ensure the "fail_interval" option from "pam_faillock.so" is not present in {{ pam_file_path }} ansible.builtin.replace: @@ -22246,7 +25915,16 @@ fi }} when: - result_authselect_check_cmd is success - - authselect_current_profile is not match("custom/") + - authselect_current_profile is not match("^(custom/|local)") + - not result_authselect_custom_profile_present.stat.exists + + - name: Set Interval For Counting Failed Password Attempts - Create an authselect + custom profile based on sssd profile + ansible.builtin.command: + cmd: authselect create-profile hardening -b sssd + when: + - result_authselect_check_cmd is success + - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists - name: Set Interval For Counting Failed Password Attempts - Ensure authselect @@ -22298,6 +25976,11 @@ fi when: - result_authselect_present.stat.exists + - name: Set Interval For Counting Failed Password Attempts - Define a fact for + control already filtered in case filters are used + ansible.builtin.set_fact: + pam_module_control: '' + - name: Set Interval For Counting Failed Password Attempts - Ensure the "fail_interval" option from "pam_faillock.so" is not present in {{ pam_file_path }} ansible.builtin.replace: @@ -22319,6 +26002,7 @@ fi - '"pam" in ansible_facts.packages' - result_faillock_conf_check.stat.exists tags: + - DISA-STIG-OL09-00-002416 - NIST-800-53-AC-7(a) - NIST-800-53-CM-6(a) - accounts_passwords_pam_faillock_interval @@ -22403,6 +26087,7 @@ fi - '"pam" in ansible_facts.packages' - not result_faillock_conf_check.stat.exists tags: + - DISA-STIG-OL09-00-002416 - NIST-800-53-AC-7(a) - NIST-800-53-CM-6(a) - accounts_passwords_pam_faillock_interval @@ -22411,25 +26096,23 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - - Set Lockout Time for Failed Password Attempts - This rule configures the system to lock out accounts during a specified time period after a + + + + + + + + + + + Set Lockout Time for Failed Password Attempts + This rule configures the system to lock out accounts during a specified time period after a number of incorrect login attempts using pam_faillock.so. - Ensure that the file /etc/security/faillock.conf contains the following entry: unlock_time=<interval-in-seconds> where -interval-in-seconds is or greater. - +interval-in-seconds is or greater. pam_faillock.so module requires multiple entries in pam files. These entries must be carefully defined to work as expected. In order to avoid any errors when manually editing these files, @@ -22437,86 +26120,88 @@ it is recommended to use the appropriate tools, such as authselectunlock_time is set to 0, manual intervention by an administrator is required -to unlock a user. This should be done using the faillock tool. - If the system supports the new /etc/security/faillock.conf file but the +to unlock a user. This should be done using the faillock tool. + If the system supports the new /etc/security/faillock.conf file but the pam_faillock.so parameters are defined directly in /etc/pam.d/system-auth and /etc/pam.d/password-auth, the remediation will migrate the unlock_time parameter to /etc/security/faillock.conf to ensure compatibility with authselect tool. The parameters deny and fail_interval, if used, also have to be migrated -by their respective remediation. - If the system relies on authselect tool to manage PAM settings, the remediation +by their respective remediation. + If the system relies on authselect tool to manage PAM settings, the remediation will also use authselect tool. However, if any manual modification was made in PAM files, the authselect integrity check will fail and the remediation will be aborted in order to preserve intentional changes. In this case, an informative message will be shown in the remediation report. If the system supports the /etc/security/faillock.conf file, the pam_faillock -parameters should be defined in faillock.conf file. - BP28(R18) - 1 - 12 - 15 - 16 - 5.5.3 - DSS05.04 - DSS05.10 - DSS06.10 - 3.1.8 - CCI-000044 - CCI-002236 - CCI-002237 - CCI-002238 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - SR 1.1 - SR 1.10 - SR 1.2 - SR 1.5 - SR 1.7 - SR 1.8 - SR 1.9 - 0421 - 0422 - 0431 - 0974 - 1173 - 1401 - 1504 - 1505 - 1546 - 1557 - 1558 - 1559 - 1560 - 1561 - A.18.1.4 - A.9.2.1 - A.9.2.4 - A.9.3.1 - A.9.4.2 - A.9.4.3 - CM-6(a) - AC-7(b) - PR.AC-7 - FIA_AFL.1 - Req-8.1.7 - 8.3.4 - SRG-OS-000329-GPOS-00128 - SRG-OS-000021-GPOS-00005 - By limiting the number of failed logon attempts the risk of unauthorized system +parameters should be defined in faillock.conf file. + 1 + 12 + 15 + 16 + 5.5.3 + DSS05.04 + DSS05.10 + DSS06.10 + 3.1.8 + CCI-000044 + CCI-002238 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + SR 1.1 + SR 1.10 + SR 1.2 + SR 1.5 + SR 1.7 + SR 1.8 + SR 1.9 + 0421 + 0422 + 0431 + 0974 + 1173 + 1401 + 1504 + 1505 + 1546 + 1557 + 1558 + 1559 + 1560 + 1561 + A.18.1.4 + A.9.2.1 + A.9.2.4 + A.9.3.1 + A.9.4.2 + A.9.4.3 + CM-6(a) + AC-7(b) + PR.AC-7 + FIA_AFL.1 + Req-8.1.7 + SRG-OS-000329-GPOS-00128 + SRG-OS-000021-GPOS-00005 + R31 + A.30.SEC-OL1 + 8.3.4 + 8.3 + OL09-00-002417 + SV-271755r1091977_rule + By limiting the number of failed logon attempts the risk of unauthorized system access via user password guessing, otherwise known as brute-forcing, is reduced. -Limits are imposed by locking the account. - - # Remediation is applicable only in certain platforms +Limits are imposed by locking the account. + + # Remediation is applicable only in certain platforms if rpm --quiet -q pam; then -var_accounts_passwords_pam_faillock_unlock_time='' +var_accounts_passwords_pam_faillock_unlock_time='' if [ -f /usr/bin/authselect ]; then @@ -22547,9 +26232,10 @@ done fi AUTH_FILES=("/etc/pam.d/system-auth" "/etc/pam.d/password-auth") +SKIP_FAILLOCK_CHECK=false FAILLOCK_CONF="/etc/security/faillock.conf" -if [ -f $FAILLOCK_CONF ]; then +if [ -f $FAILLOCK_CONF ] || [ "$SKIP_FAILLOCK_CHECK" = "true" ]; then regex="^\s*unlock_time\s*=" line="unlock_time = $var_accounts_passwords_pam_faillock_unlock_time" if ! grep -q $regex $FAILLOCK_CONF; then @@ -22557,6 +26243,7 @@ if [ -f $FAILLOCK_CONF ]; then else sed -i --follow-symlinks 's|^\s*\(unlock_time\s*=\s*\)\(\S\+\)|\1'"$var_accounts_passwords_pam_faillock_unlock_time"'|g' $FAILLOCK_CONF fi + for pam_file in "${AUTH_FILES[@]}" do if [ -e "$pam_file" ] ; then @@ -22576,6 +26263,11 @@ if [ -f $FAILLOCK_CONF ]; then # If not already in use, a custom profile is created preserving the enabled features. if [[ ! $CURRENT_PROFILE == custom/* ]]; then ENABLED_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }') + # The "local" profile does not contain essential security features required by multiple Benchmarks. + # If currently used, it is replaced by "sssd", which is the best option in this case. + if [[ $CURRENT_PROFILE == local ]]; then + CURRENT_PROFILE="sssd" + fi authselect create-profile hardening -b $CURRENT_PROFILE CURRENT_PROFILE="custom/hardening" @@ -22593,8 +26285,8 @@ if [ -f $FAILLOCK_CONF ]; then authselect apply-changes -b fi - if grep -qP '^\s*auth\s.*\bpam_faillock.so\s.*\bunlock_time\b' "$PAM_FILE_PATH"; then - sed -i -E --follow-symlinks 's/(.*auth.*pam_faillock.so.*)\bunlock_time\b=?[[:alnum:]]*(.*)/\1\2/g' "$PAM_FILE_PATH" + if grep -qP "^\s*auth\s.*\bpam_faillock.so\s.*\bunlock_time\b" "$PAM_FILE_PATH"; then + sed -i -E --follow-symlinks "s/(.*auth.*pam_faillock.so.*)\bunlock_time\b=?[[:alnum:]]*(.*)/\1\2/g" "$PAM_FILE_PATH" fi if [ -f /usr/bin/authselect ]; then @@ -22604,6 +26296,7 @@ if [ -f $FAILLOCK_CONF ]; then echo "$pam_file was not found" >&2 fi done + else for pam_file in "${AUTH_FILES[@]}" do @@ -22620,16 +26313,18 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: - CJIS-5.5.3 + - DISA-STIG-OL09-00-002417 - NIST-800-171-3.1.8 - NIST-800-53-AC-7(b) - NIST-800-53-CM-6(a) - PCI-DSS-Req-8.1.7 + - PCI-DSSv4-8.3 - PCI-DSSv4-8.3.4 - accounts_passwords_pam_faillock_unlock_time - low_complexity @@ -22646,10 +26341,12 @@ fi when: '"pam" in ansible_facts.packages' tags: - CJIS-5.5.3 + - DISA-STIG-OL09-00-002417 - NIST-800-171-3.1.8 - NIST-800-53-AC-7(b) - NIST-800-53-CM-6(a) - PCI-DSS-Req-8.1.7 + - PCI-DSSv4-8.3 - PCI-DSSv4-8.3.4 - accounts_passwords_pam_faillock_unlock_time - low_complexity @@ -22715,10 +26412,12 @@ fi - result_authselect_present.stat.exists tags: - CJIS-5.5.3 + - DISA-STIG-OL09-00-002417 - NIST-800-171-3.1.8 - NIST-800-53-AC-7(b) - NIST-800-53-CM-6(a) - PCI-DSS-Req-8.1.7 + - PCI-DSSv4-8.3 - PCI-DSSv4-8.3.4 - accounts_passwords_pam_faillock_unlock_time - low_complexity @@ -22784,10 +26483,12 @@ fi - not result_authselect_present.stat.exists tags: - CJIS-5.5.3 + - DISA-STIG-OL09-00-002417 - NIST-800-171-3.1.8 - NIST-800-53-AC-7(b) - NIST-800-53-CM-6(a) - PCI-DSS-Req-8.1.7 + - PCI-DSSv4-8.3 - PCI-DSSv4-8.3.4 - accounts_passwords_pam_faillock_unlock_time - low_complexity @@ -22797,7 +26498,7 @@ fi - restrict_strategy - name: XCCDF Value var_accounts_passwords_pam_faillock_unlock_time # promote to variable set_fact: - var_accounts_passwords_pam_faillock_unlock_time: !!str + var_accounts_passwords_pam_faillock_unlock_time: !!str tags: - always @@ -22809,10 +26510,12 @@ fi when: '"pam" in ansible_facts.packages' tags: - CJIS-5.5.3 + - DISA-STIG-OL09-00-002417 - NIST-800-171-3.1.8 - NIST-800-53-AC-7(b) - NIST-800-53-CM-6(a) - PCI-DSS-Req-8.1.7 + - PCI-DSSv4-8.3 - PCI-DSSv4-8.3.4 - accounts_passwords_pam_faillock_unlock_time - low_complexity @@ -22833,10 +26536,12 @@ fi - result_faillock_conf_check.stat.exists tags: - CJIS-5.5.3 + - DISA-STIG-OL09-00-002417 - NIST-800-171-3.1.8 - NIST-800-53-AC-7(b) - NIST-800-53-CM-6(a) - PCI-DSS-Req-8.1.7 + - PCI-DSSv4-8.3 - PCI-DSSv4-8.3.4 - accounts_passwords_pam_faillock_unlock_time - low_complexity @@ -22951,7 +26656,16 @@ fi }} when: - result_authselect_check_cmd is success - - authselect_current_profile is not match("custom/") + - authselect_current_profile is not match("^(custom/|local)") + - not result_authselect_custom_profile_present.stat.exists + + - name: Set Lockout Time for Failed Password Attempts - Create an authselect + custom profile based on sssd profile + ansible.builtin.command: + cmd: authselect create-profile hardening -b sssd + when: + - result_authselect_check_cmd is success + - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists - name: Set Lockout Time for Failed Password Attempts - Ensure authselect changes @@ -23003,6 +26717,11 @@ fi when: - result_authselect_present.stat.exists + - name: Set Lockout Time for Failed Password Attempts - Define a fact for control + already filtered in case filters are used + ansible.builtin.set_fact: + pam_module_control: '' + - name: Set Lockout Time for Failed Password Attempts - Ensure the "unlock_time" option from "pam_faillock.so" is not present in {{ pam_file_path }} ansible.builtin.replace: @@ -23123,7 +26842,16 @@ fi }} when: - result_authselect_check_cmd is success - - authselect_current_profile is not match("custom/") + - authselect_current_profile is not match("^(custom/|local)") + - not result_authselect_custom_profile_present.stat.exists + + - name: Set Lockout Time for Failed Password Attempts - Create an authselect + custom profile based on sssd profile + ansible.builtin.command: + cmd: authselect create-profile hardening -b sssd + when: + - result_authselect_check_cmd is success + - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists - name: Set Lockout Time for Failed Password Attempts - Ensure authselect changes @@ -23175,6 +26903,11 @@ fi when: - result_authselect_present.stat.exists + - name: Set Lockout Time for Failed Password Attempts - Define a fact for control + already filtered in case filters are used + ansible.builtin.set_fact: + pam_module_control: '' + - name: Set Lockout Time for Failed Password Attempts - Ensure the "unlock_time" option from "pam_faillock.so" is not present in {{ pam_file_path }} ansible.builtin.replace: @@ -23197,10 +26930,12 @@ fi - result_faillock_conf_check.stat.exists tags: - CJIS-5.5.3 + - DISA-STIG-OL09-00-002417 - NIST-800-171-3.1.8 - NIST-800-53-AC-7(b) - NIST-800-53-CM-6(a) - PCI-DSS-Req-8.1.7 + - PCI-DSSv4-8.3 - PCI-DSSv4-8.3.4 - accounts_passwords_pam_faillock_unlock_time - low_complexity @@ -23285,10 +27020,12 @@ fi - not result_faillock_conf_check.stat.exists tags: - CJIS-5.5.3 + - DISA-STIG-OL09-00-002417 - NIST-800-171-3.1.8 - NIST-800-53-AC-7(b) - NIST-800-53-CM-6(a) - PCI-DSS-Req-8.1.7 + - PCI-DSSv4-8.3 - PCI-DSSv4-8.3.4 - accounts_passwords_pam_faillock_unlock_time - low_complexity @@ -23296,19 +27033,19 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - - - Set Password Quality Requirements - The default pam_pwquality PAM module provides strength + + + + + + + + + + + + Set Password Quality Requirements + The default pam_pwquality PAM module provides strength checking for passwords. It performs a number of checks, such as making sure passwords are not similar to dictionary words, are of at least a certain length, are not the previous password reversed, @@ -23316,33 +27053,17 @@ and are not simply a change of case from the previous password. It can also require passwords to be in certain character classes. The pam_pwquality module is the preferred way of configuring password requirements. - + + The man pages pam_pwquality(8) provide information on the capabilities and configuration of -each. - - Set Password Quality Requirements, if using -pam_cracklib - The pam_cracklib PAM module can be configured to meet +each. + + Set Password Quality Requirements with pam_pwquality + The pam_pwquality PAM module can be configured to meet requirements for a variety of policies. - -For example, to configure pam_cracklib to require at least one uppercase -character, lowercase character, digit, and other (special) -character, locate the following line in /etc/pam.d/system-auth: -password requisite pam_cracklib.so try_first_pass retry=3 -and then alter it to read: -password required pam_cracklib.so try_first_pass retry=3 maxrepeat=3 minlen=14 dcredit=-1 ucredit=-1 ocredit=-1 lcredit=-1 difok=4 -If no such line exists, add one as the first line of the password section in /etc/pam.d/system-auth. -The arguments can be modified to ensure compliance with -your organization's security policy. Discussion of each parameter follows. - Note that the password quality requirements are not enforced for the -root account for some reason. - - - Set Password Quality Requirements with pam_pwquality - The pam_pwquality PAM module can be configured to meet -requirements for a variety of policies. - + + For example, to configure pam_pwquality to require at least one uppercase character, lowercase character, digit, and other (special) character, make sure that pam_pwquality exists in /etc/pam.d/system-auth: @@ -23357,206 +27078,210 @@ lcredit = -1 ocredit = -1 maxrepeat = 3 The arguments can be modified to ensure compliance with -your organization's security policy. Discussion of each parameter follows. - - dcredit - Minimum number of digits in password - 0 - -1 - -2 - -1 - - - dictcheck - Prevent the use of dictionary words for passwords. - 1 - 1 - - - difok - Minimum number of characters not present in old -password - 15 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 8 - - - lcredit - Minimum number of lower case in password - 0 - -1 - -2 - -1 - - - maxclassrepeat - Maximum Number of Consecutive Repeating Characters in a Password From the Same Character Class - 1 - 2 - 3 - 4 - 4 - - - maxrepeat - Maximum Number of Consecutive Repeating Characters in a Password - 1 - 2 - 3 - 3 - - - minclass - Minimum number of categories of characters that must exist in a password - 1 - 2 - 3 - 4 - 3 - - - minlen - Minimum number of characters in password - 10 - 12 - 14 - 15 - 18 - 20 - 6 - 7 - 8 - 15 - - - ocredit - Minimum number of other (special characters) in -password - 0 - -1 - -2 - -1 - - - retry - Number of retry attempts before erroring out - 1 - 2 - 3 - 4 - 5 - 3 - - - ucredit - Minimum number of upper case in password - 0 - -1 - -2 - -1 - - - Ensure PAM Enforces Password Requirements - Minimum Digit Characters - The pam_pwquality module's dcredit parameter controls requirements for +your organization's security policy. Discussion of each parameter follows. + + dcredit + Minimum number of digits in password + 0 + -1 + -2 + -1 + + + dictcheck + Prevent the use of dictionary words for passwords. + 1 + 1 + + + difok + Minimum number of characters not present in old +password + 15 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 8 + + + lcredit + Minimum number of lower case in password + 0 + -1 + -2 + -1 + + + maxclassrepeat + Maximum Number of Consecutive Repeating Characters in a Password From the Same Character Class + 1 + 2 + 3 + 4 + 4 + + + maxrepeat + Maximum Number of Consecutive Repeating Characters in a Password + 1 + 2 + 3 + 3 + + + minclass + Minimum number of categories of characters that must exist in a password + 1 + 2 + 3 + 4 + 3 + + + minlen + Minimum number of characters in password + 10 + 12 + 14 + 15 + 17 + 18 + 20 + 6 + 7 + 8 + 15 + + + ocredit + Minimum number of other (special characters) in +password + 0 + -1 + -2 + -1 + + + retry + Number of retry attempts before erroring out + 1 + 2 + 3 + 4 + 5 + 3 + + + ucredit + Minimum number of upper case in password + 0 + -1 + -2 + -1 + + + Ensure PAM Enforces Password Requirements - Minimum Digit Characters + The pam_pwquality module's dcredit parameter controls requirements for usage of digits in a password. When set to a negative number, any password will be required to contain that many digits. When set to a positive number, pam_pwquality will grant +1 additional length credit for each digit. Modify the dcredit setting in -/etc/security/pwquality.conf to require the use of a digit in passwords. - BP28(R18) - 1 - 12 - 15 - 16 - 5 - DSS05.04 - DSS05.05 - DSS05.07 - DSS05.10 - DSS06.03 - DSS06.10 - CCI-000194 - 4.3.3.2.2 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.2 - 4.3.3.7.4 - SR 1.1 - SR 1.10 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - 0421 - 0422 - 0431 - 0974 - 1173 - 1401 - 1504 - 1505 - 1546 - 1557 - 1558 - 1559 - 1560 - 1561 - A.18.1.4 - A.7.1.1 - A.9.2.1 - A.9.2.2 - A.9.2.3 - A.9.2.4 - A.9.2.6 - A.9.3.1 - A.9.4.2 - A.9.4.3 - IA-5(c) - IA-5(1)(a) - CM-6(a) - IA-5(4) - PR.AC-1 - PR.AC-6 - PR.AC-7 - FMT_SMF_EXT.1 - Req-8.2.3 - 8.3.6 - 8.3.9 - SRG-OS-000071-GPOS-00039 - Use of a complex password helps to increase the time and resources required +/etc/security/pwquality.conf to require the use of a digit in passwords. + 1 + 12 + 15 + 16 + 5 + DSS05.04 + DSS05.05 + DSS05.07 + DSS05.10 + DSS06.03 + DSS06.10 + CCI-004066 + 4.3.3.2.2 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.2 + 4.3.3.7.4 + SR 1.1 + SR 1.10 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + 0421 + 0422 + 0431 + 0974 + 1173 + 1401 + 1504 + 1505 + 1546 + 1557 + 1558 + 1559 + 1560 + 1561 + A.18.1.4 + A.7.1.1 + A.9.2.1 + A.9.2.2 + A.9.2.3 + A.9.2.4 + A.9.2.6 + A.9.3.1 + A.9.4.2 + A.9.4.3 + IA-5(c) + IA-5(1)(a) + CM-6(a) + IA-5(4) + PR.AC-1 + PR.AC-6 + PR.AC-7 + FMT_SMF_EXT.1 + Req-8.2.3 + SRG-OS-000071-GPOS-00039 + R31 + 8.3.6 + 8.3 + OL09-00-001020 + SV-271616r1091560_rule + Use of a complex password helps to increase the time and resources required to compromise the password. Password complexity, or strength, is a measure of the effectiveness of a password in resisting attempts at guessing and brute-force attacks. - + + Password complexity is one factor of several that determines how long it takes to crack a password. The more complex the password, the greater the number of possible combinations that need to be tested before the password is compromised. Requiring digits makes password guessing attacks more difficult by ensuring a larger -search space. - - # Remediation is applicable only in certain platforms +search space. + + # Remediation is applicable only in certain platforms if rpm --quiet -q pam; then -var_password_pam_dcredit='' +var_password_pam_dcredit='' @@ -23579,6 +27304,11 @@ if [ -e "/etc/pam.d/system-auth" ] ; then # If not already in use, a custom profile is created preserving the enabled features. if [[ ! $CURRENT_PROFILE == custom/* ]]; then ENABLED_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }') + # The "local" profile does not contain essential security features required by multiple Benchmarks. + # If currently used, it is replaced by "sssd", which is the best option in this case. + if [[ $CURRENT_PROFILE == local ]]; then + CURRENT_PROFILE="sssd" + fi authselect create-profile hardening -b $CURRENT_PROFILE CURRENT_PROFILE="custom/hardening" @@ -23596,8 +27326,8 @@ if [ -e "/etc/pam.d/system-auth" ] ; then authselect apply-changes -b fi -if grep -qP '^\s*password\s.*\bpam_pwquality.so\s.*\bdcredit\b' "$PAM_FILE_PATH"; then - sed -i -E --follow-symlinks 's/(.*password.*pam_pwquality.so.*)\bdcredit\b=?[[:alnum:]]*(.*)/\1\2/g' "$PAM_FILE_PATH" +if grep -qP "^\s*password\s.*\bpam_pwquality.so\s.*\bdcredit\b" "$PAM_FILE_PATH"; then + sed -i -E --follow-symlinks "s/(.*password.*pam_pwquality.so.*)\bdcredit\b=?[[:alnum:]]*(.*)/\1\2/g" "$PAM_FILE_PATH" fi if [ -f /usr/bin/authselect ]; then @@ -23608,6 +27338,8 @@ else fi + + # Strip any search characters in the key arg so that the key can be replaced without # adding any search characters to the config file. stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^dcredit") @@ -23631,18 +27363,19 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-001020 - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(1)(a) - NIST-800-53-IA-5(4) - NIST-800-53-IA-5(c) - PCI-DSS-Req-8.2.3 + - PCI-DSSv4-8.3 - PCI-DSSv4-8.3.6 - - PCI-DSSv4-8.3.9 - accounts_password_pam_dcredit - low_complexity - low_disruption @@ -23651,7 +27384,7 @@ fi - restrict_strategy - name: XCCDF Value var_password_pam_dcredit # promote to variable set_fact: - var_password_pam_dcredit: !!str + var_password_pam_dcredit: !!str tags: - always @@ -23662,13 +27395,14 @@ fi register: result_pam_file_present when: '"pam" in ansible_facts.packages' tags: + - DISA-STIG-OL09-00-001020 - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(1)(a) - NIST-800-53-IA-5(4) - NIST-800-53-IA-5(c) - PCI-DSS-Req-8.2.3 + - PCI-DSSv4-8.3 - PCI-DSSv4-8.3.6 - - PCI-DSSv4-8.3.9 - accounts_password_pam_dcredit - low_complexity - low_disruption @@ -23772,7 +27506,16 @@ fi }} when: - result_authselect_check_cmd is success - - authselect_current_profile is not match("custom/") + - authselect_current_profile is not match("^(custom/|local)") + - not result_authselect_custom_profile_present.stat.exists + + - name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters - + Create an authselect custom profile based on sssd profile + ansible.builtin.command: + cmd: authselect create-profile hardening -b sssd + when: + - result_authselect_check_cmd is success + - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists - name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters - @@ -23824,6 +27567,11 @@ fi when: - result_authselect_present.stat.exists + - name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters - Define + a fact for control already filtered in case filters are used + ansible.builtin.set_fact: + pam_module_control: '' + - name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters - Ensure the "dcredit" option from "pam_pwquality.so" is not present in {{ pam_file_path }} @@ -23844,13 +27592,14 @@ fi - '"pam" in ansible_facts.packages' - result_pam_file_present.stat.exists tags: + - DISA-STIG-OL09-00-001020 - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(1)(a) - NIST-800-53-IA-5(4) - NIST-800-53-IA-5(c) - PCI-DSS-Req-8.2.3 + - PCI-DSSv4-8.3 - PCI-DSSv4-8.3.6 - - PCI-DSSv4-8.3.9 - accounts_password_pam_dcredit - low_complexity - low_disruption @@ -23867,52 +27616,58 @@ fi line: dcredit = {{ var_password_pam_dcredit }} when: '"pam" in ansible_facts.packages' tags: + - DISA-STIG-OL09-00-001020 - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(1)(a) - NIST-800-53-IA-5(4) - NIST-800-53-IA-5(c) - PCI-DSS-Req-8.2.3 + - PCI-DSSv4-8.3 - PCI-DSSv4-8.3.6 - - PCI-DSSv4-8.3.9 - accounts_password_pam_dcredit - low_complexity - low_disruption - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - - Ensure PAM Enforces Password Requirements - Prevent the Use of Dictionary Words - The pam_pwquality module's dictcheck check if passwords contains dictionary words. When -dictcheck is set to 1 passwords will be checked for dictionary words. - CCI-000366 - IA-5(c) - IA-5(1)(a) - CM-6(a) - IA-5(4) - SRG-OS-000480-GPOS-00225 - Use of a complex password helps to increase the time and resources required to compromise the password. + + + + + + + + + + + Ensure PAM Enforces Password Requirements - Prevent the Use of Dictionary Words + The pam_pwquality module's dictcheck check if passwords contains dictionary words. When +dictcheck is set to 1 passwords will be checked for dictionary words. + CCI-000366 + IA-5(c) + IA-5(1)(a) + CM-6(a) + IA-5(4) + SRG-OS-000480-GPOS-00225 + SRG-OS-000072-GPOS-00040 + OL09-00-001125 + SV-271637r1091623_rule + Use of a complex password helps to increase the time and resources required to compromise the password. Password complexity, or strength, is a measure of the effectiveness of a password in resisting attempts at guessing and brute-force attacks. - + + Password complexity is one factor of several that determines how long it takes to crack a password. The more complex the password, the greater the number of possible combinations that need to be tested before the password is compromised. - -Passwords with dictionary words may be more vulnerable to password-guessing attacks. - - # Remediation is applicable only in certain platforms + + +Passwords with dictionary words may be more vulnerable to password-guessing attacks. + + # Remediation is applicable only in certain platforms if rpm --quiet -q pam; then -var_password_pam_dictcheck='' +var_password_pam_dictcheck='' @@ -23935,6 +27690,11 @@ if [ -e "/etc/pam.d/system-auth" ] ; then # If not already in use, a custom profile is created preserving the enabled features. if [[ ! $CURRENT_PROFILE == custom/* ]]; then ENABLED_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }') + # The "local" profile does not contain essential security features required by multiple Benchmarks. + # If currently used, it is replaced by "sssd", which is the best option in this case. + if [[ $CURRENT_PROFILE == local ]]; then + CURRENT_PROFILE="sssd" + fi authselect create-profile hardening -b $CURRENT_PROFILE CURRENT_PROFILE="custom/hardening" @@ -23952,8 +27712,8 @@ if [ -e "/etc/pam.d/system-auth" ] ; then authselect apply-changes -b fi -if grep -qP '^\s*password\s.*\bpam_pwquality.so\s.*\bdictcheck\b' "$PAM_FILE_PATH"; then - sed -i -E --follow-symlinks 's/(.*password.*pam_pwquality.so.*)\bdictcheck\b=?[[:alnum:]]*(.*)/\1\2/g' "$PAM_FILE_PATH" +if grep -qP "^\s*password\s.*\bpam_pwquality.so\s.*\bdictcheck\b" "$PAM_FILE_PATH"; then + sed -i -E --follow-symlinks "s/(.*password.*pam_pwquality.so.*)\bdictcheck\b=?[[:alnum:]]*(.*)/\1\2/g" "$PAM_FILE_PATH" fi if [ -f /usr/bin/authselect ]; then @@ -23964,6 +27724,8 @@ else fi + + # Strip any search characters in the key arg so that the key can be replaced without # adding any search characters to the config file. stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^dictcheck") @@ -23987,11 +27749,12 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-001125 - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(1)(a) - NIST-800-53-IA-5(4) @@ -24004,7 +27767,7 @@ fi - restrict_strategy - name: XCCDF Value var_password_pam_dictcheck # promote to variable set_fact: - var_password_pam_dictcheck: !!str + var_password_pam_dictcheck: !!str tags: - always @@ -24015,6 +27778,7 @@ fi register: result_pam_file_present when: '"pam" in ansible_facts.packages' tags: + - DISA-STIG-OL09-00-001125 - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(1)(a) - NIST-800-53-IA-5(4) @@ -24123,7 +27887,16 @@ fi }} when: - result_authselect_check_cmd is success - - authselect_current_profile is not match("custom/") + - authselect_current_profile is not match("^(custom/|local)") + - not result_authselect_custom_profile_present.stat.exists + + - name: Ensure PAM Enforces Password Requirements - Prevent the Use of Dictionary + Words - Create an authselect custom profile based on sssd profile + ansible.builtin.command: + cmd: authselect create-profile hardening -b sssd + when: + - result_authselect_check_cmd is success + - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists - name: Ensure PAM Enforces Password Requirements - Prevent the Use of Dictionary @@ -24176,6 +27949,11 @@ fi when: - result_authselect_present.stat.exists + - name: Ensure PAM Enforces Password Requirements - Prevent the Use of Dictionary + Words - Define a fact for control already filtered in case filters are used + ansible.builtin.set_fact: + pam_module_control: '' + - name: Ensure PAM Enforces Password Requirements - Prevent the Use of Dictionary Words - Ensure the "dictcheck" option from "pam_pwquality.so" is not present in {{ pam_file_path }} @@ -24196,6 +27974,7 @@ fi - '"pam" in ansible_facts.packages' - result_pam_file_present.stat.exists tags: + - DISA-STIG-OL09-00-001125 - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(1)(a) - NIST-800-53-IA-5(4) @@ -24216,6 +27995,7 @@ fi line: dictcheck = {{ var_password_pam_dictcheck }} when: '"pam" in ansible_facts.packages' tags: + - DISA-STIG-OL09-00-001125 - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(1)(a) - NIST-800-53-IA-5(4) @@ -24226,96 +28006,101 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - - Ensure PAM Enforces Password Requirements - Minimum Different Characters - The pam_pwquality module's difok parameter sets the number of characters + + + + + + + + + + + Ensure PAM Enforces Password Requirements - Minimum Different Characters + The pam_pwquality module's difok parameter sets the number of characters in a password that must not be present in and old password during a password change. - + + Modify the difok setting in /etc/security/pwquality.conf -to equal to require differing characters -when changing passwords. - 1 - 12 - 15 - 16 - 5 - 5.6.2.1.1 - DSS05.04 - DSS05.05 - DSS05.07 - DSS05.10 - DSS06.03 - DSS06.10 - CCI-000195 - 4.3.3.2.2 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.2 - 4.3.3.7.4 - SR 1.1 - SR 1.10 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - A.18.1.4 - A.7.1.1 - A.9.2.1 - A.9.2.2 - A.9.2.3 - A.9.2.4 - A.9.2.6 - A.9.3.1 - A.9.4.2 - A.9.4.3 - IA-5(c) - IA-5(1)(b) - CM-6(a) - IA-5(4) - PR.AC-1 - PR.AC-6 - PR.AC-7 - SRG-OS-000072-GPOS-00040 - Use of a complex password helps to increase the time and resources +to equal to require differing characters +when changing passwords. + 1 + 12 + 15 + 16 + 5 + 5.6.2.1.1 + DSS05.04 + DSS05.05 + DSS05.07 + DSS05.10 + DSS06.03 + DSS06.10 + CCI-004066 + 4.3.3.2.2 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.2 + 4.3.3.7.4 + SR 1.1 + SR 1.10 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + A.18.1.4 + A.7.1.1 + A.9.2.1 + A.9.2.2 + A.9.2.3 + A.9.2.4 + A.9.2.6 + A.9.3.1 + A.9.4.2 + A.9.4.3 + IA-5(c) + IA-5(1)(b) + CM-6(a) + IA-5(4) + PR.AC-1 + PR.AC-6 + PR.AC-7 + SRG-OS-000072-GPOS-00040 + OL09-00-001025 + SV-271617r1091563_rule + Use of a complex password helps to increase the time and resources required to compromise the password. Password complexity, or strength, is a measure of the effectiveness of a password in resisting attempts at guessing and brute–force attacks. - + + Password complexity is one factor of several that determines how long it takes to crack a password. The more complex the password, the greater the number of possible combinations that need to be tested before the password is compromised. - + + Requiring a minimum number of different characters during password changes ensures that newly changed passwords should not resemble previously compromised ones. -Note that passwords which are changed on compromised systems will still be compromised, however. - - # Remediation is applicable only in certain platforms +Note that passwords which are changed on compromised systems will still be compromised, however. + + # Remediation is applicable only in certain platforms if rpm --quiet -q pam; then -var_password_pam_difok='' +var_password_pam_difok='' @@ -24338,6 +28123,11 @@ if [ -e "/etc/pam.d/system-auth" ] ; then # If not already in use, a custom profile is created preserving the enabled features. if [[ ! $CURRENT_PROFILE == custom/* ]]; then ENABLED_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }') + # The "local" profile does not contain essential security features required by multiple Benchmarks. + # If currently used, it is replaced by "sssd", which is the best option in this case. + if [[ $CURRENT_PROFILE == local ]]; then + CURRENT_PROFILE="sssd" + fi authselect create-profile hardening -b $CURRENT_PROFILE CURRENT_PROFILE="custom/hardening" @@ -24355,8 +28145,8 @@ if [ -e "/etc/pam.d/system-auth" ] ; then authselect apply-changes -b fi -if grep -qP '^\s*password\s.*\bpam_pwquality.so\s.*\bdifok\b' "$PAM_FILE_PATH"; then - sed -i -E --follow-symlinks 's/(.*password.*pam_pwquality.so.*)\bdifok\b=?[[:alnum:]]*(.*)/\1\2/g' "$PAM_FILE_PATH" +if grep -qP "^\s*password\s.*\bpam_pwquality.so\s.*\bdifok\b" "$PAM_FILE_PATH"; then + sed -i -E --follow-symlinks "s/(.*password.*pam_pwquality.so.*)\bdifok\b=?[[:alnum:]]*(.*)/\1\2/g" "$PAM_FILE_PATH" fi if [ -f /usr/bin/authselect ]; then @@ -24367,6 +28157,8 @@ else fi + + # Strip any search characters in the key arg so that the key can be replaced without # adding any search characters to the config file. stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^difok") @@ -24390,12 +28182,13 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: - CJIS-5.6.2.1.1 + - DISA-STIG-OL09-00-001025 - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(1)(b) - NIST-800-53-IA-5(4) @@ -24408,7 +28201,7 @@ fi - restrict_strategy - name: XCCDF Value var_password_pam_difok # promote to variable set_fact: - var_password_pam_difok: !!str + var_password_pam_difok: !!str tags: - always @@ -24420,6 +28213,7 @@ fi when: '"pam" in ansible_facts.packages' tags: - CJIS-5.6.2.1.1 + - DISA-STIG-OL09-00-001025 - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(1)(b) - NIST-800-53-IA-5(4) @@ -24527,7 +28321,16 @@ fi }} when: - result_authselect_check_cmd is success - - authselect_current_profile is not match("custom/") + - authselect_current_profile is not match("^(custom/|local)") + - not result_authselect_custom_profile_present.stat.exists + + - name: Ensure PAM Enforces Password Requirements - Minimum Different Characters + - Create an authselect custom profile based on sssd profile + ansible.builtin.command: + cmd: authselect create-profile hardening -b sssd + when: + - result_authselect_check_cmd is success + - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists - name: Ensure PAM Enforces Password Requirements - Minimum Different Characters @@ -24579,6 +28382,11 @@ fi when: - result_authselect_present.stat.exists + - name: Ensure PAM Enforces Password Requirements - Minimum Different Characters + - Define a fact for control already filtered in case filters are used + ansible.builtin.set_fact: + pam_module_control: '' + - name: Ensure PAM Enforces Password Requirements - Minimum Different Characters - Ensure the "difok" option from "pam_pwquality.so" is not present in {{ pam_file_path }} @@ -24600,6 +28408,7 @@ fi - result_pam_file_present.stat.exists tags: - CJIS-5.6.2.1.1 + - DISA-STIG-OL09-00-001025 - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(1)(b) - NIST-800-53-IA-5(4) @@ -24621,6 +28430,7 @@ fi when: '"pam" in ansible_facts.packages' tags: - CJIS-5.6.2.1.1 + - DISA-STIG-OL09-00-001025 - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(1)(b) - NIST-800-53-IA-5(4) @@ -24631,48 +28441,44 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - - Ensure PAM Enforces Password Requirements - Enforce for root User - The pam_pwquality module's enforce_for_root parameter controls requirements for + + + + + + + + + + + Ensure PAM Enforces Password Requirements - Enforce for root User + The pam_pwquality module's enforce_for_root parameter controls requirements for enforcing password complexity for the root user. Enable the enforce_for_root setting in /etc/security/pwquality.conf to require the root user -to use complex passwords. - CCI-000194 - CCI-000193 - CCI-001619 - CCI-000205 - CCI-000195 - CCI-000192 - CCI-000366 - IA-5(c) - IA-5(1)(a) - CM-6(a) - IA-5(4) - SRG-OS-000072-GPOS-00040 - SRG-OS-000071-GPOS-00039 - SRG-OS-000070-GPOS-00038 - SRG-OS-000266-GPOS-00101 - SRG-OS-000078-GPOS-00046 - SRG-OS-000480-GPOS-00225 - SRG-OS-000069-GPOS-00037 - Use of a complex password helps to increase the time and resources required to compromise +to use complex passwords. + CCI-004066 + IA-5(c) + IA-5(1)(a) + CM-6(a) + IA-5(4) + SRG-OS-000072-GPOS-00040 + SRG-OS-000071-GPOS-00039 + SRG-OS-000070-GPOS-00038 + SRG-OS-000266-GPOS-00101 + SRG-OS-000078-GPOS-00046 + SRG-OS-000480-GPOS-00225 + SRG-OS-000069-GPOS-00037 + OL09-00-001045 + SV-271621r1091575_rule + Use of a complex password helps to increase the time and resources required to compromise the password. Password complexity, or strength, is a measure of the effectiveness of a password in resisting attempts at guessing and brute-force attacks. Password complexity is one factor of several that determines how long it takes to crack a password. The more complex the password, the greater the number of possible combinations -that need to be tested before the password is compromised. - - # Remediation is applicable only in certain platforms +that need to be tested before the password is compromised. + + # Remediation is applicable only in certain platforms if rpm --quiet -q pam; then if [ -e "/etc/security/pwquality.conf" ] ; then @@ -24693,11 +28499,12 @@ rm "/etc/security/pwquality.conf.bak" else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-001045 - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(1)(a) - NIST-800-53-IA-5(4) @@ -24713,10 +28520,12 @@ fi lineinfile: path: /etc/security/pwquality.conf create: true + regexp: '' line: enforce_for_root state: present when: '"pam" in ansible_facts.packages' tags: + - DISA-STIG-OL09-00-001045 - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(1)(a) - NIST-800-53-IA-5(4) @@ -24727,109 +28536,111 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters - The pam_pwquality module's lcredit parameter controls requirements for + + + + + + + + + + Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters + The pam_pwquality module's lcredit parameter controls requirements for usage of lowercase letters in a password. When set to a negative number, any password will be required to contain that many lowercase characters. When set to a positive number, pam_pwquality will grant +1 additional length credit for each lowercase character. Modify the lcredit setting in -/etc/security/pwquality.conf to require the use of a lowercase character in passwords. - BP28(R18) - 1 - 12 - 15 - 16 - 5 - DSS05.04 - DSS05.05 - DSS05.07 - DSS05.10 - DSS06.03 - DSS06.10 - CCI-000193 - 4.3.3.2.2 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.2 - 4.3.3.7.4 - SR 1.1 - SR 1.10 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - 0421 - 0422 - 0431 - 0974 - 1173 - 1401 - 1504 - 1505 - 1546 - 1557 - 1558 - 1559 - 1560 - 1561 - A.18.1.4 - A.7.1.1 - A.9.2.1 - A.9.2.2 - A.9.2.3 - A.9.2.4 - A.9.2.6 - A.9.3.1 - A.9.4.2 - A.9.4.3 - IA-5(c) - IA-5(1)(a) - CM-6(a) - IA-5(4) - PR.AC-1 - PR.AC-6 - PR.AC-7 - FMT_SMF_EXT.1 - Req-8.2.3 - 8.3.6 - 8.3.9 - SRG-OS-000070-GPOS-00038 - Use of a complex password helps to increase the time and resources required +/etc/security/pwquality.conf to require the use of a lowercase character in passwords. + 1 + 12 + 15 + 16 + 5 + DSS05.04 + DSS05.05 + DSS05.07 + DSS05.10 + DSS06.03 + DSS06.10 + CCI-004066 + 4.3.3.2.2 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.2 + 4.3.3.7.4 + SR 1.1 + SR 1.10 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + 0421 + 0422 + 0431 + 0974 + 1173 + 1401 + 1504 + 1505 + 1546 + 1557 + 1558 + 1559 + 1560 + 1561 + A.18.1.4 + A.7.1.1 + A.9.2.1 + A.9.2.2 + A.9.2.3 + A.9.2.4 + A.9.2.6 + A.9.3.1 + A.9.4.2 + A.9.4.3 + IA-5(c) + IA-5(1)(a) + CM-6(a) + IA-5(4) + PR.AC-1 + PR.AC-6 + PR.AC-7 + FMT_SMF_EXT.1 + Req-8.2.3 + SRG-OS-000070-GPOS-00038 + R31 + 8.3.6 + 8.3 + OL09-00-001015 + SV-271615r1091557_rule + Use of a complex password helps to increase the time and resources required to compromise the password. Password complexity, or strength, is a measure of the effectiveness of a password in resisting attempts at guessing and brute-force attacks. - + Password complexity is one factor of several that determines how long it takes to crack a password. The more complex the password, the greater the number of possble combinations that need to be tested before the password is compromised. Requiring a minimum number of lowercase characters makes password guessing attacks -more difficult by ensuring a larger search space. - - # Remediation is applicable only in certain platforms +more difficult by ensuring a larger search space. + + # Remediation is applicable only in certain platforms if rpm --quiet -q pam; then -var_password_pam_lcredit='' +var_password_pam_lcredit='' @@ -24852,6 +28663,11 @@ if [ -e "/etc/pam.d/system-auth" ] ; then # If not already in use, a custom profile is created preserving the enabled features. if [[ ! $CURRENT_PROFILE == custom/* ]]; then ENABLED_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }') + # The "local" profile does not contain essential security features required by multiple Benchmarks. + # If currently used, it is replaced by "sssd", which is the best option in this case. + if [[ $CURRENT_PROFILE == local ]]; then + CURRENT_PROFILE="sssd" + fi authselect create-profile hardening -b $CURRENT_PROFILE CURRENT_PROFILE="custom/hardening" @@ -24869,8 +28685,8 @@ if [ -e "/etc/pam.d/system-auth" ] ; then authselect apply-changes -b fi -if grep -qP '^\s*password\s.*\bpam_pwquality.so\s.*\blcredit\b' "$PAM_FILE_PATH"; then - sed -i -E --follow-symlinks 's/(.*password.*pam_pwquality.so.*)\blcredit\b=?[[:alnum:]]*(.*)/\1\2/g' "$PAM_FILE_PATH" +if grep -qP "^\s*password\s.*\bpam_pwquality.so\s.*\blcredit\b" "$PAM_FILE_PATH"; then + sed -i -E --follow-symlinks "s/(.*password.*pam_pwquality.so.*)\blcredit\b=?[[:alnum:]]*(.*)/\1\2/g" "$PAM_FILE_PATH" fi if [ -f /usr/bin/authselect ]; then @@ -24881,6 +28697,8 @@ else fi + + # Strip any search characters in the key arg so that the key can be replaced without # adding any search characters to the config file. stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^lcredit") @@ -24904,18 +28722,19 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-001015 - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(1)(a) - NIST-800-53-IA-5(4) - NIST-800-53-IA-5(c) - PCI-DSS-Req-8.2.3 + - PCI-DSSv4-8.3 - PCI-DSSv4-8.3.6 - - PCI-DSSv4-8.3.9 - accounts_password_pam_lcredit - low_complexity - low_disruption @@ -24924,7 +28743,7 @@ fi - restrict_strategy - name: XCCDF Value var_password_pam_lcredit # promote to variable set_fact: - var_password_pam_lcredit: !!str + var_password_pam_lcredit: !!str tags: - always @@ -24935,13 +28754,14 @@ fi register: result_pam_file_present when: '"pam" in ansible_facts.packages' tags: + - DISA-STIG-OL09-00-001015 - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(1)(a) - NIST-800-53-IA-5(4) - NIST-800-53-IA-5(c) - PCI-DSS-Req-8.2.3 + - PCI-DSSv4-8.3 - PCI-DSSv4-8.3.6 - - PCI-DSSv4-8.3.9 - accounts_password_pam_lcredit - low_complexity - low_disruption @@ -25045,7 +28865,16 @@ fi }} when: - result_authselect_check_cmd is success - - authselect_current_profile is not match("custom/") + - authselect_current_profile is not match("^(custom/|local)") + - not result_authselect_custom_profile_present.stat.exists + + - name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters + - Create an authselect custom profile based on sssd profile + ansible.builtin.command: + cmd: authselect create-profile hardening -b sssd + when: + - result_authselect_check_cmd is success + - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists - name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters @@ -25097,6 +28926,11 @@ fi when: - result_authselect_present.stat.exists + - name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters + - Define a fact for control already filtered in case filters are used + ansible.builtin.set_fact: + pam_module_control: '' + - name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters - Ensure the "lcredit" option from "pam_pwquality.so" is not present in {{ pam_file_path }} @@ -25117,13 +28951,14 @@ fi - '"pam" in ansible_facts.packages' - result_pam_file_present.stat.exists tags: + - DISA-STIG-OL09-00-001015 - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(1)(a) - NIST-800-53-IA-5(4) - NIST-800-53-IA-5(c) - PCI-DSS-Req-8.2.3 + - PCI-DSSv4-8.3 - PCI-DSSv4-8.3.6 - - PCI-DSSv4-8.3.9 - accounts_password_pam_lcredit - low_complexity - low_disruption @@ -25140,101 +28975,105 @@ fi line: lcredit = {{ var_password_pam_lcredit }} when: '"pam" in ansible_facts.packages' tags: + - DISA-STIG-OL09-00-001015 - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(1)(a) - NIST-800-53-IA-5(4) - NIST-800-53-IA-5(c) - PCI-DSS-Req-8.2.3 + - PCI-DSSv4-8.3 - PCI-DSSv4-8.3.6 - - PCI-DSSv4-8.3.9 - accounts_password_pam_lcredit - low_complexity - low_disruption - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - - Ensure PAM Enforces Password Requirements - Maximum Consecutive Repeating Characters from Same Character Class - The pam_pwquality module's maxclassrepeat parameter controls requirements for + + + + + + + + + + + Ensure PAM Enforces Password Requirements - Maximum Consecutive Repeating Characters from Same Character Class + The pam_pwquality module's maxclassrepeat parameter controls requirements for consecutive repeating characters from the same character class. When set to a positive number, it will reject passwords which contain more than that number of consecutive characters from the same character class. Modify the -maxclassrepeat setting in /etc/security/pwquality.conf to equal -to prevent a run of ( + 1) or more identical characters. - 1 - 12 - 15 - 16 - 5 - DSS05.04 - DSS05.05 - DSS05.07 - DSS05.10 - DSS06.03 - DSS06.10 - CCI-000195 - 4.3.3.2.2 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.2 - 4.3.3.7.4 - SR 1.1 - SR 1.10 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - A.18.1.4 - A.7.1.1 - A.9.2.1 - A.9.2.2 - A.9.2.3 - A.9.2.4 - A.9.2.6 - A.9.3.1 - A.9.4.2 - A.9.4.3 - IA-5(c) - IA-5(1)(a) - CM-6(a) - IA-5(4) - PR.AC-1 - PR.AC-6 - PR.AC-7 - SRG-OS-000072-GPOS-00040 - Use of a complex password helps to increase the time and resources required to compromise the password. +maxclassrepeat setting in /etc/security/pwquality.conf to equal +to prevent a run of ( + 1) or more identical characters. + 1 + 12 + 15 + 16 + 5 + DSS05.04 + DSS05.05 + DSS05.07 + DSS05.10 + DSS06.03 + DSS06.10 + CCI-004066 + 4.3.3.2.2 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.2 + 4.3.3.7.4 + SR 1.1 + SR 1.10 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + A.18.1.4 + A.7.1.1 + A.9.2.1 + A.9.2.2 + A.9.2.3 + A.9.2.4 + A.9.2.6 + A.9.3.1 + A.9.4.2 + A.9.4.3 + IA-5(c) + IA-5(1)(a) + CM-6(a) + IA-5(4) + PR.AC-1 + PR.AC-6 + PR.AC-7 + SRG-OS-000072-GPOS-00040 + SRG-OS-000730-GPOS-00190 + OL09-00-001030 + SV-271618r1091566_rule + Use of a complex password helps to increase the time and resources required to compromise the password. Password complexity, or strength, is a measure of the effectiveness of a password in resisting attempts at guessing and brute-force attacks. - + Password complexity is one factor of several that determines how long it takes to crack a password. The more complex a password, the greater the number of possible combinations that need to be tested before the -password is compromised. - - # Remediation is applicable only in certain platforms +password is compromised. + + # Remediation is applicable only in certain platforms if rpm --quiet -q pam; then -var_password_pam_maxclassrepeat='' +var_password_pam_maxclassrepeat='' @@ -25257,6 +29096,11 @@ if [ -e "/etc/pam.d/system-auth" ] ; then # If not already in use, a custom profile is created preserving the enabled features. if [[ ! $CURRENT_PROFILE == custom/* ]]; then ENABLED_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }') + # The "local" profile does not contain essential security features required by multiple Benchmarks. + # If currently used, it is replaced by "sssd", which is the best option in this case. + if [[ $CURRENT_PROFILE == local ]]; then + CURRENT_PROFILE="sssd" + fi authselect create-profile hardening -b $CURRENT_PROFILE CURRENT_PROFILE="custom/hardening" @@ -25274,8 +29118,8 @@ if [ -e "/etc/pam.d/system-auth" ] ; then authselect apply-changes -b fi -if grep -qP '^\s*password\s.*\bpam_pwquality.so\s.*\bmaxclassrepeat\b' "$PAM_FILE_PATH"; then - sed -i -E --follow-symlinks 's/(.*password.*pam_pwquality.so.*)\bmaxclassrepeat\b=?[[:alnum:]]*(.*)/\1\2/g' "$PAM_FILE_PATH" +if grep -qP "^\s*password\s.*\bpam_pwquality.so\s.*\bmaxclassrepeat\b" "$PAM_FILE_PATH"; then + sed -i -E --follow-symlinks "s/(.*password.*pam_pwquality.so.*)\bmaxclassrepeat\b=?[[:alnum:]]*(.*)/\1\2/g" "$PAM_FILE_PATH" fi if [ -f /usr/bin/authselect ]; then @@ -25286,6 +29130,8 @@ else fi + + # Strip any search characters in the key arg so that the key can be replaced without # adding any search characters to the config file. stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^maxclassrepeat") @@ -25309,11 +29155,12 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-001030 - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(1)(a) - NIST-800-53-IA-5(4) @@ -25326,7 +29173,7 @@ fi - restrict_strategy - name: XCCDF Value var_password_pam_maxclassrepeat # promote to variable set_fact: - var_password_pam_maxclassrepeat: !!str + var_password_pam_maxclassrepeat: !!str tags: - always @@ -25338,6 +29185,7 @@ fi register: result_pam_file_present when: '"pam" in ansible_facts.packages' tags: + - DISA-STIG-OL09-00-001030 - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(1)(a) - NIST-800-53-IA-5(4) @@ -25455,7 +29303,17 @@ fi }} when: - result_authselect_check_cmd is success - - authselect_current_profile is not match("custom/") + - authselect_current_profile is not match("^(custom/|local)") + - not result_authselect_custom_profile_present.stat.exists + + - name: Ensure PAM Enforces Password Requirements - Maximum Consecutive Repeating + Characters from Same Character Class - Create an authselect custom profile + based on sssd profile + ansible.builtin.command: + cmd: authselect create-profile hardening -b sssd + when: + - result_authselect_check_cmd is success + - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists - name: Ensure PAM Enforces Password Requirements - Maximum Consecutive Repeating @@ -25510,6 +29368,12 @@ fi when: - result_authselect_present.stat.exists + - name: Ensure PAM Enforces Password Requirements - Maximum Consecutive Repeating + Characters from Same Character Class - Define a fact for control already filtered + in case filters are used + ansible.builtin.set_fact: + pam_module_control: '' + - name: Ensure PAM Enforces Password Requirements - Maximum Consecutive Repeating Characters from Same Character Class - Ensure the "maxclassrepeat" option from "pam_pwquality.so" is not present in {{ pam_file_path }} @@ -25530,6 +29394,7 @@ fi - '"pam" in ansible_facts.packages' - result_pam_file_present.stat.exists tags: + - DISA-STIG-OL09-00-001030 - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(1)(a) - NIST-800-53-IA-5(4) @@ -25551,6 +29416,7 @@ fi line: maxclassrepeat = {{ var_password_pam_maxclassrepeat }} when: '"pam" in ansible_facts.packages' tags: + - DISA-STIG-OL09-00-001030 - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(1)(a) - NIST-800-53-IA-5(4) @@ -25561,89 +29427,93 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - - Set Password Maximum Consecutive Repeating Characters - The pam_pwquality module's maxrepeat parameter controls requirements for + + + + + + + + + + + Set Password Maximum Consecutive Repeating Characters + The pam_pwquality module's maxrepeat parameter controls requirements for consecutive repeating characters. When set to a positive number, it will reject passwords which contain more than that number of consecutive characters. Modify the maxrepeat setting -in /etc/security/pwquality.conf to equal to prevent a -run of ( + 1) or more identical characters. - 1 - 12 - 15 - 16 - 5 - DSS05.04 - DSS05.05 - DSS05.07 - DSS05.10 - DSS06.03 - DSS06.10 - CCI-000195 - 4.3.3.2.2 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.2 - 4.3.3.7.4 - SR 1.1 - SR 1.10 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - A.18.1.4 - A.7.1.1 - A.9.2.1 - A.9.2.2 - A.9.2.3 - A.9.2.4 - A.9.2.6 - A.9.3.1 - A.9.4.2 - A.9.4.3 - IA-5(c) - CM-6(a) - IA-5(4) - PR.AC-1 - PR.AC-6 - PR.AC-7 - SRG-OS-000072-GPOS-00040 - Use of a complex password helps to increase the time and resources required to compromise the password. +in /etc/security/pwquality.conf to equal to prevent a +run of ( + 1) or more identical characters. + 1 + 12 + 15 + 16 + 5 + DSS05.04 + DSS05.05 + DSS05.07 + DSS05.10 + DSS06.03 + DSS06.10 + CCI-004066 + 4.3.3.2.2 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.2 + 4.3.3.7.4 + SR 1.1 + SR 1.10 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + A.18.1.4 + A.7.1.1 + A.9.2.1 + A.9.2.2 + A.9.2.3 + A.9.2.4 + A.9.2.6 + A.9.3.1 + A.9.4.2 + A.9.4.3 + IA-5(c) + CM-6(a) + IA-5(4) + PR.AC-1 + PR.AC-6 + PR.AC-7 + SRG-OS-000072-GPOS-00040 + OL09-00-001035 + SV-271619r1091569_rule + Use of a complex password helps to increase the time and resources required to compromise the password. Password complexity, or strength, is a measure of the effectiveness of a password in resisting attempts at guessing and brute-force attacks. - + + Password complexity is one factor of several that determines how long it takes to crack a password. The more complex the password, the greater the number of possible combinations that need to be tested before the password is compromised. - -Passwords with excessive repeating characters may be more vulnerable to password-guessing attacks. - - # Remediation is applicable only in certain platforms + + +Passwords with excessive repeating characters may be more vulnerable to password-guessing attacks. + + # Remediation is applicable only in certain platforms if rpm --quiet -q pam; then -var_password_pam_maxrepeat='' +var_password_pam_maxrepeat='' @@ -25666,6 +29536,11 @@ if [ -e "/etc/pam.d/system-auth" ] ; then # If not already in use, a custom profile is created preserving the enabled features. if [[ ! $CURRENT_PROFILE == custom/* ]]; then ENABLED_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }') + # The "local" profile does not contain essential security features required by multiple Benchmarks. + # If currently used, it is replaced by "sssd", which is the best option in this case. + if [[ $CURRENT_PROFILE == local ]]; then + CURRENT_PROFILE="sssd" + fi authselect create-profile hardening -b $CURRENT_PROFILE CURRENT_PROFILE="custom/hardening" @@ -25683,8 +29558,8 @@ if [ -e "/etc/pam.d/system-auth" ] ; then authselect apply-changes -b fi -if grep -qP '^\s*password\s.*\bpam_pwquality.so\s.*\bmaxrepeat\b' "$PAM_FILE_PATH"; then - sed -i -E --follow-symlinks 's/(.*password.*pam_pwquality.so.*)\bmaxrepeat\b=?[[:alnum:]]*(.*)/\1\2/g' "$PAM_FILE_PATH" +if grep -qP "^\s*password\s.*\bpam_pwquality.so\s.*\bmaxrepeat\b" "$PAM_FILE_PATH"; then + sed -i -E --follow-symlinks "s/(.*password.*pam_pwquality.so.*)\bmaxrepeat\b=?[[:alnum:]]*(.*)/\1\2/g" "$PAM_FILE_PATH" fi if [ -f /usr/bin/authselect ]; then @@ -25695,6 +29570,8 @@ else fi + + # Strip any search characters in the key arg so that the key can be replaced without # adding any search characters to the config file. stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^maxrepeat") @@ -25718,11 +29595,12 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-001035 - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(4) - NIST-800-53-IA-5(c) @@ -25734,7 +29612,7 @@ fi - restrict_strategy - name: XCCDF Value var_password_pam_maxrepeat # promote to variable set_fact: - var_password_pam_maxrepeat: !!str + var_password_pam_maxrepeat: !!str tags: - always @@ -25745,6 +29623,7 @@ fi register: result_pam_file_present when: '"pam" in ansible_facts.packages' tags: + - DISA-STIG-OL09-00-001035 - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(4) - NIST-800-53-IA-5(c) @@ -25851,7 +29730,16 @@ fi }} when: - result_authselect_check_cmd is success - - authselect_current_profile is not match("custom/") + - authselect_current_profile is not match("^(custom/|local)") + - not result_authselect_custom_profile_present.stat.exists + + - name: Set Password Maximum Consecutive Repeating Characters - Create an authselect + custom profile based on sssd profile + ansible.builtin.command: + cmd: authselect create-profile hardening -b sssd + when: + - result_authselect_check_cmd is success + - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists - name: Set Password Maximum Consecutive Repeating Characters - Ensure authselect @@ -25903,6 +29791,11 @@ fi when: - result_authselect_present.stat.exists + - name: Set Password Maximum Consecutive Repeating Characters - Define a fact for + control already filtered in case filters are used + ansible.builtin.set_fact: + pam_module_control: '' + - name: Set Password Maximum Consecutive Repeating Characters - Ensure the "maxrepeat" option from "pam_pwquality.so" is not present in {{ pam_file_path }} ansible.builtin.replace: @@ -25922,6 +29815,7 @@ fi - '"pam" in ansible_facts.packages' - result_pam_file_present.stat.exists tags: + - DISA-STIG-OL09-00-001035 - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(4) - NIST-800-53-IA-5(c) @@ -25941,6 +29835,7 @@ fi line: maxrepeat = {{ var_password_pam_maxrepeat }} when: '"pam" in ansible_facts.packages' tags: + - DISA-STIG-OL09-00-001035 - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(4) - NIST-800-53-IA-5(c) @@ -25950,18 +29845,18 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - - Ensure PAM Enforces Password Requirements - Minimum Different Categories - The pam_pwquality module's minclass parameter controls + + + + + + + + + + + Ensure PAM Enforces Password Requirements - Minimum Different Categories + The pam_pwquality module's minclass parameter controls requirements for usage of different character classes, or types, of character that must exist in a password before it is considered valid. For example, setting this value to three (3) requires that any password must have characters @@ -25975,91 +29870,97 @@ categories available: * Special characters (for example, punctuation) Modify the minclass setting in /etc/security/pwquality.conf entry -to require -differing categories of characters when changing passwords. - 1 - 12 - 15 - 16 - 5 - DSS05.04 - DSS05.05 - DSS05.07 - DSS05.10 - DSS06.03 - DSS06.10 - CCI-000195 - 4.3.3.2.2 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.2 - 4.3.3.7.4 - SR 1.1 - SR 1.10 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - 0421 - 0422 - 0431 - 0974 - 1173 - 1401 - 1504 - 1505 - 1546 - 1557 - 1558 - 1559 - 1560 - 1561 - A.18.1.4 - A.7.1.1 - A.9.2.1 - A.9.2.2 - A.9.2.3 - A.9.2.4 - A.9.2.6 - A.9.3.1 - A.9.4.2 - A.9.4.3 - IA-5(c) - IA-5(1)(a) - CM-6(a) - IA-5(4) - PR.AC-1 - PR.AC-6 - PR.AC-7 - SRG-OS-000072-GPOS-00040 - Use of a complex password helps to increase the time and resources required to compromise the password. +to require +differing categories of characters when changing passwords. + 1 + 12 + 15 + 16 + 5 + DSS05.04 + DSS05.05 + DSS05.07 + DSS05.10 + DSS06.03 + DSS06.10 + CCI-004066 + 4.3.3.2.2 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.2 + 4.3.3.7.4 + SR 1.1 + SR 1.10 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + 0421 + 0422 + 0431 + 0974 + 1173 + 1401 + 1504 + 1505 + 1546 + 1557 + 1558 + 1559 + 1560 + 1561 + A.18.1.4 + A.7.1.1 + A.9.2.1 + A.9.2.2 + A.9.2.3 + A.9.2.4 + A.9.2.6 + A.9.3.1 + A.9.4.2 + A.9.4.3 + IA-5(c) + IA-5(1)(a) + CM-6(a) + IA-5(4) + PR.AC-1 + PR.AC-6 + PR.AC-7 + SRG-OS-000072-GPOS-00040 + R68 + A.11.SEC-OL3 + OL09-00-001040 + SV-271620r1091572_rule + Use of a complex password helps to increase the time and resources required to compromise the password. Password complexity, or strength, is a measure of the effectiveness of a password in resisting attempts at guessing and brute-force attacks. - + + Password complexity is one factor of several that determines how long it takes to crack a password. The more complex the password, the greater the number of possible combinations that need to be tested before the password is compromised. - + + Requiring a minimum number of character categories makes password guessing attacks more difficult -by ensuring a larger search space. - - # Remediation is applicable only in certain platforms +by ensuring a larger search space. + + # Remediation is applicable only in certain platforms if rpm --quiet -q pam; then -var_password_pam_minclass='' +var_password_pam_minclass='' @@ -26082,6 +29983,11 @@ if [ -e "/etc/pam.d/system-auth" ] ; then # If not already in use, a custom profile is created preserving the enabled features. if [[ ! $CURRENT_PROFILE == custom/* ]]; then ENABLED_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }') + # The "local" profile does not contain essential security features required by multiple Benchmarks. + # If currently used, it is replaced by "sssd", which is the best option in this case. + if [[ $CURRENT_PROFILE == local ]]; then + CURRENT_PROFILE="sssd" + fi authselect create-profile hardening -b $CURRENT_PROFILE CURRENT_PROFILE="custom/hardening" @@ -26099,8 +30005,8 @@ if [ -e "/etc/pam.d/system-auth" ] ; then authselect apply-changes -b fi -if grep -qP '^\s*password\s.*\bpam_pwquality.so\s.*\bminclass\b' "$PAM_FILE_PATH"; then - sed -i -E --follow-symlinks 's/(.*password.*pam_pwquality.so.*)\bminclass\b=?[[:alnum:]]*(.*)/\1\2/g' "$PAM_FILE_PATH" +if grep -qP "^\s*password\s.*\bpam_pwquality.so\s.*\bminclass\b" "$PAM_FILE_PATH"; then + sed -i -E --follow-symlinks "s/(.*password.*pam_pwquality.so.*)\bminclass\b=?[[:alnum:]]*(.*)/\1\2/g" "$PAM_FILE_PATH" fi if [ -f /usr/bin/authselect ]; then @@ -26111,6 +30017,8 @@ else fi + + # Strip any search characters in the key arg so that the key can be replaced without # adding any search characters to the config file. stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^minclass") @@ -26134,11 +30042,12 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-001040 - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(1)(a) - NIST-800-53-IA-5(4) @@ -26151,7 +30060,7 @@ fi - restrict_strategy - name: XCCDF Value var_password_pam_minclass # promote to variable set_fact: - var_password_pam_minclass: !!str + var_password_pam_minclass: !!str tags: - always @@ -26162,6 +30071,7 @@ fi register: result_pam_file_present when: '"pam" in ansible_facts.packages' tags: + - DISA-STIG-OL09-00-001040 - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(1)(a) - NIST-800-53-IA-5(4) @@ -26269,7 +30179,16 @@ fi }} when: - result_authselect_check_cmd is success - - authselect_current_profile is not match("custom/") + - authselect_current_profile is not match("^(custom/|local)") + - not result_authselect_custom_profile_present.stat.exists + + - name: Ensure PAM Enforces Password Requirements - Minimum Different Categories + - Create an authselect custom profile based on sssd profile + ansible.builtin.command: + cmd: authselect create-profile hardening -b sssd + when: + - result_authselect_check_cmd is success + - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists - name: Ensure PAM Enforces Password Requirements - Minimum Different Categories @@ -26321,6 +30240,11 @@ fi when: - result_authselect_present.stat.exists + - name: Ensure PAM Enforces Password Requirements - Minimum Different Categories + - Define a fact for control already filtered in case filters are used + ansible.builtin.set_fact: + pam_module_control: '' + - name: Ensure PAM Enforces Password Requirements - Minimum Different Categories - Ensure the "minclass" option from "pam_pwquality.so" is not present in {{ pam_file_path }} @@ -26341,6 +30265,7 @@ fi - '"pam" in ansible_facts.packages' - result_pam_file_present.stat.exists tags: + - DISA-STIG-OL09-00-001040 - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(1)(a) - NIST-800-53-IA-5(4) @@ -26361,6 +30286,7 @@ fi line: minclass = {{ var_password_pam_minclass }} when: '"pam" in ansible_facts.packages' tags: + - DISA-STIG-OL09-00-001040 - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(1)(a) - NIST-800-53-IA-5(4) @@ -26371,108 +30297,111 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - - Ensure PAM Enforces Password Requirements - Minimum Length - The pam_pwquality module's minlen parameter controls requirements for -minimum characters required in a password. Add minlen= -after pam_pwquality to set minimum password length requirements. - BP28(R18) - 1 - 12 - 15 - 16 - 5 - 5.6.2.1.1 - DSS05.04 - DSS05.05 - DSS05.07 - DSS05.10 - DSS06.03 - DSS06.10 - CCI-000205 - 4.3.3.2.2 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.2 - 4.3.3.7.4 - SR 1.1 - SR 1.10 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - 0421 - 0422 - 0431 - 0974 - 1173 - 1401 - 1504 - 1505 - 1546 - 1557 - 1558 - 1559 - 1560 - 1561 - A.18.1.4 - A.7.1.1 - A.9.2.1 - A.9.2.2 - A.9.2.3 - A.9.2.4 - A.9.2.6 - A.9.3.1 - A.9.4.2 - A.9.4.3 - IA-5(c) - IA-5(1)(a) - CM-6(a) - IA-5(4) - PR.AC-1 - PR.AC-6 - PR.AC-7 - FMT_SMF_EXT.1 - Req-8.2.3 - 8.3.6 - 8.3.9 - SRG-OS-000078-GPOS-00046 - The shorter the password, the lower the number of possible combinations + + + + + + + + + + + Ensure PAM Enforces Password Requirements - Minimum Length + The pam_pwquality module's minlen parameter controls requirements for +minimum characters required in a password. Add minlen= + +after pam_pwquality to set minimum password length requirements. + 1 + 12 + 15 + 16 + 5 + 5.6.2.1.1 + DSS05.04 + DSS05.05 + DSS05.07 + DSS05.10 + DSS06.03 + DSS06.10 + CCI-004066 + 4.3.3.2.2 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.2 + 4.3.3.7.4 + SR 1.1 + SR 1.10 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + 0421 + 0422 + 0431 + 0974 + 1173 + 1401 + 1504 + 1505 + 1546 + 1557 + 1558 + 1559 + 1560 + 1561 + A.18.1.4 + A.7.1.1 + A.9.2.1 + A.9.2.2 + A.9.2.3 + A.9.2.4 + A.9.2.6 + A.9.3.1 + A.9.4.2 + A.9.4.3 + IA-5(c) + IA-5(1)(a) + CM-6(a) + IA-5(4) + PR.AC-1 + PR.AC-6 + PR.AC-7 + FMT_SMF_EXT.1 + Req-8.2.3 + SRG-OS-000078-GPOS-00046 + R31 + R68 + A.11.SEC-OL3 + 8.3.6 + 8.3 + The shorter the password, the lower the number of possible combinations that need to be tested before the password is compromised. - + Password complexity, or strength, is a measure of the effectiveness of a password in resisting attempts at guessing and brute-force attacks. Password length is one factor of several that helps to determine strength and how long it takes to crack a password. Use of more characters in a password helps to exponentially increase the time and/or resources required to -compromise the password. - - # Remediation is applicable only in certain platforms +compromise the password. + + # Remediation is applicable only in certain platforms if rpm --quiet -q pam; then -var_password_pam_minlen='' +var_password_pam_minlen='' @@ -26495,6 +30424,11 @@ if [ -e "/etc/pam.d/system-auth" ] ; then # If not already in use, a custom profile is created preserving the enabled features. if [[ ! $CURRENT_PROFILE == custom/* ]]; then ENABLED_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }') + # The "local" profile does not contain essential security features required by multiple Benchmarks. + # If currently used, it is replaced by "sssd", which is the best option in this case. + if [[ $CURRENT_PROFILE == local ]]; then + CURRENT_PROFILE="sssd" + fi authselect create-profile hardening -b $CURRENT_PROFILE CURRENT_PROFILE="custom/hardening" @@ -26512,8 +30446,8 @@ if [ -e "/etc/pam.d/system-auth" ] ; then authselect apply-changes -b fi -if grep -qP '^\s*password\s.*\bpam_pwquality.so\s.*\bminlen\b' "$PAM_FILE_PATH"; then - sed -i -E --follow-symlinks 's/(.*password.*pam_pwquality.so.*)\bminlen\b=?[[:alnum:]]*(.*)/\1\2/g' "$PAM_FILE_PATH" +if grep -qP "^\s*password\s.*\bpam_pwquality.so\s.*\bminlen\b" "$PAM_FILE_PATH"; then + sed -i -E --follow-symlinks "s/(.*password.*pam_pwquality.so.*)\bminlen\b=?[[:alnum:]]*(.*)/\1\2/g" "$PAM_FILE_PATH" fi if [ -f /usr/bin/authselect ]; then @@ -26524,6 +30458,8 @@ else fi + + # Strip any search characters in the key arg so that the key can be replaced without # adding any search characters to the config file. stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^minlen") @@ -26547,8 +30483,8 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: @@ -26558,8 +30494,8 @@ fi - NIST-800-53-IA-5(4) - NIST-800-53-IA-5(c) - PCI-DSS-Req-8.2.3 + - PCI-DSSv4-8.3 - PCI-DSSv4-8.3.6 - - PCI-DSSv4-8.3.9 - accounts_password_pam_minlen - low_complexity - low_disruption @@ -26568,7 +30504,7 @@ fi - restrict_strategy - name: XCCDF Value var_password_pam_minlen # promote to variable set_fact: - var_password_pam_minlen: !!str + var_password_pam_minlen: !!str tags: - always @@ -26585,8 +30521,8 @@ fi - NIST-800-53-IA-5(4) - NIST-800-53-IA-5(c) - PCI-DSS-Req-8.2.3 + - PCI-DSSv4-8.3 - PCI-DSSv4-8.3.6 - - PCI-DSSv4-8.3.9 - accounts_password_pam_minlen - low_complexity - low_disruption @@ -26690,7 +30626,16 @@ fi }} when: - result_authselect_check_cmd is success - - authselect_current_profile is not match("custom/") + - authselect_current_profile is not match("^(custom/|local)") + - not result_authselect_custom_profile_present.stat.exists + + - name: Ensure PAM Enforces Password Requirements - Minimum Length - Create an + authselect custom profile based on sssd profile + ansible.builtin.command: + cmd: authselect create-profile hardening -b sssd + when: + - result_authselect_check_cmd is success + - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists - name: Ensure PAM Enforces Password Requirements - Minimum Length - Ensure authselect @@ -26742,6 +30687,11 @@ fi when: - result_authselect_present.stat.exists + - name: Ensure PAM Enforces Password Requirements - Minimum Length - Define a fact + for control already filtered in case filters are used + ansible.builtin.set_fact: + pam_module_control: '' + - name: Ensure PAM Enforces Password Requirements - Minimum Length - Ensure the "minlen" option from "pam_pwquality.so" is not present in {{ pam_file_path }} ansible.builtin.replace: @@ -26767,8 +30717,8 @@ fi - NIST-800-53-IA-5(4) - NIST-800-53-IA-5(c) - PCI-DSS-Req-8.2.3 + - PCI-DSSv4-8.3 - PCI-DSSv4-8.3.6 - - PCI-DSSv4-8.3.9 - accounts_password_pam_minlen - low_complexity - low_disruption @@ -26791,117 +30741,120 @@ fi - NIST-800-53-IA-5(4) - NIST-800-53-IA-5(c) - PCI-DSS-Req-8.2.3 + - PCI-DSSv4-8.3 - PCI-DSSv4-8.3.6 - - PCI-DSSv4-8.3.9 - accounts_password_pam_minlen - low_complexity - low_disruption - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - - Ensure PAM Enforces Password Requirements - Minimum Special Characters - The pam_pwquality module's ocredit= parameter controls requirements for + + + + + + + + + + + Ensure PAM Enforces Password Requirements - Minimum Special Characters + The pam_pwquality module's ocredit= parameter controls requirements for usage of special (or "other") characters in a password. When set to a negative number, any password will be required to contain that many special characters. When set to a positive number, pam_pwquality will grant +1 additional length credit for each special character. Modify the ocredit setting -in /etc/security/pwquality.conf to equal -to require use of a special character in passwords. - BP28(R18) - 1 - 12 - 15 - 16 - 5 - DSS05.04 - DSS05.05 - DSS05.07 - DSS05.10 - DSS06.03 - DSS06.10 - CCI-001619 - 4.3.3.2.2 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.2 - 4.3.3.7.4 - SR 1.1 - SR 1.10 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - 0421 - 0422 - 0431 - 0974 - 1173 - 1401 - 1504 - 1505 - 1546 - 1557 - 1558 - 1559 - 1560 - 1561 - A.18.1.4 - A.7.1.1 - A.9.2.1 - A.9.2.2 - A.9.2.3 - A.9.2.4 - A.9.2.6 - A.9.3.1 - A.9.4.2 - A.9.4.3 - IA-5(c) - IA-5(1)(a) - CM-6(a) - IA-5(4) - PR.AC-1 - PR.AC-6 - PR.AC-7 - FMT_SMF_EXT.1 - SRG-OS-000266-GPOS-00101 - Use of a complex password helps to increase the time and resources required +in /etc/security/pwquality.conf to equal +to require use of a special character in passwords. + 1 + 12 + 15 + 16 + 5 + DSS05.04 + DSS05.05 + DSS05.07 + DSS05.10 + DSS06.03 + DSS06.10 + CCI-004066 + 4.3.3.2.2 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.2 + 4.3.3.7.4 + SR 1.1 + SR 1.10 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + 0421 + 0422 + 0431 + 0974 + 1173 + 1401 + 1504 + 1505 + 1546 + 1557 + 1558 + 1559 + 1560 + 1561 + A.18.1.4 + A.7.1.1 + A.9.2.1 + A.9.2.2 + A.9.2.3 + A.9.2.4 + A.9.2.6 + A.9.3.1 + A.9.4.2 + A.9.4.3 + IA-5(c) + IA-5(1)(a) + CM-6(a) + IA-5(4) + PR.AC-1 + PR.AC-6 + PR.AC-7 + FMT_SMF_EXT.1 + SRG-OS-000266-GPOS-00101 + R31 + OL09-00-001120 + SV-271636r1091620_rule + Use of a complex password helps to increase the time and resources required to compromise the password. Password complexity, or strength, is a measure of the effectiveness of a password in resisting attempts at guessing and brute-force attacks. - + + Password complexity is one factor of several that determines how long it takes to crack a password. The more complex the password, the greater the number of possible combinations that need to be tested before the password is compromised. Requiring a minimum number of special characters makes password guessing attacks -more difficult by ensuring a larger search space. - - # Remediation is applicable only in certain platforms +more difficult by ensuring a larger search space. + + # Remediation is applicable only in certain platforms if rpm --quiet -q pam; then -var_password_pam_ocredit='' +var_password_pam_ocredit='' @@ -26924,6 +30877,11 @@ if [ -e "/etc/pam.d/system-auth" ] ; then # If not already in use, a custom profile is created preserving the enabled features. if [[ ! $CURRENT_PROFILE == custom/* ]]; then ENABLED_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }') + # The "local" profile does not contain essential security features required by multiple Benchmarks. + # If currently used, it is replaced by "sssd", which is the best option in this case. + if [[ $CURRENT_PROFILE == local ]]; then + CURRENT_PROFILE="sssd" + fi authselect create-profile hardening -b $CURRENT_PROFILE CURRENT_PROFILE="custom/hardening" @@ -26941,8 +30899,8 @@ if [ -e "/etc/pam.d/system-auth" ] ; then authselect apply-changes -b fi -if grep -qP '^\s*password\s.*\bpam_pwquality.so\s.*\bocredit\b' "$PAM_FILE_PATH"; then - sed -i -E --follow-symlinks 's/(.*password.*pam_pwquality.so.*)\bocredit\b=?[[:alnum:]]*(.*)/\1\2/g' "$PAM_FILE_PATH" +if grep -qP "^\s*password\s.*\bpam_pwquality.so\s.*\bocredit\b" "$PAM_FILE_PATH"; then + sed -i -E --follow-symlinks "s/(.*password.*pam_pwquality.so.*)\bocredit\b=?[[:alnum:]]*(.*)/\1\2/g" "$PAM_FILE_PATH" fi if [ -f /usr/bin/authselect ]; then @@ -26953,6 +30911,8 @@ else fi + + # Strip any search characters in the key arg so that the key can be replaced without # adding any search characters to the config file. stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^ocredit") @@ -26976,11 +30936,12 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-001120 - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(1)(a) - NIST-800-53-IA-5(4) @@ -26993,7 +30954,7 @@ fi - restrict_strategy - name: XCCDF Value var_password_pam_ocredit # promote to variable set_fact: - var_password_pam_ocredit: !!str + var_password_pam_ocredit: !!str tags: - always @@ -27004,6 +30965,7 @@ fi register: result_pam_file_present when: '"pam" in ansible_facts.packages' tags: + - DISA-STIG-OL09-00-001120 - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(1)(a) - NIST-800-53-IA-5(4) @@ -27111,7 +31073,16 @@ fi }} when: - result_authselect_check_cmd is success - - authselect_current_profile is not match("custom/") + - authselect_current_profile is not match("^(custom/|local)") + - not result_authselect_custom_profile_present.stat.exists + + - name: Ensure PAM Enforces Password Requirements - Minimum Special Characters + - Create an authselect custom profile based on sssd profile + ansible.builtin.command: + cmd: authselect create-profile hardening -b sssd + when: + - result_authselect_check_cmd is success + - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists - name: Ensure PAM Enforces Password Requirements - Minimum Special Characters @@ -27163,6 +31134,11 @@ fi when: - result_authselect_present.stat.exists + - name: Ensure PAM Enforces Password Requirements - Minimum Special Characters - + Define a fact for control already filtered in case filters are used + ansible.builtin.set_fact: + pam_module_control: '' + - name: Ensure PAM Enforces Password Requirements - Minimum Special Characters - Ensure the "ocredit" option from "pam_pwquality.so" is not present in {{ pam_file_path }} @@ -27183,6 +31159,7 @@ fi - '"pam" in ansible_facts.packages' - result_pam_file_present.stat.exists tags: + - DISA-STIG-OL09-00-001120 - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(1)(a) - NIST-800-53-IA-5(4) @@ -27203,6 +31180,7 @@ fi line: ocredit = {{ var_password_pam_ocredit }} when: '"pam" in ansible_facts.packages' tags: + - DISA-STIG-OL09-00-001120 - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(1)(a) - NIST-800-53-IA-5(4) @@ -27213,29 +31191,31 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - - Ensure PAM password complexity module is enabled in password-auth - To enable PAM password complexity in password-auth file: + + + + + + + + + + + Ensure PAM password complexity module is enabled in password-auth + To enable PAM password complexity in password-auth file: Edit the password section in /etc/pam.d/password-auth to show -password requisite pam_pwquality.so. - CCI-000366 - SRG-OS-000069-GPOS-00037 - SRG-OS-000070-GPOS-00038 - SRG-OS-000480-GPOS-00227 - Enabling PAM password complexity permits to enforce strong passwords and consequently -makes the system less prone to dictionary attacks. - - # Remediation is applicable only in certain platforms +password requisite pam_pwquality.so. + CCI-004066 + SRG-OS-000069-GPOS-00037 + SRG-OS-000070-GPOS-00038 + SRG-OS-000480-GPOS-00227 + OL09-00-001010 + SV-271614r1091554_rule + Enabling PAM password complexity permits to enforce strong passwords and consequently +makes the system less prone to dictionary attacks. + + # Remediation is applicable only in certain platforms if rpm --quiet -q pam; then if [ -e "/etc/pam.d/password-auth" ] ; then @@ -27255,6 +31235,11 @@ if [ -e "/etc/pam.d/password-auth" ] ; then # If not already in use, a custom profile is created preserving the enabled features. if [[ ! $CURRENT_PROFILE == custom/* ]]; then ENABLED_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }') + # The "local" profile does not contain essential security features required by multiple Benchmarks. + # If currently used, it is replaced by "sssd", which is the best option in this case. + if [[ $CURRENT_PROFILE == local ]]; then + CURRENT_PROFILE="sssd" + fi authselect create-profile hardening -b $CURRENT_PROFILE CURRENT_PROFILE="custom/hardening" @@ -27271,17 +31256,18 @@ if [ -e "/etc/pam.d/password-auth" ] ; then authselect apply-changes -b fi - if ! grep -qP '^\s*password\s+'"requisite"'\s+pam_pwquality.so\s*.*' "$PAM_FILE_PATH"; then + +if ! grep -qP "^\s*password\s+requisite\s+pam_pwquality.so\s*.*" "$PAM_FILE_PATH"; then # Line matching group + control + module was not found. Check group + module. if [ "$(grep -cP '^\s*password\s+.*\s+pam_pwquality.so\s*' "$PAM_FILE_PATH")" -eq 1 ]; then # The control is updated only if one single line matches. - sed -i -E --follow-symlinks 's/^(\s*password\s+).*(\bpam_pwquality.so.*)/\1'"requisite"' \2/' "$PAM_FILE_PATH" + sed -i -E --follow-symlinks "s/^(\s*password\s+).*(\bpam_pwquality.so.*)/\1requisite \2/" "$PAM_FILE_PATH" else LAST_MATCH_LINE=$(grep -nP "^account.*required.*pam_permit\.so" "$PAM_FILE_PATH" | tail -n 1 | cut -d: -f 1) if [ ! -z $LAST_MATCH_LINE ]; then - sed -i --follow-symlinks $LAST_MATCH_LINE' a password '"requisite"' pam_pwquality.so' "$PAM_FILE_PATH" + sed -i --follow-symlinks $LAST_MATCH_LINE" a password requisite pam_pwquality.so" "$PAM_FILE_PATH" else - echo 'password '"requisite"' pam_pwquality.so' >> "$PAM_FILE_PATH" + echo "password requisite pam_pwquality.so" >> "$PAM_FILE_PATH" fi fi fi @@ -27296,11 +31282,12 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-001010 - accounts_password_pam_pwquality_password_auth - configure_strategy - low_complexity @@ -27315,6 +31302,7 @@ fi register: result_pam_file_present when: '"pam" in ansible_facts.packages' tags: + - DISA-STIG-OL09-00-001010 - accounts_password_pam_pwquality_password_auth - configure_strategy - low_complexity @@ -27418,7 +31406,16 @@ fi }} when: - result_authselect_check_cmd is success - - authselect_current_profile is not match("custom/") + - authselect_current_profile is not match("^(custom/|local)") + - not result_authselect_custom_profile_present.stat.exists + + - name: Ensure PAM password complexity module is enabled in password-auth - Create + an authselect custom profile based on sssd profile + ansible.builtin.command: + cmd: authselect create-profile hardening -b sssd + when: + - result_authselect_check_cmd is success + - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists - name: Ensure PAM password complexity module is enabled in password-auth - Ensure @@ -27470,11 +31467,16 @@ fi when: - result_authselect_present.stat.exists + - name: Ensure PAM password complexity module is enabled in password-auth - Define + a fact for control already filtered in case filters are used + ansible.builtin.set_fact: + pam_module_control: requisite + - name: Ensure PAM password complexity module is enabled in password-auth - Check if expected PAM module line is present in {{ pam_file_path }} ansible.builtin.lineinfile: path: '{{ pam_file_path }}' - regexp: ^\s*password\s+requisite\s+pam_pwquality.so\s*.* + regexp: ^\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_pwquality.so\s*.* state: absent check_mode: true changed_when: false @@ -27500,7 +31502,7 @@ fi ansible.builtin.replace: dest: '{{ pam_file_path }}' regexp: ^(\s*password\s+).*(\bpam_pwquality.so.*) - replace: \1requisite \2 + replace: \1{{ pam_module_control }} \2 register: result_pam_module_edit when: - result_pam_line_other_control_present.found == 1 @@ -27510,7 +31512,7 @@ fi ansible.builtin.lineinfile: dest: '{{ pam_file_path }}' insertafter: ^account.*required.*pam_permit\.so - line: password requisite pam_pwquality.so + line: password {{ pam_module_control }} pam_pwquality.so register: result_pam_module_add when: - result_pam_line_other_control_present.found == 0 or result_pam_line_other_control_present.found @@ -27537,38 +31539,41 @@ fi when: - result_authselect_present.stat.exists - |- - (result_pam__add is defined and result_pam__add.changed) - or (result_pam__edit is defined and result_pam__edit.changed) + (result_pam_accounts_password_pam_pwquality_password_auth_add is defined and result_pam_accounts_password_pam_pwquality_password_auth_add.changed) + or (result_pam_accounts_password_pam_pwquality_password_auth_edit is defined and result_pam_accounts_password_pam_pwquality_password_auth_edit.changed) when: - '"pam" in ansible_facts.packages' - result_pam_file_present.stat.exists tags: + - DISA-STIG-OL09-00-001010 - accounts_password_pam_pwquality_password_auth - configure_strategy - low_complexity - medium_disruption - medium_severity - no_reboot_needed - - - - - - - - - - Ensure PAM password complexity module is enabled in system-auth - To enable PAM password complexity in system-auth file: + + + + + + + + + + Ensure PAM password complexity module is enabled in system-auth + To enable PAM password complexity in system-auth file: Edit the password section in /etc/pam.d/system-auth to show -password requisite pam_pwquality.so. - CCI-000366 - SRG-OS-000480-GPOS-00227 - Enabling PAM password complexity permits to enforce strong passwords and consequently -makes the system less prone to dictionary attacks. - - # Remediation is applicable only in certain platforms +password requisite pam_pwquality.so. + CCI-000366 + SRG-OS-000480-GPOS-00227 + OL09-00-001000 + SV-271611r1091545_rule + Enabling PAM password complexity permits to enforce strong passwords and consequently +makes the system less prone to dictionary attacks. + + # Remediation is applicable only in certain platforms if rpm --quiet -q pam; then if [ -e "/etc/pam.d/system-auth" ] ; then @@ -27588,6 +31593,11 @@ if [ -e "/etc/pam.d/system-auth" ] ; then # If not already in use, a custom profile is created preserving the enabled features. if [[ ! $CURRENT_PROFILE == custom/* ]]; then ENABLED_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }') + # The "local" profile does not contain essential security features required by multiple Benchmarks. + # If currently used, it is replaced by "sssd", which is the best option in this case. + if [[ $CURRENT_PROFILE == local ]]; then + CURRENT_PROFILE="sssd" + fi authselect create-profile hardening -b $CURRENT_PROFILE CURRENT_PROFILE="custom/hardening" @@ -27604,17 +31614,18 @@ if [ -e "/etc/pam.d/system-auth" ] ; then authselect apply-changes -b fi - if ! grep -qP '^\s*password\s+'"requisite"'\s+pam_pwquality.so\s*.*' "$PAM_FILE_PATH"; then + +if ! grep -qP "^\s*password\s+requisite\s+pam_pwquality.so\s*.*" "$PAM_FILE_PATH"; then # Line matching group + control + module was not found. Check group + module. if [ "$(grep -cP '^\s*password\s+.*\s+pam_pwquality.so\s*' "$PAM_FILE_PATH")" -eq 1 ]; then # The control is updated only if one single line matches. - sed -i -E --follow-symlinks 's/^(\s*password\s+).*(\bpam_pwquality.so.*)/\1'"requisite"' \2/' "$PAM_FILE_PATH" + sed -i -E --follow-symlinks "s/^(\s*password\s+).*(\bpam_pwquality.so.*)/\1requisite \2/" "$PAM_FILE_PATH" else LAST_MATCH_LINE=$(grep -nP "^account.*required.*pam_permit\.so" "$PAM_FILE_PATH" | tail -n 1 | cut -d: -f 1) if [ ! -z $LAST_MATCH_LINE ]; then - sed -i --follow-symlinks $LAST_MATCH_LINE' a password '"requisite"' pam_pwquality.so' "$PAM_FILE_PATH" + sed -i --follow-symlinks $LAST_MATCH_LINE" a password requisite pam_pwquality.so" "$PAM_FILE_PATH" else - echo 'password '"requisite"' pam_pwquality.so' >> "$PAM_FILE_PATH" + echo "password requisite pam_pwquality.so" >> "$PAM_FILE_PATH" fi fi fi @@ -27629,11 +31640,12 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-001000 - accounts_password_pam_pwquality_system_auth - configure_strategy - low_complexity @@ -27648,6 +31660,7 @@ fi register: result_pam_file_present when: '"pam" in ansible_facts.packages' tags: + - DISA-STIG-OL09-00-001000 - accounts_password_pam_pwquality_system_auth - configure_strategy - low_complexity @@ -27751,7 +31764,16 @@ fi }} when: - result_authselect_check_cmd is success - - authselect_current_profile is not match("custom/") + - authselect_current_profile is not match("^(custom/|local)") + - not result_authselect_custom_profile_present.stat.exists + + - name: Ensure PAM password complexity module is enabled in system-auth - Create + an authselect custom profile based on sssd profile + ansible.builtin.command: + cmd: authselect create-profile hardening -b sssd + when: + - result_authselect_check_cmd is success + - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists - name: Ensure PAM password complexity module is enabled in system-auth - Ensure @@ -27803,11 +31825,16 @@ fi when: - result_authselect_present.stat.exists + - name: Ensure PAM password complexity module is enabled in system-auth - Define + a fact for control already filtered in case filters are used + ansible.builtin.set_fact: + pam_module_control: requisite + - name: Ensure PAM password complexity module is enabled in system-auth - Check if expected PAM module line is present in {{ pam_file_path }} ansible.builtin.lineinfile: path: '{{ pam_file_path }}' - regexp: ^\s*password\s+requisite\s+pam_pwquality.so\s*.* + regexp: ^\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_pwquality.so\s*.* state: absent check_mode: true changed_when: false @@ -27833,7 +31860,7 @@ fi ansible.builtin.replace: dest: '{{ pam_file_path }}' regexp: ^(\s*password\s+).*(\bpam_pwquality.so.*) - replace: \1requisite \2 + replace: \1{{ pam_module_control }} \2 register: result_pam_module_edit when: - result_pam_line_other_control_present.found == 1 @@ -27843,7 +31870,7 @@ fi ansible.builtin.lineinfile: dest: '{{ pam_file_path }}' insertafter: ^account.*required.*pam_permit\.so - line: password requisite pam_pwquality.so + line: password {{ pam_module_control }} pam_pwquality.so register: result_pam_module_add when: - result_pam_line_other_control_present.found == 0 or result_pam_line_other_control_present.found @@ -27870,118 +31897,122 @@ fi when: - result_authselect_present.stat.exists - |- - (result_pam__add is defined and result_pam__add.changed) - or (result_pam__edit is defined and result_pam__edit.changed) + (result_pam_accounts_password_pam_pwquality_system_auth_add is defined and result_pam_accounts_password_pam_pwquality_system_auth_add.changed) + or (result_pam_accounts_password_pam_pwquality_system_auth_edit is defined and result_pam_accounts_password_pam_pwquality_system_auth_edit.changed) when: - '"pam" in ansible_facts.packages' - result_pam_file_present.stat.exists tags: + - DISA-STIG-OL09-00-001000 - accounts_password_pam_pwquality_system_auth - configure_strategy - low_complexity - medium_disruption - medium_severity - no_reboot_needed - - - - - - - - - - Ensure PAM Enforces Password Requirements - Authentication Retry Prompts Permitted Per-Session - To configure the number of retry prompts that are permitted per-session: + + + + + + + + + + Ensure PAM Enforces Password Requirements - Authentication Retry Prompts Permitted Per-Session + To configure the number of retry prompts that are permitted per-session: Edit the /etc/security/pwquality.conf to include -retry=, or a lower value if site +retry= + , or a lower value if site policy is more restrictive. The DoD requirement is a maximum of 3 prompts -per session. - 1 - 11 - 12 - 15 - 16 - 3 - 5 - 9 - 5.5.3 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS05.04 - DSS05.05 - DSS05.07 - DSS05.10 - DSS06.03 - DSS06.10 - CCI-000192 - CCI-000366 - 4.3.3.2.2 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.2 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - SR 1.1 - SR 1.10 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 7.6 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.18.1.4 - A.7.1.1 - A.9.2.1 - A.9.2.2 - A.9.2.3 - A.9.2.4 - A.9.2.6 - A.9.3.1 - A.9.4.2 - A.9.4.3 - CM-6(a) - AC-7(a) - IA-5(4) - PR.AC-1 - PR.AC-6 - PR.AC-7 - PR.IP-1 - FMT_MOF_EXT.1 - SRG-OS-000069-GPOS-00037 - SRG-OS-000480-GPOS-00227 - Setting the password retry prompts that are permitted on a per-session basis to a low value +per session. + 1 + 11 + 12 + 15 + 16 + 3 + 5 + 9 + 5.5.3 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS05.04 + DSS05.05 + DSS05.07 + DSS05.10 + DSS06.03 + DSS06.10 + CCI-004066 + 4.3.3.2.2 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.2 + 4.3.3.7.4 + 4.3.4.3.2 + 4.3.4.3.3 + SR 1.1 + SR 1.10 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 7.6 + A.12.1.2 + A.12.5.1 + A.12.6.2 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.18.1.4 + A.7.1.1 + A.9.2.1 + A.9.2.2 + A.9.2.3 + A.9.2.4 + A.9.2.6 + A.9.3.1 + A.9.4.2 + A.9.4.3 + CM-6(a) + AC-7(a) + IA-5(4) + PR.AC-1 + PR.AC-6 + PR.AC-7 + PR.IP-1 + SRG-OS-000069-GPOS-00037 + SRG-OS-000480-GPOS-00227 + R68 + A.11.SEC-OL3 + OL09-00-001001 + SV-271612r1091548_rule + Setting the password retry prompts that are permitted on a per-session basis to a low value requires some software, such as SSH, to re-connect. This can slow down and draw additional attention to some types of password-guessing attacks. Note that this -is different from account lockout, which is provided by the pam_faillock module. - - # Remediation is applicable only in certain platforms +is different from account lockout, which is provided by the pam_faillock module. + + # Remediation is applicable only in certain platforms if rpm --quiet -q pam; then -var_password_pam_retry='' +var_password_pam_retry='' # Strip any search characters in the key arg so that the key can be replaced without @@ -28021,6 +32052,11 @@ fi # If not already in use, a custom profile is created preserving the enabled features. if [[ ! $CURRENT_PROFILE == custom/* ]]; then ENABLED_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }') + # The "local" profile does not contain essential security features required by multiple Benchmarks. + # If currently used, it is replaced by "sssd", which is the best option in this case. + if [[ $CURRENT_PROFILE == local ]]; then + CURRENT_PROFILE="sssd" + fi authselect create-profile hardening -b $CURRENT_PROFILE CURRENT_PROFILE="custom/hardening" @@ -28038,8 +32074,8 @@ fi authselect apply-changes -b fi -if grep -qP '^\s*password\s+'".*"'\s+pam_pwquality.so\s.*\bretry\b' "$PAM_FILE_PATH"; then - sed -i -E --follow-symlinks 's/(.*password.*'".*"'.*pam_pwquality.so.*)\sretry=?[[:alnum:]]*(.*)/\1\2/g' "$PAM_FILE_PATH" +if grep -qP "^\s*password\s.*\bpam_pwquality.so\s.*\bretry\b" "$PAM_FILE_PATH"; then + sed -i -E --follow-symlinks "s/(.*password.*pam_pwquality.so.*)\bretry\b=?[[:alnum:]]*(.*)/\1\2/g" "$PAM_FILE_PATH" fi if [ -f /usr/bin/authselect ]; then @@ -28066,6 +32102,11 @@ fi # If not already in use, a custom profile is created preserving the enabled features. if [[ ! $CURRENT_PROFILE == custom/* ]]; then ENABLED_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }') + # The "local" profile does not contain essential security features required by multiple Benchmarks. + # If currently used, it is replaced by "sssd", which is the best option in this case. + if [[ $CURRENT_PROFILE == local ]]; then + CURRENT_PROFILE="sssd" + fi authselect create-profile hardening -b $CURRENT_PROFILE CURRENT_PROFILE="custom/hardening" @@ -28083,8 +32124,8 @@ fi authselect apply-changes -b fi -if grep -qP '^\s*password\s+'".*"'\s+pam_pwquality.so\s.*\bretry\b' "$PAM_FILE_PATH"; then - sed -i -E --follow-symlinks 's/(.*password.*'".*"'.*pam_pwquality.so.*)\sretry=?[[:alnum:]]*(.*)/\1\2/g' "$PAM_FILE_PATH" +if grep -qP "^\s*password\s.*\bpam_pwquality.so\s.*\bretry\b" "$PAM_FILE_PATH"; then + sed -i -E --follow-symlinks "s/(.*password.*pam_pwquality.so.*)\bretry\b=?[[:alnum:]]*(.*)/\1\2/g" "$PAM_FILE_PATH" fi if [ -f /usr/bin/authselect ]; then @@ -28097,12 +32138,13 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: - CJIS-5.5.3 + - DISA-STIG-OL09-00-001001 - NIST-800-53-AC-7(a) - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(4) @@ -28114,7 +32156,7 @@ fi - no_reboot_needed - name: XCCDF Value var_password_pam_retry # promote to variable set_fact: - var_password_pam_retry: !!str + var_password_pam_retry: !!str tags: - always @@ -28127,6 +32169,7 @@ fi when: '"pam" in ansible_facts.packages' tags: - CJIS-5.5.3 + - DISA-STIG-OL09-00-001001 - NIST-800-53-AC-7(a) - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(4) @@ -28145,6 +32188,7 @@ fi when: '"pam" in ansible_facts.packages' tags: - CJIS-5.5.3 + - DISA-STIG-OL09-00-001001 - NIST-800-53-AC-7(a) - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(4) @@ -28257,7 +32301,17 @@ fi }} when: - result_authselect_check_cmd is success - - authselect_current_profile is not match("custom/") + - authselect_current_profile is not match("^(custom/|local)") + - not result_authselect_custom_profile_present.stat.exists + + - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session - Create an authselect custom profile based on sssd + profile + ansible.builtin.command: + cmd: authselect create-profile hardening -b sssd + when: + - result_authselect_check_cmd is success + - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts @@ -28310,12 +32364,18 @@ fi when: - result_authselect_present.stat.exists + - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session - Define a fact for control already filtered in case filters + are used + ansible.builtin.set_fact: + pam_module_control: '' + - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts Permitted Per-Session - Ensure the "retry" option from "pam_pwquality.so" is not present in {{ pam_file_path }} ansible.builtin.replace: dest: '{{ pam_file_path }}' - regexp: (.*password.*.*.*pam_pwquality.so.*)\bretry\b=?[0-9a-zA-Z]*(.*) + regexp: (.*password.*pam_pwquality.so.*)\bretry\b=?[0-9a-zA-Z]*(.*) replace: \1\2 register: result_pam_option_removal @@ -28331,6 +32391,7 @@ fi - result_pam_file_present.stat.exists tags: - CJIS-5.5.3 + - DISA-STIG-OL09-00-001001 - NIST-800-53-AC-7(a) - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(4) @@ -28349,6 +32410,7 @@ fi when: '"pam" in ansible_facts.packages' tags: - CJIS-5.5.3 + - DISA-STIG-OL09-00-001001 - NIST-800-53-AC-7(a) - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(4) @@ -28461,7 +32523,17 @@ fi }} when: - result_authselect_check_cmd is success - - authselect_current_profile is not match("custom/") + - authselect_current_profile is not match("^(custom/|local)") + - not result_authselect_custom_profile_present.stat.exists + + - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session - Create an authselect custom profile based on sssd + profile + ansible.builtin.command: + cmd: authselect create-profile hardening -b sssd + when: + - result_authselect_check_cmd is success + - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts @@ -28514,12 +32586,18 @@ fi when: - result_authselect_present.stat.exists + - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session - Define a fact for control already filtered in case filters + are used + ansible.builtin.set_fact: + pam_module_control: '' + - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts Permitted Per-Session - Ensure the "retry" option from "pam_pwquality.so" is not present in {{ pam_file_path }} ansible.builtin.replace: dest: '{{ pam_file_path }}' - regexp: (.*password.*.*.*pam_pwquality.so.*)\bretry\b=?[0-9a-zA-Z]*(.*) + regexp: (.*password.*pam_pwquality.so.*)\bretry\b=?[0-9a-zA-Z]*(.*) replace: \1\2 register: result_pam_option_removal @@ -28535,6 +32613,7 @@ fi - result_pam_file_present.stat.exists tags: - CJIS-5.5.3 + - DISA-STIG-OL09-00-001001 - NIST-800-53-AC-7(a) - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(4) @@ -28544,109 +32623,109 @@ fi - medium_disruption - medium_severity - no_reboot_needed - - - - - - - - - - - Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters - The pam_pwquality module's ucredit= parameter controls requirements for + + + + + + + + + + + Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters + The pam_pwquality module's ucredit= parameter controls requirements for usage of uppercase letters in a password. When set to a negative number, any password will be required to contain that many uppercase characters. When set to a positive number, pam_pwquality will grant +1 additional length credit for each uppercase character. Modify the ucredit setting in -/etc/security/pwquality.conf to require the use of an uppercase character in passwords. - BP28(R18) - 1 - 12 - 15 - 16 - 5 - DSS05.04 - DSS05.05 - DSS05.07 - DSS05.10 - DSS06.03 - DSS06.10 - CCI-000192 - CCI-000193 - 4.3.3.2.2 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.2 - 4.3.3.7.4 - SR 1.1 - SR 1.10 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - 0421 - 0422 - 0431 - 0974 - 1173 - 1401 - 1504 - 1505 - 1546 - 1557 - 1558 - 1559 - 1560 - 1561 - A.18.1.4 - A.7.1.1 - A.9.2.1 - A.9.2.2 - A.9.2.3 - A.9.2.4 - A.9.2.6 - A.9.3.1 - A.9.4.2 - A.9.4.3 - IA-5(c) - IA-5(1)(a) - CM-6(a) - IA-5(4) - PR.AC-1 - PR.AC-6 - PR.AC-7 - FMT_SMF_EXT.1 - Req-8.2.3 - 8.3.6 - 8.3.9 - SRG-OS-000069-GPOS-00037 - SRG-OS-000070-GPOS-00038 - Use of a complex password helps to increase the time and resources required to compromise the password. +/etc/security/pwquality.conf to require the use of an uppercase character in passwords. + 1 + 12 + 15 + 16 + 5 + DSS05.04 + DSS05.05 + DSS05.07 + DSS05.10 + DSS06.03 + DSS06.10 + CCI-004066 + 4.3.3.2.2 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.2 + 4.3.3.7.4 + SR 1.1 + SR 1.10 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + 0421 + 0422 + 0431 + 0974 + 1173 + 1401 + 1504 + 1505 + 1546 + 1557 + 1558 + 1559 + 1560 + 1561 + A.18.1.4 + A.7.1.1 + A.9.2.1 + A.9.2.2 + A.9.2.3 + A.9.2.4 + A.9.2.6 + A.9.3.1 + A.9.4.2 + A.9.4.3 + IA-5(c) + IA-5(1)(a) + CM-6(a) + IA-5(4) + PR.AC-1 + PR.AC-6 + PR.AC-7 + FMT_SMF_EXT.1 + Req-8.2.3 + SRG-OS-000069-GPOS-00037 + SRG-OS-000070-GPOS-00038 + R31 + OL09-00-001005 + SV-271613r1091551_rule + Use of a complex password helps to increase the time and resources required to compromise the password. Password complexity, or strength, is a measure of the effectiveness of a password in resisting attempts at guessing and brute-force attacks. - + + Password complexity is one factor of several that determines how long it takes to crack a password. The more complex the password, the greater the number of possible combinations that need to be tested before -the password is compromised. - - # Remediation is applicable only in certain platforms +the password is compromised. + + # Remediation is applicable only in certain platforms if rpm --quiet -q pam; then -var_password_pam_ucredit='' +var_password_pam_ucredit='' @@ -28669,6 +32748,11 @@ if [ -e "/etc/pam.d/system-auth" ] ; then # If not already in use, a custom profile is created preserving the enabled features. if [[ ! $CURRENT_PROFILE == custom/* ]]; then ENABLED_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }') + # The "local" profile does not contain essential security features required by multiple Benchmarks. + # If currently used, it is replaced by "sssd", which is the best option in this case. + if [[ $CURRENT_PROFILE == local ]]; then + CURRENT_PROFILE="sssd" + fi authselect create-profile hardening -b $CURRENT_PROFILE CURRENT_PROFILE="custom/hardening" @@ -28686,8 +32770,8 @@ if [ -e "/etc/pam.d/system-auth" ] ; then authselect apply-changes -b fi -if grep -qP '^\s*password\s.*\bpam_pwquality.so\s.*\bucredit\b' "$PAM_FILE_PATH"; then - sed -i -E --follow-symlinks 's/(.*password.*pam_pwquality.so.*)\bucredit\b=?[[:alnum:]]*(.*)/\1\2/g' "$PAM_FILE_PATH" +if grep -qP "^\s*password\s.*\bpam_pwquality.so\s.*\bucredit\b" "$PAM_FILE_PATH"; then + sed -i -E --follow-symlinks "s/(.*password.*pam_pwquality.so.*)\bucredit\b=?[[:alnum:]]*(.*)/\1\2/g" "$PAM_FILE_PATH" fi if [ -f /usr/bin/authselect ]; then @@ -28698,6 +32782,8 @@ else fi + + # Strip any search characters in the key arg so that the key can be replaced without # adding any search characters to the config file. stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^ucredit") @@ -28721,18 +32807,17 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-001005 - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(1)(a) - NIST-800-53-IA-5(4) - NIST-800-53-IA-5(c) - PCI-DSS-Req-8.2.3 - - PCI-DSSv4-8.3.6 - - PCI-DSSv4-8.3.9 - accounts_password_pam_ucredit - low_complexity - low_disruption @@ -28741,7 +32826,7 @@ fi - restrict_strategy - name: XCCDF Value var_password_pam_ucredit # promote to variable set_fact: - var_password_pam_ucredit: !!str + var_password_pam_ucredit: !!str tags: - always @@ -28752,13 +32837,12 @@ fi register: result_pam_file_present when: '"pam" in ansible_facts.packages' tags: + - DISA-STIG-OL09-00-001005 - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(1)(a) - NIST-800-53-IA-5(4) - NIST-800-53-IA-5(c) - PCI-DSS-Req-8.2.3 - - PCI-DSSv4-8.3.6 - - PCI-DSSv4-8.3.9 - accounts_password_pam_ucredit - low_complexity - low_disruption @@ -28862,7 +32946,16 @@ fi }} when: - result_authselect_check_cmd is success - - authselect_current_profile is not match("custom/") + - authselect_current_profile is not match("^(custom/|local)") + - not result_authselect_custom_profile_present.stat.exists + + - name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters + - Create an authselect custom profile based on sssd profile + ansible.builtin.command: + cmd: authselect create-profile hardening -b sssd + when: + - result_authselect_check_cmd is success + - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists - name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters @@ -28914,6 +33007,11 @@ fi when: - result_authselect_present.stat.exists + - name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters + - Define a fact for control already filtered in case filters are used + ansible.builtin.set_fact: + pam_module_control: '' + - name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters - Ensure the "ucredit" option from "pam_pwquality.so" is not present in {{ pam_file_path }} @@ -28934,13 +33032,12 @@ fi - '"pam" in ansible_facts.packages' - result_pam_file_present.stat.exists tags: + - DISA-STIG-OL09-00-001005 - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(1)(a) - NIST-800-53-IA-5(4) - NIST-800-53-IA-5(c) - PCI-DSS-Req-8.2.3 - - PCI-DSSv4-8.3.6 - - PCI-DSSv4-8.3.9 - accounts_password_pam_ucredit - low_complexity - low_disruption @@ -28957,143 +33054,157 @@ fi line: ucredit = {{ var_password_pam_ucredit }} when: '"pam" in ansible_facts.packages' tags: + - DISA-STIG-OL09-00-001005 - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(1)(a) - NIST-800-53-IA-5(4) - NIST-800-53-IA-5(c) - PCI-DSS-Req-8.2.3 - - PCI-DSSv4-8.3.6 - - PCI-DSSv4-8.3.9 - accounts_password_pam_ucredit - low_complexity - low_disruption - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - - - - Set Password Hashing Algorithm - The system's default algorithm for storing password hashes in + + + + + + + + + + + + + Set Password Hashing Algorithm + The system's default algorithm for storing password hashes in /etc/shadow is SHA-512. This can be configured in several -locations. - - Set Password Hashing Algorithm in /etc/libuser.conf - In /etc/libuser.conf, add or correct the following line in its -[defaults] section to ensure the system will use the SHA-512 +locations. + + Minimum number of password hashing rounds configured through /etc/login.defs + Minimum number of password hashing rounds configured through /etc/login.defs + 5000 + 5000 + 100000 + + + Set Password Hashing Algorithm in /etc/libuser.conf + In /etc/libuser.conf, add or correct the following line in its [defaults] +section to ensure the system will use the algorithm for password hashing: -crypt_style = sha512 - 1 - 12 - 15 - 16 - 5 - 5.6.2.2 - DSS05.04 - DSS05.05 - DSS05.07 - DSS05.10 - DSS06.03 - DSS06.10 - 3.13.11 - CCI-000196 - 4.3.3.2.2 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.2 - 4.3.3.7.4 - SR 1.1 - SR 1.10 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - 0418 - 1055 - 1402 - A.18.1.4 - A.7.1.1 - A.9.2.1 - A.9.2.2 - A.9.2.3 - A.9.2.4 - A.9.2.6 - A.9.3.1 - A.9.4.2 - A.9.4.3 - IA-5(c) - IA-5(1)(c) - CM-6(a) - PR.AC-1 - PR.AC-6 - PR.AC-7 - Req-8.2.1 - 8.3.2 - SRG-OS-000073-GPOS-00041 - Passwords need to be protected at all times, and encryption is the standard -method for protecting passwords. If passwords are not encrypted, they can -be plainly read (i.e., clear text) and easily compromised. Passwords that -are encrypted with a weak algorithm are no more protected than if they are -kepy in plain text. - -This setting ensures user and group account administration utilities are -configured to store only encrypted representations of passwords. -Additionally, the crypt_style configuration option ensures the use -of a strong hashing algorithm that makes password cracking attacks more -difficult. - - # Remediation is applicable only in certain platforms +crypt_style = + + + 1 + 12 + 15 + 16 + 5 + 5.6.2.2 + DSS05.04 + DSS05.05 + DSS05.07 + DSS05.10 + DSS06.03 + DSS06.10 + 3.13.11 + CCI-004062 + 4.3.3.2.2 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.2 + 4.3.3.7.4 + SR 1.1 + SR 1.10 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + 0418 + 1055 + 1402 + A.18.1.4 + A.7.1.1 + A.9.2.1 + A.9.2.2 + A.9.2.3 + A.9.2.4 + A.9.2.6 + A.9.3.1 + A.9.4.2 + A.9.4.3 + IA-5(c) + IA-5(1)(c) + CM-6(a) + PR.AC-1 + PR.AC-6 + PR.AC-7 + Req-8.2.1 + SRG-OS-000073-GPOS-00041 + 8.3.2 + 8.3 + OL09-00-001050 + SV-271622r1091578_rule + Passwords need to be protected at all times, and encryption is the standard method for +protecting passwords. If passwords are not encrypted, they can be plainly read +(i.e., clear text) and easily compromised. Passwords that are encrypted with a weak algorithm +are no more protected than if they are kept in plain text. + + +This setting ensures user and group account administration utilities are configured to store +only encrypted representations of passwords. Additionally, the crypt_style +configuration option in /etc/libuser.conf ensures the use of a strong hashing +algorithm that makes password cracking attacks more difficult. + + # Remediation is applicable only in certain platforms if rpm --quiet -q libuser; then +var_password_hashing_algorithm_pam='' + LIBUSER_CONF="/etc/libuser.conf" CRYPT_STYLE_REGEX='[[:space:]]*\[defaults](.*(\n)+)+?[[:space:]]*crypt_style[[:space:]]*' # Try find crypt_style in [defaults] section. If it is here, then change algorithm to sha512. # If it isn't here, then add it to [defaults] section. if grep -qzosP $CRYPT_STYLE_REGEX $LIBUSER_CONF ; then - sed -i "s/\(crypt_style[[:space:]]*=[[:space:]]*\).*/\1sha512/g" $LIBUSER_CONF + sed -i "s/\(crypt_style[[:space:]]*=[[:space:]]*\).*/\1$var_password_hashing_algorithm_pam/g" $LIBUSER_CONF elif grep -qs "\[defaults]" $LIBUSER_CONF ; then - sed -i "/[[:space:]]*\[defaults]/a crypt_style = sha512" $LIBUSER_CONF + sed -i "/[[:space:]]*\[defaults]/a crypt_style = $var_password_hashing_algorithm_pam" $LIBUSER_CONF else - echo -e "[defaults]\ncrypt_style = sha512" >> $LIBUSER_CONF + echo -e "[defaults]\ncrypt_style = $var_password_hashing_algorithm_pam" >> $LIBUSER_CONF fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: - CJIS-5.6.2.2 + - DISA-STIG-OL09-00-001050 - NIST-800-171-3.13.11 - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(1)(c) - NIST-800-53-IA-5(c) - PCI-DSS-Req-8.2.1 + - PCI-DSSv4-8.3 - PCI-DSSv4-8.3.2 - low_complexity - low_disruption @@ -29101,23 +33212,31 @@ fi - no_reboot_needed - restrict_strategy - set_password_hashing_algorithm_libuserconf +- name: XCCDF Value var_password_hashing_algorithm_pam # promote to variable + set_fact: + var_password_hashing_algorithm_pam: !!str + tags: + - always -- name: Set Password Hashing Algorithm in /etc/libuser.conf - lineinfile: +- name: Set Password Hashing Algorithm in /etc/libuser.conf - Set Password Hashing + Algorithm in /etc/libuser.conf + ansible.builtin.lineinfile: dest: /etc/libuser.conf insertafter: ^\s*\[defaults] regexp: ^#?crypt_style - line: crypt_style = sha512 + line: crypt_style = {{ var_password_hashing_algorithm_pam }} state: present create: true when: '"libuser" in ansible_facts.packages' tags: - CJIS-5.6.2.2 + - DISA-STIG-OL09-00-001050 - NIST-800-171-3.13.11 - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(1)(c) - NIST-800-53-IA-5(c) - PCI-DSS-Req-8.2.1 + - PCI-DSSv4-8.3 - PCI-DSSv4-8.3.2 - low_complexity - low_disruption @@ -29125,113 +33244,140 @@ fi - no_reboot_needed - restrict_strategy - set_password_hashing_algorithm_libuserconf - - - - - - - - - - Set Password Hashing Algorithm in /etc/login.defs - In /etc/login.defs, add or correct the following line to ensure -the system will use as the hashing algorithm: -ENCRYPT_METHOD - BP28(R32) - 1 - 12 - 15 - 16 - 5 - 5.6.2.2 - DSS05.04 - DSS05.05 - DSS05.07 - DSS05.10 - DSS06.03 - DSS06.10 - 3.13.11 - CCI-000196 - 4.3.3.2.2 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.2 - 4.3.3.7.4 - SR 1.1 - SR 1.10 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - 0418 - 1055 - 1402 - A.18.1.4 - A.7.1.1 - A.9.2.1 - A.9.2.2 - A.9.2.3 - A.9.2.4 - A.9.2.6 - A.9.3.1 - A.9.4.2 - A.9.4.3 - IA-5(c) - IA-5(1)(c) - CM-6(a) - PR.AC-1 - PR.AC-6 - PR.AC-7 - Req-8.2.1 - 8.3.2 - SRG-OS-000073-GPOS-00041 - Passwords need to be protected at all times, and encryption is the standard method for protecting passwords. -If passwords are not encrypted, they can be plainly read (i.e., clear text) and easily compromised. Passwords -that are encrypted with a weak algorithm are no more protected than if they are kept in plain text. - -Using a stronger hashing algorithm makes password cracking attacks more difficult. - - # Remediation is applicable only in certain platforms + + + + + + + + + + + Set Password Hashing Algorithm in /etc/login.defs + In /etc/login.defs, add or update the following line to ensure the system will use + as the hashing algorithm: +ENCRYPT_METHOD + + + 1 + 12 + 15 + 16 + 5 + 5.6.2.2 + DSS05.04 + DSS05.05 + DSS05.07 + DSS05.10 + DSS06.03 + DSS06.10 + 3.13.11 + CCI-004062 + 4.3.3.2.2 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.2 + 4.3.3.7.4 + SR 1.1 + SR 1.10 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + 0418 + 1055 + 1402 + A.18.1.4 + A.7.1.1 + A.9.2.1 + A.9.2.2 + A.9.2.3 + A.9.2.4 + A.9.2.6 + A.9.3.1 + A.9.4.2 + A.9.4.3 + IA-5(c) + IA-5(1)(c) + CM-6(a) + PR.AC-1 + PR.AC-6 + PR.AC-7 + Req-8.2.1 + SRG-OS-000073-GPOS-00041 + A.19.SEC-OL3 + 8.3.2 + 8.3 + OL09-00-001055 + SV-271623r1091581_rule + Passwords need to be protected at all times, and encryption is the standard method for +protecting passwords. If passwords are not encrypted, they can be plainly read +(i.e., clear text) and easily compromised. Passwords that are encrypted with a weak algorithm +are no more protected than if they are kept in plain text. + + +Using a stronger hashing algorithm makes password cracking attacks more difficult. + + # Remediation is applicable only in certain platforms if rpm --quiet -q shadow-utils; then -var_password_hashing_algorithm='' +var_password_hashing_algorithm='' -if grep --silent ^ENCRYPT_METHOD /etc/login.defs ; then - sed -i "s/^ENCRYPT_METHOD .*/ENCRYPT_METHOD $var_password_hashing_algorithm/g" /etc/login.defs +# Allow multiple algorithms, but choose the first one for remediation +# +var_password_hashing_algorithm="$(echo $var_password_hashing_algorithm | cut -d \| -f 1)" + +# Strip any search characters in the key arg so that the key can be replaced without +# adding any search characters to the config file. +stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^ENCRYPT_METHOD") + +# shellcheck disable=SC2059 +printf -v formatted_output "%s %s" "$stripped_key" "$var_password_hashing_algorithm" + +# If the key exists, change it. Otherwise, add it to the config_file. +# We search for the key string followed by a word boundary (matched by \>), +# so if we search for 'setting', 'setting2' won't match. +if LC_ALL=C grep -q -m 1 -i -e "^ENCRYPT_METHOD\\>" "/etc/login.defs"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + LC_ALL=C sed -i --follow-symlinks "s/^ENCRYPT_METHOD\\>.*/$escaped_formatted_output/gi" "/etc/login.defs" else - echo "" >> /etc/login.defs - echo "ENCRYPT_METHOD $var_password_hashing_algorithm" >> /etc/login.defs + if [[ -s "/etc/login.defs" ]] && [[ -n "$(tail -c 1 -- "/etc/login.defs" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "/etc/login.defs" + fi + printf '%s\n' "$formatted_output" >> "/etc/login.defs" fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: - CJIS-5.6.2.2 + - DISA-STIG-OL09-00-001055 - NIST-800-171-3.13.11 - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(1)(c) - NIST-800-53-IA-5(c) - PCI-DSS-Req-8.2.1 + - PCI-DSSv4-8.3 - PCI-DSSv4-8.3.2 - low_complexity - low_disruption @@ -29241,7 +33387,7 @@ fi - set_password_hashing_algorithm_logindefs - name: XCCDF Value var_password_hashing_algorithm # promote to variable set_fact: - var_password_hashing_algorithm: !!str + var_password_hashing_algorithm: !!str tags: - always @@ -29249,17 +33395,19 @@ fi lineinfile: dest: /etc/login.defs regexp: ^#?ENCRYPT_METHOD - line: ENCRYPT_METHOD {{ var_password_hashing_algorithm }} + line: ENCRYPT_METHOD {{ var_password_hashing_algorithm.split('|')[0] }} state: present create: true when: '"shadow-utils" in ansible_facts.packages' tags: - CJIS-5.6.2.2 + - DISA-STIG-OL09-00-001055 - NIST-800-171-3.13.11 - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(1)(c) - NIST-800-53-IA-5(c) - PCI-DSS-Req-8.2.1 + - PCI-DSSv4-8.3 - PCI-DSSv4-8.3.2 - low_complexity - low_disruption @@ -29267,110 +33415,122 @@ fi - no_reboot_needed - restrict_strategy - set_password_hashing_algorithm_logindefs - - - - - - - - - - - Set PAM''s Password Hashing Algorithm - password-auth - The PAM system service can be configured to only store encrypted -representations of passwords. In -/etc/pam.d/password-auth, -the -password section of the file controls which PAM modules execute -during a password change. Set the pam_unix.so module in the -password section to include the argument sha512, as shown -below: - -password sufficient pam_unix.so sha512 other arguments... - -This will help ensure when local users change their passwords, hashes for -the new passwords will be generated using the SHA-512 algorithm. This is -the default. - BP28(R32) - 1 - 12 - 15 - 16 - 5 - 5.6.2.2 - DSS05.04 - DSS05.05 - DSS05.07 - DSS05.10 - DSS06.03 - DSS06.10 - 3.13.11 - CCI-000196 - CCI-000803 - 4.3.3.2.2 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.2 - 4.3.3.7.4 - SR 1.1 - SR 1.10 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - 0418 - 1055 - 1402 - A.18.1.4 - A.7.1.1 - A.9.2.1 - A.9.2.2 - A.9.2.3 - A.9.2.4 - A.9.2.6 - A.9.3.1 - A.9.4.2 - A.9.4.3 - IA-5(c) - IA-5(1)(c) - CM-6(a) - PR.AC-1 - PR.AC-6 - PR.AC-7 - Req-8.2.1 - SRG-OS-000073-GPOS-00041 - SRG-OS-000120-GPOS-00061 - Passwords need to be protected at all times, and encryption is the standard -method for protecting passwords. If passwords are not encrypted, they can -be plainly read (i.e., clear text) and easily compromised. Passwords that -are encrypted with a weak algorithm are no more protected than if they are -kepy in plain text. - -This setting ensures user and group account administration utilities are -configured to store only encrypted representations of passwords. -Additionally, the crypt_style configuration option ensures the use -of a strong hashing algorithm that makes password cracking attacks more -difficult. - - # Remediation is applicable only in certain platforms + + + + + + + + + + + Set PAM''s Password Hashing Algorithm - password-auth + The PAM system service can be configured to only store encrypted representations of passwords. +In /etc/pam.d/password-auth, the password section of the file controls which +PAM modules to execute during a password change. + +Set the pam_unix.so module in the password section to include the option + and no other hashing +algorithms as shown below: + + password sufficient pam_unix.so + other arguments... + + +This will help ensure that new passwords for local users will be stored using the + algorithm. + The hashing algorithms to be used with pam_unix.so are defined with independent module +options. There are at least 7 possible algorithms and likely more algorithms will be +introduced along the time. Due the the number of options and its possible combinations, +the use of multiple hashing algorithm options may bring unexpected behaviors to the +system. For this reason the check will pass only when one hashing algorithm option is +defined and is aligned to the "var_password_hashing_algorithm_pam" variable. The +remediation will ensure the correct option and remove any other extra hashing algorithm +option. + 1 + 12 + 15 + 16 + 5 + 5.6.2.2 + DSS05.04 + DSS05.05 + DSS05.07 + DSS05.10 + DSS06.03 + DSS06.10 + 3.13.11 + CCI-004062 + 4.3.3.2.2 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.2 + 4.3.3.7.4 + SR 1.1 + SR 1.10 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + 0418 + 1055 + 1402 + A.18.1.4 + A.7.1.1 + A.9.2.1 + A.9.2.2 + A.9.2.3 + A.9.2.4 + A.9.2.6 + A.9.3.1 + A.9.4.2 + A.9.4.3 + IA-5(c) + IA-5(1)(c) + CM-6(a) + PR.AC-1 + PR.AC-6 + PR.AC-7 + Req-8.2.1 + SRG-OS-000073-GPOS-00041 + SRG-OS-000120-GPOS-00061 + A.19.SEC-OL3 + OL09-00-001060 + SV-271624r1091584_rule + Passwords need to be protected at all times, and encryption is the standard method for +protecting passwords. If passwords are not encrypted, they can be plainly read +(i.e., clear text) and easily compromised. Passwords that are encrypted with a weak algorithm +are no more protected than if they are kept in plain text. + + +This setting ensures user and group account administration utilities are configured to store +only encrypted representations of passwords. Additionally, the crypt_style +configuration option in /etc/libuser.conf ensures the use of a strong hashing +algorithm that makes password cracking attacks more difficult. + + # Remediation is applicable only in certain platforms if rpm --quiet -q pam; then -if [ -e "/etc/pam.d/password-auth" ] ; then - PAM_FILE_PATH="/etc/pam.d/password-auth" +var_password_hashing_algorithm_pam='' + +PAM_FILE_PATH="/etc/pam.d/password-auth" + +if [ -e "$PAM_FILE_PATH" ] ; then + PAM_FILE_PATH="$PAM_FILE_PATH" if [ -f /usr/bin/authselect ]; then if ! authselect check; then @@ -29386,6 +33546,11 @@ if [ -e "/etc/pam.d/password-auth" ] ; then # If not already in use, a custom profile is created preserving the enabled features. if [[ ! $CURRENT_PROFILE == custom/* ]]; then ENABLED_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }') + # The "local" profile does not contain essential security features required by multiple Benchmarks. + # If currently used, it is replaced by "sssd", which is the best option in this case. + if [[ $CURRENT_PROFILE == local ]]; then + CURRENT_PROFILE="sssd" + fi authselect create-profile hardening -b $CURRENT_PROFILE CURRENT_PROFILE="custom/hardening" @@ -29397,41 +33562,103 @@ if [ -e "/etc/pam.d/password-auth" ] ; then authselect apply-changes -b --backup=after-hardening-custom-profile fi - PAM_FILE_NAME=$(basename "/etc/pam.d/password-auth") + PAM_FILE_NAME=$(basename "$PAM_FILE_PATH") PAM_FILE_PATH="/etc/authselect/$CURRENT_PROFILE/$PAM_FILE_NAME" authselect apply-changes -b fi - if ! grep -qP '^\s*password\s+'"sufficient"'\s+pam_unix.so\s*.*' "$PAM_FILE_PATH"; then + + + if ! grep -qP "^\s*password\s+sufficient\s+pam_unix.so\s*.*" "$PAM_FILE_PATH"; then # Line matching group + control + module was not found. Check group + module. if [ "$(grep -cP '^\s*password\s+.*\s+pam_unix.so\s*' "$PAM_FILE_PATH")" -eq 1 ]; then # The control is updated only if one single line matches. - sed -i -E --follow-symlinks 's/^(\s*password\s+).*(\bpam_unix.so.*)/\1'"sufficient"' \2/' "$PAM_FILE_PATH" + sed -i -E --follow-symlinks "s/^(\s*password\s+).*(\bpam_unix.so.*)/\1sufficient \2/" "$PAM_FILE_PATH" else - echo 'password '"sufficient"' pam_unix.so' >> "$PAM_FILE_PATH" + echo "password sufficient pam_unix.so" >> "$PAM_FILE_PATH" fi fi # Check the option - if ! grep -qP '^\s*password\s+'"sufficient"'\s+pam_unix.so\s*.*\ssha512\b' "$PAM_FILE_PATH"; then - sed -i -E --follow-symlinks '/\s*password\s+'"sufficient"'\s+pam_unix.so.*/ s/$/ sha512/' "$PAM_FILE_PATH" + if ! grep -qP "^\s*password\s+sufficient\s+pam_unix.so\s*.*\s$var_password_hashing_algorithm_pam\b" "$PAM_FILE_PATH"; then + sed -i -E --follow-symlinks "/\s*password\s+sufficient\s+pam_unix.so.*/ s/$/ $var_password_hashing_algorithm_pam/" "$PAM_FILE_PATH" fi if [ -f /usr/bin/authselect ]; then authselect apply-changes -b fi else - echo "/etc/pam.d/password-auth was not found" >&2 + echo "$PAM_FILE_PATH was not found" >&2 fi +# Ensure only the correct hashing algorithm option is used. +declare -a HASHING_ALGORITHMS_OPTIONS=("sha512" "yescrypt" "gost_yescrypt" "blowfish" "sha256" "md5" "bigcrypt") + +for hash_option in "${HASHING_ALGORITHMS_OPTIONS[@]}"; do + if [ "$hash_option" != "$var_password_hashing_algorithm_pam" ]; then + if grep -qP "^\s*password\s+.*\s+pam_unix.so\s+.*\b$hash_option\b" "$PAM_FILE_PATH"; then + if [ -e "$PAM_FILE_PATH" ] ; then + PAM_FILE_PATH="$PAM_FILE_PATH" + if [ -f /usr/bin/authselect ]; then + + if ! authselect check; then + echo " + authselect integrity check failed. Remediation aborted! + This remediation could not be applied because an authselect profile was not selected or the selected profile is not intact. + It is not recommended to manually edit the PAM files when authselect tool is available. + In cases where the default authselect profile does not cover a specific demand, a custom authselect profile is recommended." + exit 1 + fi + + CURRENT_PROFILE=$(authselect current -r | awk '{ print $1 }') + # If not already in use, a custom profile is created preserving the enabled features. + if [[ ! $CURRENT_PROFILE == custom/* ]]; then + ENABLED_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }') + # The "local" profile does not contain essential security features required by multiple Benchmarks. + # If currently used, it is replaced by "sssd", which is the best option in this case. + if [[ $CURRENT_PROFILE == local ]]; then + CURRENT_PROFILE="sssd" + fi + authselect create-profile hardening -b $CURRENT_PROFILE + CURRENT_PROFILE="custom/hardening" + + authselect apply-changes -b --backup=before-hardening-custom-profile + authselect select $CURRENT_PROFILE + for feature in $ENABLED_FEATURES; do + authselect enable-feature $feature; + done + + authselect apply-changes -b --backup=after-hardening-custom-profile + fi + PAM_FILE_NAME=$(basename "$PAM_FILE_PATH") + PAM_FILE_PATH="/etc/authselect/$CURRENT_PROFILE/$PAM_FILE_NAME" + + authselect apply-changes -b + fi + +if grep -qP "^\s*password\s+.*\s+pam_unix.so\s.*\b$hash_option\b" "$PAM_FILE_PATH"; then + sed -i -E --follow-symlinks "s/(.*password.*.*.*pam_unix.so.*)\s$hash_option=?[[:alnum:]]*(.*)/\1\2/g" "$PAM_FILE_PATH" +fi + if [ -f /usr/bin/authselect ]; then + + authselect apply-changes -b + fi +else + echo "$PAM_FILE_PATH was not found" >&2 +fi + fi + fi +done + else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: - CJIS-5.6.2.2 + - DISA-STIG-OL09-00-001060 - NIST-800-171-3.13.11 - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(1)(c) @@ -29443,6 +33670,11 @@ fi - medium_severity - no_reboot_needed - set_password_hashing_algorithm_passwordauth +- name: XCCDF Value var_password_hashing_algorithm_pam # promote to variable + set_fact: + var_password_hashing_algorithm_pam: !!str + tags: + - always - name: Set PAM's Password Hashing Algorithm - password-auth - Check if /etc/pam.d/password-auth file is present @@ -29452,6 +33684,7 @@ fi when: '"pam" in ansible_facts.packages' tags: - CJIS-5.6.2.2 + - DISA-STIG-OL09-00-001060 - NIST-800-171-3.13.11 - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(1)(c) @@ -29560,7 +33793,16 @@ fi }} when: - result_authselect_check_cmd is success - - authselect_current_profile is not match("custom/") + - authselect_current_profile is not match("^(custom/|local)") + - not result_authselect_custom_profile_present.stat.exists + + - name: Set PAM's Password Hashing Algorithm - password-auth - Create an authselect + custom profile based on sssd profile + ansible.builtin.command: + cmd: authselect create-profile hardening -b sssd + when: + - result_authselect_check_cmd is success + - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists - name: Set PAM's Password Hashing Algorithm - password-auth - Ensure authselect @@ -29612,11 +33854,16 @@ fi when: - result_authselect_present.stat.exists + - name: Set PAM's Password Hashing Algorithm - password-auth - Define a fact for + control already filtered in case filters are used + ansible.builtin.set_fact: + pam_module_control: sufficient + - name: Set PAM's Password Hashing Algorithm - password-auth - Check if expected PAM module line is present in {{ pam_file_path }} ansible.builtin.lineinfile: path: '{{ pam_file_path }}' - regexp: ^\s*password\s+sufficient\s+pam_unix.so\s*.* + regexp: ^\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_unix.so\s*.* state: absent check_mode: true changed_when: false @@ -29641,7 +33888,7 @@ fi ansible.builtin.replace: dest: '{{ pam_file_path }}' regexp: ^(\s*password\s+).*(\bpam_unix.so.*) - replace: \1sufficient \2 + replace: \1{{ pam_module_control }} \2 register: result_pam_module_edit when: - result_pam_line_other_control_present.found == 1 @@ -29650,7 +33897,7 @@ fi PAM module line is included in {{ pam_file_path }} ansible.builtin.lineinfile: dest: '{{ pam_file_path }}' - line: password sufficient pam_unix.so + line: password {{ pam_module_control }} pam_unix.so register: result_pam_module_add when: - result_pam_line_other_control_present.found == 0 or result_pam_line_other_control_present.found @@ -29670,27 +33917,34 @@ fi - result_pam_line_present.found is defined - result_pam_line_present.found == 0 + - name: Set PAM's Password Hashing Algorithm - password-auth - Define a fact for + control already filtered in case filters are used + ansible.builtin.set_fact: + pam_module_control: sufficient + - name: Set PAM's Password Hashing Algorithm - password-auth - Check if the required PAM module option is present in {{ pam_file_path }} ansible.builtin.lineinfile: path: '{{ pam_file_path }}' - regexp: ^\s*password\s+sufficient\s+pam_unix.so\s*.*\ssha512\b + regexp: ^\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_unix.so\s*.*\s{{ + var_password_hashing_algorithm_pam }}\b state: absent check_mode: true changed_when: false - register: result_pam_module_sha512_option_present + register: result_pam_module_set_password_hashing_algorithm_passwordauth_option_present - - name: Set PAM's Password Hashing Algorithm - password-auth - Ensure the "sha512" - PAM option for "pam_unix.so" is included in {{ pam_file_path }} + - name: Set PAM's Password Hashing Algorithm - password-auth - Ensure the "{{ var_password_hashing_algorithm_pam + }}" PAM option for "pam_unix.so" is included in {{ pam_file_path }} ansible.builtin.lineinfile: path: '{{ pam_file_path }}' backrefs: true - regexp: ^(\s*password\s+sufficient\s+pam_unix.so.*) - line: \1 sha512 + regexp: ^(\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_unix.so.*) + line: \1 {{ var_password_hashing_algorithm_pam }} state: present - register: result_pam_sha512_add + register: result_pam_set_password_hashing_algorithm_passwordauth_add when: - - result_pam_module_sha512_option_present.found == 0 + - result_pam_module_set_password_hashing_algorithm_passwordauth_option_present.found + == 0 - name: Set PAM's Password Hashing Algorithm - password-auth - Ensure authselect changes are applied @@ -29699,13 +33953,14 @@ fi when: - result_authselect_present.stat.exists - |- - (result_pam_sha512_add is defined and result_pam_sha512_add.changed) - or (result_pam_sha512_edit is defined and result_pam_sha512_edit.changed) + (result_pam_set_password_hashing_algorithm_passwordauth_add is defined and result_pam_set_password_hashing_algorithm_passwordauth_add.changed) + or (result_pam_set_password_hashing_algorithm_passwordauth_edit is defined and result_pam_set_password_hashing_algorithm_passwordauth_edit.changed) when: - '"pam" in ansible_facts.packages' - result_pam_file_present.stat.exists tags: - CJIS-5.6.2.2 + - DISA-STIG-OL09-00-001060 - NIST-800-171-3.13.11 - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(1)(c) @@ -29717,110 +33972,347 @@ fi - medium_severity - no_reboot_needed - set_password_hashing_algorithm_passwordauth - - - - - - - - - - Set PAM''s Password Hashing Algorithm - The PAM system service can be configured to only store encrypted -representations of passwords. In "/etc/pam.d/system-auth", the -password section of the file controls which PAM modules execute -during a password change. Set the pam_unix.so module in the -password section to include the argument sha512, as shown -below: - -password sufficient pam_unix.so sha512 other arguments... +- name: Set PAM's Password Hashing Algorithm - password-auth - Check if /etc/pam.d/password-auth + File is Present + ansible.builtin.stat: + path: /etc/pam.d/password-auth + register: result_pam_file_present + when: '"pam" in ansible_facts.packages' + tags: + - CJIS-5.6.2.2 + - DISA-STIG-OL09-00-001060 + - NIST-800-171-3.13.11 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(c) + - NIST-800-53-IA-5(c) + - PCI-DSS-Req-8.2.1 + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - set_password_hashing_algorithm_passwordauth - -This will help ensure when local users change their passwords, hashes for -the new passwords will be generated using the SHA-512 algorithm. This is -the default. - BP28(R32) - 1 - 12 - 15 - 16 - 5 - 5.6.2.2 - DSS05.04 - DSS05.05 - DSS05.07 - DSS05.10 - DSS06.03 - DSS06.10 - 3.13.11 - CCI-000196 - CCI-000803 - 4.3.3.2.2 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.2 - 4.3.3.7.4 - SR 1.1 - SR 1.10 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - 0418 - 1055 - 1402 - A.18.1.4 - A.7.1.1 - A.9.2.1 - A.9.2.2 - A.9.2.3 - A.9.2.4 - A.9.2.6 - A.9.3.1 - A.9.4.2 - A.9.4.3 - IA-5(c) - IA-5(1)(c) - CM-6(a) - PR.AC-1 - PR.AC-6 - PR.AC-7 - Req-8.2.1 - 8.3.2 - SRG-OS-000073-GPOS-00041 - SRG-OS-000120-GPOS-00061 - Passwords need to be protected at all times, and encryption is the standard -method for protecting passwords. If passwords are not encrypted, they can -be plainly read (i.e., clear text) and easily compromised. Passwords that -are encrypted with a weak algorithm are no more protected than if they are -kepy in plain text. - -This setting ensures user and group account administration utilities are -configured to store only encrypted representations of passwords. -Additionally, the crypt_style configuration option ensures the use -of a strong hashing algorithm that makes password cracking attacks more -difficult. - - # Remediation is applicable only in certain platforms +- name: Set PAM's Password Hashing Algorithm - password-auth - Check The Proper Remediation + For The System + block: + + - name: Set PAM's Password Hashing Algorithm - password-auth - Define the PAM file + to be edited as a local fact + ansible.builtin.set_fact: + pam_file_path: /etc/pam.d/password-auth + + - name: Set PAM's Password Hashing Algorithm - password-auth - Check if system relies + on authselect tool + ansible.builtin.stat: + path: /usr/bin/authselect + register: result_authselect_present + + - name: Set PAM's Password Hashing Algorithm - password-auth - Ensure authselect + custom profile is used if authselect is present + block: + + - name: Set PAM's Password Hashing Algorithm - password-auth - Check integrity + of authselect current profile + ansible.builtin.command: + cmd: authselect check + register: result_authselect_check_cmd + changed_when: false + failed_when: false + + - name: Set PAM's Password Hashing Algorithm - password-auth - Informative message + based on the authselect integrity check result + ansible.builtin.assert: + that: + - result_authselect_check_cmd.rc == 0 + fail_msg: + - authselect integrity check failed. Remediation aborted! + - This remediation could not be applied because an authselect profile was + not selected or the selected profile is not intact. + - It is not recommended to manually edit the PAM files when authselect tool + is available. + - In cases where the default authselect profile does not cover a specific + demand, a custom authselect profile is recommended. + success_msg: + - authselect integrity check passed + + - name: Set PAM's Password Hashing Algorithm - password-auth - Get authselect + current profile + ansible.builtin.shell: + cmd: authselect current -r | awk '{ print $1 }' + register: result_authselect_profile + changed_when: false + when: + - result_authselect_check_cmd is success + + - name: Set PAM's Password Hashing Algorithm - password-auth - Define the current + authselect profile as a local fact + ansible.builtin.set_fact: + authselect_current_profile: '{{ result_authselect_profile.stdout }}' + authselect_custom_profile: '{{ result_authselect_profile.stdout }}' + when: + - result_authselect_profile is not skipped + - result_authselect_profile.stdout is match("custom/") + + - name: Set PAM's Password Hashing Algorithm - password-auth - Define the new + authselect custom profile as a local fact + ansible.builtin.set_fact: + authselect_current_profile: '{{ result_authselect_profile.stdout }}' + authselect_custom_profile: custom/hardening + when: + - result_authselect_profile is not skipped + - result_authselect_profile.stdout is not match("custom/") + + - name: Set PAM's Password Hashing Algorithm - password-auth - Get authselect + current features to also enable them in the custom profile + ansible.builtin.shell: + cmd: authselect current | tail -n+3 | awk '{ print $2 }' + register: result_authselect_features + changed_when: false + when: + - result_authselect_profile is not skipped + - authselect_current_profile is not match("custom/") + + - name: Set PAM's Password Hashing Algorithm - password-auth - Check if any custom + profile with the same name was already created + ansible.builtin.stat: + path: /etc/authselect/{{ authselect_custom_profile }} + register: result_authselect_custom_profile_present + changed_when: false + when: + - authselect_current_profile is not match("custom/") + + - name: Set PAM's Password Hashing Algorithm - password-auth - Create an authselect + custom profile based on the current profile + ansible.builtin.command: + cmd: authselect create-profile hardening -b {{ authselect_current_profile + }} + when: + - result_authselect_check_cmd is success + - authselect_current_profile is not match("^(custom/|local)") + - not result_authselect_custom_profile_present.stat.exists + + - name: Set PAM's Password Hashing Algorithm - password-auth - Create an authselect + custom profile based on sssd profile + ansible.builtin.command: + cmd: authselect create-profile hardening -b sssd + when: + - result_authselect_check_cmd is success + - authselect_current_profile is match("local") + - not result_authselect_custom_profile_present.stat.exists + + - name: Set PAM's Password Hashing Algorithm - password-auth - Ensure authselect + changes are applied + ansible.builtin.command: + cmd: authselect apply-changes -b --backup=before-hardening-custom-profile + when: + - result_authselect_check_cmd is success + - result_authselect_profile is not skipped + - authselect_current_profile is not match("custom/") + - authselect_custom_profile is not match(authselect_current_profile) + + - name: Set PAM's Password Hashing Algorithm - password-auth - Ensure the authselect + custom profile is selected + ansible.builtin.command: + cmd: authselect select {{ authselect_custom_profile }} + register: result_pam_authselect_select_profile + when: + - result_authselect_check_cmd is success + - result_authselect_profile is not skipped + - authselect_current_profile is not match("custom/") + - authselect_custom_profile is not match(authselect_current_profile) + + - name: Set PAM's Password Hashing Algorithm - password-auth - Restore the authselect + features in the custom profile + ansible.builtin.command: + cmd: authselect enable-feature {{ item }} + loop: '{{ result_authselect_features.stdout_lines }}' + register: result_pam_authselect_restore_features + when: + - result_authselect_profile is not skipped + - result_authselect_features is not skipped + - result_pam_authselect_select_profile is not skipped + + - name: Set PAM's Password Hashing Algorithm - password-auth - Ensure authselect + changes are applied + ansible.builtin.command: + cmd: authselect apply-changes -b --backup=after-hardening-custom-profile + when: + - result_authselect_check_cmd is success + - result_authselect_profile is not skipped + - result_pam_authselect_restore_features is not skipped + + - name: Set PAM's Password Hashing Algorithm - password-auth - Change the PAM + file to be edited according to the custom authselect profile + ansible.builtin.set_fact: + pam_file_path: /etc/authselect/{{ authselect_custom_profile }}/{{ pam_file_path + | basename }} + when: + - result_authselect_present.stat.exists + + - name: Set PAM's Password Hashing Algorithm - password-auth - Ensure That Only + the Correct Hashing Algorithm Option For pam_unix.so Is Used in /etc/pam.d/password-auth + ansible.builtin.replace: + dest: '{{ pam_file_path }}' + regexp: (^\s*password.*pam_unix\.so.*)\b{{ item }}\b\s*(.*) + replace: \1\2 + when: item != var_password_hashing_algorithm_pam + loop: + - sha512 + - yescrypt + - gost_yescrypt + - blowfish + - sha256 + - md5 + - bigcrypt + register: result_pam_hashing_options_removal + + - name: Set PAM's Password Hashing Algorithm - password-auth - Ensure authselect + changes are applied + ansible.builtin.command: + cmd: authselect apply-changes -b + when: + - result_authselect_present.stat.exists + - result_pam_hashing_options_removal is changed + when: + - '"pam" in ansible_facts.packages' + - result_pam_file_present.stat.exists + tags: + - CJIS-5.6.2.2 + - DISA-STIG-OL09-00-001060 + - NIST-800-171-3.13.11 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(c) + - NIST-800-53-IA-5(c) + - PCI-DSS-Req-8.2.1 + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - set_password_hashing_algorithm_passwordauth + + + + + + + + + + + Set PAM''s Password Hashing Algorithm + The PAM system service can be configured to only store encrypted representations of passwords. +In "/etc/pam.d/system-auth", the password section of the file controls which +PAM modules to execute during a password change. + +Set the pam_unix.so module in the password section to include the option + and no other hashing +algorithms as shown below: + + password sufficient pam_unix.so + other arguments... + + +This will help ensure that new passwords for local users will be stored using the + algorithm. + The hashing algorithms to be used with pam_unix.so are defined with independent module +options. There are at least 7 possible algorithms and likely more algorithms will be +introduced along the time. Due the the number of options and its possible combinations, +the use of multiple hashing algorithm options may bring unexpected behaviors to the +system. For this reason the check will pass only when one hashing algorithm option is +defined and is aligned to the "var_password_hashing_algorithm_pam" variable. The +remediation will ensure the correct option and remove any other extra hashing algorithm +option. + 1 + 12 + 15 + 16 + 5 + 5.6.2.2 + DSS05.04 + DSS05.05 + DSS05.07 + DSS05.10 + DSS06.03 + DSS06.10 + 3.13.11 + CCI-000196 + CCI-000803 + CCI-004062 + 4.3.3.2.2 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.2 + 4.3.3.7.4 + SR 1.1 + SR 1.10 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + 0418 + 1055 + 1402 + A.18.1.4 + A.7.1.1 + A.9.2.1 + A.9.2.2 + A.9.2.3 + A.9.2.4 + A.9.2.6 + A.9.3.1 + A.9.4.2 + A.9.4.3 + IA-5(c) + IA-5(1)(c) + CM-6(a) + PR.AC-1 + PR.AC-6 + PR.AC-7 + Req-8.2.1 + SRG-OS-000073-GPOS-00041 + SRG-OS-000120-GPOS-00061 + R68 + A.19.SEC-OL3 + 8.3.2 + 8.3 + Passwords need to be protected at all times, and encryption is the standard method for +protecting passwords. If passwords are not encrypted, they can be plainly read +(i.e., clear text) and easily compromised. Passwords that are encrypted with a weak algorithm +are no more protected than if they are kept in plain text. + + +This setting ensures user and group account administration utilities are configured to store +only encrypted representations of passwords. Additionally, the crypt_style +configuration option in /etc/libuser.conf ensures the use of a strong hashing +algorithm that makes password cracking attacks more difficult. + + # Remediation is applicable only in certain platforms if rpm --quiet -q pam; then -if [ -e "/etc/pam.d/system-auth" ] ; then - PAM_FILE_PATH="/etc/pam.d/system-auth" +var_password_hashing_algorithm_pam='' + + +PAM_FILE_PATH="/etc/pam.d/system-auth" + + +if [ -e "$PAM_FILE_PATH" ] ; then + PAM_FILE_PATH="$PAM_FILE_PATH" if [ -f /usr/bin/authselect ]; then if ! authselect check; then @@ -29836,6 +34328,11 @@ if [ -e "/etc/pam.d/system-auth" ] ; then # If not already in use, a custom profile is created preserving the enabled features. if [[ ! $CURRENT_PROFILE == custom/* ]]; then ENABLED_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }') + # The "local" profile does not contain essential security features required by multiple Benchmarks. + # If currently used, it is replaced by "sssd", which is the best option in this case. + if [[ $CURRENT_PROFILE == local ]]; then + CURRENT_PROFILE="sssd" + fi authselect create-profile hardening -b $CURRENT_PROFILE CURRENT_PROFILE="custom/hardening" @@ -29847,37 +34344,98 @@ if [ -e "/etc/pam.d/system-auth" ] ; then authselect apply-changes -b --backup=after-hardening-custom-profile fi - PAM_FILE_NAME=$(basename "/etc/pam.d/system-auth") + PAM_FILE_NAME=$(basename "$PAM_FILE_PATH") PAM_FILE_PATH="/etc/authselect/$CURRENT_PROFILE/$PAM_FILE_NAME" authselect apply-changes -b fi - if ! grep -qP '^\s*password\s+'"sufficient"'\s+pam_unix.so\s*.*' "$PAM_FILE_PATH"; then + + + if ! grep -qP "^\s*password\s+sufficient\s+pam_unix.so\s*.*" "$PAM_FILE_PATH"; then # Line matching group + control + module was not found. Check group + module. if [ "$(grep -cP '^\s*password\s+.*\s+pam_unix.so\s*' "$PAM_FILE_PATH")" -eq 1 ]; then # The control is updated only if one single line matches. - sed -i -E --follow-symlinks 's/^(\s*password\s+).*(\bpam_unix.so.*)/\1'"sufficient"' \2/' "$PAM_FILE_PATH" + sed -i -E --follow-symlinks "s/^(\s*password\s+).*(\bpam_unix.so.*)/\1sufficient \2/" "$PAM_FILE_PATH" else - echo 'password '"sufficient"' pam_unix.so' >> "$PAM_FILE_PATH" + echo "password sufficient pam_unix.so" >> "$PAM_FILE_PATH" fi fi # Check the option - if ! grep -qP '^\s*password\s+'"sufficient"'\s+pam_unix.so\s*.*\ssha512\b' "$PAM_FILE_PATH"; then - sed -i -E --follow-symlinks '/\s*password\s+'"sufficient"'\s+pam_unix.so.*/ s/$/ sha512/' "$PAM_FILE_PATH" + if ! grep -qP "^\s*password\s+sufficient\s+pam_unix.so\s*.*\s$var_password_hashing_algorithm_pam\b" "$PAM_FILE_PATH"; then + sed -i -E --follow-symlinks "/\s*password\s+sufficient\s+pam_unix.so.*/ s/$/ $var_password_hashing_algorithm_pam/" "$PAM_FILE_PATH" fi if [ -f /usr/bin/authselect ]; then authselect apply-changes -b fi else - echo "/etc/pam.d/system-auth was not found" >&2 + echo "$PAM_FILE_PATH was not found" >&2 fi +# Ensure only the correct hashing algorithm option is used. +declare -a HASHING_ALGORITHMS_OPTIONS=("sha512" "yescrypt" "gost_yescrypt" "blowfish" "sha256" "md5" "bigcrypt") + +for hash_option in "${HASHING_ALGORITHMS_OPTIONS[@]}"; do + if [ "$hash_option" != "$var_password_hashing_algorithm_pam" ]; then + if grep -qP "^\s*password\s+.*\s+pam_unix.so\s+.*\b$hash_option\b" "$PAM_FILE_PATH"; then + if [ -e "$PAM_FILE_PATH" ] ; then + PAM_FILE_PATH="$PAM_FILE_PATH" + if [ -f /usr/bin/authselect ]; then + + if ! authselect check; then + echo " + authselect integrity check failed. Remediation aborted! + This remediation could not be applied because an authselect profile was not selected or the selected profile is not intact. + It is not recommended to manually edit the PAM files when authselect tool is available. + In cases where the default authselect profile does not cover a specific demand, a custom authselect profile is recommended." + exit 1 + fi + + CURRENT_PROFILE=$(authselect current -r | awk '{ print $1 }') + # If not already in use, a custom profile is created preserving the enabled features. + if [[ ! $CURRENT_PROFILE == custom/* ]]; then + ENABLED_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }') + # The "local" profile does not contain essential security features required by multiple Benchmarks. + # If currently used, it is replaced by "sssd", which is the best option in this case. + if [[ $CURRENT_PROFILE == local ]]; then + CURRENT_PROFILE="sssd" + fi + authselect create-profile hardening -b $CURRENT_PROFILE + CURRENT_PROFILE="custom/hardening" + + authselect apply-changes -b --backup=before-hardening-custom-profile + authselect select $CURRENT_PROFILE + for feature in $ENABLED_FEATURES; do + authselect enable-feature $feature; + done + + authselect apply-changes -b --backup=after-hardening-custom-profile + fi + PAM_FILE_NAME=$(basename "$PAM_FILE_PATH") + PAM_FILE_PATH="/etc/authselect/$CURRENT_PROFILE/$PAM_FILE_NAME" + + authselect apply-changes -b + fi + +if grep -qP "^\s*password\s+.*\s+pam_unix.so\s.*\b$hash_option\b" "$PAM_FILE_PATH"; then + sed -i -E --follow-symlinks "s/(.*password.*.*.*pam_unix.so.*)\s$hash_option=?[[:alnum:]]*(.*)/\1\2/g" "$PAM_FILE_PATH" +fi + if [ -f /usr/bin/authselect ]; then + + authselect apply-changes -b + fi +else + echo "$PAM_FILE_PATH was not found" >&2 +fi + fi + fi +done + else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: @@ -29887,6 +34445,7 @@ fi - NIST-800-53-IA-5(1)(c) - NIST-800-53-IA-5(c) - PCI-DSS-Req-8.2.1 + - PCI-DSSv4-8.3 - PCI-DSSv4-8.3.2 - configure_strategy - low_complexity @@ -29894,6 +34453,11 @@ fi - medium_severity - no_reboot_needed - set_password_hashing_algorithm_systemauth +- name: XCCDF Value var_password_hashing_algorithm_pam # promote to variable + set_fact: + var_password_hashing_algorithm_pam: !!str + tags: + - always - name: Set PAM's Password Hashing Algorithm - Check if /etc/pam.d/system-auth file is present @@ -29908,6 +34472,7 @@ fi - NIST-800-53-IA-5(1)(c) - NIST-800-53-IA-5(c) - PCI-DSS-Req-8.2.1 + - PCI-DSSv4-8.3 - PCI-DSSv4-8.3.2 - configure_strategy - low_complexity @@ -30011,7 +34576,16 @@ fi }} when: - result_authselect_check_cmd is success - - authselect_current_profile is not match("custom/") + - authselect_current_profile is not match("^(custom/|local)") + - not result_authselect_custom_profile_present.stat.exists + + - name: Set PAM's Password Hashing Algorithm - Create an authselect custom profile + based on sssd profile + ansible.builtin.command: + cmd: authselect create-profile hardening -b sssd + when: + - result_authselect_check_cmd is success + - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists - name: Set PAM's Password Hashing Algorithm - Ensure authselect changes are applied @@ -30061,11 +34635,16 @@ fi when: - result_authselect_present.stat.exists + - name: Set PAM's Password Hashing Algorithm - Define a fact for control already + filtered in case filters are used + ansible.builtin.set_fact: + pam_module_control: sufficient + - name: Set PAM's Password Hashing Algorithm - Check if expected PAM module line is present in {{ pam_file_path }} ansible.builtin.lineinfile: path: '{{ pam_file_path }}' - regexp: ^\s*password\s+sufficient\s+pam_unix.so\s*.* + regexp: ^\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_unix.so\s*.* state: absent check_mode: true changed_when: false @@ -30090,7 +34669,7 @@ fi ansible.builtin.replace: dest: '{{ pam_file_path }}' regexp: ^(\s*password\s+).*(\bpam_unix.so.*) - replace: \1sufficient \2 + replace: \1{{ pam_module_control }} \2 register: result_pam_module_edit when: - result_pam_line_other_control_present.found == 1 @@ -30099,7 +34678,7 @@ fi line is included in {{ pam_file_path }} ansible.builtin.lineinfile: dest: '{{ pam_file_path }}' - line: password sufficient pam_unix.so + line: password {{ pam_module_control }} pam_unix.so register: result_pam_module_add when: - result_pam_line_other_control_present.found == 0 or result_pam_line_other_control_present.found @@ -30118,27 +34697,34 @@ fi - result_pam_line_present.found is defined - result_pam_line_present.found == 0 + - name: Set PAM's Password Hashing Algorithm - Define a fact for control already + filtered in case filters are used + ansible.builtin.set_fact: + pam_module_control: sufficient + - name: Set PAM's Password Hashing Algorithm - Check if the required PAM module option is present in {{ pam_file_path }} ansible.builtin.lineinfile: path: '{{ pam_file_path }}' - regexp: ^\s*password\s+sufficient\s+pam_unix.so\s*.*\ssha512\b + regexp: ^\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_unix.so\s*.*\s{{ + var_password_hashing_algorithm_pam }}\b state: absent check_mode: true changed_when: false - register: result_pam_module_sha512_option_present + register: result_pam_module_set_password_hashing_algorithm_systemauth_option_present - - name: Set PAM's Password Hashing Algorithm - Ensure the "sha512" PAM option for - "pam_unix.so" is included in {{ pam_file_path }} + - name: Set PAM's Password Hashing Algorithm - Ensure the "{{ var_password_hashing_algorithm_pam + }}" PAM option for "pam_unix.so" is included in {{ pam_file_path }} ansible.builtin.lineinfile: path: '{{ pam_file_path }}' backrefs: true - regexp: ^(\s*password\s+sufficient\s+pam_unix.so.*) - line: \1 sha512 + regexp: ^(\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_unix.so.*) + line: \1 {{ var_password_hashing_algorithm_pam }} state: present - register: result_pam_sha512_add + register: result_pam_set_password_hashing_algorithm_systemauth_add when: - - result_pam_module_sha512_option_present.found == 0 + - result_pam_module_set_password_hashing_algorithm_systemauth_option_present.found + == 0 - name: Set PAM's Password Hashing Algorithm - Ensure authselect changes are applied ansible.builtin.command: @@ -30146,8 +34732,8 @@ fi when: - result_authselect_present.stat.exists - |- - (result_pam_sha512_add is defined and result_pam_sha512_add.changed) - or (result_pam_sha512_edit is defined and result_pam_sha512_edit.changed) + (result_pam_set_password_hashing_algorithm_systemauth_add is defined and result_pam_set_password_hashing_algorithm_systemauth_add.changed) + or (result_pam_set_password_hashing_algorithm_systemauth_edit is defined and result_pam_set_password_hashing_algorithm_systemauth_edit.changed) when: - '"pam" in ansible_facts.packages' - result_pam_file_present.stat.exists @@ -30158,6 +34744,7 @@ fi - NIST-800-53-IA-5(1)(c) - NIST-800-53-IA-5(c) - PCI-DSS-Req-8.2.1 + - PCI-DSSv4-8.3 - PCI-DSSv4-8.3.2 - configure_strategy - low_complexity @@ -30165,60 +34752,363 @@ fi - medium_severity - no_reboot_needed - set_password_hashing_algorithm_systemauth - - - - - - - - - - Set Password Hashing Rounds in /etc/login.defs - In /etc/login.defs, ensure SHA_CRYPT_MIN_ROUNDS and -SHA_CRYPT_MAX_ROUNDS has the minimum value of 5000. + +- name: Set PAM's Password Hashing Algorithm - Check if /etc/pam.d/system-auth File + is Present + ansible.builtin.stat: + path: /etc/pam.d/system-auth + register: result_pam_file_present + when: '"pam" in ansible_facts.packages' + tags: + - CJIS-5.6.2.2 + - NIST-800-171-3.13.11 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(c) + - NIST-800-53-IA-5(c) + - PCI-DSS-Req-8.2.1 + - PCI-DSSv4-8.3 + - PCI-DSSv4-8.3.2 + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - set_password_hashing_algorithm_systemauth + +- name: Set PAM's Password Hashing Algorithm - Check The Proper Remediation For The + System + block: + + - name: Set PAM's Password Hashing Algorithm - Define the PAM file to be edited + as a local fact + ansible.builtin.set_fact: + pam_file_path: /etc/pam.d/system-auth + + - name: Set PAM's Password Hashing Algorithm - Check if system relies on authselect + tool + ansible.builtin.stat: + path: /usr/bin/authselect + register: result_authselect_present + + - name: Set PAM's Password Hashing Algorithm - Ensure authselect custom profile + is used if authselect is present + block: + + - name: Set PAM's Password Hashing Algorithm - Check integrity of authselect current + profile + ansible.builtin.command: + cmd: authselect check + register: result_authselect_check_cmd + changed_when: false + failed_when: false + + - name: Set PAM's Password Hashing Algorithm - Informative message based on the + authselect integrity check result + ansible.builtin.assert: + that: + - result_authselect_check_cmd.rc == 0 + fail_msg: + - authselect integrity check failed. Remediation aborted! + - This remediation could not be applied because an authselect profile was + not selected or the selected profile is not intact. + - It is not recommended to manually edit the PAM files when authselect tool + is available. + - In cases where the default authselect profile does not cover a specific + demand, a custom authselect profile is recommended. + success_msg: + - authselect integrity check passed + + - name: Set PAM's Password Hashing Algorithm - Get authselect current profile + ansible.builtin.shell: + cmd: authselect current -r | awk '{ print $1 }' + register: result_authselect_profile + changed_when: false + when: + - result_authselect_check_cmd is success + + - name: Set PAM's Password Hashing Algorithm - Define the current authselect profile + as a local fact + ansible.builtin.set_fact: + authselect_current_profile: '{{ result_authselect_profile.stdout }}' + authselect_custom_profile: '{{ result_authselect_profile.stdout }}' + when: + - result_authselect_profile is not skipped + - result_authselect_profile.stdout is match("custom/") + + - name: Set PAM's Password Hashing Algorithm - Define the new authselect custom + profile as a local fact + ansible.builtin.set_fact: + authselect_current_profile: '{{ result_authselect_profile.stdout }}' + authselect_custom_profile: custom/hardening + when: + - result_authselect_profile is not skipped + - result_authselect_profile.stdout is not match("custom/") + + - name: Set PAM's Password Hashing Algorithm - Get authselect current features + to also enable them in the custom profile + ansible.builtin.shell: + cmd: authselect current | tail -n+3 | awk '{ print $2 }' + register: result_authselect_features + changed_when: false + when: + - result_authselect_profile is not skipped + - authselect_current_profile is not match("custom/") + + - name: Set PAM's Password Hashing Algorithm - Check if any custom profile with + the same name was already created + ansible.builtin.stat: + path: /etc/authselect/{{ authselect_custom_profile }} + register: result_authselect_custom_profile_present + changed_when: false + when: + - authselect_current_profile is not match("custom/") + + - name: Set PAM's Password Hashing Algorithm - Create an authselect custom profile + based on the current profile + ansible.builtin.command: + cmd: authselect create-profile hardening -b {{ authselect_current_profile + }} + when: + - result_authselect_check_cmd is success + - authselect_current_profile is not match("^(custom/|local)") + - not result_authselect_custom_profile_present.stat.exists + + - name: Set PAM's Password Hashing Algorithm - Create an authselect custom profile + based on sssd profile + ansible.builtin.command: + cmd: authselect create-profile hardening -b sssd + when: + - result_authselect_check_cmd is success + - authselect_current_profile is match("local") + - not result_authselect_custom_profile_present.stat.exists + + - name: Set PAM's Password Hashing Algorithm - Ensure authselect changes are applied + ansible.builtin.command: + cmd: authselect apply-changes -b --backup=before-hardening-custom-profile + when: + - result_authselect_check_cmd is success + - result_authselect_profile is not skipped + - authselect_current_profile is not match("custom/") + - authselect_custom_profile is not match(authselect_current_profile) + + - name: Set PAM's Password Hashing Algorithm - Ensure the authselect custom profile + is selected + ansible.builtin.command: + cmd: authselect select {{ authselect_custom_profile }} + register: result_pam_authselect_select_profile + when: + - result_authselect_check_cmd is success + - result_authselect_profile is not skipped + - authselect_current_profile is not match("custom/") + - authselect_custom_profile is not match(authselect_current_profile) + + - name: Set PAM's Password Hashing Algorithm - Restore the authselect features + in the custom profile + ansible.builtin.command: + cmd: authselect enable-feature {{ item }} + loop: '{{ result_authselect_features.stdout_lines }}' + register: result_pam_authselect_restore_features + when: + - result_authselect_profile is not skipped + - result_authselect_features is not skipped + - result_pam_authselect_select_profile is not skipped + + - name: Set PAM's Password Hashing Algorithm - Ensure authselect changes are applied + ansible.builtin.command: + cmd: authselect apply-changes -b --backup=after-hardening-custom-profile + when: + - result_authselect_check_cmd is success + - result_authselect_profile is not skipped + - result_pam_authselect_restore_features is not skipped + + - name: Set PAM's Password Hashing Algorithm - Change the PAM file to be edited + according to the custom authselect profile + ansible.builtin.set_fact: + pam_file_path: /etc/authselect/{{ authselect_custom_profile }}/{{ pam_file_path + | basename }} + when: + - result_authselect_present.stat.exists + + - name: Set PAM's Password Hashing Algorithm - Ensure That Only the Correct Hashing + Algorithm Option For pam_unix.so Is Used in /etc/pam.d/system-auth + ansible.builtin.replace: + dest: '{{ pam_file_path }}' + regexp: (^\s*password.*pam_unix\.so.*)\b{{ item }}\b\s*(.*) + replace: \1\2 + when: item != var_password_hashing_algorithm_pam + loop: + - sha512 + - yescrypt + - gost_yescrypt + - blowfish + - sha256 + - md5 + - bigcrypt + register: result_pam_hashing_options_removal + + - name: Set PAM's Password Hashing Algorithm - Ensure authselect changes are applied + ansible.builtin.command: + cmd: authselect apply-changes -b + when: + - result_authselect_present.stat.exists + - result_pam_hashing_options_removal is changed + when: + - '"pam" in ansible_facts.packages' + - result_pam_file_present.stat.exists + tags: + - CJIS-5.6.2.2 + - NIST-800-171-3.13.11 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(c) + - NIST-800-53-IA-5(c) + - PCI-DSS-Req-8.2.1 + - PCI-DSSv4-8.3 + - PCI-DSSv4-8.3.2 + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - set_password_hashing_algorithm_systemauth + + + + + + + + + + + Set Password Hashing Rounds in /etc/login.defs + In /etc/login.defs, ensure SHA_CRYPT_MIN_ROUNDS and +SHA_CRYPT_MAX_ROUNDS has the minimum value of . For example: -SHA_CRYPT_MIN_ROUNDS 5000 -SHA_CRYPT_MAX_ROUNDS 5000 +SHA_CRYPT_MIN_ROUNDS +SHA_CRYPT_MAX_ROUNDS + Notice that if neither are set, they already have the default value of 5000. -If either is set, they must have the minimum value of 5000. - BP28(R68) - CCI-000196 - CCI-000803 - SRG-OS-000073-GPOS-00041 - SRG-OS-000120-GPOS-00061 - Passwords need to be protected at all times, and encryption is the standard +If either is set, they must have the minimum value of . + CCI-000803 + CCI-004062 + SRG-OS-000073-GPOS-00041 + SRG-OS-000120-GPOS-00061 + OL09-00-001075 + SV-271627r1091593_rule + Passwords need to be protected at all times, and encryption is the standard method for protecting passwords. If passwords are not encrypted, they can be plainly read (i.e., clear text) and easily compromised. Passwords that are encrypted with a weak algorithm are no more protected than if they are kept in plain text. - -Using more hashing rounds makes password cracking attacks more difficult. - -if [ -e "/etc/login.defs" ] ; then - - LC_ALL=C sed -i "/^\s*SHA_CRYPT_MIN_ROUNDS\s*/Id" "/etc/login.defs" -else - printf '%s\n' "Path '/etc/login.defs' wasn't found on this system. Refusing to continue." >&2 - return 1 -fi -# make sure file has newline at the end -sed -i -e '$a\' "/etc/login.defs" + + +Using more hashing rounds makes password cracking attacks more difficult. + +var_password_hashing_min_rounds_login_defs='' -cp "/etc/login.defs" "/etc/login.defs.bak" -# Insert at the end of the file -printf '%s\n' "SHA_CRYPT_MIN_ROUNDS 5000" >> "/etc/login.defs" -# Clean up after ourselves. -rm "/etc/login.defs.bak" - - - name: Set Password Hashing Rounds in /etc/login.defs - Ensure SHA_CRYPT_MIN_ROUNDS + +config_file="/etc/login.defs" +current_min_rounds=$(grep -Po '^\s*SHA_CRYPT_MIN_ROUNDS\s+\K\d+' "$config_file") +current_max_rounds=$(grep -Po '^\s*SHA_CRYPT_MAX_ROUNDS\s+\K\d+' "$config_file") + +if [[ -z "$current_min_rounds" || "$current_min_rounds" -le "$var_password_hashing_min_rounds_login_defs" ]]; then + if [ -e "/etc/login.defs" ] ; then + + LC_ALL=C sed -i "/^\s*SHA_CRYPT_MIN_ROUNDS\s*/Id" "/etc/login.defs" + else + printf '%s\n' "Path '/etc/login.defs' wasn't found on this system. Refusing to continue." >&2 + return 1 + fi + # make sure file has newline at the end + sed -i -e '$a\' "/etc/login.defs" + + cp "/etc/login.defs" "/etc/login.defs.bak" + # Insert at the end of the file + printf '%s\n' "SHA_CRYPT_MIN_ROUNDS $var_password_hashing_min_rounds_login_defs" >> "/etc/login.defs" + # Clean up after ourselves. + rm "/etc/login.defs.bak" +fi + +if [[ -n "$current_max_rounds" && "$current_max_rounds" -le "$var_password_hashing_min_rounds_login_defs" ]]; then + if [ -e "/etc/login.defs" ] ; then + + LC_ALL=C sed -i "/^\s*SHA_CRYPT_MAX_ROUNDS\s*/Id" "/etc/login.defs" + else + printf '%s\n' "Path '/etc/login.defs' wasn't found on this system. Refusing to continue." >&2 + return 1 + fi + # make sure file has newline at the end + sed -i -e '$a\' "/etc/login.defs" + + cp "/etc/login.defs" "/etc/login.defs.bak" + # Insert at the end of the file + printf '%s\n' "SHA_CRYPT_MAX_ROUNDS $var_password_hashing_min_rounds_login_defs" >> "/etc/login.defs" + # Clean up after ourselves. + rm "/etc/login.defs.bak" +fi + + - name: XCCDF Value var_password_hashing_min_rounds_login_defs # promote to variable + set_fact: + var_password_hashing_min_rounds_login_defs: !!str + tags: + - always + +- name: Set Password Hashing Rounds in /etc/login.defs - extract contents of the file + /etc/login.defs + ansible.builtin.slurp: + src: /etc/login.defs + register: etc_login_defs + tags: + - DISA-STIG-OL09-00-001075 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - set_password_hashing_min_rounds_logindefs + +- name: Set Password Hashing Rounds in /etc/login.defs - extract the value of SHA_CRYPT_MIN_ROUNDS + if present + ansible.builtin.set_fact: + etc_login_defs_sha_crypt_min_rounds: '{{ etc_login_defs[''content''] | b64decode + | regex_search(''^\s*SHA_CRYPT_MIN_ROUNDS\s+(\d+)'', ''\1'', multiline=True) + | default([], true) }}' + tags: + - DISA-STIG-OL09-00-001075 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - set_password_hashing_min_rounds_logindefs + +- name: Set Password Hashing Rounds in /etc/login.defs - extract the value of SHA_CRYPT_MAX_ROUNDS + if present + ansible.builtin.set_fact: + etc_login_defs_sha_crypt_max_rounds: '{{ etc_login_defs[''content''] | b64decode + | regex_search(''^\s*SHA_CRYPT_MAX_ROUNDS\s+(\d+)'', ''\1'', multiline=True) + | default([], true) }}' + tags: + - DISA-STIG-OL09-00-001075 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - set_password_hashing_min_rounds_logindefs + +- name: Set Password Hashing Rounds in /etc/login.defs - Ensure SHA_CRYPT_MIN_ROUNDS has Minimum Value of 5000 ansible.builtin.replace: path: /etc/login.defs - regexp: (^\s*SHA_CRYPT_MIN_ROUNDS\s+)(?!(?:[5-9]\d{3,}|\d{5,}))\S*(\s*$) - replace: \g<1>5000\g<2> + regexp: (^\s*SHA_CRYPT_MIN_ROUNDS\s+)(?:\d+)(.*$) + replace: \g<1>{{ var_password_hashing_min_rounds_login_defs }}\g<2> backup: false + when: etc_login_defs_sha_crypt_min_rounds is defined and etc_login_defs_sha_crypt_min_rounds + | length > 0 and etc_login_defs_sha_crypt_min_rounds | first | int < var_password_hashing_min_rounds_login_defs + | int tags: + - DISA-STIG-OL09-00-001075 - low_complexity - low_disruption - medium_severity @@ -30230,90 +35120,136 @@ rm "/etc/login.defs.bak" has Minimum Value of 5000 ansible.builtin.replace: path: /etc/login.defs - regexp: (^\s*SHA_CRYPT_MAX_ROUNDS\s+)(?!(?:[5-9]\d{3,}|\d{5,}))\S*(\s*$) - replace: \g<1>5000\g<2> + regexp: (^\s*SHA_CRYPT_MAX_ROUNDS\s+)(?:\d+)(.*$) + replace: \g<1>{{ var_password_hashing_min_rounds_login_defs }}\g<2> backup: false + when: etc_login_defs_sha_crypt_max_rounds is defined and etc_login_defs_sha_crypt_max_rounds + | length > 0 and etc_login_defs_sha_crypt_max_rounds | first | int < var_password_hashing_min_rounds_login_defs + | int tags: + - DISA-STIG-OL09-00-001075 - low_complexity - low_disruption - medium_severity - no_reboot_needed - restrict_strategy - set_password_hashing_min_rounds_logindefs - - - - - - - - - - - - Protect Physical Console Access - It is impossible to fully protect a system from an + +- name: Set Password Hashing Rounds in /etc/login.defs - SHA_CRYPT_MIN_ROUNDS add + configuration if not found + ansible.builtin.lineinfile: + line: SHA_CRYPT_MIN_ROUNDS {{ var_password_hashing_min_rounds_login_defs }} + path: /etc/login.defs + state: present + when: etc_login_defs_sha_crypt_min_rounds | length == 0 + tags: + - DISA-STIG-OL09-00-001075 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - set_password_hashing_min_rounds_logindefs + +- name: Set Password Hashing Rounds in /etc/login.defs - SHA_CRYPT_MAX_ROUNDS add + configuration if not found + ansible.builtin.lineinfile: + line: SHA_CRYPT_MAX_ROUNDS {{ var_password_hashing_min_rounds_login_defs }} + path: /etc/login.defs + state: present + when: etc_login_defs_sha_crypt_max_rounds | length == 0 + tags: + - DISA-STIG-OL09-00-001075 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - set_password_hashing_min_rounds_logindefs + + + + + + + + + + + + + Protect Physical Console Access + It is impossible to fully protect a system from an attacker with physical access, so securing the space in which the system is located should be considered a necessary step. However, there are some steps which, if taken, make it more difficult for an attacker to quickly or undetectably modify a system from its -console. - - - Login timeout for idle sessions - Specify duration of allowed idle time. - 600 - 7200 - 840 - 900 - 1800 - 300 - 3600 - 300 - - - Disable debug-shell SystemD Service - SystemD's debug-shell service is intended to +console. + + + Login timeout for idle sessions + Specify duration of allowed idle time. + 600 + 7200 + 840 + 900 + 1800 + 300 + 3600 + 300 + + + Disable debug-shell SystemD Service + SystemD's debug-shell service is intended to diagnose SystemD related boot issues with various systemctl commands. Once enabled and following a system reboot, the root shell will be available on tty9 which is access by pressing CTRL-ALT-F9. The debug-shell service should only be used for SystemD related issues and should otherwise be disabled. - + + By default, the debug-shell SystemD service is already disabled. The debug-shell service can be disabled with the following command: -$ sudo systemctl mask --now debug-shell.service - 3.4.5 - CCI-000366 - 164.308(a)(1)(ii)(B) - 164.308(a)(7)(i) - 164.308(a)(7)(ii)(A) - 164.310(a)(1) - 164.310(a)(2)(i) - 164.310(a)(2)(ii) - 164.310(a)(2)(iii) - 164.310(b) - 164.310(c) - 164.310(d)(1) - 164.310(d)(2)(iii) - CM-6 - FIA_UAU.1 - SRG-OS-000324-GPOS-00125 - SRG-OS-000480-GPOS-00227 - This prevents attackers with physical access from trivially bypassing security +$ sudo systemctl mask --now debug-shell.service + + 3.4.5 + CCI-000366 + CCI-002235 + 164.308(a)(1)(ii)(B) + 164.308(a)(7)(i) + 164.308(a)(7)(ii)(A) + 164.310(a)(1) + 164.310(a)(2)(i) + 164.310(a)(2)(ii) + 164.310(a)(2)(iii) + 164.310(b) + 164.310(c) + 164.310(d)(1) + 164.310(d)(2)(iii) + CM-6 + FIA_UAU.1 + SRG-OS-000324-GPOS-00125 + SRG-OS-000480-GPOS-00227 + OL09-00-002403 + SV-271742r1091938_rule + This prevents attackers with physical access from trivially bypassing security on the machine through valid troubleshooting configurations and gaining root -access when the system is rebooted. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then +access when the system is rebooted. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then SYSTEMCTL_EXEC='/usr/bin/systemctl' -"$SYSTEMCTL_EXEC" stop 'debug-shell.service' +if [[ $("$SYSTEMCTL_EXEC" is-system-running) != "offline" ]]; then + "$SYSTEMCTL_EXEC" stop 'debug-shell.service' +fi "$SYSTEMCTL_EXEC" disable 'debug-shell.service' "$SYSTEMCTL_EXEC" mask 'debug-shell.service' # Disable socket activation if we have a unit file for it if "$SYSTEMCTL_EXEC" -q list-unit-files debug-shell.socket; then - "$SYSTEMCTL_EXEC" stop 'debug-shell.socket' + if [[ $("$SYSTEMCTL_EXEC" is-system-running) != "offline" ]]; then + "$SYSTEMCTL_EXEC" stop 'debug-shell.socket' + fi "$SYSTEMCTL_EXEC" mask 'debug-shell.socket' fi # The service may not be running because it has been started and failed, @@ -30324,26 +35260,51 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Block Disable service debug-shell - block: - - - name: Disable service debug-shell - block: - - - name: Disable service debug-shell - systemd: - name: debug-shell.service - enabled: 'no' - state: stopped - masked: 'yes' - rescue: - - - name: Intentionally ignored previous 'Disable service debug-shell' failure, - service was already disabled - meta: noop - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + + - name: Gather the package facts + package_facts: + manager: auto tags: + - DISA-STIG-OL09-00-002403 + - NIST-800-171-3.4.5 + - NIST-800-53-CM-6 + - disable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_debug-shell_disabled + +- name: Disable debug-shell SystemD Service - Collect systemd Services Present in + the System + ansible.builtin.command: systemctl -q list-unit-files --type service + register: service_exists + changed_when: false + failed_when: service_exists.rc not in [0, 1] + check_mode: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002403 + - NIST-800-171-3.4.5 + - NIST-800-53-CM-6 + - disable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_debug-shell_disabled + +- name: Disable debug-shell SystemD Service - Ensure debug-shell.service is Masked + ansible.builtin.systemd: + name: debug-shell.service + state: stopped + enabled: false + masked: true + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - service_exists.stdout_lines is search("debug-shell.service", multiline=True) + tags: + - DISA-STIG-OL09-00-002403 - NIST-800-171-3.4.5 - NIST-800-53-CM-6 - disable_strategy @@ -30354,13 +35315,14 @@ fi - service_debug-shell_disabled - name: Unit Socket Exists - debug-shell.socket - command: systemctl -q list-unit-files debug-shell.socket + ansible.builtin.command: systemctl -q list-unit-files debug-shell.socket register: socket_file_exists changed_when: false failed_when: socket_file_exists.rc not in [0, 1] check_mode: false - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-002403 - NIST-800-171-3.4.5 - NIST-800-53-CM-6 - disable_strategy @@ -30370,16 +35332,17 @@ fi - no_reboot_needed - service_debug-shell_disabled -- name: Disable socket debug-shell - systemd: +- name: Disable debug-shell SystemD Service - Disable Socket debug-shell + ansible.builtin.systemd: name: debug-shell.socket - enabled: 'no' + enabled: false state: stopped - masked: 'yes' + masked: true when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - socket_file_exists.stdout_lines is search("debug-shell.socket",multiline=True) + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - socket_file_exists.stdout_lines is search("debug-shell.socket", multiline=True) tags: + - DISA-STIG-OL09-00-002403 - NIST-800-171-3.4.5 - NIST-800-53-CM-6 - disable_strategy @@ -30388,8 +35351,8 @@ fi - medium_severity - no_reboot_needed - service_debug-shell_disabled - - include disable_debug-shell + + include disable_debug-shell class disable_debug-shell { service {'debug-shell': @@ -30397,107 +35360,112 @@ class disable_debug-shell { ensure => 'stopped', } } - - + + [customizations.services] -disabled = ["debug-shell"] - - - - - - - - - - Disable Ctrl-Alt-Del Burst Action - By default, SystemD will reboot the system if the Ctrl-Alt-Del +masked = ["debug-shell"] + + + + + + + + + + Disable Ctrl-Alt-Del Burst Action + By default, SystemD will reboot the system if the Ctrl-Alt-Del key sequence is pressed Ctrl-Alt-Delete more than 7 times in 2 seconds. - + + To configure the system to ignore the CtrlAltDelBurstAction setting, add or modify the following to /etc/systemd/system.conf: -CtrlAltDelBurstAction=none - Disabling the Ctrl-Alt-Del key sequence +CtrlAltDelBurstAction=none + + Disabling the Ctrl-Alt-Del key sequence in /etc/init/control-alt-delete.conf DOES NOT disable the Ctrl-Alt-Del key sequence if running in runlevel 6 (e.g. in GNOME, KDE, etc.)! The Ctrl-Alt-Del key sequence will only be disabled if running in -the non-graphical runlevel 3. - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - APO01.06 - DSS05.04 - DSS05.07 - DSS06.02 - 3.4.5 - CCI-000366 - 164.308(a)(1)(ii)(B) - 164.308(a)(7)(i) - 164.308(a)(7)(ii)(A) - 164.310(a)(1) - 164.310(a)(2)(i) - 164.310(a)(2)(ii) - 164.310(a)(2)(iii) - 164.310(b) - 164.310(c) - 164.310(d)(1) - 164.310(d)(2)(iii) - 4.3.3.7.3 - SR 2.1 - SR 5.2 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 - CM-6(a) - AC-6(1) - CM-6(a) - PR.AC-4 - PR.DS-5 - FAU_GEN.1.2 - SRG-OS-000324-GPOS-00125 - SRG-OS-000480-GPOS-00227 - A locally logged-in user who presses Ctrl-Alt-Del, when at the console, +the non-graphical runlevel 3. + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + APO01.06 + DSS05.04 + DSS05.07 + DSS06.02 + 3.4.5 + CCI-000366 + CCI-002235 + 164.308(a)(1)(ii)(B) + 164.308(a)(7)(i) + 164.308(a)(7)(ii)(A) + 164.310(a)(1) + 164.310(a)(2)(i) + 164.310(a)(2)(ii) + 164.310(a)(2)(iii) + 164.310(b) + 164.310(c) + 164.310(d)(1) + 164.310(d)(2)(iii) + 4.3.3.7.3 + SR 2.1 + SR 5.2 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 + CM-6(a) + AC-6(1) + CM-6(a) + PR.AC-4 + PR.DS-5 + FAU_GEN.1.2 + SRG-OS-000324-GPOS-00125 + SRG-OS-000480-GPOS-00227 + OL09-00-002412 + SV-271751r1091965_rule + A locally logged-in user who presses Ctrl-Alt-Del, when at the console, can reboot the system. If accidentally pressed, as could happen in the case of mixed OS environment, this can create the risk of short-term -loss of availability of systems due to unintentional reboot. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && { rpm --quiet -q systemd; }; then +loss of availability of systems due to unintentional reboot. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q systemd; }; then # Strip any search characters in the key arg so that the key can be replaced without # adding any search characters to the config file. @@ -30522,11 +35490,12 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-002412 - NIST-800-171-3.4.5 - NIST-800-53-AC-6(1) - NIST-800-53-CM-6(a) @@ -30546,9 +35515,10 @@ fi line: CtrlAltDelBurstAction=none create: true when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"systemd" in ansible_facts.packages' tags: + - DISA-STIG-OL09-00-002412 - NIST-800-171-3.4.5 - NIST-800-53-AC-6(1) - NIST-800-53-CM-6(a) @@ -30559,117 +35529,124 @@ fi - low_complexity - low_disruption - no_reboot_needed - - - - - - - - - - Disable Ctrl-Alt-Del Reboot Activation - By default, SystemD will reboot the system if the Ctrl-Alt-Del + + + + + + + + + + Disable Ctrl-Alt-Del Reboot Activation + By default, SystemD will reboot the system if the Ctrl-Alt-Del key sequence is pressed. - + + To configure the system to ignore the Ctrl-Alt-Del key sequence from the command line instead of rebooting the system, do either of the following: ln -sf /dev/null /etc/systemd/system/ctrl-alt-del.target or systemctl mask ctrl-alt-del.target - + + Do not simply delete the /usr/lib/systemd/system/ctrl-alt-del.service file, -as this file may be restored during future system updates. - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - APO01.06 - DSS05.04 - DSS05.07 - DSS06.02 - 3.4.5 - CCI-000366 - 164.308(a)(1)(ii)(B) - 164.308(a)(7)(i) - 164.308(a)(7)(ii)(A) - 164.310(a)(1) - 164.310(a)(2)(i) - 164.310(a)(2)(ii) - 164.310(a)(2)(iii) - 164.310(b) - 164.310(c) - 164.310(d)(1) - 164.310(d)(2)(iii) - 4.3.3.7.3 - SR 2.1 - SR 5.2 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 - CM-6(a) - AC-6(1) - PR.AC-4 - PR.DS-5 - FAU_GEN.1.2 - SRG-OS-000324-GPOS-00125 - SRG-OS-000480-GPOS-00227 - A locally logged-in user who presses Ctrl-Alt-Del, when at the console, +as this file may be restored during future system updates. + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + APO01.06 + DSS05.04 + DSS05.07 + DSS06.02 + 3.4.5 + CCI-000366 + CCI-002235 + 164.308(a)(1)(ii)(B) + 164.308(a)(7)(i) + 164.308(a)(7)(ii)(A) + 164.310(a)(1) + 164.310(a)(2)(i) + 164.310(a)(2)(ii) + 164.310(a)(2)(iii) + 164.310(b) + 164.310(c) + 164.310(d)(1) + 164.310(d)(2)(iii) + 4.3.3.7.3 + SR 2.1 + SR 5.2 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 + CM-6(a) + AC-6(1) + PR.AC-4 + PR.DS-5 + FAU_GEN.1.2 + SRG-OS-000324-GPOS-00125 + SRG-OS-000480-GPOS-00227 + OL09-00-002413 + SV-271752r1091968_rule + A locally logged-in user who presses Ctrl-Alt-Del, when at the console, can reboot the system. If accidentally pressed, as could happen in the case of mixed OS environment, this can create the risk of short-term -loss of availability of systems due to unintentional reboot. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then +loss of availability of systems due to unintentional reboot. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -systemctl disable --now ctrl-alt-del.target -systemctl mask --now ctrl-alt-del.target +if [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; then + systemctl disable ctrl-alt-del.target + systemctl mask ctrl-alt-del.target +else + systemctl disable --now ctrl-alt-del.target + systemctl mask --now ctrl-alt-del.target +fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Disable Ctrl-Alt-Del Reboot Activation - systemd: - name: ctrl-alt-del.target - force: true - masked: true - state: stopped - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + + - name: Gather the package facts + package_facts: + manager: auto tags: + - DISA-STIG-OL09-00-002413 - NIST-800-171-3.4.5 - NIST-800-53-AC-6(1) - NIST-800-53-CM-6(a) @@ -30679,17 +35656,36 @@ fi - low_complexity - low_disruption - no_reboot_needed - - - - - - - - - - Verify that Interactive Boot is Disabled - Oracle Linux 9 systems support an "interactive boot" option that can + +- name: Disable Ctrl-Alt-Del Reboot Activation + systemd: + name: ctrl-alt-del.target + force: true + masked: true + state: stopped + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002413 + - NIST-800-171-3.4.5 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - disable_ctrlaltdel_reboot + - disable_strategy + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + + + + + + + + + + Verify that Interactive Boot is Disabled + Oracle Linux 9 systems support an "interactive boot" option that can be used to prevent services from being started. On a Oracle Linux 9 system, interactive boot can be enabled by providing a 1, yes, true, or on value to the @@ -30701,98 +35697,99 @@ Recovery booting must also be disabled. Confirm that It is also required to change the runtime configuration, run: /sbin/grubby --update-kernel=ALL --remove-args="systemd.confirm_spawn" - -grub2-mkconfig -o /boot/grub2/grub.cfg - 11 - 12 - 14 - 15 - 16 - 18 - 3 - 5 - DSS05.02 - DSS05.04 - DSS05.05 - DSS05.07 - DSS06.03 - DSS06.06 - 3.1.2 - 3.4.5 - CCI-000213 - 164.308(a)(1)(ii)(B) - 164.308(a)(7)(i) - 164.308(a)(7)(ii)(A) - 164.310(a)(1) - 164.310(a)(2)(i) - 164.310(a)(2)(ii) - 164.310(a)(2)(iii) - 164.310(b) - 164.310(c) - 164.310(d)(1) - 164.310(d)(2)(iii) - 4.3.3.2.2 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - A.6.1.2 - A.7.1.1 - A.9.1.2 - A.9.2.1 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - SC-2(1) - CM-6(a) - PR.AC-4 - PR.AC-6 - PR.PT-3 - FIA_UAU.1 - SRG-OS-000480-GPOS-00227 - Using interactive or recovery boot, the console user could disable auditing, firewalls, -or other services, weakening system security. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && { rpm --quiet -q grub2-common; }; then + grub2-mkconfig -o /boot/grub2/grub.cfg + + 11 + 12 + 14 + 15 + 16 + 18 + 3 + 5 + DSS05.02 + DSS05.04 + DSS05.05 + DSS05.07 + DSS06.03 + DSS06.06 + 3.1.2 + 3.4.5 + CCI-000366 + 164.308(a)(1)(ii)(B) + 164.308(a)(7)(i) + 164.308(a)(7)(ii)(A) + 164.310(a)(1) + 164.310(a)(2)(i) + 164.310(a)(2)(ii) + 164.310(a)(2)(iii) + 164.310(b) + 164.310(c) + 164.310(d)(1) + 164.310(d)(2)(iii) + 4.3.3.2.2 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + A.6.1.2 + A.7.1.1 + A.9.1.2 + A.9.2.1 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + SC-2(1) + CM-6(a) + PR.AC-4 + PR.AC-6 + PR.PT-3 + SRG-OS-000480-GPOS-00227 + OL09-00-002392 + SV-271736r1091920_rule + Using interactive or recovery boot, the console user could disable auditing, firewalls, +or other services, weakening system security. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q grub2-common; }; then # Verify that Interactive Boot is Disabled in /etc/default/grub CONFIRM_SPAWN_YES="systemd.confirm_spawn\(=\(1\|yes\|true\|on\)\|\b\)" @@ -30824,11 +35821,12 @@ grub2-mkconfig -o /boot/grub2/grub.cfg else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-002392 - NIST-800-171-3.1.2 - NIST-800-171-3.4.5 - NIST-800-53-CM-6(a) @@ -30847,9 +35845,10 @@ fi line: GRUB_DISABLE_RECOVERY=true state: present when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"grub2-common" in ansible_facts.packages' tags: + - DISA-STIG-OL09-00-002392 - NIST-800-171-3.1.2 - NIST-800-171-3.4.5 - NIST-800-53-CM-6(a) @@ -30867,9 +35866,10 @@ fi regexp: systemd.confirm_spawn(=(1|yes|true|on)|\b) replace: systemd.confirm_spawn=no when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"grub2-common" in ansible_facts.packages' tags: + - DISA-STIG-OL09-00-002392 - NIST-800-171-3.1.2 - NIST-800-171-3.4.5 - NIST-800-53-CM-6(a) @@ -30884,9 +35884,10 @@ fi - name: Verify that Interactive Boot is Disabled (runtime) command: /sbin/grubby --update-kernel=ALL --remove-args="systemd.confirm_spawn" when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"grub2-common" in ansible_facts.packages' tags: + - DISA-STIG-OL09-00-002392 - NIST-800-171-3.1.2 - NIST-800-171-3.4.5 - NIST-800-53-CM-6(a) @@ -30901,9 +35902,10 @@ fi - name: Regen grub.cfg handle updated GRUB_DISABLE_RECOVERY and confirm_spawn command: grub2-mkconfig -o /boot/grub2/grub.cfg when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"grub2-common" in ansible_facts.packages' tags: + - DISA-STIG-OL09-00-002392 - NIST-800-171-3.1.2 - NIST-800-171-3.4.5 - NIST-800-53-CM-6(a) @@ -30914,139 +35916,345 @@ fi - medium_severity - reboot_required - restrict_strategy - - - - - - - - - - Require Authentication for Emergency Systemd Target - Emergency mode is intended as a system recovery + + + + + + + + + + Configure Logind to terminate idle sessions after certain time of inactivity + To configure logind service to terminate inactive user sessions +after seconds, edit the file +/etc/systemd/logind.conf. Ensure that there is a section +[Login] which contains the configuration +StopIdleSessionSec= + . + 1 + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + 7 + 8 + 5.5.6 + APO13.01 + BAI03.01 + BAI03.02 + BAI03.03 + DSS01.03 + DSS03.05 + DSS05.04 + DSS05.05 + DSS05.07 + DSS05.10 + DSS06.03 + DSS06.10 + 3.1.11 + CCI-001133 + 4.3.3.2.2 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.3 + SR 1.1 + SR 1.10 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 6.2 + A.12.4.1 + A.12.4.3 + A.14.1.1 + A.14.2.1 + A.14.2.5 + A.18.1.4 + A.6.1.2 + A.6.1.5 + A.7.1.1 + A.9.1.2 + A.9.2.1 + A.9.2.2 + A.9.2.3 + A.9.2.4 + A.9.2.6 + A.9.3.1 + A.9.4.1 + A.9.4.2 + A.9.4.3 + A.9.4.4 + A.9.4.5 + CIP-004-6 R2.2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.2 + CIP-007-3 R5.3.1 + CIP-007-3 R5.3.2 + CIP-007-3 R5.3.3 + CM-6(a) + AC-17(a) + AC-2(5) + AC-12 + AC-17(a) + SC-10 + CM-6(a) + DE.CM-1 + DE.CM-3 + PR.AC-1 + PR.AC-4 + PR.AC-6 + PR.AC-7 + PR.IP-2 + FMT_SMF_EXT.1.1 + Req-8.1.8 + SRG-OS-000163-GPOS-00072 + R32 + Terminating an idle session within a short time period reduces the window of +opportunity for unauthorized personnel to take control of a management +session enabled on the console or console port that has been let unattended. + + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { ( grep -qP "^ID=[\"']?rhel[\"']?$" "/etc/os-release" && { real="$(grep -P "^VERSION_ID=[\"']?[\w.]+[\"']?$" /etc/os-release | sed "s/^VERSION_ID=[\"']\?\([^\"']\+\)[\"']\?$/\1/")"; expected="8.7"; printf "%s\n%s" "$expected" "$real" | sort -VC; } && grep -qP "^ID=[\"']?rhel[\"']?$" "/etc/os-release" && { real="$(grep -P "^VERSION_ID=[\"']?[\w.]+[\"']?$" /etc/os-release | sed "s/^VERSION_ID=[\"']\?\([^\"']\+\)[\"']\?$/\1/")"; expected="9.0"; [[ "$real" != "$expected" ]]; } ) || grep -qP "^ID=[\"']?ol[\"']?$" "/etc/os-release" && { real="$(grep -P "^VERSION_ID=[\"']?[\w.]+[\"']?$" /etc/os-release | sed "s/^VERSION_ID=[\"']\?\([^\"']\+\)[\"']\?$/\1/")"; expected="8.7"; printf "%s\n%s" "$expected" "$real" | sort -VC; }; }; then + +var_logind_session_timeout='' + + + +# Try find '[Login]' and 'StopIdleSessionSec' in '/etc/systemd/logind.conf', if it exists, set +# to '$var_logind_session_timeout', if it isn't here, add it, if '[Login]' doesn't exist, add it there +if grep -qzosP '[[:space:]]*\[Login]([^\n\[]*\n+)+?[[:space:]]*StopIdleSessionSec' '/etc/systemd/logind.conf'; then + + sed -i "s/StopIdleSessionSec[^(\n)]*/StopIdleSessionSec=$var_logind_session_timeout/" '/etc/systemd/logind.conf' +elif grep -qs '[[:space:]]*\[Login]' '/etc/systemd/logind.conf'; then + sed -i "/[[:space:]]*\[Login]/a StopIdleSessionSec=$var_logind_session_timeout" '/etc/systemd/logind.conf' +else + if test -d "/etc/systemd"; then + printf '%s\n' '[Login]' "StopIdleSessionSec=$var_logind_session_timeout" >> '/etc/systemd/logind.conf' + else + echo "Config file directory '/etc/systemd' doesnt exist, not remediating, assuming non-applicability." >&2 + fi +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - CJIS-5.5.6 + - NIST-800-171-3.1.11 + - NIST-800-53-AC-12 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-2(5) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-SC-10 + - PCI-DSS-Req-8.1.8 + - logind_session_timeout + - low_complexity + - low_disruption + - medium_severity + - reboot_required + - restrict_strategy +- name: XCCDF Value var_logind_session_timeout # promote to variable + set_fact: + var_logind_session_timeout: !!str + tags: + - always + +- name: Set 'StopIdleSessionSec' to '{{ var_logind_session_timeout }}' in the [Login] + section of '/etc/systemd/logind.conf' + ini_file: + path: /etc/systemd/logind.conf + section: Login + option: StopIdleSessionSec + value: '{{ var_logind_session_timeout }}' + create: true + mode: 420 + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - ( ansible_distribution == 'RedHat' and ansible_distribution_version is version('8.7', + '>=') and ansible_distribution == 'RedHat' and ansible_distribution_version is + version('9.0', '!=') ) or ansible_distribution == 'OracleLinux' and ansible_distribution_version + is version('8.7', '>=') + tags: + - CJIS-5.5.6 + - NIST-800-171-3.1.11 + - NIST-800-53-AC-12 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-2(5) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-SC-10 + - PCI-DSS-Req-8.1.8 + - logind_session_timeout + - low_complexity + - low_disruption + - medium_severity + - reboot_required + - restrict_strategy + + + + + + + + + + + Require Authentication for Emergency Systemd Target + Emergency mode is intended as a system recovery method, providing a single user root access to the system during a failed boot sequence. - + + By default, Emergency mode is protected by requiring a password and is set -in /usr/lib/systemd/system/emergency.service. - 1 - 11 - 12 - 14 - 15 - 16 - 18 - 3 - 5 - DSS05.02 - DSS05.04 - DSS05.05 - DSS05.07 - DSS05.10 - DSS06.03 - DSS06.06 - DSS06.10 - 3.1.1 - 3.4.5 - CCI-000213 - 164.308(a)(1)(ii)(B) - 164.308(a)(7)(i) - 164.308(a)(7)(ii)(A) - 164.310(a)(1) - 164.310(a)(2)(i) - 164.310(a)(2)(ii) - 164.310(a)(2)(iii) - 164.310(b) - 164.310(c) - 164.310(d)(1) - 164.310(d)(2)(iii) - 4.3.3.2.2 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - 0421 - 0422 - 0431 - 0974 - 1173 - 1401 - 1504 - 1505 - 1546 - 1557 - 1558 - 1559 - 1560 - 1561 - A.18.1.4 - A.6.1.2 - A.7.1.1 - A.9.1.2 - A.9.2.1 - A.9.2.2 - A.9.2.3 - A.9.2.4 - A.9.2.6 - A.9.3.1 - A.9.4.1 - A.9.4.2 - A.9.4.3 - A.9.4.4 - A.9.4.5 - IA-2 - AC-3 - CM-6(a) - PR.AC-1 - PR.AC-4 - PR.AC-6 - PR.AC-7 - PR.PT-3 - FIA_UAU.1 - SRG-OS-000080-GPOS-00048 - This prevents attackers with physical access from trivially bypassing security +in /usr/lib/systemd/system/emergency.service. + 1 + 11 + 12 + 14 + 15 + 16 + 18 + 3 + 5 + DSS05.02 + DSS05.04 + DSS05.05 + DSS05.07 + DSS05.10 + DSS06.03 + DSS06.06 + DSS06.10 + 3.1.1 + 3.4.5 + CCI-000213 + 164.308(a)(1)(ii)(B) + 164.308(a)(7)(i) + 164.308(a)(7)(ii)(A) + 164.310(a)(1) + 164.310(a)(2)(i) + 164.310(a)(2)(ii) + 164.310(a)(2)(iii) + 164.310(b) + 164.310(c) + 164.310(d)(1) + 164.310(d)(2)(iii) + 4.3.3.2.2 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + 0421 + 0422 + 0431 + 0974 + 1173 + 1401 + 1504 + 1505 + 1546 + 1557 + 1558 + 1559 + 1560 + 1561 + A.18.1.4 + A.6.1.2 + A.7.1.1 + A.9.1.2 + A.9.2.1 + A.9.2.2 + A.9.2.3 + A.9.2.4 + A.9.2.6 + A.9.3.1 + A.9.4.1 + A.9.4.2 + A.9.4.3 + A.9.4.4 + A.9.4.5 + IA-2 + AC-3 + CM-6(a) + PR.AC-1 + PR.AC-4 + PR.AC-6 + PR.AC-7 + PR.PT-3 + SRG-OS-000080-GPOS-00048 + OL09-00-000025 + SV-271441r1091035_rule + This prevents attackers with physical access from trivially bypassing security on the machine and gaining root access. Such accesses are further prevented -by configuring the bootloader password. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then +by configuring the bootloader password. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then service_file="/usr/lib/systemd/system/emergency.service" @@ -31063,15 +36271,12 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Require emergency mode password - lineinfile: - create: true - dest: /usr/lib/systemd/system/emergency.service - regexp: ^#?ExecStart= - line: ExecStart=-/usr/lib/systemd/systemd-sulogin-shell emergency - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + + - name: Gather the package facts + package_facts: + manager: auto tags: + - DISA-STIG-OL09-00-000025 - NIST-800-171-3.1.1 - NIST-800-171-3.4.5 - NIST-800-53-AC-3 @@ -31083,172 +36288,216 @@ fi - no_reboot_needed - require_emergency_target_auth - restrict_strategy - - - - - - - - - - Require Authentication for Single User Mode - Single-user mode is intended as a system recovery + +- name: Require emergency mode password + lineinfile: + create: true + dest: /usr/lib/systemd/system/emergency.service + regexp: ^#?ExecStart= + line: ExecStart=-/usr/lib/systemd/systemd-sulogin-shell emergency + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-000025 + - NIST-800-171-3.1.1 + - NIST-800-171-3.4.5 + - NIST-800-53-AC-3 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-2 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - require_emergency_target_auth + - restrict_strategy + + + + + + + + + + Require Authentication for Single User Mode + Single-user mode is intended as a system recovery method, providing a single user root access to the system by providing a boot option at startup. - + + By default, single-user mode is protected by requiring a password and is set -in /usr/lib/systemd/system/rescue.service. - 1 - 11 - 12 - 14 - 15 - 16 - 18 - 3 - 5 - DSS05.02 - DSS05.04 - DSS05.05 - DSS05.07 - DSS05.10 - DSS06.03 - DSS06.06 - DSS06.10 - 3.1.1 - 3.4.5 - CCI-000213 - 164.308(a)(1)(ii)(B) - 164.308(a)(7)(i) - 164.308(a)(7)(ii)(A) - 164.310(a)(1) - 164.310(a)(2)(i) - 164.310(a)(2)(ii) - 164.310(a)(2)(iii) - 164.310(b) - 164.310(c) - 164.310(d)(1) - 164.310(d)(2)(iii) - 4.3.3.2.2 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - 0421 - 0422 - 0431 - 0974 - 1173 - 1401 - 1504 - 1505 - 1546 - 1557 - 1558 - 1559 - 1560 - 1561 - A.18.1.4 - A.6.1.2 - A.7.1.1 - A.9.1.2 - A.9.2.1 - A.9.2.2 - A.9.2.3 - A.9.2.4 - A.9.2.6 - A.9.3.1 - A.9.4.1 - A.9.4.2 - A.9.4.3 - A.9.4.4 - A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.2.3 - CIP-004-6 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.2 - CIP-007-3 R5.2 - CIP-007-3 R5.3.1 - CIP-007-3 R5.3.2 - CIP-007-3 R5.3.3 - IA-2 - AC-3 - CM-6(a) - PR.AC-1 - PR.AC-4 - PR.AC-6 - PR.AC-7 - PR.PT-3 - FIA_UAU.1 - SRG-OS-000080-GPOS-00048 - This prevents attackers with physical access from trivially bypassing security +in /usr/lib/systemd/system/rescue.service. + 1 + 11 + 12 + 14 + 15 + 16 + 18 + 3 + 5 + DSS05.02 + DSS05.04 + DSS05.05 + DSS05.07 + DSS05.10 + DSS06.03 + DSS06.06 + DSS06.10 + 3.1.1 + 3.4.5 + CCI-000213 + 164.308(a)(1)(ii)(B) + 164.308(a)(7)(i) + 164.308(a)(7)(ii)(A) + 164.310(a)(1) + 164.310(a)(2)(i) + 164.310(a)(2)(ii) + 164.310(a)(2)(iii) + 164.310(b) + 164.310(c) + 164.310(d)(1) + 164.310(d)(2)(iii) + 4.3.3.2.2 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + 0421 + 0422 + 0431 + 0974 + 1173 + 1401 + 1504 + 1505 + 1546 + 1557 + 1558 + 1559 + 1560 + 1561 + A.18.1.4 + A.6.1.2 + A.7.1.1 + A.9.1.2 + A.9.2.1 + A.9.2.2 + A.9.2.3 + A.9.2.4 + A.9.2.6 + A.9.3.1 + A.9.4.1 + A.9.4.2 + A.9.4.3 + A.9.4.4 + A.9.4.5 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.2.3 + CIP-004-6 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.2 + CIP-007-3 R5.2 + CIP-007-3 R5.3.1 + CIP-007-3 R5.3.2 + CIP-007-3 R5.3.3 + IA-2 + AC-3 + CM-6(a) + PR.AC-1 + PR.AC-4 + PR.AC-6 + PR.AC-7 + PR.PT-3 + FIA_UAU.1 + SRG-OS-000080-GPOS-00048 + OL09-00-000030 + SV-271442r1091038_rule + This prevents attackers with physical access from trivially bypassing security on the machine and gaining root access. Such accesses are further prevented -by configuring the bootloader password. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then +by configuring the bootloader password. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -service_file="/usr/lib/systemd/system/rescue.service" +found=false -sulogin="/usr/lib/systemd/systemd-sulogin-shell rescue" +# set value in all files if they contain section or key +for f in $(echo -n "/etc/systemd/system/rescue.service.d/10-oscap.conf /etc/systemd/system/rescue.service.d/*.conf"); do + if [ ! -e "$f" ]; then + continue + fi + + # find key in section and change value + if grep -qzosP "[[:space:]]*\[Service\]([^\n\[]*\n+)+?[[:space:]]*ExecStart" "$f"; then + + sed -i "s/ExecStart[^(\n)]*/ExecStart=\nExecStart=-\/usr\/lib\/systemd\/systemd-sulogin-shell rescue/" "$f" + + found=true + + # find section and add key = value to it + elif grep -qs "[[:space:]]*\[Service\]" "$f"; then + + sed -i "/[[:space:]]*\[Service\]/a ExecStart=\nExecStart=-\/usr\/lib\/systemd\/systemd-sulogin-shell rescue" "$f" + + found=true + fi +done + +# if section not in any file, append section with key = value to FIRST file in files parameter +if ! $found ; then + file=$(echo "/etc/systemd/system/rescue.service.d/10-oscap.conf /etc/systemd/system/rescue.service.d/*.conf" | cut -f1 -d ' ') + mkdir -p "$(dirname "$file")" + + echo -e "[Service]\nExecStart=\nExecStart=-/usr/lib/systemd/systemd-sulogin-shell rescue" >> "$file" -if grep "^ExecStart=.*" "$service_file" ; then - sed -i "s%^ExecStart=.*%ExecStart=-$sulogin%" "$service_file" -else - echo "ExecStart=-$sulogin" >> "$service_file" fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Require single user mode password - lineinfile: - create: true - dest: /usr/lib/systemd/system/rescue.service - regexp: ^#?ExecStart= - line: ExecStart=-/usr/lib/systemd/systemd-sulogin-shell rescue - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + + - name: Gather the package facts + package_facts: + manager: auto tags: + - DISA-STIG-OL09-00-000030 - NIST-800-171-3.1.1 - NIST-800-171-3.4.5 - NIST-800-53-AC-3 @@ -31260,535 +36509,131 @@ fi - no_reboot_needed - require_singleuser_auth - restrict_strategy - - - - - - - - - - Configure Screen Locking - When a user must temporarily leave an account + +- name: Require Authentication for Single User Mode - Require single user mode password + lineinfile: + create: true + dest: /usr/lib/systemd/system/rescue.service + regexp: ^#?ExecStart= + line: ExecStart=-/usr/lib/systemd/systemd-sulogin-shell rescue + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-000030 + - NIST-800-171-3.1.1 + - NIST-800-171-3.4.5 + - NIST-800-53-AC-3 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-2 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - require_singleuser_auth + - restrict_strategy + + + + + + + + + + Configure Screen Locking + When a user must temporarily leave an account logged-in, screen locking should be employed to prevent passersby from abusing the account. User education and training is particularly important for screen locking to be effective, and policies can be implemented to reinforce this. - + + Automatic screen locking is only meant as a safeguard for -those cases where a user forgot to lock the screen. - - Configure Console Screen Locking - A console screen locking mechanism is a temporary action taken when a user -stops work and moves away from the immediate physical vicinity of the -information system but does not logout because of the temporary nature of -the absence. Rather than relying on the user to manually lock their -operation system session prior to vacating the vicinity, operating systems -need to be able to identify when a user's session has idled and take action -to initiate the session lock. - - Install the tmux Package - To enable console screen locking, install the tmux package. -A session lock is a temporary action taken when a user stops work and moves away from the immediate physical vicinity of the information system but does not want to log out because of the temporary nature of the absence. -The session lock is implemented at the point where session activity can be determined. -Rather than be forced to wait for a period of time to expire before the user session can be locked, Oracle Linux 9 needs to provide users with the ability to manually invoke a session lock so users can secure their session if it is necessary to temporarily vacate the immediate physical vicinity. -Instruct users to begin new terminal sessions with the following command: -$ tmux -The console can now be locked with the following key combination: -ctrl+b :lock-session - 1 - 12 - 15 - 16 - DSS05.04 - DSS05.10 - DSS06.10 - 3.1.10 - CCI-000058 - CCI-000056 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - SR 1.1 - SR 1.10 - SR 1.2 - SR 1.5 - SR 1.7 - SR 1.8 - SR 1.9 - A.18.1.4 - A.9.2.1 - A.9.2.4 - A.9.3.1 - A.9.4.2 - A.9.4.3 - CM-6(a) - PR.AC-7 - FMT_SMF_EXT.1 - FMT_MOF_EXT.1 - FTA_SSL.1 - SRG-OS-000030-GPOS-00011 - SRG-OS-000028-GPOS-00009 - A session time-out lock is a temporary action taken when a user stops work and moves away from the immediate -physical vicinity of the information system but does not logout because of the temporary nature of the absence. -Rather than relying on the user to manually lock their operation system session prior to vacating the vicinity, -operating systems need to be able to identify when a user's session has idled and take action to initiate the -session lock. - -The tmux package allows for a session lock to be implemented and configured. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -if ! rpm -q --quiet "tmux" ; then - yum install -y "tmux" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Ensure tmux is installed - package: - name: tmux - state: present - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.10 - - NIST-800-53-CM-6(a) - - enable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - package_tmux_installed - - include install_tmux - -class install_tmux { - package { 'tmux': - ensure => 'installed', - } -} - - -package --add=tmux - - -[[packages]] -name = "tmux" -version = "*" - - - - - - - - - - Support session locking with tmux - The tmux terminal multiplexer is used to implement -automatic session locking. It should be started from -/etc/bashrc or drop-in files within /etc/profile.d/. - CCI-000056 - CCI-000058 - FMT_SMF_EXT.1 - FMT_MOF_EXT.1 - FTA_SSL.1 - SRG-OS-000031-GPOS-00012 - SRG-OS-000028-GPOS-00009 - SRG-OS-000030-GPOS-00011 - Unlike bash itself, the tmux terminal multiplexer -provides a mechanism to lock sessions after period of inactivity. -A session lock is a temporary action taken when a user stops work and moves away from the -immediate physical vicinity of the information system but does not want to -log out because of the temporary nature of the absence. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && { rpm --quiet -q tmux; }; then - -if ! grep -x ' case "$name" in sshd|login) exec tmux ;; esac' /etc/bashrc; then - cat >> /etc/profile.d/tmux.sh <<'EOF' -if [ "$PS1" ]; then - parent=$(ps -o ppid= -p $$) - name=$(ps -o comm= -p $parent) - case "$name" in sshd|login) exec tmux ;; esac -fi -EOF - chmod 0644 /etc/profile.d/tmux.sh -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Gather the package facts - package_facts: - manager: auto - tags: - - configure_bashrc_exec_tmux - - configure_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: 'Support session locking with tmux: Determine If the Tmux Launch Script Is - Present in /etc/bashrc' - ansible.builtin.find: - paths: /etc - patterns: bashrc - contains: .*case "$name" in sshd|login) exec tmux ;; esac.* - register: tmux_in_bashrc - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - '"tmux" in ansible_facts.packages' - tags: - - configure_bashrc_exec_tmux - - configure_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: 'Support session locking with tmux: Determine If the Tmux Launch Script Is - Present in /etc/profile.d/*.sh' - ansible.builtin.find: - paths: /etc/profile.d - patterns: '*.sh' - contains: .*case "$name" in sshd|login) exec tmux ;; esac.* - register: tmux_in_profile_d - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - '"tmux" in ansible_facts.packages' - tags: - - configure_bashrc_exec_tmux - - configure_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: 'Support session locking with tmux: Insert the Correct Script into /etc/profile.d/tmux.sh' - ansible.builtin.blockinfile: - path: /etc/profile.d/tmux.sh - block: | - if [ "$PS1" ]; then - parent=$(ps -o ppid= -p $$) - name=$(ps -o comm= -p $parent) - case "$name" in sshd|login) exec tmux ;; esac - fi - create: true - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - '"tmux" in ansible_facts.packages' - - tmux_in_bashrc is defined and tmux_in_bashrc.matched == 0 - - tmux_in_profile_d is defined and tmux_in_profile_d.matched == 0 - tags: - - configure_bashrc_exec_tmux - - configure_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Configure tmux to lock session after inactivity - To enable console screen locking in tmux terminal multiplexer -after a period of inactivity, -the lock-after-time option has to be set to a value greater than 0 and less than -or equal to 900 in /etc/tmux.conf. - CCI-000057 - CCI-000060 - FMT_SMF_EXT.1 - FMT_MOF_EXT.1 - FTA_SSL.1 - SRG-OS-000029-GPOS-00010 - SRG-OS-000031-GPOS-00012 - Locking the session after a period of inactivity limits the -potential exposure if the session is left unattended. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -tmux_conf="/etc/tmux.conf" - -if grep -qP '^\s*set\s+-g\s+lock-after-time' "$tmux_conf" ; then - sed -i 's/^\s*set\s\+-g\s\+lock-after-time.*$/set -g lock-after-time 900/' "$tmux_conf" -else - echo "set -g lock-after-time 900" >> "$tmux_conf" -fi -chmod 0644 "$tmux_conf" - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Configure tmux to lock session after inactivity - block: - - - name: Check for duplicate values - lineinfile: - path: /etc/tmux.conf - create: false - regexp: ^\s*set -g lock-after-time\s+ - mode: '0644' - state: absent - check_mode: true - changed_when: false - register: dupes - - - name: Deduplicate values from /etc/tmux.conf - lineinfile: - path: /etc/tmux.conf - create: false - regexp: ^\s*set -g lock-after-time\s+ - mode: '0644' - state: absent - when: dupes.found is defined and dupes.found > 1 - - - name: Insert correct line to /etc/tmux.conf - lineinfile: - path: /etc/tmux.conf - create: true - regexp: ^\s*set -g lock-after-time\s+ - mode: '0644' - line: set -g lock-after-time 900 - state: present - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - configure_tmux_lock_after_time - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - - - - - - - - - Configure the tmux Lock Command - To enable console screen locking in tmux terminal multiplexer, -the vlock command must be configured to be used as a locking -mechanism. -Add the following line to /etc/tmux.conf: -set -g lock-command vlock. -The console can now be locked with the following key combination: -ctrl+b :lock-session - CCI-000056 - CCI-000058 - AC-11(a) - AC-11(b) - CM-6(a) - FMT_SMF_EXT.1 - FMT_MOF_EXT.1 - FTA_SSL.1 - SRG-OS-000028-GPOS-00009 - SRG-OS-000030-GPOS-00011 - The tmux package allows for a session lock to be implemented and configured. -However, the session lock is implemented by an external command. The tmux -default configuration does not contain an effective session lock. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -tmux_conf="/etc/tmux.conf" - -if grep -qP '^\s*set\s+-g\s+lock-command' "$tmux_conf" ; then - sed -i 's/^\s*set\s\+-g\s\+lock-command.*$/set -g lock-command vlock/' "$tmux_conf" -else - echo "set -g lock-command vlock" >> "$tmux_conf" -fi -chmod 0644 "$tmux_conf" - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Configure the tmux Lock Command - block: - - - name: Check for duplicate values - lineinfile: - path: /etc/tmux.conf - create: false - regexp: ^\s*set -g lock-command\s+ - mode: '0644' - state: absent - check_mode: true - changed_when: false - register: dupes - - - name: Deduplicate values from /etc/tmux.conf - lineinfile: - path: /etc/tmux.conf - create: false - regexp: ^\s*set -g lock-command\s+ - mode: '0644' - state: absent - when: dupes.found is defined and dupes.found > 1 - - - name: Insert correct line to /etc/tmux.conf - lineinfile: - path: /etc/tmux.conf - create: true - regexp: ^\s*set -g lock-command\s+ - mode: '0644' - line: set -g lock-command vlock - state: present - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-11(a) - - NIST-800-53-AC-11(b) - - NIST-800-53-CM-6(a) - - configure_tmux_lock_command - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - - - - - - - - - Prevent user from disabling the screen lock - The tmux terminal multiplexer is used to implement -automatic session locking. It should not be listed in -/etc/shells. - CCI-000056 - CCI-000058 - CM-6 - FMT_SMF_EXT.1 - FMT_MOF_EXT.1 - FTA_SSL.1 - SRG-OS-000324-GPOS-00125 - SRG-OS-000028-GPOS-00009 - SRG-OS-000030-GPOS-00011 - Not listing tmux among permitted shells -prevents malicious program running as user -from lowering security by disabling the screen lock. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -if grep -q 'tmux\s*$' /etc/shells ; then - sed -i '/tmux\s*$/d' /etc/shells -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - - - - - - - - - Hardware Tokens for Authentication - The use of hardware tokens such as smart cards for system login +those cases where a user forgot to lock the screen. + + Hardware Tokens for Authentication + The use of hardware tokens such as smart cards for system login provides stronger, two-factor authentication than using a username and password. In Oracle Linux 9 servers, hardware token login -is not enabled by default and must be enabled in the system settings. - - OpenSC Smart Card Drivers - Choose the Smart Card Driver in use by your organization. -For DoD, choose the cac driver. -If your driver is not listed and you don't want to use the +is not enabled by default and must be enabled in the system settings. + + OpenSC Smart Card Drivers + Choose the Smart Card Driver in use by your organization. +For DoD, choose the cac driver. +If your driver is not listed and you don't want to use the default driver, use the other option and -manually specify your driver. - default - acos5 - akis - asepcos - atrust-acos - authentic - belpic - cac - cardos - coolkey - cyberflex - dnie - entersafe - epass2003 - flex - gemsafeV1 - gids - gpk - iasecc - incrypto34 - isoApplet - itacns - jpki - MaskTech - mcrd - muscle - myeid - npa - oberthur - openpgp - None - PIV-II - rutoken_ecp - rutoken - sc-hsm - setcos - starcos - tcos - westcos - - - Install the opensc Package For Multifactor Authentication - +manually specify your driver. + default + acos5 + akis + asepcos + atrust-acos + authentic + belpic + cac + cardos + coolkey + cyberflex + dnie + entersafe + epass2003 + flex + gemsafeV1 + gids + gpk + iasecc + incrypto34 + isoApplet + itacns + jpki + MaskTech + mcrd + muscle + myeid + npa + oberthur + openpgp + None + PIV-II + rutoken_ecp + rutoken + sc-hsm + setcos + starcos + tcos + westcos + + + Install the opensc Package For Multifactor Authentication + The opensc package can be installed with the following command: -$ sudo yum install opensc - CCI-001954 - CCI-001953 - 1382 - 1384 - 1386 - CM-6(a) - SRG-OS-000375-GPOS-00160 - SRG-OS-000376-GPOS-00161 - Using an authentication device, such as a CAC or token that is separate from +$ sudo yum install opensc + + CCI-001953 + CCI-004046 + 1382 + 1384 + 1386 + CM-6(a) + SRG-OS-000375-GPOS-00160 + SRG-OS-000376-GPOS-00161 + OL09-00-000400 + SV-271515r1091257_rule + Using an authentication device, such as a CAC or token that is separate from the information system, ensures that even if the information system is compromised, that compromise will not affect credentials stored on the authentication device. - + + Multifactor solutions that require devices separate from information systems gaining access include, for example, hardware tokens providing time-based or challenge-response authenticators and smart cards such as the U.S. Government Personal Identity Verification card and the DoD Common -Access Card. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then +Access Card. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then if ! rpm -q --quiet "opensc" ; then yum install -y "opensc" @@ -31797,13 +36642,12 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Ensure opensc is installed - package: - name: opensc - state: present - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + + - name: Gather the package facts + package_facts: + manager: auto tags: + - DISA-STIG-OL09-00-000400 - NIST-800-53-CM-6(a) - enable_strategy - low_complexity @@ -31811,45 +36655,63 @@ fi - medium_severity - no_reboot_needed - package_opensc_installed - - include install_opensc + +- name: Ensure opensc is installed + package: + name: opensc + state: present + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-000400 + - NIST-800-53-CM-6(a) + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - package_opensc_installed + + include install_opensc class install_opensc { package { 'opensc': ensure => 'installed', } } - - + + package --add=opensc - - + + [[packages]] name = "opensc" version = "*" - - - - - - - - - - Install the pcsc-lite package - The pcsc-lite package can be installed with the following command: + + + + + + + + + + Install the pcsc-lite package + The pcsc-lite package can be installed with the following command: -$ sudo yum install pcsc-lite - CCI-001954 - 1382 - 1384 - 1386 - CM-6(a) - SRG-OS-000375-GPOS-00160 - The pcsc-lite package must be installed if it is to be available for -multifactor authentication using smartcards. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then +$ sudo yum install pcsc-lite + + CCI-004046 + 1382 + 1384 + 1386 + CM-6(a) + SRG-OS-000375-GPOS-00160 + OL09-00-000390 + SV-271514r1091254_rule + The pcsc-lite package must be installed if it is to be available for +multifactor authentication using smartcards. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then if ! rpm -q --quiet "pcsc-lite" ; then yum install -y "pcsc-lite" @@ -31858,13 +36720,12 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Ensure pcsc-lite is installed - package: - name: pcsc-lite - state: present - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + + - name: Gather the package facts + package_facts: + manager: auto tags: + - DISA-STIG-OL09-00-000390 - NIST-800-53-CM-6(a) - enable_strategy - low_complexity @@ -31872,62 +36733,80 @@ fi - medium_severity - no_reboot_needed - package_pcsc-lite_installed - - include install_pcsc-lite + +- name: Ensure pcsc-lite is installed + package: + name: pcsc-lite + state: present + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-000390 + - NIST-800-53-CM-6(a) + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - package_pcsc-lite_installed + + include install_pcsc-lite class install_pcsc-lite { package { 'pcsc-lite': ensure => 'installed', } } - - + + package --add=pcsc-lite - - + + [[packages]] name = "pcsc-lite" version = "*" - - - - - - - - - - Install Smart Card Packages For Multifactor Authentication - Configure the operating system to implement multifactor authentication by + + + + + + + + + + Install Smart Card Packages For Multifactor Authentication + Configure the operating system to implement multifactor authentication by installing the required package with the following command: The openssl-pkcs11 package can be installed with the following command: -$ sudo yum install openssl-pkcs11 - CCI-000765 - CCI-001948 - CCI-001953 - CCI-001954 - CM-6(a) - Req-8.3 - 8.4 - SRG-OS-000105-GPOS-00052 - SRG-OS-000375-GPOS-00160 - SRG-OS-000375-GPOS-00161 - SRG-OS-000377-GPOS-00162 - Using an authentication device, such as a CAC or token that is separate from +$ sudo yum install openssl-pkcs11 + + CCI-000765 + CCI-001953 + CCI-001954 + CCI-004046 + CM-6(a) + Req-8.3 + SRG-OS-000105-GPOS-00052 + SRG-OS-000375-GPOS-00160 + SRG-OS-000375-GPOS-00161 + SRG-OS-000377-GPOS-00162 + OL09-00-000270 + SV-271491r1091185_rule + Using an authentication device, such as a CAC or token that is separate from the information system, ensures that even if the information system is compromised, that compromise will not affect credentials stored on the authentication device. - + + Multifactor solutions that require devices separate from information systems gaining access include, for example, hardware tokens providing time-based or challenge-response authenticators and smart cards such as the U.S. Government Personal Identity Verification card and the DoD Common -Access Card. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && { ! grep -q s390x /proc/sys/kernel/osrelease; }; then +Access Card. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { ! ( grep -sqE "^.*\.s390x$" /proc/sys/kernel/osrelease || grep -sqE "^s390x$" /proc/sys/kernel/arch; ); }; then if ! rpm -q --quiet "openssl-pkcs11" ; then yum install -y "openssl-pkcs11" @@ -31936,91 +36815,131 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Ensure openssl-pkcs11 is installed - package: - name: openssl-pkcs11 - state: present - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - ansible_architecture != "s390x" + + - name: Gather the package facts + package_facts: + manager: auto tags: + - DISA-STIG-OL09-00-000270 - NIST-800-53-CM-6(a) - PCI-DSS-Req-8.3 - - PCI-DSSv4-8.4 - enable_strategy - install_smartcard_packages - low_complexity - low_disruption - medium_severity - no_reboot_needed - - include install_openssl-pkcs11 + +- name: Ensure openssl-pkcs11 is installed + package: + name: openssl-pkcs11 + state: present + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - ansible_architecture != "s390x" + tags: + - DISA-STIG-OL09-00-000270 + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-8.3 + - enable_strategy + - install_smartcard_packages + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + include install_openssl-pkcs11 class install_openssl-pkcs11 { package { 'openssl-pkcs11': ensure => 'installed', } } - - + + package --add=openssl-pkcs11 - - + + [[packages]] name = "openssl-pkcs11" version = "*" - - - - - - - - - - Enable the pcscd Service - + + + + + + + + + + Enable the pcscd Service + The pcscd service can be enabled with the following command: -$ sudo systemctl enable pcscd.service - CCI-001954 - 1382 - 1384 - 1386 - IA-2(1) - IA-2(2) - IA-2(3) - IA-2(4) - IA-2(6) - IA-2(7) - IA-2(11) - CM-6(a) - Req-8.3 - 8.4 - SRG-OS-000375-GPOS-00160 - Using an authentication device, such as a CAC or token that is separate from +$ sudo systemctl enable pcscd.service + + CCI-004046 + 1382 + 1384 + 1386 + IA-2(1) + IA-2(2) + IA-2(3) + IA-2(4) + IA-2(6) + IA-2(7) + IA-2(11) + CM-6(a) + Req-8.3 + SRG-OS-000375-GPOS-00160 + OL09-00-000401 + SV-271516r1091260_rule + Using an authentication device, such as a CAC or token that is separate from the information system, ensures that even if the information system is compromised, that compromise will not affect credentials stored on the authentication device. - + + Multifactor solutions that require devices separate from information systems gaining access include, for example, hardware tokens providing time-based or challenge-response authenticators and smart cards such as the U.S. Government Personal Identity Verification card and the DoD Common -Access Card. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then +Access Card. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then SYSTEMCTL_EXEC='/usr/bin/systemctl' "$SYSTEMCTL_EXEC" unmask 'pcscd.service' -"$SYSTEMCTL_EXEC" start 'pcscd.service' +if [[ $("$SYSTEMCTL_EXEC" is-system-running) != "offline" ]]; then + "$SYSTEMCTL_EXEC" start 'pcscd.service' +fi "$SYSTEMCTL_EXEC" enable 'pcscd.service' else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Enable service pcscd + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-000401 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-2(1) + - NIST-800-53-IA-2(11) + - NIST-800-53-IA-2(2) + - NIST-800-53-IA-2(3) + - NIST-800-53-IA-2(4) + - NIST-800-53-IA-2(6) + - NIST-800-53-IA-2(7) + - PCI-DSS-Req-8.3 + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_pcscd_enabled + +- name: Enable service pcscd block: - name: Gather the package facts @@ -32040,8 +36959,9 @@ fi cmd: systemctl enable pcscd when: - '"pcsc-lite" in ansible_facts.packages' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-000401 - NIST-800-53-CM-6(a) - NIST-800-53-IA-2(1) - NIST-800-53-IA-2(11) @@ -32051,15 +36971,14 @@ fi - NIST-800-53-IA-2(6) - NIST-800-53-IA-2(7) - PCI-DSS-Req-8.3 - - PCI-DSSv4-8.4 - enable_strategy - low_complexity - low_disruption - medium_severity - no_reboot_needed - service_pcscd_enabled - - include enable_pcscd + + include enable_pcscd class enable_pcscd { service {'pcscd': @@ -32067,24 +36986,24 @@ class enable_pcscd { ensure => 'running', } } - - + + [customizations.services] enabled = ["pcscd"] - - - - - - - - - - Configure opensc Smart Card Drivers - The OpenSC smart card tool can auto-detect smart card drivers; however, + + + + + + + + + + Configure opensc Smart Card Drivers + The OpenSC smart card tool can auto-detect smart card drivers; however, setting the smart card drivers in use by your organization helps to prevent users from using unauthorized smart cards. The default smart card driver for this -profile is . +profile is . To configure the OpenSC driver, edit the /etc/opensc.conf and add the following line into the file in the app default block, so it will look like: @@ -32092,93 +37011,93 @@ so it will look like: app default { ... - card_drivers = ; + card_drivers = ; } - - 1 - 12 - 15 - 16 - 5 - DSS05.04 - DSS05.05 - DSS05.07 - DSS05.10 - DSS06.03 - DSS06.10 - CCI-000765 - CCI-000766 - CCI-000767 - CCI-000768 - CCI-000771 - CCI-000772 - CCI-000884 - 4.3.3.2.2 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.2 - 4.3.3.7.4 - SR 1.1 - SR 1.10 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - 1382 - 1384 - 1386 - A.18.1.4 - A.7.1.1 - A.9.2.1 - A.9.2.2 - A.9.2.3 - A.9.2.4 - A.9.2.6 - A.9.3.1 - A.9.4.2 - A.9.4.3 - IA-2(1) - IA-2(2) - IA-2(3) - IA-2(4) - IA-2(6) - IA-2(7) - IA-2(11) - CM-6(a) - PR.AC-1 - PR.AC-6 - PR.AC-7 - Req-8.3 - 8.4 - SRG-OS-000104-GPOS-00051 - SRG-OS-000106-GPOS-00053 - SRG-OS-000107-GPOS-00054 - SRG-OS-000109-GPOS-00056 - SRG-OS-000108-GPOS-00055 - SRG-OS-000108-GPOS-00057 - SRG-OS-000108-GPOS-00058 - Smart card login provides two-factor authentication stronger than + + + 1 + 12 + 15 + 16 + 5 + DSS05.04 + DSS05.05 + DSS05.07 + DSS05.10 + DSS06.03 + DSS06.10 + CCI-001941 + CCI-004045 + CCI-000765 + CCI-000766 + CCI-000764 + 4.3.3.2.2 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.2 + 4.3.3.7.4 + SR 1.1 + SR 1.10 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + 1382 + 1384 + 1386 + A.18.1.4 + A.7.1.1 + A.9.2.1 + A.9.2.2 + A.9.2.3 + A.9.2.4 + A.9.2.6 + A.9.3.1 + A.9.4.2 + A.9.4.3 + IA-2(1) + IA-2(2) + IA-2(3) + IA-2(4) + IA-2(6) + IA-2(7) + IA-2(11) + CM-6(a) + PR.AC-1 + PR.AC-6 + PR.AC-7 + Req-8.3 + SRG-OS-000104-GPOS-00051 + SRG-OS-000106-GPOS-00053 + SRG-OS-000107-GPOS-00054 + SRG-OS-000109-GPOS-00056 + SRG-OS-000108-GPOS-00055 + SRG-OS-000108-GPOS-00057 + SRG-OS-000108-GPOS-00058 + OL09-00-000940 + SV-271610r1091542_rule + Smart card login provides two-factor authentication stronger than that provided by a username and password combination. Smart cards leverage PKI (public key infrastructure) in order to provide and verify credentials. Configuring the smart card driver in use by your organization helps to prevent -users from using unauthorized smart cards. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then +users from using unauthorized smart cards. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -var_smartcard_drivers='' +var_smartcard_drivers='' OPENSC_TOOL="/usr/bin/opensc-tool" @@ -32190,19 +37109,40 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: XCCDF Value var_smartcard_drivers # promote to variable - set_fact: - var_smartcard_drivers: !!str - tags: - - always - -- name: Check existence of opensc conf - stat: - path: /etc/opensc-{{ ansible_architecture }}.conf - register: opensc_conf_cd - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + + - name: Gather the package facts + package_facts: + manager: auto tags: + - DISA-STIG-OL09-00-000940 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-2(1) + - NIST-800-53-IA-2(11) + - NIST-800-53-IA-2(2) + - NIST-800-53-IA-2(3) + - NIST-800-53-IA-2(4) + - NIST-800-53-IA-2(6) + - NIST-800-53-IA-2(7) + - PCI-DSS-Req-8.3 + - configure_opensc_card_drivers + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed +- name: XCCDF Value var_smartcard_drivers # promote to variable + set_fact: + var_smartcard_drivers: !!str + tags: + - always + +- name: Check existence of opensc conf + stat: + path: /etc/opensc-{{ ansible_architecture }}.conf + register: opensc_conf_cd + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-000940 - NIST-800-53-CM-6(a) - NIST-800-53-IA-2(1) - NIST-800-53-IA-2(11) @@ -32212,7 +37152,6 @@ fi - NIST-800-53-IA-2(6) - NIST-800-53-IA-2(7) - PCI-DSS-Req-8.3 - - PCI-DSSv4-8.4 - configure_opensc_card_drivers - configure_strategy - low_complexity @@ -32234,9 +37173,10 @@ fi when: - card_drivers.stdout != var_smartcard_drivers when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - opensc_conf_cd.stat.exists tags: + - DISA-STIG-OL09-00-000940 - NIST-800-53-CM-6(a) - NIST-800-53-IA-2(1) - NIST-800-53-IA-2(11) @@ -32246,207 +37186,27 @@ fi - NIST-800-53-IA-2(6) - NIST-800-53-IA-2(7) - PCI-DSS-Req-8.3 - - PCI-DSSv4-8.4 - configure_opensc_card_drivers - configure_strategy - low_complexity - low_disruption - medium_severity - no_reboot_needed - - - - - - - - - - - Force opensc To Use Defined Smart Card Driver - The OpenSC smart card middleware can auto-detect smart card drivers; however by -forcing the smart card driver in use by your organization, opensc will no longer -autodetect or use other drivers unless specified. This helps to prevent -users from using unauthorized smart cards. The default smart card driver for this -profile is . -To force the OpenSC driver, edit the /etc/opensc.conf. -Look for a line similar to: -# force_card_driver = customcos; -and change it to: -force_card_driver = ; - 1 - 12 - 15 - 16 - 5 - DSS05.04 - DSS05.05 - DSS05.07 - DSS05.10 - DSS06.03 - DSS06.10 - CCI-000765 - CCI-000766 - CCI-000767 - CCI-000768 - CCI-000771 - CCI-000772 - CCI-000884 - 4.3.3.2.2 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.2 - 4.3.3.7.4 - SR 1.1 - SR 1.10 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - 1382 - 1384 - 1386 - A.18.1.4 - A.7.1.1 - A.9.2.1 - A.9.2.2 - A.9.2.3 - A.9.2.4 - A.9.2.6 - A.9.3.1 - A.9.4.2 - A.9.4.3 - IA-2(1) - IA-2(2) - IA-2(3) - IA-2(4) - IA-2(6) - IA-2(7) - IA-2(11) - CM-6(a) - PR.AC-1 - PR.AC-6 - PR.AC-7 - Req-8.3 - 8.4 - SRG-OS-000104-GPOS-00051 - SRG-OS-000106-GPOS-00053 - SRG-OS-000107-GPOS-00054 - SRG-OS-000109-GPOS-00056 - SRG-OS-000108-GPOS-00055 - SRG-OS-000108-GPOS-00057 - SRG-OS-000108-GPOS-00058 - Smart card login provides two-factor authentication stronger than -that provided by a username and password combination. Smart cards leverage PKI -(public key infrastructure) in order to provide and verify credentials. -Forcing the smart card driver in use by your organization helps to prevent -users from using unauthorized smart cards. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -var_smartcard_drivers='' - - -OPENSC_TOOL="/usr/bin/opensc-tool" - -if [ -f "${OPENSC_TOOL}" ]; then - ${OPENSC_TOOL} -S app:default:force_card_driver:$var_smartcard_drivers -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: XCCDF Value var_smartcard_drivers # promote to variable - set_fact: - var_smartcard_drivers: !!str - tags: - - always - -- name: Check existence of opensc conf - stat: - path: /etc/opensc-{{ ansible_architecture }}.conf - register: opensc_conf_fcd - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-IA-2(1) - - NIST-800-53-IA-2(11) - - NIST-800-53-IA-2(2) - - NIST-800-53-IA-2(3) - - NIST-800-53-IA-2(4) - - NIST-800-53-IA-2(6) - - NIST-800-53-IA-2(7) - - PCI-DSS-Req-8.3 - - PCI-DSSv4-8.4 - - configure_strategy - - force_opensc_card_drivers - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Force smartcard driver block - block: - - - name: Check if force_card_driver is defined - command: /usr/bin/opensc-tool -G app:default:force_card_driver - changed_when: false - register: force_card_driver - - - name: Force opensc To Use Defined Smart Card Driver - command: | - /usr/bin/opensc-tool -S app:default:force_card_driver:{{ var_smartcard_drivers }} - when: - - force_card_driver.stdout != var_smartcard_drivers - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - opensc_conf_fcd.stat.exists - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-IA-2(1) - - NIST-800-53-IA-2(11) - - NIST-800-53-IA-2(2) - - NIST-800-53-IA-2(3) - - NIST-800-53-IA-2(4) - - NIST-800-53-IA-2(6) - - NIST-800-53-IA-2(7) - - PCI-DSS-Req-8.3 - - PCI-DSSv4-8.4 - - configure_strategy - - force_opensc_card_drivers - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - - - - - Protect Accounts by Restricting Password-Based Login - Conventionally, Unix shell accounts are accessed by + + + + + + + + + + + + + + Protect Accounts by Restricting Password-Based Login + Conventionally, Unix shell accounts are accessed by providing a username and password to a login program, which tests these values for correctness using the /etc/passwd and /etc/shadow files. Password-based login is vulnerable to @@ -32454,10 +37214,10 @@ guessing of weak passwords, and to sniffing and man-in-the-middle attacks against passwords entered over a network or at an insecure console. Therefore, mechanisms for accessing accounts by entering usernames and passwords should be restricted to those which are -operationally necessary. - - Accounts Authorized Local Users on the Operating System - List the user accounts that are authorized locally on the operating system. This list +operationally necessary. + + Accounts Authorized Local Users on the Operating System + List the user accounts that are authorized locally on the operating system. This list includes both users requried by the operating system and by the installed applications. Depending on the Operating System distribution, version, software groups and applications, the user list is different and can be customized with scap-workbench. @@ -32466,40 +37226,45 @@ The list starts with '^' and ends with '$' so that it matches exactly the username, not any string that includes the username. Users are separated with '|'. For example, three users: bin, oracle and sapadm are allowed, then the list is ^(bin|oracle|sapadm)$. The user root is the only user that is hard coded -in OVAL that is always allowed on the operating system. - ^(abrt|adm|avahi|bin|chrony|clevis|cockpit-ws|cockpit-wsinstance|colord|daemon|dbus|dnsmasq|flatpak|ftp|games|gdm|geoclue|gluster|gnome-initial-setup|halt|libstoragemgmt|lp|mail|nfsnobody|nobody|ntp|operator|oprofile|oracle|pcp|pegasus|pipewire|polkitd|postfix|pulse|qemu|radvd|rngd|root|rpc|rpcuser|rtkit|saned|saslauth|setroubleshoot|shutdown|sshd|sssd|sync|systemd-bus-proxy|systemd-coredump|systemd-network|systemd-resolve|tcpdump|tss|unbound|usbmuxd$|uuidd)$ - ^(abrt|adm|avahi|bin|chrony|clevis|cockpit-ws|cockpit-wsinstance|colord|daemon|dbus|dnsmasq|flatpak|ftp|games|gdm|geoclue|gluster|gnome-initial-setup|halt|libstoragemgmt|lp|mail|nfsnobody|nobody|ntp|operator|oprofile|oracle|pcp|pegasus|pipewire|polkitd|postfix|pulse|qemu|radvd|rngd|root|rpc|rpcuser|rtkit|saned|saslauth|setroubleshoot|shutdown|sshd|sssd|sync|systemd-bus-proxy|systemd-coredump|systemd-network|systemd-resolve|tcpdump|tss|unbound|usbmuxd$|uuidd)$ - ^(root|bin|daemon|adm|lp|sync|shutdown|halt|mail|operator|games|ftp|nobody|pegasus|systemd-bus-proxy|systemd-network|dbus|polkitd|abrt|unbound|tss|libstoragemgmt|rpc|colord|usbmuxd$|pcp|saslauth|geoclue|setroubleshoot|rtkit|chrony|qemu|radvd|rpcuser|nfsnobody|pulse|gdm|gnome-initial-setup|postfix|avahi|ntp|sshd|tcpdump|oprofile|uuidd)$ - ^(root|bin|daemon|adm|lp|sync|shutdown|halt|mail|operator|games|ftp|nobody|pegasus|systemd-bus-proxy|systemd-network|dbus|polkitd|abrt|unbound|tss|libstoragemgmt|rpc|colord|usbmuxd$|pcp|saslauth|geoclue|setroubleshoot|rtkit|chrony|qemu|radvd|rpcuser|nfsnobody|pulse|gdm|gnome-initial-setup|postfix|avahi|ntp|sshd|tcpdump|oprofile|uuidd|systemd-resolve|systemd-coredump|sssd|rngd)$ - ^(root|bin|daemon|adm|lp|sync|shutdown|halt|mail|operator|games|ftp|nobody|pegasus|systemd-bus-proxy|systemd-network|dbus|polkitd|abrt|unbound|tss|libstoragemgmt|rpc|colord|usbmuxd$|pcp|saslauth|geoclue|setroubleshoot|rtkit|chrony|qemu|radvd|rpcuser|nfsnobody|pulse|gdm|gnome-initial-setup|postfix|avahi|ntp|sshd|tcpdump|oprofile|uuidd|systemd-resolve|systemd-coredump|sssd|rngd)$ - ^(root|bin|daemon|adm|lp|sync|shutdown|halt|mail|operator|games|ftp|nobody|pegasus|systemd-bus-proxy|systemd-network|dbus|polkitd|abrt|unbound|tss|libstoragemgmt|rpc|colord|usbmuxd$|pcp|saslauth|geoclue|setroubleshoot|rtkit|chrony|qemu|radvd|rpcuser|nfsnobody|pulse|gdm|gnome-initial-setup|postfix|avahi|ntp|sshd|tcpdump|oprofile|uuidd|systemd-resolve|systemd-coredump|sssd|rngd|man|systemd-timesync|scard|hacluster|statd|at|dockremap|vnc)$ - ^(root|bin|daemon|adm|lp|sync|shutdown|halt|mail|operator|games|ftp|nobody|pegasus|systemd-bus-proxy|systemd-network|dbus|polkitd|abrt|unbound|tss|libstoragemgmt|rpc|colord|usbmuxd$|pcp|saslauth|geoclue|setroubleshoot|rtkit|chrony|qemu|radvd|rpcuser|nfsnobody|pulse|gdm|gnome-initial-setup|postfix|avahi|ntp|sshd|tcpdump|oprofile|uuidd|systemd-resolve|systemd-coredump|sssd|rngd|man|systemd-timesync|scard|hacluster|statd|at|dockremap|vnc|messagebus|nscd)$ - - - Ensure All Accounts on the System Have Unique User IDs - Change user IDs (UIDs), or delete accounts, so each has a unique name. - Automatic remediation of this control is not available due to unique requirements of each -system. - CCI-000135 - CCI-000764 - CCI-000804 - Req-8.1.1 - 8.2.1 - SRG-OS-000104-GPOS-00051 - SRG-OS-000121-GPOS-00062 - SRG-OS-000042-GPOS-00020 - To assure accountability and prevent unauthenticated access, interactive users must be identified and authenticated to prevent potential misuse and compromise of the system. - - - - - - - - - - Only Authorized Local User Accounts Exist on Operating System - Enterprise Application tends to use the server or virtual machine exclusively. +in OVAL that is always allowed on the operating system. + ^(abrt|adm|avahi|bin|chrony|clevis|cockpit-ws|cockpit-wsinstance|colord|daemon|dbus|dnsmasq|flatpak|ftp|games|gdm|geoclue|gluster|gnome-initial-setup|halt|libstoragemgmt|lp|mail|nfsnobody|nobody|ntp|operator|oprofile|oracle|pcp|pegasus|pipewire|polkitd|postfix|pulse|qemu|radvd|rngd|root|rpc|rpcuser|rtkit|saned|saslauth|setroubleshoot|shutdown|sshd|sssd|sync|systemd-bus-proxy|systemd-coredump|systemd-network|systemd-resolve|tcpdump|tss|unbound|usbmuxd$|uuidd)$ + ^(abrt|adm|avahi|bin|chrony|clevis|cockpit-ws|cockpit-wsinstance|colord|daemon|dbus|dnsmasq|flatpak|ftp|games|gdm|geoclue|gluster|gnome-initial-setup|halt|libstoragemgmt|lp|mail|nfsnobody|nobody|ntp|operator|oprofile|oracle|pcp|pegasus|pipewire|polkitd|postfix|pulse|qemu|radvd|rngd|root|rpc|rpcuser|rtkit|saned|saslauth|setroubleshoot|shutdown|sshd|sssd|sync|systemd-bus-proxy|systemd-coredump|systemd-network|systemd-resolve|tcpdump|tss|unbound|usbmuxd$|uuidd)$ + ^(abrt|adm|avahi|bin|chrony|clevis|cockpit-ws|cockpit-wsinstance|colord|daemon|dbus|dnsmasq|fapolicyd|flatpak|ftp|games|gdm|geoclue|gluster|gnome-initial-setup|halt|libstoragemgmt|lp|mail|nfsnobody|nobody|ntp|operator|oprofile|oracle|pcp|pegasus|pipewire|polkitd|postfix|pulse|qemu|radvd|rngd|root|rpc|rpcuser|rtkit|saned|saslauth|setroubleshoot|shutdown|sshd|sssd|sync|systemd-bus-proxy|systemd-coredump|systemd-network|systemd-oom|systemd-resolve|tcpdump|tss|unbound|usbmuxd$|uuidd)$ + ^(root|bin|daemon|adm|lp|sync|shutdown|halt|mail|operator|games|ftp|nobody|pegasus|systemd-bus-proxy|systemd-network|dbus|polkitd|abrt|unbound|tss|libstoragemgmt|rpc|colord|usbmuxd$|pcp|saslauth|geoclue|setroubleshoot|rtkit|chrony|qemu|radvd|rpcuser|nfsnobody|pulse|gdm|gnome-initial-setup|postfix|avahi|ntp|sshd|tcpdump|oprofile|uuidd)$ + ^(root|bin|daemon|adm|lp|sync|shutdown|halt|mail|operator|games|ftp|nobody|pegasus|systemd-bus-proxy|systemd-network|dbus|polkitd|abrt|unbound|tss|libstoragemgmt|rpc|colord|usbmuxd$|pcp|saslauth|geoclue|setroubleshoot|rtkit|chrony|qemu|radvd|rpcuser|nfsnobody|pulse|gdm|gnome-initial-setup|postfix|avahi|ntp|sshd|tcpdump|oprofile|uuidd|systemd-resolve|systemd-coredump|sssd|rngd)$ + ^(root|bin|daemon|adm|lp|sync|shutdown|halt|mail|operator|games|ftp|nobody|tss|systemd-coredump|dbus|polkitd|avahi|colord|rtkit|pipewire|clevis|sssd|geoclue|flatpak|setroubleshoot|libstoragemgmt|systemd-oom|gdm|cockpit-ws|cockpit-wsinstance|gnome-initial-setup|sshd|chrony|dnsmasq|tcpdump|admin)$ + ^(root|bin|daemon|adm|lp|sync|shutdown|halt|mail|operator|games|ftp|nobody|pegasus|systemd-bus-proxy|systemd-network|dbus|polkitd|abrt|unbound|tss|libstoragemgmt|rpc|colord|usbmuxd$|pcp|saslauth|geoclue|setroubleshoot|rtkit|chrony|qemu|radvd|rpcuser|nfsnobody|pulse|gdm|gnome-initial-setup|postfix|avahi|ntp|sshd|tcpdump|oprofile|uuidd|systemd-resolve|systemd-coredump|sssd|rngd|man|systemd-timesync|scard|hacluster|statd|at|dockremap|vnc)$ + ^(root|bin|daemon|adm|lp|sync|shutdown|halt|mail|operator|games|ftp|nobody|pegasus|systemd-bus-proxy|systemd-network|dbus|polkitd|abrt|unbound|tss|libstoragemgmt|rpc|colord|usbmuxd$|pcp|saslauth|geoclue|setroubleshoot|rtkit|chrony|qemu|radvd|rpcuser|nfsnobody|pulse|gdm|gnome-initial-setup|postfix|avahi|ntp|sshd|tcpdump|oprofile|uuidd|systemd-resolve|systemd-coredump|sssd|rngd|man|systemd-timesync|scard|hacluster|statd|at|dockremap|vnc|messagebus|nscd|flatpak|srvGeoClue|tftp|wsdd|dnsmasq|usbmux|brltty)$ + ^(root|bin|daemon|adm|lp|sync|shutdown|halt|mail|operator|games|ftp|nobody|pegasus|systemd-bus-proxy|systemd-network|dbus|polkitd|abrt|unbound|tss|libstoragemgmt|rpc|colord|usbmuxd$|pcp|saslauth|geoclue|setroubleshoot|rtkit|chrony|qemu|radvd|rpcuser|nfsnobody|pulse|gdm|gnome-initial-setup|postfix|avahi|ntp|sshd|tcpdump|oprofile|uuidd|systemd-resolve|systemd-coredump|sssd|rngd|man|systemd-timesync|scard|hacluster|statd|at|dockremap|vnc|messagebus|nscd|flatpak|srvGeoClue|tftp|wsdd|dnsmasq|usbmux|brltty|salt|cockpit-ws|cockpit-wsinstance)$ + ^(root|bin|daemon|adm|lp|sync|shutdown|halt|mail|operator|games|ftp|nobody|tss|systemd-coredump|dbus|polkitd|avahi|colord|rtkit|pipewire|clevis|sssd|geoclue|flatpak|setroubleshoot|libstoragemgmt|systemd-oom|gdm|cockpit-ws|cockpit-wsinstance|gnome-initial-setup|sshd|chrony|dnsmasq|tcpdump|admin)$ + + + Ensure All Accounts on the System Have Unique User IDs + Change user IDs (UIDs), or delete accounts, so each has a unique name. + Automatic remediation of this control is not available due to unique requirements of each +system. + CCI-000135 + CCI-000764 + CCI-000804 + Req-8.1.1 + SRG-OS-000104-GPOS-00051 + SRG-OS-000121-GPOS-00062 + 8.2.1 + 8.2 + OL09-00-003001 + SV-271832r1092208_rule + To assure accountability and prevent unauthenticated access, interactive users must be identified and authenticated to prevent potential misuse and compromise of the system. + + + + + + + + + + Only Authorized Local User Accounts Exist on Operating System + Enterprise Application tends to use the server or virtual machine exclusively. Besides the default operating system user, there should be only authorized local users required by the installed software groups and applications that exist on the operating system. The authorized user list can be customized in the refine @@ -32509,41 +37274,48 @@ Configure the system so all accounts on the system are assigned to an active sys application, or user account. Remove accounts that do not support approved system activities or that allow for a normal user to perform administrative-level actions. To remove unauthorized system accounts, use the following command: -$ sudo userdel unauthorized_user - Automatic remediation of this control is not available due to the unique -requirements of each system. - CCI-000366 - SRG-OS-000480-GPOS-00227 - Accounts providing no operational purpose provide additional opportunities for +$ sudo userdel unauthorized_user + + + Automatic remediation of this control is not available due to the unique +requirements of each system. + CCI-000366 + SRG-OS-000480-GPOS-00227 + OL09-00-002501 + SV-271770r1092022_rule + Accounts providing no operational purpose provide additional opportunities for system compromise. Unnecessary accounts include user accounts for individuals not requiring access to the system and application accounts for applications not installed -on the system. - - - - - - - - - - Ensure All Groups on the System Have Unique Group ID - Change the group name or delete groups, so each has a unique id. - Automatic remediation of this control is not available due to the unique requirements of each system. - CCI-000764 - 8.2.1 - SRG-OS-000104-GPOS-00051 - To assure accountability and prevent unauthenticated access, groups must be identified uniquely to prevent potential misuse and compromise of the system. - - - - - - - - - Set Account Expiration Parameters - Accounts can be configured to be automatically disabled +on the system. + + + + + + + + + + Ensure All Groups on the System Have Unique Group ID + Change the group name or delete groups, so each has a unique id. + Automatic remediation of this control is not available due to the unique requirements of each system. + CCI-000764 + SRG-OS-000104-GPOS-00051 + 8.2.1 + 8.2 + OL09-00-003006 + SV-271835r1092217_rule + To assure accountability and prevent unauthenticated access, groups must be identified uniquely to prevent potential misuse and compromise of the system. + + + + + + + + + Set Account Expiration Parameters + Accounts can be configured to be automatically disabled after a certain time period, meaning that they will require administrator interaction to become usable again. Expiration of accounts after inactivity can be set for all accounts by default @@ -32551,62 +37323,64 @@ and also on a per-account basis, such as for accounts that are known to be tempo To configure automatic expiration of an account following the expiration of its password (that is, after the password has expired and not been changed), run the following command, substituting NUM_DAYS and USER appropriately: -$ sudo chage -I NUM_DAYS USER +$ sudo chage -I NUM_DAYS USER + Accounts, such as temporary accounts, can also be configured to expire on an explicitly-set date with the -E option. The file /etc/default/useradd controls default settings for all newly-created accounts created with the system's -normal command line utilities. - This will only apply to newly created accounts - - number of days after the last login of the user when the user will be locked out - 'This option is specific for the auth or account phase. It specifies the number of days after -the last login of the user when the user will be locked out by the pam_lastlog module.' - 0 - 180 - 30 - 35 - 40 - 60 - 90 - 35 - - - number of days after a password expires until the account is permanently disabled - The number of days to wait after a password expires, until the account will be permanently disabled. - 0 - 180 - 30 - 35 - 40 - 60 - 90 - 35 - - - Set Account Expiration Following Inactivity in password-auth - Verify the account identifiers (individuals, groups, roles, and devices) are disabled after - or less days of inactivity by +normal command line utilities. + This will only apply to newly created accounts + + number of days after the last login of the user when the user will be locked out + 'This option is specific for the auth or account phase. It specifies the number of days after +the last login of the user when the user will be locked out by the pam_lastlog module.' + 0 + 180 + 30 + 35 + 40 + 60 + 90 + 35 + + + number of days after a password expires until the account is permanently disabled + The number of days to wait after a password expires, until the account will be permanently disabled. + 0 + 180 + 30 + 35 + 40 + 45 + 60 + 90 + 35 + + + Set Account Expiration Following Inactivity in password-auth + Verify the account identifiers (individuals, groups, roles, and devices) are disabled after + or less days of inactivity by checking the account inactivity value with the following command: grep 'inactive\|pam_unix' /etc/pam.d/password-auth | grep -w auth auth required pam_lastlog.so inactive=35 auth sufficient pam_unix.so The line with the inactive parameter should be placed before pam_unix.so module as in -the example output. - If the system relies on authselect tool to manage PAM settings, the remediation +the example output. + If the system relies on authselect tool to manage PAM settings, the remediation will also use authselect tool. However, if any manual modification was made in PAM files, the authselect integrity check will fail and the remediation will be aborted in order to preserve intentional changes. In this case, an informative message will -be shown in the remediation report. - CCI-000795 - IA-4(e) - SRG-OS-000118-GPOS-00060 - Inactive identifiers pose a risk to systems and applications because attackers may exploit an +be shown in the remediation report. + CCI-000795 + IA-4(e) + SRG-OS-000118-GPOS-00060 + Inactive identifiers pose a risk to systems and applications because attackers may exploit an inactive identifier and potentially obtain undetected access to the system. Owners of inactive -accounts will not notice if unauthorized access to their user account has been obtained. - - # Remediation is applicable only in certain platforms +accounts will not notice if unauthorized access to their user account has been obtained. + + # Remediation is applicable only in certain platforms if rpm --quiet -q pam; then PAM_FILE_PATH="/etc/pam.d/password-auth" @@ -32623,6 +37397,11 @@ if [ -f /usr/bin/authselect ]; then # If not already in use, a custom profile is created preserving the enabled features. if [[ ! $CURRENT_PROFILE == custom/* ]]; then ENABLED_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }') + # The "local" profile does not contain essential security features required by multiple Benchmarks. + # If currently used, it is replaced by "sssd", which is the best option in this case. + if [[ $CURRENT_PROFILE == local ]]; then + CURRENT_PROFILE="sssd" + fi authselect create-profile hardening -b $CURRENT_PROFILE CURRENT_PROFILE="custom/hardening" @@ -32638,36 +37417,47 @@ if [ -f /usr/bin/authselect ]; then PAM_FILE_PATH="/etc/authselect/$CURRENT_PROFILE/$PAM_FILE_NAME" authselect apply-changes -b --backup=before-hardening-pam_lastlog.so-inactive.backup fi -if ! grep -qP '^\s*auth\s+'"required"'\s+pam_lastlog.so\s*.*' "$PAM_FILE_PATH"; then + + +if ! grep -qP "^\s*auth\s+required\s+pam_lastlog.so\s*.*" "$PAM_FILE_PATH"; then # Line matching group + control + module was not found. Check group + module. if [ "$(grep -cP '^\s*auth\s+.*\s+pam_lastlog.so\s*' "$PAM_FILE_PATH")" -eq 1 ]; then # The control is updated only if one single line matches. - sed -i -E --follow-symlinks 's/^(\s*auth\s+).*(\bpam_lastlog.so.*)/\1'"required"' \2/' "$PAM_FILE_PATH" + sed -i -E --follow-symlinks "s/^(\s*auth\s+).*(\bpam_lastlog.so.*)/\1required \2/" "$PAM_FILE_PATH" else - echo 'auth '"required"' pam_lastlog.so' >> "$PAM_FILE_PATH" + echo "auth required pam_lastlog.so" >> "$PAM_FILE_PATH" fi fi # Check the option -if ! grep -qP '^\s*auth\s+'"required"'\s+pam_lastlog.so\s*.*\sinactive\b' "$PAM_FILE_PATH"; then - sed -i -E --follow-symlinks '/\s*auth\s+'"required"'\s+pam_lastlog.so.*/ s/$/ inactive='"35"'/' "$PAM_FILE_PATH" +if ! grep -qP "^\s*auth\s+required\s+pam_lastlog.so\s*.*\sinactive\b" "$PAM_FILE_PATH"; then + sed -i -E --follow-symlinks "/\s*auth\s+required\s+pam_lastlog.so.*/ s/$/ inactive=35/" "$PAM_FILE_PATH" else - sed -i -E --follow-symlinks 's/(\s*auth\s+'"required"'\s+pam_lastlog.so\s+.*)('"inactive"'=)[[:alnum:]]+\s*(.*)/\1\2'"35"' \3/' "$PAM_FILE_PATH" + sed -i -E --follow-symlinks "s/(\s*auth\s+required\s+pam_lastlog.so\s+.*)(inactive=)[[:alnum:]]+\s*(.*)/\1\235 \3/" "$PAM_FILE_PATH" fi -if ! grep -qP '^\s*auth\s+'"sufficient"'\s+pam_unix.so\s*.*' "$PAM_FILE_PATH"; then + +if ! grep -qP "^\s*auth\s+sufficient\s+pam_unix.so\s*.*" "$PAM_FILE_PATH"; then # Line matching group + control + module was not found. Check group + module. if [ "$(grep -cP '^\s*auth\s+.*\s+pam_unix.so\s*' "$PAM_FILE_PATH")" -eq 1 ]; then # The control is updated only if one single line matches. - sed -i -E --follow-symlinks 's/^(\s*auth\s+).*(\bpam_unix.so.*)/\1'"sufficient"' \2/' "$PAM_FILE_PATH" + sed -i -E --follow-symlinks "s/^(\s*auth\s+).*(\bpam_unix.so.*)/\1sufficient \2/" "$PAM_FILE_PATH" else - echo 'auth '"sufficient"' pam_unix.so' >> "$PAM_FILE_PATH" + LAST_MATCH_LINE=$(grep -nP "^\s*auth.*required.*pam_lastlog\.so.*" "$PAM_FILE_PATH" | tail -n 1 | cut -d: -f 1) + if [ ! -z $LAST_MATCH_LINE ]; then + sed -i --follow-symlinks $LAST_MATCH_LINE" a auth sufficient pam_unix.so" "$PAM_FILE_PATH" + else + echo "auth sufficient pam_unix.so" >> "$PAM_FILE_PATH" + fi fi fi # Ensure pam_unix.so is configured after pam_lastlog.so if ! grep -Pz \ "auth\s*required\s*pam_lastlog\.so[^#]*inactive=35[\s\S]*\n\s*auth\s*sufficient\s*pam_unix\.so"\ "$PAM_FILE_PATH" ; then - PAM_LASTLOG_LINE="$(grep -oP '^\s*auth.*pam_lastlog\.so.*' $PAM_FILE_PATH)" - sed -i "0,/^\s*auth.*pam_unix\.so.*/i$PAM_LASTLOG_LINE" "$PAM_FILE_PATH" + readarray -t pam_lastlog_lines <<< "$(grep -oP '^\s*auth.*pam_lastlog\.so[^#]*inactive=35.*' $PAM_FILE_PATH)" + sed -i "/^\s*auth.*pam_lastlog\.so[^#]*inactive=35.*/d" "$PAM_FILE_PATH" + for line in "${pam_lastlog_lines[@]}"; do + sed -i "/^\s*auth.*pam_unix\.so.*/i$line" "$PAM_FILE_PATH" + done fi if [ -f /usr/bin/authselect ]; then authselect apply-changes -b --backup=after-hardening-pam_lastlog.so-inactive.backup @@ -32676,39 +37466,39 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - - - - - - - - - Set Account Expiration Following Inactivity in system-auth - Verify the account identifiers (individuals, groups, roles, and devices) are disabled after - or less days of inactivity by + + + + + + + + + + + Set Account Expiration Following Inactivity in system-auth + Verify the account identifiers (individuals, groups, roles, and devices) are disabled after + or less days of inactivity by checking the account inactivity value with the following command: grep 'inactive\|pam_unix' /etc/pam.d/password-auth | grep -w auth auth required pam_lastlog.so inactive=35 auth sufficient pam_unix.so The line with the inactive parameter should be placed before pam_unix.so module as in -the example output. - If the system relies on authselect tool to manage PAM settings, the remediation +the example output. + If the system relies on authselect tool to manage PAM settings, the remediation will also use authselect tool. However, if any manual modification was made in PAM files, the authselect integrity check will fail and the remediation will be aborted in order to preserve intentional changes. In this case, an informative message will -be shown in the remediation report. - CCI-000795 - IA-4(e) - SRG-OS-000118-GPOS-00060 - Inactive identifiers pose a risk to systems and applications because attackers may exploit an +be shown in the remediation report. + CCI-000795 + IA-4(e) + SRG-OS-000118-GPOS-00060 + Inactive identifiers pose a risk to systems and applications because attackers may exploit an inactive identifier and potentially obtain undetected access to the system. Owners of inactive -accounts will not notice if unauthorized access to their user account has been obtained. - - # Remediation is applicable only in certain platforms +accounts will not notice if unauthorized access to their user account has been obtained. + + # Remediation is applicable only in certain platforms if rpm --quiet -q pam; then PAM_FILE_PATH="/etc/pam.d/system-auth" @@ -32725,6 +37515,11 @@ if [ -f /usr/bin/authselect ]; then # If not already in use, a custom profile is created preserving the enabled features. if [[ ! $CURRENT_PROFILE == custom/* ]]; then ENABLED_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }') + # The "local" profile does not contain essential security features required by multiple Benchmarks. + # If currently used, it is replaced by "sssd", which is the best option in this case. + if [[ $CURRENT_PROFILE == local ]]; then + CURRENT_PROFILE="sssd" + fi authselect create-profile hardening -b $CURRENT_PROFILE CURRENT_PROFILE="custom/hardening" @@ -32740,36 +37535,47 @@ if [ -f /usr/bin/authselect ]; then PAM_FILE_PATH="/etc/authselect/$CURRENT_PROFILE/$PAM_FILE_NAME" authselect apply-changes -b --backup=before-hardening-pam_lastlog.so-inactive.backup fi -if ! grep -qP '^\s*auth\s+'"required"'\s+pam_lastlog.so\s*.*' "$PAM_FILE_PATH"; then + + +if ! grep -qP "^\s*auth\s+required\s+pam_lastlog.so\s*.*" "$PAM_FILE_PATH"; then # Line matching group + control + module was not found. Check group + module. if [ "$(grep -cP '^\s*auth\s+.*\s+pam_lastlog.so\s*' "$PAM_FILE_PATH")" -eq 1 ]; then # The control is updated only if one single line matches. - sed -i -E --follow-symlinks 's/^(\s*auth\s+).*(\bpam_lastlog.so.*)/\1'"required"' \2/' "$PAM_FILE_PATH" + sed -i -E --follow-symlinks "s/^(\s*auth\s+).*(\bpam_lastlog.so.*)/\1required \2/" "$PAM_FILE_PATH" else - echo 'auth '"required"' pam_lastlog.so' >> "$PAM_FILE_PATH" + echo "auth required pam_lastlog.so" >> "$PAM_FILE_PATH" fi fi # Check the option -if ! grep -qP '^\s*auth\s+'"required"'\s+pam_lastlog.so\s*.*\sinactive\b' "$PAM_FILE_PATH"; then - sed -i -E --follow-symlinks '/\s*auth\s+'"required"'\s+pam_lastlog.so.*/ s/$/ inactive='"35"'/' "$PAM_FILE_PATH" +if ! grep -qP "^\s*auth\s+required\s+pam_lastlog.so\s*.*\sinactive\b" "$PAM_FILE_PATH"; then + sed -i -E --follow-symlinks "/\s*auth\s+required\s+pam_lastlog.so.*/ s/$/ inactive=35/" "$PAM_FILE_PATH" else - sed -i -E --follow-symlinks 's/(\s*auth\s+'"required"'\s+pam_lastlog.so\s+.*)('"inactive"'=)[[:alnum:]]+\s*(.*)/\1\2'"35"' \3/' "$PAM_FILE_PATH" + sed -i -E --follow-symlinks "s/(\s*auth\s+required\s+pam_lastlog.so\s+.*)(inactive=)[[:alnum:]]+\s*(.*)/\1\235 \3/" "$PAM_FILE_PATH" fi -if ! grep -qP '^\s*auth\s+'"sufficient"'\s+pam_unix.so\s*.*' "$PAM_FILE_PATH"; then + +if ! grep -qP "^\s*auth\s+sufficient\s+pam_unix.so\s*.*" "$PAM_FILE_PATH"; then # Line matching group + control + module was not found. Check group + module. if [ "$(grep -cP '^\s*auth\s+.*\s+pam_unix.so\s*' "$PAM_FILE_PATH")" -eq 1 ]; then # The control is updated only if one single line matches. - sed -i -E --follow-symlinks 's/^(\s*auth\s+).*(\bpam_unix.so.*)/\1'"sufficient"' \2/' "$PAM_FILE_PATH" + sed -i -E --follow-symlinks "s/^(\s*auth\s+).*(\bpam_unix.so.*)/\1sufficient \2/" "$PAM_FILE_PATH" else - echo 'auth '"sufficient"' pam_unix.so' >> "$PAM_FILE_PATH" + LAST_MATCH_LINE=$(grep -nP "^\s*auth.*required.*pam_lastlog\.so.*" "$PAM_FILE_PATH" | tail -n 1 | cut -d: -f 1) + if [ ! -z $LAST_MATCH_LINE ]; then + sed -i --follow-symlinks $LAST_MATCH_LINE" a auth sufficient pam_unix.so" "$PAM_FILE_PATH" + else + echo "auth sufficient pam_unix.so" >> "$PAM_FILE_PATH" + fi fi fi # Ensure pam_unix.so is configured after pam_lastlog.so if ! grep -Pz \ "auth\s*required\s*pam_lastlog\.so[^#]*inactive=35[\s\S]*\n\s*auth\s*sufficient\s*pam_unix\.so"\ "$PAM_FILE_PATH" ; then - PAM_LASTLOG_LINE="$(grep -oP '^\s*auth.*pam_lastlog\.so.*' $PAM_FILE_PATH)" - sed -i "0,/^\s*auth.*pam_unix\.so.*/i$PAM_LASTLOG_LINE" "$PAM_FILE_PATH" + readarray -t pam_lastlog_lines <<< "$(grep -oP '^\s*auth.*pam_lastlog\.so[^#]*inactive=35.*' $PAM_FILE_PATH)" + sed -i "/^\s*auth.*pam_lastlog\.so[^#]*inactive=35.*/d" "$PAM_FILE_PATH" + for line in "${pam_lastlog_lines[@]}"; do + sed -i "/^\s*auth.*pam_unix\.so.*/i$line" "$PAM_FILE_PATH" + done fi if [ -f /usr/bin/authselect ]; then authselect apply-changes -b --backup=after-hardening-pam_lastlog.so-inactive.backup @@ -32778,122 +37584,126 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - - - - - - - - - Set Account Expiration Following Inactivity - To specify the number of days after a password expires (which + + + + + + + + + + + Set Account Expiration Following Inactivity + To specify the number of days after a password expires (which signifies inactivity) until an account is permanently disabled, add or correct the following line in /etc/default/useradd: -INACTIVE= +INACTIVE= + If a password is currently on the verge of expiration, then - + day(s) remain(s) until the account is automatically disabled. However, if the password will not expire for another 60 days, then 60 -days plus day(s) could +days plus day(s) could elapse until the account would be automatically disabled. See the -useradd man page for more information. - 1 - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - 7 - 8 - 5.6.2.1.1 - DSS01.03 - DSS03.05 - DSS05.04 - DSS05.05 - DSS05.07 - DSS05.10 - DSS06.03 - DSS06.10 - 3.5.6 - CCI-000017 - CCI-000795 - 4.3.3.2.2 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - SR 1.1 - SR 1.10 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 6.2 - A.12.4.1 - A.12.4.3 - A.18.1.4 - A.6.1.2 - A.7.1.1 - A.9.1.2 - A.9.2.1 - A.9.2.2 - A.9.2.3 - A.9.2.4 - A.9.2.6 - A.9.3.1 - A.9.4.1 - A.9.4.2 - A.9.4.3 - A.9.4.4 - A.9.4.5 - CIP-004-6 R2.2.2 - CIP-004-6 R2.2.3 - CIP-007-3 R.1.3 - CIP-007-3 R5 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.3 - CIP-007-3 R5.2.1 - CIP-007-3 R5.2.3 - IA-4(e) - AC-2(3) - CM-6(a) - DE.CM-1 - DE.CM-3 - PR.AC-1 - PR.AC-4 - PR.AC-6 - PR.AC-7 - Req-8.1.4 - 8.2.6 - SRG-OS-000118-GPOS-00060 - Inactive identifiers pose a risk to systems and applications because attackers may exploit an inactive identifier and potentially obtain undetected access to the system. +useradd man page for more information. + 1 + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + 7 + 8 + 5.6.2.1.1 + DSS01.03 + DSS03.05 + DSS05.04 + DSS05.05 + DSS05.07 + DSS05.10 + DSS06.03 + DSS06.10 + 3.5.6 + CCI-003628 + CCI-003627 + 4.3.3.2.2 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + SR 1.1 + SR 1.10 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 6.2 + A.12.4.1 + A.12.4.3 + A.18.1.4 + A.6.1.2 + A.7.1.1 + A.9.1.2 + A.9.2.1 + A.9.2.2 + A.9.2.3 + A.9.2.4 + A.9.2.6 + A.9.3.1 + A.9.4.1 + A.9.4.2 + A.9.4.3 + A.9.4.4 + A.9.4.5 + CIP-004-6 R2.2.2 + CIP-004-6 R2.2.3 + CIP-007-3 R.1.3 + CIP-007-3 R5 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.3 + CIP-007-3 R5.2.1 + CIP-007-3 R5.2.3 + IA-4(e) + AC-2(3) + CM-6(a) + DE.CM-1 + DE.CM-3 + PR.AC-1 + PR.AC-4 + PR.AC-6 + PR.AC-7 + Req-8.1.4 + SRG-OS-000118-GPOS-00060 + 8.2.6 + 8.2 + OL09-00-003065 + SV-271849r1092259_rule + Inactive identifiers pose a risk to systems and applications because attackers may exploit an inactive identifier and potentially obtain undetected access to the system. Disabling inactive accounts ensures that accounts which may not have been responsibly removed are not available to attackers who may have compromised their credentials. -Owners of inactive accounts will not notice if unauthorized access to their user account has been obtained. - - # Remediation is applicable only in certain platforms +Owners of inactive accounts will not notice if unauthorized access to their user account has been obtained. + + # Remediation is applicable only in certain platforms if rpm --quiet -q shadow-utils; then -var_account_disable_post_pw_expiration='' +var_account_disable_post_pw_expiration='' # Strip any search characters in the key arg so that the key can be replaced without @@ -32919,17 +37729,19 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: - CJIS-5.6.2.1.1 + - DISA-STIG-OL09-00-003065 - NIST-800-171-3.5.6 - NIST-800-53-AC-2(3) - NIST-800-53-CM-6(a) - NIST-800-53-IA-4(e) - PCI-DSS-Req-8.1.4 + - PCI-DSSv4-8.2 - PCI-DSSv4-8.2.6 - account_disable_post_pw_expiration - low_complexity @@ -32939,7 +37751,7 @@ fi - restrict_strategy - name: XCCDF Value var_account_disable_post_pw_expiration # promote to variable set_fact: - var_account_disable_post_pw_expiration: !!str + var_account_disable_post_pw_expiration: !!str tags: - always @@ -32952,11 +37764,13 @@ fi when: '"shadow-utils" in ansible_facts.packages' tags: - CJIS-5.6.2.1.1 + - DISA-STIG-OL09-00-003065 - NIST-800-171-3.5.6 - NIST-800-53-AC-2(3) - NIST-800-53-CM-6(a) - NIST-800-53-IA-4(e) - PCI-DSS-Req-8.1.4 + - PCI-DSSv4-8.2 - PCI-DSSv4-8.2.6 - account_disable_post_pw_expiration - low_complexity @@ -32964,234 +37778,151 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - - Assign Expiration Date to Emergency Accounts - Emergency accounts are privileged accounts established in response to -crisis situations where the need for rapid account activation is required. -In the event emergency accounts are required, configure the system to -terminate them after a documented time period. For every emergency account, -run the following command to set an expiration date on it, substituting -ACCOUNT_NAME and YYYY-MM-DD -appropriately: -$ sudo chage -E YYYY-MM-DD ACCOUNT_NAME -YYYY-MM-DD indicates the documented expiration date for the -account. For U.S. Government systems, the operating system must be -configured to automatically terminate these types of accounts after a -period of 72 hours. - Due to the unique requirements of each system, automated -remediation is not available for this configuration check. - This rule is deprecated in favor of the account_temp_expire_date rule. -Please consider replacing this rule in your files as it is not expected to receive -updates as of version 0.1.69. - 1 - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - 7 - 8 - DSS01.03 - DSS03.05 - DSS05.04 - DSS05.05 - DSS05.07 - DSS06.03 - CCI-000016 - CCI-001682 - 4.3.3.2.2 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - SR 1.1 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 6.2 - A.12.4.1 - A.12.4.3 - A.6.1.2 - A.7.1.1 - A.9.1.2 - A.9.2.1 - A.9.2.2 - A.9.2.3 - A.9.2.4 - A.9.2.6 - A.9.3.1 - A.9.4.1 - A.9.4.2 - A.9.4.3 - A.9.4.4 - A.9.4.5 - AC-2(2) - AC-2(3) - CM-6(a) - DE.CM-1 - DE.CM-3 - PR.AC-1 - PR.AC-4 - PR.AC-6 - SRG-OS-000123-GPOS-00064 - SRG-OS-000002-GPOS-00002 - If emergency user accounts remain active when no longer needed or for -an excessive period, these accounts may be used to gain unauthorized access. -To mitigate this risk, automated termination of all emergency accounts -must be set upon account creation. - - - - - - - Assign Expiration Date to Temporary Accounts - Temporary accounts are established as part of normal account activation + + + + + + + + + + + Assign Expiration Date to Temporary Accounts + Temporary accounts are established as part of normal account activation procedures when there is a need for short-term accounts. In the event temporary accounts are required, configure the system to terminate them after a documented time period. For every temporary account, run the following command to set an expiration date on it, substituting USER and YYYY-MM-DD appropriately: -$ sudo chage -E YYYY-MM-DD USER -YYYY-MM-DD indicates the documented expiration date for the +$ sudo chage -E YYYY-MM-DD USER + + YYYY-MM-DD indicates the documented expiration date for the account. For U.S. Government systems, the operating system must be configured to automatically terminate these types of accounts after a -period of 72 hours. - 1 - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - 7 - 8 - DSS01.03 - DSS03.05 - DSS05.04 - DSS05.05 - DSS05.07 - DSS06.03 - CCI-000016 - CCI-001682 - 4.3.3.2.2 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - SR 1.1 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 6.2 - A.12.4.1 - A.12.4.3 - A.6.1.2 - A.7.1.1 - A.9.1.2 - A.9.2.1 - A.9.2.2 - A.9.2.3 - A.9.2.4 - A.9.2.6 - A.9.3.1 - A.9.4.1 - A.9.4.2 - A.9.4.3 - A.9.4.4 - A.9.4.5 - AC-2(2) - AC-2(3) - CM-6(a) - DE.CM-1 - DE.CM-3 - PR.AC-1 - PR.AC-4 - PR.AC-6 - SRG-OS-000123-GPOS-00064 - SRG-OS-000002-GPOS-00002 - If temporary user accounts remain active when no longer needed or for +period of 72 hours. + 1 + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + 7 + 8 + DSS01.03 + DSS03.05 + DSS05.04 + DSS05.05 + DSS05.07 + DSS06.03 + CCI-000016 + CCI-001682 + 4.3.3.2.2 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + SR 1.1 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 6.2 + A.12.4.1 + A.12.4.3 + A.6.1.2 + A.7.1.1 + A.9.1.2 + A.9.2.1 + A.9.2.2 + A.9.2.3 + A.9.2.4 + A.9.2.6 + A.9.3.1 + A.9.4.1 + A.9.4.2 + A.9.4.3 + A.9.4.4 + A.9.4.5 + AC-2(2) + AC-2(3) + CM-6(a) + DE.CM-1 + DE.CM-3 + PR.AC-1 + PR.AC-4 + PR.AC-6 + SRG-OS-000123-GPOS-00064 + SRG-OS-000002-GPOS-00002 + OL09-00-003030 + SV-271843r1094969_rule + If temporary user accounts remain active when no longer needed or for an excessive period, these accounts may be used to gain unauthorized access. To mitigate this risk, automated termination of all temporary accounts must be set upon account creation. - - - - - - - Ensure All Accounts on the System Have Unique Names - Ensure accounts on the system have unique names. + + + + + + + + Ensure All Accounts on the System Have Unique Names + Ensure accounts on the system have unique names. To ensure all accounts have unique names, run the following command: $ sudo getent passwd | awk -F: '{ print $1}' | uniq -d -If a username is returned, change or delete the username. - 5.5.2 - CCI-000770 - CCI-000804 - Req-8.1.1 - 8.2.1 - Unique usernames allow for accountability on the system. - - - - - - - - - Use Centralized and Automated Authentication - Implement an automated system for managing user accounts that minimizes the +If a username is returned, change or delete the username. + 5.5.2 + CCI-000770 + CCI-000804 + Req-8.1.1 + 8.2.1 + 8.2 + Unique usernames allow for accountability on the system. + + + + + + + + + Use Centralized and Automated Authentication + Implement an automated system for managing user accounts that minimizes the risk of errors, either intentional or deliberate. This system should integrate with an existing enterprise user management system, such as one based on Identity Management tools such as Active Directory, Kerberos, -Directory Server, etc. - A comprehensive account management process that includes automation helps to +Directory Server, etc. + A comprehensive account management process that includes automation helps to ensure the accounts designated as requiring attention are consistently and promptly addressed. Enterprise environments make user account management challenging and complex. A user management process requiring administrators to manually address account management functions adds risk of potential -oversight. - - - - - - - Set Password Expiration Parameters - The file /etc/login.defs controls several +oversight. + + + + + + + Set Password Expiration Parameters + The file /etc/login.defs controls several password-related settings. Programs such as passwd, su, and login consult /etc/login.defs to determine behavior with regard to password aging, expiration warnings, and length. See the man page login.defs(5) for more information. - + + Users should be forced to change their passwords, in order to decrease the utility of compromised passwords. However, the need to change passwords often should be balanced against the risk that @@ -33200,170 +37931,203 @@ too often. Forcing password changes every 90-360 days, depending on the environment, is recommended. Set the appropriate value as PASS_MAX_DAYS and apply it to existing accounts with the -M flag. - + + The PASS_MIN_DAYS (-m) setting prevents password changes for 7 days after the first change, to discourage password cycling. If you use this setting, train users to contact an administrator for an emergency password change in case a new password becomes compromised. The PASS_WARN_AGE (-W) setting gives users 7 days of warnings at login time that their passwords are about to expire. - + + For example, for each existing human user USER, expiration parameters could be adjusted to a 180 day maximum password age, 7 day minimum password age, and 7 day warning period with the following command: -$ sudo chage -M 180 -m 7 -W 7 USER - - maximum password age - Maximum age of password in days - 365 - 120 - 180 - 90 - 60 - 45 - 60 - - - minimum password age - Minimum age of password in days - 0 - 1 - 2 - 5 - 7 - 7 - - - minimum password length - Minimum number of characters in password - This will only check new passwords - 10 - 12 - 14 - 15 - 18 - 20 - 6 - 8 - 15 - - - warning days before password expires - The number of days' warning given before a password expires. - This will only apply to newly created accounts - 0 - 14 - 10 - 7 - 7 - - - Set Password Maximum Age - To specify password maximum age for new accounts, +$ sudo chage -M 180 -m 7 -W 7 USER + + + maximum password age + Maximum age of password in days + 365 + 120 + 180 + 90 + 60 + 45 + 60 + + + Maximum Root Password Age + Maximum age of password in days for the root account + 365 + 99999 + + + minimum password age + Minimum age of password in days + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 7 + + + minimum password length + Minimum number of characters in password + This will only check new passwords + 10 + 12 + 14 + 15 + 17 + 18 + 20 + 6 + 8 + 15 + + + warning days before password expires + The number of days' warning given before a password expires. + This will only apply to newly created accounts + 0 + 14 + 10 + 7 + 7 + + + Set Password Maximum Age + To specify password maximum age for new accounts, edit the file /etc/login.defs and add or correct the following line: -PASS_MAX_DAYS +PASS_MAX_DAYS + A value of 180 days is sufficient for many environments. The DoD requirement is 60. -The profile requirement is . - BP28(R18) - 1 - 12 - 15 - 16 - 5 - 5.6.2.1 - DSS05.04 - DSS05.05 - DSS05.07 - DSS05.10 - DSS06.03 - DSS06.10 - 3.5.6 - CCI-000199 - 4.3.3.2.2 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.2 - 4.3.3.7.4 - SR 1.1 - SR 1.10 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - 0418 - 1055 - 1402 - A.18.1.4 - A.7.1.1 - A.9.2.1 - A.9.2.2 - A.9.2.3 - A.9.2.4 - A.9.2.6 - A.9.3.1 - A.9.4.2 - A.9.4.3 - IA-5(f) - IA-5(1)(d) - CM-6(a) - PR.AC-1 - PR.AC-6 - PR.AC-7 - Req-8.2.4 - 8.3.10.1 - SRG-OS-000076-GPOS-00044 - Any password, no matter how complex, can eventually be cracked. Therefore, passwords +The profile requirement is . + 1 + 12 + 15 + 16 + 5 + 5.6.2.1 + DSS05.04 + DSS05.05 + DSS05.07 + DSS05.10 + DSS06.03 + DSS06.10 + 3.5.6 + CCI-004066 + 4.3.3.2.2 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.2 + 4.3.3.7.4 + SR 1.1 + SR 1.10 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + 0418 + 1055 + 1402 + A.18.1.4 + A.7.1.1 + A.9.2.1 + A.9.2.2 + A.9.2.3 + A.9.2.4 + A.9.2.6 + A.9.3.1 + A.9.4.2 + A.9.4.3 + IA-5(f) + IA-5(1)(d) + CM-6(a) + PR.AC-1 + PR.AC-6 + PR.AC-7 + Req-8.2.4 + SRG-OS-000076-GPOS-00044 + A.5.SEC-OL5 + 8.3.9 + 8.3 + OL09-00-001095 + SV-271631r1091605_rule + Any password, no matter how complex, can eventually be cracked. Therefore, passwords need to be changed periodically. If the operating system does not limit the lifetime of passwords and force users to change their passwords, there is the risk that the operating system passwords could be compromised. - + + Setting the password maximum age ensures users are required to periodically change their passwords. Requiring shorter password lifetimes increases the risk of users writing down the password in a convenient -location subject to physical compromise. - - # Remediation is applicable only in certain platforms +location subject to physical compromise. + + # Remediation is applicable only in certain platforms if rpm --quiet -q shadow-utils; then -var_accounts_maximum_age_login_defs='' +var_accounts_maximum_age_login_defs='' +# Strip any search characters in the key arg so that the key can be replaced without +# adding any search characters to the config file. +stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^PASS_MAX_DAYS") -grep -q ^PASS_MAX_DAYS /etc/login.defs && \ - sed -i "s/PASS_MAX_DAYS.*/PASS_MAX_DAYS $var_accounts_maximum_age_login_defs/g" /etc/login.defs -if ! [ $? -eq 0 ]; then - echo "PASS_MAX_DAYS $var_accounts_maximum_age_login_defs" >> /etc/login.defs +# shellcheck disable=SC2059 +printf -v formatted_output "%s %s" "$stripped_key" "$var_accounts_maximum_age_login_defs" + +# If the key exists, change it. Otherwise, add it to the config_file. +# We search for the key string followed by a word boundary (matched by \>), +# so if we search for 'setting', 'setting2' won't match. +if LC_ALL=C grep -q -m 1 -i -e "^PASS_MAX_DAYS\\>" "/etc/login.defs"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + LC_ALL=C sed -i --follow-symlinks "s/^PASS_MAX_DAYS\\>.*/$escaped_formatted_output/gi" "/etc/login.defs" +else + if [[ -s "/etc/login.defs" ]] && [[ -n "$(tail -c 1 -- "/etc/login.defs" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "/etc/login.defs" + fi + printf '%s\n' "$formatted_output" >> "/etc/login.defs" fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: - CJIS-5.6.2.1 + - DISA-STIG-OL09-00-001095 - NIST-800-171-3.5.6 - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(1)(d) - NIST-800-53-IA-5(f) - PCI-DSS-Req-8.2.4 - - PCI-DSSv4-8.3.10.1 + - PCI-DSSv4-8.3 + - PCI-DSSv4-8.3.9 - accounts_maximum_age_login_defs - low_complexity - low_disruption @@ -33372,7 +38136,7 @@ fi - restrict_strategy - name: XCCDF Value var_accounts_maximum_age_login_defs # promote to variable set_fact: - var_accounts_maximum_age_login_defs: !!str + var_accounts_maximum_age_login_defs: !!str tags: - always @@ -33385,121 +38149,138 @@ fi when: '"shadow-utils" in ansible_facts.packages' tags: - CJIS-5.6.2.1 + - DISA-STIG-OL09-00-001095 - NIST-800-171-3.5.6 - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(1)(d) - NIST-800-53-IA-5(f) - PCI-DSS-Req-8.2.4 - - PCI-DSSv4-8.3.10.1 + - PCI-DSSv4-8.3 + - PCI-DSSv4-8.3.9 - accounts_maximum_age_login_defs - low_complexity - low_disruption - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - - Set Password Minimum Age - To specify password minimum age for new accounts, + + + + + + + + + + + Set Password Minimum Age + To specify password minimum age for new accounts, edit the file /etc/login.defs and add or correct the following line: -PASS_MIN_DAYS +PASS_MIN_DAYS + A value of 1 day is considered sufficient for many environments. The DoD requirement is 1. -The profile requirement is . - 1 - 12 - 15 - 16 - 5 - 5.6.2.1.1 - DSS05.04 - DSS05.05 - DSS05.07 - DSS05.10 - DSS06.03 - DSS06.10 - 3.5.8 - CCI-000198 - 4.3.3.2.2 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.2 - 4.3.3.7.4 - SR 1.1 - SR 1.10 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - 0418 - 1055 - 1402 - A.18.1.4 - A.7.1.1 - A.9.2.1 - A.9.2.2 - A.9.2.3 - A.9.2.4 - A.9.2.6 - A.9.3.1 - A.9.4.2 - A.9.4.3 - IA-5(f) - IA-5(1)(d) - CM-6(a) - PR.AC-1 - PR.AC-6 - PR.AC-7 - 8.3.9 - SRG-OS-000075-GPOS-00043 - Enforcing a minimum password lifetime helps to prevent repeated password +The profile requirement is . + 1 + 12 + 15 + 16 + 5 + 5.6.2.1.1 + DSS05.04 + DSS05.05 + DSS05.07 + DSS05.10 + DSS06.03 + DSS06.10 + 3.5.8 + CCI-004066 + 4.3.3.2.2 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.2 + 4.3.3.7.4 + SR 1.1 + SR 1.10 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + 0418 + 1055 + 1402 + A.18.1.4 + A.7.1.1 + A.9.2.1 + A.9.2.2 + A.9.2.3 + A.9.2.4 + A.9.2.6 + A.9.3.1 + A.9.4.2 + A.9.4.3 + IA-5(f) + IA-5(1)(d) + CM-6(a) + PR.AC-1 + PR.AC-6 + PR.AC-7 + SRG-OS-000075-GPOS-00043 + A.5.SEC-OL5 + Enforcing a minimum password lifetime helps to prevent repeated password changes to defeat the password reuse or history enforcement requirement. If users are allowed to immediately and continually change their password, then the password could be repeatedly changed in a short period of time to defeat the organization's policy regarding password reuse. - + + Setting the minimum password age protects against users cycling back to a -favorite password after satisfying the password reuse requirement. - - # Remediation is applicable only in certain platforms +favorite password after satisfying the password reuse requirement. + + # Remediation is applicable only in certain platforms if rpm --quiet -q shadow-utils; then -var_accounts_minimum_age_login_defs='' +var_accounts_minimum_age_login_defs='' +# Strip any search characters in the key arg so that the key can be replaced without +# adding any search characters to the config file. +stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^PASS_MIN_DAYS") -grep -q ^PASS_MIN_DAYS /etc/login.defs && \ - sed -i "s/PASS_MIN_DAYS.*/PASS_MIN_DAYS $var_accounts_minimum_age_login_defs/g" /etc/login.defs -if ! [ $? -eq 0 ]; then - echo "PASS_MIN_DAYS $var_accounts_minimum_age_login_defs" >> /etc/login.defs +# shellcheck disable=SC2059 +printf -v formatted_output "%s %s" "$stripped_key" "$var_accounts_minimum_age_login_defs" + +# If the key exists, change it. Otherwise, add it to the config_file. +# We search for the key string followed by a word boundary (matched by \>), +# so if we search for 'setting', 'setting2' won't match. +if LC_ALL=C grep -q -m 1 -i -e "^PASS_MIN_DAYS\\>" "/etc/login.defs"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + LC_ALL=C sed -i --follow-symlinks "s/^PASS_MIN_DAYS\\>.*/$escaped_formatted_output/gi" "/etc/login.defs" +else + if [[ -s "/etc/login.defs" ]] && [[ -n "$(tail -c 1 -- "/etc/login.defs" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "/etc/login.defs" + fi + printf '%s\n' "$formatted_output" >> "/etc/login.defs" fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: @@ -33508,7 +38289,6 @@ fi - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(1)(d) - NIST-800-53-IA-5(f) - - PCI-DSSv4-8.3.9 - accounts_minimum_age_login_defs - low_complexity - low_disruption @@ -33517,7 +38297,7 @@ fi - restrict_strategy - name: XCCDF Value var_accounts_minimum_age_login_defs # promote to variable set_fact: - var_accounts_minimum_age_login_defs: !!str + var_accounts_minimum_age_login_defs: !!str tags: - always @@ -33534,134 +38314,150 @@ fi - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(1)(d) - NIST-800-53-IA-5(f) - - PCI-DSSv4-8.3.9 - accounts_minimum_age_login_defs - low_complexity - low_disruption - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - - Set Password Minimum Length in login.defs - To specify password length requirements for new accounts, edit the file + + + + + + + + + + + Set Password Minimum Length in login.defs + To specify password length requirements for new accounts, edit the file /etc/login.defs and add or correct the following line: -PASS_MIN_LEN - +PASS_MIN_LEN + + + The DoD requirement is 15. The FISMA requirement is 12. The profile requirement is -. +. If a program consults /etc/login.defs and also another PAM module (such as pam_pwquality) during a password change operation, then the most restrictive must be satisfied. See PAM section for more -information about enforcing password quality requirements. - BP28(R18) - 1 - 12 - 15 - 16 - 5 - 5.6.2.1 - DSS05.04 - DSS05.05 - DSS05.07 - DSS05.10 - DSS06.03 - DSS06.10 - 3.5.7 - CCI-000205 - 4.3.3.2.2 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.2 - 4.3.3.7.4 - SR 1.1 - SR 1.10 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - 0421 - 0422 - 0431 - 0974 - 1173 - 1401 - 1504 - 1505 - 1546 - 1557 - 1558 - 1559 - 1560 - 1561 - A.18.1.4 - A.7.1.1 - A.9.2.1 - A.9.2.2 - A.9.2.3 - A.9.2.4 - A.9.2.6 - A.9.3.1 - A.9.4.2 - A.9.4.3 - IA-5(f) - IA-5(1)(a) - CM-6(a) - PR.AC-1 - PR.AC-6 - PR.AC-7 - SRG-OS-000078-GPOS-00046 - Requiring a minimum password length makes password +information about enforcing password quality requirements. + 1 + 12 + 15 + 16 + 5 + 5.6.2.1 + DSS05.04 + DSS05.05 + DSS05.07 + DSS05.10 + DSS06.03 + DSS06.10 + 3.5.7 + CCI-004066 + 4.3.3.2.2 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.2 + 4.3.3.7.4 + SR 1.1 + SR 1.10 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + 0421 + 0422 + 0431 + 0974 + 1173 + 1401 + 1504 + 1505 + 1546 + 1557 + 1558 + 1559 + 1560 + 1561 + A.18.1.4 + A.7.1.1 + A.9.2.1 + A.9.2.2 + A.9.2.3 + A.9.2.4 + A.9.2.6 + A.9.3.1 + A.9.4.2 + A.9.4.3 + IA-5(f) + IA-5(1)(a) + CM-6(a) + PR.AC-1 + PR.AC-6 + PR.AC-7 + SRG-OS-000078-GPOS-00046 + R31 + OL09-00-001105 + SV-271633r1091611_rule + Requiring a minimum password length makes password cracking attacks more difficult by ensuring a larger search space. However, any security benefit from an onerous requirement must be carefully weighed against usability problems, support costs, or counterproductive -behavior that may result. - - # Remediation is applicable only in certain platforms +behavior that may result. + + # Remediation is applicable only in certain platforms if rpm --quiet -q shadow-utils; then -var_accounts_password_minlen_login_defs='' +var_accounts_password_minlen_login_defs='' +# Strip any search characters in the key arg so that the key can be replaced without +# adding any search characters to the config file. +stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^PASS_MIN_LEN") -grep -q ^PASS_MIN_LEN /etc/login.defs && \ -sed -i "s/PASS_MIN_LEN.*/PASS_MIN_LEN\t$var_accounts_password_minlen_login_defs/g" /etc/login.defs -if ! [ $? -eq 0 ] -then - echo -e "PASS_MIN_LEN\t$var_accounts_password_minlen_login_defs" >> /etc/login.defs +# shellcheck disable=SC2059 +printf -v formatted_output "%s %s" "$stripped_key" "$var_accounts_password_minlen_login_defs" + +# If the key exists, change it. Otherwise, add it to the config_file. +# We search for the key string followed by a word boundary (matched by \>), +# so if we search for 'setting', 'setting2' won't match. +if LC_ALL=C grep -q -m 1 -i -e "^PASS_MIN_LEN\\>" "/etc/login.defs"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + LC_ALL=C sed -i --follow-symlinks "s/^PASS_MIN_LEN\\>.*/$escaped_formatted_output/gi" "/etc/login.defs" +else + if [[ -s "/etc/login.defs" ]] && [[ -n "$(tail -c 1 -- "/etc/login.defs" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "/etc/login.defs" + fi + printf '%s\n' "$formatted_output" >> "/etc/login.defs" fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: - CJIS-5.6.2.1 + - DISA-STIG-OL09-00-001105 - NIST-800-171-3.5.7 - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(1)(a) @@ -33674,7 +38470,7 @@ fi - restrict_strategy - name: XCCDF Value var_accounts_password_minlen_login_defs # promote to variable set_fact: - var_accounts_password_minlen_login_defs: !!str + var_accounts_password_minlen_login_defs: !!str tags: - always @@ -33688,6 +38484,7 @@ fi when: '"shadow-utils" in ansible_facts.packages' tags: - CJIS-5.6.2.1 + - DISA-STIG-OL09-00-001105 - NIST-800-171-3.5.7 - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(1)(a) @@ -33698,32 +38495,40 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - - Set Existing Passwords Maximum Age - Configure non-compliant accounts to enforce a -day maximum password lifetime + + + + + + + + + + + Set Existing Passwords Maximum Age + Configure non-compliant accounts to enforce a -day maximum password lifetime restriction by running the following command: -$ sudo chage -M USER - CCI-000199 - IA-5(f) - IA-5(1)(d) - CM-6(a) - SRG-OS-000076-GPOS-00044 - Any password, no matter how complex, can eventually be cracked. Therefore, +$ sudo chage -M + USER + + + CCI-004066 + IA-5(f) + IA-5(1)(d) + CM-6(a) + SRG-OS-000076-GPOS-00044 + A.5.SEC-OL5 + 8.3.9 + 8.3 + OL09-00-001100 + SV-271632r1091608_rule + Any password, no matter how complex, can eventually be cracked. Therefore, passwords need to be changed periodically. If the operating system does not limit the lifetime of passwords and force users to change their passwords, there is the risk that the operating system passwords could be -compromised. - -var_accounts_maximum_age_login_defs='' +compromised. + +var_accounts_maximum_age_login_defs='' while IFS= read -r i; do @@ -33731,33 +38536,104 @@ while IFS= read -r i; do chage -M $var_accounts_maximum_age_login_defs $i done < <(awk -v var="$var_accounts_maximum_age_login_defs" -F: '(/^[^:]+:[^!*]/ && ($5 > var || $5 == "")) {print $1}' /etc/shadow) - - - - - - - - - - - - Set Existing Passwords Minimum Age - Configure non-compliant accounts to enforce a 24 hours/1 day minimum password + + - name: XCCDF Value var_accounts_maximum_age_login_defs # promote to variable + set_fact: + var_accounts_maximum_age_login_defs: !!str + tags: + - always + +- name: Collect users with not correct maximum time period between password changes + ansible.builtin.command: + cmd: awk -F':' '(/^[^:]+:[^!*]/ && ($5 > {{ var_accounts_maximum_age_login_defs + }} || $5 == "")) {print $1}' /etc/shadow + register: user_names + tags: + - DISA-STIG-OL09-00-001100 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(d) + - NIST-800-53-IA-5(f) + - PCI-DSSv4-8.3 + - PCI-DSSv4-8.3.9 + - accounts_password_set_max_life_existing + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Change the maximum time period between password changes + ansible.builtin.user: + user: '{{ item }}' + password_expire_max: '{{ var_accounts_maximum_age_login_defs }}' + with_items: '{{ user_names.stdout_lines }}' + when: user_names.stdout_lines | length > 0 + tags: + - DISA-STIG-OL09-00-001100 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(d) + - NIST-800-53-IA-5(f) + - PCI-DSSv4-8.3 + - PCI-DSSv4-8.3.9 + - accounts_password_set_max_life_existing + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + + + + + + + + + + + + Set Root Account Password Maximum Age + Configure the root account to enforce a -day maximum password lifetime restriction by running the following command: +$ sudo chage -M root + + R31 + Any password, no matter how complex, can eventually be cracked. Therefore, +passwords need to be changed periodically. If the operating system does +not limit the lifetime of passwords and force users to change their +passwords, there is the risk that the operating system passwords could be +compromised. + + + + + + + + + + Set Existing Passwords Minimum Age + Configure non-compliant accounts to enforce a 24 hours/1 day minimum password lifetime by running the following command: -$ sudo chage -m 1 USER - CCI-000198 - IA-5(f) - IA-5(1)(d) - CM-6(a) - SRG-OS-000075-GPOS-00043 - Enforcing a minimum password lifetime helps to prevent repeated password +$ sudo chage -m 1 USER + + + CCI-004066 + IA-5(f) + IA-5(1)(d) + CM-6(a) + SRG-OS-000075-GPOS-00043 + A.5.SEC-OL5 + OL09-00-001090 + OL09-00-001085 + SV-271630r1091602_rule + SV-271629r1091599_rule + Enforcing a minimum password lifetime helps to prevent repeated password changes to defeat the password reuse or history enforcement requirement. If users are allowed to immediately and continually change their password, the password could be repeatedly changed in a short period of time to defeat the -organization's policy regarding password reuse. - -var_accounts_minimum_age_login_defs='' +organization's policy regarding password reuse. + +var_accounts_minimum_age_login_defs='' while IFS= read -r i; do @@ -33765,10 +38641,10 @@ while IFS= read -r i; do chage -m $var_accounts_minimum_age_login_defs $i done < <(awk -v var="$var_accounts_minimum_age_login_defs" -F: '(/^[^:]+:[^!*]/ && ($4 < var || $4 == "")) {print $1}' /etc/shadow) - - - name: XCCDF Value var_accounts_minimum_age_login_defs # promote to variable + + - name: XCCDF Value var_accounts_minimum_age_login_defs # promote to variable set_fact: - var_accounts_minimum_age_login_defs: !!str + var_accounts_minimum_age_login_defs: !!str tags: - always @@ -33777,6 +38653,8 @@ done < <(awk -v var="$var_accounts_minimum_age_login_defs" -F: '(/^[^:]+ awk -F':' '(/^[^:]+:[^!*]/ && ($4 < {{ var_accounts_minimum_age_login_defs }} || $4 == "")) {print $1}' /etc/shadow register: user_names tags: + - DISA-STIG-OL09-00-001085 + - DISA-STIG-OL09-00-001090 - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(1)(d) - NIST-800-53-IA-5(f) @@ -33793,6 +38671,8 @@ done < <(awk -v var="$var_accounts_minimum_age_login_defs" -F: '(/^[^:]+ with_items: '{{ user_names.stdout_lines }}' when: user_names.stdout_lines | length > 0 tags: + - DISA-STIG-OL09-00-001085 + - DISA-STIG-OL09-00-001090 - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(1)(d) - NIST-800-53-IA-5(f) @@ -33802,123 +38682,220 @@ done < <(awk -v var="$var_accounts_minimum_age_login_defs" -F: '(/^[^:]+ - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - - - Set Password Warning Age - To specify how many days prior to password + + + + + + + + + + + + Set Existing Passwords Warning Age + To configure how many days prior to password expiration that a warning will be issued to +users, run the command: +$ sudo chage --warndays + USER + +The DoD requirement is 7, and CIS recommendation is no less than 7 days. +This profile requirement is . + CCI-000198 + IA-5(f) + IA-5(1)(d) + CM-6(a) + A.5.SEC-OL5 + 8.3.9 + 8.3 + Providing an advance warning that a password will be expiring gives users +time to think of a secure password. Users caught unaware may choose a simple +password or write it down where it may be discovered. + +var_accounts_password_warn_age_login_defs='' + + +while IFS= read -r i; do + chage --warndays $var_accounts_password_warn_age_login_defs $i +done < <(awk -v var="$var_accounts_password_warn_age_login_defs" -F: '(($6 < var || $6 == "") && $2 ~ /^\$/) {print $1}' /etc/shadow) + + - name: XCCDF Value var_accounts_password_warn_age_login_defs # promote to variable + set_fact: + var_accounts_password_warn_age_login_defs: !!str + tags: + - always + +- name: Set Existing Passwords Warning Age - Collect Users With Incorrect Number of + Days of Warning Before Password Expires + ansible.builtin.command: + cmd: awk -F':' '(($6 < {{ var_accounts_password_warn_age_login_defs }} || $6 == + "") && $2 ~ /^\$/) {print $1}' /etc/shadow + register: result_pass_warn_age_user_names + changed_when: false + tags: + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(d) + - NIST-800-53-IA-5(f) + - PCI-DSSv4-8.3 + - PCI-DSSv4-8.3.9 + - accounts_password_set_warn_age_existing + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Set Existing Passwords Warning Age - Ensure the Number of Days of Warning + Before Password Expires + ansible.builtin.command: + cmd: chage --warndays {{ var_accounts_password_warn_age_login_defs }} {{ item + }} + with_items: '{{ result_pass_warn_age_user_names.stdout_lines }}' + when: result_pass_warn_age_user_names is not skipped and result_pass_warn_age_user_names.stdout_lines + | length > 0 + tags: + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(d) + - NIST-800-53-IA-5(f) + - PCI-DSSv4-8.3 + - PCI-DSSv4-8.3.9 + - accounts_password_set_warn_age_existing + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + + Set Password Warning Age + To specify how many days prior to password expiration that a warning will be issued to users, edit the file /etc/login.defs and add or correct the following line: -PASS_WARN_AGE +PASS_WARN_AGE + The DoD requirement is 7. -The profile requirement is . - 1 - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - 7 - 8 - DSS01.03 - DSS03.05 - DSS05.04 - DSS05.05 - DSS05.07 - DSS05.10 - DSS06.03 - DSS06.10 - 3.5.8 - 4.3.3.2.2 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - SR 1.1 - SR 1.10 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 6.2 - 0418 - 1055 - 1402 - A.12.4.1 - A.12.4.3 - A.18.1.4 - A.6.1.2 - A.7.1.1 - A.9.1.2 - A.9.2.1 - A.9.2.2 - A.9.2.3 - A.9.2.4 - A.9.2.6 - A.9.3.1 - A.9.4.1 - A.9.4.2 - A.9.4.3 - A.9.4.4 - A.9.4.5 - IA-5(f) - IA-5(1)(d) - CM-6(a) - DE.CM-1 - DE.CM-3 - PR.AC-1 - PR.AC-4 - PR.AC-6 - PR.AC-7 - Req-8.2.4 - 8.3.9 - Setting the password warning age enables users to -make the change at a practical time. - - # Remediation is applicable only in certain platforms +The profile requirement is . + 1 + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + 7 + 8 + DSS01.03 + DSS03.05 + DSS05.04 + DSS05.05 + DSS05.07 + DSS05.10 + DSS06.03 + DSS06.10 + 3.5.8 + 4.3.3.2.2 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + SR 1.1 + SR 1.10 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 6.2 + 0418 + 1055 + 1402 + A.12.4.1 + A.12.4.3 + A.18.1.4 + A.6.1.2 + A.7.1.1 + A.9.1.2 + A.9.2.1 + A.9.2.2 + A.9.2.3 + A.9.2.4 + A.9.2.6 + A.9.3.1 + A.9.4.1 + A.9.4.2 + A.9.4.3 + A.9.4.4 + A.9.4.5 + IA-5(f) + IA-5(1)(d) + CM-6(a) + DE.CM-1 + DE.CM-3 + PR.AC-1 + PR.AC-4 + PR.AC-6 + PR.AC-7 + Req-8.2.4 + A.5.SEC-OL5 + 8.3.9 + 8.3 + Setting the password warning age enables users to +make the change at a practical time. + + # Remediation is applicable only in certain platforms if rpm --quiet -q shadow-utils; then -var_accounts_password_warn_age_login_defs='' +var_accounts_password_warn_age_login_defs='' +# Strip any search characters in the key arg so that the key can be replaced without +# adding any search characters to the config file. +stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^PASS_WARN_AGE") -grep -q ^PASS_WARN_AGE /etc/login.defs && \ -sed -i "s/PASS_WARN_AGE.*/PASS_WARN_AGE\t$var_accounts_password_warn_age_login_defs/g" /etc/login.defs -if ! [ $? -eq 0 ] -then - echo -e "PASS_WARN_AGE\t$var_accounts_password_warn_age_login_defs" >> /etc/login.defs +# shellcheck disable=SC2059 +printf -v formatted_output "%s %s" "$stripped_key" "$var_accounts_password_warn_age_login_defs" + +# If the key exists, change it. Otherwise, add it to the config_file. +# We search for the key string followed by a word boundary (matched by \>), +# so if we search for 'setting', 'setting2' won't match. +if LC_ALL=C grep -q -m 1 -i -e "^PASS_WARN_AGE\\>" "/etc/login.defs"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + LC_ALL=C sed -i --follow-symlinks "s/^PASS_WARN_AGE\\>.*/$escaped_formatted_output/gi" "/etc/login.defs" +else + if [[ -s "/etc/login.defs" ]] && [[ -n "$(tail -c 1 -- "/etc/login.defs" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "/etc/login.defs" + fi + printf '%s\n' "$formatted_output" >> "/etc/login.defs" fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: @@ -33927,6 +38904,7 @@ fi - NIST-800-53-IA-5(1)(d) - NIST-800-53-IA-5(f) - PCI-DSS-Req-8.2.4 + - PCI-DSSv4-8.3 - PCI-DSSv4-8.3.9 - accounts_password_warn_age_login_defs - low_complexity @@ -33936,7 +38914,7 @@ fi - restrict_strategy - name: XCCDF Value var_accounts_password_warn_age_login_defs # promote to variable set_fact: - var_accounts_password_warn_age_login_defs: !!str + var_accounts_password_warn_age_login_defs: !!str tags: - always @@ -33954,6 +38932,7 @@ fi - NIST-800-53-IA-5(1)(d) - NIST-800-53-IA-5(f) - PCI-DSS-Req-8.2.4 + - PCI-DSSv4-8.3 - PCI-DSSv4-8.3.9 - accounts_password_warn_age_login_defs - low_complexity @@ -33961,20 +38940,169 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - - - Verify Proper Storage and Existence of Password -Hashes - By default, password hashes for local accounts are stored + + + + + + + + + + + Set existing passwords a period of inactivity before they been locked + Configure user accounts that have been inactive for over a given period of time +to be automatically disabled by running the following command: +$ sudo chage --inactive 30USER + + + DSS01.03 + DSS03.05 + DSS05.04 + DSS05.05 + DSS05.07 + DSS05.10 + DSS06.03 + DSS06.10 + 3.5.6 + CCI-000017 + CCI-000795 + CCI-003627 + CCI-003628 + 4.3.3.2.2 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + SR 1.1 + SR 1.10 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 6.2 + A.12.4.1 + A.12.4.3 + A.18.1.4 + A.6.1.2 + A.7.1.1 + A.9.1.2 + A.9.2.1 + A.9.2.2 + A.9.2.3 + A.9.2.4 + A.9.2.6 + A.9.3.1 + A.9.4.1 + A.9.4.2 + A.9.4.3 + A.9.4.4 + A.9.4.5 + CIP-004-6 R2.2.2 + CIP-004-6 R2.2.3 + CIP-007-3 R.1.3 + CIP-007-3 R5 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.3 + CIP-007-3 R5.2.1 + CIP-007-3 R5.2.3 + IA-4(e) + AC-2(3) + CM-6(a) + DE.CM-1 + DE.CM-3 + PR.AC-1 + PR.AC-4 + PR.AC-6 + PR.AC-7 + Req-8.1.4 + SRG-OS-000118-GPOS-00060 + 8.2.6 + 8.2 + Inactive accounts pose a threat to system security since the users are not logging in to +notice failed login attempts or other anomalies. + +var_account_disable_post_pw_expiration='' + + +while IFS= read -r i; do + chage --inactive $var_account_disable_post_pw_expiration $i +done < <(awk -v var="$var_account_disable_post_pw_expiration" -F: '(($7 > var || $7 == "") && $2 ~ /^\$/) {print $1}' /etc/shadow) + + - name: XCCDF Value var_account_disable_post_pw_expiration # promote to variable + set_fact: + var_account_disable_post_pw_expiration: !!str + tags: + - always + +- name: Collect users with not correct INACTIVE parameter set + ansible.builtin.command: + cmd: awk -F':' '(($7 > {{ var_account_disable_post_pw_expiration }} || $7 == "") + && $2 ~ /^\$/) {print $1}' /etc/shadow + register: user_names + changed_when: false + tags: + - NIST-800-171-3.5.6 + - NIST-800-53-AC-2(3) + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-4(e) + - PCI-DSS-Req-8.1.4 + - PCI-DSSv4-8.2 + - PCI-DSSv4-8.2.6 + - accounts_set_post_pw_existing + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Change the period of inactivity + ansible.builtin.command: + cmd: chage --inactive {{ var_account_disable_post_pw_expiration }} {{ item }} + with_items: '{{ user_names.stdout_lines }}' + when: user_names is not skipped and user_names.stdout_lines | length > 0 + tags: + - NIST-800-171-3.5.6 + - NIST-800-53-AC-2(3) + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-4(e) + - PCI-DSS-Req-8.1.4 + - PCI-DSSv4-8.2 + - PCI-DSSv4-8.2.6 + - accounts_set_post_pw_existing + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + + + + + + + + + + + + Verify Proper Storage and Existence of Password +Hashes + By default, password hashes for local accounts are stored in the second field (colon-separated) in /etc/shadow. This file should be readable only by processes running with root credentials, preventing users from @@ -33985,90 +39113,95 @@ and store password hashes in world-readable files such as /etc/passwd, or to even store passwords themselves in plaintext on the system. Using system-provided tools for password change/creation -should allow administrators to avoid such misconfiguration. - - Password Hashing algorithm - Specify the number of SHA rounds for the system password encryption algorithm. -Defines the value set in /etc/pam.d/system-auth and /etc/pam.d/password-auth - 5000 - 5000 - 65536 - - - Verify All Account Password Hashes are Shadowed - If any password hashes are stored in /etc/passwd (in the second field, +should allow administrators to avoid such misconfiguration. + + Password Hashing algorithm + Specify the number of rounds for the system password encryption algorithm. +Defines the value set in /etc/pam.d/system-auth and /etc/pam.d/password-auth + + 5000 + 5000 + 65536 + 100000 + 11 + 5 + + + Verify All Account Password Hashes are Shadowed + If any password hashes are stored in /etc/passwd (in the second field, instead of an x or *), the cause of this misconfiguration should be investigated. The account should have its password reset and the hash should be -properly stored, or the account should be deleted entirely. - 1 - 12 - 15 - 16 - 5 - 5.5.2 - DSS05.04 - DSS05.05 - DSS05.07 - DSS05.10 - DSS06.03 - DSS06.10 - 3.5.10 - 4.3.3.2.2 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.2 - 4.3.3.7.4 - SR 1.1 - SR 1.10 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - 1410 - A.18.1.4 - A.7.1.1 - A.9.2.1 - A.9.2.2 - A.9.2.3 - A.9.2.4 - A.9.2.6 - A.9.3.1 - A.9.4.2 - A.9.4.3 - IA-5(h) - CM-6(a) - PR.AC-1 - PR.AC-6 - PR.AC-7 - Req-8.2.1 - 8.3.2 - The hashes for all user account passwords should be stored in +properly stored, or the account should be deleted entirely. + 1 + 12 + 15 + 16 + 5 + 5.5.2 + DSS05.04 + DSS05.05 + DSS05.07 + DSS05.10 + DSS06.03 + DSS06.10 + 3.5.10 + 4.3.3.2.2 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.2 + 4.3.3.7.4 + SR 1.1 + SR 1.10 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + 1410 + A.18.1.4 + A.7.1.1 + A.9.2.1 + A.9.2.2 + A.9.2.3 + A.9.2.4 + A.9.2.6 + A.9.3.1 + A.9.4.2 + A.9.4.3 + IA-5(h) + CM-6(a) + PR.AC-1 + PR.AC-6 + PR.AC-7 + Req-8.2.1 + 8.3.2 + 8.3 + The hashes for all user account passwords should be stored in the file /etc/shadow and never in /etc/passwd, -which is readable by all users. - - - - - - - - - - Verify All Account Password Hashes are Shadowed with SHA512 - Verify the operating system requires the shadow password suite +which is readable by all users. + + + + + + + + + + Verify All Account Password Hashes are Shadowed with SHA512 + Verify the operating system requires the shadow password suite configuration be set to encrypt interactive user passwords using a strong cryptographic hash. Check that the interactive user account passwords are using a strong @@ -34078,59 +39211,71 @@ $6$kcOnRq/5$NUEYPuyL.wghQwWssXRcLRFiiru7f5JPV6GaJhNC2aK5F3PZpE/BCCtwrxRc/AInKMNX Password hashes ! or * indicate inactive accounts not available for logon and are not evaluated. If any interactive user password hash does not begin with $6, -this is a finding. - CCI-000196 - CCI-000803 - IA-5(1)(c) - IA-5(1).1(v) - IA-7 - IA-7.1 - SRG-OS-000073-GPOS-00041 - SRG-OS-000120-GPOS-00061 - Passwords need to be protected at all times, and encryption is the standard method for +this is a finding. + CCI-000803 + CCI-004062 + IA-5(1)(c) + IA-5(1).1(v) + IA-7 + IA-7.1 + SRG-OS-000073-GPOS-00041 + SRG-OS-000120-GPOS-00061 + OL09-00-001080 + SV-271628r1091596_rule + Passwords need to be protected at all times, and encryption is the standard method for protecting passwords. If passwords are not encrypted, they can be plainly read -(i.e., clear text) and easily compromised. - - - - - - - - - Ensure all users last password change date is in the past - All users should have a password change date in the past. - Automatic remediation is not available, in order to avoid any system disruption. - If a user recorded password change date is in the future then they could -bypass any set password expiration. - - - - - - - - - - Set number of Password Hashing Rounds - password-auth - Configure the number or rounds for the password hashing algorithm. This can be +(i.e., clear text) and easily compromised. + + + + + + + + + Ensure all users last password change date is in the past + All users should have a password change date in the past. + Automatic remediation is not available, in order to avoid any system disruption. + 8.3.5 + 8.3 + If a user recorded password change date is in the future then they could +bypass any set password expiration. + + + + + + + + + + Set number of Password Hashing Rounds - password-auth + Configure the number or rounds for the password hashing algorithm. This can be accomplished by using the rounds option for the pam_unix PAM module. - -In file /etc/pam.d/password-auth append rounds= + + +In file /etc/pam.d/password-auth append rounds= + to the pam_unix.so entry, as shown below: -password sufficient pam_unix.so ...existing_options... rounds= -The system's default number of rounds is 5000. - Setting a high number of hashing rounds makes it more difficult to brute force the password, -but requires more CPU resources to authenticate users. - BP28(R68) - CCI-000196 - SRG-OS-000073-GPOS-00041 - Using a higher number of rounds makes password cracking attacks more difficult. - - # Remediation is applicable only in certain platforms + +password sufficient pam_unix.so ...existing_options... rounds= + + +The system's default number of rounds is 5000. + Setting a high number of hashing rounds makes it more difficult to brute force the password, +but requires more CPU resources to authenticate users. + CCI-000803 + CCI-004062 + SRG-OS-000073-GPOS-00041 + R68 + OL09-00-001065 + SV-271625r1091587_rule + Using a higher number of rounds makes password cracking attacks more difficult. + + # Remediation is applicable only in certain platforms if rpm --quiet -q pam; then -var_password_pam_unix_rounds='' +var_password_pam_unix_rounds='' @@ -34151,6 +39296,11 @@ if [ -e "/etc/pam.d/password-auth" ] ; then # If not already in use, a custom profile is created preserving the enabled features. if [[ ! $CURRENT_PROFILE == custom/* ]]; then ENABLED_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }') + # The "local" profile does not contain essential security features required by multiple Benchmarks. + # If currently used, it is replaced by "sssd", which is the best option in this case. + if [[ $CURRENT_PROFILE == local ]]; then + CURRENT_PROFILE="sssd" + fi authselect create-profile hardening -b $CURRENT_PROFILE CURRENT_PROFILE="custom/hardening" @@ -34167,20 +39317,22 @@ if [ -e "/etc/pam.d/password-auth" ] ; then authselect apply-changes -b fi - if ! grep -qP '^\s*password\s+'"sufficient"'\s+pam_unix.so\s*.*' "$PAM_FILE_PATH"; then + + + if ! grep -qP "^\s*password\s+sufficient\s+pam_unix.so\s*.*" "$PAM_FILE_PATH"; then # Line matching group + control + module was not found. Check group + module. if [ "$(grep -cP '^\s*password\s+.*\s+pam_unix.so\s*' "$PAM_FILE_PATH")" -eq 1 ]; then # The control is updated only if one single line matches. - sed -i -E --follow-symlinks 's/^(\s*password\s+).*(\bpam_unix.so.*)/\1'"sufficient"' \2/' "$PAM_FILE_PATH" + sed -i -E --follow-symlinks "s/^(\s*password\s+).*(\bpam_unix.so.*)/\1sufficient \2/" "$PAM_FILE_PATH" else - echo 'password '"sufficient"' pam_unix.so' >> "$PAM_FILE_PATH" + echo "password sufficient pam_unix.so" >> "$PAM_FILE_PATH" fi fi # Check the option - if ! grep -qP '^\s*password\s+'"sufficient"'\s+pam_unix.so\s*.*\srounds\b' "$PAM_FILE_PATH"; then - sed -i -E --follow-symlinks '/\s*password\s+'"sufficient"'\s+pam_unix.so.*/ s/$/ rounds='"$var_password_pam_unix_rounds"'/' "$PAM_FILE_PATH" + if ! grep -qP "^\s*password\s+sufficient\s+pam_unix.so\s*.*\srounds\b" "$PAM_FILE_PATH"; then + sed -i -E --follow-symlinks "/\s*password\s+sufficient\s+pam_unix.so.*/ s/$/ rounds=$var_password_pam_unix_rounds/" "$PAM_FILE_PATH" else - sed -i -E --follow-symlinks 's/(\s*password\s+'"sufficient"'\s+pam_unix.so\s+.*)('"rounds"'=)[[:alnum:]]+\s*(.*)/\1\2'"$var_password_pam_unix_rounds"' \3/' "$PAM_FILE_PATH" + sed -i -E --follow-symlinks "s/(\s*password\s+sufficient\s+pam_unix.so\s+.*)(rounds=)[[:alnum:]]+\s*(.*)/\1\2$var_password_pam_unix_rounds \3/" "$PAM_FILE_PATH" fi if [ -f /usr/bin/authselect ]; then @@ -34193,11 +39345,12 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-001065 - accounts_password_pam_unix_rounds_password_auth - configure_strategy - low_complexity @@ -34206,7 +39359,7 @@ fi - no_reboot_needed - name: XCCDF Value var_password_pam_unix_rounds # promote to variable set_fact: - var_password_pam_unix_rounds: !!str + var_password_pam_unix_rounds: !!str tags: - always @@ -34217,6 +39370,7 @@ fi register: result_pam_file_present when: '"pam" in ansible_facts.packages' tags: + - DISA-STIG-OL09-00-001065 - accounts_password_pam_unix_rounds_password_auth - configure_strategy - low_complexity @@ -34320,7 +39474,16 @@ fi }} when: - result_authselect_check_cmd is success - - authselect_current_profile is not match("custom/") + - authselect_current_profile is not match("^(custom/|local)") + - not result_authselect_custom_profile_present.stat.exists + + - name: Set number of Password Hashing Rounds - password-auth - Create an authselect + custom profile based on sssd profile + ansible.builtin.command: + cmd: authselect create-profile hardening -b sssd + when: + - result_authselect_check_cmd is success + - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists - name: Set number of Password Hashing Rounds - password-auth - Ensure authselect @@ -34372,11 +39535,16 @@ fi when: - result_authselect_present.stat.exists + - name: Set number of Password Hashing Rounds - password-auth - Define a fact for + control already filtered in case filters are used + ansible.builtin.set_fact: + pam_module_control: sufficient + - name: Set number of Password Hashing Rounds - password-auth - Check if expected PAM module line is present in {{ pam_file_path }} ansible.builtin.lineinfile: path: '{{ pam_file_path }}' - regexp: ^\s*password\s+sufficient\s+pam_unix.so\s*.* + regexp: ^\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_unix.so\s*.* state: absent check_mode: true changed_when: false @@ -34401,7 +39569,7 @@ fi ansible.builtin.replace: dest: '{{ pam_file_path }}' regexp: ^(\s*password\s+).*(\bpam_unix.so.*) - replace: \1sufficient \2 + replace: \1{{ pam_module_control }} \2 register: result_pam_module_edit when: - result_pam_line_other_control_present.found == 1 @@ -34410,7 +39578,7 @@ fi PAM module line is included in {{ pam_file_path }} ansible.builtin.lineinfile: dest: '{{ pam_file_path }}' - line: password sufficient pam_unix.so + line: password {{ pam_module_control }} pam_unix.so register: result_pam_module_add when: - result_pam_line_other_control_present.found == 0 or result_pam_line_other_control_present.found @@ -34430,38 +39598,45 @@ fi - result_pam_line_present.found is defined - result_pam_line_present.found == 0 + - name: Set number of Password Hashing Rounds - password-auth - Define a fact for + control already filtered in case filters are used + ansible.builtin.set_fact: + pam_module_control: sufficient + - name: Set number of Password Hashing Rounds - password-auth - Check if the required PAM module option is present in {{ pam_file_path }} ansible.builtin.lineinfile: path: '{{ pam_file_path }}' - regexp: ^\s*password\s+sufficient\s+pam_unix.so\s*.*\srounds\b + regexp: ^\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_unix.so\s*.*\srounds\b state: absent check_mode: true changed_when: false - register: result_pam_module_rounds_option_present + register: result_pam_module_accounts_password_pam_unix_rounds_password_auth_option_present - name: Set number of Password Hashing Rounds - password-auth - Ensure the "rounds" PAM option for "pam_unix.so" is included in {{ pam_file_path }} ansible.builtin.lineinfile: path: '{{ pam_file_path }}' backrefs: true - regexp: ^(\s*password\s+sufficient\s+pam_unix.so.*) + regexp: ^(\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_unix.so.*) line: \1 rounds={{ var_password_pam_unix_rounds }} state: present - register: result_pam_rounds_add + register: result_pam_accounts_password_pam_unix_rounds_password_auth_add when: - - result_pam_module_rounds_option_present.found == 0 + - result_pam_module_accounts_password_pam_unix_rounds_password_auth_option_present.found + == 0 - name: Set number of Password Hashing Rounds - password-auth - Ensure the required value for "rounds" PAM option from "pam_unix.so" in {{ pam_file_path }} ansible.builtin.lineinfile: path: '{{ pam_file_path }}' backrefs: true - regexp: ^(\s*password\s+sufficient\s+pam_unix.so\s+.*)(rounds)=[0-9a-zA-Z]+\s*(.*) + regexp: ^(\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_unix.so\s+.*)(rounds)=[0-9a-zA-Z]+\s*(.*) line: \1\2={{ var_password_pam_unix_rounds }} \3 - register: result_pam_rounds_edit + register: result_pam_accounts_password_pam_unix_rounds_password_auth_edit when: - - result_pam_module_rounds_option_present.found > 0 + - result_pam_module_accounts_password_pam_unix_rounds_password_auth_option_present.found + > 0 - name: Set number of Password Hashing Rounds - password-auth - Ensure authselect changes are applied @@ -34470,47 +39645,54 @@ fi when: - result_authselect_present.stat.exists - |- - (result_pam_rounds_add is defined and result_pam_rounds_add.changed) - or (result_pam_rounds_edit is defined and result_pam_rounds_edit.changed) + (result_pam_accounts_password_pam_unix_rounds_password_auth_add is defined and result_pam_accounts_password_pam_unix_rounds_password_auth_add.changed) + or (result_pam_accounts_password_pam_unix_rounds_password_auth_edit is defined and result_pam_accounts_password_pam_unix_rounds_password_auth_edit.changed) when: - '"pam" in ansible_facts.packages' - result_pam_file_present.stat.exists tags: + - DISA-STIG-OL09-00-001065 - accounts_password_pam_unix_rounds_password_auth - configure_strategy - low_complexity - medium_disruption - medium_severity - no_reboot_needed - - - - - - - - - - - Set number of Password Hashing Rounds - system-auth - Configure the number or rounds for the password hashing algorithm. This can be + + + + + + + + + + + Set number of Password Hashing Rounds - system-auth + Configure the number or rounds for the password hashing algorithm. This can be accomplished by using the rounds option for the pam_unix PAM module. - -In file /etc/pam.d/system-auth append rounds= + + +In file /etc/pam.d/system-auth append rounds= + to the pam_unix.so entry, as shown below: -password sufficient pam_unix.so ...existing_options... rounds= -The system's default number of rounds is 5000. - Setting a high number of hashing rounds makes it more difficult to brute force the password, -but requires more CPU resources to authenticate users. - BP28(R68) - CCI-000196 - SRG-OS-000073-GPOS-00041 - Using a higher number of rounds makes password cracking attacks more difficult. - - # Remediation is applicable only in certain platforms +password sufficient pam_unix.so ...existing_options... rounds= + +The system's default number of rounds is 5000. + Setting a high number of hashing rounds makes it more difficult to brute force the password, +but requires more CPU resources to authenticate users. + CCI-000803 + CCI-004062 + SRG-OS-000073-GPOS-00041 + R68 + OL09-00-001070 + SV-271626r1091590_rule + Using a higher number of rounds makes password cracking attacks more difficult. + + # Remediation is applicable only in certain platforms if rpm --quiet -q pam; then -var_password_pam_unix_rounds='' +var_password_pam_unix_rounds='' if [ -e "/etc/pam.d/system-auth" ] ; then @@ -34530,6 +39712,11 @@ if [ -e "/etc/pam.d/system-auth" ] ; then # If not already in use, a custom profile is created preserving the enabled features. if [[ ! $CURRENT_PROFILE == custom/* ]]; then ENABLED_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }') + # The "local" profile does not contain essential security features required by multiple Benchmarks. + # If currently used, it is replaced by "sssd", which is the best option in this case. + if [[ $CURRENT_PROFILE == local ]]; then + CURRENT_PROFILE="sssd" + fi authselect create-profile hardening -b $CURRENT_PROFILE CURRENT_PROFILE="custom/hardening" @@ -34546,20 +39733,22 @@ if [ -e "/etc/pam.d/system-auth" ] ; then authselect apply-changes -b fi - if ! grep -qP '^\s*password\s+'"sufficient"'\s+pam_unix.so\s*.*' "$PAM_FILE_PATH"; then + + + if ! grep -qP "^\s*password\s+sufficient\s+pam_unix.so\s*.*" "$PAM_FILE_PATH"; then # Line matching group + control + module was not found. Check group + module. if [ "$(grep -cP '^\s*password\s+.*\s+pam_unix.so\s*' "$PAM_FILE_PATH")" -eq 1 ]; then # The control is updated only if one single line matches. - sed -i -E --follow-symlinks 's/^(\s*password\s+).*(\bpam_unix.so.*)/\1'"sufficient"' \2/' "$PAM_FILE_PATH" + sed -i -E --follow-symlinks "s/^(\s*password\s+).*(\bpam_unix.so.*)/\1sufficient \2/" "$PAM_FILE_PATH" else - echo 'password '"sufficient"' pam_unix.so' >> "$PAM_FILE_PATH" + echo "password sufficient pam_unix.so" >> "$PAM_FILE_PATH" fi fi # Check the option - if ! grep -qP '^\s*password\s+'"sufficient"'\s+pam_unix.so\s*.*\srounds\b' "$PAM_FILE_PATH"; then - sed -i -E --follow-symlinks '/\s*password\s+'"sufficient"'\s+pam_unix.so.*/ s/$/ rounds='"$var_password_pam_unix_rounds"'/' "$PAM_FILE_PATH" + if ! grep -qP "^\s*password\s+sufficient\s+pam_unix.so\s*.*\srounds\b" "$PAM_FILE_PATH"; then + sed -i -E --follow-symlinks "/\s*password\s+sufficient\s+pam_unix.so.*/ s/$/ rounds=$var_password_pam_unix_rounds/" "$PAM_FILE_PATH" else - sed -i -E --follow-symlinks 's/(\s*password\s+'"sufficient"'\s+pam_unix.so\s+.*)('"rounds"'=)[[:alnum:]]+\s*(.*)/\1\2'"$var_password_pam_unix_rounds"' \3/' "$PAM_FILE_PATH" + sed -i -E --follow-symlinks "s/(\s*password\s+sufficient\s+pam_unix.so\s+.*)(rounds=)[[:alnum:]]+\s*(.*)/\1\2$var_password_pam_unix_rounds \3/" "$PAM_FILE_PATH" fi if [ -f /usr/bin/authselect ]; then @@ -34572,11 +39761,12 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-001070 - accounts_password_pam_unix_rounds_system_auth - configure_strategy - low_complexity @@ -34585,7 +39775,7 @@ fi - no_reboot_needed - name: XCCDF Value var_password_pam_unix_rounds # promote to variable set_fact: - var_password_pam_unix_rounds: !!str + var_password_pam_unix_rounds: !!str tags: - always @@ -34596,6 +39786,7 @@ fi register: result_pam_file_present when: '"pam" in ansible_facts.packages' tags: + - DISA-STIG-OL09-00-001070 - accounts_password_pam_unix_rounds_system_auth - configure_strategy - low_complexity @@ -34699,7 +39890,16 @@ fi }} when: - result_authselect_check_cmd is success - - authselect_current_profile is not match("custom/") + - authselect_current_profile is not match("^(custom/|local)") + - not result_authselect_custom_profile_present.stat.exists + + - name: Set number of Password Hashing Rounds - system-auth - Create an authselect + custom profile based on sssd profile + ansible.builtin.command: + cmd: authselect create-profile hardening -b sssd + when: + - result_authselect_check_cmd is success + - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists - name: Set number of Password Hashing Rounds - system-auth - Ensure authselect @@ -34751,11 +39951,16 @@ fi when: - result_authselect_present.stat.exists + - name: Set number of Password Hashing Rounds - system-auth - Define a fact for + control already filtered in case filters are used + ansible.builtin.set_fact: + pam_module_control: sufficient + - name: Set number of Password Hashing Rounds - system-auth - Check if expected PAM module line is present in {{ pam_file_path }} ansible.builtin.lineinfile: path: '{{ pam_file_path }}' - regexp: ^\s*password\s+sufficient\s+pam_unix.so\s*.* + regexp: ^\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_unix.so\s*.* state: absent check_mode: true changed_when: false @@ -34780,7 +39985,7 @@ fi ansible.builtin.replace: dest: '{{ pam_file_path }}' regexp: ^(\s*password\s+).*(\bpam_unix.so.*) - replace: \1sufficient \2 + replace: \1{{ pam_module_control }} \2 register: result_pam_module_edit when: - result_pam_line_other_control_present.found == 1 @@ -34789,7 +39994,7 @@ fi PAM module line is included in {{ pam_file_path }} ansible.builtin.lineinfile: dest: '{{ pam_file_path }}' - line: password sufficient pam_unix.so + line: password {{ pam_module_control }} pam_unix.so register: result_pam_module_add when: - result_pam_line_other_control_present.found == 0 or result_pam_line_other_control_present.found @@ -34809,38 +40014,45 @@ fi - result_pam_line_present.found is defined - result_pam_line_present.found == 0 + - name: Set number of Password Hashing Rounds - system-auth - Define a fact for + control already filtered in case filters are used + ansible.builtin.set_fact: + pam_module_control: sufficient + - name: Set number of Password Hashing Rounds - system-auth - Check if the required PAM module option is present in {{ pam_file_path }} ansible.builtin.lineinfile: path: '{{ pam_file_path }}' - regexp: ^\s*password\s+sufficient\s+pam_unix.so\s*.*\srounds\b + regexp: ^\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_unix.so\s*.*\srounds\b state: absent check_mode: true changed_when: false - register: result_pam_module_rounds_option_present + register: result_pam_module_accounts_password_pam_unix_rounds_system_auth_option_present - name: Set number of Password Hashing Rounds - system-auth - Ensure the "rounds" PAM option for "pam_unix.so" is included in {{ pam_file_path }} ansible.builtin.lineinfile: path: '{{ pam_file_path }}' backrefs: true - regexp: ^(\s*password\s+sufficient\s+pam_unix.so.*) + regexp: ^(\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_unix.so.*) line: \1 rounds={{ var_password_pam_unix_rounds }} state: present - register: result_pam_rounds_add + register: result_pam_accounts_password_pam_unix_rounds_system_auth_add when: - - result_pam_module_rounds_option_present.found == 0 + - result_pam_module_accounts_password_pam_unix_rounds_system_auth_option_present.found + == 0 - name: Set number of Password Hashing Rounds - system-auth - Ensure the required value for "rounds" PAM option from "pam_unix.so" in {{ pam_file_path }} ansible.builtin.lineinfile: path: '{{ pam_file_path }}' backrefs: true - regexp: ^(\s*password\s+sufficient\s+pam_unix.so\s+.*)(rounds)=[0-9a-zA-Z]+\s*(.*) + regexp: ^(\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_unix.so\s+.*)(rounds)=[0-9a-zA-Z]+\s*(.*) line: \1\2={{ var_password_pam_unix_rounds }} \3 - register: result_pam_rounds_edit + register: result_pam_accounts_password_pam_unix_rounds_system_auth_edit when: - - result_pam_module_rounds_option_present.found > 0 + - result_pam_module_accounts_password_pam_unix_rounds_system_auth_option_present.found + > 0 - name: Set number of Password Hashing Rounds - system-auth - Ensure authselect changes are applied @@ -34849,108 +40061,112 @@ fi when: - result_authselect_present.stat.exists - |- - (result_pam_rounds_add is defined and result_pam_rounds_add.changed) - or (result_pam_rounds_edit is defined and result_pam_rounds_edit.changed) + (result_pam_accounts_password_pam_unix_rounds_system_auth_add is defined and result_pam_accounts_password_pam_unix_rounds_system_auth_add.changed) + or (result_pam_accounts_password_pam_unix_rounds_system_auth_edit is defined and result_pam_accounts_password_pam_unix_rounds_system_auth_edit.changed) when: - '"pam" in ansible_facts.packages' - result_pam_file_present.stat.exists tags: + - DISA-STIG-OL09-00-001070 - accounts_password_pam_unix_rounds_system_auth - configure_strategy - low_complexity - medium_disruption - medium_severity - no_reboot_needed - - - - - - - - - - - All GIDs referenced in /etc/passwd must be defined in /etc/group - Add a group to the system for each GID referenced without a corresponding group. - 1 - 12 - 15 - 16 - 5 - 5.5.2 - DSS05.04 - DSS05.05 - DSS05.07 - DSS05.10 - DSS06.03 - DSS06.10 - CCI-000764 - 4.3.3.2.2 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.2 - 4.3.3.7.4 - SR 1.1 - SR 1.10 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - A.18.1.4 - A.7.1.1 - A.9.2.1 - A.9.2.2 - A.9.2.3 - A.9.2.4 - A.9.2.6 - A.9.3.1 - A.9.4.2 - A.9.4.3 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.2.3 - CIP-004-6 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.2 - CIP-007-3 R5.2 - CIP-007-3 R5.3.1 - CIP-007-3 R5.3.2 - CIP-007-3 R5.3.3 - IA-2 - CM-6(a) - PR.AC-1 - PR.AC-6 - PR.AC-7 - Req-8.5.a - 8.2.2 - SRG-OS-000104-GPOS-00051 - If a user is assigned the Group Identifier (GID) of a group not existing on the system, and a group + + + + + + + + + + + All GIDs referenced in /etc/passwd must be defined in /etc/group + Add a group to the system for each GID referenced without a corresponding group. + 1 + 12 + 15 + 16 + 5 + 5.5.2 + DSS05.04 + DSS05.05 + DSS05.07 + DSS05.10 + DSS06.03 + DSS06.10 + CCI-000764 + 4.3.3.2.2 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.2 + 4.3.3.7.4 + SR 1.1 + SR 1.10 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + A.18.1.4 + A.7.1.1 + A.9.2.1 + A.9.2.2 + A.9.2.3 + A.9.2.4 + A.9.2.6 + A.9.3.1 + A.9.4.2 + A.9.4.3 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.2.3 + CIP-004-6 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.2 + CIP-007-3 R5.2 + CIP-007-3 R5.3.1 + CIP-007-3 R5.3.2 + CIP-007-3 R5.3.3 + IA-2 + CM-6(a) + PR.AC-1 + PR.AC-6 + PR.AC-7 + Req-8.5.a + SRG-OS-000104-GPOS-00051 + 8.2.2 + 8.2 + OL09-00-003005 + SV-271834r1092214_rule + If a user is assigned the Group Identifier (GID) of a group not existing on the system, and a group with the Group Identifier (GID) is subsequently created, the user may have unintended rights to -any files associated with the group. - - - - - - - - - Prevent Login to Accounts With Empty Password - If an account is configured for password authentication +any files associated with the group. + + + + + + + + + Prevent Login to Accounts With Empty Password + If an account is configured for password authentication but does not have an assigned password, it may be possible to log into the account without authentication. Remove any instances of the nullok in @@ -34958,8 +40174,8 @@ into the account without authentication. Remove any instances of the /etc/pam.d/system-auth and /etc/pam.d/password-auth -to prevent logins with empty passwords. - If the system relies on authselect tool to manage PAM settings, the remediation +to prevent logins with empty passwords. + If the system relies on authselect tool to manage PAM settings, the remediation will also use authselect tool. However, if any manual modification was made in PAM files, the authselect integrity check will fail and the remediation will be aborted in order to preserve intentional changes. In this case, an informative message will @@ -34967,115 +40183,117 @@ be shown in the remediation report. Note that this rule is not applicable for systems running within a container. Having user with empty password within a container is not considered a risk, because it should not be possible to directly login into -a container anyway. - 1 - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - 5.5.2 - APO01.06 - DSS05.04 - DSS05.05 - DSS05.07 - DSS05.10 - DSS06.02 - DSS06.03 - DSS06.10 - 3.1.1 - 3.1.5 - CCI-000366 - 164.308(a)(1)(ii)(B) - 164.308(a)(7)(i) - 164.308(a)(7)(ii)(A) - 164.310(a)(1) - 164.310(a)(2)(i) - 164.310(a)(2)(ii) - 164.310(a)(2)(iii) - 164.310(b) - 164.310(c) - 164.310(d)(1) - 164.310(d)(2)(iii) - 4.3.3.2.2 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - SR 1.1 - SR 1.10 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 5.2 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.18.1.4 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.1 - A.9.2.2 - A.9.2.3 - A.9.2.4 - A.9.2.6 - A.9.3.1 - A.9.4.1 - A.9.4.2 - A.9.4.3 - A.9.4.4 - A.9.4.5 - IA-5(1)(a) - IA-5(c) - CM-6(a) - PR.AC-1 - PR.AC-4 - PR.AC-6 - PR.AC-7 - PR.DS-5 - FIA_UAU.1 - Req-8.2.3 - 8.3.6 - 8.3.9 - SRG-OS-000480-GPOS-00227 - If an account has an empty password, anyone could log in and +a container anyway. + 1 + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + 5.5.2 + APO01.06 + DSS05.04 + DSS05.05 + DSS05.07 + DSS05.10 + DSS06.02 + DSS06.03 + DSS06.10 + 3.1.1 + 3.1.5 + CCI-000366 + 164.308(a)(1)(ii)(B) + 164.308(a)(7)(i) + 164.308(a)(7)(ii)(A) + 164.310(a)(1) + 164.310(a)(2)(i) + 164.310(a)(2)(ii) + 164.310(a)(2)(iii) + 164.310(b) + 164.310(c) + 164.310(d)(1) + 164.310(d)(2)(iii) + 4.3.3.2.2 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + SR 1.1 + SR 1.10 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 5.2 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.18.1.4 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.1 + A.9.2.2 + A.9.2.3 + A.9.2.4 + A.9.2.6 + A.9.3.1 + A.9.4.1 + A.9.4.2 + A.9.4.3 + A.9.4.4 + A.9.4.5 + IA-5(1)(a) + IA-5(c) + CM-6(a) + PR.AC-1 + PR.AC-4 + PR.AC-6 + PR.AC-7 + PR.DS-5 + FIA_UAU.1 + Req-8.2.3 + SRG-OS-000480-GPOS-00227 + 8.3.1 + 8.3 + OL09-00-001110 + SV-271634r1091614_rule + If an account has an empty password, anyone could log in and run commands with the privileges of that account. Accounts with -empty passwords should never be used in operational environments. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then +empty passwords should never be used in operational environments. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then if [ -f /usr/bin/authselect ]; then if ! authselect check; then @@ -35091,43 +40309,65 @@ authselect enable-feature without-nullok authselect apply-changes -b else -if grep -qP '^\s*auth\s+'"sufficient"'\s+pam_unix.so\s.*\bnullok\b' "/etc/pam.d/system-auth"; then - sed -i -E --follow-symlinks 's/(.*auth.*'"sufficient"'.*pam_unix.so.*)\snullok=?[[:alnum:]]*(.*)/\1\2/g' "/etc/pam.d/system-auth" +if grep -qP "^\s*auth\s+sufficient\s+pam_unix.so\s.*\bnullok\b" "/etc/pam.d/system-auth"; then + sed -i -E --follow-symlinks "s/(.*auth.*sufficient.*pam_unix.so.*)\snullok=?[[:alnum:]]*(.*)/\1\2/g" "/etc/pam.d/system-auth" fi -if grep -qP '^\s*password\s+'"sufficient"'\s+pam_unix.so\s.*\bnullok\b' "/etc/pam.d/system-auth"; then - sed -i -E --follow-symlinks 's/(.*password.*'"sufficient"'.*pam_unix.so.*)\snullok=?[[:alnum:]]*(.*)/\1\2/g' "/etc/pam.d/system-auth" +if grep -qP "^\s*password\s+sufficient\s+pam_unix.so\s.*\bnullok\b" "/etc/pam.d/system-auth"; then + sed -i -E --follow-symlinks "s/(.*password.*sufficient.*pam_unix.so.*)\snullok=?[[:alnum:]]*(.*)/\1\2/g" "/etc/pam.d/system-auth" fi -if grep -qP '^\s*auth\s+'"sufficient"'\s+pam_unix.so\s.*\bnullok\b' "/etc/pam.d/password-auth"; then - sed -i -E --follow-symlinks 's/(.*auth.*'"sufficient"'.*pam_unix.so.*)\snullok=?[[:alnum:]]*(.*)/\1\2/g' "/etc/pam.d/password-auth" +if grep -qP "^\s*auth\s+sufficient\s+pam_unix.so\s.*\bnullok\b" "/etc/pam.d/password-auth"; then + sed -i -E --follow-symlinks "s/(.*auth.*sufficient.*pam_unix.so.*)\snullok=?[[:alnum:]]*(.*)/\1\2/g" "/etc/pam.d/password-auth" fi -if grep -qP '^\s*password\s+'"sufficient"'\s+pam_unix.so\s.*\bnullok\b' "/etc/pam.d/password-auth"; then - sed -i -E --follow-symlinks 's/(.*password.*'"sufficient"'.*pam_unix.so.*)\snullok=?[[:alnum:]]*(.*)/\1\2/g' "/etc/pam.d/password-auth" +if grep -qP "^\s*password\s+sufficient\s+pam_unix.so\s.*\bnullok\b" "/etc/pam.d/password-auth"; then + sed -i -E --follow-symlinks "s/(.*password.*sufficient.*pam_unix.so.*)\snullok=?[[:alnum:]]*(.*)/\1\2/g" "/etc/pam.d/password-auth" fi fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Prevent Login to Accounts With Empty Password - Check if system relies on - authselect - ansible.builtin.stat: - path: /usr/bin/authselect - register: result_authselect_present - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + + - name: Gather the package facts + package_facts: + manager: auto tags: - CJIS-5.5.2 + - DISA-STIG-OL09-00-001110 - NIST-800-171-3.1.1 - NIST-800-171-3.1.5 - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(1)(a) - NIST-800-53-IA-5(c) - PCI-DSS-Req-8.2.3 - - PCI-DSSv4-8.3.6 - - PCI-DSSv4-8.3.9 + - PCI-DSSv4-8.3 + - PCI-DSSv4-8.3.1 + - configure_strategy + - high_severity + - low_complexity + - medium_disruption + - no_empty_passwords + - no_reboot_needed + +- name: Prevent Login to Accounts With Empty Password - Check if system relies on + authselect + ansible.builtin.stat: + path: /usr/bin/authselect + register: result_authselect_present + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.5.2 + - DISA-STIG-OL09-00-001110 + - NIST-800-171-3.1.1 + - NIST-800-171-3.1.5 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(a) + - NIST-800-53-IA-5(c) + - PCI-DSS-Req-8.2.3 + - PCI-DSSv4-8.3 + - PCI-DSSv4-8.3.1 - configure_strategy - high_severity - low_complexity @@ -35187,18 +40427,19 @@ fi - result_authselect_enable_feature_cmd is not skipped - result_authselect_enable_feature_cmd is success when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - result_authselect_present.stat.exists tags: - CJIS-5.5.2 + - DISA-STIG-OL09-00-001110 - NIST-800-171-3.1.1 - NIST-800-171-3.1.5 - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(1)(a) - NIST-800-53-IA-5(c) - PCI-DSS-Req-8.2.3 - - PCI-DSSv4-8.3.6 - - PCI-DSSv4-8.3.9 + - PCI-DSSv4-8.3 + - PCI-DSSv4-8.3.1 - configure_strategy - high_severity - low_complexity @@ -35215,26 +40456,27 @@ fi - /etc/pam.d/system-auth - /etc/pam.d/password-auth when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - not result_authselect_present.stat.exists tags: - CJIS-5.5.2 + - DISA-STIG-OL09-00-001110 - NIST-800-171-3.1.1 - NIST-800-171-3.1.5 - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(1)(a) - NIST-800-53-IA-5(c) - PCI-DSS-Req-8.2.3 - - PCI-DSSv4-8.3.6 - - PCI-DSSv4-8.3.9 + - PCI-DSSv4-8.3 + - PCI-DSSv4-8.3.1 - configure_strategy - high_severity - low_complexity - medium_disruption - no_empty_passwords - no_reboot_needed - - --- + + --- apiVersion: machineconfiguration.openshift.io/v1 kind: MachineConfig spec: @@ -35253,17 +40495,17 @@ spec: mode: 0644 path: /etc/pam.d/system-auth overwrite: true - - - - - - - - - - Ensure There Are No Accounts With Blank or Null Passwords - Check the "/etc/shadow" file for blank passwords with the + + + + + + + + + + Ensure There Are No Accounts With Blank or Null Passwords + Check the "/etc/shadow" file for blank passwords with the following command: $ sudo awk -F: '!$2 {print $1}' /etc/shadow If the command returns any results, this is a finding. @@ -35272,18 +40514,24 @@ the account with the following commands: Perform a password reset: $ sudo passwd [username] Lock an account: -$ sudo passwd -l [username] - Note that this rule is not applicable for systems running within a container. Having user with empty password within a container is not considered a risk, because it should not be possible to directly login into a container anyway. - CCI-000366 - CM-6(b) - CM-6.1(iv) - SRG-OS-000480-GPOS-00227 - If an account has an empty password, anyone could log in and +$ sudo passwd -l [username] + + Note that this rule is not applicable for systems running within a container. Having user with empty password within a container is not considered a risk, because it should not be possible to directly login into a container anyway. + CCI-000366 + CM-6(b) + CM-6.1(iv) + SRG-OS-000480-GPOS-00227 + A.6.SEC-OL4 + 2.2.2 + 2.2 + OL09-00-001130 + SV-271638r1091626_rule + If an account has an empty password, anyone could log in and run commands with the privileges of that account. Accounts with -empty passwords should never be used in operational environments. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then +empty passwords should never be used in operational environments. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then readarray -t users_with_empty_pass < <(sudo awk -F: '!$2 {print $1}' /etc/shadow) @@ -35295,15 +40543,35 @@ done else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Collect users with no password + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-001130 + - NIST-800-53-CM-6(b) + - NIST-800-53-CM-6.1(iv) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.2 + - high_severity + - low_complexity + - low_disruption + - no_empty_passwords_etc_shadow + - no_reboot_needed + - restrict_strategy + +- name: Collect users with no password command: | awk -F: '!$2 {print $1}' /etc/shadow register: users_nopasswd - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + changed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-001130 - NIST-800-53-CM-6(b) - NIST-800-53-CM-6.1(iv) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.2 - high_severity - low_complexity - low_disruption @@ -35316,144 +40584,147 @@ fi passwd -l {{ item }} with_items: '{{ users_nopasswd.stdout_lines }}' when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - users_nopasswd.stdout_lines | length > 0 + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - users_nopasswd is not skipped and users_nopasswd.stdout_lines | length > 0 tags: + - DISA-STIG-OL09-00-001130 - NIST-800-53-CM-6(b) - NIST-800-53-CM-6.1(iv) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.2 - high_severity - low_complexity - low_disruption - no_empty_passwords_etc_shadow - no_reboot_needed - restrict_strategy - - - - - - - - - - Verify No netrc Files Exist - The .netrc files contain login information + + + + + + + + + + Verify No netrc Files Exist + The .netrc files contain login information used to auto-login into FTP servers and reside in the user's home directory. These files may contain unencrypted passwords to remote FTP servers making them susceptible to access by unauthorized -users and should not be used. Any .netrc files should be removed. - 1 - 11 - 12 - 14 - 15 - 16 - 18 - 3 - 5 - DSS05.02 - DSS05.04 - DSS05.05 - DSS05.07 - DSS05.10 - DSS06.03 - DSS06.06 - DSS06.10 - CCI-000196 - 4.3.3.2.2 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - A.18.1.4 - A.6.1.2 - A.7.1.1 - A.9.1.2 - A.9.2.1 - A.9.2.2 - A.9.2.3 - A.9.2.4 - A.9.2.6 - A.9.3.1 - A.9.4.1 - A.9.4.2 - A.9.4.3 - A.9.4.4 - A.9.4.5 - CIP-003-8 R1.3 - CIP-003-8 R3 - CIP-003-8 R3.1 - CIP-003-8 R3.2 - CIP-003-8 R3.3 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.2.3 - CIP-004-6 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.2 - CIP-007-3 R5.2 - CIP-007-3 R5.3.1 - CIP-007-3 R5.3.2 - CIP-007-3 R5.3.3 - IA-5(h) - IA-5(1)(c) - CM-6(a) - IA-5(7) - PR.AC-1 - PR.AC-4 - PR.AC-6 - PR.AC-7 - PR.PT-3 - Unencrypted passwords for remote FTP servers may be stored in .netrc -files. - - - - - - - - - - Restrict Root Logins - Direct root logins should be allowed only for emergency use. +users and should not be used. Any .netrc files should be removed. + 1 + 11 + 12 + 14 + 15 + 16 + 18 + 3 + 5 + DSS05.02 + DSS05.04 + DSS05.05 + DSS05.07 + DSS05.10 + DSS06.03 + DSS06.06 + DSS06.10 + CCI-000196 + 4.3.3.2.2 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + A.18.1.4 + A.6.1.2 + A.7.1.1 + A.9.1.2 + A.9.2.1 + A.9.2.2 + A.9.2.3 + A.9.2.4 + A.9.2.6 + A.9.3.1 + A.9.4.1 + A.9.4.2 + A.9.4.3 + A.9.4.4 + A.9.4.5 + CIP-003-8 R1.3 + CIP-003-8 R3 + CIP-003-8 R3.1 + CIP-003-8 R3.2 + CIP-003-8 R3.3 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.2.3 + CIP-004-6 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.2 + CIP-007-3 R5.2 + CIP-007-3 R5.3.1 + CIP-007-3 R5.3.2 + CIP-007-3 R5.3.3 + IA-5(h) + IA-5(1)(c) + CM-6(a) + IA-5(7) + PR.AC-1 + PR.AC-4 + PR.AC-6 + PR.AC-7 + PR.PT-3 + Unencrypted passwords for remote FTP servers may be stored in .netrc +files. + + + + + + + + + + Restrict Root Logins + Direct root logins should be allowed only for emergency use. In normal situations, the administrator should access the system via a unique unprivileged account, and then use su or sudo to execute privileged commands. Discouraging administrators from accessing the @@ -35471,144 +40742,147 @@ installation). The default securetty file also contains /dev/vc/* - - Group Name Used by pam_wheel Group Parameter - pam_wheel module has a parameter called group, which controls which groups +include guidance describing how to prevent root from logging in via SSH. + + Group Name Used by pam_wheel Group Parameter + pam_wheel module has a parameter called group, which controls which groups can access the su command. -This variable holds the valid value for the parameter. - - sugroup - - - Verify Only Root Has UID 0 - If any account other than root has a UID of 0, this misconfiguration should +This variable holds the valid value for the parameter. + sugroup + sugroup + + + Verify Only Root Has UID 0 + If any account other than root has a UID of 0, this misconfiguration should be investigated and the accounts other than root should be removed or have their UID changed. - + If the account is associated with system commands or applications the UID should be changed to one greater than "0" but less than "1000." Otherwise assign a UID greater than "1000" that has not already been -assigned. - 1 - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - APO01.06 - DSS05.04 - DSS05.05 - DSS05.07 - DSS05.10 - DSS06.02 - DSS06.03 - DSS06.10 - 3.1.1 - 3.1.5 - CCI-000366 - 4.3.3.2.2 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - SR 1.1 - SR 1.10 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 5.2 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.18.1.4 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.1 - A.9.2.2 - A.9.2.3 - A.9.2.4 - A.9.2.6 - A.9.3.1 - A.9.4.1 - A.9.4.2 - A.9.4.3 - A.9.4.4 - A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.2.3 - CIP-004-6 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.2 - CIP-007-3 R5.2 - CIP-007-3 R5.3.1 - CIP-007-3 R5.3.2 - CIP-007-3 R5.3.3 - IA-2 - AC-6(5) - IA-4(b) - PR.AC-1 - PR.AC-4 - PR.AC-6 - PR.AC-7 - PR.DS-5 - Req-8.5 - 8.2.2 - 8.2.3 - SRG-OS-000480-GPOS-00227 - An account has root authority if it has a UID of 0. Multiple accounts +assigned. + 1 + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + APO01.06 + DSS05.04 + DSS05.05 + DSS05.07 + DSS05.10 + DSS06.02 + DSS06.03 + DSS06.10 + 3.1.1 + 3.1.5 + CCI-000366 + 4.3.3.2.2 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + SR 1.1 + SR 1.10 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 5.2 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.18.1.4 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.1 + A.9.2.2 + A.9.2.3 + A.9.2.4 + A.9.2.6 + A.9.3.1 + A.9.4.1 + A.9.4.2 + A.9.4.3 + A.9.4.4 + A.9.4.5 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.2.3 + CIP-004-6 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.2 + CIP-007-3 R5.2 + CIP-007-3 R5.3.1 + CIP-007-3 R5.3.2 + CIP-007-3 R5.3.3 + IA-2 + AC-6(5) + IA-4(b) + PR.AC-1 + PR.AC-4 + PR.AC-6 + PR.AC-7 + PR.DS-5 + Req-8.5 + SRG-OS-000480-GPOS-00227 + 8.2.1 + 8.2 + OL09-00-003000 + SV-271831r1092205_rule + An account has root authority if it has a UID of 0. Multiple accounts with a UID of 0 afford more opportunity for potential intruders to guess a password for a privileged account. Proper configuration of sudo is recommended to afford multiple system administrators -access to root privileges in an accountable manner. - awk -F: '$3 == 0 && $1 != "root" { print $1 }' /etc/passwd | xargs --no-run-if-empty --max-lines=1 passwd -l - - - name: Get all /etc/passwd file entries +access to root privileges in an accountable manner. + awk -F: '$3 == 0 && $1 != "root" { print $1 }' /etc/passwd | xargs --no-run-if-empty --max-lines=1 passwd -l + + - name: Get all /etc/passwd file entries getent: database: passwd split: ':' tags: + - DISA-STIG-OL09-00-003000 - NIST-800-171-3.1.1 - NIST-800-171-3.1.5 - NIST-800-53-AC-6(5) - NIST-800-53-IA-2 - NIST-800-53-IA-4(b) - PCI-DSS-Req-8.5 - - PCI-DSSv4-8.2.2 - - PCI-DSSv4-8.2.3 + - PCI-DSSv4-8.2 + - PCI-DSSv4-8.2.1 - accounts_no_uid_except_zero - high_severity - low_complexity @@ -35622,44 +40896,88 @@ access to root privileges in an accountable manner. | list }}' when: item.value.1 == '0' tags: + - DISA-STIG-OL09-00-003000 - NIST-800-171-3.1.1 - NIST-800-171-3.1.5 - NIST-800-53-AC-6(5) - NIST-800-53-IA-2 - NIST-800-53-IA-4(b) - PCI-DSS-Req-8.5 - - PCI-DSSv4-8.2.2 - - PCI-DSSv4-8.2.3 + - PCI-DSSv4-8.2 + - PCI-DSSv4-8.2.1 - accounts_no_uid_except_zero - high_severity - low_complexity - low_disruption - no_reboot_needed - restrict_strategy - - - - - - - - - - Verify Root Has A Primary GID 0 - The root user should have a primary group of 0. - Req-8.1.1 - 8.2.1 - To help ensure that root-owned files are not inadvertently exposed to other users. - - - - - - - - - Direct root Logins Not Allowed - To further limit access to the root account, administrators + + + + + + + + + + Verify Root Has A Primary GID 0 + The root user should have a primary group of 0. + Req-8.1.1 + 8.2.1 + 8.2 + To help ensure that root-owned files are not inadvertently exposed to other users. + + + + + + + + + Ensure the Group Used by pam_wheel.so Module Exists on System and is Empty + Ensure that the group referenced by +var_pam_wheel_group_for_su variable and used as value for the pam_wheel.so + group option exists and has no members. This empty group used by +pam_wheel.so in /etc/pam.d/su ensures that no user can run commands with +altered privileges through the su command. + Note that this rule just ensures the group exists and has no members. This rule does not +configure pam_wheel.so module. The pam_wheel.so module configuration is +accomplished by use_pam_wheel_group_for_su rule. + 2.2.6 + 2.2 + The su program allows to run commands with a substitute user and group ID. +It is commonly used to run commands as the root user. +Limiting access to such command is considered a good security practice. + + + + + + + + + + + Ensure Authentication Required for Single User Mode + Single user mode is used for recovery when the system detects an +issue during boot or by manual selection from the bootloader. + A.6.SEC-OL4 + 2.2.2 + 2.2 + Requiring authentication in single user mode prevents an unauthorized +user from rebooting the system into single user to gain root privileges +without credentials. + + + + + + + + + + Direct root Logins Not Allowed + To further limit access to the root account, administrators can disable root logins at the console by editing the /etc/securetty file. This file lists all devices the root user is allowed to login to. If the file does not exist at all, the root user can login through any communication device on the @@ -35672,109 +40990,110 @@ contents of this file. To prevent direct root logins, remove the contents of thi file by typing the following command: $ sudo echo > /etc/securetty - - This rule only checks the /etc/securetty file existence and its content. + + + This rule only checks the /etc/securetty file existence and its content. If you need to restrict user access using the /etc/securetty file, make sure -the pam_securetty.so PAM module is properly enabled in relevant PAM files. - BP28(R19) - 1 - 12 - 15 - 16 - 5 - DSS05.04 - DSS05.05 - DSS05.07 - DSS05.10 - DSS06.03 - DSS06.10 - 3.1.1 - 3.1.6 - 164.308(a)(1)(ii)(B) - 164.308(a)(7)(i) - 164.308(a)(7)(ii)(A) - 164.310(a)(1) - 164.310(a)(2)(i) - 164.310(a)(2)(ii) - 164.310(a)(2)(iii) - 164.310(b) - 164.310(c) - 164.310(d)(1) - 164.310(d)(2)(iii) - 4.3.3.2.2 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.2 - 4.3.3.7.4 - SR 1.1 - SR 1.10 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - A.18.1.4 - A.7.1.1 - A.9.2.1 - A.9.2.2 - A.9.2.3 - A.9.2.4 - A.9.2.6 - A.9.3.1 - A.9.4.2 - A.9.4.3 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.2.3 - CIP-004-6 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.2 - CIP-007-3 R5.2 - CIP-007-3 R5.3.1 - CIP-007-3 R5.3.2 - CIP-007-3 R5.3.3 - IA-2 - CM-6(a) - PR.AC-1 - PR.AC-6 - PR.AC-7 - 8.6.1 - Disabling direct root logins ensures proper accountability and multifactor +the pam_securetty.so PAM module is properly enabled in relevant PAM files. + 1 + 12 + 15 + 16 + 5 + DSS05.04 + DSS05.05 + DSS05.07 + DSS05.10 + DSS06.03 + DSS06.10 + 3.1.1 + 3.1.6 + 164.308(a)(1)(ii)(B) + 164.308(a)(7)(i) + 164.308(a)(7)(ii)(A) + 164.310(a)(1) + 164.310(a)(2)(i) + 164.310(a)(2)(ii) + 164.310(a)(2)(iii) + 164.310(b) + 164.310(c) + 164.310(d)(1) + 164.310(d)(2)(iii) + 4.3.3.2.2 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.2 + 4.3.3.7.4 + SR 1.1 + SR 1.10 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + A.18.1.4 + A.7.1.1 + A.9.2.1 + A.9.2.2 + A.9.2.3 + A.9.2.4 + A.9.2.6 + A.9.3.1 + A.9.4.2 + A.9.4.3 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.2.3 + CIP-004-6 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.2 + CIP-007-3 R5.2 + CIP-007-3 R5.3.1 + CIP-007-3 R5.3.2 + CIP-007-3 R5.3.3 + IA-2 + CM-6(a) + PR.AC-1 + PR.AC-6 + PR.AC-7 + R33 + 8.6.1 + 8.6 + Disabling direct root logins ensures proper accountability and multifactor authentication to privileged accounts. Users will first login, then escalate to privileged (root) access via su / sudo. This is required for FISMA Low -and FISMA Moderate systems. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then +and FISMA Moderate systems. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then echo > /etc/securetty else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Direct root Logins Not Allowed - copy: - dest: /etc/securetty - content: '' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + + - name: Gather the package facts + package_facts: + manager: auto tags: - NIST-800-171-3.1.1 - NIST-800-171-3.1.6 - NIST-800-53-CM-6(a) - NIST-800-53-IA-2 + - PCI-DSSv4-8.6 - PCI-DSSv4-8.6.1 - low_complexity - low_disruption @@ -35782,37 +41101,62 @@ fi - no_direct_root_logins - no_reboot_needed - restrict_strategy - - - - - - - - - - Ensure that System Accounts Are Locked - Some accounts are not associated with a human user of the system, and exist to perform some + +- name: Direct root Logins Not Allowed + copy: + dest: /etc/securetty + content: '' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-171-3.1.1 + - NIST-800-171-3.1.6 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-2 + - PCI-DSSv4-8.6 + - PCI-DSSv4-8.6.1 + - low_complexity + - low_disruption + - medium_severity + - no_direct_root_logins + - no_reboot_needed + - restrict_strategy + + + + + + + + + + Ensure that System Accounts Are Locked + Some accounts are not associated with a human user of the system, and exist to perform some administrative functions. An attacker should not be able to log into these accounts. - + + System accounts are those user accounts with a user ID less than 1000. If any system account other than root, halt, sync, shutdown and nfsnobody has an unlocked password, disable it with the command: -$ sudo usermod -L account - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 - AC-6 - CM-6(a) - Disabling authentication for default system accounts makes it more difficult for attackers -to make use of them to compromise a system. - +$ sudo usermod -L account + + + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 + AC-6 + CM-6(a) + A.6.SEC-OL3 + 8.2.2 + 8.2 + Disabling authentication for default system accounts makes it more difficult for attackers +to make use of them to compromise a system. + readarray -t systemaccounts < <(awk -F: \ '($3 < 1000 && $3 != root && $3 != halt && $3 != sync && $3 != shutdown \ && $3 != nfsnobody) { print $1 }' /etc/passwd) @@ -35820,14 +41164,16 @@ readarray -t systemaccounts < <(awk -F: \ for systemaccount in "${systemaccounts[@]}"; do usermod -L "$systemaccount" done - - - name: Ensure that System Accounts Are Locked - Get All Local Users From /etc/passwd + + - name: Ensure that System Accounts Are Locked - Get All Local Users From /etc/passwd ansible.builtin.getent: database: passwd split: ':' tags: - NIST-800-53-AC-6 - NIST-800-53-CM-6(a) + - PCI-DSSv4-8.2 + - PCI-DSSv4-8.2.2 - low_complexity - medium_disruption - medium_severity @@ -35842,6 +41188,8 @@ done tags: - NIST-800-53-AC-6 - NIST-800-53-CM-6(a) + - PCI-DSSv4-8.2 + - PCI-DSSv4-8.2.2 - low_complexity - medium_disruption - medium_severity @@ -35860,98 +41208,107 @@ done tags: - NIST-800-53-AC-6 - NIST-800-53-CM-6(a) + - PCI-DSSv4-8.2 + - PCI-DSSv4-8.2.2 - low_complexity - medium_disruption - medium_severity - no_password_auth_for_systemaccounts - no_reboot_needed - restrict_strategy - - - - - - - - - - Ensure that System Accounts Do Not Run a Shell Upon Login - Some accounts are not associated with a human user of the system, and exist to perform some + + + + + + + + + + Ensure that System Accounts Do Not Run a Shell Upon Login + Some accounts are not associated with a human user of the system, and exist to perform some administrative functions. Should an attacker be able to log into these accounts, they should not be granted access to a shell. - + + The login shell for each local account is stored in the last field of each line in /etc/passwd. System accounts are those user accounts with a user ID less than 1000. The user ID is stored in the third field. If any system account other than root has a login shell, disable it with the command: -$ sudo usermod -s /sbin/nologin account - Do not perform the steps in this section on the root account. Doing so might cause the -system to become inaccessible. - 1 - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - 7 - 8 - DSS01.03 - DSS03.05 - DSS05.04 - DSS05.05 - DSS05.07 - DSS06.03 - CCI-000366 - 4.3.3.2.2 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - SR 1.1 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 6.2 - 1491 - A.12.4.1 - A.12.4.3 - A.6.1.2 - A.7.1.1 - A.9.1.2 - A.9.2.1 - A.9.2.2 - A.9.2.3 - A.9.2.4 - A.9.2.6 - A.9.3.1 - A.9.4.1 - A.9.4.2 - A.9.4.3 - A.9.4.4 - A.9.4.5 - AC-6 - CM-6(a) - CM-6(b) - CM-6.1(iv) - DE.CM-1 - DE.CM-3 - PR.AC-1 - PR.AC-4 - PR.AC-6 - 8.6.1 - SRG-OS-000480-GPOS-00227 - Ensuring shells are not given to system accounts upon login makes it more difficult for -attackers to make use of system accounts. - +$ sudo usermod -s /sbin/nologin account + + + Do not perform the steps in this section on the root account. Doing so might cause the +system to become inaccessible. + 1 + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + 7 + 8 + DSS01.03 + DSS03.05 + DSS05.04 + DSS05.05 + DSS05.07 + DSS06.03 + CCI-000366 + 4.3.3.2.2 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + SR 1.1 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 6.2 + 1491 + A.12.4.1 + A.12.4.3 + A.6.1.2 + A.7.1.1 + A.9.1.2 + A.9.2.1 + A.9.2.2 + A.9.2.3 + A.9.2.4 + A.9.2.6 + A.9.3.1 + A.9.4.1 + A.9.4.2 + A.9.4.3 + A.9.4.4 + A.9.4.5 + AC-6 + CM-6(a) + CM-6(b) + CM-6.1(iv) + DE.CM-1 + DE.CM-3 + PR.AC-1 + PR.AC-4 + PR.AC-6 + SRG-OS-000480-GPOS-00227 + A.6.SEC-OL3 + 8.2.2 + 8.2 + OL09-00-003051 + SV-271845r1092247_rule + Ensuring shells are not given to system accounts upon login makes it more difficult for +attackers to make use of system accounts. + readarray -t systemaccounts < <(awk -F: '($3 < 1000 && $3 != root \ && $7 != "\/sbin\/shutdown" && $7 != "\/sbin\/halt" && $7 != "\/bin\/sync") \ { print $1 }' /etc/passwd) @@ -35959,18 +41316,20 @@ readarray -t systemaccounts < <(awk -F: '($3 < 1000 && $3 != ro for systemaccount in "${systemaccounts[@]}"; do usermod -s /sbin/nologin "$systemaccount" done - - - name: Ensure that System Accounts Do Not Run a Shell Upon Login - Get All Local + + - name: Ensure that System Accounts Do Not Run a Shell Upon Login - Get All Local Users From /etc/passwd ansible.builtin.getent: database: passwd split: ':' tags: + - DISA-STIG-OL09-00-003051 - NIST-800-53-AC-6 - NIST-800-53-CM-6(a) - NIST-800-53-CM-6(b) - NIST-800-53-CM-6.1(iv) - - PCI-DSSv4-8.6.1 + - PCI-DSSv4-8.2 + - PCI-DSSv4-8.2.2 - low_complexity - medium_disruption - medium_severity @@ -35983,11 +41342,13 @@ done ansible.builtin.set_fact: local_users: '{{ ansible_facts.getent_passwd | dict2items }}' tags: + - DISA-STIG-OL09-00-003051 - NIST-800-53-AC-6 - NIST-800-53-CM-6(a) - NIST-800-53-CM-6(b) - NIST-800-53-CM-6.1(iv) - - PCI-DSSv4-8.6.1 + - PCI-DSSv4-8.2 + - PCI-DSSv4-8.2.2 - low_complexity - medium_disruption - medium_severity @@ -36006,102 +41367,105 @@ done - item.value[1]|int < 1000 - item.value[5] not in ['/sbin/shutdown', '/sbin/halt', '/bin/sync'] tags: + - DISA-STIG-OL09-00-003051 - NIST-800-53-AC-6 - NIST-800-53-CM-6(a) - NIST-800-53-CM-6(b) - NIST-800-53-CM-6.1(iv) - - PCI-DSSv4-8.6.1 + - PCI-DSSv4-8.2 + - PCI-DSSv4-8.2.2 - low_complexity - medium_disruption - medium_severity - no_reboot_needed - no_shelllogin_for_systemaccounts - restrict_strategy - - - - - - - - - - Restrict Serial Port Root Logins - To restrict root logins on serial ports, + + + + + + + + + + Restrict Serial Port Root Logins + To restrict root logins on serial ports, ensure lines of this form do not appear in /etc/securetty: ttyS0 -ttyS1 - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - APO01.06 - DSS05.04 - DSS05.07 - DSS06.02 - 3.1.1 - 3.1.5 - CCI-000770 - 164.308(a)(1)(ii)(B) - 164.308(a)(7)(i) - 164.308(a)(7)(ii)(A) - 164.310(a)(1) - 164.310(a)(2)(i) - 164.310(a)(2)(ii) - 164.310(a)(2)(iii) - 164.310(b) - 164.310(c) - 164.310(d)(1) - 164.310(d)(2)(iii) - 4.3.3.7.3 - SR 2.1 - SR 5.2 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 - AC-6 - CM-6(a) - PR.AC-4 - PR.DS-5 - Preventing direct root login to serial port interfaces +ttyS1 + + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + APO01.06 + DSS05.04 + DSS05.07 + DSS06.02 + 3.1.1 + 3.1.5 + CCI-000770 + 164.308(a)(1)(ii)(B) + 164.308(a)(7)(i) + 164.308(a)(7)(ii)(A) + 164.310(a)(1) + 164.310(a)(2)(i) + 164.310(a)(2)(ii) + 164.310(a)(2)(iii) + 164.310(b) + 164.310(c) + 164.310(d)(1) + 164.310(d)(2)(iii) + 4.3.3.7.3 + SR 2.1 + SR 5.2 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 + AC-6 + CM-6(a) + PR.AC-4 + PR.DS-5 + Preventing direct root login to serial port interfaces helps ensure accountability for actions taken on the systems -using the root account. - sed -i '/ttyS/d' /etc/securetty - - - name: Restrict Serial Port Root Logins +using the root account. + sed -i '/ttyS/d' /etc/securetty + + - name: Restrict Serial Port Root Logins lineinfile: dest: /etc/securetty regexp: ttyS[0-9] @@ -36117,104 +41481,107 @@ using the root account. - no_reboot_needed - restrict_serial_port_logins - restrict_strategy - - - - - - - - - - Restrict Virtual Console Root Logins - To restrict root logins through the (deprecated) virtual console devices, + + + + + + + + + + Restrict Virtual Console Root Logins + To restrict root logins through the (deprecated) virtual console devices, ensure lines of this form do not appear in /etc/securetty: vc/1 vc/2 vc/3 -vc/4 - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - APO01.06 - DSS05.04 - DSS05.07 - DSS06.02 - 3.1.1 - 3.1.5 - CCI-000770 - 164.308(a)(1)(ii)(B) - 164.308(a)(7)(i) - 164.308(a)(7)(ii)(A) - 164.310(a)(1) - 164.310(a)(2)(i) - 164.310(a)(2)(ii) - 164.310(a)(2)(iii) - 164.310(b) - 164.310(c) - 164.310(d)(1) - 164.310(d)(2)(iii) - 4.3.3.7.3 - SR 2.1 - SR 5.2 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 - AC-6 - CM-6(a) - PR.AC-4 - PR.DS-5 - 8.6.1 - SRG-OS-000324-GPOS-00125 - Preventing direct root login to virtual console devices +vc/4 + + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + APO01.06 + DSS05.04 + DSS05.07 + DSS06.02 + 3.1.1 + 3.1.5 + CCI-000770 + 164.308(a)(1)(ii)(B) + 164.308(a)(7)(i) + 164.308(a)(7)(ii)(A) + 164.310(a)(1) + 164.310(a)(2)(i) + 164.310(a)(2)(ii) + 164.310(a)(2)(iii) + 164.310(b) + 164.310(c) + 164.310(d)(1) + 164.310(d)(2)(iii) + 4.3.3.7.3 + SR 2.1 + SR 5.2 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 + AC-6 + CM-6(a) + PR.AC-4 + PR.DS-5 + SRG-OS-000324-GPOS-00125 + 8.6.1 + 8.6 + Preventing direct root login to virtual console devices helps ensure accountability for actions taken on the system -using the root account. - sed -i '/^vc\//d' /etc/securetty - - - name: Restrict Virtual Console Root Logins +using the root account. + sed -i '/^vc\/[0-9]/d' /etc/securetty + + - name: Restrict Virtual Console Root Logins lineinfile: dest: /etc/securetty - regexp: ^vc + regexp: ^vc/[0-9] state: absent tags: - NIST-800-171-3.1.1 - NIST-800-171-3.1.5 - NIST-800-53-AC-6 - NIST-800-53-CM-6(a) + - PCI-DSSv4-8.6 - PCI-DSSv4-8.6.1 - low_complexity - low_disruption @@ -36222,46 +41589,51 @@ using the root account. - no_reboot_needed - restrict_strategy - securetty_root_login_console_only - - - - - - - - - - Enforce usage of pam_wheel for su authentication - To ensure that only users who are members of the wheel group can + + + + + + + + + + Enforce usage of pam_wheel for su authentication + To ensure that only users who are members of the wheel group can run commands with altered privileges through the su command, make sure that the following line exists in the file /etc/pam.d/su: -auth required pam_wheel.so use_uid - Members of "wheel" or GID 0 groups are checked by default if the group option is not set +auth required pam_wheel.so use_uid + + Members of "wheel" or GID 0 groups are checked by default if the group option is not set for pam_wheel.so module. Therefore, members of these groups should be manually checked or -a different group should be informed according to the site policy. - FMT_SMF_EXT.1.1 - 8.6.1 - SRG-OS-000373-GPOS-00156 - SRG-OS-000312-GPOS-00123 - The su program allows to run commands with a substitute user and +a different group should be informed according to the site policy. + CCI-002165 + CCI-004895 + FMT_SMF_EXT.1.1 + SRG-OS-000373-GPOS-00156 + SRG-OS-000312-GPOS-00123 + A.5.SEC-OL1 + OL09-00-002361 + SV-271723r1091881_rule + The su program allows to run commands with a substitute user and group ID. It is commonly used to run commands as the root user. Limiting -access to such command is considered a good security practice. - - # Remediation is applicable only in certain platforms +access to such command is considered a good security practice. + + # Remediation is applicable only in certain platforms if rpm --quiet -q pam; then # uncomment the option if commented - sed '/^[[:space:]]*#[[:space:]]*auth[[:space:]]\+required[[:space:]]\+pam_wheel\.so[[:space:]]\+use_uid$/s/^[[:space:]]*#//' -i /etc/pam.d/su +sed '/^[[:space:]]*#[[:space:]]*auth[[:space:]]\+required[[:space:]]\+pam_wheel\.so[[:space:]]\+use_uid$/s/^[[:space:]]*#//' -i /etc/pam.d/su else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: - - PCI-DSSv4-8.6.1 + - DISA-STIG-OL09-00-002361 - low_complexity - low_disruption - medium_severity @@ -36276,26 +41648,50 @@ fi replace: auth required pam_wheel.so use_uid when: '"pam" in ansible_facts.packages' tags: - - PCI-DSSv4-8.6.1 + - DISA-STIG-OL09-00-002361 - low_complexity - low_disruption - medium_severity - no_reboot_needed - restrict_strategy - use_pam_wheel_for_su - - - - - - - - - - - - Secure Session Configuration Files for Login Accounts - When a user logs into a Unix account, the system + + + + + + + + + + Enforce Usage of pam_wheel with Group Parameter for su Authentication + To ensure that only users who are members of the group set in the group option of +pam_wheel.so module can run commands with altered privileges through the su +command, make sure that the following line exists in the file /etc/pam.d/su: +auth required pam_wheel.so use_uid group= + + + Note that ensure_pam_wheel_group_empty rule complements this requirement by +ensuring the referenced group exists and has no members. + 2.2.6 + 2.2 + The su program allows to run commands with a substitute user and group ID. +It is commonly used to run commands as the root user. +Limiting access to such command is considered a good security practice. + + + + + + + + + + + + + Secure Session Configuration Files for Login Accounts + When a user logs into a Unix account, the system configures the user's session by reading a number of files. Many of these files are located in the user's home directory, and may have weak permissions as a result of user error or misconfiguration. If @@ -36304,61 +41700,66 @@ configuration information, they can often gain full access to the affected user's account. Therefore, it is important to test and correct configuration file permissions for interactive accounts, particularly those of privileged users such as root or system -administrators. - - Maximum login attempts delay - Maximum time in seconds between fail login attempts before re-prompting. - 1 - 2 - 3 - 4 - 5 - 4 - - - Maximum concurrent login sessions - Maximum number of concurrent sessions by a user - 1 - 10 - 15 - 20 - 3 - 5 - 1 - - - Account Inactivity Timeout (seconds) - In an interactive shell, the value is interpreted as the +administrators. + + Maximum login attempts delay + Maximum time in seconds between fail login attempts before re-prompting. + 1 + 2 + 3 + 4 + 5 + 4 + + + Maximum concurrent login sessions + Maximum number of concurrent sessions by a user + 1 + 10 + 15 + 20 + 3 + 5 + 1 + + + Account Inactivity Timeout (seconds) + In an interactive shell, the value is interpreted as the number of seconds to wait for input after issuing the primary prompt. Bash terminates after waiting for that number of seconds if input does -not arrive. - 1800 - 600 - 900 - 300 - 600 - - - Interactive users initialization files - 'A regular expression describing a list of file names -for files that are sourced at login time for interactive users' - ^(\.bashrc|\.zshrc|\.cshrc|\.profile|\.bash_login|\.bash_profile)$ - ^\.[\w\- ]+$ - - - Ensure Home Directories are Created for New Users - All local interactive user accounts, upon creation, should be assigned a home directory. - +not arrive. + 1800 + 600 + 900 + 300 + 600 + + + Interactive users initialization files + 'A regular expression describing a list of file names +for files that are sourced at login time for interactive users' + ^(\.bashrc|\.zshrc|\.cshrc|\.profile|\.bash_login|\.bash_profile)$ + ^\.[\w\- ]+$ + + + Ensure Home Directories are Created for New Users + All local interactive user accounts, upon creation, should be assigned a home directory. + + Configure the operating system to assign home directories to all new local interactive users by setting the CREATE_HOME parameter in /etc/login.defs to yes as follows: - -CREATE_HOME yes - CCI-000366 - SRG-OS-000480-GPOS-00227 - If local interactive users are not assigned a valid home directory, there is no place -for the storage and control of files they should own. - - # Remediation is applicable only in certain platforms + + + CREATE_HOME yes + + CCI-000366 + SRG-OS-000480-GPOS-00227 + OL09-00-003052 + SV-271846r1092250_rule + If local interactive users are not assigned a valid home directory, there is no place +for the storage and control of files they should own. + + # Remediation is applicable only in certain platforms if rpm --quiet -q shadow-utils; then if [ -e "/etc/login.defs" ] ; then @@ -36388,11 +41789,12 @@ rm "/etc/login.defs.bak" else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-003052 - accounts_have_homedir_login_defs - low_complexity - low_disruption @@ -36406,8 +41808,8 @@ fi - name: Check for duplicate values lineinfile: path: /etc/login.defs - create: false - regexp: ^\s*CREATE_HOME\s+ + create: true + regexp: (?i)^\s*CREATE_HOME\s+ state: absent check_mode: true changed_when: false @@ -36416,8 +41818,8 @@ fi - name: Deduplicate values from /etc/login.defs lineinfile: path: /etc/login.defs - create: false - regexp: ^\s*CREATE_HOME\s+ + create: true + regexp: (?i)^\s*CREATE_HOME\s+ state: absent when: dupes.found is defined and dupes.found > 1 @@ -36425,58 +41827,63 @@ fi lineinfile: path: /etc/login.defs create: true - regexp: ^\s*CREATE_HOME\s+ + regexp: (?i)^\s*CREATE_HOME\s+ line: CREATE_HOME yes state: present when: '"shadow-utils" in ansible_facts.packages' tags: + - DISA-STIG-OL09-00-003052 - accounts_have_homedir_login_defs - low_complexity - low_disruption - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Ensure the Logon Failure Delay is Set Correctly in login.defs - To ensure the logon failure delay controlled by /etc/login.defs is set properly, + + + + + + + + + + Ensure the Logon Failure Delay is Set Correctly in login.defs + To ensure the logon failure delay controlled by /etc/login.defs is set properly, add or correct the FAIL_DELAY setting in /etc/login.defs to read as follows: -FAIL_DELAY - 11 - 3 - 9 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - CCI-000366 - 4.3.4.3.2 - 4.3.4.3.3 - SR 7.6 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.14.2.2 - A.14.2.3 - A.14.2.4 - AC-7(b) - CM-6(a) - PR.IP-1 - SRG-OS-000480-GPOS-00226 - Increasing the time between a failed authentication attempt and re-prompting to -enter credentials helps to slow a single-threaded brute force attack. - - # Remediation is applicable only in certain platforms +FAIL_DELAY + + + 11 + 3 + 9 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + CCI-000366 + 4.3.4.3.2 + 4.3.4.3.3 + SR 7.6 + A.12.1.2 + A.12.5.1 + A.12.6.2 + A.14.2.2 + A.14.2.3 + A.14.2.4 + AC-7(b) + CM-6(a) + PR.IP-1 + SRG-OS-000480-GPOS-00226 + OL09-00-003070 + SV-271850r1092262_rule + Increasing the time between a failed authentication attempt and re-prompting to +enter credentials helps to slow a single-threaded brute force attack. + + # Remediation is applicable only in certain platforms if rpm --quiet -q shadow-utils; then -var_accounts_fail_delay='' +var_accounts_fail_delay='' # Strip any search characters in the key arg so that the key can be replaced without @@ -36502,11 +41909,12 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-003070 - NIST-800-53-AC-7(b) - NIST-800-53-CM-6(a) - accounts_logon_fail_delay @@ -36517,7 +41925,7 @@ fi - restrict_strategy - name: XCCDF Value var_accounts_fail_delay # promote to variable set_fact: - var_accounts_fail_delay: !!str + var_accounts_fail_delay: !!str tags: - always @@ -36529,6 +41937,7 @@ fi create: true when: '"shadow-utils" in ansible_facts.packages' tags: + - DISA-STIG-OL09-00-003070 - NIST-800-53-AC-7(b) - NIST-800-53-CM-6(a) - accounts_logon_fail_delay @@ -36537,53 +41946,57 @@ fi - medium_severity - reboot_required - restrict_strategy - - - - - - - - - - - Limit the Number of Concurrent Login Sessions Allowed Per User - Limiting the number of allowed users and sessions per user can limit risks related to Denial of + + + + + + + + + + + Limit the Number of Concurrent Login Sessions Allowed Per User + Limiting the number of allowed users and sessions per user can limit risks related to Denial of Service attacks. This addresses concurrent sessions for a single account and does not address concurrent sessions by a single user via multiple accounts. To set the number of concurrent sessions per user add the following line in /etc/security/limits.conf or a file under /etc/security/limits.d/: -* hard maxlogins - 14 - 15 - 18 - 9 - 5.5.2.2 - DSS01.05 - DSS05.02 - CCI-000054 - 4.3.3.4 - SR 3.1 - SR 3.8 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.14.1.2 - A.14.1.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.2 - AC-10 - CM-6(a) - PR.AC-5 - SRG-OS-000027-GPOS-00008 - Limiting simultaneous user logins can insulate the system from denial of service +* hard maxlogins + + + 14 + 15 + 18 + 9 + 5.5.2.2 + DSS01.05 + DSS05.02 + CCI-000054 + 4.3.3.4 + SR 3.1 + SR 3.8 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.14.1.2 + A.14.1.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.2 + AC-10 + CM-6(a) + PR.AC-5 + SRG-OS-000027-GPOS-00008 + OL09-00-002415 + SV-271753r1091971_rule + Limiting simultaneous user logins can insulate the system from denial of service problems caused by excessive logins. Automated login processes operating improperly or -maliciously may result in an exceptional number of simultaneous login sessions. - - # Remediation is applicable only in certain platforms +maliciously may result in an exceptional number of simultaneous login sessions. + + # Remediation is applicable only in certain platforms if rpm --quiet -q pam; then -var_accounts_max_concurrent_login_sessions='' +var_accounts_max_concurrent_login_sessions='' if grep -q '^[^#]*\<maxlogins\>' /etc/security/limits.d/*.conf; then @@ -36597,12 +42010,13 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: - CJIS-5.5.2.2 + - DISA-STIG-OL09-00-002415 - NIST-800-53-AC-10 - NIST-800-53-CM-6(a) - accounts_max_concurrent_login_sessions @@ -36613,7 +42027,7 @@ fi - restrict_strategy - name: XCCDF Value var_accounts_max_concurrent_login_sessions # promote to variable set_fact: - var_accounts_max_concurrent_login_sessions: !!str + var_accounts_max_concurrent_login_sessions: !!str tags: - always @@ -36626,6 +42040,7 @@ fi when: '"pam" in ansible_facts.packages' tags: - CJIS-5.5.2.2 + - DISA-STIG-OL09-00-002415 - NIST-800-53-AC-10 - NIST-800-53-CM-6(a) - accounts_max_concurrent_login_sessions @@ -36647,6 +42062,7 @@ fi when: '"pam" in ansible_facts.packages' tags: - CJIS-5.5.2.2 + - DISA-STIG-OL09-00-002415 - NIST-800-53-AC-10 - NIST-800-53-CM-6(a) - accounts_max_concurrent_login_sessions @@ -36670,6 +42086,7 @@ fi - maxlogins.matched == 0 tags: - CJIS-5.5.2.2 + - DISA-STIG-OL09-00-002415 - NIST-800-53-AC-10 - NIST-800-53-CM-6(a) - accounts_max_concurrent_login_sessions @@ -36678,32 +42095,28 @@ fi - low_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - - Configure Polyinstantiation of /tmp Directories - To configure polyinstantiated /tmp directories, first create the parent directories + + + + + + + + + + + Configure Polyinstantiation of /tmp Directories + To configure polyinstantiated /tmp directories, first create the parent directories which will hold the polyinstantiation child directories. Use the following command: $ sudo mkdir --mode 000 /tmp/tmp-inst Then, add the following entry to /etc/security/namespace.conf: -/tmp /tmp/tmp-inst/ level root,adm - BP28(R39) - Polyinstantiation of temporary directories is a proactive security measure +/tmp /tmp/tmp-inst/ level root,adm + + R55 + Polyinstantiation of temporary directories is a proactive security measure which reduces chances of attacks that are made possible by /tmp -directories being world-writable. - - # Remediation is applicable only in certain platforms -if ! ( [ "${container:-}" == "bwrap-osbuild" ] ); then - -#!/bin/bash - +directories being world-writable. + # shellcheck disable=SC2174 mkdir -p --mode 000 /tmp/tmp-inst chmod 000 /tmp/tmp-inst @@ -36715,35 +42128,27 @@ if ! grep -Eq '^\s*/tmp\s+/tmp/tmp-inst/\s+level\s+root,adm$' /etc/security/name fi echo "/tmp /tmp/tmp-inst/ level root,adm" >> /etc/security/namespace.conf fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - - - - - - - - Configure Polyinstantiation of /var/tmp Directories - To configure polyinstantiated /tmp directories, first create the parent directories + + + + + + + + + + Configure Polyinstantiation of /var/tmp Directories + To configure polyinstantiated /tmp directories, first create the parent directories which will hold the polyinstantiation child directories. Use the following command: $ sudo mkdir --mode 000 /var/tmp/tmp-inst Then, add the following entry to /etc/security/namespace.conf: -/var/tmp /var/tmp/tmp-inst/ level root,adm - BP28(R39) - Polyinstantiation of temporary directories is a proactive security measure +/var/tmp /var/tmp/tmp-inst/ level root,adm + + R55 + Polyinstantiation of temporary directories is a proactive security measure which reduces chances of attacks that are made possible by /var/tmp -directories being world-writable. - - # Remediation is applicable only in certain platforms -if ! ( [ "${container:-}" == "bwrap-osbuild" ] ); then - -#!/bin/bash - +directories being world-writable. + # shellcheck disable=SC2174 mkdir -p --mode 000 /var/tmp/tmp-inst chmod 000 /var/tmp/tmp-inst @@ -36755,86 +42160,89 @@ if ! grep -Eq '^\s*/var/tmp\s+/var/tmp/tmp-inst/\s+level\s+root,adm$' /etc/secur fi echo "/var/tmp /var/tmp/tmp-inst/ level root,adm" >> /etc/security/namespace.conf fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - - - - - - - - Set Interactive Session Timeout - Setting the TMOUT option in /etc/profile ensures that + + + + + + + + + + Set Interactive Session Timeout + Setting the TMOUT option in /etc/profile ensures that all user sessions will terminate based on inactivity. The value of TMOUT should be exported and read only. The TMOUT setting in a file loaded by /etc/profile, e.g. /etc/profile.d/tmout.sh should read as follows: -declare -xr TMOUT= - BP28(R29) - 1 - 12 - 15 - 16 - DSS05.04 - DSS05.10 - DSS06.10 - 3.1.11 - CCI-000057 - CCI-001133 - CCI-002361 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - SR 1.1 - SR 1.10 - SR 1.2 - SR 1.5 - SR 1.7 - SR 1.8 - SR 1.9 - A.18.1.4 - A.9.2.1 - A.9.2.4 - A.9.3.1 - A.9.4.2 - A.9.4.3 - CIP-004-6 R2.2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.2 - CIP-007-3 R5.3.1 - CIP-007-3 R5.3.2 - CIP-007-3 R5.3.3 - AC-12 - SC-10 - AC-2(5) - CM-6(a) - PR.AC-7 - FMT_MOF_EXT.1 - 8.6.1 - SRG-OS-000163-GPOS-00072 - SRG-OS-000029-GPOS-00010 - Terminating an idle session within a short time period reduces +typeset -xr TMOUT= + +or +declare -xr TMOUT= + +Using the typeset keyword is preferred for wider compatibility with ksh and other shells. + 1 + 12 + 15 + 16 + DSS05.04 + DSS05.10 + DSS06.10 + 3.1.11 + CCI-000057 + CCI-001133 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + SR 1.1 + SR 1.10 + SR 1.2 + SR 1.5 + SR 1.7 + SR 1.8 + SR 1.9 + A.18.1.4 + A.9.2.1 + A.9.2.4 + A.9.3.1 + A.9.4.2 + A.9.4.3 + CIP-004-6 R2.2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.2 + CIP-007-3 R5.3.1 + CIP-007-3 R5.3.2 + CIP-007-3 R5.3.3 + AC-12 + SC-10 + AC-2(5) + CM-6(a) + PR.AC-7 + SRG-OS-000163-GPOS-00072 + SRG-OS-000029-GPOS-00010 + R32 + A.5.SEC-OL8 + 8.6.1 + 8.6 + OL09-00-002411 + SV-271750r1091962_rule + Terminating an idle session within a short time period reduces the window of opportunity for unauthorized personnel to take control of a management session enabled on the console or console port that has been -left unattended. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then +left unattended. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -var_accounts_tmout='' +var_accounts_tmout='' # if 0, no occurence of tmout found, if 1, occurence found @@ -36844,25 +42252,41 @@ tmout_found=0 for f in /etc/profile /etc/profile.d/*.sh; do if grep --silent '^[^#].*TMOUT' $f; then - sed -i -E "s/^(.*)TMOUT\s*=\s*(\w|\$)*(.*)$/declare -xr TMOUT=$var_accounts_tmout\3/g" $f + sed -i -E "s/^(.*)TMOUT\s*=\s*(\w|\$)*(.*)$/typeset -xr TMOUT=$var_accounts_tmout\3/g" $f tmout_found=1 fi done if [ $tmout_found -eq 0 ]; then echo -e "\n# Set TMOUT to $var_accounts_tmout per security requirements" >> /etc/profile.d/tmout.sh - echo "declare -xr TMOUT=$var_accounts_tmout" >> /etc/profile.d/tmout.sh - echo "readonly TMOUT" >> /etc/profile.d/tmout.sh - echo "export TMOUT" >> /etc/profile.d/tmout.sh + echo "typeset -xr TMOUT=$var_accounts_tmout" >> /etc/profile.d/tmout.sh fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: XCCDF Value var_accounts_tmout # promote to variable + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002411 + - NIST-800-171-3.1.11 + - NIST-800-53-AC-12 + - NIST-800-53-AC-2(5) + - NIST-800-53-CM-6(a) + - NIST-800-53-SC-10 + - PCI-DSSv4-8.6 + - PCI-DSSv4-8.6.1 + - accounts_tmout + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy +- name: XCCDF Value var_accounts_tmout # promote to variable set_fact: - var_accounts_tmout: !!str + var_accounts_tmout: !!str tags: - always @@ -36870,15 +42294,17 @@ fi replace: path: /etc/profile regexp: ^[^#].*TMOUT=.* - replace: declare -xr TMOUT={{ var_accounts_tmout }} + replace: typeset -xr TMOUT={{ var_accounts_tmout }} register: profile_replaced - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-002411 - NIST-800-171-3.1.11 - NIST-800-53-AC-12 - NIST-800-53-AC-2(5) - NIST-800-53-CM-6(a) - NIST-800-53-SC-10 + - PCI-DSSv4-8.6 - PCI-DSSv4-8.6.1 - accounts_tmout - low_complexity @@ -36892,15 +42318,17 @@ fi path: /etc/profile.d/tmout.sh create: true regexp: TMOUT= - line: declare -xr TMOUT={{ var_accounts_tmout }} + line: typeset -xr TMOUT={{ var_accounts_tmout }} state: present - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-002411 - NIST-800-171-3.1.11 - NIST-800-53-AC-12 - NIST-800-53-AC-2(5) - NIST-800-53-CM-6(a) - NIST-800-53-SC-10 + - PCI-DSSv4-8.6 - PCI-DSSv4-8.6.1 - accounts_tmout - low_complexity @@ -36908,28 +42336,74 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - - User Initialization Files Must Not Run World-Writable Programs - Set the mode on files being executed by the user initialization files with the + + + + + + + + + + + User Initialization Files Must Be Group-Owned By The Primary Group + Change the group owner of interactive users files to the group found +in /etc/passwd for the user. To change the group owner of a local +interactive user home directory, use the following command: +$ sudo chgrp USER_GROUP /home/USER/.INIT_FILE + + +This rule ensures every initialization file related to an interactive user +is group-owned by an interactive user. + Due to OVAL limitation, this rule can report a false negative in a +specific situation where two interactive users swap the group-ownership +of their respective initialization files. + CCI-000366 + SRG-OS-000480-GPOS-00227 + R50 + Local initialization files for interactive users are used to configure the +user's shell environment upon logon. Malicious modification of these files could +compromise accounts upon logon. + +awk -F':' '{ if ($3 >= 1000 && $3 != 65534) system("chgrp -f " $4" "$6"/.[^\.]?*") }' /etc/passwd + + - name: Ensure interactive local users are the group-owners of their respective initialization + files + ansible.builtin.command: + cmd: awk -F':' '{ if ($3 >= 1000 && $3 != 65534) system("chgrp -f " $4" "$6"/.[^\.]?*") + }' /etc/passwd + tags: + - accounts_user_dot_group_ownership + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + + + + + + + + + + User Initialization Files Must Not Run World-Writable Programs + Set the mode on files being executed by the user initialization files with the following command: -$ sudo chmod o-w FILE - CCI-000366 - SRG-OS-000480-GPOS-00227 - If user start-up files execute world-writable programs, especially in +$ sudo chmod o-w FILE + + + CCI-000366 + SRG-OS-000480-GPOS-00227 + OL09-00-002427 + SV-271765r1092007_rule + If user start-up files execute world-writable programs, especially in unprotected directories, they could be maliciously modified to destroy user files or otherwise compromise the system at the user level. If the system is compromised at the user level, it is easier to elevate privileges to eventually -compromise the system at the root and network level. - +compromise the system at the root and network level. + readarray -t world_writable_files < <(find / -xdev -type f -perm -0002 2> /dev/null) readarray -t interactive_home_dirs < <(awk -F':' '{ if ($3 >= 1000 && $3 != 65534) print $6 }' /etc/passwd) @@ -36941,23 +42415,158 @@ for world_writable in "${world_writable_files[@]}"; do fi done done - - - - - - - - - - - Ensure that Users Path Contains Only Local Directories - Ensure that all interactive user initialization files executable search + + - name: User Initialization Files Must Not Run World-Writable Programs - Initialize + variables + set_fact: + home_user_dirs: [] + world_writable_files: [] + tags: + - DISA-STIG-OL09-00-002427 + - accounts_user_dot_no_world_writable_programs + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: User Initialization Files Must Not Run World-Writable Programs - Get user's + home dir list + ansible.builtin.getent: + database: passwd + register: passwd_database + tags: + - DISA-STIG-OL09-00-002427 + - accounts_user_dot_no_world_writable_programs + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: User Initialization Files Must Not Run World-Writable Programs - Fill home_user_dirs + set_fact: + home_user_dirs: '{{ home_user_dirs + [item.data[4]] }}' + when: item.data[4] is defined and item.data[2]|int >= 1000 and item.data[2]|int + != 65534 + with_items: '{{ passwd_database.ansible_facts.getent_passwd | dict2items(key_name=''user'', + value_name=''data'')}}' + tags: + - DISA-STIG-OL09-00-002427 + - accounts_user_dot_no_world_writable_programs + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: User Initialization Files Must Not Run World-Writable Programs - Get world + writable files + ansible.builtin.shell: | + find / -xdev -type f -perm -0002 2> /dev/null + register: world_writable_files + tags: + - DISA-STIG-OL09-00-002427 + - accounts_user_dot_no_world_writable_programs + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: User Initialization Files Must Not Run World-Writable Programs - Find referenced_files + in init files + ansible.builtin.find: + paths: '{{ home_user_dirs }}' + contains: '{{ item }}' + hidden: true + read_whole_file: true + recurse: true + with_items: '{{ world_writable_files.stdout_lines }}' + register: referenced_files + tags: + - DISA-STIG-OL09-00-002427 + - accounts_user_dot_no_world_writable_programs + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: User Initialization Files Must Not Run World-Writable Programs - Remove world + writable permissions + ansible.builtin.file: + path: '{{ item.item }}' + mode: o-w + when: item.matched > 0 + with_items: '{{ referenced_files.results }}' + tags: + - DISA-STIG-OL09-00-002427 + - accounts_user_dot_no_world_writable_programs + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + + + + + + + + + + + User Initialization Files Must Be Owned By the Primary User + Set the owner of the user initialization files for interactive users to +the primary owner with the following command: +$ sudo chown USER /home/USER/.* + +This rule ensures every initialization file related to an interactive user +is owned by an interactive user. + Due to OVAL limitation, this rule can report a false negative in a +specific situation where two interactive users swap the ownership of +their respective initialization files. + CCI-000366 + SRG-OS-000480-GPOS-00227 + R50 + Local initialization files are used to configure the user's shell environment +upon logon. Malicious modification of these files could compromise accounts upon +logon. + +awk -F':' '{ if ($3 >= 1000 && $3 != 65534) system("chown -f " $3" "$6"/.[^\.]?*") }' /etc/passwd + + - name: Ensure interactive local users are the owners of their respective initialization + files + ansible.builtin.command: + cmd: awk -F':' '{ if ($3 >= 1000 && $3 != 65534) system("chown -f " $3" "$6"/.[^\.]?*") + }' /etc/passwd + tags: + - accounts_user_dot_user_ownership + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + + + + + + + + + + Ensure that Users Path Contains Only Local Directories + Ensure that all interactive user initialization files executable search path statements do not contain statements that will reference a working -directory other than the users home directory. - CCI-000366 - SRG-OS-000480-GPOS-00227 - The executable search path (typically the PATH environment variable) contains a +directory other than the users home directory. + CCI-000366 + SRG-OS-000480-GPOS-00227 + OL09-00-003053 + SV-271847r1092253_rule + The executable search path (typically the PATH environment variable) contains a list of directories for the shell to search to find executables. If this path includes the current working directory (other than the users home directory), executables in these directories may be executed instead of system commands. @@ -36965,37 +42574,40 @@ This variable is formatted as a colon-separated list of directories. If there is an empty entry, such as a leading or trailing colon or two consecutive colons, this is interpreted as the current working directory. If deviations from the default system search path for the local interactive user are required, they -must be documented with the Information System Security Officer (ISSO). - - - - - - All Interactive Users Must Have A Home Directory Defined - Assign home directories to all interactive users that currently do not +must be documented with the Information System Security Officer (ISSO). + + + + + + All Interactive Users Must Have A Home Directory Defined + Assign home directories to all interactive users that currently do not have a home directory assigned. This rule checks if the home directory is properly defined in a folder which has at least one parent folder, like "user" in "/home/user" or "/remote/users/user". Therefore, this rule will report a finding for home directories like /users, -/tmp or /. - CCI-000366 - SRG-OS-000480-GPOS-00227 - If local interactive users are not assigned a valid home directory, there is no -place for the storage and control of files they should own. - +/tmp or /. + CCI-000366 + SRG-OS-000480-GPOS-00227 + OL09-00-003002 + SV-271833r1092607_rule + If local interactive users are not assigned a valid home directory, there is no +place for the storage and control of files they should own. + for user in $(awk -F':' '{ if ($3 >= 1000 && $3 != 65534) print $1 }' /etc/passwd); do # This follows the same logic of evaluation of home directories as used in OVAL. if ! grep -q $user /etc/passwd | cut -d: -f6 | grep '^\/\w*\/\w\{1,\}'; then sed -i "s/\($user:x:[0-9]*:[0-9]*:.*:\).*\(:.*\)$/\1\/home\/$user\2/g" /etc/passwd; fi done - - - name: Get all local users from /etc/passwd + + - name: Get all local users from /etc/passwd ansible.builtin.getent: database: passwd split: ':' tags: + - DISA-STIG-OL09-00-003002 - accounts_user_interactive_home_directory_defined - low_complexity - low_disruption @@ -37007,6 +42619,7 @@ done ansible.builtin.set_fact: local_users: '{{ ansible_facts.getent_passwd|dict2items }}' tags: + - DISA-STIG-OL09-00-003002 - accounts_user_interactive_home_directory_defined - low_complexity - low_disruption @@ -37023,45 +42636,52 @@ done when: - item.value[2]|int >= 1000 - item.value[2]|int != 65534 + - item.value[2]|int < 61184 or item.value[2]|int > 65519 - not item.value[4] | regex_search('^\/\w*\/\w{1,}') tags: + - DISA-STIG-OL09-00-003002 - accounts_user_interactive_home_directory_defined - low_complexity - low_disruption - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - All Interactive Users Home Directories Must Exist - Create home directories to all local interactive users that currently do not + + + + + + + + + + All Interactive Users Home Directories Must Exist + Create home directories to all local interactive users that currently do not have a home directory assigned. Use the following commands to create the user home directory assigned in /etc/passwd: -$ sudo mkdir /home/USER - CCI-000366 - SRG-OS-000480-GPOS-00227 - If a local interactive user has a home directory defined that does not exist, +$ sudo mkdir /home/USER + + + CCI-000366 + SRG-OS-000480-GPOS-00227 + OL09-00-003050 + SV-271844r1092244_rule + If a local interactive user has a home directory defined that does not exist, the user may be given access to the / directory as the current working directory upon logon. This could create a Denial of Service because the user would not be able to access their logon configuration files, and it may give them visibility -to system files they normally would not be able to access. - +to system files they normally would not be able to access. + for user in $(awk -F':' '{ if ($3 >= 1000 && $3 != 65534) print $1}' /etc/passwd); do mkhomedir_helper $user 0077; done - - - name: Get all local users from /etc/passwd + + - name: Get all local users from /etc/passwd ansible.builtin.getent: database: passwd split: ':' tags: + - DISA-STIG-OL09-00-003050 - accounts_user_interactive_home_directory_exists - low_complexity - low_disruption @@ -37073,6 +42693,7 @@ done ansible.builtin.set_fact: local_users: '{{ ansible_facts.getent_passwd|dict2items }}' tags: + - DISA-STIG-OL09-00-003050 - accounts_user_interactive_home_directory_exists - low_complexity - low_disruption @@ -37089,47 +42710,319 @@ done - item.value[2]|int >= 1000 - item.value[2]|int != 65534 tags: + - DISA-STIG-OL09-00-003050 - accounts_user_interactive_home_directory_exists - low_complexity - low_disruption - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - All Interactive User Home Directories Must Be Group-Owned By The Primary Group - Change the group owner of interactive users home directory to the -group found in /etc/passwd. To change the group owner of -interactive users home directory, use the following command: -$ sudo chgrp USER_GROUP /home/USER + + + + + + + + + + All User Files and Directories In The Home Directory Must Be Group-Owned By The Primary Group + Change the group of a local interactive users files and directories to a +group that the interactive user is a member of. To change the group owner of a +local interactive users files and directories, use the following command: +$ sudo chgrp USER_GROUP /home/USER/FILE_DIR + -This rule ensures every home directory related to an interactive user is -group-owned by an interactive user. It also ensures that interactive users -are group-owners of one and only one home directory. - Due to OVAL limitation, this rule can report a false negative in a +This rule ensures every file or directory under the home directory related +to an interactive user is group-owned by an interactive user. + Due to OVAL limitation, this rule can report a false negative in a specific situation where two interactive users swap the group-ownership -of their respective home directories. - CCI-000366 - SRG-OS-000480-GPOS-00227 - If the Group Identifier (GID) of a local interactive users home directory is -not the same as the primary GID of the user, this would allow unauthorized -access to the users files, and users that share the same group may not be -able to access files that they legitimately should. - -awk -F':' '{ if ($3 >= 1000 && $3 != 65534) system("chgrp -f " $4" "$6) }' /etc/passwd - - - name: Get all local users from /etc/passwd +of folders or files in their respective home directories. + CCI-000366 + SRG-OS-000480-GPOS-00227 + R50 + If a local interactive users files are group-owned by a group of which the +user is not a member, unintended users may be able to access them. + +for user in $(awk -F':' '{ if ($3 >= 1000 && $3 != 65534 && $6 != "/") print $1 }' /etc/passwd); do + home_dir=$(getent passwd $user | cut -d: -f6) + group=$(getent passwd $user | cut -d: -f4) + # Only update the group-ownership when necessary. This will avoid changing the inode timestamp + # when the group is already defined as expected, therefore not impacting in possible integrity + # check systems that also check inodes timestamps. + find $home_dir -not -group $group -exec chgrp -f --no-dereference $group {} \; +done + + - name: Get all local users from /etc/passwd ansible.builtin.getent: database: passwd split: ':' tags: + - accounts_users_home_files_groupownership + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Create local_users variable from the getent output + ansible.builtin.set_fact: + local_users: '{{ ansible_facts.getent_passwd|dict2items }}' + tags: + - accounts_users_home_files_groupownership + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Test for existence of home directories to avoid creating them, but only fixing + ownership + ansible.builtin.stat: + path: '{{ item.value[4] }}' + register: path_exists + loop: '{{ local_users }}' + when: + - item.value[1]|int >= 1000 + - item.value[1]|int != 65534 + - item.value[4] != "/" + tags: + - accounts_users_home_files_groupownership + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure interactive local users are the owners of their respective home directories + ansible.builtin.file: + path: '{{ item.0.value[4] }}' + group: '{{ item.0.value[2] }}' + recurse: true + loop: '{{ local_users|zip(path_exists.results)|list }}' + when: item.1.stat is defined and item.1.stat.exists + tags: + - accounts_users_home_files_groupownership + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + + + + + + + + + + All User Files and Directories In The Home Directory Must Have a Valid Owner + Either remove all files and directories from the system that +do not have a valid user, or assign a valid user to all unowned +files and directories. To assign a valid owner to a local +interactive user's files and directories, use the following command: +$ sudo chown -R USER /home/USER + + +This rule ensures every file or directory under the home directory related +to an interactive user is owned by an interactive user. + Due to OVAL limitation, this rule can report a false negative in a +specific situation where two interactive users swap the ownership of +folders or files in their respective home directories. + CCI-000366 + SRG-OS-000480-GPOS-00227 + R50 + If local interactive users do not own the files in their directories, +unauthorized users may be able to access them. Additionally, if files are not +owned by the user, this could be an indication of system compromise. + +for user in $(awk -F':' '{ if ($3 >= 1000 && $3 != 65534 && $6 != "/") print $1 }' /etc/passwd); do + home_dir=$(getent passwd $user | cut -d: -f6) + # Only update the ownership when necessary. This will avoid changing the inode timestamp + # when the owner is already defined as expected, therefore not impacting in possible integrity + # check systems that also check inodes timestamps. + find $home_dir -not -user $user -exec chown -f --no-dereference $user {} \; +done + + - name: Get all local users from /etc/passwd + ansible.builtin.getent: + database: passwd + split: ':' + tags: + - accounts_users_home_files_ownership + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Create local_users variable from the getent output + ansible.builtin.set_fact: + local_users: '{{ ansible_facts.getent_passwd|dict2items }}' + tags: + - accounts_users_home_files_ownership + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Test for existence of home directories to avoid creating them, but only fixing + ownership + ansible.builtin.stat: + path: '{{ item.value[4] }}' + register: path_exists + loop: '{{ local_users }}' + when: + - item.value[1]|int >= 1000 + - item.value[1]|int != 65534 + - item.value[4] != "/" + tags: + - accounts_users_home_files_ownership + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure interactive local users are the owners of their respective home directories + ansible.builtin.file: + path: '{{ item.0.value[4] }}' + owner: '{{ item.0.value[1] }}' + recurse: true + loop: '{{ local_users|zip(path_exists.results)|list }}' + when: item.1.stat is defined and item.1.stat.exists + tags: + - accounts_users_home_files_ownership + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + + + + + + + + + + All User Files and Directories In The Home Directory Must Have Mode 0750 Or Less Permissive + Set the mode on files and directories in the local interactive user home +directory with the following command: +$ sudo chmod 0750 /home/USER/FILE_DIR + +Files that begin with a "." are excluded from this requirement. + CCI-000366 + SRG-OS-000480-GPOS-00227 + R50 + If a local interactive user files have excessive permissions, unintended users +may be able to access or modify them. + +for home_dir in $(awk -F':' '{ if ($3 >= 1000 && $3 != 65534 && $6 != "/") print $6 }' /etc/passwd); do + # Only update the permissions when necessary. This will avoid changing the inode timestamp when + # the permission is already defined as expected, therefore not impacting in possible integrity + # check systems that also check inodes timestamps. + find "$home_dir" -perm /7027 \! -type l -exec chmod u-s,g-w-s,o=- {} \; +done + + - name: Get all local users from /etc/passwd + ansible.builtin.getent: + database: passwd + split: ':' + tags: + - accounts_users_home_files_permissions + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Create local_users variable from the getent output + ansible.builtin.set_fact: + local_users: '{{ ansible_facts.getent_passwd|dict2items }}' + tags: + - accounts_users_home_files_permissions + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Test for existence home directories to avoid creating them. + ansible.builtin.stat: + path: '{{ item.value[4] }}' + register: path_exists + loop: '{{ local_users }}' + when: + - item.value[1]|int >= 1000 + - item.value[1]|int != 65534 + - item.value[4] != "/" + tags: + - accounts_users_home_files_permissions + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure interactive local users have proper permissions on their respective + home directories + ansible.builtin.file: + path: '{{ item.0.value[4] }}' + mode: u-s,g-w-s,o=- + follow: false + recurse: true + loop: '{{ local_users|zip(path_exists.results)|list }}' + when: item.1.stat is defined and item.1.stat.exists + tags: + - accounts_users_home_files_permissions + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + + + + + + + + + + All Interactive User Home Directories Must Be Group-Owned By The Primary Group + Change the group owner of interactive users home directory to the +group found in /etc/passwd. To change the group owner of +interactive users home directory, use the following command: +$ sudo chgrp USER_GROUP /home/USER + + +This rule ensures every home directory related to an interactive user is +group-owned by an interactive user. It also ensures that interactive users +are group-owners of one and only one home directory. + Due to OVAL limitation, this rule can report a false negative in a +specific situation where two interactive users swap the group-ownership +of their respective home directories. + CCI-000366 + SRG-OS-000480-GPOS-00227 + OL09-00-002514 + SV-271783r1092061_rule + If the Group Identifier (GID) of a local interactive users home directory is +not the same as the primary GID of the user, this would allow unauthorized +access to the users files, and users that share the same group may not be +able to access files that they legitimately should. + +awk -F':' '{ if ($3 >= 1000 && $3 != 65534) system("chgrp -f " $4" "$6) }' /etc/passwd + + - name: Get all local users from /etc/passwd + ansible.builtin.getent: + database: passwd + split: ':' + tags: + - DISA-STIG-OL09-00-002514 - file_groupownership_home_directories - low_complexity - low_disruption @@ -37141,6 +43034,7 @@ awk -F':' '{ if ($3 >= 1000 && $3 != 65534) system("chgrp -f " $4" "$ ansible.builtin.set_fact: local_users: '{{ ansible_facts.getent_passwd|dict2items }}' tags: + - DISA-STIG-OL09-00-002514 - file_groupownership_home_directories - low_complexity - low_disruption @@ -37158,6 +43052,7 @@ awk -F':' '{ if ($3 >= 1000 && $3 != 65534) system("chgrp -f " $4" "$ - item.value[1]|int >= 1000 - item.value[1]|int != 65534 tags: + - DISA-STIG-OL09-00-002514 - file_groupownership_home_directories - low_complexity - low_disruption @@ -37173,32 +43068,38 @@ awk -F':' '{ if ($3 >= 1000 && $3 != 65534) system("chgrp -f " $4" "$ loop: '{{ local_users|zip(path_exists.results)|list }}' when: item.1.stat is defined and item.1.stat.exists tags: + - DISA-STIG-OL09-00-002514 - file_groupownership_home_directories - low_complexity - low_disruption - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Ensure All User Initialization Files Have Mode 0740 Or Less Permissive - Set the mode of the user initialization files to 0740 with the + + + + + + + + + + Ensure All User Initialization Files Have Mode 0740 Or Less Permissive + Set the mode of the user initialization files to 0740 with the following command: -$ sudo chmod 0740 /home/USER/.INIT_FILE - CCI-000366 - SRG-OS-000480-GPOS-00227 - Local initialization files are used to configure the user's shell environment +$ sudo chmod 0740 /home/USER/.INIT_FILE + + + CCI-000366 + SRG-OS-000480-GPOS-00227 + R50 + OL09-00-002513 + SV-271782r1092058_rule + Local initialization files are used to configure the user's shell environment upon logon. Malicious modification of these files could compromise accounts upon -logon. - -var_user_initialization_files_regex='' +logon. + +var_user_initialization_files_regex='' readarray -t interactive_users < <(awk -F: '$3>=1000 {print $1}' /etc/passwd) @@ -37218,10 +43119,10 @@ for (( i=0; i<"${#interactive_users[@]}"; i++ )); do done fi done - - - name: XCCDF Value var_user_initialization_files_regex # promote to variable + + - name: XCCDF Value var_user_initialization_files_regex # promote to variable set_fact: - var_user_initialization_files_regex: !!str + var_user_initialization_files_regex: !!str tags: - always @@ -37230,6 +43131,7 @@ done ansible.builtin.getent: database: passwd tags: + - DISA-STIG-OL09-00-002513 - file_permission_user_init_files - low_complexity - low_disruption @@ -37251,6 +43153,7 @@ done - item.value[1] | int >= 1000 register: found_init_files tags: + - DISA-STIG-OL09-00-002513 - file_permission_user_init_files - low_complexity - low_disruption @@ -37266,44 +43169,50 @@ done loop: '{{ q(''ansible.builtin.subelements'', found_init_files.results, ''files'', {''skip_missing'': True}) }}' tags: + - DISA-STIG-OL09-00-002513 - file_permission_user_init_files - low_complexity - low_disruption - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - - All Interactive User Home Directories Must Have mode 0750 Or Less Permissive - Change the mode of interactive users home directories to 0750. To + + + + + + + + + + + All Interactive User Home Directories Must Have mode 0750 Or Less Permissive + Change the mode of interactive users home directories to 0750. To change the mode of interactive users home directory, use the following command: -$ sudo chmod 0750 /home/USER - CCI-000366 - SRG-OS-000480-GPOS-00227 - Excessive permissions on local interactive user home directories may allow -unauthorized access to user files by other users. - -for home_dir in $(awk -F':' '{ if ($3 >= 1000 && $3 != 65534) print $6 }' /etc/passwd); do +$ sudo chmod 0750 /home/USER + + + CCI-000366 + SRG-OS-000480-GPOS-00227 + OL09-00-002515 + SV-271784r1092064_rule + Excessive permissions on local interactive user home directories may allow +unauthorized access to user files by other users. + +for home_dir in $(awk -F':' '{ if ($3 >= 1000 && $3 != 65534 && $6 != "/") print $6 }' /etc/passwd); do # Only update the permissions when necessary. This will avoid changing the inode timestamp when # the permission is already defined as expected, therefore not impacting in possible integrity # check systems that also check inodes timestamps. - find "$home_dir" -maxdepth 0 -perm /7027 -exec chmod u-s,g-w-s,o=- {} \; + find "$home_dir" -maxdepth 0 -perm /7027 \! -type l -exec chmod u-s,g-w-s,o=- {} \; done - - - name: Get all local users from /etc/passwd + + - name: Get all local users from /etc/passwd ansible.builtin.getent: database: passwd split: ':' tags: + - DISA-STIG-OL09-00-002515 - file_permissions_home_directories - low_complexity - low_disruption @@ -37315,6 +43224,7 @@ done ansible.builtin.set_fact: local_users: '{{ ansible_facts.getent_passwd|dict2items }}' tags: + - DISA-STIG-OL09-00-002515 - file_permissions_home_directories - low_complexity - low_disruption @@ -37330,7 +43240,9 @@ done when: - item.value[1]|int >= 1000 - item.value[1]|int != 65534 + - item.value[4] != "/" tags: + - DISA-STIG-OL09-00-002515 - file_permissions_home_directories - low_complexity - low_disruption @@ -37348,89 +43260,92 @@ done loop: '{{ local_users|zip(path_exists.results)|list }}' when: item.1.stat is defined and item.1.stat.exists tags: + - DISA-STIG-OL09-00-002515 - file_permissions_home_directories - low_complexity - low_disruption - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Ensure that User Home Directories are not Group-Writable or World-Readable - For each human user of the system, view the + + + + + + + + + + Ensure that User Home Directories are not Group-Writable or World-Readable + For each human user of the system, view the permissions of the user's home directory: -# ls -ld /home/USER +# ls -ld /home/USER + Ensure that the directory is not group-writable and that it is not world-readable. If necessary, repair the permissions: # chmod g-w /home/USER -# chmod o-rwx /home/USER - This action may involve modifying user home directories. +# chmod o-rwx /home/USER + + + This action may involve modifying user home directories. Notify your user community, and solicit input if appropriate, -before making this type of change. - This rule is deprecated in favor of the file_permissions_home_directories rule. -Please consider replacing this rule in your files as it is not expected to receive -updates as of version 0.1.62. - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - APO01.06 - DSS05.04 - DSS05.07 - DSS06.02 - CCI-000225 - 4.3.3.7.3 - SR 2.1 - SR 5.2 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 - CM-6(a) - AC-6(1) - CM-6(a) - PR.AC-4 - PR.DS-5 - User home directories contain many configuration files which +before making this type of change. + This rule is deprecated in favor of the file_permissions_home_directories rule.Please consider replacing this rule in your files as it is not expected to receive +updates as of version 0.1.62. + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + APO01.06 + DSS05.04 + DSS05.07 + DSS06.02 + CCI-000225 + 4.3.3.7.3 + SR 2.1 + SR 5.2 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 + CM-6(a) + AC-6(1) + CM-6(a) + PR.AC-4 + PR.DS-5 + User home directories contain many configuration files which affect the behavior of a user's account. No user should ever have write permission to another user's home directory. Group shared directories can be configured in sub-directories or elsewhere in the @@ -37438,16 +43353,16 @@ filesystem if they are needed. Typically, user home directories should not be world-readable, as it would disclose file names to other users. If a subset of users need read access to one another's home directories, this can be provided using -groups or ACLs. - -for home_dir in $(awk -F':' '{ if ($3 >= 1000 && $3 != 65534) print $6 }' /etc/passwd); do +groups or ACLs. + +for home_dir in $(awk -F':' '{ if ($3 >= 1000 && $3 != 65534 && $6 != "/") print $6 }' /etc/passwd); do # Only update the permissions when necessary. This will avoid changing the inode timestamp when # the permission is already defined as expected, therefore not impacting in possible integrity # check systems that also check inodes timestamps. - find "$home_dir" -maxdepth 0 -perm /7027 -exec chmod u-s,g-w-s,o=- {} \; + find "$home_dir" -maxdepth 0 -perm /7027 \! -type l -exec chmod u-s,g-w-s,o=- {} \; done - - - name: Get all local users from /etc/passwd + + - name: Get all local users from /etc/passwd ansible.builtin.getent: database: passwd split: ':' @@ -37484,6 +43399,7 @@ done when: - item.value[1]|int >= 1000 - item.value[1]|int != 65534 + - item.value[4] != "/" tags: - NIST-800-53-AC-6(1) - NIST-800-53-CM-6(a) @@ -37514,22 +43430,23 @@ done - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Ensure that No Dangerous Directories Exist in Root's Path - The active path of the root account can be obtained by + + + + + + + + + + Ensure that No Dangerous Directories Exist in Root's Path + The active path of the root account can be obtained by starting a new root shell and running: # echo $PATH This will produce a colon-separated list of directories in the path. - + + Certain path elements could be considered dangerous, as they could lead to root executing unknown or untrusted programs, which could contain malicious @@ -37539,40 +43456,42 @@ untrusted directories, the . character, which represents current directory, should never be in the root path, nor should any directory which can be written to by an unprivileged or semi-privileged (system) user. - + + It is a good practice for administrators to always execute privileged commands by typing the full path to the -command. - - Ensure that Root's Path Does Not Include World or Group-Writable Directories - For each element in root's path, run: -# ls -ld DIR +command. + + Ensure that Root's Path Does Not Include World or Group-Writable Directories + For each element in root's path, run: +# ls -ld DIR + and ensure that write permissions are disabled for group and -other. - 11 - 3 - 9 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - CCI-000366 - 4.3.4.3.2 - 4.3.4.3.3 - SR 7.6 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.14.2.2 - A.14.2.3 - A.14.2.4 - CM-6(a) - CM-6(a) - PR.IP-1 - Such entries increase the risk that root could +other. + 11 + 3 + 9 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + CCI-000366 + 4.3.4.3.2 + 4.3.4.3.3 + SR 7.6 + A.12.1.2 + A.12.5.1 + A.12.6.2 + A.14.2.2 + A.14.2.3 + A.14.2.4 + CM-6(a) + CM-6(a) + PR.IP-1 + Such entries increase the risk that root could execute code provided by unprivileged users, -and potentially malicious code. - - name: Get root paths which are not symbolic links +and potentially malicious code. + - name: Get root paths which are not symbolic links stat: path: '{{ item }}' changed_when: false @@ -37607,17 +43526,17 @@ and potentially malicious code. - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Ensure that Root's Path Does Not Include Relative Paths or Null Directories - Ensure that none of the directories in root's path is equal to a single + + + + + + + + + + Ensure that Root's Path Does Not Include Relative Paths or Null Directories + Ensure that none of the directories in root's path is equal to a single . character, or that it contains any instances that lead to relative path traversal, such as .. or beginning a path without the slash (/) character. @@ -37625,37 +43544,37 @@ Also ensure that there are no "empty" elements in the path, such as in these exa PATH=:/bin PATH=/bin: PATH=/bin::/sbin -These empty elements have the same effect as a single . character. - 11 - 3 - 9 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - CCI-000366 - 4.3.4.3.2 - 4.3.4.3.3 - SR 7.6 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.14.2.2 - A.14.2.3 - A.14.2.4 - CM-6(a) - CM-6(a) - PR.IP-1 - Including these entries increases the risk that root could -execute code from an untrusted location. - - - - - - - Ensure that Users Have Sensible Umask Values - The umask setting controls the default permissions +These empty elements have the same effect as a single . character. + 11 + 3 + 9 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + CCI-000366 + 4.3.4.3.2 + 4.3.4.3.3 + SR 7.6 + A.12.1.2 + A.12.5.1 + A.12.6.2 + A.14.2.2 + A.14.2.3 + A.14.2.4 + CM-6(a) + CM-6(a) + PR.IP-1 + Including these entries increases the risk that root could +execute code from an untrusted location. + + + + + + + Ensure that Users Have Sensible Umask Values + The umask setting controls the default permissions for the creation of new files. With a default umask setting of 077, files and directories created by users will not be readable by any other user on the @@ -37669,84 +43588,111 @@ user's username and whose only member is the user), then it may even be safe for users to select a umask of 007, making it very easy to intentionally share files with groups of which the user is a member. - - - Sensible umask - Enter default user umask - 007 - 022 - 027 - 077 - 027 - - - Ensure the Default Bash Umask is Set Correctly - To ensure the default umask for users of the Bash shell is set properly, + + + + + Sensible umask + Enter default user umask + 007 + 022 + 027 + 077 + 027 + + + Ensure the Default Bash Umask is Set Correctly + To ensure the default umask for users of the Bash shell is set properly, add or correct the umask setting in /etc/bashrc to read as follows: -umask - BP28(R35) - 18 - APO13.01 - BAI03.01 - BAI03.02 - BAI03.03 - CCI-000366 - 4.3.4.3.3 - A.14.1.1 - A.14.2.1 - A.14.2.5 - A.6.1.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 - AC-6(1) - CM-6(a) - PR.IP-2 - 8.6.1 - SRG-OS-000480-GPOS-00228 - SRG-OS-000480-GPOS-00227 - The umask value influences the permissions assigned to files when they are created. +umask + + + 18 + APO13.01 + BAI03.01 + BAI03.02 + BAI03.03 + CCI-000366 + 4.3.4.3.3 + A.14.1.1 + A.14.2.1 + A.14.2.5 + A.6.1.5 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 + AC-6(1) + CM-6(a) + PR.IP-2 + SRG-OS-000480-GPOS-00228 + SRG-OS-000480-GPOS-00227 + R36 + A.6.SEC-OL5 + OL09-00-002301 + SV-271693r1091791_rule + The umask value influences the permissions assigned to files when they are created. A misconfigured umask value could result in files with excessive permissions that can be read or -written to by unauthorized users. - -var_accounts_user_umask='' +written to by unauthorized users. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q bash; then + +var_accounts_user_umask='' -grep -q "^\s*umask" /etc/bashrc && \ - sed -i -E -e "s/^(\s*umask).*/\1 $var_accounts_user_umask/g" /etc/bashrc +grep -q "^[^#]*\bumask" /etc/bashrc && \ + sed -i -E -e "s/^([^#]*\bumask)[[:space:]]+[[:digit:]]+/\1 $var_accounts_user_umask/g" /etc/bashrc if ! [ $? -eq 0 ]; then echo "umask $var_accounts_user_umask" >> /etc/bashrc fi - - - name: XCCDF Value var_accounts_user_umask # promote to variable + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002301 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - accounts_umask_etc_bashrc + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy +- name: XCCDF Value var_accounts_user_umask # promote to variable set_fact: - var_accounts_user_umask: !!str + var_accounts_user_umask: !!str tags: - always - name: Check if umask in /etc/bashrc is already set ansible.builtin.lineinfile: path: /etc/bashrc - regexp: ^(\s*)umask\s+.* + regexp: ^[^#]*\bumask\s+\d+$ state: absent check_mode: true changed_when: false register: umask_replace + when: '"bash" in ansible_facts.packages' tags: + - DISA-STIG-OL09-00-002301 - NIST-800-53-AC-6(1) - NIST-800-53-CM-6(a) - - PCI-DSSv4-8.6.1 - accounts_umask_etc_bashrc - low_complexity - low_disruption @@ -37757,13 +43703,15 @@ fi - name: Replace user umask in /etc/bashrc ansible.builtin.replace: path: /etc/bashrc - regexp: ^(\s*)umask(\s+).* - replace: \g<1>umask\g<2>{{ var_accounts_user_umask }} - when: umask_replace.found > 0 + regexp: ^([^#]*\b)umask\s+\d+$ + replace: \g<1>umask {{ var_accounts_user_umask }} + when: + - '"bash" in ansible_facts.packages' + - umask_replace.found > 0 tags: + - DISA-STIG-OL09-00-002301 - NIST-800-53-AC-6(1) - NIST-800-53-CM-6(a) - - PCI-DSSv4-8.6.1 - accounts_umask_etc_bashrc - low_complexity - low_disruption @@ -37776,61 +43724,67 @@ fi create: true path: /etc/bashrc line: umask {{ var_accounts_user_umask }} - when: umask_replace.found == 0 + when: + - '"bash" in ansible_facts.packages' + - umask_replace.found == 0 tags: + - DISA-STIG-OL09-00-002301 - NIST-800-53-AC-6(1) - NIST-800-53-CM-6(a) - - PCI-DSSv4-8.6.1 - accounts_umask_etc_bashrc - low_complexity - low_disruption - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - - Ensure the Default C Shell Umask is Set Correctly - To ensure the default umask for users of the C shell is set properly, + + + + + + + + + + + Ensure the Default C Shell Umask is Set Correctly + To ensure the default umask for users of the C shell is set properly, add or correct the umask setting in /etc/csh.cshrc to read as follows: -umask - 18 - APO13.01 - BAI03.01 - BAI03.02 - BAI03.03 - CCI-000366 - 4.3.4.3.3 - A.14.1.1 - A.14.2.1 - A.14.2.5 - A.6.1.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 - AC-6(1) - CM-6(a) - PR.IP-2 - SRG-OS-000480-GPOS-00228 - SRG-OS-000480-GPOS-00227 - The umask value influences the permissions assigned to files when they are created. +umask + + + 18 + APO13.01 + BAI03.01 + BAI03.02 + BAI03.03 + CCI-000366 + 4.3.4.3.3 + A.14.1.1 + A.14.2.1 + A.14.2.5 + A.6.1.5 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 + AC-6(1) + CM-6(a) + PR.IP-2 + SRG-OS-000480-GPOS-00228 + SRG-OS-000480-GPOS-00227 + OL09-00-002302 + SV-271694r1091794_rule + The umask value influences the permissions assigned to files when they are created. A misconfigured umask value could result in files with excessive permissions that can be read or -written to by unauthorized users. - -var_accounts_user_umask='' +written to by unauthorized users. + +var_accounts_user_umask='' grep -q "^\s*umask" /etc/csh.cshrc && \ @@ -37838,10 +43792,10 @@ grep -q "^\s*umask" /etc/csh.cshrc && \ if ! [ $? -eq 0 ]; then echo "umask $var_accounts_user_umask" >> /etc/csh.cshrc fi - - - name: XCCDF Value var_accounts_user_umask # promote to variable + + - name: XCCDF Value var_accounts_user_umask # promote to variable set_fact: - var_accounts_user_umask: !!str + var_accounts_user_umask: !!str tags: - always @@ -37854,6 +43808,7 @@ fi changed_when: false register: umask_replace tags: + - DISA-STIG-OL09-00-002302 - NIST-800-53-AC-6(1) - NIST-800-53-CM-6(a) - accounts_umask_etc_csh_cshrc @@ -37870,6 +43825,7 @@ fi replace: \g<1>umask\g<2>{{ var_accounts_user_umask }} when: umask_replace.found > 0 tags: + - DISA-STIG-OL09-00-002302 - NIST-800-53-AC-6(1) - NIST-800-53-CM-6(a) - accounts_umask_etc_csh_cshrc @@ -37886,6 +43842,7 @@ fi line: umask {{ var_accounts_user_umask }} when: umask_replace.found == 0 tags: + - DISA-STIG-OL09-00-002302 - NIST-800-53-AC-6(1) - NIST-800-53-CM-6(a) - accounts_umask_etc_csh_cshrc @@ -37894,70 +43851,74 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - - Ensure the Default Umask is Set Correctly in login.defs - To ensure the default umask controlled by /etc/login.defs is set properly, + + + + + + + + + + + Ensure the Default Umask is Set Correctly in login.defs + To ensure the default umask controlled by /etc/login.defs is set properly, add or correct the UMASK setting in /etc/login.defs to read as follows: -UMASK - BP28(R35) - 11 - 18 - 3 - 9 - APO13.01 - BAI03.01 - BAI03.02 - BAI03.03 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - CCI-000366 - 4.3.4.3.2 - 4.3.4.3.3 - SR 7.6 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.14.1.1 - A.14.2.1 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.14.2.5 - A.6.1.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 - AC-6(1) - CM-6(a) - PR.IP-1 - PR.IP-2 - 8.6.1 - SRG-OS-000480-GPOS-00228 - The umask value influences the permissions assigned to files when they are created. +UMASK + + + 11 + 18 + 3 + 9 + APO13.01 + BAI03.01 + BAI03.02 + BAI03.03 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + CCI-000366 + 4.3.4.3.2 + 4.3.4.3.3 + SR 7.6 + A.12.1.2 + A.12.5.1 + A.12.6.2 + A.14.1.1 + A.14.2.1 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.14.2.5 + A.6.1.5 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 + AC-6(1) + CM-6(a) + PR.IP-1 + PR.IP-2 + SRG-OS-000480-GPOS-00228 + R36 + A.6.SEC-OL5 + OL09-00-002304 + SV-271696r1091800_rule + The umask value influences the permissions assigned to files when they are created. A misconfigured umask value could result in files with excessive permissions that can be read and -written to by unauthorized users. - - # Remediation is applicable only in certain platforms +written to by unauthorized users. + + # Remediation is applicable only in certain platforms if rpm --quiet -q shadow-utils; then -var_accounts_user_umask='' +var_accounts_user_umask='' # Strip any search characters in the key arg so that the key can be replaced without @@ -37983,14 +43944,14 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-002304 - NIST-800-53-AC-6(1) - NIST-800-53-CM-6(a) - - PCI-DSSv4-8.6.1 - accounts_umask_etc_login_defs - low_complexity - low_disruption @@ -37999,7 +43960,7 @@ fi - restrict_strategy - name: XCCDF Value var_accounts_user_umask # promote to variable set_fact: - var_accounts_user_umask: !!str + var_accounts_user_umask: !!str tags: - always @@ -38013,9 +43974,9 @@ fi register: result_umask_is_set when: '"shadow-utils" in ansible_facts.packages' tags: + - DISA-STIG-OL09-00-002304 - NIST-800-53-AC-6(1) - NIST-800-53-CM-6(a) - - PCI-DSSv4-8.6.1 - accounts_umask_etc_login_defs - low_complexity - low_disruption @@ -38032,9 +43993,9 @@ fi - '"shadow-utils" in ansible_facts.packages' - result_umask_is_set.found > 0 tags: + - DISA-STIG-OL09-00-002304 - NIST-800-53-AC-6(1) - NIST-800-53-CM-6(a) - - PCI-DSSv4-8.6.1 - accounts_umask_etc_login_defs - low_complexity - low_disruption @@ -38051,65 +44012,68 @@ fi - '"shadow-utils" in ansible_facts.packages' - result_umask_is_set.found == 0 tags: + - DISA-STIG-OL09-00-002304 - NIST-800-53-AC-6(1) - NIST-800-53-CM-6(a) - - PCI-DSSv4-8.6.1 - accounts_umask_etc_login_defs - low_complexity - low_disruption - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - - Ensure the Default Umask is Set Correctly in /etc/profile - To ensure the default umask controlled by /etc/profile is set properly, + + + + + + + + + + + Ensure the Default Umask is Set Correctly in /etc/profile + To ensure the default umask controlled by /etc/profile is set properly, add or correct the umask setting in /etc/profile to read as follows: -umask +umask + Note that /etc/profile also reads scrips within /etc/profile.d directory. These scripts are also valid files to set umask value. Therefore, they should also be -considered during the check and properly remediated, if necessary. - BP28(R35) - 18 - APO13.01 - BAI03.01 - BAI03.02 - BAI03.03 - CCI-000366 - 4.3.4.3.3 - A.14.1.1 - A.14.2.1 - A.14.2.5 - A.6.1.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 - AC-6(1) - CM-6(a) - PR.IP-2 - 8.6.1 - SRG-OS-000480-GPOS-00228 - SRG-OS-000480-GPOS-00227 - The umask value influences the permissions assigned to files when they are created. +considered during the check and properly remediated, if necessary. + 18 + APO13.01 + BAI03.01 + BAI03.02 + BAI03.03 + CCI-000366 + 4.3.4.3.3 + A.14.1.1 + A.14.2.1 + A.14.2.5 + A.6.1.5 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 + AC-6(1) + CM-6(a) + PR.IP-2 + SRG-OS-000480-GPOS-00228 + SRG-OS-000480-GPOS-00227 + R36 + A.6.SEC-OL5 + OL09-00-002303 + SV-271695r1091797_rule + The umask value influences the permissions assigned to files when they are created. A misconfigured umask value could result in files with excessive permissions that can be read or -written to by unauthorized users. - -var_accounts_user_umask='' +written to by unauthorized users. + +var_accounts_user_umask='' readarray -t profile_files < <(find /etc/profile.d/ -type f -name '*.sh' -or -name 'sh.local') @@ -38121,10 +44085,10 @@ done if ! grep -qrE '^[^#]*umask' /etc/profile*; then echo "umask $var_accounts_user_umask" >> /etc/profile fi - - - name: XCCDF Value var_accounts_user_umask # promote to variable + + - name: XCCDF Value var_accounts_user_umask # promote to variable set_fact: - var_accounts_user_umask: !!str + var_accounts_user_umask: !!str tags: - always @@ -38139,9 +44103,9 @@ fi contains: ^[\s]*umask\s+\d+ register: result_profile_d_files tags: + - DISA-STIG-OL09-00-002303 - NIST-800-53-AC-6(1) - NIST-800-53-CM-6(a) - - PCI-DSSv4-8.6.1 - accounts_umask_etc_profile - low_complexity - low_disruption @@ -38159,9 +44123,9 @@ fi register: result_umask_replaced_profile_d when: result_profile_d_files.matched tags: + - DISA-STIG-OL09-00-002303 - NIST-800-53-AC-6(1) - NIST-800-53-CM-6(a) - - PCI-DSSv4-8.6.1 - accounts_umask_etc_profile - low_complexity - low_disruption @@ -38178,9 +44142,9 @@ fi line: umask {{ var_accounts_user_umask }} when: not result_profile_d_files.matched tags: + - DISA-STIG-OL09-00-002303 - NIST-800-53-AC-6(1) - NIST-800-53-CM-6(a) - - PCI-DSSv4-8.6.1 - accounts_umask_etc_profile - low_complexity - low_disruption @@ -38196,38 +44160,39 @@ fi replace: \1umask {{ var_accounts_user_umask }} register: result_umask_replaced_profile tags: + - DISA-STIG-OL09-00-002303 - NIST-800-53-AC-6(1) - NIST-800-53-CM-6(a) - - PCI-DSSv4-8.6.1 - accounts_umask_etc_profile - low_complexity - low_disruption - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - - Ensure the Default Umask is Set Correctly For Interactive Users - Remove the UMASK environment variable from all interactive users initialization files. - CCI-000366 - CCI-001814 - SRG-OS-000480-GPOS-00227 - SRG-OS-000480-GPOS-00228 - The umask controls the default access mode assigned to newly created files. A + + + + + + + + + + + Ensure the Default Umask is Set Correctly For Interactive Users + Remove the UMASK environment variable from all interactive users initialization files. + CCI-000366 + SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00228 + OL09-00-003060 + SV-271848r1092256_rule + The umask controls the default access mode assigned to newly created files. A umask of 077 limits new files to mode 700 or less permissive. Although umask can be represented as a four-digit number, the first digit representing special access modes is typically ignored or required to be 0. This requirement applies to the globally configured system defaults and the local interactive -user defaults for each account on the system. - +user defaults for each account on the system. + while IFS= read -r dir; do while IFS= read -r -d '' file; do if [ "$(basename $file)" != ".bash_history" ]; then @@ -38235,8 +44200,8 @@ while IFS= read -r dir; do fi done < <(find $dir -maxdepth 1 -type f -name ".*" -print0) done < <(awk -F':' '{ if ($3 >= 1000 && $3 != 65534) print $6}' /etc/passwd) - - - name: Ensure interactive local users are the owners of their respective initialization + + - name: Ensure interactive local users are the owners of their respective initialization files ansible.builtin.shell: cmd: |- @@ -38248,33 +44213,73769 @@ done < <(awk -F':' '{ if ($3 >= 1000 && $3 != 65534) print $6 done done tags: + - DISA-STIG-OL09-00-003060 - accounts_umask_interactive_users - low_complexity - low_disruption - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - - - - System Accounting with auditd - The audit service provides substantial capabilities + + + + + + + + + + + + + GRUB2 bootloader configuration + During the boot process, the boot loader is +responsible for starting the execution of the kernel and passing +options to it. The boot loader allows for the selection of +different kernels - possibly on different partitions or media. +The default Oracle Linux 9 boot loader for x86 systems is called GRUB2. +Options it can pass to the kernel include single-user mode, which +provides root access without any authentication, and the ability to +disable SELinux. To prevent local users from modifying the boot +parameters and endangering security, protect the boot loader configuration +with a password and ensure its configuration file's permissions +are set properly. + + + L1TF vulnerability mitigation + Defines the L1TF vulneratility mitigations to employ. + flush + full + full,force + flush + flush,nosmt + flush,nowarn + + + MDS vulnerability mitigation + Defines the MDS vulneratility mitigation to employ. + full + full + full,nosmt + + + Confidence level on Hardware Random Number Generator + Defines the level of trust on the hardware random number generators available in the +system and the percentage of entropy to credit. + 500 + 500 + 512 + 1000 + + + Spec Store Bypass Mitigation + This controls how the Speculative Store Bypass (SSB) vulnerability is mitigated. + prctl + on + auto + prctl + seccomp + + + Disable Recovery Booting + Oracle Linux 9 systems support an "recovery boot" option that can be used +to prevent services from being started. The GRUB_DISABLE_RECOVERY +configuration option in /etc/default/grub should be set to +true to disable the generation of recovery mode menu entries. It is +also required to change the runtime configuration, run: +$ sudo grubby --update-kernel=ALL + + FIA_UAU.1 + Using recovery boot, the console user could disable auditing, firewalls, +or other services, weakening system security. + # Remediation is applicable only in certain platforms +if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ); then + +if grep -q '^GRUB_DISABLE_RECOVERY=.*' '/etc/default/grub' ; then + sed -i 's/GRUB_DISABLE_RECOVERY=.*/GRUB_DISABLE_RECOVERY=true/' "/etc/default/grub" +else + echo "GRUB_DISABLE_RECOVERY=true" >> '/etc/default/grub' +fi + +grubby --update-kernel=ALL + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - grub2_disable_recovery + - low_complexity + - low_disruption + - medium_severity + - reboot_required + - restrict_strategy + +- name: Verify GRUB_DISABLE_RECOVERY=true + lineinfile: + path: /etc/default/grub + regexp: ^GRUB_DISABLE_RECOVERY=.* + line: GRUB_DISABLE_RECOVERY=true + state: present + when: ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + tags: + - grub2_disable_recovery + - low_complexity + - low_disruption + - medium_severity + - reboot_required + - restrict_strategy + +- name: Update grub defaults and the bootloader menu + command: /sbin/grubby --update-kernel=ALL + when: ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + tags: + - grub2_disable_recovery + - low_complexity + - low_disruption + - medium_severity + - reboot_required + - restrict_strategy + + + + + + + + + + IOMMU configuration directive + On x86 architecture supporting VT-d, the IOMMU manages the access control policy between the hardware devices and some + of the system critical units such as the memory. +To ensure that iommu=force is added as a kernel command line +argument to newly installed kernels, add iommu=force to the +default Grub2 command line for Linux operating systems. Modify the line within +/etc/default/grub as shown below: +GRUB_CMDLINE_LINUX="... iommu=force ..." +Run the following command to update command line for already installed kernels:# grubby --update-kernel=ALL --args="iommu=force" + + Depending on the hardware, devices and operating system used, enabling IOMMU can cause hardware instabilities. Proper function and stability should be assessed before applying remediation to production systems. + R7 + On x86 architectures, activating the I/OMMU prevents the system from arbitrary accesses potentially made by + hardware devices. + # Remediation is applicable only in certain platforms +if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ); then + +expected_value="force" + + +if [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; then + KARGS_DIR="/usr/lib/bootc/kargs.d/" + if grep -q -E "iommu" "$KARGS_DIR/*.toml" ; then + sed -i -E "s/^(\s*kargs\s*=\s*\[.*)\"iommu=[^\"]*\"(.*]\s*)/\1\"iommu=$expected_value\"\2/" "$KARGS_DIR/*.toml" + else + echo "kargs = [\"iommu=$expected_value\"]" >> "$KARGS_DIR/10-iommu.toml" + fi +else + + grubby --update-kernel=ALL --args=iommu=force + +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - grub2_enable_iommu_force + - low_disruption + - medium_complexity + - reboot_required + - restrict_strategy + - unknown_severity + +- name: Update grub defaults and the bootloader menu + command: /sbin/grubby --update-kernel=ALL --args="iommu=force" + when: ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + tags: + - grub2_enable_iommu_force + - low_disruption + - medium_complexity + - reboot_required + - restrict_strategy + - unknown_severity + + [customizations.kernel] +append = "iommu=force" + + + + + + + + + + Configure kernel to zero out memory before allocation + To configure the kernel to zero out memory before allocating it, add the +init_on_alloc=1 argument to the default GRUB 2 command line. +To ensure that init_on_alloc=1 is added as a kernel command line +argument to newly installed kernels, add init_on_alloc=1 to the +default Grub2 command line for Linux operating systems. Modify the line within +/etc/default/grub as shown below: +GRUB_CMDLINE_LINUX="... init_on_alloc=1 ..." +Run the following command to update command line for already installed kernels:# grubby --update-kernel=ALL --args="init_on_alloc=1" + + AVA_VAN.1 + When the kernel configuration option init_on_alloc is enabled, +all page allocator and slab allocator memory will be zeroed when allocated, +eliminating many kinds of "uninitialized heap memory" flaws, effectively +preventing data leaks. + # Remediation is applicable only in certain platforms +if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ); then + +expected_value="1" + + +if [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; then + KARGS_DIR="/usr/lib/bootc/kargs.d/" + if grep -q -E "init_on_alloc" "$KARGS_DIR/*.toml" ; then + sed -i -E "s/^(\s*kargs\s*=\s*\[.*)\"init_on_alloc=[^\"]*\"(.*]\s*)/\1\"init_on_alloc=$expected_value\"\2/" "$KARGS_DIR/*.toml" + else + echo "kargs = [\"init_on_alloc=$expected_value\"]" >> "$KARGS_DIR/10-init_on_alloc.toml" + fi +else + + grubby --update-kernel=ALL --args=init_on_alloc=1 + +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - grub2_init_on_alloc_argument + - low_disruption + - medium_complexity + - medium_severity + - reboot_required + - restrict_strategy + +- name: Update grub defaults and the bootloader menu + command: /sbin/grubby --update-kernel=ALL --args="init_on_alloc=1" + when: ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + tags: + - grub2_init_on_alloc_argument + - low_disruption + - medium_complexity + - medium_severity + - reboot_required + - restrict_strategy + + [customizations.kernel] +append = "init_on_alloc=1" + + + + + + + + + + Configure L1 Terminal Fault mitigations + L1 Terminal Fault (L1TF) is a hardware vulnerability which allows unprivileged +speculative access to data which is available in the Level 1 Data Cache when +the page table entry isn't present. + +Select the appropriate mitigation by adding the argument +l1tf= + to the default +GRUB 2 command line for the Linux operating system. +To ensure that l1tf= + is added as a kernel command line +argument to newly installed kernels, add l1tf= + to the +default Grub2 command line for Linux operating systems. Modify the line within +/etc/default/grub as shown below: +GRUB_CMDLINE_LINUX="... l1tf= ..." +Run the following command to update command line for already installed kernels:# grubby --update-kernel=ALL --args="l1tf=" + +Since Linux Kernel 4.19 you can check the L1TF vulnerability state with the +following command: +cat /sys/devices/system/cpu/vulnerabilities/l1tf + + Enabling L1TF mitigations may impact performance of the system. + R8 + The L1TF vulnerability allows an attacker to bypass memory access security controls imposed +by the system or hypervisor. The L1TF vulnerability allows read access to any physical memory +location that is cached in the L1 Data Cache. + # Remediation is applicable only in certain platforms +if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ); then + +var_l1tf_options='' + +expected_value="$var_l1tf_options" + + +if [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; then + KARGS_DIR="/usr/lib/bootc/kargs.d/" + if grep -q -E "l1tf" "$KARGS_DIR/*.toml" ; then + sed -i -E "s/^(\s*kargs\s*=\s*\[.*)\"l1tf=[^\"]*\"(.*]\s*)/\1\"l1tf=$expected_value\"\2/" "$KARGS_DIR/*.toml" + else + echo "kargs = [\"l1tf=$expected_value\"]" >> "$KARGS_DIR/10-l1tf.toml" + fi +else + + grubby --update-kernel=ALL --args=l1tf=$var_l1tf_options + +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - grub2_l1tf_argument + - high_severity + - low_disruption + - medium_complexity + - reboot_required + - restrict_strategy +- name: XCCDF Value var_l1tf_options # promote to variable + set_fact: + var_l1tf_options: !!str + tags: + - always + +- name: Update grub defaults and the bootloader menu + command: /sbin/grubby --update-kernel=ALL --args="l1tf={{ var_l1tf_options }}" + when: ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + tags: + - grub2_l1tf_argument + - high_severity + - low_disruption + - medium_complexity + - reboot_required + - restrict_strategy + + [customizations.kernel] +append = "l1tf=" + + + + + + + + + + + Force kernel panic on uncorrected MCEs + A Machine Check Exception is an error generated by the CPU itdetects an error +in itself, memory or I/O devices. +These errors may be corrected and generate a check log entry, if an error +cannot be corrected the kernel may panic or SIGBUS. + +To force the kernel to panic on any uncorrected error reported by Machine Check +set the MCE tolerance to zero by adding mce=0 +to the default GRUB 2 command line for the Linux operating system. +To ensure that mce=0 is added as a kernel command line +argument to newly installed kernels, add mce=0 to the +default Grub2 command line for Linux operating systems. Modify the line within +/etc/default/grub as shown below: +GRUB_CMDLINE_LINUX="... mce=0 ..." +Run the following command to update command line for already installed kernels:# grubby --update-kernel=ALL --args="mce=0" + + R8 + Allowing uncorrected errors to result on a SIGBUS may allow an attacker to continue +trying to exploit a vulnerability such as Rowhammer. + # Remediation is applicable only in certain platforms +if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ); then + +expected_value="0" + + +if [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; then + KARGS_DIR="/usr/lib/bootc/kargs.d/" + if grep -q -E "mce" "$KARGS_DIR/*.toml" ; then + sed -i -E "s/^(\s*kargs\s*=\s*\[.*)\"mce=[^\"]*\"(.*]\s*)/\1\"mce=$expected_value\"\2/" "$KARGS_DIR/*.toml" + else + echo "kargs = [\"mce=$expected_value\"]" >> "$KARGS_DIR/10-mce.toml" + fi +else + + grubby --update-kernel=ALL --args=mce=0 + +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - grub2_mce_argument + - low_disruption + - medium_complexity + - medium_severity + - reboot_required + - restrict_strategy + +- name: Update grub defaults and the bootloader menu + command: /sbin/grubby --update-kernel=ALL --args="mce=0" + when: ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + tags: + - grub2_mce_argument + - low_disruption + - medium_complexity + - medium_severity + - reboot_required + - restrict_strategy + + [customizations.kernel] +append = "mce=0" + + + + + + + + + + Configure Microarchitectural Data Sampling mitigation + Microarchitectural Data Sampling (MDS) is a hardware vulnerability which allows unprivileged +speculative access to data which is available in various CPU internal buffers. + +When performing store, load, L1 refill operations, processors write data into temporary +microarchitectural structures (buffers), and the data in the buffer can be forwarded to load +operations as an optimization. + +Under certain conditions, data unrelated to the load operations can be speculatively +forwarded from the buffers to a disclosure gadget which allows in turn to infer the value +via a cache side channel attack. + +Select the appropriate mitigation by adding the argument +mds= + to the default +GRUB 2 command line for the Linux operating system. +To ensure that mds= + is added as a kernel command line +argument to newly installed kernels, add mds= + to the +default Grub2 command line for Linux operating systems. Modify the line within +/etc/default/grub as shown below: +GRUB_CMDLINE_LINUX="... mds= ..." +Run the following command to update command line for already installed kernels:# grubby --update-kernel=ALL --args="mds=" + +Not all processors are affected by all variants of MDS, but the mitigation mechanism is +identical for all of them. + +Since Linux Kernel 5.2 you can check whether the system is vulnerable or mitigated with the +following command: +cat /sys/devices/system/cpu/vulnerabilities/mds + + Enabling MDS mitigations will impact performance of the system, mainly by workloads with +high rates of user-kernel-user space transitions. For example, system calls, NMIs and interrupts. + R8 + The MDS vulnerability allows an attacker to sample data from internal CPU buffers. + # Remediation is applicable only in certain platforms +if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ); then + +var_mds_options='' + +expected_value="$var_mds_options" + + +if [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; then + KARGS_DIR="/usr/lib/bootc/kargs.d/" + if grep -q -E "mds" "$KARGS_DIR/*.toml" ; then + sed -i -E "s/^(\s*kargs\s*=\s*\[.*)\"mds=[^\"]*\"(.*]\s*)/\1\"mds=$expected_value\"\2/" "$KARGS_DIR/*.toml" + else + echo "kargs = [\"mds=$expected_value\"]" >> "$KARGS_DIR/10-mds.toml" + fi +else + + grubby --update-kernel=ALL --args=mds=$var_mds_options + +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - grub2_mds_argument + - low_disruption + - medium_complexity + - medium_severity + - reboot_required + - restrict_strategy +- name: XCCDF Value var_mds_options # promote to variable + set_fact: + var_mds_options: !!str + tags: + - always + +- name: Update grub defaults and the bootloader menu + command: /sbin/grubby --update-kernel=ALL --args="mds={{ var_mds_options }}" + when: ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + tags: + - grub2_mds_argument + - low_disruption + - medium_complexity + - medium_severity + - reboot_required + - restrict_strategy + + [customizations.kernel] +append = "mds=" + + + + + + + + + + + Ensure SMAP is not disabled during boot + The SMAP is used to prevent the supervisor mode from unintentionally reading/writing into +memory pages in the user space, it is enabled by default since Linux kernel 3.7. +But it could be disabled through kernel boot parameters. + +Ensure that Supervisor Mode Access Prevention (SMAP) is not disabled by +the nosmap boot paramenter option. + +Check that the line GRUB_CMDLINE_LINUX="..." within /etc/default/grub +doesn't contain the argument nosmap. +Run the following command to update command line for already installed kernels: +# grubby --update-kernel=ALL --remove-args="nosmap" + + R1 + Disabling SMAP can facilitate exploitation of vulnerabilities caused by unintended access and +manipulation of data in the user space. + # Remediation is applicable only in certain platforms +if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ); then + +if [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; then + sed -i -E "/kargs\s*=\s*\[\s*\"nosmap=[^\"]*\"\s*]/{:a;N;/^\n$/ba;N;/match-architectures.*/d;}" "$KARGS_DIR/*.toml" + sed -i -E -e "s/^(\s*kargs\s*=\s*\[.*)\"nosmap=[^\"]*\"[,[:space:]]*(.*]\s*)/\1\2/" -e "s/^(\s*kargs.*),\s*\]$/\1\]/" "$KARGS_DIR/*.toml" +else + +grubby --update-kernel=ALL --remove-args=nosmap + +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - grub2_nosmap_argument_absent + - low_disruption + - medium_complexity + - medium_severity + - reboot_required + - restrict_strategy + +- name: Update grub defaults and the bootloader menu + command: /sbin/grubby --update-kernel=ALL --remove-args="nosmap" + when: ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + tags: + - grub2_nosmap_argument_absent + - low_disruption + - medium_complexity + - medium_severity + - reboot_required + - restrict_strategy + + + + + + + + + + Ensure SMEP is not disabled during boot + The SMEP is used to prevent the supervisor mode from executing user space code, +it is enabled by default since Linux kernel 3.0. But it could be disabled through +kernel boot parameters. + +Ensure that Supervisor Mode Execution Prevention (SMEP) is not disabled by +the nosmep boot paramenter option. + +Check that the line GRUB_CMDLINE_LINUX="..." within /etc/default/grub +doesn't contain the argument nosmep. +Run the following command to update command line for already installed kernels: +# grubby --update-kernel=ALL --remove-args="nosmep" + + R1 + Disabling SMEP can facilitate exploitation of certain vulnerabilities because it allows +the kernel to unintentionally execute code in less privileged memory space. + # Remediation is applicable only in certain platforms +if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ); then + +if [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; then + sed -i -E "/kargs\s*=\s*\[\s*\"nosmep=[^\"]*\"\s*]/{:a;N;/^\n$/ba;N;/match-architectures.*/d;}" "$KARGS_DIR/*.toml" + sed -i -E -e "s/^(\s*kargs\s*=\s*\[.*)\"nosmep=[^\"]*\"[,[:space:]]*(.*]\s*)/\1\2/" -e "s/^(\s*kargs.*),\s*\]$/\1\]/" "$KARGS_DIR/*.toml" +else + +grubby --update-kernel=ALL --remove-args=nosmep + +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - grub2_nosmep_argument_absent + - low_disruption + - medium_complexity + - medium_severity + - reboot_required + - restrict_strategy + +- name: Update grub defaults and the bootloader menu + command: /sbin/grubby --update-kernel=ALL --remove-args="nosmep" + when: ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + tags: + - grub2_nosmep_argument_absent + - low_disruption + - medium_complexity + - medium_severity + - reboot_required + - restrict_strategy + + + + + + + + + + Enable randomization of the page allocator + To enable randomization of the page allocator in the kernel, add the +page_alloc.shuffle=1 argument to the default GRUB 2 command line. +To ensure that page_alloc.shuffle=1 is added as a kernel command line +argument to newly installed kernels, add page_alloc.shuffle=1 to the +default Grub2 command line for Linux operating systems. Modify the line within +/etc/default/grub as shown below: +GRUB_CMDLINE_LINUX="... page_alloc.shuffle=1 ..." +Run the following command to update command line for already installed kernels:# grubby --update-kernel=ALL --args="page_alloc.shuffle=1" + + AVA_VAN.1 + R8 + The CONFIG_SHUFFLE_PAGE_ALLOCATOR config option is primarily +focused on improving the average utilization of a direct-mapped +memory-side-cache. Aside of this performance effect, it also reduces +predictability of page allocations in situations when the bad actor can +crash the system and somehow leverage knowledge of (page) allocation order +right after a fresh reboot, or can control the timing between a +hot-pluggable memory node (as in NUMA node) and applications allocating +memory ouf of that node. The page_alloc.shuffle=1 kernel command +line parameter then forces this functionality irrespectively of memory cache +architecture. + # Remediation is applicable only in certain platforms +if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ); then + +expected_value="1" + + +if [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; then + KARGS_DIR="/usr/lib/bootc/kargs.d/" + if grep -q -E "page_alloc.shuffle" "$KARGS_DIR/*.toml" ; then + sed -i -E "s/^(\s*kargs\s*=\s*\[.*)\"page_alloc.shuffle=[^\"]*\"(.*]\s*)/\1\"page_alloc.shuffle=$expected_value\"\2/" "$KARGS_DIR/*.toml" + else + echo "kargs = [\"page_alloc.shuffle=$expected_value\"]" >> "$KARGS_DIR/10-page_alloc_shuffle.toml" + fi +else + + grubby --update-kernel=ALL --args=page_alloc.shuffle=1 + +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - grub2_page_alloc_shuffle_argument + - low_disruption + - medium_complexity + - medium_severity + - reboot_required + - restrict_strategy + +- name: Update grub defaults and the bootloader menu + command: /sbin/grubby --update-kernel=ALL --args="page_alloc.shuffle=1" + when: ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + tags: + - grub2_page_alloc_shuffle_argument + - low_disruption + - medium_complexity + - medium_severity + - reboot_required + - restrict_strategy + + [customizations.kernel] +append = "page_alloc.shuffle=1" + + + + + + + + + + Enable Kernel Page-Table Isolation (KPTI) + To enable Kernel page-table isolation, +add the argument pti=on to the default +GRUB 2 command line for the Linux operating system. +To ensure that pti=on is added as a kernel command line +argument to newly installed kernels, add pti=on to the +default Grub2 command line for Linux operating systems. Modify the line within +/etc/default/grub as shown below: +GRUB_CMDLINE_LINUX="... pti=on ..." +Run the following command to update command line for already installed kernels:# grubby --update-kernel=ALL --args="pti=on" + + CCI-002824 + CCI-000381 + SI-16 + SRG-OS-000433-GPOS-00193 + SRG-OS-000095-GPOS-00049 + R8 + OL09-00-002391 + SV-271735r1091917_rule + Kernel page-table isolation is a kernel feature that mitigates +the Meltdown security vulnerability and hardens the kernel +against attempts to bypass kernel address space layout +randomization (KASLR). + # Remediation is applicable only in certain platforms +if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ); then + +expected_value="on" + + +if [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; then + KARGS_DIR="/usr/lib/bootc/kargs.d/" + if grep -q -E "pti" "$KARGS_DIR/*.toml" ; then + sed -i -E "s/^(\s*kargs\s*=\s*\[.*)\"pti=[^\"]*\"(.*]\s*)/\1\"pti=$expected_value\"\2/" "$KARGS_DIR/*.toml" + else + echo "kargs = [\"pti=$expected_value\"]" >> "$KARGS_DIR/10-pti.toml" + fi +else + + grubby --update-kernel=ALL --args=pti=on + +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002391 + - NIST-800-53-SI-16 + - grub2_pti_argument + - low_disruption + - low_severity + - medium_complexity + - reboot_required + - restrict_strategy + +- name: Update grub defaults and the bootloader menu + command: /sbin/grubby --update-kernel=ALL --args="pti=on" + when: ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + tags: + - DISA-STIG-OL09-00-002391 + - NIST-800-53-SI-16 + - grub2_pti_argument + - low_disruption + - low_severity + - medium_complexity + - reboot_required + - restrict_strategy + + [customizations.kernel] +append = "pti=on" + + + + + + + + + + Configure the confidence in TPM for entropy + The TPM security chip that is available in most modern systems has a hardware RNG. +It is also used to feed the entropy pool, but generally not credited entropy. + +Use rng_core.default_quality in the kernel command line to set the trust +level on the hardware generators. The trust level defines the amount of entropy to credit. +A value of 0 tells the system not to trust the hardware random number generators +available, and doesn't credit any entropy to the pool. +A value of 1000 assigns full confidence in the generators, and credits all the +entropy it provides to the pool. + +Note that the value of rng_core.default_quality is global, affecting the trust +on all hardware random number generators. + +Select the appropriate confidence by adding the argument +rng_core.default_quality= + to the default +GRUB 2 command line for the Linux operating system. +To ensure that rng_core.default_quality= + is added as a kernel command line +argument to newly installed kernels, add rng_core.default_quality= + to the +default Grub2 command line for Linux operating systems. Modify the line within +/etc/default/grub as shown below: +GRUB_CMDLINE_LINUX="... rng_core.default_quality= ..." +Run the following command to update command line for already installed kernels:# grubby --update-kernel=ALL --args="rng_core.default_quality=" + + R8 + A system may struggle to initialize its entropy pool and end up starving. Crediting entropy +from the hardware number generators available in the system helps fill up the entropy pool. + # Remediation is applicable only in certain platforms +if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ); then + +var_rng_core_default_quality='' + +expected_value="$var_rng_core_default_quality" + + +if [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; then + KARGS_DIR="/usr/lib/bootc/kargs.d/" + if grep -q -E "rng_core.default_quality" "$KARGS_DIR/*.toml" ; then + sed -i -E "s/^(\s*kargs\s*=\s*\[.*)\"rng_core.default_quality=[^\"]*\"(.*]\s*)/\1\"rng_core.default_quality=$expected_value\"\2/" "$KARGS_DIR/*.toml" + else + echo "kargs = [\"rng_core.default_quality=$expected_value\"]" >> "$KARGS_DIR/10-rng_core_default_quality.toml" + fi +else + + grubby --update-kernel=ALL --args=rng_core.default_quality=$var_rng_core_default_quality + +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - grub2_rng_core_default_quality_argument + - low_disruption + - low_severity + - medium_complexity + - reboot_required + - restrict_strategy +- name: XCCDF Value var_rng_core_default_quality # promote to variable + set_fact: + var_rng_core_default_quality: !!str + tags: + - always + +- name: Update grub defaults and the bootloader menu + command: /sbin/grubby --update-kernel=ALL --args="rng_core.default_quality={{ var_rng_core_default_quality + }}" + when: ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + tags: + - grub2_rng_core_default_quality_argument + - low_disruption + - low_severity + - medium_complexity + - reboot_required + - restrict_strategy + + [customizations.kernel] +append = "rng_core.default_quality=" + + + + + + + + + + + Disable merging of slabs with similar size + The kernel may merge similar slabs together to reduce overhead and increase +cache hotness of objects. +Disabling merging of slabs keeps the slabs separate and reduces the risk of +kernel heap overflows overwriting objects in merged caches. + +To disable merging of slabs in the Kernel add the argument slab_nomerge=yes +to the default GRUB 2 command line for the Linux operating system. +To ensure that slab_nomerge=yes is added as a kernel command line +argument to newly installed kernels, add slab_nomerge=yes to the +default Grub2 command line for Linux operating systems. Modify the line within +/etc/default/grub as shown below: +GRUB_CMDLINE_LINUX="... slab_nomerge=yes ..." +Run the following command to update command line for already installed kernels:# grubby --update-kernel=ALL --args="slab_nomerge=yes" + + Disabling merge of slabs will slightly increase kernel memory utilization. + R8 + Disabling the merge of slabs of similar sizes prevents the kernel from +merging a seemingly useless but vulnerable slab with a useful and valuable slab. +This increase the risk that a heap overflow could overwrite objects from merged caches, +with unmerged caches the heap overflow would only affect the objects in the same cache. +Overall, this reduces the kernel attack surface area by isolating slabs from each other. + # Remediation is applicable only in certain platforms +if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ); then + +expected_value="yes" + + +if [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; then + KARGS_DIR="/usr/lib/bootc/kargs.d/" + if grep -q -E "slab_nomerge" "$KARGS_DIR/*.toml" ; then + sed -i -E "s/^(\s*kargs\s*=\s*\[.*)\"slab_nomerge=[^\"]*\"(.*]\s*)/\1\"slab_nomerge=$expected_value\"\2/" "$KARGS_DIR/*.toml" + else + echo "kargs = [\"slab_nomerge=$expected_value\"]" >> "$KARGS_DIR/10-slab_nomerge.toml" + fi +else + + grubby --update-kernel=ALL --args=slab_nomerge=yes + +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - grub2_slab_nomerge_argument + - low_disruption + - medium_complexity + - medium_severity + - reboot_required + - restrict_strategy + +- name: Update grub defaults and the bootloader menu + command: /sbin/grubby --update-kernel=ALL --args="slab_nomerge=yes" + when: ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + tags: + - grub2_slab_nomerge_argument + - low_disruption + - medium_complexity + - medium_severity + - reboot_required + - restrict_strategy + + [customizations.kernel] +append = "slab_nomerge=yes" + + + + + + + + + + Configure Speculative Store Bypass Mitigation + Certain CPUs are vulnerable to an exploit against a common wide industry wide performance +optimization known as Speculative Store Bypass (SSB). + +In such cases, recent stores to the same memory location cannot always be observed by later +loads during speculative execution. However, such stores are unlikely and thus they can be +detected prior to instruction retirement at the end of a particular speculation execution +window. + +Since Linux Kernel 4.17 you can check the SSB mitigation state with the following command: +cat /sys/devices/system/cpu/vulnerabilities/spec_store_bypass + +Select the appropriate SSB state by adding the argument +spec_store_bypass_disable= + to the default +GRUB 2 command line for the Linux operating system. +To ensure that spec_store_bypass_disable= + is added as a kernel command line +argument to newly installed kernels, add spec_store_bypass_disable= + to the +default Grub2 command line for Linux operating systems. Modify the line within +/etc/default/grub as shown below: +GRUB_CMDLINE_LINUX="... spec_store_bypass_disable= ..." +Run the following command to update command line for already installed kernels:# grubby --update-kernel=ALL --args="spec_store_bypass_disable=" + + Disabling Speculative Store Bypass may impact performance of the system. + R8 + In vulnerable processsors, the speculatively forwarded store can be used in a cache side channel +attack. An example of this is reading memory to which the attacker does not directly have access, +for example inside the sandboxed code. + # Remediation is applicable only in certain platforms +if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ); then + +var_spec_store_bypass_disable_options='' + +expected_value="$var_spec_store_bypass_disable_options" + + +if [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; then + KARGS_DIR="/usr/lib/bootc/kargs.d/" + if grep -q -E "spec_store_bypass_disable" "$KARGS_DIR/*.toml" ; then + sed -i -E "s/^(\s*kargs\s*=\s*\[.*)\"spec_store_bypass_disable=[^\"]*\"(.*]\s*)/\1\"spec_store_bypass_disable=$expected_value\"\2/" "$KARGS_DIR/*.toml" + else + echo "kargs = [\"spec_store_bypass_disable=$expected_value\"]" >> "$KARGS_DIR/10-spec_store_bypass_disable.toml" + fi +else + + grubby --update-kernel=ALL --args=spec_store_bypass_disable=$var_spec_store_bypass_disable_options + +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - grub2_spec_store_bypass_disable_argument + - low_disruption + - medium_complexity + - medium_severity + - reboot_required + - restrict_strategy +- name: XCCDF Value var_spec_store_bypass_disable_options # promote to variable + set_fact: + var_spec_store_bypass_disable_options: !!str + tags: + - always + +- name: Update grub defaults and the bootloader menu + command: /sbin/grubby --update-kernel=ALL --args="spec_store_bypass_disable={{ var_spec_store_bypass_disable_options + }}" + when: ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + tags: + - grub2_spec_store_bypass_disable_argument + - low_disruption + - medium_complexity + - medium_severity + - reboot_required + - restrict_strategy + + [customizations.kernel] +append = "spec_store_bypass_disable=" + + + + + + + + + + + Enforce Spectre v2 mitigation + Spectre V2 is an indirect branch poisoning attack that can lead to data leakage. +An exploit for Spectre V2 tricks the indirect branch predictor into executing +code from a future indirect branch chosen by the attacker, even if the privilege +level is different. + +Since Linux Kernel 4.15 you can check the Spectre V2 mitigation state with the following command: +cat /sys/devices/system/cpu/vulnerabilities/spectre_v2 + +Enforce the Spectre V2 mitigation by adding the argument +spectre_v2=on to the default +GRUB 2 command line for the Linux operating system. +To ensure that spectre_v2=on is added as a kernel command line +argument to newly installed kernels, add spectre_v2=on to the +default Grub2 command line for Linux operating systems. Modify the line within +/etc/default/grub as shown below: +GRUB_CMDLINE_LINUX="... spectre_v2=on ..." +Run the following command to update command line for already installed kernels:# grubby --update-kernel=ALL --args="spectre_v2=on" + + R8 + The Spectre V2 vulnerability allows an attacker to read memory that he should not have +access to. + # Remediation is applicable only in certain platforms +if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ); then + +expected_value="on" + + +if [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; then + KARGS_DIR="/usr/lib/bootc/kargs.d/" + if grep -q -E "spectre_v2" "$KARGS_DIR/*.toml" ; then + sed -i -E "s/^(\s*kargs\s*=\s*\[.*)\"spectre_v2=[^\"]*\"(.*]\s*)/\1\"spectre_v2=$expected_value\"\2/" "$KARGS_DIR/*.toml" + else + echo "kargs = [\"spectre_v2=$expected_value\"]" >> "$KARGS_DIR/10-spectre_v2.toml" + fi +else + + grubby --update-kernel=ALL --args=spectre_v2=on + +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - grub2_spectre_v2_argument + - high_severity + - low_disruption + - medium_complexity + - reboot_required + - restrict_strategy + +- name: Update grub defaults and the bootloader menu + command: /sbin/grubby --update-kernel=ALL --args="spectre_v2=on" + when: ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + tags: + - grub2_spectre_v2_argument + - high_severity + - low_disruption + - medium_complexity + - reboot_required + - restrict_strategy + + [customizations.kernel] +append = "spectre_v2=on" + + + + + + + + + + Ensure debug-shell service is not enabled during boot + systemd's debug-shell service is intended to +diagnose systemd related boot issues with various systemctl +commands. Once enabled and following a system reboot, the root shell +will be available on tty9 which is access by pressing +CTRL-ALT-F9. The debug-shell service should only be used +for systemd related issues and should otherwise be disabled. + + +By default, the debug-shell systemd service is already disabled. + +Ensure the debug-shell is not enabled by the systemd.debug-shel=1 +boot parameter option. + +Check that the line GRUB_CMDLINE_LINUX="..." within /etc/default/grub +doesn't contain the argument systemd.debug-shell. +Run the following command to update command line for already installed kernels: +# grubby --update-kernel=ALL --remove-args="systemd.debug-shell" + + FIA_UAU.1 + This prevents attackers with physical access from trivially bypassing security +on the machine through valid troubleshooting configurations and gaining root +access when the system is rebooted. + # Remediation is applicable only in certain platforms +if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ); then + +if [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; then + sed -i -E "/kargs\s*=\s*\[\s*\"systemd.debug-shell=[^\"]*\"\s*]/{:a;N;/^\n$/ba;N;/match-architectures.*/d;}" "$KARGS_DIR/*.toml" + sed -i -E -e "s/^(\s*kargs\s*=\s*\[.*)\"systemd.debug-shell=[^\"]*\"[,[:space:]]*(.*]\s*)/\1\2/" -e "s/^(\s*kargs.*),\s*\]$/\1\]/" "$KARGS_DIR/*.toml" +else + +grubby --update-kernel=ALL --remove-args=systemd.debug-shell + +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - grub2_systemd_debug-shell_argument_absent + - low_disruption + - medium_complexity + - medium_severity + - reboot_required + - restrict_strategy + +- name: Update grub defaults and the bootloader menu + command: /sbin/grubby --update-kernel=ALL --remove-args="systemd.debug-shell" + when: ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + tags: + - grub2_systemd_debug-shell_argument_absent + - low_disruption + - medium_complexity + - medium_severity + - reboot_required + - restrict_strategy + + + + + + + + + + Disable vsyscalls + To disable use of virtual syscalls, +add the argument vsyscall=none to the default +GRUB 2 command line for the Linux operating system. +To ensure that vsyscall=none is added as a kernel command line +argument to newly installed kernels, add vsyscall=none to the +default Grub2 command line for Linux operating systems. Modify the line within +/etc/default/grub as shown below: +GRUB_CMDLINE_LINUX="... vsyscall=none ..." +Run the following command to update command line for already installed kernels:# grubby --update-kernel=ALL --args="vsyscall=none" + + The vsyscall emulation is only available on x86_64 architecture +(CONFIG_X86_VSYSCALL_EMULATION) making this rule not applicable +to other CPU architectures. + CCI-000366 + CCI-001084 + CM-7(a) + FPT_ASLR_EXT.1 + SRG-OS-000480-GPOS-00227 + SRG-OS-000134-GPOS-00068 + OL09-00-002393 + SV-271737r1094967_rule + Virtual Syscalls provide an opportunity of attack for a user who has control +of the return instruction pointer. + + # Remediation is applicable only in certain platforms +if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ) && { ( grep -sqE "^.*\.x86_64$" /proc/sys/kernel/osrelease || grep -sqE "^x86_64$" /proc/sys/kernel/arch; ); }; then + +expected_value="none" + + +if [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; then + KARGS_DIR="/usr/lib/bootc/kargs.d/" + if grep -q -E "vsyscall" "$KARGS_DIR/*.toml" ; then + sed -i -E "s/^(\s*kargs\s*=\s*\[.*)\"vsyscall=[^\"]*\"(.*]\s*)/\1\"vsyscall=$expected_value\"\2/" "$KARGS_DIR/*.toml" + else + echo "kargs = [\"vsyscall=$expected_value\"]" >> "$KARGS_DIR/10-vsyscall.toml" + fi +else + + grubby --update-kernel=ALL --args=vsyscall=none + +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002393 + - NIST-800-53-CM-7(a) + - grub2_vsyscall_argument + - low_disruption + - medium_complexity + - medium_severity + - reboot_required + - restrict_strategy + +- name: Update grub defaults and the bootloader menu + command: /sbin/grubby --update-kernel=ALL --args="vsyscall=none" + when: + - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + - ansible_architecture == "x86_64" + tags: + - DISA-STIG-OL09-00-002393 + - NIST-800-53-CM-7(a) + - grub2_vsyscall_argument + - low_disruption + - medium_complexity + - medium_severity + - reboot_required + - restrict_strategy + + [customizations.kernel] +append = "vsyscall=none" + + + + + + + + + + Non-UEFI GRUB2 bootloader configuration + Non-UEFI GRUB2 bootloader configuration + + + Verify /boot/grub2/grub.cfg Group Ownership + The file /boot/grub2/grub.cfg should +be group-owned by the root group to prevent +destruction or modification of the file. + +To properly set the group owner of /boot/grub2/grub.cfg, run the command: +$ sudo chgrp root /boot/grub2/grub.cfg + + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + 5.5.2.2 + APO01.06 + DSS05.04 + DSS05.07 + DSS06.02 + 3.4.5 + CCI-000366 + 164.308(a)(1)(ii)(B) + 164.308(a)(7)(i) + 164.308(a)(7)(ii)(A) + 164.310(a)(1) + 164.310(a)(2)(i) + 164.310(a)(2)(ii) + 164.310(a)(2)(iii) + 164.310(b) + 164.310(c) + 164.310(d)(1) + 164.310(d)(2)(iii) + 4.3.3.7.3 + SR 2.1 + SR 5.2 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CM-6(a) + AC-6(1) + PR.AC-4 + PR.DS-5 + Req-7.1 + SRG-OS-000480-GPOS-00227 + R29 + A.6.SEC-OL2 + 2.2.6 + 2.2 + OL09-00-002530 + SV-271792r1094968_rule + The root group is a highly-privileged group. Furthermore, the group-owner of this +file should not have any access privileges anyway. + + # Remediation is applicable only in certain platforms +if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ) && [ ! -d /sys/firmware/efi ] && { ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ); }; then + +chgrp 0 /boot/grub2/grub.cfg + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - CJIS-5.5.2.2 + - DISA-STIG-OL09-00-002530 + - NIST-800-171-3.4.5 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-7.1 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_groupowner_grub2_cfg + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /boot/grub2/grub.cfg + stat: + path: /boot/grub2/grub.cfg + register: file_exists + when: + - '"/boot/efi" not in ansible_mounts | map(attribute="mount") | list' + - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + - not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) + tags: + - CJIS-5.5.2.2 + - DISA-STIG-OL09-00-002530 + - NIST-800-171-3.4.5 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-7.1 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_groupowner_grub2_cfg + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure group owner 0 on /boot/grub2/grub.cfg + file: + path: /boot/grub2/grub.cfg + group: '0' + when: + - '"/boot/efi" not in ansible_mounts | map(attribute="mount") | list' + - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + - not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) + - file_exists.stat is defined and file_exists.stat.exists + tags: + - CJIS-5.5.2.2 + - DISA-STIG-OL09-00-002530 + - NIST-800-171-3.4.5 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-7.1 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_groupowner_grub2_cfg + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify /boot/grub2/user.cfg Group Ownership + The file /boot/grub2/user.cfg should be group-owned by the root +group to prevent reading or modification of the file. + +To properly set the group owner of /boot/grub2/user.cfg, run the command: +$ sudo chgrp root /boot/grub2/user.cfg + + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + 5.5.2.2 + APO01.06 + DSS05.04 + DSS05.07 + DSS06.02 + 3.4.5 + CCI-000225 + 164.308(a)(1)(ii)(B) + 164.308(a)(7)(i) + 164.308(a)(7)(ii)(A) + 164.310(a)(1) + 164.310(a)(2)(i) + 164.310(a)(2)(ii) + 164.310(a)(2)(iii) + 164.310(b) + 164.310(c) + 164.310(d)(1) + 164.310(d)(2)(iii) + 4.3.3.7.3 + SR 2.1 + SR 5.2 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CM-6(a) + AC-6(1) + PR.AC-4 + PR.DS-5 + Req-7.1 + SRG-OS-000480-GPOS-00227 + R29 + A.6.SEC-OL2 + 2.2.6 + 2.2 + The root group is a highly-privileged group. Furthermore, the group-owner of this +file should not have any access privileges anyway. Non-root users who read the boot parameters +may be able to identify weaknesses in security upon boot and be able to exploit them. + + # Remediation is applicable only in certain platforms +if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ) && [ ! -d /sys/firmware/efi ] && { ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ); }; then + +chgrp 0 /boot/grub2/user.cfg + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - CJIS-5.5.2.2 + - NIST-800-171-3.4.5 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-7.1 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_groupowner_user_cfg + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /boot/grub2/user.cfg + stat: + path: /boot/grub2/user.cfg + register: file_exists + when: + - '"/boot/efi" not in ansible_mounts | map(attribute="mount") | list' + - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + - not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) + tags: + - CJIS-5.5.2.2 + - NIST-800-171-3.4.5 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-7.1 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_groupowner_user_cfg + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure group owner 0 on /boot/grub2/user.cfg + file: + path: /boot/grub2/user.cfg + group: '0' + when: + - '"/boot/efi" not in ansible_mounts | map(attribute="mount") | list' + - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + - not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) + - file_exists.stat is defined and file_exists.stat.exists + tags: + - CJIS-5.5.2.2 + - NIST-800-171-3.4.5 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-7.1 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_groupowner_user_cfg + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify /boot/grub2/grub.cfg User Ownership + The file /boot/grub2/grub.cfg should +be owned by the root user to prevent destruction +or modification of the file. + +To properly set the owner of /boot/grub2/grub.cfg, run the command: +$ sudo chown root /boot/grub2/grub.cfg + + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + 5.5.2.2 + APO01.06 + DSS05.04 + DSS05.07 + DSS06.02 + 3.4.5 + CCI-000366 + 164.308(a)(1)(ii)(B) + 164.308(a)(7)(i) + 164.308(a)(7)(ii)(A) + 164.310(a)(1) + 164.310(a)(2)(i) + 164.310(a)(2)(ii) + 164.310(a)(2)(iii) + 164.310(b) + 164.310(c) + 164.310(d)(1) + 164.310(d)(2)(iii) + 4.3.3.7.3 + SR 2.1 + SR 5.2 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CM-6(a) + AC-6(1) + PR.AC-4 + PR.DS-5 + Req-7.1 + SRG-OS-000480-GPOS-00227 + R29 + A.6.SEC-OL2 + 2.2.6 + 2.2 + OL09-00-002531 + SV-271793r1092605_rule + Only root should be able to modify important boot parameters. + + # Remediation is applicable only in certain platforms +if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ) && [ ! -d /sys/firmware/efi ] && { ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ); }; then + +chown 0 /boot/grub2/grub.cfg + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - CJIS-5.5.2.2 + - DISA-STIG-OL09-00-002531 + - NIST-800-171-3.4.5 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-7.1 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_owner_grub2_cfg + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /boot/grub2/grub.cfg + stat: + path: /boot/grub2/grub.cfg + register: file_exists + when: + - '"/boot/efi" not in ansible_mounts | map(attribute="mount") | list' + - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + - not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) + tags: + - CJIS-5.5.2.2 + - DISA-STIG-OL09-00-002531 + - NIST-800-171-3.4.5 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-7.1 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_owner_grub2_cfg + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure owner 0 on /boot/grub2/grub.cfg + file: + path: /boot/grub2/grub.cfg + owner: '0' + when: + - '"/boot/efi" not in ansible_mounts | map(attribute="mount") | list' + - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + - not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) + - file_exists.stat is defined and file_exists.stat.exists + tags: + - CJIS-5.5.2.2 + - DISA-STIG-OL09-00-002531 + - NIST-800-171-3.4.5 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-7.1 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_owner_grub2_cfg + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify /boot/grub2/user.cfg User Ownership + The file /boot/grub2/user.cfg should be owned by the root +user to prevent reading or modification of the file. + +To properly set the owner of /boot/grub2/user.cfg, run the command: +$ sudo chown root /boot/grub2/user.cfg + + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + 5.5.2.2 + APO01.06 + DSS05.04 + DSS05.07 + DSS06.02 + 3.4.5 + CCI-000225 + 164.308(a)(1)(ii)(B) + 164.308(a)(7)(i) + 164.308(a)(7)(ii)(A) + 164.310(a)(1) + 164.310(a)(2)(i) + 164.310(a)(2)(ii) + 164.310(a)(2)(iii) + 164.310(b) + 164.310(c) + 164.310(d)(1) + 164.310(d)(2)(iii) + 4.3.3.7.3 + SR 2.1 + SR 5.2 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CM-6(a) + AC-6(1) + PR.AC-4 + PR.DS-5 + Req-7.1 + R29 + A.6.SEC-OL2 + 2.2.6 + 2.2 + Only root should be able to modify important boot parameters. Also, non-root users who read +the boot parameters may be able to identify weaknesses in security upon boot and be able to +exploit them. + + # Remediation is applicable only in certain platforms +if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ) && [ ! -d /sys/firmware/efi ] && { ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ); }; then + +chown 0 /boot/grub2/user.cfg + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - CJIS-5.5.2.2 + - NIST-800-171-3.4.5 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-7.1 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_owner_user_cfg + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /boot/grub2/user.cfg + stat: + path: /boot/grub2/user.cfg + register: file_exists + when: + - '"/boot/efi" not in ansible_mounts | map(attribute="mount") | list' + - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + - not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) + tags: + - CJIS-5.5.2.2 + - NIST-800-171-3.4.5 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-7.1 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_owner_user_cfg + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure owner 0 on /boot/grub2/user.cfg + file: + path: /boot/grub2/user.cfg + owner: '0' + when: + - '"/boot/efi" not in ansible_mounts | map(attribute="mount") | list' + - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + - not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) + - file_exists.stat is defined and file_exists.stat.exists + tags: + - CJIS-5.5.2.2 + - NIST-800-171-3.4.5 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-7.1 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_owner_user_cfg + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify /boot/grub2/grub.cfg Permissions + File permissions for /boot/grub2/grub.cfg should be set to 600. + +To properly set the permissions of /boot/grub2/grub.cfg, run the command: +$ sudo chmod 600 /boot/grub2/grub.cfg + + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + APO01.06 + DSS05.04 + DSS05.07 + DSS06.02 + 3.4.5 + CCI-000225 + 164.308(a)(1)(ii)(B) + 164.308(a)(7)(i) + 164.308(a)(7)(ii)(A) + 164.310(a)(1) + 164.310(a)(2)(i) + 164.310(a)(2)(ii) + 164.310(a)(2)(iii) + 164.310(b) + 164.310(c) + 164.310(d)(1) + 164.310(d)(2)(iii) + 4.3.3.7.3 + SR 2.1 + SR 5.2 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CM-6(a) + AC-6(1) + PR.AC-4 + PR.DS-5 + R29 + A.6.SEC-OL2 + 2.2.6 + 2.2 + Proper permissions ensure that only the root user can modify important boot +parameters. + + # Remediation is applicable only in certain platforms +if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ) && [ ! -d /sys/firmware/efi ] && { ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ); }; then + +chmod u-xs,g-xwrs,o-xwrt /boot/grub2/grub.cfg + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-171-3.4.5 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_permissions_grub2_cfg + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /boot/grub2/grub.cfg + stat: + path: /boot/grub2/grub.cfg + register: file_exists + when: + - '"/boot/efi" not in ansible_mounts | map(attribute="mount") | list' + - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + - not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) + tags: + - NIST-800-171-3.4.5 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_permissions_grub2_cfg + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure permission u-xs,g-xwrs,o-xwrt on /boot/grub2/grub.cfg + file: + path: /boot/grub2/grub.cfg + mode: u-xs,g-xwrs,o-xwrt + when: + - '"/boot/efi" not in ansible_mounts | map(attribute="mount") | list' + - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + - not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) + - file_exists.stat is defined and file_exists.stat.exists + tags: + - NIST-800-171-3.4.5 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_permissions_grub2_cfg + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify /boot/grub2/user.cfg Permissions + File permissions for /boot/grub2/user.cfg should be set to 600. + +To properly set the permissions of /boot/grub2/user.cfg, run the command: +$ sudo chmod 600 /boot/grub2/user.cfg + + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + APO01.06 + DSS05.04 + DSS05.07 + DSS06.02 + 3.4.5 + CCI-000225 + 164.308(a)(1)(ii)(B) + 164.308(a)(7)(i) + 164.308(a)(7)(ii)(A) + 164.310(a)(1) + 164.310(a)(2)(i) + 164.310(a)(2)(ii) + 164.310(a)(2)(iii) + 164.310(b) + 164.310(c) + 164.310(d)(1) + 164.310(d)(2)(iii) + 4.3.3.7.3 + SR 2.1 + SR 5.2 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CM-6(a) + AC-6(1) + PR.AC-4 + PR.DS-5 + R29 + A.6.SEC-OL2 + 2.2.6 + 2.2 + Proper permissions ensure that only the root user can read or modify important boot +parameters. + + # Remediation is applicable only in certain platforms +if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ) && [ ! -d /sys/firmware/efi ] && { ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ); }; then + +chmod u-xs,g-xwrs,o-xwrt /boot/grub2/user.cfg + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-171-3.4.5 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_permissions_user_cfg + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /boot/grub2/user.cfg + stat: + path: /boot/grub2/user.cfg + register: file_exists + when: + - '"/boot/efi" not in ansible_mounts | map(attribute="mount") | list' + - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + - not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) + tags: + - NIST-800-171-3.4.5 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_permissions_user_cfg + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure permission u-xs,g-xwrs,o-xwrt on /boot/grub2/user.cfg + file: + path: /boot/grub2/user.cfg + mode: u-xs,g-xwrs,o-xwrt + when: + - '"/boot/efi" not in ansible_mounts | map(attribute="mount") | list' + - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + - not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) + - file_exists.stat is defined and file_exists.stat.exists + tags: + - NIST-800-171-3.4.5 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_permissions_user_cfg + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Set the Boot Loader Admin Username to a Non-Default Value + The grub2 boot loader should have a superuser account and password +protection enabled to protect boot-time settings. + + +To maximize the protection, select a password-protected superuser account with unique name, and modify the +/etc/grub.d/01_users configuration file to reflect the account name change. + + +Do not to use common administrator account names like root, +admin, or administrator for the grub2 superuser account. + + +Change the superuser to a different username (The default is 'root'). +$ sed -i 's/\(set superusers=\).*/\1"<unique user ID>"/g' /etc/grub.d/01_users + + +Once the superuser account has been added, +update the +grub.cfg file by running: +grubby --update-kernel=ALL + + To prevent hard-coded admin usernames, automatic remediation of this control is not available. Remediation +must be automated as a component of machine provisioning, or followed manually as outlined above. + +Also, do NOT manually add the superuser account and password to the +grub.cfg file as the grub2-mkconfig command overwrites this file. + 1 + 11 + 12 + 14 + 15 + 16 + 18 + 3 + 5 + DSS05.02 + DSS05.04 + DSS05.05 + DSS05.07 + DSS05.10 + DSS06.03 + DSS06.06 + DSS06.10 + 3.4.5 + CCI-000213 + 164.308(a)(1)(ii)(B) + 164.308(a)(7)(i) + 164.308(a)(7)(ii)(A) + 164.310(a)(1) + 164.310(a)(2)(i) + 164.310(a)(2)(ii) + 164.310(a)(2)(iii) + 164.310(b) + 164.310(c) + 164.310(d)(1) + 164.310(d)(2)(iii) + 4.3.3.2.2 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + A.18.1.4 + A.6.1.2 + A.7.1.1 + A.9.1.2 + A.9.2.1 + A.9.2.2 + A.9.2.3 + A.9.2.4 + A.9.2.6 + A.9.3.1 + A.9.4.1 + A.9.4.2 + A.9.4.3 + A.9.4.4 + A.9.4.5 + CM-6(a) + PR.AC-1 + PR.AC-4 + PR.AC-6 + PR.AC-7 + PR.PT-3 + SRG-OS-000080-GPOS-00048 + OL09-00-000050 + SV-271451r1091065_rule + Having a non-default grub superuser username makes password-guessing attacks less effective. + + + + + + + + + Set Boot Loader Password in grub2 + The grub2 boot loader should have a superuser account and password +protection enabled to protect boot-time settings. + + +Since plaintext passwords are a security risk, generate a hash for the password +by running the following command: + +# grub2-setpassword + +When prompted, enter the password that was selected. + + + + To prevent hard-coded passwords, automatic remediation of this control is not available. Remediation +must be automated as a component of machine provisioning, or followed manually as outlined above. + +Also, do NOT manually add the superuser account and password to the +grub.cfg file as the grub2-mkconfig command overwrites this file. + 1 + 11 + 12 + 14 + 15 + 16 + 18 + 3 + 5 + DSS05.02 + DSS05.04 + DSS05.05 + DSS05.07 + DSS05.10 + DSS06.03 + DSS06.06 + DSS06.10 + 3.4.5 + CCI-000213 + 164.308(a)(1)(ii)(B) + 164.308(a)(7)(i) + 164.308(a)(7)(ii)(A) + 164.310(a)(1) + 164.310(a)(2)(i) + 164.310(a)(2)(ii) + 164.310(a)(2)(iii) + 164.310(b) + 164.310(c) + 164.310(d)(1) + 164.310(d)(2)(iii) + 4.3.3.2.2 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + A.18.1.4 + A.6.1.2 + A.7.1.1 + A.9.1.2 + A.9.2.1 + A.9.2.2 + A.9.2.3 + A.9.2.4 + A.9.2.6 + A.9.3.1 + A.9.4.1 + A.9.4.2 + A.9.4.3 + A.9.4.4 + A.9.4.5 + CM-6(a) + PR.AC-1 + PR.AC-4 + PR.AC-6 + PR.AC-7 + PR.PT-3 + SRG-OS-000080-GPOS-00048 + R5 + A.8.SEC-OL7 + OL09-00-001115 + SV-271635r1091617_rule + Password protection on the boot loader configuration ensures +users with physical access cannot trivially alter +important bootloader settings. These include which kernel to use, +and whether to enter single-user mode. + + + + + + + + + + UEFI GRUB2 bootloader configuration + UEFI GRUB2 bootloader configuration + UEFI generally uses vfat file systems, which does not support Unix-style permissions +managed by chmod command. In this case, in order to change file permissions for files +within /boot/efi it is necessary to update the mount options in /etc/fstab file and +reboot the system. + + + Verify the UEFI Boot Loader grub.cfg Group Ownership + The file /boot/grub2/grub.cfg should +be group-owned by the root group to prevent +destruction or modification of the file. + +To properly set the group owner of /boot/grub2/grub.cfg, run the command: +$ sudo chgrp root /boot/grub2/grub.cfg + + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + 5.5.2.2 + APO01.06 + DSS05.04 + DSS05.07 + DSS06.02 + 3.4.5 + CCI-000225 + 4.3.3.7.3 + SR 2.1 + SR 5.2 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CM-6(a) + AC-6(1) + PR.AC-4 + PR.DS-5 + Req-7.1 + R29 + The root group is a highly-privileged group. Furthermore, the group-owner of this +file should not have any access privileges anyway. + # Remediation is applicable only in certain platforms +if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ) && [ -d /sys/firmware/efi ]; then + +chgrp 0 /boot/grub2/grub.cfg + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - CJIS-5.5.2.2 + - NIST-800-171-3.4.5 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-7.1 + - configure_strategy + - file_groupowner_efi_grub2_cfg + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /boot/grub2/grub.cfg + stat: + path: /boot/grub2/grub.cfg + register: file_exists + when: + - '"/boot/efi" in ansible_mounts | map(attribute="mount") | list' + - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + tags: + - CJIS-5.5.2.2 + - NIST-800-171-3.4.5 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-7.1 + - configure_strategy + - file_groupowner_efi_grub2_cfg + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure group owner 0 on /boot/grub2/grub.cfg + file: + path: /boot/grub2/grub.cfg + group: '0' + when: + - '"/boot/efi" in ansible_mounts | map(attribute="mount") | list' + - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + - file_exists.stat is defined and file_exists.stat.exists + tags: + - CJIS-5.5.2.2 + - NIST-800-171-3.4.5 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-7.1 + - configure_strategy + - file_groupowner_efi_grub2_cfg + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify /boot/grub2/user.cfg Group Ownership + The file /boot/grub2/user.cfg should be group-owned by the +root group to prevent reading or modification of the file. + +To properly set the group owner of /boot/grub2/user.cfg, run the command: +$ sudo chgrp root /boot/grub2/user.cfg + + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + 5.5.2.2 + APO01.06 + DSS05.04 + DSS05.07 + DSS06.02 + 3.4.5 + CCI-000225 + 4.3.3.7.3 + SR 2.1 + SR 5.2 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CM-6(a) + AC-6(1) + PR.AC-4 + PR.DS-5 + Req-7.1 + R29 + The root group is a highly-privileged group. Furthermore, the group-owner of this +file should not have any access privileges anyway. Non-root users who read the boot parameters +may be able to identify weaknesses in security upon boot and be able to exploit them. + # Remediation is applicable only in certain platforms +if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ) && [ -d /sys/firmware/efi ]; then + +chgrp 0 /boot/grub2/user.cfg + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - CJIS-5.5.2.2 + - NIST-800-171-3.4.5 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-7.1 + - configure_strategy + - file_groupowner_efi_user_cfg + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /boot/grub2/user.cfg + stat: + path: /boot/grub2/user.cfg + register: file_exists + when: + - '"/boot/efi" in ansible_mounts | map(attribute="mount") | list' + - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + tags: + - CJIS-5.5.2.2 + - NIST-800-171-3.4.5 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-7.1 + - configure_strategy + - file_groupowner_efi_user_cfg + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure group owner 0 on /boot/grub2/user.cfg + file: + path: /boot/grub2/user.cfg + group: '0' + when: + - '"/boot/efi" in ansible_mounts | map(attribute="mount") | list' + - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + - file_exists.stat is defined and file_exists.stat.exists + tags: + - CJIS-5.5.2.2 + - NIST-800-171-3.4.5 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-7.1 + - configure_strategy + - file_groupowner_efi_user_cfg + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify the UEFI Boot Loader grub.cfg User Ownership + The file /boot/grub2/grub.cfg should +be owned by the root user to prevent destruction +or modification of the file. + +To properly set the owner of /boot/grub2/grub.cfg, run the command: +$ sudo chown root /boot/grub2/grub.cfg + + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + 5.5.2.2 + APO01.06 + DSS05.04 + DSS05.07 + DSS06.02 + 3.4.5 + CCI-000225 + 4.3.3.7.3 + SR 2.1 + SR 5.2 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CM-6(a) + AC-6(1) + PR.AC-4 + PR.DS-5 + Req-7.1 + R29 + Only root should be able to modify important boot parameters. + # Remediation is applicable only in certain platforms +if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ) && [ -d /sys/firmware/efi ]; then + +chown 0 /boot/grub2/grub.cfg + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - CJIS-5.5.2.2 + - NIST-800-171-3.4.5 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-7.1 + - configure_strategy + - file_owner_efi_grub2_cfg + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /boot/grub2/grub.cfg + stat: + path: /boot/grub2/grub.cfg + register: file_exists + when: + - '"/boot/efi" in ansible_mounts | map(attribute="mount") | list' + - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + tags: + - CJIS-5.5.2.2 + - NIST-800-171-3.4.5 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-7.1 + - configure_strategy + - file_owner_efi_grub2_cfg + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure owner 0 on /boot/grub2/grub.cfg + file: + path: /boot/grub2/grub.cfg + owner: '0' + when: + - '"/boot/efi" in ansible_mounts | map(attribute="mount") | list' + - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + - file_exists.stat is defined and file_exists.stat.exists + tags: + - CJIS-5.5.2.2 + - NIST-800-171-3.4.5 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-7.1 + - configure_strategy + - file_owner_efi_grub2_cfg + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify /boot/grub2/user.cfg User Ownership + The file /boot/grub2/user.cfg should be owned by the root +user to prevent reading or modification of the file. + +To properly set the owner of /boot/grub2/user.cfg, run the command: +$ sudo chown root /boot/grub2/user.cfg + + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + 5.5.2.2 + APO01.06 + DSS05.04 + DSS05.07 + DSS06.02 + 3.4.5 + CCI-000225 + 4.3.3.7.3 + SR 2.1 + SR 5.2 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CM-6(a) + AC-6(1) + PR.AC-4 + PR.DS-5 + Req-7.1 + R29 + Only root should be able to modify important boot parameters. Also, non-root users who read +the boot parameters may be able to identify weaknesses in security upon boot and be able to +exploit them. + # Remediation is applicable only in certain platforms +if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ) && [ -d /sys/firmware/efi ]; then + +chown 0 /boot/grub2/user.cfg + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - CJIS-5.5.2.2 + - NIST-800-171-3.4.5 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-7.1 + - configure_strategy + - file_owner_efi_user_cfg + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /boot/grub2/user.cfg + stat: + path: /boot/grub2/user.cfg + register: file_exists + when: + - '"/boot/efi" in ansible_mounts | map(attribute="mount") | list' + - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + tags: + - CJIS-5.5.2.2 + - NIST-800-171-3.4.5 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-7.1 + - configure_strategy + - file_owner_efi_user_cfg + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure owner 0 on /boot/grub2/user.cfg + file: + path: /boot/grub2/user.cfg + owner: '0' + when: + - '"/boot/efi" in ansible_mounts | map(attribute="mount") | list' + - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + - file_exists.stat is defined and file_exists.stat.exists + tags: + - CJIS-5.5.2.2 + - NIST-800-171-3.4.5 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-7.1 + - configure_strategy + - file_owner_efi_user_cfg + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify the UEFI Boot Loader grub.cfg Permissions + File permissions for /boot/grub2/grub.cfg should be set to 700. + +To properly set the permissions of /boot/grub2/grub.cfg, run the command: +$ sudo chmod 700 /boot/grub2/grub.cfg + + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + APO01.06 + DSS05.04 + DSS05.07 + DSS06.02 + 3.4.5 + CCI-000225 + 4.3.3.7.3 + SR 2.1 + SR 5.2 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CM-6(a) + AC-6(1) + PR.AC-4 + PR.DS-5 + R29 + Proper permissions ensure that only the root user can modify important boot +parameters. + # Remediation is applicable only in certain platforms +if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ) && [ -d /sys/firmware/efi ]; then + +chmod u-s,g-xwrs,o-xwrt /boot/grub2/grub.cfg + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-171-3.4.5 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - configure_strategy + - file_permissions_efi_grub2_cfg + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /boot/grub2/grub.cfg + stat: + path: /boot/grub2/grub.cfg + register: file_exists + when: + - '"/boot/efi" in ansible_mounts | map(attribute="mount") | list' + - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + tags: + - NIST-800-171-3.4.5 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - configure_strategy + - file_permissions_efi_grub2_cfg + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure permission u-s,g-xwrs,o-xwrt on /boot/grub2/grub.cfg + file: + path: /boot/grub2/grub.cfg + mode: u-s,g-xwrs,o-xwrt + when: + - '"/boot/efi" in ansible_mounts | map(attribute="mount") | list' + - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + - file_exists.stat is defined and file_exists.stat.exists + tags: + - NIST-800-171-3.4.5 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - configure_strategy + - file_permissions_efi_grub2_cfg + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify /boot/grub2/user.cfg Permissions + File permissions for /boot/grub2/user.cfg should be set to 600. + +To properly set the permissions of /boot/grub2/user.cfg, run the command: +$ sudo chmod 600 /boot/grub2/user.cfg + + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + APO01.06 + DSS05.04 + DSS05.07 + DSS06.02 + 3.4.5 + CCI-000225 + 4.3.3.7.3 + SR 2.1 + SR 5.2 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CM-6(a) + AC-6(1) + PR.AC-4 + PR.DS-5 + R29 + Proper permissions ensure that only the root user can read or modify important boot +parameters. + # Remediation is applicable only in certain platforms +if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ) && [ -d /sys/firmware/efi ]; then + +chmod u-s,g-xwrs,o-xwrt /boot/grub2/user.cfg + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-171-3.4.5 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - configure_strategy + - file_permissions_efi_user_cfg + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /boot/grub2/user.cfg + stat: + path: /boot/grub2/user.cfg + register: file_exists + when: + - '"/boot/efi" in ansible_mounts | map(attribute="mount") | list' + - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + tags: + - NIST-800-171-3.4.5 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - configure_strategy + - file_permissions_efi_user_cfg + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure permission u-s,g-xwrs,o-xwrt on /boot/grub2/user.cfg + file: + path: /boot/grub2/user.cfg + mode: u-s,g-xwrs,o-xwrt + when: + - '"/boot/efi" in ansible_mounts | map(attribute="mount") | list' + - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + - file_exists.stat is defined and file_exists.stat.exists + tags: + - NIST-800-171-3.4.5 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - configure_strategy + - file_permissions_efi_user_cfg + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Set the UEFI Boot Loader Password + The grub2 boot loader should have a superuser account and password +protection enabled to protect boot-time settings. + + +Since plaintext passwords are a security risk, generate a hash for the password +by running the following command: + +# grub2-setpassword + +When prompted, enter the password that was selected. + + + + To prevent hard-coded passwords, automatic remediation of this control is not available. Remediation +must be automated as a component of machine provisioning, or followed manually as outlined above. + +Also, do NOT manually add the superuser account and password to the +grub.cfg file as the grub2-mkconfig command overwrites this file. + 11 + 12 + 14 + 15 + 16 + 18 + 3 + 5 + DSS05.02 + DSS05.04 + DSS05.05 + DSS05.07 + DSS06.03 + DSS06.06 + 3.4.5 + CCI-000213 + 164.308(a)(1)(ii)(B) + 164.308(a)(7)(i) + 164.308(a)(7)(ii)(A) + 164.310(a)(1) + 164.310(a)(2)(i) + 164.310(a)(2)(ii) + 164.310(a)(2)(iii) + 164.310(b) + 164.310(c) + 164.310(d)(1) + 164.310(d)(2)(iii) + 4.3.3.2.2 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + A.6.1.2 + A.7.1.1 + A.9.1.2 + A.9.2.1 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CM-6(a) + PR.AC-4 + PR.AC-6 + PR.PT-3 + FIA_UAU.1 + SRG-OS-000080-GPOS-00048 + R5 + Password protection on the boot loader configuration ensures +users with physical access cannot trivially alter +important bootloader settings. These include which kernel to use, +and whether to enter single-user mode. + + + + + + + + + + + Protect Random-Number Entropy Pool + The I/O operations of the Linux kernel block layer due to their inherently +unpredictable execution times have been traditionally considered as a reliable +source to contribute to random-number entropy pool of the Linux kernel. This +has changed with introduction of solid-state storage devices (SSDs) though. + + + Ensure Solid State Drives Do Not Contribute To Random-Number Entropy Pool + For each solid-state drive on the system, run: + # echo 0 > /sys/block/DRIVE/queue/add_random + + In contrast to traditional electromechanical magnetic disks, containing +spinning disks and / or movable read / write heads, the solid-state storage +devices (SSDs) do not contain moving / mechanical components. Therefore the +I/O operation completion times are much more predictable for them. + + + + Kernel Configuration + Contains rules that check the kernel configuration that was used to build it. + + + Hash function for kernel module signing + The hash function to use when signing modules during kernel build process. + sha512 + sha1 + sha224 + sha256 + sha384 + sha512 + + + Key and certificate for kernel module signing + The private key and certificate to use when signing modules during kernel build process. +On systems where the OpenSSL ENGINE_pkcs11 is functional — a PKCS#11 URI as defined by RFC7512 +In the latter case, the PKCS#11 URI should reference both a certificate and a private key. + certs/signing_key.pem + certs/signing_key.pem + + + Kernel panic timeout + The time, in seconds, to wait until a reboot occurs. +If the value is 0 the system never reboots. +If the value is less than 0 the system reboots immediately. + 0 + 0 + 300 + 60 + -1 + + + Do not allow ACPI methods to be inserted/replaced at run time + This debug facility allows ACPI AML methods to be inserted and/or replaced without rebooting +the system. +This configuration is available from kernel 3.0. + +The configuration that was used to build kernel is available at /boot/config-*. + To check the configuration value for CONFIG_ACPI_CUSTOM_METHOD, run the following command: + grep CONFIG_ACPI_CUSTOM_METHOD /boot/config-* + + Configs with value 'n' are not explicitly set in the file, so either commented lines or no + lines should be returned. + + There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. + R15 + Enabling this feature allows arbitrary kernel memory to be written to by root (uid=0) users, +allowing them to bypass certain security measures + + + + + + + + + Emulate Privileged Access Never (PAN) + Enabling this option prevents the kernel from accessing user-space memory directly by pointing +TTBR0_EL1 to a reserved zeroed area and reserved ASID. +The user access routines restore the valid TTBR0_EL1 temporarily. +This configuration is available from kernel 4.10, but may be available if backported +by distros. + +The configuration that was used to build kernel is available at /boot/config-*. + To check the configuration value for CONFIG_ARM64_SW_TTBR0_PAN, run the following command: + grep CONFIG_ARM64_SW_TTBR0_PAN /boot/config-* + + For each kernel installed, a line with value "y" should be returned. + + There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. + R27 + The Privileged Access Never (PAN) is the ARM equivalent of the x86 Supervisor Mode Access +Prevention (SMAP), and it prevents privileged acccess to user data unless explicitly enabled. + + + + + + + + + + Disable kernel support for MISC binaries + Enabling CONFIG_BINFMT_MISC makes it possible to plug wrapper-driven binary formats +into the kernel. This is specially useful for programs that need an interpreter to run like +Java, Python and DOS emulators. Once you have registered such a binary class with the kernel, +you can start one of those programs simply by typing in its name at a shell prompt. + +The configuration that was used to build kernel is available at /boot/config-*. + To check the configuration value for CONFIG_BINFMT_MISC, run the following command: + grep CONFIG_BINFMT_MISC /boot/config-* + + Configs with value 'n' are not explicitly set in the file, so either commented lines or no + lines should be returned. + + There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. + R23 + This disables arbitrary binary format support and helps reduce attack surface. + + + + + + + + + Enable support for BUG() + Disabling this option eliminates support for BUG and WARN, reducing the size of your kernel +image and potentially quietly ignoring numerous fatal conditions. You should only consider +disabling this option for embedded systems with no facilities for reporting errors. + +The configuration that was used to build kernel is available at /boot/config-*. + To check the configuration value for CONFIG_BUG, run the following command: + grep CONFIG_BUG /boot/config-* + + For each kernel installed, a line with value "y" should be returned. + + There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. + R19 + Not setting this variable may hide a number of critical errors. + + + + + + + + + Trigger a kernel BUG when data corruption is detected + This option makes the kernel BUG when it encounters data corruption in kernel memory structures +when they get checked for validity. +This configuration is available from kernel 4.10. + +The configuration that was used to build kernel is available at /boot/config-*. + To check the configuration value for CONFIG_BUG_ON_DATA_CORRUPTION, run the following command: + grep CONFIG_BUG_ON_DATA_CORRUPTION /boot/config-* + + For each kernel installed, a line with value "y" should be returned. + + There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. + R16 + This helps detect data corruptions early and stop with a BUG() error message. + + + + + + + + + Disable compatibility with brk() + Enabling compatiliby with brk() allows legacy binaries to run (i.e. those linked +against libc5). But this compatibility comes at the cost of not being able to randomize +the heap placement (ASLR). + +Unless legacy binaries need to run on the system, set CONFIG_COMPAT_BRK to "n". + +The configuration that was used to build kernel is available at /boot/config-*. + To check the configuration value for CONFIG_COMPAT_BRK, run the following command: + grep CONFIG_COMPAT_BRK /boot/config-* + + Configs with value 'n' are not explicitly set in the file, so either commented lines or no + lines should be returned. + + There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. + R17 + Enabling compatibility with brk() disables support for ASLR. + + + + + + + + + Disable the 32-bit vDSO + Certain buggy versions of glibc (2.3.3) will crash if they are presented with a 32-bit vDSO +that is not mapped at the address indicated in its segment table. +Setting CONFIG_COMPAT_VDSO to y turns off the 32-bit VDSO and works +aroud the glibc bug. + +The configuration that was used to build kernel is available at /boot/config-*. + To check the configuration value for CONFIG_COMPAT_VDSO, run the following command: + grep CONFIG_COMPAT_VDSO /boot/config-* + + Configs with value 'n' are not explicitly set in the file, so either commented lines or no + lines should be returned. + + There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. + R15 + Enabling VDSO compatibility hurts performance and disables ASLR. + + + + + + + + + Enable checks on credential management + Enable this to turn on some debug checking for credential management. The additional code keeps +track of the number of pointers from task_structs to any given cred struct, and checks to see +that this number never exceeds the usage count of the cred struct. + +Furthermore, if SELinux is enabled, this also checks that the security pointer in the cred +struct is never seen to be invalid. + +The configuration that was used to build kernel is available at /boot/config-*. + To check the configuration value for CONFIG_DEBUG_CREDENTIALS, run the following command: + grep CONFIG_DEBUG_CREDENTIALS /boot/config-* + + For each kernel installed, a line with value "y" should be returned. + + There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. + R16 + This adds sanity checks and validations to credential data structures. + + + + + + + + + Disable kernel debugfs + debugfs is a virtual file system that kernel developers use to put debugging files +into. Enable this option to be able to read and write to these files. + +The configuration that was used to build kernel is available at /boot/config-*. + To check the configuration value for CONFIG_DEBUG_FS, run the following command: + grep CONFIG_DEBUG_FS /boot/config-* + + Configs with value 'n' are not explicitly set in the file, so either commented lines or no + lines should be returned. + + There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. + R15 + To reduce the attack surface, this file system should be disabled if not in use. + + + + + + + + + Enable checks on linked list manipulation + Enable this to turn on extended checks in the linked-list walking routines. + +The configuration that was used to build kernel is available at /boot/config-*. + To check the configuration value for CONFIG_DEBUG_LIST, run the following command: + grep CONFIG_DEBUG_LIST /boot/config-* + + For each kernel installed, a line with value "y" should be returned. + + There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. + R16 + This add sanity checks to manipulation of linked lists structures in the kernel and may +prevent exploits such as CVE-2017-1661, where a race condition and simultaneos operations +caused a list to corrupt. + + + + + + + + + Enable checks on notifier call chains + Enable this to turn on sanity checking for notifier call chains. This is most useful for kernel +developers to make sure that modules properly unregister themselves from notifier chains. + +The configuration that was used to build kernel is available at /boot/config-*. + To check the configuration value for CONFIG_DEBUG_NOTIFIERS, run the following command: + grep CONFIG_DEBUG_NOTIFIERS /boot/config-* + + For each kernel installed, a line with value "y" should be returned. + + There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. + R16 + This provides validation of notifier chains, it checks whether the notifiers are from the +kernel or a module that is still loaded prior to being invoked. + + + + + + + + + Enable checks on scatter-gather (SG) table operations + Scatter-gather tables are mechanism used for high performance I/O on DMA devices. +Enable this to turn on checks on scatter-gather tables. + +The configuration that was used to build kernel is available at /boot/config-*. + To check the configuration value for CONFIG_DEBUG_SG, run the following command: + grep CONFIG_DEBUG_SG /boot/config-* + + For each kernel installed, a line with value "y" should be returned. + + There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. + R16 + This can help find problems with drivers that do not properly initialize their SG tables. + + + + + + + + + Warn on W+X mappings found at boot + Generate a warning if any W+X mappings are found at boot. +This configuration is available from kernel 5.8. + +The configuration that was used to build kernel is available at /boot/config-*. + To check the configuration value for CONFIG_DEBUG_WX, run the following command: + grep CONFIG_DEBUG_WX /boot/config-* + + For each kernel installed, a line with value "y" should be returned. + + There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. + R15 + This is useful for discovering cases where the kernel is leaving W+X mappings after applying NX, +as such mappings are a security risk. +Note that even if the check fails, your kernel is possibly still fine, as W+X mappings are not +a security hole in themselves, what they do is that they make the exploitation of other unfixed +kernel bugs easier. + + + + + + + + + Configure Low Address Space To Protect From User Allocation + This is the portion of low virtual memory which should be protected from userspace allocation. +This configuration is available from kernel 3.14, but may be available if backported +by distros. + +The configuration that was used to build kernel is available at /boot/config-*. +To check the configuration value for CONFIG_DEFAULT_MMAP_MIN_ADDR, run the following command: +grep CONFIG_DEFAULT_MMAP_MIN_ADDR /boot/config-* +For each kernel installed, a line with value should be returned. +If the system architecture is x86_64, the value should be 65536. +If the system architecture is aarch64, the value should be 32768. + There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. + R25 + R27 + Keeping a user from writing to low pages can help reduce the impact of kernel NULL pointer bugs. + + + + + + + + + + Disable /dev/kmem virtual device support + Disable support for the /dev/kmem device. + +The configuration that was used to build kernel is available at /boot/config-*. + To check the configuration value for CONFIG_DEVKMEM, run the following command: + grep CONFIG_DEVKMEM /boot/config-* + + Configs with value 'n' are not explicitly set in the file, so either commented lines or no + lines should be returned. + + There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. + R15 + The /dev/kmem device is rarely used, but can be used for certain kind of kernel debugging +operations. + + + + + + + + + Harden common str/mem functions against buffer overflows + Detect overflows of buffers in common string and memory functions where the compiler can +determine and validate the buffer sizes. +This configuration is available from kernel 4.13, but may be available if backported by distros. + +The configuration that was used to build kernel is available at /boot/config-*. + To check the configuration value for CONFIG_FORTIFY_SOURCE, run the following command: + grep CONFIG_FORTIFY_SOURCE /boot/config-* + + For each kernel installed, a line with value "y" should be returned. + + There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. + R15 + This features helps reduce likelihood of memory corruption of kernel structures. + + + + + + + + + Harden memory copies between kernel and userspace + This option checks for obviously wrong memory regions when copying memory to/from the kernel +(via copy_to_user() and copy_from_user() functions) by rejecting memory ranges that are larger +than the specified heap object, span multiple separately allocated pages, are not on the +process stack, or are part of the kernel text. +This configuration is available from kernel 4.8, and may be available if backported by distros. + +The configuration that was used to build kernel is available at /boot/config-*. + To check the configuration value for CONFIG_HARDENED_USERCOPY, run the following command: + grep CONFIG_HARDENED_USERCOPY /boot/config-* + + For each kernel installed, a line with value "y" should be returned. + + There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. + R15 + This config prevents entire classes of heap overflow exploits and similar kernel memory exposures. + + + + + + + + + + Do not allow usercopy whitelist violations to fallback to object size + This is a temporary option that allows missing usercopy whitelists to be discovered via a WARN() +to the kernel log, instead of rejecting the copy, falling back to non-whitelisted hardened +usercopy that checks the slab allocation size instead of the whitelist size. +This configuration is available from kernel 4.16. + +The configuration that was used to build kernel is available at /boot/config-*. + To check the configuration value for CONFIG_HARDENED_USERCOPY_FALLBACK, run the following command: + grep CONFIG_HARDENED_USERCOPY_FALLBACK /boot/config-* + + Configs with value 'n' are not explicitly set in the file, so either commented lines or no + lines should be returned. + + There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. + R15 + This config prevents entire classes of heap overflow exploits and similar kernel memory exposures. + + + + + + + + + Disable hibernation + Enable the suspend to disk (STD) functionality, which is usually called "hibernation" in user +interfaces. STD checkpoints the system and powers it off; and restores that checkpoint on +reboot. + +The configuration that was used to build kernel is available at /boot/config-*. + To check the configuration value for CONFIG_HIBERNATION, run the following command: + grep CONFIG_HIBERNATION /boot/config-* + + Configs with value 'n' are not explicitly set in the file, so either commented lines or no + lines should be returned. + + There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. + R23 + Suspending to disk allows one to replace the running kernel. + + + + + + + + + Disable IA32 emulation + Disables support for legacy 32-bit programs under a 64-bit kernel. + +The configuration that was used to build kernel is available at /boot/config-*. + To check the configuration value for CONFIG_IA32_EMULATION, run the following command: + grep CONFIG_IA32_EMULATION /boot/config-* + + Configs with value 'n' are not explicitly set in the file, so either commented lines or no + lines should be returned. + + There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. + Only disable support for 32-bit programs if you are sure you don't need any 32-bit program. + R25 + Disabling 32-bit backwards compatibility helps reduce the attack surface. + + + + + + + + + + Disable the IPv6 protocol + Disable support for IP version 6 (IPv6). + +The configuration that was used to build kernel is available at /boot/config-*. + To check the configuration value for CONFIG_IPV6, run the following command: + grep CONFIG_IPV6 /boot/config-* + + Configs with value 'n' are not explicitly set in the file, so either commented lines or no + lines should be returned. + + There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. + Any unnecessary network stacks, including IPv6, should be disabled to reduce +the vulnerability to exploitation. + + + + + + + + + Disable kexec system call + kexec is a system call that implements the ability to shutdown your current kernel, +and to start another kernel. It is like a reboot but it is independent of the system firmware. +And like a reboot you can start any kernel with it, not just Linux. + +The configuration that was used to build kernel is available at /boot/config-*. + To check the configuration value for CONFIG_KEXEC, run the following command: + grep CONFIG_KEXEC /boot/config-* + + Configs with value 'n' are not explicitly set in the file, so either commented lines or no + lines should be returned. + + There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. + R23 + Prohibits the execution of a new kernel image after reboot. + + + + + + + + + Disable legacy (BSD) PTY support + Disable the Linux traditional BSD-like terminal names /dev/ptyxx for masters and /dev/ttyxx for +slaves of pseudo terminals, and use only the modern ptys (devpts) interface. + +The configuration that was used to build kernel is available at /boot/config-*. + To check the configuration value for CONFIG_LEGACY_PTYS, run the following command: + grep CONFIG_LEGACY_PTYS /boot/config-* + + Configs with value 'n' are not explicitly set in the file, so either commented lines or no + lines should be returned. + + There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. + R23 + The legacy scheme has a number of security problems. + + + + + + + + + Disable vsyscall emulation + The kernel traps and emulates calls into the fixed vsyscall address mapping. +This configuration is available from kernel 5.3, but may be available if backported by distros. + +The configuration that was used to build kernel is available at /boot/config-*. + To check the configuration value for CONFIG_LEGACY_VSYSCALL_EMULATE, run the following command: + grep CONFIG_LEGACY_VSYSCALL_EMULATE /boot/config-* + + Configs with value 'n' are not explicitly set in the file, so either commented lines or no + lines should be returned. + + There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. + R15 + The mapping is non-executable, but it still contains known contents, which could be +used in certain rare security vulnerability exploits. + + + + + + + + + Disable vsyscall mapping + This config disables the vsyscall mapping at all. Attempts to use the vsyscalls will be reported to +dmesg, so that either old or malicious userspace programs can be identified. +This configuration is available from kernel 4.4. + +The configuration that was used to build kernel is available at /boot/config-*. + To check the configuration value for CONFIG_LEGACY_VSYSCALL_NONE, run the following command: + grep CONFIG_LEGACY_VSYSCALL_NONE /boot/config-* + + For each kernel installed, a line with value "y" should be returned. + + There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. + R15 + This will eliminate any risk of ASLR bypass due to the vsyscall fixed address mapping. + + + + + + + + + Disable vsyscall emulate execution only + The kernel traps and emulates calls into the fixed vsyscall address mapping and does not allow +reads. +This configuration is available from kernel 5.3. + +The configuration that was used to build kernel is available at /boot/config-*. + To check the configuration value for CONFIG_LEGACY_VSYSCALL_XONLY, run the following command: + grep CONFIG_LEGACY_VSYSCALL_XONLY /boot/config-* + + Configs with value 'n' are not explicitly set in the file, so either commented lines or no + lines should be returned. + + There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. + R15 + Disabling this mitigates certain uses of the vsyscall area as an ASLR-bypassing buffer. + + + + + + + + + Disable the LDT (local descriptor table) + Linux can allow user programs to install a per-process x86 Local Descriptor Table (LDT) using +the modify_ldt(2) system call. This is required to run 16-bit or segmented code such as DOSEMU +or some Wine programs. It is also used by some very old threading libraries. +This configuration is available from kernel 4.3, but may be available if backported +by distros. + +Disable LDT if 16-bit program emulation is not necessary. + +The configuration that was used to build kernel is available at /boot/config-*. + To check the configuration value for CONFIG_MODIFY_LDT_SYSCALL, run the following command: + grep CONFIG_MODIFY_LDT_SYSCALL /boot/config-* + + Configs with value 'n' are not explicitly set in the file, so either commented lines or no + lines should be returned. + + There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. + R25 + Disabling support for unnecessary code reduces attack surface. + + + + + + + + + + Enable module signature verification + Check modules for valid signatures upon load. +Note that this option adds the OpenSSL development packages as a kernel build dependency so +that the signing tool can use its crypto library. + +The configuration that was used to build kernel is available at /boot/config-*. + To check the configuration value for CONFIG_MODULE_SIG, run the following command: + grep CONFIG_MODULE_SIG /boot/config-* + + For each kernel installed, a line with value "y" should be returned. + + There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. + R18 + Loaded modules must be signed. + + + + + + + + + Enable automatic signing of all modules + Sign all modules during make modules_install. Without this option, modules must be signed +manually, using the scripts/sign-file tool. + +The configuration that was used to build kernel is available at /boot/config-*. + To check the configuration value for CONFIG_MODULE_SIG_ALL, run the following command: + grep CONFIG_MODULE_SIG_ALL /boot/config-* + + For each kernel installed, a line with value "y" should be returned. + + There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. + R18 + This ensures the modules are signed during install process. + + + + + + + + + Require modules to be validly signed + Reject unsigned modules or signed modules with an unknown key. + +The configuration that was used to build kernel is available at /boot/config-*. + To check the configuration value for CONFIG_MODULE_SIG_FORCE, run the following command: + grep CONFIG_MODULE_SIG_FORCE /boot/config-* + + For each kernel installed, a line with value "y" should be returned. + + There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. + R18 + Prevent loading modules that are unsigned or signed with an unknown key. + + + + + + + + + Specify the hash to use when signing modules + This configures the kernel to build and sign modules using + as the hash function. + +The configuration that was used to build kernel is available at /boot/config-*. + To check the configuration value for CONFIG_MODULE_SIG_HASH, run the following command: + grep CONFIG_MODULE_SIG_HASH /boot/config-* + + For each kernel installed, a line with value "" should be returned. + + There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. + R18 + Use of strong hash function is important to secure the module against counterfeit signatures. + + + + + + + + + + Specify module signing key to use + Setting this option to something other than its default of certs/signing_key.pem will +disable the autogeneration of signing keys and allow the kernel modules to be signed with a key +of your choosing. + +The string provided should identify a file containing both a private key and +its corresponding X.509 certificate in PEM form, or — on systems where the OpenSSL ENGINE_pkcs11 +is functional — a PKCS#11 URI as defined by RFC7512. In the latter case, the PKCS#11 URI should +reference both a certificate and a private key. + +The configuration that was used to build kernel is available at /boot/config-*. + To check the configuration value for CONFIG_MODULE_SIG_KEY, run the following command: + grep CONFIG_MODULE_SIG_KEY /boot/config-* + + For each kernel installed, a line with value "" should be returned. + + There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. + R18 + A key and certificate is required to sign the built modules. + + + + + + + + + + Sign kernel modules with SHA-512 + This configures the kernel to build and sign modules using SHA512 as the hash function. + +The configuration that was used to build kernel is available at /boot/config-*. + To check the configuration value for CONFIG_MODULE_SIG_SHA512, run the following command: + grep CONFIG_MODULE_SIG_SHA512 /boot/config-* + + For each kernel installed, a line with value "y" should be returned. + + There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. + R18 + Use of strong hash function is important to secure the module against counterfeit signatures. + + + + + + + + + Enable poison of pages after freeing + Fill the pages with poison patterns after free_pages() and verify the patterns before +alloc_pages. This does have a potential performance impact if enabled with the "page_poison=1" +kernel boot option. +This configuration is available from kernel 4.6. + +The configuration that was used to build kernel is available at /boot/config-*. + To check the configuration value for CONFIG_PAGE_POISONING, run the following command: + grep CONFIG_PAGE_POISONING /boot/config-* + + For each kernel installed, a line with value "y" should be returned. + + There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. + R17 + The filling of the memory helps reduce the risk of information leaks from freed data. + + + + + + + + + Enable poison without sanity check + Skip the sanity checking on alloc, only fill the pages with poison on free. This reduces some +of the overhead of the poisoning feature. +This configuration is available from kernel 4.6. + +The configuration that was used to build kernel is available at /boot/config-*. + To check the configuration value for CONFIG_PAGE_POISONING_NO_SANITY, run the following command: + grep CONFIG_PAGE_POISONING_NO_SANITY /boot/config-* + + For each kernel installed, a line with value "y" should be returned. + + There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. + R17 + This configuration helps alleviates the performance impact of poisonining. + + + + + + + + + Use zero for poisoning instead of debugging value + Instead of using the existing poison value, fill the pages with zeros. This makes it harder to +detect when errors are occurring due to sanitization but the zeroing at free means that it is +no longer necessary to write zeros when GFP_ZERO is used on allocation. +This configuration is available from kernel 4.19. + +The configuration that was used to build kernel is available at /boot/config-*. + To check the configuration value for CONFIG_PAGE_POISONING_ZERO, run the following command: + grep CONFIG_PAGE_POISONING_ZERO /boot/config-* + + For each kernel installed, a line with value "y" should be returned. + + There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. + R17 + This configuration helps alleviates the performance impact of poisonining. + + + + + + + + + Remove the kernel mapping in user mode + This feature reduces the number of hardware side channels by ensuring that the majority of +kernel addresses are not mapped into userspace. +This configuration is available from kernel 4.15, but may be available if backported +by distros. + +The configuration that was used to build kernel is available at /boot/config-*. + To check the configuration value for CONFIG_PAGE_TABLE_ISOLATION, run the following command: + grep CONFIG_PAGE_TABLE_ISOLATION /boot/config-* + + For each kernel installed, a line with value "y" should be returned. + + There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. + R25 + This is a countermeasure to the Meltdown attack. + + + + + + + + + + Kernel panic oops + Enable the kernel to panic when it oopses. +This has the same effect as setting oops=panic on the kernel command line. + +The configuration that was used to build kernel is available at /boot/config-*. + To check the configuration value for CONFIG_PANIC_ON_OOPS, run the following command: + grep CONFIG_PANIC_ON_OOPS /boot/config-* + + For each kernel installed, a line with value "y" should be returned. + + There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. + R19 + This feature ensures that the kernel does not do anything erroneous after an oops which +could result in data corruption or other issues. + + + + + + + + + Kernel panic timeout + Set the timeout value (in seconds) until a reboot occurs when the kernel panics. +A timeout of 0 configures the system to wait forever. With a timeout value greater than 0, +the system will wait the specified amount of seconds before rebooting. While a timeout value +less than 0 makes the system reboot immediately. + +The configuration that was used to build kernel is available at /boot/config-*. + To check the configuration value for CONFIG_PANIC_TIMEOUT, run the following command: + grep CONFIG_PANIC_TIMEOUT /boot/config-* + + For each kernel installed, a line with value "" should be returned. + + There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. + R19 + This is required to enable protection against Spectre v2. + + + + + + + + + + Disable support for /proc/kkcore + Provides a virtual ELF core file of the live kernel. + +The configuration that was used to build kernel is available at /boot/config-*. + To check the configuration value for CONFIG_PROC_KCORE, run the following command: + grep CONFIG_PROC_KCORE /boot/config-* + + Configs with value 'n' are not explicitly set in the file, so either commented lines or no + lines should be returned. + + There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. + R15 + This feature exposes the memory to the userspace and can assist an attacker in discovering +attack vectors. + + + + + + + + + Randomize the address of the kernel image (KASLR) + In support of Kernel Address Space Layout Randomization (KASLR), this randomizes the physical +address at which the kernel image is decompressed and the virtual address where the kernel +image is mapped. + +The configuration that was used to build kernel is available at /boot/config-*. + To check the configuration value for CONFIG_RANDOMIZE_BASE, run the following command: + grep CONFIG_RANDOMIZE_BASE /boot/config-* + + For each kernel installed, a line with value "y" should be returned. + + There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. + R25 + R27 + An unpredictable kernel address makes it more difficult to succeed with exploits that rely on +knowledge of the location of kernel code internals. + + + + + + + + + Randomize the kernel memory sections + Randomizes the base virtual address of kernel memory sections (physical memory mapping, +vmalloc & vmemmap). +This configuration is available from kernel 4.8, but may be available if backported +by distros. + +The configuration that was used to build kernel is available at /boot/config-*. + To check the configuration value for CONFIG_RANDOMIZE_MEMORY, run the following command: + grep CONFIG_RANDOMIZE_MEMORY /boot/config-* + + For each kernel installed, a line with value "y" should be returned. + + There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. + R25 + This security feature makes exploits relying on predictable memory locations less reliable. + + + + + + + + + + Perform full reference count validation + Enabling this switches the refcounting infrastructure from a fast unchecked atomic_t +implementation to a fully state checked implementation, which can have a slight +impact in performance. +This configuration is available from kernel 4.13, but may be available if backported +by distros. + +The configuration that was used to build kernel is available at /boot/config-*. + To check the configuration value for CONFIG_REFCOUNT_FULL, run the following command: + grep CONFIG_REFCOUNT_FULL /boot/config-* + + For each kernel installed, a line with value "y" should be returned. + + There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. + R15 + Refcounting provides protections against various use-after-free conditions that can be +used in security flaw exploits. + + + + + + + + + Avoid speculative indirect branches in kernel + Compile kernel with the retpoline compiler options to guard against kernel-to-user data leaks +by avoiding speculative indirect branches. +Requires a compiler with -mindirect-branch=thunk-extern support for full protection. +The kernel may run slower. + +The configuration that was used to build kernel is available at /boot/config-*. + To check the configuration value for CONFIG_RETPOLINE, run the following command: + grep CONFIG_RETPOLINE /boot/config-* + + For each kernel installed, a line with value "y" should be returned. + + There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. + R15 + This is required to enable protection against Spectre v2. + + + + + + + + + Detect stack corruption on calls to schedule() + This option checks for a stack overrun on calls to schedule(). If the stack end location is +found to be overwritten always panic as the content of the corrupted region can no longer +be trusted. +This configuration is available from kernel 3.18. + +The configuration that was used to build kernel is available at /boot/config-*. + To check the configuration value for CONFIG_SCHED_STACK_END_CHECK, run the following command: + grep CONFIG_SCHED_STACK_END_CHECK /boot/config-* + + For each kernel installed, a line with value "y" should be returned. + + There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. + R15 + This ensures no erroneous behaviour occurs which could result in data corruption or a +sporadic crash at a later stage once the region is examined. + + + + + + + + + Enable seccomp to safely compute untrusted bytecode + This kernel feature is useful for number crunching applications that may need to compute +untrusted bytecode during their execution. By using pipes or other transports made available +to the process as file descriptors supporting the read/write syscalls, it's possible to isolate +those applications in their own address space using seccomp. + +The configuration that was used to build kernel is available at /boot/config-*. + To check the configuration value for CONFIG_SECCOMP, run the following command: + grep CONFIG_SECCOMP /boot/config-* + + For each kernel installed, a line with value "y" should be returned. + + There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. + R20 + seccomp enables the ability to filter system calls made by an application, effectively +isolating the system's resources from it. + + + + + + + + + Enable use of Berkeley Packet Filter with seccomp + Enable tasks to build secure computing environments defined in terms of Berkeley Packet Filter +programs which implement task-defined system call filtering polices. + +The configuration that was used to build kernel is available at /boot/config-*. + To check the configuration value for CONFIG_SECCOMP_FILTER, run the following command: + grep CONFIG_SECCOMP_FILTER /boot/config-* + + For each kernel installed, a line with value "y" should be returned. + + There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. + R20 + Use of BPF filters allows for expressive filtering of system calls using a filter program +language with a long history of being exposed to userland. + + + + + + + + + Enable different security models + This allows you to choose different security modules to be configured into your kernel. + +The configuration that was used to build kernel is available at /boot/config-*. + To check the configuration value for CONFIG_SECURITY, run the following command: + grep CONFIG_SECURITY /boot/config-* + + For each kernel installed, a line with value "y" should be returned. + + There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. + R20 + This is enables kernel security primitives required by the LSM framework. + + + + + + + + + Restrict unprivileged access to the kernel syslog + Enforce restrictions on unprivileged users reading the kernel syslog via dmesg(8). + +The configuration that was used to build kernel is available at /boot/config-*. + To check the configuration value for CONFIG_SECURITY_DMESG_RESTRICT, run the following command: + grep CONFIG_SECURITY_DMESG_RESTRICT /boot/config-* + + For each kernel installed, a line with value "y" should be returned. + + There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. + R15 + Prevents unprivileged users from retrieving kernel addresses with dmesg. + + + + + + + + + Disable mutable hooks + Ensure kernel structures associated with LSMs are always mapped as read-only after system boot. + +The configuration that was used to build kernel is available at /boot/config-*. + To check the configuration value for CONFIG_SECURITY_WRITABLE_HOOKS, run the following command: + grep CONFIG_SECURITY_WRITABLE_HOOKS /boot/config-* + + Configs with value 'n' are not explicitly set in the file, so either commented lines or no + lines should be returned. + + There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. + R20 + If CONFIG_SECURITY_WRITABLE_HOOKS is enabled, then hooks can be loaded at runtime and +being able to manipulate hooks is a way to bypass all LSMs. + + + + + + + + + Enable Yama support + This enables support for LSM module Yama, which extends DAC support with additional system-wide +security settings beyond regular Linux discretionary access controls. The module will limit the +use of the system call ptrace(). + +The configuration that was used to build kernel is available at /boot/config-*. + To check the configuration value for CONFIG_SECURITY_YAMA, run the following command: + grep CONFIG_SECURITY_YAMA /boot/config-* + + For each kernel installed, a line with value "y" should be returned. + + There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. + R20 + Unrestricted usage of ptrace allows compromised binaries to run ptrace +on another processes of the user. + + + + + + + + + Harden slab freelist metadata + This feature protects integrity of the allocator's metadata. +This configuration is available from kernel 4.14. + +The configuration that was used to build kernel is available at /boot/config-*. + To check the configuration value for CONFIG_SLAB_FREELIST_HARDENED, run the following command: + grep CONFIG_SLAB_FREELIST_HARDENED /boot/config-* + + For each kernel installed, a line with value "y" should be returned. + + There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. + R17 + Many kernel heap attacks try to target slab cache metadata and other infrastructure. +This options makes minor performance sacrifices to harden the kernel slab allocator against +common freelist exploit methods. + + + + + + + + + Randomize slab freelist + Randomizes the freelist order used on creating new pages. +This configuration is available from kernel 5.9, but may be available if backported by distros. + +The configuration that was used to build kernel is available at /boot/config-*. + To check the configuration value for CONFIG_SLAB_FREELIST_RANDOM, run the following command: + grep CONFIG_SLAB_FREELIST_RANDOM /boot/config-* + + For each kernel installed, a line with value "y" should be returned. + + There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. + R17 + This security feature reduces the predictability of the kernel slab allocator against heap overflows. + + + + + + + + + Disallow merge of slab caches + For reduced kernel memory fragmentation, slab caches can be merged when they share the same +size and other characteristics. This carries a risk of kernel heap overflows being able to +overwrite objects from merged caches (and more easily control cache layout), which makes such +heap attacks easier to exploit by attackers. +This configuration is available from kernel 4.13. + +The configuration that was used to build kernel is available at /boot/config-*. + To check the configuration value for CONFIG_SLAB_MERGE_DEFAULT, run the following command: + grep CONFIG_SLAB_MERGE_DEFAULT /boot/config-* + + Configs with value 'n' are not explicitly set in the file, so either commented lines or no + lines should be returned. + + There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. + R17 + Disabling the merge of slabs of similar sizes prevents the kernel from +merging a seemingly useless but vulnerable slab with a useful and valuable slab. +This increase the risk that a heap overflow could overwrite objects from merged caches, +with unmerged caches the heap overflow would only affect the objects in the same cache. +Overall, this reduces the kernel attack surface area by isolating slabs from each other. + + + + + + + + + Enable SLUB debugging support + SLUB has extensive debug support features and this allows the allocator validation checking to +be enabled. + +The configuration that was used to build kernel is available at /boot/config-*. + To check the configuration value for CONFIG_SLUB_DEBUG, run the following command: + grep CONFIG_SLUB_DEBUG /boot/config-* + + For each kernel installed, a line with value "y" should be returned. + + There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. + R17 + This activates the checking of the memory allocator structures and resets to zero the zones +allocated when they are released. + + + + + + + + + Stack Protector buffer overlow detection + This feature puts, at the beginning of functions, a canary value on the stack just before the +return address, and validates the value just before actually returning. +This configuration is available from kernel 4.18. + +The configuration that was used to build kernel is available at /boot/config-*. + To check the configuration value for CONFIG_STACKPROTECTOR, run the following command: + grep CONFIG_STACKPROTECTOR /boot/config-* + + For each kernel installed, a line with value "y" should be returned. + + There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. + R15 + This halts the program when a stack overflow is detected, potentially reducing the impact of +exploits. + + + + + + + + + Strong Stack Protector + This features adds canary logic protection to more kinds of vulnerable functions than +CONFIG_STACKPROTECTOR, but not to all functions so that performance is not severily impacted. +This configuration is available from kernel 4.18. +This config requires gcc version 4.9 or above, or a distribution gcc with the feature +backported ("-fstack-protector-strong"). + +The configuration that was used to build kernel is available at /boot/config-*. + To check the configuration value for CONFIG_STACKPROTECTOR_STRONG, run the following command: + grep CONFIG_STACKPROTECTOR_STRONG /boot/config-* + + For each kernel installed, a line with value "y" should be returned. + + There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. + R15 + This provides a mechanism that protects more vulnerable functions than CONFIG_STACKPROTECTOR, +balancing between security and performance. + + + + + + + + + Make the kernel text and rodata read-only + When set, kernel text and rodata memory will be made read-only, and non-text memory will be made non-executable. +This configuration is available from kernel 4.11. + +The configuration that was used to build kernel is available at /boot/config-*. + To check the configuration value for CONFIG_STRICT_KERNEL_RWX, run the following command: + grep CONFIG_STRICT_KERNEL_RWX /boot/config-* + + For each kernel installed, a line with value "y" should be returned. + + There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. + R15 + This provides protection against certain security exploits (e.g. executing the heap or modifying text) + + + + + + + + + Make the module text and rodata read-only + When set, module text and rodata memory will be made read-only, and non-text memory will be made non-executable. +This configuration is available from kernel 4.11. + +The configuration that was used to build kernel is available at /boot/config-*. + To check the configuration value for CONFIG_STRICT_MODULE_RWX, run the following command: + grep CONFIG_STRICT_MODULE_RWX /boot/config-* + + For each kernel installed, a line with value "y" should be returned. + + There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. + R18 + This provides protection against certain security exploits (e.g. executing the heap or modifying text) + + + + + + + + + Enable TCP/IP syncookie support + Normal TCP/IP networking is open to an attack known as SYN flooding. +It is denial-of-service attack that prevents legitimate remote users from being able to connect +to your computer during an ongoing attack. + +When enabled the TCP/IP stack will use a cryptographic challenge protocol known as SYN cookies +to enable legitimate users to continue to connect, even when your machine is under attack. + +The configuration that was used to build kernel is available at /boot/config-*. + To check the configuration value for CONFIG_SYN_COOKIES, run the following command: + grep CONFIG_SYN_COOKIES /boot/config-* + + For each kernel installed, a line with value "y" should be returned. + + There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. + R22 + SYN cookies provide protection against SYN flooding attacks. + + + + + + + + + Unmap kernel when running in userspace (aka KAISER) + Speculation attacks against some high-performance processors can be used to bypass MMU +permission checks and leak kernel data to userspace. This can be defended against by unmapping +the kernel when running in userspace, mapping it back in on exception entry via a trampoline +page in the vector table. +This configuration is available from kernel 4.16, but may be available if backported +by distros. +The configuration that was used to build kernel is available at /boot/config-*. + To check the configuration value for CONFIG_UNMAP_KERNEL_AT_EL0, run the following command: + grep CONFIG_UNMAP_KERNEL_AT_EL0 /boot/config-* + + For each kernel installed, a line with value "y" should be returned. + + There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. + R27 + This is a countermeasure to the Meltdown attack. + + + + + + + + + + User a virtually-mapped stack + Enable this to use virtually-mapped kernel stacks with guard pages. +This configuration is available from kernel 4.9. + +The configuration that was used to build kernel is available at /boot/config-*. + To check the configuration value for CONFIG_VMAP_STACK, run the following command: + grep CONFIG_VMAP_STACK /boot/config-* + + For each kernel installed, a line with value "y" should be returned. + + There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. + R15 + This causes kernel stack overflows to be caught immediately rather than causing difficult-to-diagnose corruption. + + + + + + + + + Disable x86 vsyscall emulation + Disabling it is roughly equivalent to booting with vsyscall=none, except that it will also +disable the helpful warning if a program tries to use a vsyscall. With this option set to N, +offending programs will just segfault, citing addresses of the form 0xffffffffff600?00. +This configuration is available from kernel 3.19. + +The configuration that was used to build kernel is available at /boot/config-*. + To check the configuration value for CONFIG_X86_VSYSCALL_EMULATION, run the following command: + grep CONFIG_X86_VSYSCALL_EMULATION /boot/config-* + + Configs with value 'n' are not explicitly set in the file, so either commented lines or no + lines should be returned. + + There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. + R15 + The vsyscall table is no longer required and is a potential source of ROP gadgets. + + + + + + + + + Kernel GCC plugin configuration + Contains rules that check the configuration of GCC plugins used by the compiler + + Generate some entropy during boot and runtime + Instrument some kernel code to extract some entropy from both original and artificially created +program state. This will help especially embedded systems where there is little 'natural' source +of entropy normally. + +This configuration is available from kernel 4.9, but may be available if backported +by distros. + +The configuration that was used to build kernel is available at /boot/config-*. + To check the configuration value for CONFIG_GCC_PLUGIN_LATENT_ENTROPY, run the following command: + grep CONFIG_GCC_PLUGIN_LATENT_ENTROPY /boot/config-* + + For each kernel installed, a line with value "y" should be returned. + + There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. + Note that entropy extracted this way is not cryptographically secure! + There is a performance cost during the boot process (about 0.5%) and fork and irq processing. + R21 + This helps generate entropy during startup and is particularly relevant for devices with +inappropriate entropy sources. + + + + + + + + + Randomize layout of sensitive kernel structures + Randomize at compile-time the layouts of structures that are entirely function pointers +(and have not been manually annotated with __no_randomize_layout), or structures that have +been explicitly marked with __randomize_layout. +This configuration is available from kernel 4.13, but may be available if backported +by distros. + +The configuration that was used to build kernel is available at /boot/config-*. + To check the configuration value for CONFIG_GCC_PLUGIN_RANDSTRUCT, run the following command: + grep CONFIG_GCC_PLUGIN_RANDSTRUCT /boot/config-* + + For each kernel installed, a line with value "y" should be returned. + + There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. + R21 + Randomizing the layout of kernel data structures make it more difficult for an attacker to +know the location of sensitive data. + + + + + + + + + Poison kernel stack before returning from syscalls + This option makes the kernel erase the kernel stack before returning from system calls. +This has the effect of leaving the stack initialized to the poison value, which both reduces +the lifetime of any sensitive stack contents and reduces potential for uninitialized stack +variable exploits or information exposures (it does not cover functions reaching the same +stack depth as prior functions during the same syscall). + +This configuration is available from kernel 4.20, but may be available if backported +by distros. + +The configuration that was used to build kernel is available at /boot/config-*. + To check the configuration value for CONFIG_GCC_PLUGIN_STACKLEAK, run the following command: + grep CONFIG_GCC_PLUGIN_STACKLEAK /boot/config-* + + For each kernel installed, a line with value "y" should be returned. + + There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. + The performance impact on a single CPU system kernel is of 1% slowdown. + R21 + This blocks most uninitialized stack variable attacks, with the performance impact being +driven by the depth of the stack usage, rather than the function calling complexity. + + + + + + + + + Force initialization of variables containing userspace addresses + While the kernel is built with warnings enabled for any missed stack variable initializations, +this warning is silenced for anything passed by reference to another function, under the +occasionally misguided assumption that the function will do the initialization. As this +regularly leads to exploitable flaws, this plugin is available to identify and zero-initialize +such variables, depending on the chosen level of coverage. +This configuration is available from kernel 4.11, but may be available if backported +by distros. + +The configuration that was used to build kernel is available at /boot/config-*. + To check the configuration value for CONFIG_GCC_PLUGIN_STRUCTLEAK, run the following command: + grep CONFIG_GCC_PLUGIN_STRUCTLEAK /boot/config-* + + For each kernel installed, a line with value "y" should be returned. + + There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. + R21 + Initializing structures from userspace can prevent some classes of information exposure. + + + + + + + + + zero-init everything passed by reference + Zero-initialize any stack variables that may be passed by reference and had not already been explicitly initialized. +This configuration is available from kernel 4.14, but may be available if backported +by distros. + +The configuration that was used to build kernel is available at /boot/config-*. + To check the configuration value for CONFIG_GCC_PLUGIN_STRUCTLEAK_BYREF_ALL, run the following command: + grep CONFIG_GCC_PLUGIN_STRUCTLEAK_BYREF_ALL /boot/config-* + + For each kernel installed, a line with value "y" should be returned. + + There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. + R21 + This eliminates all classes of uninitialized stack variable exploits and information exposures. + + + + + + + + + + + Configure Syslog + The syslog service has been the default Unix logging mechanism for +many years. It has a number of downsides, including inconsistent log format, +lack of authentication for received messages, and lack of authentication, +encryption, or reliable transport for messages sent over a network. However, +due to its long history, syslog is a de facto standard which is supported by +almost all Unix applications. + + +In Oracle Linux 9, rsyslog has replaced ksyslogd as the +syslog daemon of choice, and it includes some additional security features +such as reliable, connection-oriented (i.e. TCP) transmission of logs, the +option to log to database formats, and the encryption of log data en route to +a central logging server. +This section discusses how to configure rsyslog for +best effect, and how to use tools provided with the system to maintain and +monitor logs. + + + Ensure rsyslog-gnutls is installed + TLS protocol support for rsyslog is installed. + +The rsyslog-gnutls package can be installed with the following command: + +$ sudo yum install rsyslog-gnutls + + CCI-000366 + CCI-000803 + SRG-OS-000480-GPOS-00227 + SRG-OS-000120-GPOS-00061 + R71 + OL09-00-000355 + SV-271510r1091242_rule + The rsyslog-gnutls package provides Transport Layer Security (TLS) support +for the rsyslog daemon, which enables secure remote logging. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +if ! rpm -q --quiet "rsyslog-gnutls" ; then + yum install -y "rsyslog-gnutls" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-000355 + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - package_rsyslog-gnutls_installed + +- name: Ensure rsyslog-gnutls is installed + package: + name: rsyslog-gnutls + state: present + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-000355 + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - package_rsyslog-gnutls_installed + + include install_rsyslog-gnutls + +class install_rsyslog-gnutls { + package { 'rsyslog-gnutls': + ensure => 'installed', + } +} + + +package --add=rsyslog-gnutls + + +[[packages]] +name = "rsyslog-gnutls" +version = "*" + + + + + + + + + + Ensure rsyslog is Installed + Rsyslog is installed by default. The rsyslog package can be installed with the following command: $ sudo yum install rsyslog + + 1 + 14 + 15 + 16 + 3 + 5 + 6 + APO11.04 + BAI03.05 + DSS05.04 + DSS05.07 + MEA02.01 + CCI-000366 + CCI-000154 + CCI-001851 + 164.312(a)(2)(ii) + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.4.4.7 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.8 + SR 2.9 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + CM-6(a) + PR.PT-1 + SRG-OS-000479-GPOS-00224 + SRG-OS-000051-GPOS-00024 + SRG-OS-000480-GPOS-00227 + OL09-00-000350 + SV-271508r1091236_rule + The rsyslog package provides the rsyslog daemon, which provides +system logging services. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +if ! rpm -q --quiet "rsyslog" ; then + yum install -y "rsyslog" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-000350 + - NIST-800-53-CM-6(a) + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - package_rsyslog_installed + +- name: Ensure rsyslog is installed + package: + name: rsyslog + state: present + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-000350 + - NIST-800-53-CM-6(a) + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - package_rsyslog_installed + + include install_rsyslog + +class install_rsyslog { + package { 'rsyslog': + ensure => 'installed', + } +} + + +package --add=rsyslog + + +[[packages]] +name = "rsyslog" +version = "*" + + + + + + + + + + Enable rsyslog Service + The rsyslog service provides syslog-style logging by default on Oracle Linux 9. + +The rsyslog service can be enabled with the following command: +$ sudo systemctl enable rsyslog.service + + 1 + 12 + 13 + 14 + 15 + 16 + 2 + 3 + 5 + 6 + 7 + 8 + 9 + APO10.01 + APO10.03 + APO10.04 + APO10.05 + APO11.04 + APO13.01 + BAI03.05 + BAI04.04 + DSS01.03 + DSS03.05 + DSS05.02 + DSS05.04 + DSS05.05 + DSS05.07 + MEA01.01 + MEA01.02 + MEA01.03 + MEA01.04 + MEA01.05 + MEA02.01 + CCI-000366 + 164.312(a)(2)(ii) + 4.3.2.6.7 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.4.4.7 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.8 + SR 2.9 + SR 6.1 + SR 6.2 + SR 7.1 + SR 7.2 + A.12.1.3 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.14.2.7 + A.15.2.1 + A.15.2.2 + A.17.2.1 + CM-6(a) + AU-4(1) + DE.CM-1 + DE.CM-3 + DE.CM-7 + ID.SC-4 + PR.DS-4 + PR.PT-1 + SRG-OS-000480-GPOS-00227 + OL09-00-000351 + SV-271509r1091239_rule + The rsyslog service must be running in order to provide +logging services, which are essential to system administration. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +SYSTEMCTL_EXEC='/usr/bin/systemctl' +"$SYSTEMCTL_EXEC" unmask 'rsyslog.service' +if [[ $("$SYSTEMCTL_EXEC" is-system-running) != "offline" ]]; then + "$SYSTEMCTL_EXEC" start 'rsyslog.service' +fi +"$SYSTEMCTL_EXEC" enable 'rsyslog.service' + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-000351 + - NIST-800-53-AU-4(1) + - NIST-800-53-CM-6(a) + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_rsyslog_enabled + +- name: Enable rsyslog Service - Enable service rsyslog + block: + + - name: Gather the package facts + package_facts: + manager: auto + + - name: Enable rsyslog Service - Enable Service rsyslog + ansible.builtin.systemd: + name: rsyslog + enabled: true + state: started + masked: false + when: + - '"rsyslog" in ansible_facts.packages' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-000351 + - NIST-800-53-AU-4(1) + - NIST-800-53-CM-6(a) + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_rsyslog_enabled + + include enable_rsyslog + +class enable_rsyslog { + service {'rsyslog': + enable => true, + ensure => 'running', + } +} + + +[customizations.services] +enabled = ["rsyslog"] + + + + + + + + + + Ensure Proper Configuration of Log Files + The file /etc/rsyslog.conf controls where log message are written. +These are controlled by lines called rules, which consist of a +selector and an action. +These rules are often customized depending on the role of the system, the +requirements of the environment, and whatever may enable +the administrator to most effectively make use of log data. +The default rules in Oracle Linux 9 are: +*.info;mail.none;authpriv.none;cron.none /var/log/messages +authpriv.* /var/log/secure +mail.* -/var/log/maillog +cron.* /var/log/cron +*.emerg * +uucp,news.crit /var/log/spooler +local7.* /var/log/boot.log +See the man page rsyslog.conf(5) for more information. +Note that the rsyslog daemon can be configured to use a timestamp format that +some log processing programs may not understand. If this occurs, +edit the file /etc/rsyslog.conf and add or edit the following line: + $ ActionFileDefaultTemplate RSYSLOG_TraditionalFileFormat + + + + Ensure cron Is Logging To Rsyslog + Cron logging must be implemented to spot intrusions or trace +cron job status. If cron is not logging to rsyslog, it +can be implemented by adding the following to the RULES section of +/etc/rsyslog.conf: +If the legacy syntax is used: +cron.* /var/log/cron +If the modern syntax (RainerScript) is used: +cron.* action(type="omfile" file="/var/log/cron") + + 1 + 14 + 15 + 16 + 3 + 5 + 6 + APO10.01 + APO10.03 + APO10.04 + APO10.05 + APO11.04 + BAI03.05 + DSS05.04 + DSS05.07 + MEA01.01 + MEA01.02 + MEA01.03 + MEA01.04 + MEA01.05 + MEA02.01 + CCI-000366 + 4.3.2.6.7 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.4.4.7 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.8 + SR 2.9 + SR 6.1 + 0988 + 1405 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.15.2.1 + A.15.2.2 + CM-6(a) + ID.SC-4 + PR.PT-1 + SRG-OS-000480-GPOS-00227 + OL09-00-005010 + SV-271853r1092271_rule + Cron logging can be used to trace the successful or unsuccessful execution +of cron jobs. It can also be used to spot intrusions into the use of the cron +facility by unauthorized and malicious users. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && rpm --quiet -q rsyslog; then + +if ! grep -Pzo '(?m)^\s*(cron|\*)\.\*\s*(/var/log/(cron|messages)|action\(\s*.*(?i:\btype\b)="omfile"\s*.*(?i:\bfile\b)="/var/log/(cron|messages)"\s*\))\s*$' /etc/rsyslog.conf /etc/rsyslog.d/*.conf; then + + mkdir -p /etc/rsyslog.d + echo "cron.* /var/log/cron" >> /etc/rsyslog.d/cron.conf +fi + +if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then + systemctl restart rsyslog.service +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-005010 + - NIST-800-53-CM-6(a) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - rsyslog_cron_logging + +- name: Ensure cron Is Logging To Rsyslog - Search if cron configuration exists + ansible.builtin.command: grep -Pzo '(?m)^\s*(cron|\*)\.\*\s*(/var/log/(cron|messages)|action\(\s*.*(?i:\btype\b)="omfile"\s*.*(?i:\bfile\b)="/var/log/(cron|messages)"\s*\))\s*$' + /etc/rsyslog.conf /etc/rsyslog.d/*.conf + register: cron_log_config_exists + failed_when: false + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-005010 + - NIST-800-53-CM-6(a) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - rsyslog_cron_logging + +- name: Ensure cron Is Logging To Rsyslog - Ensure the /etc/rsyslog.d directory exists + ansible.builtin.file: + path: /etc/rsyslog.d + state: directory + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-005010 + - NIST-800-53-CM-6(a) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - rsyslog_cron_logging + +- name: Ensure cron Is Logging To Rsyslog - Add cron log configuration line + ansible.builtin.lineinfile: + path: /etc/rsyslog.d/cron.conf + line: cron.* /var/log/cron + create: true + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - cron_log_config_exists.stdout_lines | length == 0 + tags: + - DISA-STIG-OL09-00-005010 + - NIST-800-53-CM-6(a) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - rsyslog_cron_logging + +- name: Ensure cron Is Logging To Rsyslog - Restart the rsyslog service now + ansible.builtin.service: + name: rsyslog + state: restarted + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-005010 + - NIST-800-53-CM-6(a) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - rsyslog_cron_logging + + + + + + + + + + Ensure Rsyslog Authenticates Off-Loaded Audit Records + Rsyslogd is a system utility providing support for message logging. Support +for both internet and UNIX domain sockets enables this utility to support both local +and remote logging. Couple this utility with gnutls (which is a secure communications +library implementing the SSL, TLS and DTLS protocols), and you have a method to securely +encrypt and off-load auditing. + +When using rsyslogd to off-load logs the remote system must be authenticated. + +Set the following configuration option in /etc/rsyslog.conf or in a file in /etc/rsyslog.d (using legacy syntax): +$ActionSendStreamDriverAuthMode x509/name +Alternatively, use the RainerScript syntax: +action(type="omfwd" Target="some.example.com" StreamDriverAuthMode="x509/name") + + CCI-001851 + AU-4(1) + SRG-OS-000342-GPOS-00133 + SRG-OS-000479-GPOS-00224 + OL09-00-005015 + SV-271854r1092274_rule + The audit records generated by Rsyslog contain valuable information regarding system +configuration, user authentication, and other such information. Audit records should be +protected from unauthorized access. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && rpm --quiet -q rsyslog; then + +sed -i '/^.*\$ActionSendStreamDriverAuthMode.*/d' /etc/rsyslog.conf /etc/rsyslog.d/*.conf 2> /dev/null + +if [ -e "/etc/rsyslog.d/stream_driver_auth.conf" ] ; then + + LC_ALL=C sed -i "/^\s*\$ActionSendStreamDriverAuthMode /Id" "/etc/rsyslog.d/stream_driver_auth.conf" +else + touch "/etc/rsyslog.d/stream_driver_auth.conf" +fi +# make sure file has newline at the end +sed -i -e '$a\' "/etc/rsyslog.d/stream_driver_auth.conf" + +cp "/etc/rsyslog.d/stream_driver_auth.conf" "/etc/rsyslog.d/stream_driver_auth.conf.bak" +# Insert at the end of the file +printf '%s\n' "\$ActionSendStreamDriverAuthMode x509/name" >> "/etc/rsyslog.d/stream_driver_auth.conf" +# Clean up after ourselves. +rm "/etc/rsyslog.d/stream_driver_auth.conf.bak" + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-005015 + - NIST-800-53-AU-4(1) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - rsyslog_encrypt_offload_actionsendstreamdriverauthmode + +- name: Ensure Rsyslog Authenticates Off-Loaded Audit Records + block: + + - name: Deduplicate values from /etc/rsyslog.conf + lineinfile: + path: /etc/rsyslog.conf + create: false + regexp: (?i)^\s*{{ "$ActionSendStreamDriverAuthMode"| regex_escape }}\s + state: absent + + - name: Check if /etc/rsyslog.d exists + stat: + path: /etc/rsyslog.d + register: _etc_rsyslog_d_exists + + - name: Check if the parameter $ActionSendStreamDriverAuthMode is present in /etc/rsyslog.d + find: + paths: /etc/rsyslog.d + recurse: 'yes' + follow: 'no' + contains: ^\s*{{ "$ActionSendStreamDriverAuthMode"| regex_escape }}\s + register: _etc_rsyslog_d_has_parameter + when: _etc_rsyslog_d_exists.stat.isdir is defined and _etc_rsyslog_d_exists.stat.isdir + + - name: Remove parameter from files in /etc/rsyslog.d + lineinfile: + path: '{{ item.path }}' + create: false + regexp: (?i)^\s*{{ "$ActionSendStreamDriverAuthMode"| regex_escape }}\s + state: absent + with_items: '{{ _etc_rsyslog_d_has_parameter.files }}' + when: _etc_rsyslog_d_has_parameter.matched + + - name: Insert correct line to /etc/rsyslog.conf + lineinfile: + path: /etc/rsyslog.conf + create: true + regexp: (?i)^\s*{{ "$ActionSendStreamDriverAuthMode"| regex_escape }}\s + line: $ActionSendStreamDriverAuthMode x509/name + state: present + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-005015 + - NIST-800-53-AU-4(1) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - rsyslog_encrypt_offload_actionsendstreamdriverauthmode + + + + + + + + + + Ensure Rsyslog Encrypts Off-Loaded Audit Records + Rsyslogd is a system utility providing support for message logging. Support +for both internet and UNIX domain sockets enables this utility to support both local +and remote logging. Couple this utility with gnutls (which is a secure communications +library implementing the SSL, TLS and DTLS protocols), and you have a method to securely +encrypt and off-load auditing. + +When using rsyslogd to off-load logs off a encrpytion system must be used. + +Set the following configuration option in /etc/rsyslog.conf or in a file in /etc/rsyslog.d (using legacy syntax): +$ActionSendStreamDriverMode 1 + +Alternatively, use the RainerScript syntax: +action(type="omfwd" ... StreamDriverMode="1") + + CCI-001851 + AU-4(1) + SRG-OS-000342-GPOS-00133 + SRG-OS-000479-GPOS-00224 + OL09-00-005020 + SV-271855r1092277_rule + The audit records generated by Rsyslog contain valuable information regarding system +configuration, user authentication, and other such information. Audit records should be +protected from unauthorized access. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && rpm --quiet -q rsyslog; then + +if [ -e "/etc/rsyslog.d/encrypt.conf" ] ; then + + LC_ALL=C sed -i "/^\s*\$ActionSendStreamDriverMode /Id" "/etc/rsyslog.d/encrypt.conf" +else + touch "/etc/rsyslog.d/encrypt.conf" +fi +# make sure file has newline at the end +sed -i -e '$a\' "/etc/rsyslog.d/encrypt.conf" + +cp "/etc/rsyslog.d/encrypt.conf" "/etc/rsyslog.d/encrypt.conf.bak" +# Insert at the end of the file +printf '%s\n' "\$ActionSendStreamDriverMode 1" >> "/etc/rsyslog.d/encrypt.conf" +# Clean up after ourselves. +rm "/etc/rsyslog.d/encrypt.conf.bak" + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-005020 + - NIST-800-53-AU-4(1) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - rsyslog_encrypt_offload_actionsendstreamdrivermode + +- name: Ensure Rsyslog Encrypts Off-Loaded Audit Records + block: + + - name: Deduplicate values from /etc/rsyslog.conf + lineinfile: + path: /etc/rsyslog.conf + create: false + regexp: '(?i)^\s*{{ "$ActionSendStreamDriverMode"| regex_escape }} ' + state: absent + + - name: Check if /etc/rsyslog.d exists + stat: + path: /etc/rsyslog.d + register: _etc_rsyslog_d_exists + + - name: Check if the parameter $ActionSendStreamDriverMode is present in /etc/rsyslog.d + find: + paths: /etc/rsyslog.d + recurse: 'yes' + follow: 'no' + contains: '^\s*{{ "$ActionSendStreamDriverMode"| regex_escape }} ' + register: _etc_rsyslog_d_has_parameter + when: _etc_rsyslog_d_exists.stat.isdir is defined and _etc_rsyslog_d_exists.stat.isdir + + - name: Remove parameter from files in /etc/rsyslog.d + lineinfile: + path: '{{ item.path }}' + create: false + regexp: '(?i)^\s*{{ "$ActionSendStreamDriverMode"| regex_escape }} ' + state: absent + with_items: '{{ _etc_rsyslog_d_has_parameter.files }}' + when: _etc_rsyslog_d_has_parameter.matched + + - name: Insert correct line to /etc/rsyslog.conf + lineinfile: + path: /etc/rsyslog.conf + create: true + regexp: '(?i)^\s*{{ "$ActionSendStreamDriverMode"| regex_escape }} ' + line: $ActionSendStreamDriverMode 1 + state: present + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-005020 + - NIST-800-53-AU-4(1) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - rsyslog_encrypt_offload_actionsendstreamdrivermode + + + + + + + + + + Ensure Rsyslog Encrypts Off-Loaded Audit Records + Rsyslogd is a system utility providing support for message logging. Support +for both internet and UNIX domain sockets enables this utility to support both local +and remote logging. Couple this utility with gnutls (which is a secure communications +library implementing the SSL, TLS and DTLS protocols), and you have a method to securely +encrypt and off-load auditing. + +When using rsyslogd to off-load logs off an encryption system must be used. + +Set the following configuration option in /etc/rsyslog.conf or in a file in /etc/rsyslog.d (using legacy syntax): +$DefaultNetstreamDriver gtls + +Alternatively, use the RainerScript syntax: +global(DefaultNetstreamDriver="gtls") + + CCI-001851 + AU-4(1) + SRG-OS-000342-GPOS-00133 + SRG-OS-000479-GPOS-00224 + OL09-00-005025 + SV-271856r1092280_rule + The audit records generated by Rsyslog contain valuable information regarding system +configuration, user authentication, and other such information. Audit records should be +protected from unauthorized access. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && rpm --quiet -q rsyslog; then + +if [ -e "/etc/rsyslog.d/encrypt.conf" ] ; then + + LC_ALL=C sed -i "/^\s*\$DefaultNetstreamDriver /Id" "/etc/rsyslog.d/encrypt.conf" +else + touch "/etc/rsyslog.d/encrypt.conf" +fi +# make sure file has newline at the end +sed -i -e '$a\' "/etc/rsyslog.d/encrypt.conf" + +cp "/etc/rsyslog.d/encrypt.conf" "/etc/rsyslog.d/encrypt.conf.bak" +# Insert at the end of the file +printf '%s\n' "\$DefaultNetstreamDriver gtls" >> "/etc/rsyslog.d/encrypt.conf" +# Clean up after ourselves. +rm "/etc/rsyslog.d/encrypt.conf.bak" + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-005025 + - NIST-800-53-AU-4(1) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - rsyslog_encrypt_offload_defaultnetstreamdriver + +- name: Ensure Rsyslog Encrypts Off-Loaded Audit Records + block: + + - name: Deduplicate values from /etc/rsyslog.conf + lineinfile: + path: /etc/rsyslog.conf + create: false + regexp: '(?i)^\s*{{ "$DefaultNetstreamDriver"| regex_escape }} ' + state: absent + + - name: Check if /etc/rsyslog.d exists + stat: + path: /etc/rsyslog.d + register: _etc_rsyslog_d_exists + + - name: Check if the parameter $DefaultNetstreamDriver is present in /etc/rsyslog.d + find: + paths: /etc/rsyslog.d + recurse: 'yes' + follow: 'no' + contains: '^\s*{{ "$DefaultNetstreamDriver"| regex_escape }} ' + register: _etc_rsyslog_d_has_parameter + when: _etc_rsyslog_d_exists.stat.isdir is defined and _etc_rsyslog_d_exists.stat.isdir + + - name: Remove parameter from files in /etc/rsyslog.d + lineinfile: + path: '{{ item.path }}' + create: false + regexp: '(?i)^\s*{{ "$DefaultNetstreamDriver"| regex_escape }} ' + state: absent + with_items: '{{ _etc_rsyslog_d_has_parameter.files }}' + when: _etc_rsyslog_d_has_parameter.matched + + - name: Insert correct line to /etc/rsyslog.conf + lineinfile: + path: /etc/rsyslog.conf + create: true + regexp: '(?i)^\s*{{ "$DefaultNetstreamDriver"| regex_escape }} ' + line: $DefaultNetstreamDriver gtls + state: present + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-005025 + - NIST-800-53-AU-4(1) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - rsyslog_encrypt_offload_defaultnetstreamdriver + + + + + + + + + + Ensure Log Files Are Owned By Appropriate Group + The group-owner of all log files written by +rsyslog should be root. +These log files are determined by the second part of each Rule line in +/etc/rsyslog.conf and typically all appear in /var/log. +For each log file LOGFILE referenced in /etc/rsyslog.conf, +run the following command to inspect the file's group owner: +$ ls -l LOGFILE + +If the owner is not root, +run the following command to +correct this: +$ sudo chgrp root LOGFILE + + + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + APO01.06 + DSS05.04 + DSS05.07 + DSS06.02 + CCI-001314 + 4.3.3.7.3 + SR 2.1 + SR 5.2 + 0988 + 1405 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 + CM-6(a) + AC-6(1) + PR.AC-4 + PR.DS-5 + Req-10.5.1 + Req-10.5.2 + R71 + 10.3.2 + 10.3 + The log files generated by rsyslog contain valuable information regarding system +configuration, user authentication, and other such information. Log files should be +protected from unauthorized access. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && rpm --quiet -q rsyslog; then + +# List of log file paths to be inspected for correct permissions +# * Primarily inspect log file paths listed in /etc/rsyslog.conf +RSYSLOG_ETC_CONFIG="/etc/rsyslog.conf" +# * And also the log file paths listed after rsyslog's $IncludeConfig directive +# (store the result into array for the case there's shell glob used as value of IncludeConfig) +readarray -t OLD_INC < <(grep -e "\$IncludeConfig[[:space:]]\+[^[:space:];]\+" /etc/rsyslog.conf | cut -d ' ' -f 2) +readarray -t RSYSLOG_INCLUDE_CONFIG < <(for INCPATH in "${OLD_INC[@]}"; do eval printf '%s\\n' "${INCPATH}"; done) +readarray -t NEW_INC < <(sed -n '/^\s*include(/,/)/Ip' /etc/rsyslog.conf | sed -n 's@.*file\s*=\s*"\([/[:alnum:][:punct:]]*\)".*@\1@Ip') +readarray -t RSYSLOG_INCLUDE < <(for INCPATH in "${NEW_INC[@]}"; do eval printf '%s\\n' "${INCPATH}"; done) + +# Declare an array to hold the final list of different log file paths +declare -a LOG_FILE_PATHS + +# Array to hold all rsyslog config entries +RSYSLOG_CONFIGS=() +RSYSLOG_CONFIGS=("${RSYSLOG_ETC_CONFIG}" "${RSYSLOG_INCLUDE_CONFIG[@]}" "${RSYSLOG_INCLUDE[@]}") + +# Get full list of files to be checked +# RSYSLOG_CONFIGS may contain globs such as +# /etc/rsyslog.d/*.conf /etc/rsyslog.d/*.frule +# So, loop over the entries in RSYSLOG_CONFIGS and use find to get the list of included files. +RSYSLOG_CONFIG_FILES=() +for ENTRY in "${RSYSLOG_CONFIGS[@]}" +do + # If directory, rsyslog will search for config files in recursively. + # However, files in hidden sub-directories or hidden files will be ignored. + if [ -d "${ENTRY}" ] + then + readarray -t FINDOUT < <(find "${ENTRY}" -not -path '*/.*' -type f) + RSYSLOG_CONFIG_FILES+=("${FINDOUT[@]}") + elif [ -f "${ENTRY}" ] + then + RSYSLOG_CONFIG_FILES+=("${ENTRY}") + else + echo "Invalid include object: ${ENTRY}" + fi +done + +# Browse each file selected above as containing paths of log files +# ('/etc/rsyslog.conf' and '/etc/rsyslog.d/*.conf' in the default configuration) +for LOG_FILE in "${RSYSLOG_CONFIG_FILES[@]}" +do + # From each of these files extract just particular log file path(s), thus: + # * Ignore lines starting with space (' '), comment ('#"), or variable syntax ('$') characters, + # * Ignore empty lines, + # * Strip quotes and closing brackets from paths. + # * Ignore paths that match /dev|/etc.*\.conf, as those are paths, but likely not log files + # * From the remaining valid rows select only fields constituting a log file path + # Text file column is understood to represent a log file path if and only if all of the + # following are met: + # * it contains at least one slash '/' character, + # * it is preceded by space + # * it doesn't contain space (' '), colon (':'), and semicolon (';') characters + # Search log file for path(s) only in case it exists! + if [[ -f "${LOG_FILE}" ]] + then + NORMALIZED_CONFIG_FILE_LINES=$(sed -e "/^[#|$]/d" "${LOG_FILE}") + LINES_WITH_PATHS=$(grep '[^/]*\s\+\S*/\S\+$' <<< "${NORMALIZED_CONFIG_FILE_LINES}") + FILTERED_PATHS=$(awk '{if(NF>=2&&($NF~/^\//||$NF~/^-\//)){sub(/^-\//,"/",$NF);print $NF}}' <<< "${LINES_WITH_PATHS}") + CLEANED_PATHS=$(sed -e "s/[\"')]//g; /\\/etc.*\.conf/d; /\\/dev\\//d" <<< "${FILTERED_PATHS}") + MATCHED_ITEMS=$(sed -e "/^$/d" <<< "${CLEANED_PATHS}") + # Since above sed command might return more than one item (delimited by newline), split + # the particular matches entries into new array specific for this log file + readarray -t ARRAY_FOR_LOG_FILE <<< "$MATCHED_ITEMS" + # Concatenate the two arrays - previous content of $LOG_FILE_PATHS array with + # items from newly created array for this log file + LOG_FILE_PATHS+=("${ARRAY_FOR_LOG_FILE[@]}") + # Delete the temporary array + unset ARRAY_FOR_LOG_FILE + fi +done + +# Check for RainerScript action log format which might be also multiline so grep regex is a bit +# curly: +# extract possibly multiline action omfile expressions +# extract File="logfile" expression +# match only "logfile" expression +for LOG_FILE in "${RSYSLOG_CONFIG_FILES[@]}" +do + ACTION_OMFILE_LINES=$(grep -iozP "action\s*\(\s*type\s*=\s*\"omfile\"[^\)]*\)" "${LOG_FILE}") + OMFILE_LINES=$(echo "${ACTION_OMFILE_LINES}"| grep -iaoP "\bFile\s*=\s*\"([/[:alnum:][:punct:]]*)\"\s*\)") + LOG_FILE_PATHS+=("$(echo "${OMFILE_LINES}"| grep -oE "\"([/[:alnum:][:punct:]]*)\""|tr -d "\"")") +done + +# Ensure the correct attribute if file exists +FILE_CMD="chgrp" +for LOG_FILE_PATH in "${LOG_FILE_PATHS[@]}" +do + # Sanity check - if particular $LOG_FILE_PATH is empty string, skip it from further processing + if [ -z "$LOG_FILE_PATH" ] + then + continue + fi + $FILE_CMD "root" "$LOG_FILE_PATH" +done + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-10.5.1 + - PCI-DSS-Req-10.5.2 + - PCI-DSSv4-10.3 + - PCI-DSSv4-10.3.2 + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - rsyslog_files_groupownership + +- name: Ensure Log Files Are Owned By Appropriate Group - Set rsyslog logfile configuration + facts + ansible.builtin.set_fact: + rsyslog_etc_config: /etc/rsyslog.conf + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-10.5.1 + - PCI-DSS-Req-10.5.2 + - PCI-DSSv4-10.3 + - PCI-DSSv4-10.3.2 + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - rsyslog_files_groupownership + +- name: Ensure Log Files Are Owned By Appropriate Group - Get IncludeConfig directive + ansible.builtin.shell: | + set -o pipefail + grep -e '$IncludeConfig' {{ rsyslog_etc_config }} | cut -d ' ' -f 2 || true + register: rsyslog_old_inc + changed_when: false + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-10.5.1 + - PCI-DSS-Req-10.5.2 + - PCI-DSSv4-10.3 + - PCI-DSSv4-10.3.2 + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - rsyslog_files_groupownership + +- name: Ensure Log Files Are Owned By Appropriate Group - Get include files directives + ansible.builtin.shell: | + set -o pipefail + awk '/)/{f=0} /include\(/{f=1} f{ nf=gensub("^(include\\(|\\s*)file=\"(\\S+)\".*","\\2",1); if($0!=nf){ print nf }}' {{ rsyslog_etc_config }} || true + register: rsyslog_new_inc + changed_when: false + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-10.5.1 + - PCI-DSS-Req-10.5.2 + - PCI-DSSv4-10.3 + - PCI-DSSv4-10.3.2 + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - rsyslog_files_groupownership + +- name: Ensure Log Files Are Owned By Appropriate Group - Aggregate rsyslog includes + ansible.builtin.set_fact: + include_config_output: '{{ rsyslog_old_inc.stdout_lines + rsyslog_new_inc.stdout_lines + }}' + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - rsyslog_old_inc is not skipped and rsyslog_new_inc is not skipped + tags: + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-10.5.1 + - PCI-DSS-Req-10.5.2 + - PCI-DSSv4-10.3 + - PCI-DSSv4-10.3.2 + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - rsyslog_files_groupownership + +- name: Ensure Log Files Are Owned By Appropriate Group - List all config files + ansible.builtin.find: + paths: '{{ item | dirname }}' + patterns: '{{ item | basename }}' + hidden: false + follow: true + loop: '{{ include_config_output | list + [rsyslog_etc_config] }}' + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - include_config_output is defined + register: rsyslog_config_files + failed_when: false + changed_when: false + tags: + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-10.5.1 + - PCI-DSS-Req-10.5.2 + - PCI-DSSv4-10.3 + - PCI-DSSv4-10.3.2 + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - rsyslog_files_groupownership + +- name: Ensure Log Files Are Owned By Appropriate Group - Extract log files old format + ansible.builtin.shell: | + set -o pipefail + grep -oP '^[^(\s|#|\$)]+[\s]+.*[\s]+-?(/+[^:;\s]+);*\.*$' {{ item.1.path }} | \ + awk '{print $NF}' | \ + sed -e 's/^-//' || true + loop: '{{ rsyslog_config_files.results | default([]) | subelements(''files'') }}' + register: log_files_old + changed_when: false + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - rsyslog_config_files is not skipped + tags: + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-10.5.1 + - PCI-DSS-Req-10.5.2 + - PCI-DSSv4-10.3 + - PCI-DSSv4-10.3.2 + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - rsyslog_files_groupownership + +- name: Ensure Log Files Are Owned By Appropriate Group - Extract log files new format + ansible.builtin.shell: | + set -o pipefail + grep -ozP "action\s*\(\s*type\s*=\s*\"omfile\"[^\)]*\)" {{ item.1.path }} | \ + grep -aoP "\bFile\s*=\s*\"([/[:alnum:][:punct:]]*)\"\s*\)" | \ + grep -oE "\"([/[:alnum:][:punct:]]*)\"" | \ + tr -d "\""|| true + loop: '{{ rsyslog_config_files.results | default([]) | subelements(''files'') }}' + register: log_files_new + changed_when: false + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - rsyslog_config_files is not skipped + tags: + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-10.5.1 + - PCI-DSS-Req-10.5.2 + - PCI-DSSv4-10.3 + - PCI-DSSv4-10.3.2 + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - rsyslog_files_groupownership + +- name: Ensure Log Files Are Owned By Appropriate Group - Sum all log files found + ansible.builtin.set_fact: + log_files: '{{ log_files_new.results | map(attribute=''stdout_lines'') | list + | flatten | unique + log_files_old.results | map(attribute=''stdout_lines'') + | list | flatten | unique }}' + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-10.5.1 + - PCI-DSS-Req-10.5.2 + - PCI-DSSv4-10.3 + - PCI-DSSv4-10.3.2 + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - rsyslog_files_groupownership + +- name: Ensure Log Files Are Owned By Appropriate Group -Setup log files attribute + ansible.builtin.file: + path: '{{ item }}' + group: root + state: file + loop: '{{ log_files | list | flatten | unique }}' + failed_when: false + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-10.5.1 + - PCI-DSS-Req-10.5.2 + - PCI-DSSv4-10.3 + - PCI-DSSv4-10.3.2 + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - rsyslog_files_groupownership + + + + + + + + + + Ensure Log Files Are Owned By Appropriate User + The owner of all log files written by +rsyslog should be + +root. + +These log files are determined by the second part of each Rule line in +/etc/rsyslog.conf and typically all appear in /var/log. +For each log file LOGFILE referenced in /etc/rsyslog.conf, +run the following command to inspect the file's owner: +$ ls -l LOGFILE + +If the owner is not + +root, + +run the following command to +correct this: + +$ sudo chown root LOGFILE + + + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + APO01.06 + DSS05.04 + DSS05.07 + DSS06.02 + CCI-001314 + 4.3.3.7.3 + SR 2.1 + SR 5.2 + 0988 + 1405 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 + CM-6(a) + AC-6(1) + PR.AC-4 + PR.DS-5 + Req-10.5.1 + Req-10.5.2 + R71 + 10.3.2 + 10.3 + The log files generated by rsyslog contain valuable information regarding system +configuration, user authentication, and other such information. Log files should be +protected from unauthorized access. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && rpm --quiet -q rsyslog; then + +# List of log file paths to be inspected for correct permissions +# * Primarily inspect log file paths listed in /etc/rsyslog.conf +RSYSLOG_ETC_CONFIG="/etc/rsyslog.conf" +# * And also the log file paths listed after rsyslog's $IncludeConfig directive +# (store the result into array for the case there's shell glob used as value of IncludeConfig) +readarray -t OLD_INC < <(grep -e "\$IncludeConfig[[:space:]]\+[^[:space:];]\+" /etc/rsyslog.conf | cut -d ' ' -f 2) +readarray -t RSYSLOG_INCLUDE_CONFIG < <(for INCPATH in "${OLD_INC[@]}"; do eval printf '%s\\n' "${INCPATH}"; done) +readarray -t NEW_INC < <(sed -n '/^\s*include(/,/)/Ip' /etc/rsyslog.conf | sed -n 's@.*file\s*=\s*"\([/[:alnum:][:punct:]]*\)".*@\1@Ip') +readarray -t RSYSLOG_INCLUDE < <(for INCPATH in "${NEW_INC[@]}"; do eval printf '%s\\n' "${INCPATH}"; done) + +# Declare an array to hold the final list of different log file paths +declare -a LOG_FILE_PATHS + +# Array to hold all rsyslog config entries +RSYSLOG_CONFIGS=() +RSYSLOG_CONFIGS=("${RSYSLOG_ETC_CONFIG}" "${RSYSLOG_INCLUDE_CONFIG[@]}" "${RSYSLOG_INCLUDE[@]}") + +# Get full list of files to be checked +# RSYSLOG_CONFIGS may contain globs such as +# /etc/rsyslog.d/*.conf /etc/rsyslog.d/*.frule +# So, loop over the entries in RSYSLOG_CONFIGS and use find to get the list of included files. +RSYSLOG_CONFIG_FILES=() +for ENTRY in "${RSYSLOG_CONFIGS[@]}" +do + # If directory, rsyslog will search for config files in recursively. + # However, files in hidden sub-directories or hidden files will be ignored. + if [ -d "${ENTRY}" ] + then + readarray -t FINDOUT < <(find "${ENTRY}" -not -path '*/.*' -type f) + RSYSLOG_CONFIG_FILES+=("${FINDOUT[@]}") + elif [ -f "${ENTRY}" ] + then + RSYSLOG_CONFIG_FILES+=("${ENTRY}") + else + echo "Invalid include object: ${ENTRY}" + fi +done + +# Browse each file selected above as containing paths of log files +# ('/etc/rsyslog.conf' and '/etc/rsyslog.d/*.conf' in the default configuration) +for LOG_FILE in "${RSYSLOG_CONFIG_FILES[@]}" +do + # From each of these files extract just particular log file path(s), thus: + # * Ignore lines starting with space (' '), comment ('#"), or variable syntax ('$') characters, + # * Ignore empty lines, + # * Strip quotes and closing brackets from paths. + # * Ignore paths that match /dev|/etc.*\.conf, as those are paths, but likely not log files + # * From the remaining valid rows select only fields constituting a log file path + # Text file column is understood to represent a log file path if and only if all of the + # following are met: + # * it contains at least one slash '/' character, + # * it is preceded by space + # * it doesn't contain space (' '), colon (':'), and semicolon (';') characters + # Search log file for path(s) only in case it exists! + if [[ -f "${LOG_FILE}" ]] + then + NORMALIZED_CONFIG_FILE_LINES=$(sed -e "/^[#|$]/d" "${LOG_FILE}") + LINES_WITH_PATHS=$(grep '[^/]*\s\+\S*/\S\+$' <<< "${NORMALIZED_CONFIG_FILE_LINES}") + FILTERED_PATHS=$(awk '{if(NF>=2&&($NF~/^\//||$NF~/^-\//)){sub(/^-\//,"/",$NF);print $NF}}' <<< "${LINES_WITH_PATHS}") + CLEANED_PATHS=$(sed -e "s/[\"')]//g; /\\/etc.*\.conf/d; /\\/dev\\//d" <<< "${FILTERED_PATHS}") + MATCHED_ITEMS=$(sed -e "/^$/d" <<< "${CLEANED_PATHS}") + # Since above sed command might return more than one item (delimited by newline), split + # the particular matches entries into new array specific for this log file + readarray -t ARRAY_FOR_LOG_FILE <<< "$MATCHED_ITEMS" + # Concatenate the two arrays - previous content of $LOG_FILE_PATHS array with + # items from newly created array for this log file + LOG_FILE_PATHS+=("${ARRAY_FOR_LOG_FILE[@]}") + # Delete the temporary array + unset ARRAY_FOR_LOG_FILE + fi +done + +# Check for RainerScript action log format which might be also multiline so grep regex is a bit +# curly: +# extract possibly multiline action omfile expressions +# extract File="logfile" expression +# match only "logfile" expression +for LOG_FILE in "${RSYSLOG_CONFIG_FILES[@]}" +do + ACTION_OMFILE_LINES=$(grep -iozP "action\s*\(\s*type\s*=\s*\"omfile\"[^\)]*\)" "${LOG_FILE}") + OMFILE_LINES=$(echo "${ACTION_OMFILE_LINES}"| grep -iaoP "\bFile\s*=\s*\"([/[:alnum:][:punct:]]*)\"\s*\)") + LOG_FILE_PATHS+=("$(echo "${OMFILE_LINES}"| grep -oE "\"([/[:alnum:][:punct:]]*)\""|tr -d "\"")") +done + +# Ensure the correct attribute if file exists +FILE_CMD="chown" +for LOG_FILE_PATH in "${LOG_FILE_PATHS[@]}" +do + # Sanity check - if particular $LOG_FILE_PATH is empty string, skip it from further processing + if [ -z "$LOG_FILE_PATH" ] + then + continue + fi + $FILE_CMD "root" "$LOG_FILE_PATH" +done + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-10.5.1 + - PCI-DSS-Req-10.5.2 + - PCI-DSSv4-10.3 + - PCI-DSSv4-10.3.2 + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - rsyslog_files_ownership + +- name: Ensure Log Files Are Owned By Appropriate User - Set rsyslog logfile configuration + facts + ansible.builtin.set_fact: + rsyslog_etc_config: /etc/rsyslog.conf + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-10.5.1 + - PCI-DSS-Req-10.5.2 + - PCI-DSSv4-10.3 + - PCI-DSSv4-10.3.2 + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - rsyslog_files_ownership + +- name: Ensure Log Files Are Owned By Appropriate User - Get IncludeConfig directive + ansible.builtin.shell: | + set -o pipefail + grep -e '$IncludeConfig' {{ rsyslog_etc_config }} | cut -d ' ' -f 2 || true + register: rsyslog_old_inc + changed_when: false + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-10.5.1 + - PCI-DSS-Req-10.5.2 + - PCI-DSSv4-10.3 + - PCI-DSSv4-10.3.2 + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - rsyslog_files_ownership + +- name: Ensure Log Files Are Owned By Appropriate User - Get include files directives + ansible.builtin.shell: | + set -o pipefail + awk '/)/{f=0} /include\(/{f=1} f{ nf=gensub("^(include\\(|\\s*)file=\"(\\S+)\".*","\\2",1); if($0!=nf){ print nf }}' {{ rsyslog_etc_config }} || true + register: rsyslog_new_inc + changed_when: false + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-10.5.1 + - PCI-DSS-Req-10.5.2 + - PCI-DSSv4-10.3 + - PCI-DSSv4-10.3.2 + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - rsyslog_files_ownership + +- name: Ensure Log Files Are Owned By Appropriate User - Aggregate rsyslog includes + ansible.builtin.set_fact: + include_config_output: '{{ rsyslog_old_inc.stdout_lines + rsyslog_new_inc.stdout_lines + }}' + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - rsyslog_old_inc is not skipped and rsyslog_new_inc is not skipped + tags: + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-10.5.1 + - PCI-DSS-Req-10.5.2 + - PCI-DSSv4-10.3 + - PCI-DSSv4-10.3.2 + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - rsyslog_files_ownership + +- name: Ensure Log Files Are Owned By Appropriate User - List all config files + ansible.builtin.find: + paths: '{{ item | dirname }}' + patterns: '{{ item | basename }}' + hidden: false + follow: true + loop: '{{ include_config_output | list + [rsyslog_etc_config] }}' + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - include_config_output is defined + register: rsyslog_config_files + failed_when: false + changed_when: false + tags: + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-10.5.1 + - PCI-DSS-Req-10.5.2 + - PCI-DSSv4-10.3 + - PCI-DSSv4-10.3.2 + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - rsyslog_files_ownership + +- name: Ensure Log Files Are Owned By Appropriate User - Extract log files old format + ansible.builtin.shell: | + set -o pipefail + grep -oP '^[^(\s|#|\$)]+[\s]+.*[\s]+-?(/+[^:;\s]+);*\.*$' {{ item.1.path }} | \ + awk '{print $NF}' | \ + sed -e 's/^-//' || true + loop: '{{ rsyslog_config_files.results | default([]) | subelements(''files'') }}' + register: log_files_old + changed_when: false + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - rsyslog_config_files is not skipped + tags: + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-10.5.1 + - PCI-DSS-Req-10.5.2 + - PCI-DSSv4-10.3 + - PCI-DSSv4-10.3.2 + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - rsyslog_files_ownership + +- name: Ensure Log Files Are Owned By Appropriate User - Extract log files new format + ansible.builtin.shell: | + set -o pipefail + grep -ozP "action\s*\(\s*type\s*=\s*\"omfile\"[^\)]*\)" {{ item.1.path }} | \ + grep -aoP "\bFile\s*=\s*\"([/[:alnum:][:punct:]]*)\"\s*\)" | \ + grep -oE "\"([/[:alnum:][:punct:]]*)\"" | \ + tr -d "\""|| true + loop: '{{ rsyslog_config_files.results | default([]) | subelements(''files'') }}' + register: log_files_new + changed_when: false + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - rsyslog_config_files is not skipped + tags: + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-10.5.1 + - PCI-DSS-Req-10.5.2 + - PCI-DSSv4-10.3 + - PCI-DSSv4-10.3.2 + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - rsyslog_files_ownership + +- name: Ensure Log Files Are Owned By Appropriate User - Sum all log files found + ansible.builtin.set_fact: + log_files: '{{ log_files_new.results | map(attribute=''stdout_lines'') | list + | flatten | unique + log_files_old.results | map(attribute=''stdout_lines'') + | list | flatten | unique }}' + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-10.5.1 + - PCI-DSS-Req-10.5.2 + - PCI-DSSv4-10.3 + - PCI-DSSv4-10.3.2 + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - rsyslog_files_ownership + +- name: Ensure Log Files Are Owned By Appropriate User -Setup log files attribute + ansible.builtin.file: + path: '{{ item }}' + owner: root + state: file + loop: '{{ log_files | list | flatten | unique }}' + failed_when: false + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-10.5.1 + - PCI-DSS-Req-10.5.2 + - PCI-DSSv4-10.3 + - PCI-DSSv4-10.3.2 + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - rsyslog_files_ownership + + + + + + + + + + Ensure System Log Files Have Correct Permissions + The file permissions for all log files written by rsyslog should +be set to 640, or more restrictive. These log files are determined by the +second part of each Rule line in /etc/rsyslog.conf and typically +all appear in /var/log. For each log file LOGFILE +referenced in /etc/rsyslog.conf, run the following command to +inspect the file's permissions: +$ ls -l LOGFILE + +If the permissions are not 640 or more restrictive, run the following +command to correct this: +$ sudo chmod 640 LOGFILE + " + CCI-001314 + 0988 + 1405 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 + CM-6(a) + AC-6(1) + Req-10.5.1 + Req-10.5.2 + R71 + 10.3.1 + 10.3 + Log files can contain valuable information regarding system +configuration. If the system log files are not protected unauthorized +users could change the logged data, eliminating their forensic value. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && rpm --quiet -q rsyslog; then + +# List of log file paths to be inspected for correct permissions +# * Primarily inspect log file paths listed in /etc/rsyslog.conf +RSYSLOG_ETC_CONFIG="/etc/rsyslog.conf" +# * And also the log file paths listed after rsyslog's $IncludeConfig directive +# (store the result into array for the case there's shell glob used as value of IncludeConfig) +readarray -t OLD_INC < <(grep -e "\$IncludeConfig[[:space:]]\+[^[:space:];]\+" /etc/rsyslog.conf | cut -d ' ' -f 2) +readarray -t RSYSLOG_INCLUDE_CONFIG < <(for INCPATH in "${OLD_INC[@]}"; do eval printf '%s\\n' "${INCPATH}"; done) +readarray -t NEW_INC < <(sed -n '/^\s*include(/,/)/Ip' /etc/rsyslog.conf | sed -n 's@.*file\s*=\s*"\([/[:alnum:][:punct:]]*\)".*@\1@Ip') +readarray -t RSYSLOG_INCLUDE < <(for INCPATH in "${NEW_INC[@]}"; do eval printf '%s\\n' "${INCPATH}"; done) + +# Declare an array to hold the final list of different log file paths +declare -a LOG_FILE_PATHS + +# Array to hold all rsyslog config entries +RSYSLOG_CONFIGS=() +RSYSLOG_CONFIGS=("${RSYSLOG_ETC_CONFIG}" "${RSYSLOG_INCLUDE_CONFIG[@]}" "${RSYSLOG_INCLUDE[@]}") + +# Get full list of files to be checked +# RSYSLOG_CONFIGS may contain globs such as +# /etc/rsyslog.d/*.conf /etc/rsyslog.d/*.frule +# So, loop over the entries in RSYSLOG_CONFIGS and use find to get the list of included files. +RSYSLOG_CONFIG_FILES=() +for ENTRY in "${RSYSLOG_CONFIGS[@]}" +do + # If directory, rsyslog will search for config files in recursively. + # However, files in hidden sub-directories or hidden files will be ignored. + if [ -d "${ENTRY}" ] + then + readarray -t FINDOUT < <(find "${ENTRY}" -not -path '*/.*' -type f) + RSYSLOG_CONFIG_FILES+=("${FINDOUT[@]}") + elif [ -f "${ENTRY}" ] + then + RSYSLOG_CONFIG_FILES+=("${ENTRY}") + else + echo "Invalid include object: ${ENTRY}" + fi +done + +# Browse each file selected above as containing paths of log files +# ('/etc/rsyslog.conf' and '/etc/rsyslog.d/*.conf' in the default configuration) +for LOG_FILE in "${RSYSLOG_CONFIG_FILES[@]}" +do + # From each of these files extract just particular log file path(s), thus: + # * Ignore lines starting with space (' '), comment ('#"), or variable syntax ('$') characters, + # * Ignore empty lines, + # * Strip quotes and closing brackets from paths. + # * Ignore paths that match /dev|/etc.*\.conf, as those are paths, but likely not log files + # * From the remaining valid rows select only fields constituting a log file path + # Text file column is understood to represent a log file path if and only if all of the + # following are met: + # * it contains at least one slash '/' character, + # * it is preceded by space + # * it doesn't contain space (' '), colon (':'), and semicolon (';') characters + # Search log file for path(s) only in case it exists! + if [[ -f "${LOG_FILE}" ]] + then + NORMALIZED_CONFIG_FILE_LINES=$(sed -e "/^[#|$]/d" "${LOG_FILE}") + LINES_WITH_PATHS=$(grep '[^/]*\s\+\S*/\S\+$' <<< "${NORMALIZED_CONFIG_FILE_LINES}") + FILTERED_PATHS=$(awk '{if(NF>=2&&($NF~/^\//||$NF~/^-\//)){sub(/^-\//,"/",$NF);print $NF}}' <<< "${LINES_WITH_PATHS}") + CLEANED_PATHS=$(sed -e "s/[\"')]//g; /\\/etc.*\.conf/d; /\\/dev\\//d" <<< "${FILTERED_PATHS}") + MATCHED_ITEMS=$(sed -e "/^$/d" <<< "${CLEANED_PATHS}") + # Since above sed command might return more than one item (delimited by newline), split + # the particular matches entries into new array specific for this log file + readarray -t ARRAY_FOR_LOG_FILE <<< "$MATCHED_ITEMS" + # Concatenate the two arrays - previous content of $LOG_FILE_PATHS array with + # items from newly created array for this log file + LOG_FILE_PATHS+=("${ARRAY_FOR_LOG_FILE[@]}") + # Delete the temporary array + unset ARRAY_FOR_LOG_FILE + fi +done + +# Check for RainerScript action log format which might be also multiline so grep regex is a bit +# curly: +# extract possibly multiline action omfile expressions +# extract File="logfile" expression +# match only "logfile" expression +for LOG_FILE in "${RSYSLOG_CONFIG_FILES[@]}" +do + ACTION_OMFILE_LINES=$(grep -iozP "action\s*\(\s*type\s*=\s*\"omfile\"[^\)]*\)" "${LOG_FILE}") + OMFILE_LINES=$(echo "${ACTION_OMFILE_LINES}"| grep -iaoP "\bFile\s*=\s*\"([/[:alnum:][:punct:]]*)\"\s*\)") + LOG_FILE_PATHS+=("$(echo "${OMFILE_LINES}"| grep -oE "\"([/[:alnum:][:punct:]]*)\""|tr -d "\"")") +done + +# Ensure the correct attribute if file exists +FILE_CMD="chmod" +for LOG_FILE_PATH in "${LOG_FILE_PATHS[@]}" +do + # Sanity check - if particular $LOG_FILE_PATH is empty string, skip it from further processing + if [ -z "$LOG_FILE_PATH" ] + then + continue + fi + $FILE_CMD "0640" "$LOG_FILE_PATH" +done + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-10.5.1 + - PCI-DSS-Req-10.5.2 + - PCI-DSSv4-10.3 + - PCI-DSSv4-10.3.1 + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - rsyslog_files_permissions + +- name: Ensure System Log Files Have Correct Permissions - Set rsyslog logfile configuration + facts + ansible.builtin.set_fact: + rsyslog_etc_config: /etc/rsyslog.conf + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-10.5.1 + - PCI-DSS-Req-10.5.2 + - PCI-DSSv4-10.3 + - PCI-DSSv4-10.3.1 + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - rsyslog_files_permissions + +- name: Ensure System Log Files Have Correct Permissions - Get IncludeConfig directive + ansible.builtin.shell: | + set -o pipefail + grep -e '$IncludeConfig' {{ rsyslog_etc_config }} | cut -d ' ' -f 2 || true + register: rsyslog_old_inc + changed_when: false + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-10.5.1 + - PCI-DSS-Req-10.5.2 + - PCI-DSSv4-10.3 + - PCI-DSSv4-10.3.1 + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - rsyslog_files_permissions + +- name: Ensure System Log Files Have Correct Permissions - Get include files directives + ansible.builtin.shell: | + set -o pipefail + awk '/)/{f=0} /include\(/{f=1} f{ nf=gensub("^(include\\(|\\s*)file=\"(\\S+)\".*","\\2",1); if($0!=nf){ print nf }}' {{ rsyslog_etc_config }} || true + register: rsyslog_new_inc + changed_when: false + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-10.5.1 + - PCI-DSS-Req-10.5.2 + - PCI-DSSv4-10.3 + - PCI-DSSv4-10.3.1 + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - rsyslog_files_permissions + +- name: Ensure System Log Files Have Correct Permissions - Aggregate rsyslog includes + ansible.builtin.set_fact: + include_config_output: '{{ rsyslog_old_inc.stdout_lines + rsyslog_new_inc.stdout_lines + }}' + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - rsyslog_old_inc is not skipped and rsyslog_new_inc is not skipped + tags: + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-10.5.1 + - PCI-DSS-Req-10.5.2 + - PCI-DSSv4-10.3 + - PCI-DSSv4-10.3.1 + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - rsyslog_files_permissions + +- name: Ensure System Log Files Have Correct Permissions - List all config files + ansible.builtin.find: + paths: '{{ item | dirname }}' + patterns: '{{ item | basename }}' + hidden: false + follow: true + loop: '{{ include_config_output | list + [rsyslog_etc_config] }}' + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - include_config_output is defined + register: rsyslog_config_files + failed_when: false + changed_when: false + tags: + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-10.5.1 + - PCI-DSS-Req-10.5.2 + - PCI-DSSv4-10.3 + - PCI-DSSv4-10.3.1 + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - rsyslog_files_permissions + +- name: Ensure System Log Files Have Correct Permissions - Extract log files old format + ansible.builtin.shell: | + set -o pipefail + grep -oP '^[^(\s|#|\$)]+[\s]+.*[\s]+-?(/+[^:;\s]+);*\.*$' {{ item.1.path }} | \ + awk '{print $NF}' | \ + sed -e 's/^-//' || true + loop: '{{ rsyslog_config_files.results | default([]) | subelements(''files'') }}' + register: log_files_old + changed_when: false + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - rsyslog_config_files is not skipped + tags: + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-10.5.1 + - PCI-DSS-Req-10.5.2 + - PCI-DSSv4-10.3 + - PCI-DSSv4-10.3.1 + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - rsyslog_files_permissions + +- name: Ensure System Log Files Have Correct Permissions - Extract log files new format + ansible.builtin.shell: | + set -o pipefail + grep -ozP "action\s*\(\s*type\s*=\s*\"omfile\"[^\)]*\)" {{ item.1.path }} | \ + grep -aoP "\bFile\s*=\s*\"([/[:alnum:][:punct:]]*)\"\s*\)" | \ + grep -oE "\"([/[:alnum:][:punct:]]*)\"" | \ + tr -d "\""|| true + loop: '{{ rsyslog_config_files.results | default([]) | subelements(''files'') }}' + register: log_files_new + changed_when: false + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - rsyslog_config_files is not skipped + tags: + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-10.5.1 + - PCI-DSS-Req-10.5.2 + - PCI-DSSv4-10.3 + - PCI-DSSv4-10.3.1 + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - rsyslog_files_permissions + +- name: Ensure System Log Files Have Correct Permissions - Sum all log files found + ansible.builtin.set_fact: + log_files: '{{ log_files_new.results | map(attribute=''stdout_lines'') | list + | flatten | unique + log_files_old.results | map(attribute=''stdout_lines'') + | list | flatten | unique }}' + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-10.5.1 + - PCI-DSS-Req-10.5.2 + - PCI-DSSv4-10.3 + - PCI-DSSv4-10.3.1 + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - rsyslog_files_permissions + +- name: Ensure System Log Files Have Correct Permissions -Setup log files attribute + ansible.builtin.file: + path: '{{ item }}' + mode: '0640' + state: file + loop: '{{ log_files | list | flatten | unique }}' + failed_when: false + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-10.5.1 + - PCI-DSS-Req-10.5.2 + - PCI-DSSv4-10.3 + - PCI-DSSv4-10.3.1 + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - rsyslog_files_permissions + + + + + + + + + + Ensure remote access methods are monitored in Rsyslog + Logging of remote access methods must be implemented to help identify cyber +attacks and ensure ongoing compliance with remote access policies are being +audited and upheld. An examples of a remote access method is the use of the +Remote Desktop Protocol (RDP) from an external, non-organization controlled +network. The /etc/rsyslog.conf or +/etc/rsyslog.d/*.conf file should contain a match for the following +selectors: auth.*, authpriv.*, and daemon.*. If +not, use the following as an example configuration: + + auth.*;authpriv.* /var/log/secure + daemon.* /var/log/messages + + + CCI-000067 + AC-17(1) + SRG-OS-000032-GPOS-00013 + OL09-00-005000 + SV-271851r1092265_rule + Logging remote access methods can be used to trace the decrease the risks +associated with remote user access management. It can also be used to spot +cyber attacks and ensure ongoing compliance with organizational policies +surrounding the use of remote access methods. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && rpm --quiet -q rsyslog; then + +declare -A REMOTE_METHODS=( ['auth.*']='^[^#]*auth\.\*.*$' ['authpriv.*']='^[^#]*authpriv\.\*.*$' ['daemon.*']='^[^#]*daemon\.\*.*$' ) +declare -A LOCATIONS=( ['auth.*']='/var/log/secure' ['authpriv.*']='/var/log/secure' ['daemon.*']='/var/log/messages' ) + +if [[ ! -f /etc/rsyslog.conf ]]; then + # Something is not right, create the file + touch /etc/rsyslog.conf +fi + + +# Loop through the remote methods associative array +for K in "${!REMOTE_METHODS[@]}" +do + # Check to see if selector/value exists + if ! grep -rq "${REMOTE_METHODS[$K]}" /etc/rsyslog.*; then + APPEND_LINE=$(sed -rn "/^\S+\s+\${LOCATIONS[$K]}$/p" /etc/rsyslog.conf) + # Make sure we have a line to insert after, otherwise append to end + if [[ ! -z ${APPEND_LINE} ]]; then + # Add selector to file + sed -r -i "0,/^(\S+\s+\/var\/log\/secure$)/s//\1\n${K} \/var\/log\/secure/" /etc/rsyslog.conf + else + echo "${K} ${LOCATIONS[$K]}" >> /etc/rsyslog.conf + fi + fi +done + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-005000 + - NIST-800-53-AC-17(1) + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - rsyslog_remote_access_monitoring + +- name: 'Ensure remote access methods are monitored in Rsyslog: Set facts' + set_fact: + conf_files: + - /etc/rsyslog.conf + remote_methods: + - selector: auth.* + regexp: ^.*auth\.\*.*$ + location: /var/log/secure + - selector: authpriv.* + regexp: ^.*authpriv\.\*.*$ + location: /var/log/secure + - selector: daemon.* + regexp: ^.*daemon\.\*.*$ + location: /var/log/messages + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-005000 + - NIST-800-53-AC-17(1) + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - rsyslog_remote_access_monitoring + +- name: 'Ensure remote access methods are monitored in Rsyslog: Ensure rsyslog.conf + exists' + file: + path: '{{ conf_files.0 }}' + state: touch + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-005000 + - NIST-800-53-AC-17(1) + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - rsyslog_remote_access_monitoring + +- name: 'Ensure remote access methods are monitored in Rsyslog: Gather conf.d files' + find: + patterns: + - '*.conf' + paths: + - /etc/rsyslog.d + register: rsyslogd + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-005000 + - NIST-800-53-AC-17(1) + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - rsyslog_remote_access_monitoring + +- name: 'Ensure remote access methods are monitored in Rsyslog: Set conf file(s)' + set_fact: + conf_files: '{{ conf_files + [item.path] }}' + loop: '{{ rsyslogd.files }}' + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - rsyslogd.matched > 0 + tags: + - DISA-STIG-OL09-00-005000 + - NIST-800-53-AC-17(1) + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - rsyslog_remote_access_monitoring + +- name: 'Ensure remote access methods are monitored in Rsyslog: Check for existing + values' + lineinfile: + path: '{{ item.1 }}' + regexp: '{{ item.0.regexp }}' + state: absent + check_mode: true + changed_when: false + register: remote_method_values + loop: '{{ remote_methods|product(conf_files)|list }}' + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-005000 + - NIST-800-53-AC-17(1) + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - rsyslog_remote_access_monitoring + +- name: 'Ensure remote access methods are monitored in Rsyslog: Configure' + lineinfile: + path: /etc/rsyslog.conf + line: '{{ item.item.0.selector }} {{ item.item.0.location }}' + insertafter: ^.*\/var\/log\/secure.*$ + create: true + loop: '{{ remote_method_values.results }}' + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - item.found == 0 + tags: + - DISA-STIG-OL09-00-005000 + - NIST-800-53-AC-17(1) + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - rsyslog_remote_access_monitoring + + + + + + + + + + + systemd-journald + systemd-journald is a system service that collects and stores +logging data. It creates and maintains structured, indexed +journals based on logging information that is received from a +variety of sources. + +For more information on systemd-journald and additional systemd-journald configuration options, see +https://systemd.io/. + + Enable systemd-journald Service + The systemd-journald service is an essential component of +systemd. + +The systemd-journald service can be enabled with the following command: +$ sudo systemctl enable systemd-journald.service + + CCI-001665 + SC-24 + SRG-OS-000269-GPOS-00103 + OL09-00-002400 + SV-271739r1091929_rule + In the event of a system failure, Oracle Linux 9 must preserve any information necessary to determine cause of failure and any information necessary to return to operations with least disruption to system processes. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +SYSTEMCTL_EXEC='/usr/bin/systemctl' +"$SYSTEMCTL_EXEC" unmask 'systemd-journald.service' +if [[ $("$SYSTEMCTL_EXEC" is-system-running) != "offline" ]]; then + "$SYSTEMCTL_EXEC" start 'systemd-journald.service' +fi +"$SYSTEMCTL_EXEC" enable 'systemd-journald.service' + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002400 + - NIST-800-53-SC-24 + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_systemd-journald_enabled + +- name: Enable systemd-journald Service - Enable service systemd-journald + block: + + - name: Gather the package facts + package_facts: + manager: auto + + - name: Enable systemd-journald Service - Enable Service systemd-journald + ansible.builtin.systemd: + name: systemd-journald + enabled: true + state: started + masked: false + when: + - '"systemd" in ansible_facts.packages' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002400 + - NIST-800-53-SC-24 + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_systemd-journald_enabled + + include enable_systemd-journald + +class enable_systemd-journald { + service {'systemd-journald': + enable => true, + ensure => 'running', + } +} + + +[customizations.services] +enabled = ["systemd-journald"] + + + + + + + + + + + Ensure All Logs are Rotated by logrotate + +Edit the file /etc/logrotate.d/syslog. Find the first + +line, which should look like this (wrapped for clarity): +/var/log/messages /var/log/secure /var/log/maillog /var/log/spooler \ + /var/log/boot.log /var/log/cron { +Edit this line so that it contains a one-space-separated +listing of each log file referenced in /etc/rsyslog.conf. + + +All logs in use on a system must be rotated regularly, or the +log files will consume disk space over time, eventually interfering +with system operation. The file /etc/logrotate.d/syslog is the +configuration file used by the logrotate program to maintain all +log files written by syslog. By default, it rotates logs weekly and +stores four archival copies of each log. These settings can be +modified by editing /etc/logrotate.conf, but the defaults are +sufficient for purposes of this guide. + + +Note that logrotate is run nightly by the cron job +/etc/cron.daily/logrotate. If particularly active logs need to be +rotated more often than once a day, some other mechanism must be +used. + + Ensure logrotate is Installed + logrotate is installed by default. The logrotate package can be installed with the following command: $ sudo yum install logrotate + + 1 + 14 + 15 + 16 + 3 + 5 + 6 + APO11.04 + BAI03.05 + DSS05.04 + DSS05.07 + MEA02.01 + CCI-000366 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.4.4.7 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.8 + SR 2.9 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + CM-6(a) + PR.PT-1 + Req-10.7 + R71 + 10.5.1 + 10.5 + The logrotate package provides the logrotate services. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +if ! rpm -q --quiet "logrotate" ; then + yum install -y "logrotate" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-10.7 + - PCI-DSSv4-10.5 + - PCI-DSSv4-10.5.1 + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - package_logrotate_installed + +- name: Ensure logrotate is installed + package: + name: logrotate + state: present + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-10.7 + - PCI-DSSv4-10.5 + - PCI-DSSv4-10.5.1 + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - package_logrotate_installed + + include install_logrotate + +class install_logrotate { + package { 'logrotate': + ensure => 'installed', + } +} + + +package --add=logrotate + + +[[packages]] +name = "logrotate" +version = "*" + + + + + + + + + + Ensure Logrotate Runs Periodically + The logrotate utility allows for the automatic rotation of +log files. The frequency of rotation is specified in /etc/logrotate.conf, +which triggers a cron task or a timer. To configure logrotate to run daily, add or correct +the following line in /etc/logrotate.conf: +# rotate log files frequency +daily + + 1 + 14 + 15 + 16 + 3 + 5 + 6 + APO11.04 + BAI03.05 + DSS05.04 + DSS05.07 + MEA02.01 + CCI-000366 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.4.4.7 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.8 + SR 2.9 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + CM-6(a) + PR.PT-1 + Req-10.7 + R71 + Log files that are not properly rotated run the risk of growing so large +that they fill up the /var/log partition. Valuable logging information could be lost +if the /var/log partition becomes full. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q logrotate; }; then + +LOGROTATE_CONF_FILE="/etc/logrotate.conf" + +if ! rpm -q --quiet "crontabs" ; then + yum install -y "crontabs" +fi +CRON_DAILY_LOGROTATE_FILE="/etc/cron.daily/logrotate" + + +# daily rotation is configured +grep -q "^daily$" $LOGROTATE_CONF_FILE|| echo "daily" >> $LOGROTATE_CONF_FILE + +# remove any line configuring weekly, monthly or yearly rotation +sed -i '/^\s*\(weekly\|monthly\|yearly\).*$/d' $LOGROTATE_CONF_FILE + + +# configure cron.daily if not already +if ! grep -q "^[[:space:]]*/usr/sbin/logrotate[[:alnum:][:blank:][:punct:]]*$LOGROTATE_CONF_FILE$" $CRON_DAILY_LOGROTATE_FILE; then + echo '#!/bin/sh' > $CRON_DAILY_LOGROTATE_FILE + echo "/usr/sbin/logrotate $LOGROTATE_CONF_FILE" >> $CRON_DAILY_LOGROTATE_FILE +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-10.7 + - configure_strategy + - ensure_logrotate_activated + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Configure daily log rotation in /etc/logrotate.conf + lineinfile: + create: true + dest: /etc/logrotate.conf + regexp: ^daily$ + line: daily + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"logrotate" in ansible_facts.packages' + tags: + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-10.7 + - configure_strategy + - ensure_logrotate_activated + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Make sure daily log rotation setting is not overriden in /etc/logrotate.conf + lineinfile: + create: false + dest: /etc/logrotate.conf + regexp: ^[\s]*(weekly|monthly|yearly)$ + state: absent + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"logrotate" in ansible_facts.packages' + tags: + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-10.7 + - configure_strategy + - ensure_logrotate_activated + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Configure cron.daily if not already + block: + + - name: Add shebang + lineinfile: + path: /etc/cron.daily/logrotate + line: '#!/bin/sh' + insertbefore: BOF + create: true + + - name: Add logrotate call + lineinfile: + path: /etc/cron.daily/logrotate + line: /usr/sbin/logrotate /etc/logrotate.conf + regexp: ^[\s]*/usr/sbin/logrotate[\s\S]*/etc/logrotate.conf$ + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"logrotate" in ansible_facts.packages' + tags: + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-10.7 + - configure_strategy + - ensure_logrotate_activated + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Enable logrotate Timer + +The logrotate timer can be enabled with the following command: +$ sudo systemctl enable logrotate.timer + + 1 + 14 + 15 + 16 + 3 + 5 + 6 + APO11.04 + BAI03.05 + DSS05.04 + DSS05.07 + MEA02.01 + CCI-000366 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.4.4.7 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.8 + SR 2.9 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + CM-6(a) + PR.PT-1 + Req-10.7 + R71 + 10.5.1 + 10.5 + Log files that are not properly rotated run the risk of growing so large +that they fill up the /var/log partition. Valuable logging information could be lost +if the /var/log partition becomes full. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { ( grep -qP "^ID=[\"']?ol[\"']?$" "/etc/os-release" && { real="$(grep -P "^VERSION_ID=[\"']?[\w.]+[\"']?$" /etc/os-release | sed "s/^VERSION_ID=[\"']\?\([^\"']\+\)[\"']\?$/\1/")"; expected="9"; printf "%s\n%s" "$expected" "$real" | sort -VC; } && rpm --quiet -q logrotate ); }; then + +SYSTEMCTL_EXEC='/usr/bin/systemctl' +if [[ $("$SYSTEMCTL_EXEC" is-system-running) != "offline" ]]; then + "$SYSTEMCTL_EXEC" start 'logrotate.timer' +fi +"$SYSTEMCTL_EXEC" enable 'logrotate.timer' + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-10.7 + - PCI-DSSv4-10.5 + - PCI-DSSv4-10.5.1 + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - timer_logrotate_enabled + +- name: Enable timer logrotate + block: + + - name: Gather the package facts + package_facts: + manager: auto + + - name: Enable timer logrotate + systemd: + name: logrotate.timer + enabled: 'yes' + state: started + when: + - '"logrotate" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - ( ansible_distribution == 'OracleLinux' and ansible_distribution_version is version('9', + '>=') and "logrotate" in ansible_facts.packages ) + tags: + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-10.7 + - PCI-DSSv4-10.5 + - PCI-DSSv4-10.5.1 + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - timer_logrotate_enabled + + + + + + + + + + + Configure rsyslogd to Accept Remote Messages If Acting as a Log Server + By default, rsyslog does not listen over the network +for log messages. If needed, modules can be enabled to allow +the rsyslog daemon to receive messages from other systems and for the system +thus to act as a log server. +If the system is not a log server, then lines concerning these modules +should remain commented out. + + + + + Ensure syslog-ng is Installed + syslog-ng can be installed in replacement of rsyslog. +The syslog-ng-core package can be installed with the following command: + +$ sudo yum install syslog-ng-core + + 1 + 14 + 15 + 16 + 3 + 5 + 6 + APO11.04 + BAI03.05 + DSS05.04 + DSS05.07 + MEA02.01 + CCI-001311 + CCI-001312 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.4.4.7 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.8 + SR 2.9 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + CM-6(a) + PR.PT-1 + The syslog-ng-core package provides the syslog-ng daemon, which provides +system logging services. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +if ! rpm -q --quiet "syslog-ng" ; then + yum install -y "syslog-ng" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-53-CM-6(a) + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - package_syslogng_installed + +- name: Ensure syslog-ng is installed + package: + name: syslog-ng + state: present + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-CM-6(a) + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - package_syslogng_installed + + include install_syslog-ng + +class install_syslog-ng { + package { 'syslog-ng': + ensure => 'installed', + } +} + + +package --add=syslog-ng + + +[[packages]] +name = "syslog-ng" +version = "*" + + + + + + + + + + Enable syslog-ng Service + The syslog-ng service (in replacement of rsyslog) provides syslog-style logging by default on Debian. + +The syslog-ng service can be enabled with the following command: +$ sudo systemctl enable syslog-ng.service + + 1 + 12 + 13 + 14 + 15 + 16 + 2 + 3 + 5 + 6 + 7 + 8 + 9 + APO10.01 + APO10.03 + APO10.04 + APO10.05 + APO11.04 + APO13.01 + BAI03.05 + BAI04.04 + DSS01.03 + DSS03.05 + DSS05.02 + DSS05.04 + DSS05.05 + DSS05.07 + MEA01.01 + MEA01.02 + MEA01.03 + MEA01.04 + MEA01.05 + MEA02.01 + CCI-001311 + CCI-001312 + CCI-001557 + CCI-001851 + 4.3.2.6.7 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.4.4.7 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.8 + SR 2.9 + SR 6.1 + SR 6.2 + SR 7.1 + SR 7.2 + A.12.1.3 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.14.2.7 + A.15.2.1 + A.15.2.2 + A.17.2.1 + CM-6(a) + AU-4(1) + DE.CM-1 + DE.CM-3 + DE.CM-7 + ID.SC-4 + PR.DS-4 + PR.PT-1 + The syslog-ng service must be running in order to provide +logging services, which are essential to system administration. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +SYSTEMCTL_EXEC='/usr/bin/systemctl' +"$SYSTEMCTL_EXEC" unmask 'syslog-ng.service' +if [[ $("$SYSTEMCTL_EXEC" is-system-running) != "offline" ]]; then + "$SYSTEMCTL_EXEC" start 'syslog-ng.service' +fi +"$SYSTEMCTL_EXEC" enable 'syslog-ng.service' + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-53-AU-4(1) + - NIST-800-53-CM-6(a) + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_syslogng_enabled + +- name: Enable syslog-ng Service - Enable service syslog-ng + block: + + - name: Gather the package facts + package_facts: + manager: auto + + - name: Enable syslog-ng Service - Enable Service syslog-ng + ansible.builtin.systemd: + name: syslog-ng + enabled: true + state: started + masked: false + when: + - '"syslog-ng" in ansible_facts.packages' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-AU-4(1) + - NIST-800-53-CM-6(a) + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_syslogng_enabled + + include enable_syslog-ng + +class enable_syslog-ng { + service {'syslog-ng': + enable => true, + ensure => 'running', + } +} + + +[customizations.services] +enabled = ["syslog-ng"] + + + + + + + + + + Enable rsyslog to Accept Messages via TCP, if Acting As Log Server + The rsyslog daemon should not accept remote messages +unless the system acts as a log server. +If the system needs to act as a central log server, add the following lines to +/etc/rsyslog.conf to enable reception of messages over TCP: +$ModLoad imtcp +$InputTCPServerRun 514 + + 1 + 14 + 15 + 16 + 3 + 5 + 6 + APO11.04 + BAI03.05 + DSS05.04 + DSS05.07 + MEA02.01 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.4.4.7 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.8 + SR 2.9 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + CIP-004-6 R2.2.2 + CIP-004-6 R3.3 + CIP-007-3 R.1.3 + CIP-007-3 R5 + CIP-007-3 R5.1.1 + CIP-007-3 R6.5 + CM-6(a) + AU-6(3) + AU-6(4) + PR.PT-1 + If the system needs to act as a log server, this ensures that it can receive +messages over a reliable TCP connection. + + + Enable rsyslog to Accept Messages via UDP, if Acting As Log Server + The rsyslog daemon should not accept remote messages +unless the system acts as a log server. +If the system needs to act as a central log server, add the following lines to +/etc/rsyslog.conf to enable reception of messages over UDP: +$ModLoad imudp +$UDPServerRun 514 + + 1 + 14 + 15 + 16 + 3 + 5 + 6 + APO11.04 + BAI03.05 + DSS05.04 + DSS05.07 + MEA02.01 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.4.4.7 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.8 + SR 2.9 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + CIP-004-6 R2.2.2 + CIP-004-6 R3.3 + CIP-007-3 R.1.3 + CIP-007-3 R5 + CIP-007-3 R5.1.1 + CIP-007-3 R6.5 + CM-6(a) + AU-6(3) + AU-6(4) + PR.PT-1 + Many devices, such as switches, routers, and other Unix-like systems, may only support +the traditional syslog transmission over UDP. If the system must act as a log server, +this enables it to receive their messages as well. + + + Ensure rsyslog Does Not Accept Remote Messages Unless Acting As Log Server + The rsyslog daemon should not accept remote messages unless the system acts as a log +server. To ensure that it is not listening on the network, ensure any of the following lines +are not found in rsyslog configuration files. + +If using legacy syntax: +$ModLoad imtcp +$InputTCPServerRun port +$ModLoad imudp +$UDPServerRun port +$ModLoad imrelp +$InputRELPServerRun port + + +If using RainerScript syntax: +module(load="imtcp") +module(load="imudp") +input(type="imtcp" port="514") +input(type="imudp" port="514") + + + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 4 + 5 + 6 + 8 + 9 + APO01.06 + APO11.04 + APO13.01 + BAI03.05 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS01.05 + DSS03.01 + DSS05.02 + DSS05.04 + DSS05.07 + DSS06.02 + MEA02.01 + CCI-000366 + 4.2.3.4 + 4.3.3.3.9 + 4.3.3.4 + 4.3.3.5.8 + 4.3.4.3.2 + 4.3.4.3.3 + 4.3.4.4.7 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + 4.4.3.3 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.8 + SR 2.9 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 7.1 + SR 7.6 + 0988 + 1405 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.12.1.1 + A.12.1.2 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.5.1 + A.12.6.2 + A.12.7.1 + A.13.1.1 + A.13.1.2 + A.13.1.3 + A.13.2.1 + A.13.2.2 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CM-7(a) + CM-7(b) + CM-6(a) + DE.AE-1 + ID.AM-3 + PR.AC-5 + PR.DS-5 + PR.IP-1 + PR.PT-1 + PR.PT-4 + SRG-OS-000480-GPOS-00227 + OL09-00-005030 + SV-271857r1092283_rule + Any process which receives messages from the network incurs some risk of receiving malicious +messages. This risk can be eliminated for rsyslog by configuring it not to listen on the +network. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +legacy_regex='^\s*\$(((Input(TCP|RELP)|UDP)ServerRun)|ModLoad\s+(imtcp|imudp|imrelp))' +rainer_regex='^\s*(module|input)\((load|type)="(imtcp|imudp)".*$' + +readarray -t legacy_targets < <(grep -l -E -r "${legacy_regex[@]}" /etc/rsyslog.conf /etc/rsyslog.d/) +readarray -t rainer_targets < <(grep -l -E -r "${rainer_regex[@]}" /etc/rsyslog.conf /etc/rsyslog.d/) + +config_changed=false +if [ ${#legacy_targets[@]} -gt 0 ]; then + for target in "${legacy_targets[@]}"; do + sed -E -i "/$legacy_regex/ s/^/# /" "$target" + done + config_changed=true +fi + +if [ ${#rainer_targets[@]} -gt 0 ]; then + for target in "${rainer_targets[@]}"; do + sed -E -i "/$rainer_regex/ s/^/# /" "$target" + done + config_changed=true +fi + +if $config_changed; then + systemctl restart rsyslog.service +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-005030 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - rsyslog_nolisten + +- name: Ensure rsyslog Does Not Accept Remote Messages Unless Acting As Log Server + - Define Rsyslog Config Lines Regex in Legacy Syntax + ansible.builtin.set_fact: + rsyslog_listen_legacy_regex: ^\s*\$(((Input(TCP|RELP)|UDP)ServerRun)|ModLoad\s+(imtcp|imudp|imrelp)) + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-005030 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - rsyslog_nolisten + +- name: Ensure rsyslog Does Not Accept Remote Messages Unless Acting As Log Server + - Search for Legacy Config Lines in Rsyslog Main Config File + ansible.builtin.find: + paths: /etc + pattern: rsyslog.conf + contains: '{{ rsyslog_listen_legacy_regex }}' + register: rsyslog_listen_legacy_main_file + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-005030 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - rsyslog_nolisten + +- name: Ensure rsyslog Does Not Accept Remote Messages Unless Acting As Log Server + - Search for Legacy Config Lines in Rsyslog Include Files + ansible.builtin.find: + paths: /etc/rsyslog.d/ + pattern: '*.conf' + contains: '{{ rsyslog_listen_legacy_regex }}' + register: rsyslog_listen_legacy_include_files + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-005030 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - rsyslog_nolisten + +- name: Ensure rsyslog Does Not Accept Remote Messages Unless Acting As Log Server + - Assemble List of Config Files With Listen Lines in Legacy Syntax + ansible.builtin.set_fact: + rsyslog_legacy_remote_listen_files: '{{ rsyslog_listen_legacy_main_file.files + | map(attribute=''path'') | list + rsyslog_listen_legacy_include_files.files + | map(attribute=''path'') | list }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-005030 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - rsyslog_nolisten + +- name: Ensure rsyslog Does Not Accept Remote Messages Unless Acting As Log Server + - Comment Listen Config Lines Wherever Defined Using Legacy Syntax + ansible.builtin.replace: + path: '{{ item }}' + regexp: '{{ rsyslog_listen_legacy_regex }}' + replace: '# \1' + loop: '{{ rsyslog_legacy_remote_listen_files }}' + register: rsyslog_listen_legacy_comment + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - rsyslog_legacy_remote_listen_files | length > 0 + tags: + - DISA-STIG-OL09-00-005030 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - rsyslog_nolisten + +- name: Ensure rsyslog Does Not Accept Remote Messages Unless Acting As Log Server + - Define Rsyslog Config Lines Regex in RainerScript Syntax + ansible.builtin.set_fact: + rsyslog_listen_rainer_regex: ^\s*(module|input)\((load|type)="(imtcp|imudp)".*$ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-005030 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - rsyslog_nolisten + +- name: Ensure rsyslog Does Not Accept Remote Messages Unless Acting As Log Server + - Search for RainerScript Config Lines in Rsyslog Main Config File + ansible.builtin.find: + paths: /etc + pattern: rsyslog.conf + contains: '{{ rsyslog_listen_rainer_regex }}' + register: rsyslog_rainer_remote_main_file + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-005030 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - rsyslog_nolisten + +- name: Ensure rsyslog Does Not Accept Remote Messages Unless Acting As Log Server + - Search for RainerScript Config Lines in Rsyslog Include Files + ansible.builtin.find: + paths: /etc/rsyslog.d/ + pattern: '*.conf' + contains: '{{ rsyslog_listen_rainer_regex }}' + register: rsyslog_rainer_remote_include_files + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-005030 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - rsyslog_nolisten + +- name: Ensure rsyslog Does Not Accept Remote Messages Unless Acting As Log Server + - Assemble List of Config Files With Listen Lines in RainerScript + ansible.builtin.set_fact: + rsyslog_rainer_remote_listen_files: '{{ rsyslog_rainer_remote_main_file.files + | map(attribute=''path'') | list + rsyslog_rainer_remote_include_files.files + | map(attribute=''path'') | list }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-005030 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - rsyslog_nolisten + +- name: Ensure rsyslog Does Not Accept Remote Messages Unless Acting As Log Server + - Comment Listen Config Lines Wherever Defined Using RainerScript + ansible.builtin.replace: + path: '{{ item }}' + regexp: '{{ rsyslog_listen_rainer_regex }}' + replace: '# \1' + loop: '{{ rsyslog_rainer_remote_listen_files }}' + register: rsyslog_listen_rainer_comment + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - rsyslog_rainer_remote_listen_files | length > 0 + tags: + - DISA-STIG-OL09-00-005030 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - rsyslog_nolisten + +- name: Ensure rsyslog Does Not Accept Remote Messages Unless Acting As Log Server + - Restart Rsyslog if Any Line Were Commented Out + ansible.builtin.service: + name: rsyslog + state: restarted + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - rsyslog_listen_legacy_comment is changed or rsyslog_listen_rainer_comment is changed + tags: + - DISA-STIG-OL09-00-005030 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - rsyslog_nolisten + + + + + + + + + + + Rsyslog Logs Sent To Remote Host + If system logs are to be useful in detecting malicious +activities, it is necessary to send logs to a remote server. An +intruder who has compromised the root account on a system may +delete the log entries which indicate that the system was attacked +before they are seen by an administrator. + + +However, it is recommended that logs be stored on the local +host in addition to being sent to the loghost, especially if +rsyslog has been configured to use the UDP protocol to send +messages over a network. UDP does not guarantee reliable delivery, +and moderately busy sites will lose log messages occasionally, +especially in periods of high traffic which may be the result of an +attack. In addition, remote rsyslog messages are not +authenticated in any way by default, so it is easy for an attacker to +introduce spurious messages to the central log server. Also, some +problems cause loss of network connectivity, which will prevent the +sending of messages to the central server. For all of these reasons, it is +better to store log messages both centrally and on each host, so +that they can be correlated if necessary. + + Remote Log Server + Specify an URI or IP address of a remote host where the log messages will be sent and stored. + logcollector + + + Ensure Logs Sent To Remote Host + To configure rsyslog to send logs to a remote log server, +open /etc/rsyslog.conf and read and understand the last section of the file, +which describes the multiple directives necessary to activate remote +logging. +Along with these other directives, the system can be configured +to forward its logs to a particular log server by +adding or correcting one of the following lines, +substituting appropriately. +The choice of protocol depends on the environment of the system; +although TCP and RELP provide more reliable message delivery, +they may not be supported in all environments. + +To use UDP for log message delivery: +*.* @ + + +To use TCP for log message delivery: +*.* @@ + + +To use RELP for log message delivery: +*.* :omrelp: + + +There must be a resolvable DNS CNAME or Alias record set to "" for logs to be sent correctly to the centralized logging utility. + It is important to configure queues in case the client is sending log +messages to a remote server. If queues are not configured, +the system will stop functioning when the connection +to the remote server is not available. Please consult Rsyslog +documentation for more information about configuration of queues. The +example configuration which should go into /etc/rsyslog.conf +can look like the following lines: + +$ActionQueueType LinkedList +$ActionQueueFileName queuefilename +$ActionQueueMaxDiskSpace 1g +$ActionQueueSaveOnShutdown on +$ActionResumeRetryCount -1 + + + 1 + 13 + 14 + 15 + 16 + 2 + 3 + 5 + 6 + APO11.04 + APO13.01 + BAI03.05 + BAI04.04 + DSS05.04 + DSS05.07 + MEA02.01 + CCI-000366 + CCI-001851 + 164.308(a)(1)(ii)(D) + 164.308(a)(5)(ii)(B) + 164.308(a)(5)(ii)(C) + 164.308(a)(6)(ii) + 164.308(a)(8) + 164.310(d)(2)(iii) + 164.312(b) + 164.314(a)(2)(i)(C) + 164.314(a)(2)(iii) + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.4.4.7 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.8 + SR 2.9 + SR 7.1 + SR 7.2 + 0988 + 1405 + A.12.1.3 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.17.2.1 + CIP-003-8 R5.2 + CIP-004-6 R3.3 + CM-6(a) + AU-4(1) + AU-9(2) + PR.DS-4 + PR.PT-1 + SRG-OS-000479-GPOS-00224 + SRG-OS-000480-GPOS-00227 + SRG-OS-000342-GPOS-00133 + R71 + OL09-00-005005 + SV-271852r1092608_rule + A log server (loghost) receives syslog messages from one or more +systems. This data can be used as an additional log source in the event a +system is compromised and its local logs are suspect. Forwarding log messages +to a remote loghost also provides system administrators with a centralized +place to view the status of multiple hosts within the enterprise. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +rsyslog_remote_loghost_address='' + + +# Strip any search characters in the key arg so that the key can be replaced without +# adding any search characters to the config file. +stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^\*\.\*") + +# shellcheck disable=SC2059 +printf -v formatted_output "%s %s" "$stripped_key" "@@$rsyslog_remote_loghost_address" + +# If the key exists, change it. Otherwise, add it to the config_file. +# We search for the key string followed by a word boundary (matched by \>), +# so if we search for 'setting', 'setting2' won't match. +if LC_ALL=C grep -q -m 1 -i -e "^\*\.\*\\>" "/etc/rsyslog.conf"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + LC_ALL=C sed -i --follow-symlinks "s/^\*\.\*\\>.*/$escaped_formatted_output/gi" "/etc/rsyslog.conf" +else + if [[ -s "/etc/rsyslog.conf" ]] && [[ -n "$(tail -c 1 -- "/etc/rsyslog.conf" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "/etc/rsyslog.conf" + fi + printf '%s\n' "$formatted_output" >> "/etc/rsyslog.conf" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-005005 + - NIST-800-53-AU-4(1) + - NIST-800-53-AU-9(2) + - NIST-800-53-CM-6(a) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - rsyslog_remote_loghost +- name: XCCDF Value rsyslog_remote_loghost_address # promote to variable + set_fact: + rsyslog_remote_loghost_address: !!str + tags: + - always + +- name: Set rsyslog remote loghost + lineinfile: + dest: /etc/rsyslog.conf + regexp: ^\*\.\* + line: '*.* @@{{ rsyslog_remote_loghost_address }}' + create: true + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-005005 + - NIST-800-53-AU-4(1) + - NIST-800-53-AU-9(2) + - NIST-800-53-CM-6(a) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - rsyslog_remote_loghost + + + + + + + + + + Configure TLS for rsyslog remote logging + Configure rsyslog to use Transport Layer +Security (TLS) support for logging to remote server +for the Forwarding Output Module in /etc/rsyslog.conf +using action. You can use the following command: +echo 'action(type="omfwd" protocol="tcp" Target="<remote system>" port="6514" + StreamDriver="gtls" StreamDriverMode="1" StreamDriverAuthMode="x509/name" streamdriver.CheckExtendedKeyPurpose="on")' >> /etc/rsyslog.conf + +Replace the <remote system> in the above command with an IP address or a host name of the remote logging server. + 0988 + 1405 + AU-9(3) + CM-6(a) + SRG-OS-000480-GPOS-00227 + SRG-OS-000120-GPOS-00061 + R71 + For protection of data being logged, the connection to the +remote logging server needs to be authenticated and encrypted. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +rsyslog_remote_loghost_address='' + +params_to_add_if_missing=("protocol" "target" "port" "StreamDriver" "StreamDriverMode" "StreamDriverAuthMode" "streamdriver.CheckExtendedKeyPurpose") +values_to_add_if_missing=("tcp" "$rsyslog_remote_loghost_address" "6514" "gtls" "1" "x509/name" "on") +params_to_replace_if_wrong_value=("protocol" "StreamDriver" "StreamDriverMode" "StreamDriverAuthMode" "streamdriver.CheckExtendedKeyPurpose") +values_to_replace_if_wrong_value=("tcp" "gtls" "1" "x509/name" "on") + +files_containing_omfwd=("$(grep -ilE '^[^#]*\s*action\s*\(\s*type\s*=\s*"omfwd".*' /etc/rsyslog.conf /etc/rsyslog.d/*.conf)") +if [ -n "${files_containing_omfwd[*]}" ]; then + for file in "${files_containing_omfwd[@]}"; do + for ((i=0; i<${#params_to_replace_if_wrong_value[@]}; i++)); do + sed -i -E -e 'H;$!d;x;s/^\n//' -e "s|(\s*action\s*\(\s*type\s*=\s*[\"]omfwd[\"].*?)${params_to_replace_if_wrong_value[$i]}\s*=\s*[\"]\S*[\"](.*\))|\1${params_to_replace_if_wrong_value[$i]}=\"${values_to_replace_if_wrong_value[$i]}\"\2|gI" "$file" + done + for ((i=0; i<${#params_to_add_if_missing[@]}; i++)); do + if ! grep -qPzi "(?s)\s*action\s*\(\s*type\s*=\s*[\"]omfwd[\"].*?${params_to_add_if_missing[$i]}.*?\).*" "$file"; then + sed -i -E -e 'H;$!d;x;s/^\n//' -e "s|(\s*action\s*\(\s*type\s*=\s*[\"]omfwd[\"])|\1\n${params_to_add_if_missing[$i]}=\"${values_to_add_if_missing[$i]}\"|gI" "$file" + fi + done + done +else + echo "action(type=\"omfwd\" protocol=\"tcp\" Target=\"$rsyslog_remote_loghost_address\" port=\"6514\" StreamDriver=\"gtls\" StreamDriverMode=\"1\" StreamDriverAuthMode=\"x509/name\" streamdriver.CheckExtendedKeyPurpose=\"on\")" >> /etc/rsyslog.conf +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-53-AU-9(3) + - NIST-800-53-CM-6(a) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - rsyslog_remote_tls +- name: XCCDF Value rsyslog_remote_loghost_address # promote to variable + set_fact: + rsyslog_remote_loghost_address: !!str + tags: + - always + +- name: 'Configure TLS for rsyslog remote logging: search for omfwd action directive + in rsyslog include files' + ansible.builtin.find: + paths: /etc/rsyslog.d/ + pattern: '*.conf' + contains: ^\s*action\s*\(\s*type\s*=\s*"omfwd".* + register: rsyslog_includes_with_directive + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-AU-9(3) + - NIST-800-53-CM-6(a) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - rsyslog_remote_tls + +- name: 'Configure TLS for rsyslog remote logging: search for omfwd action directive + in rsyslog main config file' + ansible.builtin.find: + paths: /etc + pattern: rsyslog.conf + contains: ^\s*action\s*\(\s*type\s*=\s*"omfwd".* + register: rsyslog_main_file_with_directive + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-AU-9(3) + - NIST-800-53-CM-6(a) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - rsyslog_remote_tls + +- name: 'Configure TLS for rsyslog remote logging: declare Rsyslog option parameters + to be inserted if entirely missing' + ansible.builtin.set_fact: + rsyslog_parameters_to_add_if_missing: + - protocol + - target + - port + - StreamDriver + - StreamDriverMode + - StreamDriverAuthMode + - streamdriver.CheckExtendedKeyPurpose + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-AU-9(3) + - NIST-800-53-CM-6(a) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - rsyslog_remote_tls + +- name: 'Configure TLS for rsyslog remote logging: declare Rsyslog option values to + be inserted if entirely missing' + ansible.builtin.set_fact: + rsyslog_values_to_add_if_missing: + - tcp + - '{{ rsyslog_remote_loghost_address }}' + - '6514' + - gtls + - '1' + - x509/name + - 'on' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-AU-9(3) + - NIST-800-53-CM-6(a) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - rsyslog_remote_tls + +- name: 'Configure TLS for rsyslog remote logging: declare Rsyslog option parameters + to be replaced if defined with wrong values' + ansible.builtin.set_fact: + rsyslog_parameters_to_replace_if_wrong_value: + - protocol + - StreamDriver + - StreamDriverMode + - StreamDriverAuthMode + - streamdriver.CheckExtendedKeyPurpose + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-AU-9(3) + - NIST-800-53-CM-6(a) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - rsyslog_remote_tls + +- name: 'Configure TLS for rsyslog remote logging: declare Rsyslog option values to + be replaced when having wrong value' + ansible.builtin.set_fact: + rsyslog_values_to_replace_if_wrong_value: + - tcp + - gtls + - '1' + - x509/name + - 'on' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-AU-9(3) + - NIST-800-53-CM-6(a) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - rsyslog_remote_tls + +- name: 'Configure TLS for rsyslog remote logging: assemble list of files with existing + directives' + ansible.builtin.set_fact: + rsyslog_files: '{{ rsyslog_includes_with_directive.files | map(attribute=''path'') + | list + rsyslog_main_file_with_directive.files | map(attribute=''path'') | + list }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-AU-9(3) + - NIST-800-53-CM-6(a) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - rsyslog_remote_tls + +- name: 'Configure TLS for rsyslog remote logging: try to fix existing directives' + block: + + - name: 'Configure TLS for rsyslog remote logging: Fix existing omfwd directives + by adjusting the value' + ansible.builtin.replace: + path: '{{ item[0] }}' + regexp: (?i)^(\s*action\s*\(\s*type\s*=\s*"omfwd"[\s\S]*)({{ item[1][0] | regex_escape() + }}\s*=\s*"\S*")([\s\S]*\))$ + replace: \1{{ item[1][0] }}="{{ item[1][1] }}"\3 + loop: '{{ rsyslog_files | product (rsyslog_parameters_to_replace_if_wrong_value + | zip(rsyslog_values_to_replace_if_wrong_value)) | list }}' + + - name: 'Configure TLS for rsyslog remote logging: Fix existing omfwd directives + by adding parameter and value' + ansible.builtin.replace: + path: '{{ item[0] }}' + regexp: (?i)^(\s*action\s*\(\s*type\s*=\s*"omfwd"(?:[\s\S](?!{{ item[1][0] | + regex_escape() }}))*.)(\))$ + replace: \1 {{ item[1][0] }}="{{ item[1][1] }}" \2 + loop: '{{ rsyslog_files | product (rsyslog_parameters_to_add_if_missing | zip(rsyslog_values_to_add_if_missing)) + | list }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - rsyslog_includes_with_directive.matched or rsyslog_main_file_with_directive.matched + tags: + - NIST-800-53-AU-9(3) + - NIST-800-53-CM-6(a) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - rsyslog_remote_tls + +- name: 'Configure TLS for rsyslog remote logging: Add missing rsyslog directive' + ansible.builtin.lineinfile: + dest: /etc/rsyslog.conf + line: action(type="omfwd" protocol="tcp" Target="{{ rsyslog_remote_loghost_address + }}" port="6514" StreamDriver="gtls" StreamDriverMode="1" StreamDriverAuthMode="x509/name" + streamdriver.CheckExtendedKeyPurpose="on") + create: true + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - not rsyslog_includes_with_directive.matched and not rsyslog_main_file_with_directive.matched + tags: + - NIST-800-53-AU-9(3) + - NIST-800-53-CM-6(a) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - rsyslog_remote_tls + + + + + + + + + + Configure CA certificate for rsyslog remote logging + Configure CA certificate for rsyslog logging +to remote server using Transport Layer Security (TLS) +using correct path for the DefaultNetstreamDriverCAFile +global option in /etc/rsyslog.conf, for example with the following command: +echo 'global(DefaultNetstreamDriverCAFile="/etc/pki/tls/cert.pem")' >> /etc/rsyslog.conf +Replace the /etc/pki/tls/cert.pem in the above command with the path to the file with CA certificate generated for the purpose of remote logging. + Automatic remediation is not available as each organization has unique requirements. + 0988 + 1405 + SRG-OS-000480-GPOS-00227 + R71 + The CA certificate needs to be set or rsyslog.service +fails to start with +error: ca certificate is not set, cannot continue + + + + + + + + + + + + Network Configuration and Firewalls + Most systems must be connected to a network of some +sort, and this brings with it the substantial risk of network +attack. This section discusses the security impact of decisions +about networking which must be made when configuring a system. + + +This section also discusses firewalls, network access +controls, and other network security frameworks, which allow +system-level rules to be written that can limit an attackers' ability +to connect to your system. These rules can specify that network +traffic should be allowed or denied from certain IP addresses, +hosts, and networks. The rules can also specify which of the +system's network services are available to particular hosts or +networks. + + Configure Multiple DNS Servers in /etc/resolv.conf + +Determine whether the system is using local or DNS name resolution with the +following command: +$ sudo grep hosts /etc/nsswitch.conf +hosts: files dns +If the DNS entry is missing from the host's line in the "/etc/nsswitch.conf" +file, the "/etc/resolv.conf" file must be empty. +Verify the "/etc/resolv.conf" file is empty with the following command: +$ sudo ls -al /etc/resolv.conf +-rw-r--r-- 1 root root 0 Aug 19 08:31 resolv.conf +If the DNS entry is found on the host's line of the "/etc/nsswitch.conf" file, +then verify the following: + +Multiple Domain Name System (DNS) Servers should be configured +in /etc/resolv.conf. This provides redundant name resolution services +in the event that a domain server crashes. To configure the system to contain +as least 2 DNS servers, add a corresponding nameserver +ip_address + entry in /etc/resolv.conf for each DNS +server where ip_address is the IP address of a valid DNS server. +For example: +search example.com +nameserver 192.168.0.1 +nameserver 192.168.0.2 + + This rule doesn't come with a remediation, the IP addresses of local authoritative name servers need to be added by the administrator. + 12 + 15 + 8 + APO13.01 + DSS05.02 + CCI-000366 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 7.1 + SR 7.6 + A.13.1.1 + A.13.2.1 + A.14.1.3 + SC-20(a) + CM-6(a) + PR.PT-4 + SRG-OS-000480-GPOS-00227 + OL09-00-006003 + SV-271861r1092295_rule + To provide availability for name resolution services, multiple redundant +name servers are mandated. A failure in name resolution could lead to the +failure of security functions requiring name resolution, which may include +time synchronization, centralized authentication, and remote system logging. + + + + + + + + + Prevent non-Privileged Users from Modifying Network Interfaces using nmcli + By default, non-privileged users are given permissions to modify networking +interfaces and configurations using the nmcli command. Non-privileged +users should not be making configuration changes to network configurations. To +ensure that non-privileged users do not have permissions to make changes to the +network configuration using nmcli, create the following configuration in +/etc/polkit-1/localauthority/20-org.d/10-nm-harden-access.pkla: + +[Disable General User Access to NetworkManager] +Identity=default +Action=org.freedesktop.NetworkManager.* +ResultAny=no +ResultInactive=no +ResultActive=auth_admin + + + 3.1.16 + 0418 + 1055 + 1402 + AC-18(4) + CM-6(a) + 1.2.8 + 1.2 + Allowing non-privileged users to make changes to network settings can allow +untrusted access, prevent system availability, and/or can lead to a compromise or +attack. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q polkit; then + +printf "[Disable General User Access to NetworkManager]\nIdentity=default\nAction=org.freedesktop.NetworkManager.*\nResultAny=no\nResultInactive=no\nResultActive=auth_admin\n" > /etc/polkit-1/localauthority/20-org.d/10-nm-harden-access.pkla + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-171-3.1.16 + - NIST-800-53-AC-18(4) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-1.2 + - PCI-DSSv4-1.2.8 + - low_complexity + - low_disruption + - medium_severity + - network_nmcli_permissions + - no_reboot_needed + - restrict_strategy + +- name: Ensure non-privileged users do not have access to nmcli + ini_file: + path: /etc/polkit-1/localauthority/20-org.d/10-nm-harden-access.pkla + section: Disable General User Access to NetworkManager + option: '{{ item.option }}' + value: '{{ item.value }}' + no_extra_spaces: true + create: true + loop: + - option: Identity + value: default + - option: Action + value: org.freedesktop.NetworkManager.* + - option: ResultAny + value: 'no' + - option: ResultInactive + value: 'no' + - option: ResultActive + value: auth_admin + when: '"polkit" in ansible_facts.packages' + tags: + - NIST-800-171-3.1.16 + - NIST-800-53-AC-18(4) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-1.2 + - PCI-DSSv4-1.2.8 + - low_complexity + - low_disruption + - medium_severity + - network_nmcli_permissions + - no_reboot_needed + - restrict_strategy + + + + + + + + + + Ensure System is Not Acting as a Network Sniffer + The system should not be acting as a network sniffer, which can +capture all traffic on the network to which it is connected. Run the following +to determine if any interface is running in promiscuous mode: +$ ip link | grep PROMISC +Promiscuous mode of an interface can be disabled with the following command: +$ sudo ip link set dev device_name multicast off promisc off + + 1 + 11 + 14 + 3 + 9 + APO11.06 + APO12.06 + BAI03.10 + BAI09.01 + BAI09.02 + BAI09.03 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS01.05 + DSS04.05 + DSS05.02 + DSS05.05 + DSS06.06 + CCI-000366 + 4.2.3.4 + 4.3.3.3.7 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.2 + 4.3.4.3.3 + 4.4.3.4 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 7.6 + SR 7.8 + A.11.1.2 + A.11.2.4 + A.11.2.5 + A.11.2.6 + A.12.1.2 + A.12.5.1 + A.12.6.2 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.16.1.6 + A.8.1.1 + A.8.1.2 + A.9.1.2 + CM-7(a) + CM-7(b) + CM-6(a) + CM-7(2) + MA-3 + DE.DP-5 + ID.AM-1 + PR.IP-1 + PR.MA-1 + PR.PT-3 + SRG-OS-000480-GPOS-00227 + 1.4.5 + 1.4 + OL09-00-006004 + SV-271862r1092298_rule + Network interfaces in promiscuous mode allow for the capture of all network traffic +visible to the system. If unauthorized individuals can access these applications, it +may allow them to collect information such as logon IDs, passwords, and key exchanges +between systems. + + +If the system is being used to perform a network troubleshooting function, the use of these +tools must be documented with the Information Systems Security Manager (ISSM) and restricted +to only authorized personnel. + + # Remediation is applicable only in certain platforms +if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then + +for interface in $(ip -o link show | cut -d ":" -f 2); do + ip link set dev $interface multicast off promisc off +done + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Ensure System is Not Acting as a Network Sniffer - Gather network interfaces + ansible.builtin.command: + cmd: ip -o link show + register: network_interfaces + when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + tags: + - DISA-STIG-OL09-00-006004 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(2) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MA-3 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.5 + - low_complexity + - low_disruption + - medium_severity + - network_sniffer_disabled + - no_reboot_needed + - restrict_strategy + +- name: Ensure System is Not Acting as a Network Sniffer - Disable promiscuous mode + ansible.builtin.command: + cmd: ip link set dev {{ item.split(':')[1] }} multicast off promisc off + loop: '{{ network_interfaces.stdout_lines }}' + when: + - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - network_interfaces.stdout_lines is defined and "item.split(':') | length == 3" + tags: + - DISA-STIG-OL09-00-006004 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(2) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MA-3 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.5 + - low_complexity + - low_disruption + - medium_severity + - network_sniffer_disabled + - no_reboot_needed + - restrict_strategy + + + + + + + + + + firewalld + The dynamic firewall daemon firewalld provides a +dynamically managed firewall with support for network “zones” to assign +a level of trust to a network and its associated connections and interfaces. +It has support for IPv4 and IPv6 firewall settings. It supports Ethernet +bridges and has a separation of runtime and permanent configuration options. +It also has an interface for services or applications to add firewall rules +directly. + +A graphical configuration tool, firewall-config, is used to configure +firewalld, which in turn uses iptables tool to communicate +with Netfilter in the kernel which implements packet filtering. + +The firewall service provided by firewalld is dynamic rather than +static because changes to the configuration can be made at anytime and are +immediately implemented. There is no need to save or apply the changes. No +unintended disruption of existing network connections occurs as no part of +the firewall has to be reloaded. + + + Configure Firewalld to Use the Nftables Backend + Firewalld can be configured with many backends, such as nftables. + CCI-002385 + SC-5 + SRG-OS-000420-GPOS-00186 + OL09-00-006000 + SV-271858r1092286_rule + Nftables is modern kernel module for controling network connections coming into a system. +Utilizing the limit statement in "nftables" can help to mitigate DoS attacks. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q firewalld; }; then + +if [ -e "/etc/firewalld/firewalld.conf" ] ; then + + LC_ALL=C sed -i "/^\s*FirewallBackend\s*=\s*/d" "/etc/firewalld/firewalld.conf" +else + touch "/etc/firewalld/firewalld.conf" +fi +# make sure file has newline at the end +sed -i -e '$a\' "/etc/firewalld/firewalld.conf" + +cp "/etc/firewalld/firewalld.conf" "/etc/firewalld/firewalld.conf.bak" +# Insert before the line matching the regex '^#\s*FirewallBackend'. +line_number="$(LC_ALL=C grep -n "^#\s*FirewallBackend" "/etc/firewalld/firewalld.conf.bak" | LC_ALL=C sed 's/:.*//g')" +if [ -z "$line_number" ]; then + # There was no match of '^#\s*FirewallBackend', insert at + # the end of the file. + printf '%s\n' "FirewallBackend=nftables" >> "/etc/firewalld/firewalld.conf" +else + head -n "$(( line_number - 1 ))" "/etc/firewalld/firewalld.conf.bak" > "/etc/firewalld/firewalld.conf" + printf '%s\n' "FirewallBackend=nftables" >> "/etc/firewalld/firewalld.conf" + tail -n "+$(( line_number ))" "/etc/firewalld/firewalld.conf.bak" >> "/etc/firewalld/firewalld.conf" +fi +# Clean up after ourselves. +rm "/etc/firewalld/firewalld.conf.bak" + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-006000 + - NIST-800-53-SC-5 + - firewalld-backend + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Setting unquoted shell-style assignment of 'FirewallBackend' to 'nftables' + in '/etc/firewalld/firewalld.conf' + block: + + - name: Check for duplicate values + lineinfile: + path: /etc/firewalld/firewalld.conf + create: true + regexp: (?i)^\s*FirewallBackend= + state: absent + check_mode: true + changed_when: false + register: dupes + + - name: Deduplicate values from /etc/firewalld/firewalld.conf + lineinfile: + path: /etc/firewalld/firewalld.conf + create: true + regexp: (?i)^\s*FirewallBackend= + state: absent + when: dupes.found is defined and dupes.found > 1 + + - name: Insert correct line to /etc/firewalld/firewalld.conf + lineinfile: + path: /etc/firewalld/firewalld.conf + create: true + regexp: (?i)^\s*FirewallBackend= + line: FirewallBackend=nftables + state: present + insertbefore: ^# FirewallBackend + validate: /usr/bin/bash -n %s + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"firewalld" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-006000 + - NIST-800-53-SC-5 + - firewalld-backend + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + + + + + + + + + + Inspect and Activate Default firewalld Rules + Firewalls can be used to separate networks into different zones +based on the level of trust the user has decided to place on the devices and +traffic within that network. NetworkManager informs firewalld to which +zone an interface belongs. An interface's assigned zone can be changed by +NetworkManager or via the firewall-config tool. + +The zone settings in /etc/firewalld/ are a range of preset settings +which can be quickly applied to a network interface. These are the zones +provided by firewalld sorted according to the default trust level of the +zones from untrusted to trusted: +dropAny incoming network packets are dropped, there is no +reply. Only outgoing network connections are possible.blockAny incoming network connections are rejected with an +icmp-host-prohibited message for IPv4 and icmp6-adm-prohibited +for IPv6. Only network connections initiated from within the system are +possible.publicFor use in public areas. You do not trust the other +computers on the network to not harm your computer. Only selected incoming +connections are accepted.externalFor use on external networks with masquerading enabled +especially for routers. You do not trust the other computers on the network to +not harm your computer. Only selected incoming connections are accepted.dmzFor computers in your demilitarized zone that are +publicly-accessible with limited access to your internal network. Only selected +incoming connections are accepted.workFor use in work areas. You mostly trust the other computers +on networks to not harm your computer. Only selected incoming connections are +accepted.homeFor use in home areas. You mostly trust the other computers +on networks to not harm your computer. Only selected incoming connections are +accepted.internalFor use on internal networks. You mostly trust the +other computers on the networks to not harm your computer. Only selected +incoming connections are accepted.trustedAll network connections are accepted. + +It is possible to designate one of these zones to be the default zone. When +interface connections are added to NetworkManager, they are assigned +to the default zone. On installation, the default zone in firewalld is set to +be the public zone. + +To find out all the settings of a zone, for example the public zone, +enter the following command as root: +# firewall-cmd --zone=public --list-all +Example output of this command might look like the following: + +# firewall-cmd --zone=public --list-all +public + interfaces: + services: mdns dhcpv6-client ssh + ports: + forward-ports: + icmp-blocks: source-quench + +To view the network zones currently active, enter the following command as root: +# firewall-cmd --get-service +The following listing displays the result of this command +on common Oracle Linux 9 system: + +# firewall-cmd --get-service +amanda-client bacula bacula-client dhcp dhcpv6 dhcpv6-client dns ftp +high-availability http https imaps ipp ipp-client ipsec kerberos kpasswd +ldap ldaps libvirt libvirt-tls mdns mountd ms-wbt mysql nfs ntp openvpn +pmcd pmproxy pmwebapi pmwebapis pop3s postgresql proxy-dhcp radius rpc-bind +samba samba-client smtp ssh telnet tftp tftp-client transmission-client +vnc-server wbem-https + +Finally to view the network zones that will be active after the next firewalld +service reload, enter the following command as root: +# firewall-cmd --get-service --permanent + + + Install firewalld Package + The firewalld package can be installed with the following command: + +$ sudo yum install firewalld + + CCI-000382 + CCI-000366 + CCI-002314 + CCI-002322 + CM-6(a) + FMT_SMF_EXT.1 + SRG-OS-000096-GPOS-00050 + SRG-OS-000297-GPOS-00115 + SRG-OS-000298-GPOS-00116 + SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00232 + A.8.SEC-OL3 + 1.2.1 + 1.2 + OL09-00-000220 + SV-271469r1091119_rule + "Firewalld" provides an easy and effective way to block/limit remote access to the system via ports, services, and protocols. + +Remote access services, such as those providing remote access to network devices and information systems, which lack automated control capabilities, increase risk and make remote user access management difficult at best. + +Remote access is access to DoD nonpublic information systems by an authorized user (or an information system) communicating through an external, non-organization-controlled network. Remote access methods include, for example, dial-up, broadband, and wireless. + +Oracle Linux 9 functionality (e.g., SSH) must be capable of taking enforcement action if the audit reveals unauthorized activity. +Automated control of remote access sessions allows organizations to ensure ongoing compliance with remote access policies by enforcing connection rules of remote access applications on a variety of information system components (e.g., servers, workstations, notebook computers, smartphones, and tablets)." + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +if ! rpm -q --quiet "firewalld" ; then + yum install -y "firewalld" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-000220 + - NIST-800-53-CM-6(a) + - PCI-DSSv4-1.2 + - PCI-DSSv4-1.2.1 + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - package_firewalld_installed + +- name: Ensure firewalld is installed + package: + name: firewalld + state: present + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-000220 + - NIST-800-53-CM-6(a) + - PCI-DSSv4-1.2 + - PCI-DSSv4-1.2.1 + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - package_firewalld_installed + + include install_firewalld + +class install_firewalld { + package { 'firewalld': + ensure => 'installed', + } +} + + +package --add=firewalld + + +[[packages]] +name = "firewalld" +version = "*" + + + + + + + + + + Verify firewalld Enabled + +The firewalld service can be enabled with the following command: +$ sudo systemctl enable firewalld.service + + 11 + 3 + 9 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + 3.1.3 + 3.4.7 + CCI-000382 + CCI-000366 + CCI-002314 + 4.3.4.3.2 + 4.3.4.3.3 + SR 7.6 + A.12.1.2 + A.12.5.1 + A.12.6.2 + A.14.2.2 + A.14.2.3 + A.14.2.4 + CIP-003-8 R4 + CIP-003-8 R5 + CIP-004-6 R3 + AC-4 + CM-7(b) + CA-3(5) + SC-7(21) + CM-6(a) + PR.IP-1 + FMT_SMF_EXT.1 + SRG-OS-000096-GPOS-00050 + SRG-OS-000297-GPOS-00115 + SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00231 + SRG-OS-000480-GPOS-00232 + SYS.1.6.A5 + SYS.1.6.A21 + A.8.SEC-OL3 + 1.2.1 + 1.2 + OL09-00-000221 + SV-271470r1092618_rule + Access control methods provide the ability to enhance system security posture +by restricting services and known good IP addresses and address ranges. This +prevents connections from unknown hosts and protocols. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q firewalld; }; then + +SYSTEMCTL_EXEC='/usr/bin/systemctl' +"$SYSTEMCTL_EXEC" unmask 'firewalld.service' +if [[ $("$SYSTEMCTL_EXEC" is-system-running) != "offline" ]]; then + "$SYSTEMCTL_EXEC" start 'firewalld.service' +fi +"$SYSTEMCTL_EXEC" enable 'firewalld.service' + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-000221 + - NIST-800-171-3.1.3 + - NIST-800-171-3.4.7 + - NIST-800-53-AC-4 + - NIST-800-53-CA-3(5) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-7(21) + - PCI-DSSv4-1.2 + - PCI-DSSv4-1.2.1 + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_firewalld_enabled + +- name: Verify firewalld Enabled - Enable service firewalld + block: + + - name: Gather the package facts + package_facts: + manager: auto + + - name: Verify firewalld Enabled - Enable Service firewalld + ansible.builtin.systemd: + name: firewalld + enabled: true + state: started + masked: false + when: + - '"firewalld" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"firewalld" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-000221 + - NIST-800-171-3.1.3 + - NIST-800-171-3.4.7 + - NIST-800-53-AC-4 + - NIST-800-53-CA-3(5) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-7(21) + - PCI-DSSv4-1.2 + - PCI-DSSv4-1.2.1 + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_firewalld_enabled + + include enable_firewalld + +class enable_firewalld { + service {'firewalld': + enable => true, + ensure => 'running', + } +} + + +[customizations.services] +enabled = ["firewalld"] + + + + + + + + + + + Strengthen the Default Ruleset + The default rules can be strengthened. The system +scripts that activate the firewall rules expect them to be defined +in configuration files under the /etc/firewalld/services +and /etc/firewalld/zones directories. + + +The following recommendations describe how to strengthen the +default ruleset configuration file. An alternative to editing this +configuration file is to create a shell script that makes calls to +the firewall-cmd program to load in rules under the /etc/firewalld/services +and /etc/firewalld/zones directories. + + +Instructions apply to both unless otherwise noted. Language and address +conventions for regular firewalld rules are used throughout this section. + The program firewall-config +allows additional services to penetrate the default firewall rules +and automatically adjusts the firewalld ruleset(s). + + Configure the Firewalld Ports + Configure the firewalld ports to allow approved services to have access to the system. +To configure firewalld to open ports, run the following command: +firewall-cmd --permanent --add-port=port_number/tcp + +To configure firewalld to allow access for pre-defined services, run the following +command: +firewall-cmd --permanent --add-service=service_name + + + 11 + 12 + 14 + 15 + 3 + 8 + 9 + APO13.01 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS01.04 + DSS05.02 + DSS05.03 + DSS05.05 + DSS06.06 + CCI-000382 + CCI-002314 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.2 + 4.3.4.3.3 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 7.1 + SR 7.6 + 1416 + A.11.2.6 + A.12.1.2 + A.12.5.1 + A.12.6.2 + A.13.1.1 + A.13.2.1 + A.14.1.3 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.6.2.1 + A.6.2.2 + A.9.1.2 + AC-4 + CM-7(b) + CA-3(5) + SC-7(21) + CM-6(a) + PR.AC-3 + PR.IP-1 + PR.PT-3 + PR.PT-4 + SRG-OS-000096-GPOS-00050 + SRG-OS-000297-GPOS-00115 + 1.3.1 + 1.3 + OL09-00-000223 + SV-271472r1091128_rule + In order to prevent unauthorized connection of devices, unauthorized transfer of information, +or unauthorized tunneling (i.e., embedding of data types within data types), organizations must +disable or restrict unused or unnecessary physical and logical ports/protocols on information +systems. + + +Operating systems are capable of providing a wide variety of functions and services. +Some of the functions and services provided by default may not be necessary to support +essential organizational operations. +Additionally, it is sometimes convenient to provide multiple services from a single component +(e.g., VPN and IPS); however, doing so increases risk over limiting the services provided by +one component. + + +To support the requirements and principles of least functionality, the operating system must +support the organizational requirements, providing only essential capabilities and limiting the +use of ports, protocols, and/or services to only those required, authorized, and approved to +conduct official business. + + + + + + Firewalld Must Employ a Deny-all, Allow-by-exception Policy for Allowing Connections to Other Systems + Oracle Linux 9 incorporates the "firewalld" daemon, which allows for many different configurations. One of these configurations is zones. +Zones can be utilized to a deny-all, allow-by-exception approach. +The default "drop" zone will drop all incoming network packets unless it is explicitly allowed by the configuration file or is related to an outgoing network connection. + CCI-000366 + AC-17 (1) + SRG-OS-000297-GPOS-00115 + OL09-00-000224 + SV-271473r1091131_rule + Failure to restrict network connectivity only to authorized systems permits inbound connections from malicious systems. +It also permits outbound connections that may facilitate exfiltration of data. + + + + + + Configure Firewalld to Restrict Loopback Traffic + Configure firewalld to restrict loopback traffic to the lo interface. + +The loopback traffic must be trusted by assigning the lo interface to the +firewalld + trusted zone. However, the loopback traffic must be restricted +to the loopback interface as an anti-spoofing measure. + +To configure firewalld to restrict loopback traffic to the lo interface, +run the following commands: + +sudo firewall-cmd --permanent --zone=trusted --add-rich-rule='rule family=ipv4 source address="127.0.0.1" destination not address="127.0.0.1" drop' +sudo firewall-cmd --permanent --zone=trusted --add-rich-rule='rule family=ipv6 source address="::1" destination not address="::1" drop' + + +To ensure firewalld settings are applied in runtime, run the following command: +firewall-cmd --reload + + A.8.SEC-OL3 + 1.4.1 + 1.4 + Loopback traffic is generated between processes on machine and is typically critical to +operation of the system. The loopback interface is the only place that loopback network +traffic should be seen, all other interfaces should ignore traffic on this network as an +anti-spoofing measure. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +if ! rpm -q --quiet "firewalld" ; then + yum install -y "firewalld" +fi + +ipv4_rule='rule family=ipv4 source address="127.0.0.1" destination not address="127.0.0.1" drop' +ipv6_rule='rule family=ipv6 source address="::1" destination not address="::1" drop' + +if test "$(stat -c %d:%i /)" != "$(stat -c %d:%i /proc/1/root/.)" || [[ "$OSCAP_BOOTC_BUILD" == "YES" ]]; then + firewall-offline-cmd --zone=trusted --add-rich-rule="${ipv4_rule}" + firewall-offline-cmd --zone=trusted --add-rich-rule="${ipv6_rule}" +elif systemctl is-active firewalld; then + firewall-cmd --permanent --zone=trusted --add-rich-rule="${ipv4_rule}" + firewall-cmd --permanent --zone=trusted --add-rich-rule="${ipv6_rule}" + firewall-cmd --reload +else + echo " + firewalld service is not active. Remediation aborted! + This remediation could not be applied because it depends on firewalld service running. + The service is not started by this remediation in order to prevent connection issues." +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.1 + - configure_strategy + - firewalld_loopback_traffic_restricted + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Configure Firewalld to Restrict Loopback Traffic - Ensure firewalld Package + is Installed + ansible.builtin.package: + name: '{{ item }}' + state: present + with_items: + - firewalld + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.1 + - configure_strategy + - firewalld_loopback_traffic_restricted + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Configure Firewalld to Restrict Loopback Traffic - Collect Facts About System + Services + ansible.builtin.service_facts: null + register: result_services_states + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.1 + - configure_strategy + - firewalld_loopback_traffic_restricted + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Configure Firewalld to Restrict Loopback Traffic - Remediation is Applicable + if firewalld Service is Running + block: + + - name: Configure Firewalld to Restrict Loopback Traffic - Ensure firewalld trusted + Zone Restricts IPv4 Loopback Traffic + ansible.builtin.command: + cmd: firewall-cmd --permanent --zone=trusted --add-rich-rule='rule family=ipv4 + source address="127.0.0.1" destination not address="127.0.0.1" drop' + register: result_trusted_ipv4_restriction + changed_when: + - '''ALREADY_ENABLED'' not in result_trusted_ipv4_restriction.stderr' + + - name: Configure Firewalld to Restrict Loopback Traffic - Ensure firewalld trusted + Zone Restricts IPv6 Loopback Traffic + ansible.builtin.command: + cmd: firewall-cmd --permanent --zone=trusted --add-rich-rule='rule family=ipv6 + source address="::1" destination not address="::1" drop' + register: result_trusted_ipv6_restriction + changed_when: + - '''ALREADY_ENABLED'' not in result_trusted_ipv6_restriction.stderr' + + - name: Configure Firewalld to Restrict Loopback Traffic - Ensure firewalld Changes + are Applied + ansible.builtin.service: + name: firewalld + state: reloaded + when: + - result_trusted_ipv4_restriction is changed or result_trusted_ipv6_restriction + is changed + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - ansible_facts.services['firewalld.service'].state == 'running' + tags: + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.1 + - configure_strategy + - firewalld_loopback_traffic_restricted + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Configure Firewalld to Restrict Loopback Traffic - Informative Message Based + on Service State + ansible.builtin.assert: + that: + - ansible_facts.services['firewalld.service'].state == 'running' + fail_msg: + - firewalld service is not active. Remediation aborted! + - This remediation could not be applied because it depends on firewalld service + running. + - The service is not started by this remediation in order to prevent connection + issues. + success_msg: + - Configure Firewalld to Restrict Loopback Traffic remediation successfully executed + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.1 + - configure_strategy + - firewalld_loopback_traffic_restricted + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Configure Firewalld to Trust Loopback Traffic + Assign loopback interface to the firewalld + trusted zone in order to +explicitly allow the loopback traffic in the system. + +To configure firewalld to trust loopback traffic, run the following command: +sudo firewall-cmd --permanent --zone=trusted --add-interface=lo +To ensure firewalld settings are applied in runtime, run the following command: +firewall-cmd --reload + + A.8.SEC-OL3 + 1.4.1 + 1.4 + Loopback traffic is generated between processes on machine and is typically critical to +operation of the system. The loopback interface is the only place that loopback network +traffic should be seen, all other interfaces should ignore traffic on this network as an +anti-spoofing measure. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +if ! rpm -q --quiet "firewalld" ; then + yum install -y "firewalld" +fi + +if test "$(stat -c %d:%i /)" != "$(stat -c %d:%i /proc/1/root/.)" || [[ "$OSCAP_BOOTC_BUILD" == "YES" ]]; then + firewall-offline-cmd --zone=trusted --add-interface=lo +elif systemctl is-active firewalld; then + firewall-cmd --permanent --zone=trusted --add-interface=lo + firewall-cmd --reload +else + echo " + firewalld service is not active. Remediation aborted! + This remediation could not be applied because it depends on firewalld service running. + The service is not started by this remediation in order to prevent connection issues." +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.1 + - configure_strategy + - firewalld_loopback_traffic_trusted + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Configure Firewalld to Trust Loopback Traffic - Ensure firewalld Package is + Installed + ansible.builtin.package: + name: '{{ item }}' + state: present + with_items: + - firewalld + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.1 + - configure_strategy + - firewalld_loopback_traffic_trusted + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Configure Firewalld to Trust Loopback Traffic - Collect Facts About System + Services + ansible.builtin.service_facts: null + register: result_services_states + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.1 + - configure_strategy + - firewalld_loopback_traffic_trusted + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Configure Firewalld to Trust Loopback Traffic - Remediation is Applicable + if firewalld Service is Running + block: + + - name: Configure Firewalld to Trust Loopback Traffic - Ensure firewalld trusted + Zone Includes lo Interface + ansible.builtin.command: + cmd: firewall-cmd --permanent --zone=trusted --add-interface=lo + register: result_lo_interface_assignment + changed_when: + - '''ALREADY_ENABLED'' not in result_lo_interface_assignment.stderr' + + - name: Configure Firewalld to Trust Loopback Traffic - Ensure firewalld Changes + are Applied + ansible.builtin.service: + name: firewalld + state: reloaded + when: + - result_lo_interface_assignment is changed + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - ansible_facts.services['firewalld.service'].state == 'running' + tags: + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.1 + - configure_strategy + - firewalld_loopback_traffic_trusted + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Configure Firewalld to Trust Loopback Traffic - Informative Message Based + on Service State + ansible.builtin.assert: + that: + - ansible_facts.services['firewalld.service'].state == 'running' + fail_msg: + - firewalld service is not active. Remediation aborted! + - This remediation could not be applied because it depends on firewalld service + running. + - The service is not started by this remediation in order to prevent connection + issues. + success_msg: + - Configure Firewalld to Trust Loopback Traffic remediation successfully executed + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.1 + - configure_strategy + - firewalld_loopback_traffic_trusted + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Set Default firewalld Zone for Incoming Packets + To set the default zone to drop for +the built-in default zone which processes incoming IPv4 and IPv6 packets, +modify the following line in +/etc/firewalld/firewalld.conf to be: +DefaultZone=drop + + To prevent denying any access to the system, automatic remediation +of this control is not available. Remediation must be automated as +a component of machine provisioning, or followed manually as outlined +above. + 11 + 14 + 3 + 9 + 5.10.1 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS05.02 + DSS05.05 + DSS06.06 + 3.1.3 + 3.4.7 + 3.13.6 + CCI-000366 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.2 + 4.3.4.3.3 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 7.6 + 1416 + A.12.1.2 + A.12.5.1 + A.12.6.2 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.9.1.2 + CA-3(5) + CM-7(b) + SC-7(23) + CM-6(a) + PR.IP-1 + PR.PT-3 + Req-1.4 + SRG-OS-000480-GPOS-00227 + A.8.SEC-OL3 + 1.3.1 + 1.3 + In firewalld the default zone is applied only after all +the applicable rules in the table are examined for a match. Setting the +default zone to drop implements proper design for a firewall, i.e. +any packets which are not explicitly permitted should not be +accepted. + + + + + + + + + + + + IPSec Support + Support for Internet Protocol Security (IPsec) +is provided with Libreswan. + + Install libreswan Package + The libreswan package provides an implementation of IPsec +and IKE, which permits the creation of secure tunnels over +untrusted networks. The libreswan package can be installed with the following command: + +$ sudo yum install libreswan + + 12 + 15 + 3 + 5 + 8 + APO13.01 + DSS01.04 + DSS05.02 + DSS05.03 + DSS05.04 + CCI-000366 + CCI-000803 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + SR 1.13 + SR 2.6 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 7.1 + SR 7.6 + A.11.2.4 + A.11.2.6 + A.13.1.1 + A.13.2.1 + A.14.1.3 + A.15.1.1 + A.15.2.1 + A.6.2.1 + A.6.2.2 + CM-6(a) + PR.AC-3 + PR.MA-2 + PR.PT-4 + Req-4.1 + SRG-OS-000480-GPOS-00227 + SRG-OS-000120-GPOS-00061 + OL09-00-000410 + SV-271517r1091263_rule + Providing the ability for remote users or systems +to initiate a secure VPN connection protects information when it is +transmitted over a wide area network. + +if ! rpm -q --quiet "libreswan" ; then + yum install -y "libreswan" +fi + + - name: Ensure libreswan is installed + package: + name: libreswan + state: present + tags: + - DISA-STIG-OL09-00-000410 + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-4.1 + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - package_libreswan_installed + + include install_libreswan + +class install_libreswan { + package { 'libreswan': + ensure => 'installed', + } +} + + +package --add=libreswan + + +[[packages]] +name = "libreswan" +version = "*" + + + + + + + + + + Verify Group Who Owns /etc/ipsec.d Directory + To properly set the group owner of /etc/ipsec.d, run the command: $ sudo chgrp root /etc/ipsec.d + + R50 + The ownership of the /etc/ipsec.d directory by the root group is important +because this directory hosts Libreswan configuration. Protection of this +file is critical for system security. Assigning the ownership to root +ensures exclusive control of the Libreswan configuration. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q libreswan; then + +find -H /etc/ipsec.d/ -maxdepth 1 -type d -exec chgrp -L root {} \; + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - configure_strategy + - directory_groupowner_etc_ipsecd + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure group owner on /etc/ipsec.d/ + file: + path: /etc/ipsec.d/ + state: directory + group: root + when: '"libreswan" in ansible_facts.packages' + tags: + - configure_strategy + - directory_groupowner_etc_ipsecd + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify User Who Owns /etc/ipsec.d Directory + To properly set the owner of /etc/ipsec.d, run the command: $ sudo chown root /etc/ipsec.d + + R50 + The ownership of the /etc/ipsec.d directory by the root user is important +because this directory hosts Libreswan configuration. Protection of this +file is critical for system security. Assigning the ownership to root +ensures exclusive control of the Libreswan configuration. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q libreswan; then + +find -H /etc/ipsec.d/ -maxdepth 1 -type d -exec chown -L 0 {} \; + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - configure_strategy + - directory_owner_etc_ipsecd + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure owner on directory /etc/ipsec.d/ + file: + path: /etc/ipsec.d/ + state: directory + owner: '0' + when: '"libreswan" in ansible_facts.packages' + tags: + - configure_strategy + - directory_owner_etc_ipsecd + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify Permissions On /etc/ipsec.d Directory + To properly set the permissions of /etc/ipsec.d, run the command: $ sudo chmod 0700 /etc/ipsec.d + + R50 + Setting correct permissions on the /etc/ipsec.d directory is important +because this directory hosts Libreswan configuration. Protection of this +directory is critical for system security. Restricting the permissions +ensures exclusive control of the Libreswan configuration. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q libreswan; then + +find -H /etc/ipsec.d/ -maxdepth 1 -perm /u+s,g+xwrs,o+xwrt -type d -exec chmod u-s,g-xwrs,o-xwrt {} \; + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - configure_strategy + - directory_permissions_etc_ipsecd + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Find /etc/ipsec.d/ file(s) + command: 'find -H /etc/ipsec.d/ -maxdepth 1 -perm /u+s,g+xwrs,o+xwrt -type d ' + register: files_found + changed_when: false + failed_when: false + check_mode: false + when: '"libreswan" in ansible_facts.packages' + tags: + - configure_strategy + - directory_permissions_etc_ipsecd + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Set permissions for /etc/ipsec.d/ file(s) + file: + path: '{{ item }}' + mode: u-s,g-xwrs,o-xwrt + state: directory + with_items: + - '{{ files_found.stdout_lines }}' + when: '"libreswan" in ansible_facts.packages' + tags: + - configure_strategy + - directory_permissions_etc_ipsecd + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify Group Who Owns /etc/ipsec.conf File + To properly set the group owner of /etc/ipsec.conf, run the command: $ sudo chgrp root /etc/ipsec.conf + + R50 + The ownership of the /etc/ipsec.conf file by the root group is important +because this file hosts Libreswan configuration. Protection of this +file is critical for system security. Assigning the ownership to root +ensures exclusive control of the Libreswan configuration. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q libreswan; then + +chgrp root /etc/ipsec.conf + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - configure_strategy + - file_groupowner_etc_ipsec_conf + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /etc/ipsec.conf + stat: + path: /etc/ipsec.conf + register: file_exists + when: '"libreswan" in ansible_facts.packages' + tags: + - configure_strategy + - file_groupowner_etc_ipsec_conf + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure group owner root on /etc/ipsec.conf + file: + path: /etc/ipsec.conf + group: root + when: + - '"libreswan" in ansible_facts.packages' + - file_exists.stat is defined and file_exists.stat.exists + tags: + - configure_strategy + - file_groupowner_etc_ipsec_conf + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify Group Who Owns /etc/ipsec.secrets File + To properly set the group owner of /etc/ipsec.secrets, run the command: $ sudo chgrp root /etc/ipsec.secrets + + R50 + The ownership of the /etc/ipsec.secrets file by the root group is important +because this file hosts Libreswan configuration. Protection of this +file is critical for system security. Assigning the ownership to root +ensures exclusive control of the Libreswan configuration. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q libreswan; then + +chgrp root /etc/ipsec.secrets + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - configure_strategy + - file_groupowner_etc_ipsec_secrets + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /etc/ipsec.secrets + stat: + path: /etc/ipsec.secrets + register: file_exists + when: '"libreswan" in ansible_facts.packages' + tags: + - configure_strategy + - file_groupowner_etc_ipsec_secrets + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure group owner root on /etc/ipsec.secrets + file: + path: /etc/ipsec.secrets + group: root + when: + - '"libreswan" in ansible_facts.packages' + - file_exists.stat is defined and file_exists.stat.exists + tags: + - configure_strategy + - file_groupowner_etc_ipsec_secrets + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify User Who Owns /etc/ipsec.conf File + To properly set the owner of /etc/ipsec.conf, run the command: $ sudo chown root /etc/ipsec.conf + + R50 + The ownership of the /etc/ipsec.conf file by the root user is important +because this file hosts Libreswan configuration. Protection of this +file is critical for system security. Assigning the ownership to root +ensures exclusive control of the Libreswan configuration. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q libreswan; then + +chown 0 /etc/ipsec.conf + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - configure_strategy + - file_owner_etc_ipsec_conf + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /etc/ipsec.conf + stat: + path: /etc/ipsec.conf + register: file_exists + when: '"libreswan" in ansible_facts.packages' + tags: + - configure_strategy + - file_owner_etc_ipsec_conf + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure owner 0 on /etc/ipsec.conf + file: + path: /etc/ipsec.conf + owner: '0' + when: + - '"libreswan" in ansible_facts.packages' + - file_exists.stat is defined and file_exists.stat.exists + tags: + - configure_strategy + - file_owner_etc_ipsec_conf + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify User Who Owns /etc/ipsec.secrets File + To properly set the owner of /etc/ipsec.secrets, run the command: $ sudo chown root /etc/ipsec.secrets + + R50 + The ownership of the /etc/ipsec.secrets file by the root user is important +because this file hosts Libreswan configuration. Protection of this +file is critical for system security. Assigning the ownership to root +ensures exclusive control of the Libreswan configuration. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q libreswan; then + +chown 0 /etc/ipsec.secrets + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - configure_strategy + - file_owner_etc_ipsec_secrets + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /etc/ipsec.secrets + stat: + path: /etc/ipsec.secrets + register: file_exists + when: '"libreswan" in ansible_facts.packages' + tags: + - configure_strategy + - file_owner_etc_ipsec_secrets + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure owner 0 on /etc/ipsec.secrets + file: + path: /etc/ipsec.secrets + owner: '0' + when: + - '"libreswan" in ansible_facts.packages' + - file_exists.stat is defined and file_exists.stat.exists + tags: + - configure_strategy + - file_owner_etc_ipsec_secrets + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify Permissions On /etc/ipsec.conf File + To properly set the permissions of /etc/ipsec.conf, run the command: $ sudo chmod 0644 /etc/ipsec.conf + + R50 + Setting correct permissions on the /etc/ipsec.conf file is important +because this file hosts Libreswan configuration. Protection of this +file is critical for system security. Restricting the permissions +ensures exclusive control of the Libreswan configuration. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q libreswan; then + +chmod u-xs,g-xws,o-xwt /etc/ipsec.conf + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - configure_strategy + - file_permissions_etc_ipsec_conf + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /etc/ipsec.conf + stat: + path: /etc/ipsec.conf + register: file_exists + when: '"libreswan" in ansible_facts.packages' + tags: + - configure_strategy + - file_permissions_etc_ipsec_conf + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure permission u-xs,g-xws,o-xwt on /etc/ipsec.conf + file: + path: /etc/ipsec.conf + mode: u-xs,g-xws,o-xwt + when: + - '"libreswan" in ansible_facts.packages' + - file_exists.stat is defined and file_exists.stat.exists + tags: + - configure_strategy + - file_permissions_etc_ipsec_conf + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify Permissions On /etc/ipsec.secrets File + To properly set the permissions of /etc/ipsec.secrets, run the command: $ sudo chmod 0644 /etc/ipsec.secrets + + R50 + Setting correct permissions on the /etc/ipsec.secrets file is important +because this file hosts Libreswan configuration. Protection of this +file is critical for system security. Restricting the permissions +ensures exclusive control of the Libreswan configuration. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q libreswan; then + +chmod u-xs,g-xws,o-xwt /etc/ipsec.secrets + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - configure_strategy + - file_permissions_etc_ipsec_secrets + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /etc/ipsec.secrets + stat: + path: /etc/ipsec.secrets + register: file_exists + when: '"libreswan" in ansible_facts.packages' + tags: + - configure_strategy + - file_permissions_etc_ipsec_secrets + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure permission u-xs,g-xws,o-xwt on /etc/ipsec.secrets + file: + path: /etc/ipsec.secrets + mode: u-xs,g-xws,o-xwt + when: + - '"libreswan" in ansible_facts.packages' + - file_exists.stat is defined and file_exists.stat.exists + tags: + - configure_strategy + - file_permissions_etc_ipsec_secrets + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify Any Configured IPSec Tunnel Connections + Libreswan provides an implementation of IPsec +and IKE, which permits the creation of secure tunnels over +untrusted networks. As such, IPsec can be used to circumvent certain +network requirements such as filtering. Verify that if any IPsec connection +(conn) configured in /etc/ipsec.conf and /etc/ipsec.d +exists is an approved organizational connection. + Automatic remediation of this control is not available due to the unique +requirements of each system. + 1 + 12 + 13 + 14 + 15 + 16 + 18 + 4 + 6 + 8 + 9 + APO01.06 + APO13.01 + DSS01.05 + DSS03.01 + DSS05.02 + DSS05.04 + DSS05.07 + DSS06.02 + CCI-000366 + 164.308(a)(4)(i) + 164.308(b)(1) + 164.308(b)(3) + 164.310(b) + 164.312(e)(1) + 164.312(e)(2)(ii) + 4.2.3.4 + 4.3.3.4 + 4.4.3.3 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 7.1 + SR 7.6 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.12.1.1 + A.12.1.2 + A.13.1.1 + A.13.1.2 + A.13.1.3 + A.13.2.1 + A.13.2.2 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + AC-17(a) + MA-4(6) + CM-6(a) + AC-4 + SC-8 + DE.AE-1 + ID.AM-3 + PR.AC-5 + PR.DS-5 + PR.PT-4 + SRG-OS-000480-GPOS-00227 + OL09-00-006010 + SV-271863r1092639_rule + IP tunneling mechanisms can be used to bypass network filtering. + + + + + + + iptables and ip6tables + A host-based firewall called netfilter is included as +part of the Linux kernel distributed with the system. It is +activated by default. This firewall is controlled by the program +iptables, and the entire capability is frequently referred to by +this name. An analogous program called ip6tables handles filtering +for IPv6. + + +Unlike TCP Wrappers, which depends on the network server +program to support and respect the rules written, netfilter +filtering occurs at the kernel level, before a program can even +process the data from the network packet. As such, any program on +the system is affected by the rules written. + + +This section provides basic information about strengthening +the iptables and ip6tables configurations included with the system. +For more complete information that may allow the construction of a +sophisticated ruleset tailored to your environment, please consult +the references at the end of this section. + + Verify Group Who Owns /etc/iptables Directory + To properly set the group owner of /etc/iptables, run the command: $ sudo chgrp root /etc/iptables + + R50 + The ownership of the /etc/iptables directory by the root group is important +because this directory hosts iptables configuration. Protection of this +file is critical for system security. Assigning the ownership to root +ensures exclusive control of the iptables configuration. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q iptables; then + +find -H /etc/iptables/ -maxdepth 1 -type d -exec chgrp -L root {} \; + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - configure_strategy + - directory_groupowner_etc_iptables + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure group owner on /etc/iptables/ + file: + path: /etc/iptables/ + state: directory + group: root + when: '"iptables" in ansible_facts.packages' + tags: + - configure_strategy + - directory_groupowner_etc_iptables + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify User Who Owns /etc/iptables Directory + To properly set the owner of /etc/iptables, run the command: $ sudo chown root /etc/iptables + + R50 + The ownership of the /etc/iptables directory by the root user is important +because this directory hosts iptables configuration. Protection of this +file is critical for system security. Assigning the ownership to root +ensures exclusive control of the iptables configuration. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q iptables; then + +find -H /etc/iptables/ -maxdepth 1 -type d -exec chown -L 0 {} \; + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - configure_strategy + - directory_owner_etc_iptables + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure owner on directory /etc/iptables/ + file: + path: /etc/iptables/ + state: directory + owner: '0' + when: '"iptables" in ansible_facts.packages' + tags: + - configure_strategy + - directory_owner_etc_iptables + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify Permissions On /etc/iptables Directory + To properly set the permissions of /etc/iptables, run the command: $ sudo chmod 0700 /etc/iptables + + R50 + Setting correct permissions on the /etc/iptables directory is important +because this directory hosts iptables configuration. Protection of this +directory is critical for system security. Restricting the permissions +ensures exclusive control of the iptables configuration. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q iptables; then + +find -H /etc/iptables/ -maxdepth 1 -perm /u+s,g+xwrs,o+xwrt -type d -exec chmod u-s,g-xwrs,o-xwrt {} \; + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - configure_strategy + - directory_permissions_etc_iptables + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Find /etc/iptables/ file(s) + command: 'find -H /etc/iptables/ -maxdepth 1 -perm /u+s,g+xwrs,o+xwrt -type d ' + register: files_found + changed_when: false + failed_when: false + check_mode: false + when: '"iptables" in ansible_facts.packages' + tags: + - configure_strategy + - directory_permissions_etc_iptables + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Set permissions for /etc/iptables/ file(s) + file: + path: '{{ item }}' + mode: u-s,g-xwrs,o-xwrt + state: directory + with_items: + - '{{ files_found.stdout_lines }}' + when: '"iptables" in ansible_facts.packages' + tags: + - configure_strategy + - directory_permissions_etc_iptables + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Inspect and Activate Default Rules + View the currently-enforced iptables rules by running +the command: +$ sudo iptables -nL --line-numbers +The command is analogous for ip6tables. + + +If the firewall does not appear to be active (i.e., no rules +appear), activate it and ensure that it starts at boot by issuing +the following commands (and analogously for ip6tables): +$ sudo service iptables restart +The default iptables rules are: +Chain INPUT (policy ACCEPT) +num target prot opt source destination +1 ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED +2 ACCEPT icmp -- 0.0.0.0/0 0.0.0.0/0 +3 ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 +4 ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 state NEW tcp dpt:22 +5 REJECT all -- 0.0.0.0/0 0.0.0.0/0 reject-with icmp-host-prohibited + +Chain FORWARD (policy ACCEPT) +num target prot opt source destination +1 REJECT all -- 0.0.0.0/0 0.0.0.0/0 reject-with icmp-host-prohibited + +Chain OUTPUT (policy ACCEPT) +num target prot opt source destination +The ip6tables default rules are essentially the same. + + Verify iptables Enabled + +The iptables service can be enabled with the following command: +$ sudo systemctl enable iptables.service + + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 4 + 6 + 8 + 9 + APO01.06 + APO13.01 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS01.05 + DSS03.01 + DSS05.02 + DSS05.04 + DSS05.05 + DSS05.07 + DSS06.02 + DSS06.06 + 4.2.3.4 + 4.3.3.4 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.2 + 4.3.4.3.3 + 4.4.3.3 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 7.1 + SR 7.6 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.12.1.1 + A.12.1.2 + A.12.5.1 + A.12.6.2 + A.13.1.1 + A.13.1.2 + A.13.1.3 + A.13.2.1 + A.13.2.2 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CIP-003-8 R4 + CIP-003-8 R5 + CIP-004-6 R3 + AC-4 + CM-7(b) + CA-3(5) + SC-7(21) + CM-6(a) + DE.AE-1 + ID.AM-3 + PR.AC-5 + PR.DS-5 + PR.IP-1 + PR.PT-3 + PR.PT-4 + The iptables service provides the system's host-based firewalling +capability for IPv4 and ICMP. + + # Remediation is applicable only in certain platforms +if ( rpm --quiet -q iptables && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ); then + +SYSTEMCTL_EXEC='/usr/bin/systemctl' +"$SYSTEMCTL_EXEC" unmask 'iptables.service' +if [[ $("$SYSTEMCTL_EXEC" is-system-running) != "offline" ]]; then + "$SYSTEMCTL_EXEC" start 'iptables.service' +fi +"$SYSTEMCTL_EXEC" enable 'iptables.service' + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-53-AC-4 + - NIST-800-53-CA-3(5) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-7(21) + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_iptables_enabled + +- name: Verify iptables Enabled - Enable service iptables + block: + + - name: Gather the package facts + package_facts: + manager: auto + + - name: Verify iptables Enabled - Enable Service iptables + ansible.builtin.systemd: + name: iptables + enabled: true + state: started + masked: false + when: + - '"iptables" in ansible_facts.packages' + when: ( "iptables" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + tags: + - NIST-800-53-AC-4 + - NIST-800-53-CA-3(5) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-7(21) + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_iptables_enabled + + include enable_iptables + +class enable_iptables { + service {'iptables': + enable => true, + ensure => 'running', + } +} + + +[customizations.services] +enabled = ["iptables"] + + + + + + + + + + Set Default ip6tables Policy for Incoming Packets + To set the default policy to DROP (instead of ACCEPT) for +the built-in INPUT chain which processes incoming packets, +add or correct the following line in + +/etc/sysconfig/ip6tables: + +:INPUT DROP [0:0] +If changes were required, reload the ip6tables rules: +$ sudo service ip6tables reload + + 11 + 14 + 3 + 9 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS05.02 + DSS05.05 + DSS06.06 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.2 + 4.3.4.3.3 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 7.6 + A.12.1.2 + A.12.5.1 + A.12.6.2 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.9.1.2 + CIP-003-8 R4 + CIP-003-8 R5 + CIP-004-6 R3 + AC-4 + CM-7(b) + CA-3(5) + SC-7(21) + CM-6(a) + PR.IP-1 + PR.PT-3 + 1.4.1 + 1.4 + In ip6tables, the default policy is applied only after all +the applicable rules in the table are examined for a match. Setting the +default policy to DROP implements proper design for a firewall, i.e. +any packets which are not explicitly permitted should not be +accepted. + + # Remediation is applicable only in certain platforms +if ( ! ( rpm --quiet -q nftables ) && ! ( rpm --quiet -q ufw ) && rpm --quiet -q iptables ); then + +sed -i 's/^:INPUT ACCEPT.*/:INPUT DROP [0:0]/g' /etc/sysconfig/ip6tables + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + + + + + + + Strengthen the Default Ruleset + The default rules can be strengthened. The system +scripts that activate the firewall rules expect them to be defined +in the configuration files iptables and ip6tables in the directory +/etc/sysconfig. Many of the lines in these files are similar +to the command line arguments that would be provided to the programs +/sbin/iptables or /sbin/ip6tables - but some are quite +different. + + +The following recommendations describe how to strengthen the +default ruleset configuration file. An alternative to editing this +configuration file is to create a shell script that makes calls to +the iptables program to load in rules, and then invokes service +iptables save to write those loaded rules to +/etc/sysconfig/iptables. + + +The following alterations can be made directly to +/etc/sysconfig/iptables and /etc/sysconfig/ip6tables. +Instructions apply to both unless otherwise noted. Language and address +conventions for regular iptables are used throughout this section; +configuration for ip6tables will be either analogous or explicitly +covered. + The program system-config-securitylevel +allows additional services to penetrate the default firewall rules +and automatically adjusts /etc/sysconfig/iptables. This program +is only useful if the default ruleset meets your security +requirements. Otherwise, this program should not be used to make +changes to the firewall configuration because it re-writes the +saved configuration file. + + + Set Default iptables Policy for Incoming Packets + To set the default policy to DROP (instead of ACCEPT) for +the built-in INPUT chain which processes incoming packets, +add or correct the following line in +/etc/sysconfig/iptables: +:INPUT DROP [0:0] + + 11 + 14 + 3 + 9 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS05.02 + DSS05.05 + DSS06.06 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.2 + 4.3.4.3.3 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 7.6 + A.12.1.2 + A.12.5.1 + A.12.6.2 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.9.1.2 + CA-3(5) + CM-7(b) + SC-7(23) + CM-6(a) + PR.IP-1 + PR.PT-3 + In iptables the default policy is applied only after all +the applicable rules in the table are examined for a match. Setting the +default policy to DROP implements proper design for a firewall, i.e. +any packets which are not explicitly permitted should not be +accepted. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q iptables && { ( ! ( rpm --quiet -q nftables ) && ! ( rpm --quiet -q ufw ) ); }; then + +sed -i 's/^:INPUT ACCEPT.*/:INPUT DROP [0:0]/g' /etc/sysconfig/iptables + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + + + + + + Set Default iptables Policy for Forwarded Packets + To set the default policy to DROP (instead of ACCEPT) for +the built-in FORWARD chain which processes packets that will be forwarded from +one interface to another, +add or correct the following line in +/etc/sysconfig/iptables: +:FORWARD DROP [0:0] + + 11 + 14 + 3 + 9 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS05.02 + DSS05.05 + DSS06.06 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.2 + 4.3.4.3.3 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 7.6 + A.12.1.2 + A.12.5.1 + A.12.6.2 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.9.1.2 + CA-3(5) + CM-7(b) + SC-7(23) + CM-6(a) + PR.IP-1 + PR.PT-3 + In iptables, the default policy is applied only after all +the applicable rules in the table are examined for a match. Setting the +default policy to DROP implements proper design for a firewall, i.e. +any packets which are not explicitly permitted should not be +accepted. + # Remediation is applicable only in certain platforms +if rpm --quiet -q iptables; then + +sed -i 's/^:FORWARD ACCEPT.*/:FORWARD DROP [0:0]/g' /etc/sysconfig/iptables + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + + + + + + + + IPv6 + The system includes support for Internet Protocol +version 6. A major and often-mentioned improvement over IPv4 is its +enormous increase in the number of available addresses. Another +important feature is its support for automatic configuration of +many network settings. + + Disable Support for IPv6 Unless Needed + Despite configuration that suggests support for IPv6 has +been disabled, link-local IPv6 address auto-configuration occurs +even when only an IPv4 address is assigned. The only way to +effectively prevent execution of the IPv6 networking stack is to +instruct the system not to activate the IPv6 kernel module. + + Disable IPv6 Networking Support Automatic Loading + To prevent the IPv6 kernel module (ipv6) from binding to the +IPv6 networking stack, add the following line to +/etc/modprobe.d/disabled.conf (or another file in +/etc/modprobe.d): +options ipv6 disable=1 +This permits the IPv6 module to be loaded (and thus satisfy other modules that +depend on it), while disabling support for the IPv6 protocol. + 11 + 14 + 3 + 9 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS05.02 + DSS05.05 + DSS06.06 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.2 + 4.3.4.3.3 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 7.6 + A.12.1.2 + A.12.5.1 + A.12.6.2 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.9.1.2 + CM-7(a) + CM-7(b) + CM-6(a) + PR.IP-1 + PR.PT-3 + Any unnecessary network stacks - including IPv6 - should be disabled, to reduce +the vulnerability to exploitation. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Prevent the IPv6 kernel module (ipv6) from loading the IPv6 networking stack +echo "options ipv6 disable=1" > /etc/modprobe.d/ipv6.conf + +# Since according to: https://access.redhat.com/solutions/72733 +# "ipv6 disable=1" options doesn't always disable the IPv6 networking stack from +# loading, instruct also sysctl configuration to disable IPv6 according to: +# https://access.redhat.com/solutions/8709#rhel6disable + +declare -a IPV6_SETTINGS=("net.ipv6.conf.all.disable_ipv6" "net.ipv6.conf.default.disable_ipv6") + +for setting in "${IPV6_SETTINGS[@]}" +do + # Set runtime =1 for setting + /sbin/sysctl -q -n -w "$setting=1" + + # If setting is present in /etc/sysctl.conf, change value to "1" + # else, add "$setting = 1" to /etc/sysctl.conf + if grep -q ^"$setting" /etc/sysctl.conf ; then + sed -i "s/^$setting.*/$setting = 1/g" /etc/sysctl.conf + else + echo "" >> /etc/sysctl.conf + echo "# Set $setting = 1 per security requirements" >> /etc/sysctl.conf + echo "$setting = 1" >> /etc/sysctl.conf + fi +done + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - kernel_module_ipv6_option_disabled + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + +- name: Disable IPv6 Networking kernel module + lineinfile: + create: true + dest: /etc/modprobe.d/ipv6.conf + regexp: ^options\s+ipv6\s+disable=\d + line: options ipv6 disable=1 + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - kernel_module_ipv6_option_disabled + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + +- name: Ensure disable_ipv6 (all and default) is set to 1 + sysctl: + name: '{{ item }}' + value: '1' + state: present + reload: true + with_items: + - net.ipv6.conf.all.disable_ipv6 + - net.ipv6.conf.default.disable_ipv6 + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - kernel_module_ipv6_option_disabled + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + + + + + + + + + + Disable IPv6 Addressing on All IPv6 Interfaces + To disable support for (ipv6) addressing on all interface add the following line to +/etc/sysctl.d/ipv6.conf (or another file in /etc/sysctl.d): +net.ipv6.conf.all.disable_ipv6 = 1 +This disables IPv6 on all network interfaces as other services and system +functionality require the IPv6 stack loaded to work. + 11 + 14 + 3 + 9 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS05.02 + DSS05.05 + DSS06.06 + 3.1.20 + CCI-001551 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.2 + 4.3.4.3.3 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 7.6 + A.12.1.2 + A.12.5.1 + A.12.6.2 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.9.1.2 + CM-7(a) + CM-7(b) + CM-6(a) + PR.IP-1 + PR.PT-3 + Any unnecessary network stacks - including IPv6 - should be disabled, to reduce +the vulnerability to exploitation. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Comment out any occurrences of net.ipv6.conf.all.disable_ipv6 from /etc/sysctl.d/*.conf files + +for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do + + + # skip systemd-sysctl symlink (/etc/sysctl.d/99-sysctl.conf -> /etc/sysctl.conf) + if [[ "$(readlink -f "$f")" == "/etc/sysctl.conf" ]]; then continue; fi + + matching_list=$(grep -P '^(?!#).*[\s]*net.ipv6.conf.all.disable_ipv6.*$' $f | uniq ) + if ! test -z "$matching_list"; then + while IFS= read -r entry; do + escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") + # comment out "net.ipv6.conf.all.disable_ipv6" matches to preserve user data + sed -i --follow-symlinks "s/^${escaped_entry}$/# &/g" $f + done <<< "$matching_list" + fi +done + +# +# Set sysctl config file which to save the desired value +# + +SYSCONFIG_FILE="/etc/sysctl.conf" + + +# +# Set runtime for net.ipv6.conf.all.disable_ipv6 +# +if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then + /sbin/sysctl -q -n -w net.ipv6.conf.all.disable_ipv6="1" +fi + +# +# If net.ipv6.conf.all.disable_ipv6 present in /etc/sysctl.conf, change value to "1" +# else, add "net.ipv6.conf.all.disable_ipv6 = 1" to /etc/sysctl.conf +# + +# Strip any search characters in the key arg so that the key can be replaced without +# adding any search characters to the config file. +stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv6.conf.all.disable_ipv6") + +# shellcheck disable=SC2059 +printf -v formatted_output "%s = %s" "$stripped_key" "1" + +# If the key exists, change it. Otherwise, add it to the config_file. +# We search for the key string followed by a word boundary (matched by \>), +# so if we search for 'setting', 'setting2' won't match. +if LC_ALL=C grep -q -m 1 -i -e "^net.ipv6.conf.all.disable_ipv6\\>" "${SYSCONFIG_FILE}"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + LC_ALL=C sed -i --follow-symlinks "s/^net.ipv6.conf.all.disable_ipv6\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" +else + if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" + fi + printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_all_disable_ipv6 + +- name: List /etc/sysctl.d/*.conf files + find: + paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + contains: ^[\s]*net.ipv6.conf.all.disable_ipv6.*$ + patterns: '*.conf' + file_type: any + register: find_sysctl_d + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_all_disable_ipv6 + +- name: Comment out any occurrences of net.ipv6.conf.all.disable_ipv6 from config + files + replace: + path: '{{ item.path }}' + regexp: ^[\s]*net.ipv6.conf.all.disable_ipv6 + replace: '#net.ipv6.conf.all.disable_ipv6' + loop: '{{ find_sysctl_d.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_all_disable_ipv6 + +- name: Ensure sysctl net.ipv6.conf.all.disable_ipv6 is set to 1 + sysctl: + name: net.ipv6.conf.all.disable_ipv6 + value: '1' + sysctl_file: /etc/sysctl.conf + state: present + reload: true + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_all_disable_ipv6 + + + + + + + + + + Disable IPv6 Addressing on IPv6 Interfaces by Default + To disable support for (ipv6) addressing on interfaces by default add the following line to +/etc/sysctl.d/ipv6.conf (or another file in /etc/sysctl.d): +net.ipv6.conf.default.disable_ipv6 = 1 +This disables IPv6 on network interfaces by default as other services and system +functionality require the IPv6 stack loaded to work. + 11 + 14 + 3 + 9 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS05.02 + DSS05.05 + DSS06.06 + 3.1.20 + CCI-001551 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.2 + 4.3.4.3.3 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 7.6 + A.12.1.2 + A.12.5.1 + A.12.6.2 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.9.1.2 + CM-7(a) + CM-7(b) + CM-6(a) + PR.IP-1 + PR.PT-3 + Any unnecessary network stacks - including IPv6 - should be disabled, to reduce +the vulnerability to exploitation. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Comment out any occurrences of net.ipv6.conf.default.disable_ipv6 from /etc/sysctl.d/*.conf files + +for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do + + + # skip systemd-sysctl symlink (/etc/sysctl.d/99-sysctl.conf -> /etc/sysctl.conf) + if [[ "$(readlink -f "$f")" == "/etc/sysctl.conf" ]]; then continue; fi + + matching_list=$(grep -P '^(?!#).*[\s]*net.ipv6.conf.default.disable_ipv6.*$' $f | uniq ) + if ! test -z "$matching_list"; then + while IFS= read -r entry; do + escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") + # comment out "net.ipv6.conf.default.disable_ipv6" matches to preserve user data + sed -i --follow-symlinks "s/^${escaped_entry}$/# &/g" $f + done <<< "$matching_list" + fi +done + +# +# Set sysctl config file which to save the desired value +# + +SYSCONFIG_FILE="/etc/sysctl.conf" + + +# +# Set runtime for net.ipv6.conf.default.disable_ipv6 +# +if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then + /sbin/sysctl -q -n -w net.ipv6.conf.default.disable_ipv6="1" +fi + +# +# If net.ipv6.conf.default.disable_ipv6 present in /etc/sysctl.conf, change value to "1" +# else, add "net.ipv6.conf.default.disable_ipv6 = 1" to /etc/sysctl.conf +# + +# Strip any search characters in the key arg so that the key can be replaced without +# adding any search characters to the config file. +stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv6.conf.default.disable_ipv6") + +# shellcheck disable=SC2059 +printf -v formatted_output "%s = %s" "$stripped_key" "1" + +# If the key exists, change it. Otherwise, add it to the config_file. +# We search for the key string followed by a word boundary (matched by \>), +# so if we search for 'setting', 'setting2' won't match. +if LC_ALL=C grep -q -m 1 -i -e "^net.ipv6.conf.default.disable_ipv6\\>" "${SYSCONFIG_FILE}"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + LC_ALL=C sed -i --follow-symlinks "s/^net.ipv6.conf.default.disable_ipv6\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" +else + if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" + fi + printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_default_disable_ipv6 + +- name: List /etc/sysctl.d/*.conf files + find: + paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + contains: ^[\s]*net.ipv6.conf.default.disable_ipv6.*$ + patterns: '*.conf' + file_type: any + register: find_sysctl_d + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_default_disable_ipv6 + +- name: Comment out any occurrences of net.ipv6.conf.default.disable_ipv6 from config + files + replace: + path: '{{ item.path }}' + regexp: ^[\s]*net.ipv6.conf.default.disable_ipv6 + replace: '#net.ipv6.conf.default.disable_ipv6' + loop: '{{ find_sysctl_d.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_default_disable_ipv6 + +- name: Ensure sysctl net.ipv6.conf.default.disable_ipv6 is set to 1 + sysctl: + name: net.ipv6.conf.default.disable_ipv6 + value: '1' + sysctl_file: /etc/sysctl.conf + state: present + reload: true + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_default_disable_ipv6 + + + + + + + + + + + Configure IPv6 Settings if Necessary + A major feature of IPv6 is the extent to which systems +implementing it can automatically configure their networking +devices using information from the network. From a security +perspective, manually configuring important configuration +information is preferable to accepting it from the network +in an unauthenticated fashion. + + + net.ipv6.conf.all.accept_ra_defrtr + Accept default router in router advertisements? + 0 + 0 + 1 + + + net.ipv6.conf.all.accept_ra_pinfo + Accept prefix information in router advertisements? + 0 + 0 + 1 + + + net.ipv6.conf.all.accept_ra_rtr_pref + Accept router preference in router advertisements? + 0 + 0 + 1 + + + net.ipv6.conf.all.accept_ra + Accept all router advertisements? + 0 + 0 + 1 + + + net.ipv6.conf.all.accept_redirects + Toggle ICMP Redirect Acceptance + 0 + 0 + 1 + + + net.ipv6.conf.all.accept_source_route + Trackers could be using source-routed packets to +generate traffic that seems to be intra-net, but actually was +created outside and has been redirected. + 0 + 0 + 1 + + + net.ipv6.conf.all.autoconf + Enable auto configuration on IPv6 interfaces + 0 + 0 + 1 + + + net.ipv6.conf.all.forwarding + Toggle IPv6 Forwarding + 0 + 0 + 1 + + + net.ipv6.conf.all.max_addresses + Maximum number of autoconfigured IPv6 addresses + 1 + + + net.ipv6.conf.all.router_solicitations + Accept all router solicitations? + 0 + 0 + 1 + + + net.ipv6.conf.default.accept_ra_defrtr + Accept default router in router advertisements? + 0 + 0 + 1 + + + net.ipv6.conf.default.accept_ra_pinfo + Accept prefix information in router advertisements? + 0 + 0 + 1 + + + net.ipv6.conf.default.accept_ra_rtr_pref + Accept router preference in router advertisements? + 0 + 0 + 1 + + + net.ipv6.conf.default.accept_ra + Accept default router advertisements by default? + 0 + 0 + 1 + + + net.ipv6.conf.default.accept_redirects + Toggle ICMP Redirect Acceptance By Default + 0 + 0 + 1 + + + net.ipv6.conf.default.accept_source_route + Trackers could be using source-routed packets to +generate traffic that seems to be intra-net, but actually was +created outside and has been redirected. + 0 + 0 + 1 + + + net.ipv6.conf.default.autoconf + Enable auto configuration on IPv6 interfaces + 0 + 0 + 1 + + + net.ipv6.conf.default.max_addresses + Maximum number of autoconfigured IPv6 addresses + 1 + + + net.ipv6.conf.default.router_solicitations + Accept all router solicitations by default? + 0 + 0 + 1 + + + Configure Accepting Router Advertisements on All IPv6 Interfaces + To set the runtime status of the net.ipv6.conf.all.accept_ra kernel parameter, run the following command: $ sudo sysctl -w net.ipv6.conf.all.accept_ra=0 +To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv6.conf.all.accept_ra = 0 + + 11 + 14 + 3 + 9 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS05.02 + DSS05.05 + DSS06.06 + 3.1.20 + CCI-000366 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.2 + 4.3.4.3.3 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 7.6 + A.12.1.2 + A.12.5.1 + A.12.6.2 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.9.1.2 + CM-7(a) + CM-7(b) + CM-6(a) + PR.IP-1 + PR.PT-3 + SRG-OS-000480-GPOS-00227 + A.8.SEC-OL6 + OL09-00-006040 + SV-271877r1092343_rule + An illicit router advertisement message could result in a man-in-the-middle attack. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Comment out any occurrences of net.ipv6.conf.all.accept_ra from /etc/sysctl.d/*.conf files + +for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do + + + # skip systemd-sysctl symlink (/etc/sysctl.d/99-sysctl.conf -> /etc/sysctl.conf) + if [[ "$(readlink -f "$f")" == "/etc/sysctl.conf" ]]; then continue; fi + + matching_list=$(grep -P '^(?!#).*[\s]*net.ipv6.conf.all.accept_ra.*$' $f | uniq ) + if ! test -z "$matching_list"; then + while IFS= read -r entry; do + escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") + # comment out "net.ipv6.conf.all.accept_ra" matches to preserve user data + sed -i --follow-symlinks "s/^${escaped_entry}$/# &/g" $f + done <<< "$matching_list" + fi +done + +# +# Set sysctl config file which to save the desired value +# + +SYSCONFIG_FILE="/etc/sysctl.conf" + +sysctl_net_ipv6_conf_all_accept_ra_value='' + + +# +# Set runtime for net.ipv6.conf.all.accept_ra +# +if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then + /sbin/sysctl -q -n -w net.ipv6.conf.all.accept_ra="$sysctl_net_ipv6_conf_all_accept_ra_value" +fi + +# +# If net.ipv6.conf.all.accept_ra present in /etc/sysctl.conf, change value to appropriate value +# else, add "net.ipv6.conf.all.accept_ra = value" to /etc/sysctl.conf +# + +# Strip any search characters in the key arg so that the key can be replaced without +# adding any search characters to the config file. +stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv6.conf.all.accept_ra") + +# shellcheck disable=SC2059 +printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv6_conf_all_accept_ra_value" + +# If the key exists, change it. Otherwise, add it to the config_file. +# We search for the key string followed by a word boundary (matched by \>), +# so if we search for 'setting', 'setting2' won't match. +if LC_ALL=C grep -q -m 1 -i -e "^net.ipv6.conf.all.accept_ra\\>" "${SYSCONFIG_FILE}"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + LC_ALL=C sed -i --follow-symlinks "s/^net.ipv6.conf.all.accept_ra\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" +else + if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" + fi + printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-006040 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_all_accept_ra + +- name: List /etc/sysctl.d/*.conf files + find: + paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + contains: ^[\s]*net.ipv6.conf.all.accept_ra.*$ + patterns: '*.conf' + file_type: any + register: find_sysctl_d + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006040 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_all_accept_ra + +- name: Comment out any occurrences of net.ipv6.conf.all.accept_ra from config files + replace: + path: '{{ item.path }}' + regexp: ^[\s]*net.ipv6.conf.all.accept_ra + replace: '#net.ipv6.conf.all.accept_ra' + loop: '{{ find_sysctl_d.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006040 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_all_accept_ra +- name: XCCDF Value sysctl_net_ipv6_conf_all_accept_ra_value # promote to variable + set_fact: + sysctl_net_ipv6_conf_all_accept_ra_value: !!str + tags: + - always + +- name: Ensure sysctl net.ipv6.conf.all.accept_ra is set + sysctl: + name: net.ipv6.conf.all.accept_ra + value: '{{ sysctl_net_ipv6_conf_all_accept_ra_value }}' + sysctl_file: /etc/sysctl.conf + state: present + reload: true + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006040 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_all_accept_ra + + + + + + + + + + + Configure Accepting Default Router in Router Advertisements on All IPv6 Interfaces + To set the runtime status of the net.ipv6.conf.all.accept_ra_defrtr kernel parameter, run the following command: $ sudo sysctl -w net.ipv6.conf.all.accept_ra_defrtr=0 +To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv6.conf.all.accept_ra_defrtr = 0 + + R13 + An illicit router advertisement message could result in a man-in-the-middle attack. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Comment out any occurrences of net.ipv6.conf.all.accept_ra_defrtr from /etc/sysctl.d/*.conf files + +for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do + + + # skip systemd-sysctl symlink (/etc/sysctl.d/99-sysctl.conf -> /etc/sysctl.conf) + if [[ "$(readlink -f "$f")" == "/etc/sysctl.conf" ]]; then continue; fi + + matching_list=$(grep -P '^(?!#).*[\s]*net.ipv6.conf.all.accept_ra_defrtr.*$' $f | uniq ) + if ! test -z "$matching_list"; then + while IFS= read -r entry; do + escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") + # comment out "net.ipv6.conf.all.accept_ra_defrtr" matches to preserve user data + sed -i --follow-symlinks "s/^${escaped_entry}$/# &/g" $f + done <<< "$matching_list" + fi +done + +# +# Set sysctl config file which to save the desired value +# + +SYSCONFIG_FILE="/etc/sysctl.conf" + +sysctl_net_ipv6_conf_all_accept_ra_defrtr_value='' + + +# +# Set runtime for net.ipv6.conf.all.accept_ra_defrtr +# +if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then + /sbin/sysctl -q -n -w net.ipv6.conf.all.accept_ra_defrtr="$sysctl_net_ipv6_conf_all_accept_ra_defrtr_value" +fi + +# +# If net.ipv6.conf.all.accept_ra_defrtr present in /etc/sysctl.conf, change value to appropriate value +# else, add "net.ipv6.conf.all.accept_ra_defrtr = value" to /etc/sysctl.conf +# + +# Strip any search characters in the key arg so that the key can be replaced without +# adding any search characters to the config file. +stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv6.conf.all.accept_ra_defrtr") + +# shellcheck disable=SC2059 +printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv6_conf_all_accept_ra_defrtr_value" + +# If the key exists, change it. Otherwise, add it to the config_file. +# We search for the key string followed by a word boundary (matched by \>), +# so if we search for 'setting', 'setting2' won't match. +if LC_ALL=C grep -q -m 1 -i -e "^net.ipv6.conf.all.accept_ra_defrtr\\>" "${SYSCONFIG_FILE}"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + LC_ALL=C sed -i --follow-symlinks "s/^net.ipv6.conf.all.accept_ra_defrtr\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" +else + if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" + fi + printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_all_accept_ra_defrtr + - unknown_severity + +- name: List /etc/sysctl.d/*.conf files + find: + paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + contains: ^[\s]*net.ipv6.conf.all.accept_ra_defrtr.*$ + patterns: '*.conf' + file_type: any + register: find_sysctl_d + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_all_accept_ra_defrtr + - unknown_severity + +- name: Comment out any occurrences of net.ipv6.conf.all.accept_ra_defrtr from config + files + replace: + path: '{{ item.path }}' + regexp: ^[\s]*net.ipv6.conf.all.accept_ra_defrtr + replace: '#net.ipv6.conf.all.accept_ra_defrtr' + loop: '{{ find_sysctl_d.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_all_accept_ra_defrtr + - unknown_severity +- name: XCCDF Value sysctl_net_ipv6_conf_all_accept_ra_defrtr_value # promote to variable + set_fact: + sysctl_net_ipv6_conf_all_accept_ra_defrtr_value: !!str + tags: + - always + +- name: Ensure sysctl net.ipv6.conf.all.accept_ra_defrtr is set + sysctl: + name: net.ipv6.conf.all.accept_ra_defrtr + value: '{{ sysctl_net_ipv6_conf_all_accept_ra_defrtr_value }}' + sysctl_file: /etc/sysctl.conf + state: present + reload: true + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_all_accept_ra_defrtr + - unknown_severity + + + + + + + + + + + Configure Accepting Prefix Information in Router Advertisements on All IPv6 Interfaces + To set the runtime status of the net.ipv6.conf.all.accept_ra_pinfo kernel parameter, run the following command: $ sudo sysctl -w net.ipv6.conf.all.accept_ra_pinfo=0 +To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv6.conf.all.accept_ra_pinfo = 0 + + R13 + An illicit router advertisement message could result in a man-in-the-middle attack. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Comment out any occurrences of net.ipv6.conf.all.accept_ra_pinfo from /etc/sysctl.d/*.conf files + +for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do + + + # skip systemd-sysctl symlink (/etc/sysctl.d/99-sysctl.conf -> /etc/sysctl.conf) + if [[ "$(readlink -f "$f")" == "/etc/sysctl.conf" ]]; then continue; fi + + matching_list=$(grep -P '^(?!#).*[\s]*net.ipv6.conf.all.accept_ra_pinfo.*$' $f | uniq ) + if ! test -z "$matching_list"; then + while IFS= read -r entry; do + escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") + # comment out "net.ipv6.conf.all.accept_ra_pinfo" matches to preserve user data + sed -i --follow-symlinks "s/^${escaped_entry}$/# &/g" $f + done <<< "$matching_list" + fi +done + +# +# Set sysctl config file which to save the desired value +# + +SYSCONFIG_FILE="/etc/sysctl.conf" + +sysctl_net_ipv6_conf_all_accept_ra_pinfo_value='' + + +# +# Set runtime for net.ipv6.conf.all.accept_ra_pinfo +# +if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then + /sbin/sysctl -q -n -w net.ipv6.conf.all.accept_ra_pinfo="$sysctl_net_ipv6_conf_all_accept_ra_pinfo_value" +fi + +# +# If net.ipv6.conf.all.accept_ra_pinfo present in /etc/sysctl.conf, change value to appropriate value +# else, add "net.ipv6.conf.all.accept_ra_pinfo = value" to /etc/sysctl.conf +# + +# Strip any search characters in the key arg so that the key can be replaced without +# adding any search characters to the config file. +stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv6.conf.all.accept_ra_pinfo") + +# shellcheck disable=SC2059 +printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv6_conf_all_accept_ra_pinfo_value" + +# If the key exists, change it. Otherwise, add it to the config_file. +# We search for the key string followed by a word boundary (matched by \>), +# so if we search for 'setting', 'setting2' won't match. +if LC_ALL=C grep -q -m 1 -i -e "^net.ipv6.conf.all.accept_ra_pinfo\\>" "${SYSCONFIG_FILE}"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + LC_ALL=C sed -i --follow-symlinks "s/^net.ipv6.conf.all.accept_ra_pinfo\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" +else + if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" + fi + printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_all_accept_ra_pinfo + - unknown_severity + +- name: List /etc/sysctl.d/*.conf files + find: + paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + contains: ^[\s]*net.ipv6.conf.all.accept_ra_pinfo.*$ + patterns: '*.conf' + file_type: any + register: find_sysctl_d + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_all_accept_ra_pinfo + - unknown_severity + +- name: Comment out any occurrences of net.ipv6.conf.all.accept_ra_pinfo from config + files + replace: + path: '{{ item.path }}' + regexp: ^[\s]*net.ipv6.conf.all.accept_ra_pinfo + replace: '#net.ipv6.conf.all.accept_ra_pinfo' + loop: '{{ find_sysctl_d.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_all_accept_ra_pinfo + - unknown_severity +- name: XCCDF Value sysctl_net_ipv6_conf_all_accept_ra_pinfo_value # promote to variable + set_fact: + sysctl_net_ipv6_conf_all_accept_ra_pinfo_value: !!str + tags: + - always + +- name: Ensure sysctl net.ipv6.conf.all.accept_ra_pinfo is set + sysctl: + name: net.ipv6.conf.all.accept_ra_pinfo + value: '{{ sysctl_net_ipv6_conf_all_accept_ra_pinfo_value }}' + sysctl_file: /etc/sysctl.conf + state: present + reload: true + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_all_accept_ra_pinfo + - unknown_severity + + + + + + + + + + + Configure Accepting Router Preference in Router Advertisements on All IPv6 Interfaces + To set the runtime status of the net.ipv6.conf.all.accept_ra_rtr_pref kernel parameter, run the following command: $ sudo sysctl -w net.ipv6.conf.all.accept_ra_rtr_pref=0 +To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv6.conf.all.accept_ra_rtr_pref = 0 + + R13 + An illicit router advertisement message could result in a man-in-the-middle attack. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Comment out any occurrences of net.ipv6.conf.all.accept_ra_rtr_pref from /etc/sysctl.d/*.conf files + +for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do + + + # skip systemd-sysctl symlink (/etc/sysctl.d/99-sysctl.conf -> /etc/sysctl.conf) + if [[ "$(readlink -f "$f")" == "/etc/sysctl.conf" ]]; then continue; fi + + matching_list=$(grep -P '^(?!#).*[\s]*net.ipv6.conf.all.accept_ra_rtr_pref.*$' $f | uniq ) + if ! test -z "$matching_list"; then + while IFS= read -r entry; do + escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") + # comment out "net.ipv6.conf.all.accept_ra_rtr_pref" matches to preserve user data + sed -i --follow-symlinks "s/^${escaped_entry}$/# &/g" $f + done <<< "$matching_list" + fi +done + +# +# Set sysctl config file which to save the desired value +# + +SYSCONFIG_FILE="/etc/sysctl.conf" + +sysctl_net_ipv6_conf_all_accept_ra_rtr_pref_value='' + + +# +# Set runtime for net.ipv6.conf.all.accept_ra_rtr_pref +# +if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then + /sbin/sysctl -q -n -w net.ipv6.conf.all.accept_ra_rtr_pref="$sysctl_net_ipv6_conf_all_accept_ra_rtr_pref_value" +fi + +# +# If net.ipv6.conf.all.accept_ra_rtr_pref present in /etc/sysctl.conf, change value to appropriate value +# else, add "net.ipv6.conf.all.accept_ra_rtr_pref = value" to /etc/sysctl.conf +# + +# Strip any search characters in the key arg so that the key can be replaced without +# adding any search characters to the config file. +stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv6.conf.all.accept_ra_rtr_pref") + +# shellcheck disable=SC2059 +printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv6_conf_all_accept_ra_rtr_pref_value" + +# If the key exists, change it. Otherwise, add it to the config_file. +# We search for the key string followed by a word boundary (matched by \>), +# so if we search for 'setting', 'setting2' won't match. +if LC_ALL=C grep -q -m 1 -i -e "^net.ipv6.conf.all.accept_ra_rtr_pref\\>" "${SYSCONFIG_FILE}"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + LC_ALL=C sed -i --follow-symlinks "s/^net.ipv6.conf.all.accept_ra_rtr_pref\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" +else + if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" + fi + printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_all_accept_ra_rtr_pref + - unknown_severity + +- name: List /etc/sysctl.d/*.conf files + find: + paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + contains: ^[\s]*net.ipv6.conf.all.accept_ra_rtr_pref.*$ + patterns: '*.conf' + file_type: any + register: find_sysctl_d + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_all_accept_ra_rtr_pref + - unknown_severity + +- name: Comment out any occurrences of net.ipv6.conf.all.accept_ra_rtr_pref from config + files + replace: + path: '{{ item.path }}' + regexp: ^[\s]*net.ipv6.conf.all.accept_ra_rtr_pref + replace: '#net.ipv6.conf.all.accept_ra_rtr_pref' + loop: '{{ find_sysctl_d.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_all_accept_ra_rtr_pref + - unknown_severity +- name: XCCDF Value sysctl_net_ipv6_conf_all_accept_ra_rtr_pref_value # promote to variable + set_fact: + sysctl_net_ipv6_conf_all_accept_ra_rtr_pref_value: !!str + tags: + - always + +- name: Ensure sysctl net.ipv6.conf.all.accept_ra_rtr_pref is set + sysctl: + name: net.ipv6.conf.all.accept_ra_rtr_pref + value: '{{ sysctl_net_ipv6_conf_all_accept_ra_rtr_pref_value }}' + sysctl_file: /etc/sysctl.conf + state: present + reload: true + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_all_accept_ra_rtr_pref + - unknown_severity + + + + + + + + + + + Disable Accepting ICMP Redirects for All IPv6 Interfaces + To set the runtime status of the net.ipv6.conf.all.accept_redirects kernel parameter, run the following command: $ sudo sysctl -w net.ipv6.conf.all.accept_redirects=0 +To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv6.conf.all.accept_redirects = 0 + + 11 + 14 + 3 + 9 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS05.02 + DSS05.05 + DSS06.06 + 3.1.20 + CCI-000366 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.2 + 4.3.4.3.3 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 7.6 + A.12.1.2 + A.12.5.1 + A.12.6.2 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.9.1.2 + CM-7(a) + CM-7(b) + CM-6(a) + CM-6(b) + CM-6.1(iv) + PR.IP-1 + PR.PT-3 + SRG-OS-000480-GPOS-00227 + R13 + A.8.SEC-OL6 + OL09-00-006041 + SV-271878r1092346_rule + An illicit ICMP redirect message could result in a man-in-the-middle attack. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Comment out any occurrences of net.ipv6.conf.all.accept_redirects from /etc/sysctl.d/*.conf files + +for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do + + + # skip systemd-sysctl symlink (/etc/sysctl.d/99-sysctl.conf -> /etc/sysctl.conf) + if [[ "$(readlink -f "$f")" == "/etc/sysctl.conf" ]]; then continue; fi + + matching_list=$(grep -P '^(?!#).*[\s]*net.ipv6.conf.all.accept_redirects.*$' $f | uniq ) + if ! test -z "$matching_list"; then + while IFS= read -r entry; do + escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") + # comment out "net.ipv6.conf.all.accept_redirects" matches to preserve user data + sed -i --follow-symlinks "s/^${escaped_entry}$/# &/g" $f + done <<< "$matching_list" + fi +done + +# +# Set sysctl config file which to save the desired value +# + +SYSCONFIG_FILE="/etc/sysctl.conf" + +sysctl_net_ipv6_conf_all_accept_redirects_value='' + + +# +# Set runtime for net.ipv6.conf.all.accept_redirects +# +if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then + /sbin/sysctl -q -n -w net.ipv6.conf.all.accept_redirects="$sysctl_net_ipv6_conf_all_accept_redirects_value" +fi + +# +# If net.ipv6.conf.all.accept_redirects present in /etc/sysctl.conf, change value to appropriate value +# else, add "net.ipv6.conf.all.accept_redirects = value" to /etc/sysctl.conf +# + +# Strip any search characters in the key arg so that the key can be replaced without +# adding any search characters to the config file. +stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv6.conf.all.accept_redirects") + +# shellcheck disable=SC2059 +printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv6_conf_all_accept_redirects_value" + +# If the key exists, change it. Otherwise, add it to the config_file. +# We search for the key string followed by a word boundary (matched by \>), +# so if we search for 'setting', 'setting2' won't match. +if LC_ALL=C grep -q -m 1 -i -e "^net.ipv6.conf.all.accept_redirects\\>" "${SYSCONFIG_FILE}"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + LC_ALL=C sed -i --follow-symlinks "s/^net.ipv6.conf.all.accept_redirects\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" +else + if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" + fi + printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-006041 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-6(b) + - NIST-800-53-CM-6.1(iv) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_all_accept_redirects + +- name: List /etc/sysctl.d/*.conf files + find: + paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + contains: ^[\s]*net.ipv6.conf.all.accept_redirects.*$ + patterns: '*.conf' + file_type: any + register: find_sysctl_d + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006041 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-6(b) + - NIST-800-53-CM-6.1(iv) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_all_accept_redirects + +- name: Comment out any occurrences of net.ipv6.conf.all.accept_redirects from config + files + replace: + path: '{{ item.path }}' + regexp: ^[\s]*net.ipv6.conf.all.accept_redirects + replace: '#net.ipv6.conf.all.accept_redirects' + loop: '{{ find_sysctl_d.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006041 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-6(b) + - NIST-800-53-CM-6.1(iv) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_all_accept_redirects +- name: XCCDF Value sysctl_net_ipv6_conf_all_accept_redirects_value # promote to variable + set_fact: + sysctl_net_ipv6_conf_all_accept_redirects_value: !!str + tags: + - always + +- name: Ensure sysctl net.ipv6.conf.all.accept_redirects is set + sysctl: + name: net.ipv6.conf.all.accept_redirects + value: '{{ sysctl_net_ipv6_conf_all_accept_redirects_value }}' + sysctl_file: /etc/sysctl.conf + state: present + reload: true + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006041 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-6(b) + - NIST-800-53-CM-6.1(iv) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_all_accept_redirects + + + + + + + + + + + Disable Kernel Parameter for Accepting Source-Routed Packets on all IPv6 Interfaces + To set the runtime status of the net.ipv6.conf.all.accept_source_route kernel parameter, run the following command: $ sudo sysctl -w net.ipv6.conf.all.accept_source_route=0 +To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv6.conf.all.accept_source_route = 0 + + 1 + 12 + 13 + 14 + 15 + 16 + 18 + 4 + 6 + 8 + 9 + APO01.06 + APO13.01 + DSS01.05 + DSS03.01 + DSS05.02 + DSS05.04 + DSS05.07 + DSS06.02 + 3.1.20 + CCI-000366 + 4.2.3.4 + 4.3.3.4 + 4.4.3.3 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 7.1 + SR 7.6 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.12.1.1 + A.12.1.2 + A.13.1.1 + A.13.1.2 + A.13.1.3 + A.13.2.1 + A.13.2.2 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CM-7(a) + CM-7(b) + CM-6(a) + DE.AE-1 + ID.AM-3 + PR.AC-5 + PR.DS-5 + PR.PT-4 + SRG-OS-000480-GPOS-00227 + R13 + A.8.SEC-OL6 + OL09-00-006042 + SV-271879r1092349_rule + Source-routed packets allow the source of the packet to suggest routers +forward the packet along a different path than configured on the router, which can +be used to bypass network security measures. This requirement applies only to the +forwarding of source-routerd traffic, such as when IPv6 forwarding is enabled and +the system is functioning as a router. + + +Accepting source-routed packets in the IPv6 protocol has few legitimate +uses. It should be disabled unless it is absolutely required. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Comment out any occurrences of net.ipv6.conf.all.accept_source_route from /etc/sysctl.d/*.conf files + +for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do + + + # skip systemd-sysctl symlink (/etc/sysctl.d/99-sysctl.conf -> /etc/sysctl.conf) + if [[ "$(readlink -f "$f")" == "/etc/sysctl.conf" ]]; then continue; fi + + matching_list=$(grep -P '^(?!#).*[\s]*net.ipv6.conf.all.accept_source_route.*$' $f | uniq ) + if ! test -z "$matching_list"; then + while IFS= read -r entry; do + escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") + # comment out "net.ipv6.conf.all.accept_source_route" matches to preserve user data + sed -i --follow-symlinks "s/^${escaped_entry}$/# &/g" $f + done <<< "$matching_list" + fi +done + +# +# Set sysctl config file which to save the desired value +# + +SYSCONFIG_FILE="/etc/sysctl.conf" + +sysctl_net_ipv6_conf_all_accept_source_route_value='' + + +# +# Set runtime for net.ipv6.conf.all.accept_source_route +# +if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then + /sbin/sysctl -q -n -w net.ipv6.conf.all.accept_source_route="$sysctl_net_ipv6_conf_all_accept_source_route_value" +fi + +# +# If net.ipv6.conf.all.accept_source_route present in /etc/sysctl.conf, change value to appropriate value +# else, add "net.ipv6.conf.all.accept_source_route = value" to /etc/sysctl.conf +# + +# Strip any search characters in the key arg so that the key can be replaced without +# adding any search characters to the config file. +stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv6.conf.all.accept_source_route") + +# shellcheck disable=SC2059 +printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv6_conf_all_accept_source_route_value" + +# If the key exists, change it. Otherwise, add it to the config_file. +# We search for the key string followed by a word boundary (matched by \>), +# so if we search for 'setting', 'setting2' won't match. +if LC_ALL=C grep -q -m 1 -i -e "^net.ipv6.conf.all.accept_source_route\\>" "${SYSCONFIG_FILE}"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + LC_ALL=C sed -i --follow-symlinks "s/^net.ipv6.conf.all.accept_source_route\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" +else + if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" + fi + printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-006042 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_all_accept_source_route + +- name: List /etc/sysctl.d/*.conf files + find: + paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + contains: ^[\s]*net.ipv6.conf.all.accept_source_route.*$ + patterns: '*.conf' + file_type: any + register: find_sysctl_d + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006042 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_all_accept_source_route + +- name: Comment out any occurrences of net.ipv6.conf.all.accept_source_route from + config files + replace: + path: '{{ item.path }}' + regexp: ^[\s]*net.ipv6.conf.all.accept_source_route + replace: '#net.ipv6.conf.all.accept_source_route' + loop: '{{ find_sysctl_d.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006042 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_all_accept_source_route +- name: XCCDF Value sysctl_net_ipv6_conf_all_accept_source_route_value # promote to variable + set_fact: + sysctl_net_ipv6_conf_all_accept_source_route_value: !!str + tags: + - always + +- name: Ensure sysctl net.ipv6.conf.all.accept_source_route is set + sysctl: + name: net.ipv6.conf.all.accept_source_route + value: '{{ sysctl_net_ipv6_conf_all_accept_source_route_value }}' + sysctl_file: /etc/sysctl.conf + state: present + reload: true + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006042 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_all_accept_source_route + + + + + + + + + + + Configure Auto Configuration on All IPv6 Interfaces + To set the runtime status of the net.ipv6.conf.all.autoconf kernel parameter, run the following command: $ sudo sysctl -w net.ipv6.conf.all.autoconf=0 +To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv6.conf.all.autoconf = 0 + + R13 + An illicit router advertisement message could result in a man-in-the-middle attack. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Comment out any occurrences of net.ipv6.conf.all.autoconf from /etc/sysctl.d/*.conf files + +for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do + + + # skip systemd-sysctl symlink (/etc/sysctl.d/99-sysctl.conf -> /etc/sysctl.conf) + if [[ "$(readlink -f "$f")" == "/etc/sysctl.conf" ]]; then continue; fi + + matching_list=$(grep -P '^(?!#).*[\s]*net.ipv6.conf.all.autoconf.*$' $f | uniq ) + if ! test -z "$matching_list"; then + while IFS= read -r entry; do + escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") + # comment out "net.ipv6.conf.all.autoconf" matches to preserve user data + sed -i --follow-symlinks "s/^${escaped_entry}$/# &/g" $f + done <<< "$matching_list" + fi +done + +# +# Set sysctl config file which to save the desired value +# + +SYSCONFIG_FILE="/etc/sysctl.conf" + +sysctl_net_ipv6_conf_all_autoconf_value='' + + +# +# Set runtime for net.ipv6.conf.all.autoconf +# +if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then + /sbin/sysctl -q -n -w net.ipv6.conf.all.autoconf="$sysctl_net_ipv6_conf_all_autoconf_value" +fi + +# +# If net.ipv6.conf.all.autoconf present in /etc/sysctl.conf, change value to appropriate value +# else, add "net.ipv6.conf.all.autoconf = value" to /etc/sysctl.conf +# + +# Strip any search characters in the key arg so that the key can be replaced without +# adding any search characters to the config file. +stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv6.conf.all.autoconf") + +# shellcheck disable=SC2059 +printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv6_conf_all_autoconf_value" + +# If the key exists, change it. Otherwise, add it to the config_file. +# We search for the key string followed by a word boundary (matched by \>), +# so if we search for 'setting', 'setting2' won't match. +if LC_ALL=C grep -q -m 1 -i -e "^net.ipv6.conf.all.autoconf\\>" "${SYSCONFIG_FILE}"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + LC_ALL=C sed -i --follow-symlinks "s/^net.ipv6.conf.all.autoconf\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" +else + if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" + fi + printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_all_autoconf + - unknown_severity + +- name: List /etc/sysctl.d/*.conf files + find: + paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + contains: ^[\s]*net.ipv6.conf.all.autoconf.*$ + patterns: '*.conf' + file_type: any + register: find_sysctl_d + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_all_autoconf + - unknown_severity + +- name: Comment out any occurrences of net.ipv6.conf.all.autoconf from config files + replace: + path: '{{ item.path }}' + regexp: ^[\s]*net.ipv6.conf.all.autoconf + replace: '#net.ipv6.conf.all.autoconf' + loop: '{{ find_sysctl_d.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_all_autoconf + - unknown_severity +- name: XCCDF Value sysctl_net_ipv6_conf_all_autoconf_value # promote to variable + set_fact: + sysctl_net_ipv6_conf_all_autoconf_value: !!str + tags: + - always + +- name: Ensure sysctl net.ipv6.conf.all.autoconf is set + sysctl: + name: net.ipv6.conf.all.autoconf + value: '{{ sysctl_net_ipv6_conf_all_autoconf_value }}' + sysctl_file: /etc/sysctl.conf + state: present + reload: true + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_all_autoconf + - unknown_severity + + + + + + + + + + + Disable Kernel Parameter for IPv6 Forwarding + To set the runtime status of the net.ipv6.conf.all.forwarding kernel parameter, run the following command: $ sudo sysctl -w net.ipv6.conf.all.forwarding=0 +To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv6.conf.all.forwarding = 0 + + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 2 + 3 + 7 + 8 + 9 + APO13.01 + BAI04.04 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS01.03 + DSS03.05 + DSS05.02 + DSS05.05 + DSS05.07 + DSS06.06 + CCI-000366 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.2 + 4.3.4.3.3 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 6.2 + SR 7.1 + SR 7.2 + SR 7.6 + A.12.1.2 + A.12.1.3 + A.12.5.1 + A.12.6.2 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.17.2.1 + A.9.1.2 + CM-7(a) + CM-7(b) + CM-6(a) + CM-6(b) + CM-6.1(iv) + DE.CM-1 + PR.DS-4 + PR.IP-1 + PR.PT-3 + SRG-OS-000480-GPOS-00227 + OL09-00-006043 + SV-271880r1092352_rule + IP forwarding permits the kernel to forward packets from one network +interface to another. The ability to forward packets between two networks is +only appropriate for systems acting as routers. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Comment out any occurrences of net.ipv6.conf.all.forwarding from /etc/sysctl.d/*.conf files + +for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do + + + # skip systemd-sysctl symlink (/etc/sysctl.d/99-sysctl.conf -> /etc/sysctl.conf) + if [[ "$(readlink -f "$f")" == "/etc/sysctl.conf" ]]; then continue; fi + + matching_list=$(grep -P '^(?!#).*[\s]*net.ipv6.conf.all.forwarding.*$' $f | uniq ) + if ! test -z "$matching_list"; then + while IFS= read -r entry; do + escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") + # comment out "net.ipv6.conf.all.forwarding" matches to preserve user data + sed -i --follow-symlinks "s/^${escaped_entry}$/# &/g" $f + done <<< "$matching_list" + fi +done + +# +# Set sysctl config file which to save the desired value +# + +SYSCONFIG_FILE="/etc/sysctl.conf" + +sysctl_net_ipv6_conf_all_forwarding_value='' + + +# +# Set runtime for net.ipv6.conf.all.forwarding +# +if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then + /sbin/sysctl -q -n -w net.ipv6.conf.all.forwarding="$sysctl_net_ipv6_conf_all_forwarding_value" +fi + +# +# If net.ipv6.conf.all.forwarding present in /etc/sysctl.conf, change value to appropriate value +# else, add "net.ipv6.conf.all.forwarding = value" to /etc/sysctl.conf +# + +# Strip any search characters in the key arg so that the key can be replaced without +# adding any search characters to the config file. +stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv6.conf.all.forwarding") + +# shellcheck disable=SC2059 +printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv6_conf_all_forwarding_value" + +# If the key exists, change it. Otherwise, add it to the config_file. +# We search for the key string followed by a word boundary (matched by \>), +# so if we search for 'setting', 'setting2' won't match. +if LC_ALL=C grep -q -m 1 -i -e "^net.ipv6.conf.all.forwarding\\>" "${SYSCONFIG_FILE}"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + LC_ALL=C sed -i --follow-symlinks "s/^net.ipv6.conf.all.forwarding\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" +else + if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" + fi + printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-006043 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-6(b) + - NIST-800-53-CM-6.1(iv) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_all_forwarding + +- name: List /etc/sysctl.d/*.conf files + find: + paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + contains: ^[\s]*net.ipv6.conf.all.forwarding.*$ + patterns: '*.conf' + file_type: any + register: find_sysctl_d + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006043 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-6(b) + - NIST-800-53-CM-6.1(iv) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_all_forwarding + +- name: Comment out any occurrences of net.ipv6.conf.all.forwarding from config files + replace: + path: '{{ item.path }}' + regexp: ^[\s]*net.ipv6.conf.all.forwarding + replace: '#net.ipv6.conf.all.forwarding' + loop: '{{ find_sysctl_d.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006043 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-6(b) + - NIST-800-53-CM-6.1(iv) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_all_forwarding +- name: XCCDF Value sysctl_net_ipv6_conf_all_forwarding_value # promote to variable + set_fact: + sysctl_net_ipv6_conf_all_forwarding_value: !!str + tags: + - always + +- name: Ensure sysctl net.ipv6.conf.all.forwarding is set + sysctl: + name: net.ipv6.conf.all.forwarding + value: '{{ sysctl_net_ipv6_conf_all_forwarding_value }}' + sysctl_file: /etc/sysctl.conf + state: present + reload: true + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006043 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-6(b) + - NIST-800-53-CM-6.1(iv) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_all_forwarding + + + + + + + + + + + Configure Maximum Number of Autoconfigured Addresses on All IPv6 Interfaces + To set the runtime status of the net.ipv6.conf.all.max_addresses kernel parameter, run the following command: $ sudo sysctl -w net.ipv6.conf.all.max_addresses=1 +To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv6.conf.all.max_addresses = 1 + + R13 + The number of global unicast IPv6 addresses for each interface should be limited exactly to the number of statically configured addresses. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Comment out any occurrences of net.ipv6.conf.all.max_addresses from /etc/sysctl.d/*.conf files + +for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do + + + # skip systemd-sysctl symlink (/etc/sysctl.d/99-sysctl.conf -> /etc/sysctl.conf) + if [[ "$(readlink -f "$f")" == "/etc/sysctl.conf" ]]; then continue; fi + + matching_list=$(grep -P '^(?!#).*[\s]*net.ipv6.conf.all.max_addresses.*$' $f | uniq ) + if ! test -z "$matching_list"; then + while IFS= read -r entry; do + escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") + # comment out "net.ipv6.conf.all.max_addresses" matches to preserve user data + sed -i --follow-symlinks "s/^${escaped_entry}$/# &/g" $f + done <<< "$matching_list" + fi +done + +# +# Set sysctl config file which to save the desired value +# + +SYSCONFIG_FILE="/etc/sysctl.conf" + +sysctl_net_ipv6_conf_all_max_addresses_value='' + + +# +# Set runtime for net.ipv6.conf.all.max_addresses +# +if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then + /sbin/sysctl -q -n -w net.ipv6.conf.all.max_addresses="$sysctl_net_ipv6_conf_all_max_addresses_value" +fi + +# +# If net.ipv6.conf.all.max_addresses present in /etc/sysctl.conf, change value to appropriate value +# else, add "net.ipv6.conf.all.max_addresses = value" to /etc/sysctl.conf +# + +# Strip any search characters in the key arg so that the key can be replaced without +# adding any search characters to the config file. +stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv6.conf.all.max_addresses") + +# shellcheck disable=SC2059 +printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv6_conf_all_max_addresses_value" + +# If the key exists, change it. Otherwise, add it to the config_file. +# We search for the key string followed by a word boundary (matched by \>), +# so if we search for 'setting', 'setting2' won't match. +if LC_ALL=C grep -q -m 1 -i -e "^net.ipv6.conf.all.max_addresses\\>" "${SYSCONFIG_FILE}"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + LC_ALL=C sed -i --follow-symlinks "s/^net.ipv6.conf.all.max_addresses\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" +else + if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" + fi + printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_all_max_addresses + - unknown_severity + +- name: List /etc/sysctl.d/*.conf files + find: + paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + contains: ^[\s]*net.ipv6.conf.all.max_addresses.*$ + patterns: '*.conf' + file_type: any + register: find_sysctl_d + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_all_max_addresses + - unknown_severity + +- name: Comment out any occurrences of net.ipv6.conf.all.max_addresses from config + files + replace: + path: '{{ item.path }}' + regexp: ^[\s]*net.ipv6.conf.all.max_addresses + replace: '#net.ipv6.conf.all.max_addresses' + loop: '{{ find_sysctl_d.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_all_max_addresses + - unknown_severity +- name: XCCDF Value sysctl_net_ipv6_conf_all_max_addresses_value # promote to variable + set_fact: + sysctl_net_ipv6_conf_all_max_addresses_value: !!str + tags: + - always + +- name: Ensure sysctl net.ipv6.conf.all.max_addresses is set + sysctl: + name: net.ipv6.conf.all.max_addresses + value: '{{ sysctl_net_ipv6_conf_all_max_addresses_value }}' + sysctl_file: /etc/sysctl.conf + state: present + reload: true + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_all_max_addresses + - unknown_severity + + + + + + + + + + + Configure Denying Router Solicitations on All IPv6 Interfaces + To set the runtime status of the net.ipv6.conf.all.router_solicitations kernel parameter, run the following command: $ sudo sysctl -w net.ipv6.conf.all.router_solicitations=0 +To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv6.conf.all.router_solicitations = 0 + + R13 + To prevent discovery of the system by other systems, router solicitation requests should be denied. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Comment out any occurrences of net.ipv6.conf.all.router_solicitations from /etc/sysctl.d/*.conf files + +for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do + + + # skip systemd-sysctl symlink (/etc/sysctl.d/99-sysctl.conf -> /etc/sysctl.conf) + if [[ "$(readlink -f "$f")" == "/etc/sysctl.conf" ]]; then continue; fi + + matching_list=$(grep -P '^(?!#).*[\s]*net.ipv6.conf.all.router_solicitations.*$' $f | uniq ) + if ! test -z "$matching_list"; then + while IFS= read -r entry; do + escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") + # comment out "net.ipv6.conf.all.router_solicitations" matches to preserve user data + sed -i --follow-symlinks "s/^${escaped_entry}$/# &/g" $f + done <<< "$matching_list" + fi +done + +# +# Set sysctl config file which to save the desired value +# + +SYSCONFIG_FILE="/etc/sysctl.conf" + +sysctl_net_ipv6_conf_all_router_solicitations_value='' + + +# +# Set runtime for net.ipv6.conf.all.router_solicitations +# +if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then + /sbin/sysctl -q -n -w net.ipv6.conf.all.router_solicitations="$sysctl_net_ipv6_conf_all_router_solicitations_value" +fi + +# +# If net.ipv6.conf.all.router_solicitations present in /etc/sysctl.conf, change value to appropriate value +# else, add "net.ipv6.conf.all.router_solicitations = value" to /etc/sysctl.conf +# + +# Strip any search characters in the key arg so that the key can be replaced without +# adding any search characters to the config file. +stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv6.conf.all.router_solicitations") + +# shellcheck disable=SC2059 +printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv6_conf_all_router_solicitations_value" + +# If the key exists, change it. Otherwise, add it to the config_file. +# We search for the key string followed by a word boundary (matched by \>), +# so if we search for 'setting', 'setting2' won't match. +if LC_ALL=C grep -q -m 1 -i -e "^net.ipv6.conf.all.router_solicitations\\>" "${SYSCONFIG_FILE}"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + LC_ALL=C sed -i --follow-symlinks "s/^net.ipv6.conf.all.router_solicitations\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" +else + if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" + fi + printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_all_router_solicitations + - unknown_severity + +- name: List /etc/sysctl.d/*.conf files + find: + paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + contains: ^[\s]*net.ipv6.conf.all.router_solicitations.*$ + patterns: '*.conf' + file_type: any + register: find_sysctl_d + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_all_router_solicitations + - unknown_severity + +- name: Comment out any occurrences of net.ipv6.conf.all.router_solicitations from + config files + replace: + path: '{{ item.path }}' + regexp: ^[\s]*net.ipv6.conf.all.router_solicitations + replace: '#net.ipv6.conf.all.router_solicitations' + loop: '{{ find_sysctl_d.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_all_router_solicitations + - unknown_severity +- name: XCCDF Value sysctl_net_ipv6_conf_all_router_solicitations_value # promote to variable + set_fact: + sysctl_net_ipv6_conf_all_router_solicitations_value: !!str + tags: + - always + +- name: Ensure sysctl net.ipv6.conf.all.router_solicitations is set + sysctl: + name: net.ipv6.conf.all.router_solicitations + value: '{{ sysctl_net_ipv6_conf_all_router_solicitations_value }}' + sysctl_file: /etc/sysctl.conf + state: present + reload: true + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_all_router_solicitations + - unknown_severity + + + + + + + + + + + Disable Accepting Router Advertisements on all IPv6 Interfaces by Default + To set the runtime status of the net.ipv6.conf.default.accept_ra kernel parameter, run the following command: $ sudo sysctl -w net.ipv6.conf.default.accept_ra=0 +To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv6.conf.default.accept_ra = 0 + + 11 + 14 + 3 + 9 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS05.02 + DSS05.05 + DSS06.06 + 3.1.20 + CCI-000366 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.2 + 4.3.4.3.3 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 7.6 + A.12.1.2 + A.12.5.1 + A.12.6.2 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.9.1.2 + CM-7(a) + CM-7(b) + CM-6(a) + PR.IP-1 + PR.PT-3 + SRG-OS-000480-GPOS-00227 + A.8.SEC-OL6 + OL09-00-006044 + SV-271881r1092355_rule + An illicit router advertisement message could result in a man-in-the-middle attack. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Comment out any occurrences of net.ipv6.conf.default.accept_ra from /etc/sysctl.d/*.conf files + +for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do + + + # skip systemd-sysctl symlink (/etc/sysctl.d/99-sysctl.conf -> /etc/sysctl.conf) + if [[ "$(readlink -f "$f")" == "/etc/sysctl.conf" ]]; then continue; fi + + matching_list=$(grep -P '^(?!#).*[\s]*net.ipv6.conf.default.accept_ra.*$' $f | uniq ) + if ! test -z "$matching_list"; then + while IFS= read -r entry; do + escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") + # comment out "net.ipv6.conf.default.accept_ra" matches to preserve user data + sed -i --follow-symlinks "s/^${escaped_entry}$/# &/g" $f + done <<< "$matching_list" + fi +done + +# +# Set sysctl config file which to save the desired value +# + +SYSCONFIG_FILE="/etc/sysctl.conf" + +sysctl_net_ipv6_conf_default_accept_ra_value='' + + +# +# Set runtime for net.ipv6.conf.default.accept_ra +# +if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then + /sbin/sysctl -q -n -w net.ipv6.conf.default.accept_ra="$sysctl_net_ipv6_conf_default_accept_ra_value" +fi + +# +# If net.ipv6.conf.default.accept_ra present in /etc/sysctl.conf, change value to appropriate value +# else, add "net.ipv6.conf.default.accept_ra = value" to /etc/sysctl.conf +# + +# Strip any search characters in the key arg so that the key can be replaced without +# adding any search characters to the config file. +stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv6.conf.default.accept_ra") + +# shellcheck disable=SC2059 +printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv6_conf_default_accept_ra_value" + +# If the key exists, change it. Otherwise, add it to the config_file. +# We search for the key string followed by a word boundary (matched by \>), +# so if we search for 'setting', 'setting2' won't match. +if LC_ALL=C grep -q -m 1 -i -e "^net.ipv6.conf.default.accept_ra\\>" "${SYSCONFIG_FILE}"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + LC_ALL=C sed -i --follow-symlinks "s/^net.ipv6.conf.default.accept_ra\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" +else + if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" + fi + printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-006044 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_default_accept_ra + +- name: List /etc/sysctl.d/*.conf files + find: + paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + contains: ^[\s]*net.ipv6.conf.default.accept_ra.*$ + patterns: '*.conf' + file_type: any + register: find_sysctl_d + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006044 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_default_accept_ra + +- name: Comment out any occurrences of net.ipv6.conf.default.accept_ra from config + files + replace: + path: '{{ item.path }}' + regexp: ^[\s]*net.ipv6.conf.default.accept_ra + replace: '#net.ipv6.conf.default.accept_ra' + loop: '{{ find_sysctl_d.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006044 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_default_accept_ra +- name: XCCDF Value sysctl_net_ipv6_conf_default_accept_ra_value # promote to variable + set_fact: + sysctl_net_ipv6_conf_default_accept_ra_value: !!str + tags: + - always + +- name: Ensure sysctl net.ipv6.conf.default.accept_ra is set + sysctl: + name: net.ipv6.conf.default.accept_ra + value: '{{ sysctl_net_ipv6_conf_default_accept_ra_value }}' + sysctl_file: /etc/sysctl.conf + state: present + reload: true + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006044 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_default_accept_ra + + + + + + + + + + + Configure Accepting Default Router in Router Advertisements on All IPv6 Interfaces By Default + To set the runtime status of the net.ipv6.conf.default.accept_ra_defrtr kernel parameter, run the following command: $ sudo sysctl -w net.ipv6.conf.default.accept_ra_defrtr=0 +To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv6.conf.default.accept_ra_defrtr = 0 + + R13 + An illicit router advertisement message could result in a man-in-the-middle attack. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Comment out any occurrences of net.ipv6.conf.default.accept_ra_defrtr from /etc/sysctl.d/*.conf files + +for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do + + + # skip systemd-sysctl symlink (/etc/sysctl.d/99-sysctl.conf -> /etc/sysctl.conf) + if [[ "$(readlink -f "$f")" == "/etc/sysctl.conf" ]]; then continue; fi + + matching_list=$(grep -P '^(?!#).*[\s]*net.ipv6.conf.default.accept_ra_defrtr.*$' $f | uniq ) + if ! test -z "$matching_list"; then + while IFS= read -r entry; do + escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") + # comment out "net.ipv6.conf.default.accept_ra_defrtr" matches to preserve user data + sed -i --follow-symlinks "s/^${escaped_entry}$/# &/g" $f + done <<< "$matching_list" + fi +done + +# +# Set sysctl config file which to save the desired value +# + +SYSCONFIG_FILE="/etc/sysctl.conf" + +sysctl_net_ipv6_conf_default_accept_ra_defrtr_value='' + + +# +# Set runtime for net.ipv6.conf.default.accept_ra_defrtr +# +if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then + /sbin/sysctl -q -n -w net.ipv6.conf.default.accept_ra_defrtr="$sysctl_net_ipv6_conf_default_accept_ra_defrtr_value" +fi + +# +# If net.ipv6.conf.default.accept_ra_defrtr present in /etc/sysctl.conf, change value to appropriate value +# else, add "net.ipv6.conf.default.accept_ra_defrtr = value" to /etc/sysctl.conf +# + +# Strip any search characters in the key arg so that the key can be replaced without +# adding any search characters to the config file. +stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv6.conf.default.accept_ra_defrtr") + +# shellcheck disable=SC2059 +printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv6_conf_default_accept_ra_defrtr_value" + +# If the key exists, change it. Otherwise, add it to the config_file. +# We search for the key string followed by a word boundary (matched by \>), +# so if we search for 'setting', 'setting2' won't match. +if LC_ALL=C grep -q -m 1 -i -e "^net.ipv6.conf.default.accept_ra_defrtr\\>" "${SYSCONFIG_FILE}"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + LC_ALL=C sed -i --follow-symlinks "s/^net.ipv6.conf.default.accept_ra_defrtr\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" +else + if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" + fi + printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_default_accept_ra_defrtr + - unknown_severity + +- name: List /etc/sysctl.d/*.conf files + find: + paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + contains: ^[\s]*net.ipv6.conf.default.accept_ra_defrtr.*$ + patterns: '*.conf' + file_type: any + register: find_sysctl_d + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_default_accept_ra_defrtr + - unknown_severity + +- name: Comment out any occurrences of net.ipv6.conf.default.accept_ra_defrtr from + config files + replace: + path: '{{ item.path }}' + regexp: ^[\s]*net.ipv6.conf.default.accept_ra_defrtr + replace: '#net.ipv6.conf.default.accept_ra_defrtr' + loop: '{{ find_sysctl_d.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_default_accept_ra_defrtr + - unknown_severity +- name: XCCDF Value sysctl_net_ipv6_conf_default_accept_ra_defrtr_value # promote to variable + set_fact: + sysctl_net_ipv6_conf_default_accept_ra_defrtr_value: !!str + tags: + - always + +- name: Ensure sysctl net.ipv6.conf.default.accept_ra_defrtr is set + sysctl: + name: net.ipv6.conf.default.accept_ra_defrtr + value: '{{ sysctl_net_ipv6_conf_default_accept_ra_defrtr_value }}' + sysctl_file: /etc/sysctl.conf + state: present + reload: true + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_default_accept_ra_defrtr + - unknown_severity + + + + + + + + + + + Configure Accepting Prefix Information in Router Advertisements on All IPv6 Interfaces By Default + To set the runtime status of the net.ipv6.conf.default.accept_ra_pinfo kernel parameter, run the following command: $ sudo sysctl -w net.ipv6.conf.default.accept_ra_pinfo=0 +To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv6.conf.default.accept_ra_pinfo = 0 + + R13 + An illicit router advertisement message could result in a man-in-the-middle attack. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Comment out any occurrences of net.ipv6.conf.default.accept_ra_pinfo from /etc/sysctl.d/*.conf files + +for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do + + + # skip systemd-sysctl symlink (/etc/sysctl.d/99-sysctl.conf -> /etc/sysctl.conf) + if [[ "$(readlink -f "$f")" == "/etc/sysctl.conf" ]]; then continue; fi + + matching_list=$(grep -P '^(?!#).*[\s]*net.ipv6.conf.default.accept_ra_pinfo.*$' $f | uniq ) + if ! test -z "$matching_list"; then + while IFS= read -r entry; do + escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") + # comment out "net.ipv6.conf.default.accept_ra_pinfo" matches to preserve user data + sed -i --follow-symlinks "s/^${escaped_entry}$/# &/g" $f + done <<< "$matching_list" + fi +done + +# +# Set sysctl config file which to save the desired value +# + +SYSCONFIG_FILE="/etc/sysctl.conf" + +sysctl_net_ipv6_conf_default_accept_ra_pinfo_value='' + + +# +# Set runtime for net.ipv6.conf.default.accept_ra_pinfo +# +if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then + /sbin/sysctl -q -n -w net.ipv6.conf.default.accept_ra_pinfo="$sysctl_net_ipv6_conf_default_accept_ra_pinfo_value" +fi + +# +# If net.ipv6.conf.default.accept_ra_pinfo present in /etc/sysctl.conf, change value to appropriate value +# else, add "net.ipv6.conf.default.accept_ra_pinfo = value" to /etc/sysctl.conf +# + +# Strip any search characters in the key arg so that the key can be replaced without +# adding any search characters to the config file. +stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv6.conf.default.accept_ra_pinfo") + +# shellcheck disable=SC2059 +printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv6_conf_default_accept_ra_pinfo_value" + +# If the key exists, change it. Otherwise, add it to the config_file. +# We search for the key string followed by a word boundary (matched by \>), +# so if we search for 'setting', 'setting2' won't match. +if LC_ALL=C grep -q -m 1 -i -e "^net.ipv6.conf.default.accept_ra_pinfo\\>" "${SYSCONFIG_FILE}"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + LC_ALL=C sed -i --follow-symlinks "s/^net.ipv6.conf.default.accept_ra_pinfo\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" +else + if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" + fi + printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_default_accept_ra_pinfo + - unknown_severity + +- name: List /etc/sysctl.d/*.conf files + find: + paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + contains: ^[\s]*net.ipv6.conf.default.accept_ra_pinfo.*$ + patterns: '*.conf' + file_type: any + register: find_sysctl_d + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_default_accept_ra_pinfo + - unknown_severity + +- name: Comment out any occurrences of net.ipv6.conf.default.accept_ra_pinfo from + config files + replace: + path: '{{ item.path }}' + regexp: ^[\s]*net.ipv6.conf.default.accept_ra_pinfo + replace: '#net.ipv6.conf.default.accept_ra_pinfo' + loop: '{{ find_sysctl_d.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_default_accept_ra_pinfo + - unknown_severity +- name: XCCDF Value sysctl_net_ipv6_conf_default_accept_ra_pinfo_value # promote to variable + set_fact: + sysctl_net_ipv6_conf_default_accept_ra_pinfo_value: !!str + tags: + - always + +- name: Ensure sysctl net.ipv6.conf.default.accept_ra_pinfo is set + sysctl: + name: net.ipv6.conf.default.accept_ra_pinfo + value: '{{ sysctl_net_ipv6_conf_default_accept_ra_pinfo_value }}' + sysctl_file: /etc/sysctl.conf + state: present + reload: true + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_default_accept_ra_pinfo + - unknown_severity + + + + + + + + + + + Configure Accepting Router Preference in Router Advertisements on All IPv6 Interfaces By Default + To set the runtime status of the net.ipv6.conf.default.accept_ra_rtr_pref kernel parameter, run the following command: $ sudo sysctl -w net.ipv6.conf.default.accept_ra_rtr_pref=0 +To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv6.conf.default.accept_ra_rtr_pref = 0 + + R13 + An illicit router advertisement message could result in a man-in-the-middle attack. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Comment out any occurrences of net.ipv6.conf.default.accept_ra_rtr_pref from /etc/sysctl.d/*.conf files + +for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do + + + # skip systemd-sysctl symlink (/etc/sysctl.d/99-sysctl.conf -> /etc/sysctl.conf) + if [[ "$(readlink -f "$f")" == "/etc/sysctl.conf" ]]; then continue; fi + + matching_list=$(grep -P '^(?!#).*[\s]*net.ipv6.conf.default.accept_ra_rtr_pref.*$' $f | uniq ) + if ! test -z "$matching_list"; then + while IFS= read -r entry; do + escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") + # comment out "net.ipv6.conf.default.accept_ra_rtr_pref" matches to preserve user data + sed -i --follow-symlinks "s/^${escaped_entry}$/# &/g" $f + done <<< "$matching_list" + fi +done + +# +# Set sysctl config file which to save the desired value +# + +SYSCONFIG_FILE="/etc/sysctl.conf" + +sysctl_net_ipv6_conf_default_accept_ra_rtr_pref_value='' + + +# +# Set runtime for net.ipv6.conf.default.accept_ra_rtr_pref +# +if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then + /sbin/sysctl -q -n -w net.ipv6.conf.default.accept_ra_rtr_pref="$sysctl_net_ipv6_conf_default_accept_ra_rtr_pref_value" +fi + +# +# If net.ipv6.conf.default.accept_ra_rtr_pref present in /etc/sysctl.conf, change value to appropriate value +# else, add "net.ipv6.conf.default.accept_ra_rtr_pref = value" to /etc/sysctl.conf +# + +# Strip any search characters in the key arg so that the key can be replaced without +# adding any search characters to the config file. +stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv6.conf.default.accept_ra_rtr_pref") + +# shellcheck disable=SC2059 +printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv6_conf_default_accept_ra_rtr_pref_value" + +# If the key exists, change it. Otherwise, add it to the config_file. +# We search for the key string followed by a word boundary (matched by \>), +# so if we search for 'setting', 'setting2' won't match. +if LC_ALL=C grep -q -m 1 -i -e "^net.ipv6.conf.default.accept_ra_rtr_pref\\>" "${SYSCONFIG_FILE}"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + LC_ALL=C sed -i --follow-symlinks "s/^net.ipv6.conf.default.accept_ra_rtr_pref\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" +else + if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" + fi + printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_default_accept_ra_rtr_pref + - unknown_severity + +- name: List /etc/sysctl.d/*.conf files + find: + paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + contains: ^[\s]*net.ipv6.conf.default.accept_ra_rtr_pref.*$ + patterns: '*.conf' + file_type: any + register: find_sysctl_d + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_default_accept_ra_rtr_pref + - unknown_severity + +- name: Comment out any occurrences of net.ipv6.conf.default.accept_ra_rtr_pref from + config files + replace: + path: '{{ item.path }}' + regexp: ^[\s]*net.ipv6.conf.default.accept_ra_rtr_pref + replace: '#net.ipv6.conf.default.accept_ra_rtr_pref' + loop: '{{ find_sysctl_d.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_default_accept_ra_rtr_pref + - unknown_severity +- name: XCCDF Value sysctl_net_ipv6_conf_default_accept_ra_rtr_pref_value # promote to variable + set_fact: + sysctl_net_ipv6_conf_default_accept_ra_rtr_pref_value: !!str + tags: + - always + +- name: Ensure sysctl net.ipv6.conf.default.accept_ra_rtr_pref is set + sysctl: + name: net.ipv6.conf.default.accept_ra_rtr_pref + value: '{{ sysctl_net_ipv6_conf_default_accept_ra_rtr_pref_value }}' + sysctl_file: /etc/sysctl.conf + state: present + reload: true + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_default_accept_ra_rtr_pref + - unknown_severity + + + + + + + + + + + Disable Kernel Parameter for Accepting ICMP Redirects by Default on IPv6 Interfaces + To set the runtime status of the net.ipv6.conf.default.accept_redirects kernel parameter, run the following command: $ sudo sysctl -w net.ipv6.conf.default.accept_redirects=0 +To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv6.conf.default.accept_redirects = 0 + + 11 + 14 + 3 + 9 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS05.02 + DSS05.05 + DSS06.06 + 3.1.20 + CCI-000366 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.2 + 4.3.4.3.3 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 7.6 + A.12.1.2 + A.12.5.1 + A.12.6.2 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.9.1.2 + CM-7(a) + CM-7(b) + CM-6(a) + PR.IP-1 + PR.PT-3 + SRG-OS-000480-GPOS-00227 + R13 + A.8.SEC-OL6 + OL09-00-006045 + SV-271882r1092358_rule + An illicit ICMP redirect message could result in a man-in-the-middle attack. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Comment out any occurrences of net.ipv6.conf.default.accept_redirects from /etc/sysctl.d/*.conf files + +for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do + + + # skip systemd-sysctl symlink (/etc/sysctl.d/99-sysctl.conf -> /etc/sysctl.conf) + if [[ "$(readlink -f "$f")" == "/etc/sysctl.conf" ]]; then continue; fi + + matching_list=$(grep -P '^(?!#).*[\s]*net.ipv6.conf.default.accept_redirects.*$' $f | uniq ) + if ! test -z "$matching_list"; then + while IFS= read -r entry; do + escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") + # comment out "net.ipv6.conf.default.accept_redirects" matches to preserve user data + sed -i --follow-symlinks "s/^${escaped_entry}$/# &/g" $f + done <<< "$matching_list" + fi +done + +# +# Set sysctl config file which to save the desired value +# + +SYSCONFIG_FILE="/etc/sysctl.conf" + +sysctl_net_ipv6_conf_default_accept_redirects_value='' + + +# +# Set runtime for net.ipv6.conf.default.accept_redirects +# +if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then + /sbin/sysctl -q -n -w net.ipv6.conf.default.accept_redirects="$sysctl_net_ipv6_conf_default_accept_redirects_value" +fi + +# +# If net.ipv6.conf.default.accept_redirects present in /etc/sysctl.conf, change value to appropriate value +# else, add "net.ipv6.conf.default.accept_redirects = value" to /etc/sysctl.conf +# + +# Strip any search characters in the key arg so that the key can be replaced without +# adding any search characters to the config file. +stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv6.conf.default.accept_redirects") + +# shellcheck disable=SC2059 +printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv6_conf_default_accept_redirects_value" + +# If the key exists, change it. Otherwise, add it to the config_file. +# We search for the key string followed by a word boundary (matched by \>), +# so if we search for 'setting', 'setting2' won't match. +if LC_ALL=C grep -q -m 1 -i -e "^net.ipv6.conf.default.accept_redirects\\>" "${SYSCONFIG_FILE}"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + LC_ALL=C sed -i --follow-symlinks "s/^net.ipv6.conf.default.accept_redirects\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" +else + if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" + fi + printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-006045 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_default_accept_redirects + +- name: List /etc/sysctl.d/*.conf files + find: + paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + contains: ^[\s]*net.ipv6.conf.default.accept_redirects.*$ + patterns: '*.conf' + file_type: any + register: find_sysctl_d + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006045 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_default_accept_redirects + +- name: Comment out any occurrences of net.ipv6.conf.default.accept_redirects from + config files + replace: + path: '{{ item.path }}' + regexp: ^[\s]*net.ipv6.conf.default.accept_redirects + replace: '#net.ipv6.conf.default.accept_redirects' + loop: '{{ find_sysctl_d.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006045 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_default_accept_redirects +- name: XCCDF Value sysctl_net_ipv6_conf_default_accept_redirects_value # promote to variable + set_fact: + sysctl_net_ipv6_conf_default_accept_redirects_value: !!str + tags: + - always + +- name: Ensure sysctl net.ipv6.conf.default.accept_redirects is set + sysctl: + name: net.ipv6.conf.default.accept_redirects + value: '{{ sysctl_net_ipv6_conf_default_accept_redirects_value }}' + sysctl_file: /etc/sysctl.conf + state: present + reload: true + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006045 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_default_accept_redirects + + + + + + + + + + + Disable Kernel Parameter for Accepting Source-Routed Packets on IPv6 Interfaces by Default + To set the runtime status of the net.ipv6.conf.default.accept_source_route kernel parameter, run the following command: $ sudo sysctl -w net.ipv6.conf.default.accept_source_route=0 +To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv6.conf.default.accept_source_route = 0 + + 1 + 12 + 13 + 14 + 15 + 16 + 18 + 4 + 6 + 8 + 9 + APO01.06 + APO13.01 + DSS01.05 + DSS03.01 + DSS05.02 + DSS05.04 + DSS05.07 + DSS06.02 + 3.1.20 + CCI-000366 + 4.2.3.4 + 4.3.3.4 + 4.4.3.3 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 7.1 + SR 7.6 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.12.1.1 + A.12.1.2 + A.13.1.1 + A.13.1.2 + A.13.1.3 + A.13.2.1 + A.13.2.2 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CM-7(a) + CM-7(b) + CM-6(a) + CM-6(b) + CM-6.1(iv) + DE.AE-1 + ID.AM-3 + PR.AC-5 + PR.DS-5 + PR.PT-4 + Req-1.4.3 + SRG-OS-000480-GPOS-00227 + R13 + A.8.SEC-OL6 + 1.4.2 + 1.4 + OL09-00-006046 + SV-271883r1092361_rule + Source-routed packets allow the source of the packet to suggest routers +forward the packet along a different path than configured on the router, which can +be used to bypass network security measures. This requirement applies only to the +forwarding of source-routerd traffic, such as when IPv6 forwarding is enabled and +the system is functioning as a router. + +Accepting source-routed packets in the IPv6 protocol has few legitimate +uses. It should be disabled unless it is absolutely required. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Comment out any occurrences of net.ipv6.conf.default.accept_source_route from /etc/sysctl.d/*.conf files + +for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do + + + # skip systemd-sysctl symlink (/etc/sysctl.d/99-sysctl.conf -> /etc/sysctl.conf) + if [[ "$(readlink -f "$f")" == "/etc/sysctl.conf" ]]; then continue; fi + + matching_list=$(grep -P '^(?!#).*[\s]*net.ipv6.conf.default.accept_source_route.*$' $f | uniq ) + if ! test -z "$matching_list"; then + while IFS= read -r entry; do + escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") + # comment out "net.ipv6.conf.default.accept_source_route" matches to preserve user data + sed -i --follow-symlinks "s/^${escaped_entry}$/# &/g" $f + done <<< "$matching_list" + fi +done + +# +# Set sysctl config file which to save the desired value +# + +SYSCONFIG_FILE="/etc/sysctl.conf" + +sysctl_net_ipv6_conf_default_accept_source_route_value='' + + +# +# Set runtime for net.ipv6.conf.default.accept_source_route +# +if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then + /sbin/sysctl -q -n -w net.ipv6.conf.default.accept_source_route="$sysctl_net_ipv6_conf_default_accept_source_route_value" +fi + +# +# If net.ipv6.conf.default.accept_source_route present in /etc/sysctl.conf, change value to appropriate value +# else, add "net.ipv6.conf.default.accept_source_route = value" to /etc/sysctl.conf +# + +# Strip any search characters in the key arg so that the key can be replaced without +# adding any search characters to the config file. +stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv6.conf.default.accept_source_route") + +# shellcheck disable=SC2059 +printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv6_conf_default_accept_source_route_value" + +# If the key exists, change it. Otherwise, add it to the config_file. +# We search for the key string followed by a word boundary (matched by \>), +# so if we search for 'setting', 'setting2' won't match. +if LC_ALL=C grep -q -m 1 -i -e "^net.ipv6.conf.default.accept_source_route\\>" "${SYSCONFIG_FILE}"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + LC_ALL=C sed -i --follow-symlinks "s/^net.ipv6.conf.default.accept_source_route\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" +else + if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" + fi + printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-006046 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-6(b) + - NIST-800-53-CM-6.1(iv) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - PCI-DSS-Req-1.4.3 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.2 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_default_accept_source_route + +- name: List /etc/sysctl.d/*.conf files + find: + paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + contains: ^[\s]*net.ipv6.conf.default.accept_source_route.*$ + patterns: '*.conf' + file_type: any + register: find_sysctl_d + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006046 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-6(b) + - NIST-800-53-CM-6.1(iv) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - PCI-DSS-Req-1.4.3 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.2 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_default_accept_source_route + +- name: Comment out any occurrences of net.ipv6.conf.default.accept_source_route from + config files + replace: + path: '{{ item.path }}' + regexp: ^[\s]*net.ipv6.conf.default.accept_source_route + replace: '#net.ipv6.conf.default.accept_source_route' + loop: '{{ find_sysctl_d.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006046 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-6(b) + - NIST-800-53-CM-6.1(iv) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - PCI-DSS-Req-1.4.3 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.2 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_default_accept_source_route +- name: XCCDF Value sysctl_net_ipv6_conf_default_accept_source_route_value # promote to variable + set_fact: + sysctl_net_ipv6_conf_default_accept_source_route_value: !!str + tags: + - always + +- name: Ensure sysctl net.ipv6.conf.default.accept_source_route is set + sysctl: + name: net.ipv6.conf.default.accept_source_route + value: '{{ sysctl_net_ipv6_conf_default_accept_source_route_value }}' + sysctl_file: /etc/sysctl.conf + state: present + reload: true + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006046 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-6(b) + - NIST-800-53-CM-6.1(iv) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - PCI-DSS-Req-1.4.3 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.2 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_default_accept_source_route + + + + + + + + + + + Configure Auto Configuration on All IPv6 Interfaces By Default + To set the runtime status of the net.ipv6.conf.default.autoconf kernel parameter, run the following command: $ sudo sysctl -w net.ipv6.conf.default.autoconf=0 +To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv6.conf.default.autoconf = 0 + + R13 + An illicit router advertisement message could result in a man-in-the-middle attack. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Comment out any occurrences of net.ipv6.conf.default.autoconf from /etc/sysctl.d/*.conf files + +for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do + + + # skip systemd-sysctl symlink (/etc/sysctl.d/99-sysctl.conf -> /etc/sysctl.conf) + if [[ "$(readlink -f "$f")" == "/etc/sysctl.conf" ]]; then continue; fi + + matching_list=$(grep -P '^(?!#).*[\s]*net.ipv6.conf.default.autoconf.*$' $f | uniq ) + if ! test -z "$matching_list"; then + while IFS= read -r entry; do + escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") + # comment out "net.ipv6.conf.default.autoconf" matches to preserve user data + sed -i --follow-symlinks "s/^${escaped_entry}$/# &/g" $f + done <<< "$matching_list" + fi +done + +# +# Set sysctl config file which to save the desired value +# + +SYSCONFIG_FILE="/etc/sysctl.conf" + +sysctl_net_ipv6_conf_default_autoconf_value='' + + +# +# Set runtime for net.ipv6.conf.default.autoconf +# +if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then + /sbin/sysctl -q -n -w net.ipv6.conf.default.autoconf="$sysctl_net_ipv6_conf_default_autoconf_value" +fi + +# +# If net.ipv6.conf.default.autoconf present in /etc/sysctl.conf, change value to appropriate value +# else, add "net.ipv6.conf.default.autoconf = value" to /etc/sysctl.conf +# + +# Strip any search characters in the key arg so that the key can be replaced without +# adding any search characters to the config file. +stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv6.conf.default.autoconf") + +# shellcheck disable=SC2059 +printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv6_conf_default_autoconf_value" + +# If the key exists, change it. Otherwise, add it to the config_file. +# We search for the key string followed by a word boundary (matched by \>), +# so if we search for 'setting', 'setting2' won't match. +if LC_ALL=C grep -q -m 1 -i -e "^net.ipv6.conf.default.autoconf\\>" "${SYSCONFIG_FILE}"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + LC_ALL=C sed -i --follow-symlinks "s/^net.ipv6.conf.default.autoconf\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" +else + if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" + fi + printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_default_autoconf + - unknown_severity + +- name: List /etc/sysctl.d/*.conf files + find: + paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + contains: ^[\s]*net.ipv6.conf.default.autoconf.*$ + patterns: '*.conf' + file_type: any + register: find_sysctl_d + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_default_autoconf + - unknown_severity + +- name: Comment out any occurrences of net.ipv6.conf.default.autoconf from config + files + replace: + path: '{{ item.path }}' + regexp: ^[\s]*net.ipv6.conf.default.autoconf + replace: '#net.ipv6.conf.default.autoconf' + loop: '{{ find_sysctl_d.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_default_autoconf + - unknown_severity +- name: XCCDF Value sysctl_net_ipv6_conf_default_autoconf_value # promote to variable + set_fact: + sysctl_net_ipv6_conf_default_autoconf_value: !!str + tags: + - always + +- name: Ensure sysctl net.ipv6.conf.default.autoconf is set + sysctl: + name: net.ipv6.conf.default.autoconf + value: '{{ sysctl_net_ipv6_conf_default_autoconf_value }}' + sysctl_file: /etc/sysctl.conf + state: present + reload: true + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_default_autoconf + - unknown_severity + + + + + + + + + + + Configure Maximum Number of Autoconfigured Addresses on All IPv6 Interfaces By Default + To set the runtime status of the net.ipv6.conf.default.max_addresses kernel parameter, run the following command: $ sudo sysctl -w net.ipv6.conf.default.max_addresses=1 +To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv6.conf.default.max_addresses = 1 + + R13 + The number of global unicast IPv6 addresses for each interface should be limited exactly to the number of statically configured addresses. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Comment out any occurrences of net.ipv6.conf.default.max_addresses from /etc/sysctl.d/*.conf files + +for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do + + + # skip systemd-sysctl symlink (/etc/sysctl.d/99-sysctl.conf -> /etc/sysctl.conf) + if [[ "$(readlink -f "$f")" == "/etc/sysctl.conf" ]]; then continue; fi + + matching_list=$(grep -P '^(?!#).*[\s]*net.ipv6.conf.default.max_addresses.*$' $f | uniq ) + if ! test -z "$matching_list"; then + while IFS= read -r entry; do + escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") + # comment out "net.ipv6.conf.default.max_addresses" matches to preserve user data + sed -i --follow-symlinks "s/^${escaped_entry}$/# &/g" $f + done <<< "$matching_list" + fi +done + +# +# Set sysctl config file which to save the desired value +# + +SYSCONFIG_FILE="/etc/sysctl.conf" + +sysctl_net_ipv6_conf_default_max_addresses_value='' + + +# +# Set runtime for net.ipv6.conf.default.max_addresses +# +if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then + /sbin/sysctl -q -n -w net.ipv6.conf.default.max_addresses="$sysctl_net_ipv6_conf_default_max_addresses_value" +fi + +# +# If net.ipv6.conf.default.max_addresses present in /etc/sysctl.conf, change value to appropriate value +# else, add "net.ipv6.conf.default.max_addresses = value" to /etc/sysctl.conf +# + +# Strip any search characters in the key arg so that the key can be replaced without +# adding any search characters to the config file. +stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv6.conf.default.max_addresses") + +# shellcheck disable=SC2059 +printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv6_conf_default_max_addresses_value" + +# If the key exists, change it. Otherwise, add it to the config_file. +# We search for the key string followed by a word boundary (matched by \>), +# so if we search for 'setting', 'setting2' won't match. +if LC_ALL=C grep -q -m 1 -i -e "^net.ipv6.conf.default.max_addresses\\>" "${SYSCONFIG_FILE}"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + LC_ALL=C sed -i --follow-symlinks "s/^net.ipv6.conf.default.max_addresses\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" +else + if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" + fi + printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_default_max_addresses + - unknown_severity + +- name: List /etc/sysctl.d/*.conf files + find: + paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + contains: ^[\s]*net.ipv6.conf.default.max_addresses.*$ + patterns: '*.conf' + file_type: any + register: find_sysctl_d + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_default_max_addresses + - unknown_severity + +- name: Comment out any occurrences of net.ipv6.conf.default.max_addresses from config + files + replace: + path: '{{ item.path }}' + regexp: ^[\s]*net.ipv6.conf.default.max_addresses + replace: '#net.ipv6.conf.default.max_addresses' + loop: '{{ find_sysctl_d.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_default_max_addresses + - unknown_severity +- name: XCCDF Value sysctl_net_ipv6_conf_default_max_addresses_value # promote to variable + set_fact: + sysctl_net_ipv6_conf_default_max_addresses_value: !!str + tags: + - always + +- name: Ensure sysctl net.ipv6.conf.default.max_addresses is set + sysctl: + name: net.ipv6.conf.default.max_addresses + value: '{{ sysctl_net_ipv6_conf_default_max_addresses_value }}' + sysctl_file: /etc/sysctl.conf + state: present + reload: true + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_default_max_addresses + - unknown_severity + + + + + + + + + + + Configure Denying Router Solicitations on All IPv6 Interfaces By Default + To set the runtime status of the net.ipv6.conf.default.router_solicitations kernel parameter, run the following command: $ sudo sysctl -w net.ipv6.conf.default.router_solicitations=0 +To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv6.conf.default.router_solicitations = 0 + + R13 + To prevent discovery of the system by other systems, router solicitation requests should be denied. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Comment out any occurrences of net.ipv6.conf.default.router_solicitations from /etc/sysctl.d/*.conf files + +for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do + + + # skip systemd-sysctl symlink (/etc/sysctl.d/99-sysctl.conf -> /etc/sysctl.conf) + if [[ "$(readlink -f "$f")" == "/etc/sysctl.conf" ]]; then continue; fi + + matching_list=$(grep -P '^(?!#).*[\s]*net.ipv6.conf.default.router_solicitations.*$' $f | uniq ) + if ! test -z "$matching_list"; then + while IFS= read -r entry; do + escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") + # comment out "net.ipv6.conf.default.router_solicitations" matches to preserve user data + sed -i --follow-symlinks "s/^${escaped_entry}$/# &/g" $f + done <<< "$matching_list" + fi +done + +# +# Set sysctl config file which to save the desired value +# + +SYSCONFIG_FILE="/etc/sysctl.conf" + +sysctl_net_ipv6_conf_default_router_solicitations_value='' + + +# +# Set runtime for net.ipv6.conf.default.router_solicitations +# +if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then + /sbin/sysctl -q -n -w net.ipv6.conf.default.router_solicitations="$sysctl_net_ipv6_conf_default_router_solicitations_value" +fi + +# +# If net.ipv6.conf.default.router_solicitations present in /etc/sysctl.conf, change value to appropriate value +# else, add "net.ipv6.conf.default.router_solicitations = value" to /etc/sysctl.conf +# + +# Strip any search characters in the key arg so that the key can be replaced without +# adding any search characters to the config file. +stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv6.conf.default.router_solicitations") + +# shellcheck disable=SC2059 +printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv6_conf_default_router_solicitations_value" + +# If the key exists, change it. Otherwise, add it to the config_file. +# We search for the key string followed by a word boundary (matched by \>), +# so if we search for 'setting', 'setting2' won't match. +if LC_ALL=C grep -q -m 1 -i -e "^net.ipv6.conf.default.router_solicitations\\>" "${SYSCONFIG_FILE}"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + LC_ALL=C sed -i --follow-symlinks "s/^net.ipv6.conf.default.router_solicitations\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" +else + if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" + fi + printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_default_router_solicitations + - unknown_severity + +- name: List /etc/sysctl.d/*.conf files + find: + paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + contains: ^[\s]*net.ipv6.conf.default.router_solicitations.*$ + patterns: '*.conf' + file_type: any + register: find_sysctl_d + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_default_router_solicitations + - unknown_severity + +- name: Comment out any occurrences of net.ipv6.conf.default.router_solicitations + from config files + replace: + path: '{{ item.path }}' + regexp: ^[\s]*net.ipv6.conf.default.router_solicitations + replace: '#net.ipv6.conf.default.router_solicitations' + loop: '{{ find_sysctl_d.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_default_router_solicitations + - unknown_severity +- name: XCCDF Value sysctl_net_ipv6_conf_default_router_solicitations_value # promote to variable + set_fact: + sysctl_net_ipv6_conf_default_router_solicitations_value: !!str + tags: + - always + +- name: Ensure sysctl net.ipv6.conf.default.router_solicitations is set + sysctl: + name: net.ipv6.conf.default.router_solicitations + value: '{{ sysctl_net_ipv6_conf_default_router_solicitations_value }}' + sysctl_file: /etc/sysctl.conf + state: present + reload: true + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_default_router_solicitations + - unknown_severity + + + + + + + + + + + + + Kernel Parameters Which Affect Networking + The sysctl utility is used to set +parameters which affect the operation of the Linux kernel. Kernel parameters +which affect networking and have security implications are described here. + + Network Related Kernel Runtime Parameters for Hosts and Routers + Certain kernel parameters should be set for systems which are +acting as either hosts or routers to improve the system's ability defend +against certain types of IPv4 protocol attacks. + + + net.ipv4.conf.all.accept_redirects + Disable ICMP Redirect Acceptance + 0 + 0 + 1 + + + net.ipv4.conf.all.accept_source_route + Trackers could be using source-routed packets to +generate traffic that seems to be intra-net, but actually was +created outside and has been redirected. + 0 + 0 + 1 + + + net.ipv4.conf.default.arp_filter + Controls whether the ARP filter is enabled or not. + +1 - Allows you to have multiple network interfaces on the same subnet, and have the ARPs for each +interface be answered based on whether or not the kernel would route a packet from the ARP’d IP out that interface. +In other words it allows control of which cards (usually 1) will respond to an ARP request. + +0 - (default) The kernel can respond to arp requests with addresses from other interfaces. +This may seem wrong but it usually makes sense, because it increases the chance of successful communication. +IP addresses are owned by the complete host on Linux, not by particular interfaces. + 0 + 0 + 1 + + + net.ipv4.conf.default.arp_ignore + Control the response modes for ARP queries that resolve local target IP addresses: + +0 - (default): reply for any local target IP address, configured on any interface +1 - reply only if the target IP address is local address configured on the incoming interface +2 - reply only if the target IP address is local address configured on the incoming interface and both with the sender’s IP address are part from same subnet on this interface +3 - do not reply for local addresses configured with scope host, only resolutions for global and link addresses are replied +4-7 - reserved +8 - do not reply for all local addresses + 0 + 0 + 1 + 2 + 3 + 8 + + + net.ipv4.conf.all.forwarding + Toggle IPv4 Forwarding + 0 + 0 + 1 + + + net.ipv4.conf.all.log_martians + Disable so you don't Log Spoofed Packets, Source +Routed Packets, Redirect Packets + 1 + 0 + 1 + + + net.ipv4.conf.all.rp_filter + Enable to enforce sanity checking, also called ingress +filtering or egress filtering. The point is to drop a packet if the +source and destination IP addresses in the IP header do not make +sense when considered in light of the physical interface on which +it arrived. + 1 + 1 + 2 + + + net.ipv4.conf.all.secure_redirects + Enable to prevent hijacking of routing path by only +allowing redirects from gateways known in routing +table. Disable to refuse acceptance of secure ICMP redirected packets on all interfaces. + 0 + 0 + 1 + + + net.ipv4.conf.all.shared_media + Controls whether the system can send (router) or accept (host) RFC1620 shared media redirects. +shared_media for the interface will be enabled if at least one of conf/{all,interface}/shared_media +is set to TRUE, it will be disabled otherwise. + 0 + 0 + 1 + + + net.ipv4.conf.default.accept_redirects + Disable ICMP Redirect Acceptance? + 0 + 0 + 1 + + + net.ipv4.conf.default.accept_source_route + Disable IP source routing? + 0 + 0 + 1 + + + net.ipv4.conf.default.log_martians + Disable so you don't Log Spoofed Packets, Source +Routed Packets, Redirect Packets + 1 + 0 + 1 + + + net.ipv4.conf.default.rp_filter + Enables source route verification + 1 + 0 + 1 + + + net.ipv4.conf.default.secure_redirects + Enable to prevent hijacking of routing path by only +allowing redirects from gateways known in routing +table. Disable to refuse acceptance of secure ICMP redirected packages by default. + 0 + 0 + 1 + + + net.ipv4.conf.default.shared_media + Controls whether the system can send(router) or accept(host) RFC1620 shared media redirects. +shared_media for the interface will be enabled if at least one of conf/{all,interface}/shared_media +is set to TRUE, it will be disabled otherwise. + 0 + 0 + 1 + + + net.ipv4.icmp_echo_ignore_broadcasts + Ignore all ICMP ECHO and TIMESTAMP requests sent to it +via broadcast/multicast + 1 + 0 + 1 + + + net.ipv4.icmp_ignore_bogus_error_responses + Enable to prevent unnecessary logging + 1 + 0 + 1 + + + net.ipv4.tcp_rfc1337 + Enable to enable TCP behavior conformant with RFC 1337 + 1 + 0 + 1 + + + net.ipv4.tcp_syncookies + Enable to turn on TCP SYN Cookie +Protection + 1 + 0 + 1 + + + Disable Accepting Packets Routed Between Local Interfaces + To set the runtime status of the net.ipv4.conf.all.accept_local kernel parameter, run the following command: $ sudo sysctl -w net.ipv4.conf.all.accept_local=0 +To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv4.conf.all.accept_local = 0 + + R12 + Configure net.ipv4.conf.all.accept_local=0 to consider as invalid the packets +received from outside whose source is the 127.0.0.0/8 address block. +In combination with suitable routing, this can be used to direct packets between two +local interfaces over the wire and have them accepted properly. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Comment out any occurrences of net.ipv4.conf.all.accept_local from /etc/sysctl.d/*.conf files + +for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do + + + # skip systemd-sysctl symlink (/etc/sysctl.d/99-sysctl.conf -> /etc/sysctl.conf) + if [[ "$(readlink -f "$f")" == "/etc/sysctl.conf" ]]; then continue; fi + + matching_list=$(grep -P '^(?!#).*[\s]*net.ipv4.conf.all.accept_local.*$' $f | uniq ) + if ! test -z "$matching_list"; then + while IFS= read -r entry; do + escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") + # comment out "net.ipv4.conf.all.accept_local" matches to preserve user data + sed -i --follow-symlinks "s/^${escaped_entry}$/# &/g" $f + done <<< "$matching_list" + fi +done + +# +# Set sysctl config file which to save the desired value +# + +SYSCONFIG_FILE="/etc/sysctl.conf" + + +# +# Set runtime for net.ipv4.conf.all.accept_local +# +if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then + /sbin/sysctl -q -n -w net.ipv4.conf.all.accept_local="0" +fi + +# +# If net.ipv4.conf.all.accept_local present in /etc/sysctl.conf, change value to "0" +# else, add "net.ipv4.conf.all.accept_local = 0" to /etc/sysctl.conf +# + +# Strip any search characters in the key arg so that the key can be replaced without +# adding any search characters to the config file. +stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv4.conf.all.accept_local") + +# shellcheck disable=SC2059 +printf -v formatted_output "%s = %s" "$stripped_key" "0" + +# If the key exists, change it. Otherwise, add it to the config_file. +# We search for the key string followed by a word boundary (matched by \>), +# so if we search for 'setting', 'setting2' won't match. +if LC_ALL=C grep -q -m 1 -i -e "^net.ipv4.conf.all.accept_local\\>" "${SYSCONFIG_FILE}"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + LC_ALL=C sed -i --follow-symlinks "s/^net.ipv4.conf.all.accept_local\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" +else + if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" + fi + printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_accept_local + +- name: List /etc/sysctl.d/*.conf files + find: + paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + contains: ^[\s]*net.ipv4.conf.all.accept_local.*$ + patterns: '*.conf' + file_type: any + register: find_sysctl_d + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_accept_local + +- name: Comment out any occurrences of net.ipv4.conf.all.accept_local from config + files + replace: + path: '{{ item.path }}' + regexp: ^[\s]*net.ipv4.conf.all.accept_local + replace: '#net.ipv4.conf.all.accept_local' + loop: '{{ find_sysctl_d.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_accept_local + +- name: Ensure sysctl net.ipv4.conf.all.accept_local is set to 0 + sysctl: + name: net.ipv4.conf.all.accept_local + value: '0' + sysctl_file: /etc/sysctl.conf + state: present + reload: true + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_accept_local + + + + + + + + + + Disable Accepting ICMP Redirects for All IPv4 Interfaces + To set the runtime status of the net.ipv4.conf.all.accept_redirects kernel parameter, run the following command: $ sudo sysctl -w net.ipv4.conf.all.accept_redirects=0 +To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv4.conf.all.accept_redirects = 0 + + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 2 + 3 + 7 + 8 + 9 + 5.10.1.1 + APO13.01 + BAI04.04 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS01.03 + DSS03.05 + DSS05.02 + DSS05.05 + DSS05.07 + DSS06.06 + 3.1.20 + CCI-000366 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.2 + 4.3.4.3.3 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 6.2 + SR 7.1 + SR 7.2 + SR 7.6 + A.12.1.2 + A.12.1.3 + A.12.5.1 + A.12.6.2 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.17.2.1 + A.9.1.2 + CM-7(a) + CM-7(b) + CM-6(a) + SC-7(a) + DE.CM-1 + PR.DS-4 + PR.IP-1 + PR.PT-3 + SRG-OS-000480-GPOS-00227 + R12 + A.8.SEC-OL6 + OL09-00-006020 + SV-271864r1092304_rule + ICMP redirect messages are used by routers to inform hosts that a more +direct route exists for a particular destination. These messages modify the +host's route table and are unauthenticated. An illicit ICMP redirect +message could result in a man-in-the-middle attack. + +This feature of the IPv4 protocol has few legitimate uses. It should be +disabled unless absolutely required." + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Comment out any occurrences of net.ipv4.conf.all.accept_redirects from /etc/sysctl.d/*.conf files + +for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do + + + # skip systemd-sysctl symlink (/etc/sysctl.d/99-sysctl.conf -> /etc/sysctl.conf) + if [[ "$(readlink -f "$f")" == "/etc/sysctl.conf" ]]; then continue; fi + + matching_list=$(grep -P '^(?!#).*[\s]*net.ipv4.conf.all.accept_redirects.*$' $f | uniq ) + if ! test -z "$matching_list"; then + while IFS= read -r entry; do + escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") + # comment out "net.ipv4.conf.all.accept_redirects" matches to preserve user data + sed -i --follow-symlinks "s/^${escaped_entry}$/# &/g" $f + done <<< "$matching_list" + fi +done + +# +# Set sysctl config file which to save the desired value +# + +SYSCONFIG_FILE="/etc/sysctl.conf" + +sysctl_net_ipv4_conf_all_accept_redirects_value='' + + +# +# Set runtime for net.ipv4.conf.all.accept_redirects +# +if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then + /sbin/sysctl -q -n -w net.ipv4.conf.all.accept_redirects="$sysctl_net_ipv4_conf_all_accept_redirects_value" +fi + +# +# If net.ipv4.conf.all.accept_redirects present in /etc/sysctl.conf, change value to appropriate value +# else, add "net.ipv4.conf.all.accept_redirects = value" to /etc/sysctl.conf +# + +# Strip any search characters in the key arg so that the key can be replaced without +# adding any search characters to the config file. +stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv4.conf.all.accept_redirects") + +# shellcheck disable=SC2059 +printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv4_conf_all_accept_redirects_value" + +# If the key exists, change it. Otherwise, add it to the config_file. +# We search for the key string followed by a word boundary (matched by \>), +# so if we search for 'setting', 'setting2' won't match. +if LC_ALL=C grep -q -m 1 -i -e "^net.ipv4.conf.all.accept_redirects\\>" "${SYSCONFIG_FILE}"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + LC_ALL=C sed -i --follow-symlinks "s/^net.ipv4.conf.all.accept_redirects\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" +else + if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" + fi + printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - CJIS-5.10.1.1 + - DISA-STIG-OL09-00-006020 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-7(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_accept_redirects + +- name: List /etc/sysctl.d/*.conf files + find: + paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + contains: ^[\s]*net.ipv4.conf.all.accept_redirects.*$ + patterns: '*.conf' + file_type: any + register: find_sysctl_d + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.10.1.1 + - DISA-STIG-OL09-00-006020 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-7(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_accept_redirects + +- name: Comment out any occurrences of net.ipv4.conf.all.accept_redirects from config + files + replace: + path: '{{ item.path }}' + regexp: ^[\s]*net.ipv4.conf.all.accept_redirects + replace: '#net.ipv4.conf.all.accept_redirects' + loop: '{{ find_sysctl_d.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.10.1.1 + - DISA-STIG-OL09-00-006020 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-7(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_accept_redirects +- name: XCCDF Value sysctl_net_ipv4_conf_all_accept_redirects_value # promote to variable + set_fact: + sysctl_net_ipv4_conf_all_accept_redirects_value: !!str + tags: + - always + +- name: Ensure sysctl net.ipv4.conf.all.accept_redirects is set + sysctl: + name: net.ipv4.conf.all.accept_redirects + value: '{{ sysctl_net_ipv4_conf_all_accept_redirects_value }}' + sysctl_file: /etc/sysctl.conf + state: present + reload: true + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.10.1.1 + - DISA-STIG-OL09-00-006020 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-7(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_accept_redirects + + + + + + + + + + + Disable Kernel Parameter for Accepting Source-Routed Packets on all IPv4 Interfaces + To set the runtime status of the net.ipv4.conf.all.accept_source_route kernel parameter, run the following command: $ sudo sysctl -w net.ipv4.conf.all.accept_source_route=0 +To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv4.conf.all.accept_source_route = 0 + + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 18 + 2 + 3 + 4 + 6 + 7 + 8 + 9 + APO01.06 + APO13.01 + BAI04.04 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS01.03 + DSS01.05 + DSS03.01 + DSS03.05 + DSS05.02 + DSS05.04 + DSS05.05 + DSS05.07 + DSS06.02 + DSS06.06 + 3.1.20 + CCI-000366 + 4.2.3.4 + 4.3.3.4 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.2 + 4.3.4.3.3 + 4.4.3.3 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 6.2 + SR 7.1 + SR 7.2 + SR 7.6 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.12.1.1 + A.12.1.2 + A.12.1.3 + A.12.5.1 + A.12.6.2 + A.13.1.1 + A.13.1.2 + A.13.1.3 + A.13.2.1 + A.13.2.2 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.17.2.1 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CIP-007-3 R4 + CIP-007-3 R4.1 + CIP-007-3 R4.2 + CIP-007-3 R5.1 + CM-7(a) + CM-7(b) + SC-5 + CM-6(a) + SC-7(a) + DE.AE-1 + DE.CM-1 + ID.AM-3 + PR.AC-5 + PR.DS-4 + PR.DS-5 + PR.IP-1 + PR.PT-3 + PR.PT-4 + SRG-OS-000480-GPOS-00227 + R12 + A.8.SEC-OL6 + OL09-00-006021 + SV-271865r1092307_rule + Source-routed packets allow the source of the packet to suggest routers +forward the packet along a different path than configured on the router, +which can be used to bypass network security measures. This requirement +applies only to the forwarding of source-routerd traffic, such as when IPv4 +forwarding is enabled and the system is functioning as a router. + + +Accepting source-routed packets in the IPv4 protocol has few legitimate +uses. It should be disabled unless it is absolutely required. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Comment out any occurrences of net.ipv4.conf.all.accept_source_route from /etc/sysctl.d/*.conf files + +for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do + + + # skip systemd-sysctl symlink (/etc/sysctl.d/99-sysctl.conf -> /etc/sysctl.conf) + if [[ "$(readlink -f "$f")" == "/etc/sysctl.conf" ]]; then continue; fi + + matching_list=$(grep -P '^(?!#).*[\s]*net.ipv4.conf.all.accept_source_route.*$' $f | uniq ) + if ! test -z "$matching_list"; then + while IFS= read -r entry; do + escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") + # comment out "net.ipv4.conf.all.accept_source_route" matches to preserve user data + sed -i --follow-symlinks "s/^${escaped_entry}$/# &/g" $f + done <<< "$matching_list" + fi +done + +# +# Set sysctl config file which to save the desired value +# + +SYSCONFIG_FILE="/etc/sysctl.conf" + +sysctl_net_ipv4_conf_all_accept_source_route_value='' + + +# +# Set runtime for net.ipv4.conf.all.accept_source_route +# +if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then + /sbin/sysctl -q -n -w net.ipv4.conf.all.accept_source_route="$sysctl_net_ipv4_conf_all_accept_source_route_value" +fi + +# +# If net.ipv4.conf.all.accept_source_route present in /etc/sysctl.conf, change value to appropriate value +# else, add "net.ipv4.conf.all.accept_source_route = value" to /etc/sysctl.conf +# + +# Strip any search characters in the key arg so that the key can be replaced without +# adding any search characters to the config file. +stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv4.conf.all.accept_source_route") + +# shellcheck disable=SC2059 +printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv4_conf_all_accept_source_route_value" + +# If the key exists, change it. Otherwise, add it to the config_file. +# We search for the key string followed by a word boundary (matched by \>), +# so if we search for 'setting', 'setting2' won't match. +if LC_ALL=C grep -q -m 1 -i -e "^net.ipv4.conf.all.accept_source_route\\>" "${SYSCONFIG_FILE}"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + LC_ALL=C sed -i --follow-symlinks "s/^net.ipv4.conf.all.accept_source_route\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" +else + if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" + fi + printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-006021 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - NIST-800-53-SC-7(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_accept_source_route + +- name: List /etc/sysctl.d/*.conf files + find: + paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + contains: ^[\s]*net.ipv4.conf.all.accept_source_route.*$ + patterns: '*.conf' + file_type: any + register: find_sysctl_d + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006021 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - NIST-800-53-SC-7(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_accept_source_route + +- name: Comment out any occurrences of net.ipv4.conf.all.accept_source_route from + config files + replace: + path: '{{ item.path }}' + regexp: ^[\s]*net.ipv4.conf.all.accept_source_route + replace: '#net.ipv4.conf.all.accept_source_route' + loop: '{{ find_sysctl_d.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006021 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - NIST-800-53-SC-7(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_accept_source_route +- name: XCCDF Value sysctl_net_ipv4_conf_all_accept_source_route_value # promote to variable + set_fact: + sysctl_net_ipv4_conf_all_accept_source_route_value: !!str + tags: + - always + +- name: Ensure sysctl net.ipv4.conf.all.accept_source_route is set + sysctl: + name: net.ipv4.conf.all.accept_source_route + value: '{{ sysctl_net_ipv4_conf_all_accept_source_route_value }}' + sysctl_file: /etc/sysctl.conf + state: present + reload: true + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006021 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - NIST-800-53-SC-7(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_accept_source_route + + + + + + + + + + + Configure ARP filtering for All IPv4 Interfaces + To set the runtime status of the net.ipv4.conf.all.arp_filter kernel parameter, run the following command: $ sudo sysctl -w net.ipv4.conf.all.arp_filter= + +To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv4.conf.all.arp_filter = + + + This behaviour may cause problems to system on a high availability or load balancing configuration. + R12 + Prevents the Linux Kernel from handling the ARP table globally. +By default, the kernel may respond to an ARP request from a certain interface with information +from another interface. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Comment out any occurrences of net.ipv4.conf.all.arp_filter from /etc/sysctl.d/*.conf files + +for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do + + + # skip systemd-sysctl symlink (/etc/sysctl.d/99-sysctl.conf -> /etc/sysctl.conf) + if [[ "$(readlink -f "$f")" == "/etc/sysctl.conf" ]]; then continue; fi + + matching_list=$(grep -P '^(?!#).*[\s]*net.ipv4.conf.all.arp_filter.*$' $f | uniq ) + if ! test -z "$matching_list"; then + while IFS= read -r entry; do + escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") + # comment out "net.ipv4.conf.all.arp_filter" matches to preserve user data + sed -i --follow-symlinks "s/^${escaped_entry}$/# &/g" $f + done <<< "$matching_list" + fi +done + +# +# Set sysctl config file which to save the desired value +# + +SYSCONFIG_FILE="/etc/sysctl.conf" + +sysctl_net_ipv4_conf_all_arp_filter_value='' + + +# +# Set runtime for net.ipv4.conf.all.arp_filter +# +if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then + /sbin/sysctl -q -n -w net.ipv4.conf.all.arp_filter="$sysctl_net_ipv4_conf_all_arp_filter_value" +fi + +# +# If net.ipv4.conf.all.arp_filter present in /etc/sysctl.conf, change value to appropriate value +# else, add "net.ipv4.conf.all.arp_filter = value" to /etc/sysctl.conf +# + +# Strip any search characters in the key arg so that the key can be replaced without +# adding any search characters to the config file. +stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv4.conf.all.arp_filter") + +# shellcheck disable=SC2059 +printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv4_conf_all_arp_filter_value" + +# If the key exists, change it. Otherwise, add it to the config_file. +# We search for the key string followed by a word boundary (matched by \>), +# so if we search for 'setting', 'setting2' won't match. +if LC_ALL=C grep -q -m 1 -i -e "^net.ipv4.conf.all.arp_filter\\>" "${SYSCONFIG_FILE}"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + LC_ALL=C sed -i --follow-symlinks "s/^net.ipv4.conf.all.arp_filter\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" +else + if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" + fi + printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_arp_filter + +- name: List /etc/sysctl.d/*.conf files + find: + paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + contains: ^[\s]*net.ipv4.conf.all.arp_filter.*$ + patterns: '*.conf' + file_type: any + register: find_sysctl_d + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_arp_filter + +- name: Comment out any occurrences of net.ipv4.conf.all.arp_filter from config files + replace: + path: '{{ item.path }}' + regexp: ^[\s]*net.ipv4.conf.all.arp_filter + replace: '#net.ipv4.conf.all.arp_filter' + loop: '{{ find_sysctl_d.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_arp_filter +- name: XCCDF Value sysctl_net_ipv4_conf_all_arp_filter_value # promote to variable + set_fact: + sysctl_net_ipv4_conf_all_arp_filter_value: !!str + tags: + - always + +- name: Ensure sysctl net.ipv4.conf.all.arp_filter is set + sysctl: + name: net.ipv4.conf.all.arp_filter + value: '{{ sysctl_net_ipv4_conf_all_arp_filter_value }}' + sysctl_file: /etc/sysctl.conf + state: present + reload: true + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_arp_filter + + + + + + + + + + + Configure Response Mode of ARP Requests for All IPv4 Interfaces + To set the runtime status of the net.ipv4.conf.all.arp_ignore kernel parameter, run the following command: $ sudo sysctl -w net.ipv4.conf.all.arp_ignore= + +To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv4.conf.all.arp_ignore = + + + The ARP response mode may impact behaviour of workloads and firewalls on the system. + R12 + Avoids ARP Flux on system that have more than one interface on the same subnet. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Comment out any occurrences of net.ipv4.conf.all.arp_ignore from /etc/sysctl.d/*.conf files + +for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do + + + # skip systemd-sysctl symlink (/etc/sysctl.d/99-sysctl.conf -> /etc/sysctl.conf) + if [[ "$(readlink -f "$f")" == "/etc/sysctl.conf" ]]; then continue; fi + + matching_list=$(grep -P '^(?!#).*[\s]*net.ipv4.conf.all.arp_ignore.*$' $f | uniq ) + if ! test -z "$matching_list"; then + while IFS= read -r entry; do + escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") + # comment out "net.ipv4.conf.all.arp_ignore" matches to preserve user data + sed -i --follow-symlinks "s/^${escaped_entry}$/# &/g" $f + done <<< "$matching_list" + fi +done + +# +# Set sysctl config file which to save the desired value +# + +SYSCONFIG_FILE="/etc/sysctl.conf" + +sysctl_net_ipv4_conf_all_arp_ignore_value='' + + +# +# Set runtime for net.ipv4.conf.all.arp_ignore +# +if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then + /sbin/sysctl -q -n -w net.ipv4.conf.all.arp_ignore="$sysctl_net_ipv4_conf_all_arp_ignore_value" +fi + +# +# If net.ipv4.conf.all.arp_ignore present in /etc/sysctl.conf, change value to appropriate value +# else, add "net.ipv4.conf.all.arp_ignore = value" to /etc/sysctl.conf +# + +# Strip any search characters in the key arg so that the key can be replaced without +# adding any search characters to the config file. +stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv4.conf.all.arp_ignore") + +# shellcheck disable=SC2059 +printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv4_conf_all_arp_ignore_value" + +# If the key exists, change it. Otherwise, add it to the config_file. +# We search for the key string followed by a word boundary (matched by \>), +# so if we search for 'setting', 'setting2' won't match. +if LC_ALL=C grep -q -m 1 -i -e "^net.ipv4.conf.all.arp_ignore\\>" "${SYSCONFIG_FILE}"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + LC_ALL=C sed -i --follow-symlinks "s/^net.ipv4.conf.all.arp_ignore\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" +else + if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" + fi + printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_arp_ignore + +- name: List /etc/sysctl.d/*.conf files + find: + paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + contains: ^[\s]*net.ipv4.conf.all.arp_ignore.*$ + patterns: '*.conf' + file_type: any + register: find_sysctl_d + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_arp_ignore + +- name: Comment out any occurrences of net.ipv4.conf.all.arp_ignore from config files + replace: + path: '{{ item.path }}' + regexp: ^[\s]*net.ipv4.conf.all.arp_ignore + replace: '#net.ipv4.conf.all.arp_ignore' + loop: '{{ find_sysctl_d.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_arp_ignore +- name: XCCDF Value sysctl_net_ipv4_conf_all_arp_ignore_value # promote to variable + set_fact: + sysctl_net_ipv4_conf_all_arp_ignore_value: !!str + tags: + - always + +- name: Ensure sysctl net.ipv4.conf.all.arp_ignore is set + sysctl: + name: net.ipv4.conf.all.arp_ignore + value: '{{ sysctl_net_ipv4_conf_all_arp_ignore_value }}' + sysctl_file: /etc/sysctl.conf + state: present + reload: true + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_arp_ignore + + + + + + + + + + + Drop Gratuitious ARP frames on All IPv4 Interfaces + To set the runtime status of the net.ipv4.conf.all.drop_gratuitous_arp kernel parameter, run the following command: $ sudo sysctl -w net.ipv4.conf.all.drop_gratuitous_arp=1 +To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv4.conf.all.drop_gratuitous_arp = 1 + + This can cause problems if ARP proxies are used in the network. + R12 + Drop Gratuitous ARP frames to prevent ARP poisoning. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Comment out any occurrences of net.ipv4.conf.all.drop_gratuitous_arp from /etc/sysctl.d/*.conf files + +for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do + + + # skip systemd-sysctl symlink (/etc/sysctl.d/99-sysctl.conf -> /etc/sysctl.conf) + if [[ "$(readlink -f "$f")" == "/etc/sysctl.conf" ]]; then continue; fi + + matching_list=$(grep -P '^(?!#).*[\s]*net.ipv4.conf.all.drop_gratuitous_arp.*$' $f | uniq ) + if ! test -z "$matching_list"; then + while IFS= read -r entry; do + escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") + # comment out "net.ipv4.conf.all.drop_gratuitous_arp" matches to preserve user data + sed -i --follow-symlinks "s/^${escaped_entry}$/# &/g" $f + done <<< "$matching_list" + fi +done + +# +# Set sysctl config file which to save the desired value +# + +SYSCONFIG_FILE="/etc/sysctl.conf" + + +# +# Set runtime for net.ipv4.conf.all.drop_gratuitous_arp +# +if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then + /sbin/sysctl -q -n -w net.ipv4.conf.all.drop_gratuitous_arp="1" +fi + +# +# If net.ipv4.conf.all.drop_gratuitous_arp present in /etc/sysctl.conf, change value to "1" +# else, add "net.ipv4.conf.all.drop_gratuitous_arp = 1" to /etc/sysctl.conf +# + +# Strip any search characters in the key arg so that the key can be replaced without +# adding any search characters to the config file. +stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv4.conf.all.drop_gratuitous_arp") + +# shellcheck disable=SC2059 +printf -v formatted_output "%s = %s" "$stripped_key" "1" + +# If the key exists, change it. Otherwise, add it to the config_file. +# We search for the key string followed by a word boundary (matched by \>), +# so if we search for 'setting', 'setting2' won't match. +if LC_ALL=C grep -q -m 1 -i -e "^net.ipv4.conf.all.drop_gratuitous_arp\\>" "${SYSCONFIG_FILE}"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + LC_ALL=C sed -i --follow-symlinks "s/^net.ipv4.conf.all.drop_gratuitous_arp\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" +else + if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" + fi + printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_drop_gratuitous_arp + +- name: List /etc/sysctl.d/*.conf files + find: + paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + contains: ^[\s]*net.ipv4.conf.all.drop_gratuitous_arp.*$ + patterns: '*.conf' + file_type: any + register: find_sysctl_d + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_drop_gratuitous_arp + +- name: Comment out any occurrences of net.ipv4.conf.all.drop_gratuitous_arp from + config files + replace: + path: '{{ item.path }}' + regexp: ^[\s]*net.ipv4.conf.all.drop_gratuitous_arp + replace: '#net.ipv4.conf.all.drop_gratuitous_arp' + loop: '{{ find_sysctl_d.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_drop_gratuitous_arp + +- name: Ensure sysctl net.ipv4.conf.all.drop_gratuitous_arp is set to 1 + sysctl: + name: net.ipv4.conf.all.drop_gratuitous_arp + value: '1' + sysctl_file: /etc/sysctl.conf + state: present + reload: true + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_drop_gratuitous_arp + + + + + + + + + + Disable Kernel Parameter for IPv4 Forwarding on all IPv4 Interfaces + To set the runtime status of the net.ipv4.conf.all.forwarding kernel parameter, run the following command: $ sudo sysctl -w net.ipv4.conf.all.forwarding=0 +To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv4.conf.all.forwarding = 0 + + There might be cases when certain applications can systematically override this option. +One such case is Libvirt; a toolkit for managing of virtualization platforms. +By default, Libvirt requires IP forwarding to be enabled to facilitate +network communication between the virtualization host and guest +machines. It enables IP forwarding after every reboot. + CCI-000366 + CM-6(b) + SRG-OS-000480-GPOS-00227 + OL09-00-006028 + SV-271872r1092328_rule + IP forwarding permits the kernel to forward packets from one network +interface to another. The ability to forward packets between two networks is +only appropriate for systems acting as routers. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Comment out any occurrences of net.ipv4.conf.all.forwarding from /etc/sysctl.d/*.conf files + +for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do + + + # skip systemd-sysctl symlink (/etc/sysctl.d/99-sysctl.conf -> /etc/sysctl.conf) + if [[ "$(readlink -f "$f")" == "/etc/sysctl.conf" ]]; then continue; fi + + matching_list=$(grep -P '^(?!#).*[\s]*net.ipv4.conf.all.forwarding.*$' $f | uniq ) + if ! test -z "$matching_list"; then + while IFS= read -r entry; do + escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") + # comment out "net.ipv4.conf.all.forwarding" matches to preserve user data + sed -i --follow-symlinks "s/^${escaped_entry}$/# &/g" $f + done <<< "$matching_list" + fi +done + +# +# Set sysctl config file which to save the desired value +# + +SYSCONFIG_FILE="/etc/sysctl.conf" + +sysctl_net_ipv4_conf_all_forwarding_value='' + + +# +# Set runtime for net.ipv4.conf.all.forwarding +# +if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then + /sbin/sysctl -q -n -w net.ipv4.conf.all.forwarding="$sysctl_net_ipv4_conf_all_forwarding_value" +fi + +# +# If net.ipv4.conf.all.forwarding present in /etc/sysctl.conf, change value to appropriate value +# else, add "net.ipv4.conf.all.forwarding = value" to /etc/sysctl.conf +# + +# Strip any search characters in the key arg so that the key can be replaced without +# adding any search characters to the config file. +stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv4.conf.all.forwarding") + +# shellcheck disable=SC2059 +printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv4_conf_all_forwarding_value" + +# If the key exists, change it. Otherwise, add it to the config_file. +# We search for the key string followed by a word boundary (matched by \>), +# so if we search for 'setting', 'setting2' won't match. +if LC_ALL=C grep -q -m 1 -i -e "^net.ipv4.conf.all.forwarding\\>" "${SYSCONFIG_FILE}"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + LC_ALL=C sed -i --follow-symlinks "s/^net.ipv4.conf.all.forwarding\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" +else + if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" + fi + printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-006028 + - NIST-800-53-CM-6(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_forwarding + +- name: List /etc/sysctl.d/*.conf files + find: + paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + contains: ^[\s]*net.ipv4.conf.all.forwarding.*$ + patterns: '*.conf' + file_type: any + register: find_sysctl_d + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006028 + - NIST-800-53-CM-6(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_forwarding + +- name: Comment out any occurrences of net.ipv4.conf.all.forwarding from config files + replace: + path: '{{ item.path }}' + regexp: ^[\s]*net.ipv4.conf.all.forwarding + replace: '#net.ipv4.conf.all.forwarding' + loop: '{{ find_sysctl_d.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006028 + - NIST-800-53-CM-6(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_forwarding +- name: XCCDF Value sysctl_net_ipv4_conf_all_forwarding_value # promote to variable + set_fact: + sysctl_net_ipv4_conf_all_forwarding_value: !!str + tags: + - always + +- name: Ensure sysctl net.ipv4.conf.all.forwarding is set + sysctl: + name: net.ipv4.conf.all.forwarding + value: '{{ sysctl_net_ipv4_conf_all_forwarding_value }}' + sysctl_file: /etc/sysctl.conf + state: present + reload: true + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006028 + - NIST-800-53-CM-6(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_forwarding + + + + + + + + + + + Enable Kernel Parameter to Log Martian Packets on all IPv4 Interfaces + To set the runtime status of the net.ipv4.conf.all.log_martians kernel parameter, run the following command: $ sudo sysctl -w net.ipv4.conf.all.log_martians=1 +To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv4.conf.all.log_martians = 1 + + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 2 + 3 + 7 + 8 + 9 + APO13.01 + BAI04.04 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS01.03 + DSS01.04 + DSS03.05 + DSS05.02 + DSS05.03 + DSS05.05 + DSS05.07 + DSS06.06 + 3.1.20 + CCI-000366 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.2 + 4.3.4.3.3 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 6.2 + SR 7.1 + SR 7.2 + SR 7.6 + A.11.2.6 + A.12.1.2 + A.12.1.3 + A.12.5.1 + A.12.6.2 + A.13.1.1 + A.13.2.1 + A.14.1.3 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.17.2.1 + A.6.2.1 + A.6.2.2 + A.9.1.2 + CM-7(a) + CM-7(b) + SC-5(3)(a) + DE.CM-1 + PR.AC-3 + PR.DS-4 + PR.IP-1 + PR.PT-3 + PR.PT-4 + SRG-OS-000480-GPOS-00227 + A.8.SEC-OL6 + OL09-00-006022 + SV-271866r1092310_rule + The presence of "martian" packets (which have impossible addresses) +as well as spoofed packets, source-routed packets, and redirects could be a +sign of nefarious network activity. Logging these packets enables this activity +to be detected. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Comment out any occurrences of net.ipv4.conf.all.log_martians from /etc/sysctl.d/*.conf files + +for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do + + + # skip systemd-sysctl symlink (/etc/sysctl.d/99-sysctl.conf -> /etc/sysctl.conf) + if [[ "$(readlink -f "$f")" == "/etc/sysctl.conf" ]]; then continue; fi + + matching_list=$(grep -P '^(?!#).*[\s]*net.ipv4.conf.all.log_martians.*$' $f | uniq ) + if ! test -z "$matching_list"; then + while IFS= read -r entry; do + escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") + # comment out "net.ipv4.conf.all.log_martians" matches to preserve user data + sed -i --follow-symlinks "s/^${escaped_entry}$/# &/g" $f + done <<< "$matching_list" + fi +done + +# +# Set sysctl config file which to save the desired value +# + +SYSCONFIG_FILE="/etc/sysctl.conf" + +sysctl_net_ipv4_conf_all_log_martians_value='' + + +# +# Set runtime for net.ipv4.conf.all.log_martians +# +if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then + /sbin/sysctl -q -n -w net.ipv4.conf.all.log_martians="$sysctl_net_ipv4_conf_all_log_martians_value" +fi + +# +# If net.ipv4.conf.all.log_martians present in /etc/sysctl.conf, change value to appropriate value +# else, add "net.ipv4.conf.all.log_martians = value" to /etc/sysctl.conf +# + +# Strip any search characters in the key arg so that the key can be replaced without +# adding any search characters to the config file. +stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv4.conf.all.log_martians") + +# shellcheck disable=SC2059 +printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv4_conf_all_log_martians_value" + +# If the key exists, change it. Otherwise, add it to the config_file. +# We search for the key string followed by a word boundary (matched by \>), +# so if we search for 'setting', 'setting2' won't match. +if LC_ALL=C grep -q -m 1 -i -e "^net.ipv4.conf.all.log_martians\\>" "${SYSCONFIG_FILE}"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + LC_ALL=C sed -i --follow-symlinks "s/^net.ipv4.conf.all.log_martians\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" +else + if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" + fi + printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-006022 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5(3)(a) + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv4_conf_all_log_martians + - unknown_severity + +- name: List /etc/sysctl.d/*.conf files + find: + paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + contains: ^[\s]*net.ipv4.conf.all.log_martians.*$ + patterns: '*.conf' + file_type: any + register: find_sysctl_d + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006022 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5(3)(a) + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv4_conf_all_log_martians + - unknown_severity + +- name: Comment out any occurrences of net.ipv4.conf.all.log_martians from config + files + replace: + path: '{{ item.path }}' + regexp: ^[\s]*net.ipv4.conf.all.log_martians + replace: '#net.ipv4.conf.all.log_martians' + loop: '{{ find_sysctl_d.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006022 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5(3)(a) + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv4_conf_all_log_martians + - unknown_severity +- name: XCCDF Value sysctl_net_ipv4_conf_all_log_martians_value # promote to variable + set_fact: + sysctl_net_ipv4_conf_all_log_martians_value: !!str + tags: + - always + +- name: Ensure sysctl net.ipv4.conf.all.log_martians is set + sysctl: + name: net.ipv4.conf.all.log_martians + value: '{{ sysctl_net_ipv4_conf_all_log_martians_value }}' + sysctl_file: /etc/sysctl.conf + state: present + reload: true + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006022 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5(3)(a) + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv4_conf_all_log_martians + - unknown_severity + + + + + + + + + + + Prevent Routing External Traffic to Local Loopback on All IPv4 Interfaces + To set the runtime status of the net.ipv4.conf.all.route_localnet kernel parameter, run the following command: $ sudo sysctl -w net.ipv4.conf.all.route_localnet=0 +To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv4.conf.all.route_localnet = 0 + + R12 + Refuse the routing of packets whose source or destination address is the local loopback. +This prohibits the use of network 127/8 for local routing purposes. +Enabling route_localnet can expose applications listening on localhost to external traffic. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Comment out any occurrences of net.ipv4.conf.all.route_localnet from /etc/sysctl.d/*.conf files + +for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do + + + # skip systemd-sysctl symlink (/etc/sysctl.d/99-sysctl.conf -> /etc/sysctl.conf) + if [[ "$(readlink -f "$f")" == "/etc/sysctl.conf" ]]; then continue; fi + + matching_list=$(grep -P '^(?!#).*[\s]*net.ipv4.conf.all.route_localnet.*$' $f | uniq ) + if ! test -z "$matching_list"; then + while IFS= read -r entry; do + escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") + # comment out "net.ipv4.conf.all.route_localnet" matches to preserve user data + sed -i --follow-symlinks "s/^${escaped_entry}$/# &/g" $f + done <<< "$matching_list" + fi +done + +# +# Set sysctl config file which to save the desired value +# + +SYSCONFIG_FILE="/etc/sysctl.conf" + + +# +# Set runtime for net.ipv4.conf.all.route_localnet +# +if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then + /sbin/sysctl -q -n -w net.ipv4.conf.all.route_localnet="0" +fi + +# +# If net.ipv4.conf.all.route_localnet present in /etc/sysctl.conf, change value to "0" +# else, add "net.ipv4.conf.all.route_localnet = 0" to /etc/sysctl.conf +# + +# Strip any search characters in the key arg so that the key can be replaced without +# adding any search characters to the config file. +stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv4.conf.all.route_localnet") + +# shellcheck disable=SC2059 +printf -v formatted_output "%s = %s" "$stripped_key" "0" + +# If the key exists, change it. Otherwise, add it to the config_file. +# We search for the key string followed by a word boundary (matched by \>), +# so if we search for 'setting', 'setting2' won't match. +if LC_ALL=C grep -q -m 1 -i -e "^net.ipv4.conf.all.route_localnet\\>" "${SYSCONFIG_FILE}"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + LC_ALL=C sed -i --follow-symlinks "s/^net.ipv4.conf.all.route_localnet\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" +else + if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" + fi + printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_route_localnet + +- name: List /etc/sysctl.d/*.conf files + find: + paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + contains: ^[\s]*net.ipv4.conf.all.route_localnet.*$ + patterns: '*.conf' + file_type: any + register: find_sysctl_d + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_route_localnet + +- name: Comment out any occurrences of net.ipv4.conf.all.route_localnet from config + files + replace: + path: '{{ item.path }}' + regexp: ^[\s]*net.ipv4.conf.all.route_localnet + replace: '#net.ipv4.conf.all.route_localnet' + loop: '{{ find_sysctl_d.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_route_localnet + +- name: Ensure sysctl net.ipv4.conf.all.route_localnet is set to 0 + sysctl: + name: net.ipv4.conf.all.route_localnet + value: '0' + sysctl_file: /etc/sysctl.conf + state: present + reload: true + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_route_localnet + + + + + + + + + + Enable Kernel Parameter to Use Reverse Path Filtering on all IPv4 Interfaces + To set the runtime status of the net.ipv4.conf.all.rp_filter kernel parameter, run the following command: $ sudo sysctl -w net.ipv4.conf.all.rp_filter=1 +To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv4.conf.all.rp_filter = 1 + + 1 + 12 + 13 + 14 + 15 + 16 + 18 + 2 + 4 + 6 + 7 + 8 + 9 + APO01.06 + APO13.01 + BAI04.04 + DSS01.03 + DSS01.05 + DSS03.01 + DSS03.05 + DSS05.02 + DSS05.04 + DSS05.07 + DSS06.02 + 3.1.20 + CCI-000366 + 4.2.3.4 + 4.3.3.4 + 4.4.3.3 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 6.2 + SR 7.1 + SR 7.2 + SR 7.6 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.12.1.1 + A.12.1.2 + A.12.1.3 + A.13.1.1 + A.13.1.2 + A.13.1.3 + A.13.2.1 + A.13.2.2 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.17.2.1 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CM-7(a) + CM-7(b) + CM-6(a) + SC-7(a) + DE.AE-1 + DE.CM-1 + ID.AM-3 + PR.AC-5 + PR.DS-4 + PR.DS-5 + PR.PT-4 + Req-1.4.3 + SRG-OS-000480-GPOS-00227 + R12 + A.8.SEC-OL6 + 1.4.3 + 1.4 + OL09-00-006024 + SV-271868r1092316_rule + Enabling reverse path filtering drops packets with source addresses +that should not have been able to be received on the interface they were +received on. It should not be used on systems which are routers for +complicated networks, but is helpful for end hosts and routers serving small +networks. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Comment out any occurrences of net.ipv4.conf.all.rp_filter from /etc/sysctl.d/*.conf files + +for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do + + + # skip systemd-sysctl symlink (/etc/sysctl.d/99-sysctl.conf -> /etc/sysctl.conf) + if [[ "$(readlink -f "$f")" == "/etc/sysctl.conf" ]]; then continue; fi + + matching_list=$(grep -P '^(?!#).*[\s]*net.ipv4.conf.all.rp_filter.*$' $f | uniq ) + if ! test -z "$matching_list"; then + while IFS= read -r entry; do + escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") + # comment out "net.ipv4.conf.all.rp_filter" matches to preserve user data + sed -i --follow-symlinks "s/^${escaped_entry}$/# &/g" $f + done <<< "$matching_list" + fi +done + +# +# Set sysctl config file which to save the desired value +# + +SYSCONFIG_FILE="/etc/sysctl.conf" + +sysctl_net_ipv4_conf_all_rp_filter_value='' + + +# +# Set runtime for net.ipv4.conf.all.rp_filter +# +if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then + /sbin/sysctl -q -n -w net.ipv4.conf.all.rp_filter="$sysctl_net_ipv4_conf_all_rp_filter_value" +fi + +# +# If net.ipv4.conf.all.rp_filter present in /etc/sysctl.conf, change value to appropriate value +# else, add "net.ipv4.conf.all.rp_filter = value" to /etc/sysctl.conf +# + +# Strip any search characters in the key arg so that the key can be replaced without +# adding any search characters to the config file. +stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv4.conf.all.rp_filter") + +# shellcheck disable=SC2059 +printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv4_conf_all_rp_filter_value" + +# If the key exists, change it. Otherwise, add it to the config_file. +# We search for the key string followed by a word boundary (matched by \>), +# so if we search for 'setting', 'setting2' won't match. +if LC_ALL=C grep -q -m 1 -i -e "^net.ipv4.conf.all.rp_filter\\>" "${SYSCONFIG_FILE}"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + LC_ALL=C sed -i --follow-symlinks "s/^net.ipv4.conf.all.rp_filter\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" +else + if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" + fi + printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-006024 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-7(a) + - PCI-DSS-Req-1.4.3 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.3 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_rp_filter + +- name: List /etc/sysctl.d/*.conf files + find: + paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + contains: ^[\s]*net.ipv4.conf.all.rp_filter.*$ + patterns: '*.conf' + file_type: any + register: find_sysctl_d + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006024 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-7(a) + - PCI-DSS-Req-1.4.3 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.3 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_rp_filter + +- name: Comment out any occurrences of net.ipv4.conf.all.rp_filter from config files + replace: + path: '{{ item.path }}' + regexp: ^[\s]*net.ipv4.conf.all.rp_filter + replace: '#net.ipv4.conf.all.rp_filter' + loop: '{{ find_sysctl_d.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006024 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-7(a) + - PCI-DSS-Req-1.4.3 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.3 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_rp_filter +- name: XCCDF Value sysctl_net_ipv4_conf_all_rp_filter_value # promote to variable + set_fact: + sysctl_net_ipv4_conf_all_rp_filter_value: !!str + tags: + - always + +- name: Ensure sysctl net.ipv4.conf.all.rp_filter is set + sysctl: + name: net.ipv4.conf.all.rp_filter + value: '{{ sysctl_net_ipv4_conf_all_rp_filter_value }}' + sysctl_file: /etc/sysctl.conf + state: present + reload: true + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006024 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-7(a) + - PCI-DSS-Req-1.4.3 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.3 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_rp_filter + + + + + + + + + + Disable Kernel Parameter for Accepting Secure ICMP Redirects on all IPv4 Interfaces + To set the runtime status of the net.ipv4.conf.all.secure_redirects kernel parameter, run the following command: $ sudo sysctl -w net.ipv4.conf.all.secure_redirects=0 +To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv4.conf.all.secure_redirects = 0 + + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 18 + 2 + 3 + 4 + 6 + 7 + 8 + 9 + APO01.06 + APO13.01 + BAI04.04 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS01.03 + DSS01.05 + DSS03.01 + DSS03.05 + DSS05.02 + DSS05.04 + DSS05.05 + DSS05.07 + DSS06.02 + DSS06.06 + 3.1.20 + CCI-001503 + CCI-001551 + 4.2.3.4 + 4.3.3.4 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.2 + 4.3.4.3.3 + 4.4.3.3 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 6.2 + SR 7.1 + SR 7.2 + SR 7.6 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.12.1.1 + A.12.1.2 + A.12.1.3 + A.12.5.1 + A.12.6.2 + A.13.1.1 + A.13.1.2 + A.13.1.3 + A.13.2.1 + A.13.2.2 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.17.2.1 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CM-7(a) + CM-7(b) + CM-6(a) + SC-7(a) + DE.AE-1 + DE.CM-1 + ID.AM-3 + PR.AC-5 + PR.DS-4 + PR.DS-5 + PR.IP-1 + PR.PT-3 + PR.PT-4 + Req-1.4.3 + SRG-OS-000480-GPOS-00227 + R12 + A.8.SEC-OL6 + 1.4.3 + 1.4 + Accepting "secure" ICMP redirects (from those gateways listed as +default gateways) has few legitimate uses. It should be disabled unless it is +absolutely required. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Comment out any occurrences of net.ipv4.conf.all.secure_redirects from /etc/sysctl.d/*.conf files + +for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do + + + # skip systemd-sysctl symlink (/etc/sysctl.d/99-sysctl.conf -> /etc/sysctl.conf) + if [[ "$(readlink -f "$f")" == "/etc/sysctl.conf" ]]; then continue; fi + + matching_list=$(grep -P '^(?!#).*[\s]*net.ipv4.conf.all.secure_redirects.*$' $f | uniq ) + if ! test -z "$matching_list"; then + while IFS= read -r entry; do + escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") + # comment out "net.ipv4.conf.all.secure_redirects" matches to preserve user data + sed -i --follow-symlinks "s/^${escaped_entry}$/# &/g" $f + done <<< "$matching_list" + fi +done + +# +# Set sysctl config file which to save the desired value +# + +SYSCONFIG_FILE="/etc/sysctl.conf" + +sysctl_net_ipv4_conf_all_secure_redirects_value='' + + +# +# Set runtime for net.ipv4.conf.all.secure_redirects +# +if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then + /sbin/sysctl -q -n -w net.ipv4.conf.all.secure_redirects="$sysctl_net_ipv4_conf_all_secure_redirects_value" +fi + +# +# If net.ipv4.conf.all.secure_redirects present in /etc/sysctl.conf, change value to appropriate value +# else, add "net.ipv4.conf.all.secure_redirects = value" to /etc/sysctl.conf +# + +# Strip any search characters in the key arg so that the key can be replaced without +# adding any search characters to the config file. +stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv4.conf.all.secure_redirects") + +# shellcheck disable=SC2059 +printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv4_conf_all_secure_redirects_value" + +# If the key exists, change it. Otherwise, add it to the config_file. +# We search for the key string followed by a word boundary (matched by \>), +# so if we search for 'setting', 'setting2' won't match. +if LC_ALL=C grep -q -m 1 -i -e "^net.ipv4.conf.all.secure_redirects\\>" "${SYSCONFIG_FILE}"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + LC_ALL=C sed -i --follow-symlinks "s/^net.ipv4.conf.all.secure_redirects\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" +else + if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" + fi + printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-7(a) + - PCI-DSS-Req-1.4.3 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.3 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_secure_redirects + +- name: List /etc/sysctl.d/*.conf files + find: + paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + contains: ^[\s]*net.ipv4.conf.all.secure_redirects.*$ + patterns: '*.conf' + file_type: any + register: find_sysctl_d + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-7(a) + - PCI-DSS-Req-1.4.3 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.3 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_secure_redirects + +- name: Comment out any occurrences of net.ipv4.conf.all.secure_redirects from config + files + replace: + path: '{{ item.path }}' + regexp: ^[\s]*net.ipv4.conf.all.secure_redirects + replace: '#net.ipv4.conf.all.secure_redirects' + loop: '{{ find_sysctl_d.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-7(a) + - PCI-DSS-Req-1.4.3 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.3 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_secure_redirects +- name: XCCDF Value sysctl_net_ipv4_conf_all_secure_redirects_value # promote to variable + set_fact: + sysctl_net_ipv4_conf_all_secure_redirects_value: !!str + tags: + - always + +- name: Ensure sysctl net.ipv4.conf.all.secure_redirects is set + sysctl: + name: net.ipv4.conf.all.secure_redirects + value: '{{ sysctl_net_ipv4_conf_all_secure_redirects_value }}' + sysctl_file: /etc/sysctl.conf + state: present + reload: true + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-7(a) + - PCI-DSS-Req-1.4.3 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.3 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_secure_redirects + + + + + + + + + + + Configure Sending and Accepting Shared Media Redirects for All IPv4 Interfaces + To set the runtime status of the net.ipv4.conf.all.shared_media kernel parameter, run the following command: $ sudo sysctl -w net.ipv4.conf.all.shared_media= + +To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv4.conf.all.shared_media = + + + R12 + This setting should be aligned with net.ipv4.conf.all.secure_redirects because it overrides it. +If shared_media is enabled for an interface secure_redirects will be enabled too. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Comment out any occurrences of net.ipv4.conf.all.shared_media from /etc/sysctl.d/*.conf files + +for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do + + + # skip systemd-sysctl symlink (/etc/sysctl.d/99-sysctl.conf -> /etc/sysctl.conf) + if [[ "$(readlink -f "$f")" == "/etc/sysctl.conf" ]]; then continue; fi + + matching_list=$(grep -P '^(?!#).*[\s]*net.ipv4.conf.all.shared_media.*$' $f | uniq ) + if ! test -z "$matching_list"; then + while IFS= read -r entry; do + escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") + # comment out "net.ipv4.conf.all.shared_media" matches to preserve user data + sed -i --follow-symlinks "s/^${escaped_entry}$/# &/g" $f + done <<< "$matching_list" + fi +done + +# +# Set sysctl config file which to save the desired value +# + +SYSCONFIG_FILE="/etc/sysctl.conf" + +sysctl_net_ipv4_conf_all_shared_media_value='' + + +# +# Set runtime for net.ipv4.conf.all.shared_media +# +if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then + /sbin/sysctl -q -n -w net.ipv4.conf.all.shared_media="$sysctl_net_ipv4_conf_all_shared_media_value" +fi + +# +# If net.ipv4.conf.all.shared_media present in /etc/sysctl.conf, change value to appropriate value +# else, add "net.ipv4.conf.all.shared_media = value" to /etc/sysctl.conf +# + +# Strip any search characters in the key arg so that the key can be replaced without +# adding any search characters to the config file. +stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv4.conf.all.shared_media") + +# shellcheck disable=SC2059 +printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv4_conf_all_shared_media_value" + +# If the key exists, change it. Otherwise, add it to the config_file. +# We search for the key string followed by a word boundary (matched by \>), +# so if we search for 'setting', 'setting2' won't match. +if LC_ALL=C grep -q -m 1 -i -e "^net.ipv4.conf.all.shared_media\\>" "${SYSCONFIG_FILE}"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + LC_ALL=C sed -i --follow-symlinks "s/^net.ipv4.conf.all.shared_media\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" +else + if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" + fi + printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_shared_media + +- name: List /etc/sysctl.d/*.conf files + find: + paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + contains: ^[\s]*net.ipv4.conf.all.shared_media.*$ + patterns: '*.conf' + file_type: any + register: find_sysctl_d + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_shared_media + +- name: Comment out any occurrences of net.ipv4.conf.all.shared_media from config + files + replace: + path: '{{ item.path }}' + regexp: ^[\s]*net.ipv4.conf.all.shared_media + replace: '#net.ipv4.conf.all.shared_media' + loop: '{{ find_sysctl_d.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_shared_media +- name: XCCDF Value sysctl_net_ipv4_conf_all_shared_media_value # promote to variable + set_fact: + sysctl_net_ipv4_conf_all_shared_media_value: !!str + tags: + - always + +- name: Ensure sysctl net.ipv4.conf.all.shared_media is set + sysctl: + name: net.ipv4.conf.all.shared_media + value: '{{ sysctl_net_ipv4_conf_all_shared_media_value }}' + sysctl_file: /etc/sysctl.conf + state: present + reload: true + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_shared_media + + + + + + + + + + + Disable Kernel Parameter for Accepting ICMP Redirects by Default on IPv4 Interfaces + To set the runtime status of the net.ipv4.conf.default.accept_redirects kernel parameter, run the following command: $ sudo sysctl -w net.ipv4.conf.default.accept_redirects=0 +To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv4.conf.default.accept_redirects = 0 + + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 18 + 2 + 3 + 4 + 6 + 7 + 8 + 9 + 5.10.1.1 + APO01.06 + APO13.01 + BAI04.04 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS01.03 + DSS01.05 + DSS03.01 + DSS03.05 + DSS05.02 + DSS05.04 + DSS05.05 + DSS05.07 + DSS06.02 + DSS06.06 + 3.1.20 + CCI-000366 + 4.2.3.4 + 4.3.3.4 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.2 + 4.3.4.3.3 + 4.4.3.3 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 6.2 + SR 7.1 + SR 7.2 + SR 7.6 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.12.1.1 + A.12.1.2 + A.12.1.3 + A.12.5.1 + A.12.6.2 + A.13.1.1 + A.13.1.2 + A.13.1.3 + A.13.2.1 + A.13.2.2 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.17.2.1 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CM-7(a) + CM-7(b) + CM-6(a) + SC-7(a) + DE.AE-1 + DE.CM-1 + ID.AM-3 + PR.AC-5 + PR.DS-4 + PR.DS-5 + PR.IP-1 + PR.PT-3 + PR.PT-4 + Req-1.4.3 + SRG-OS-000480-GPOS-00227 + R12 + A.8.SEC-OL6 + 1.4.3 + 1.4 + OL09-00-006025 + SV-271869r1092319_rule + ICMP redirect messages are used by routers to inform hosts that a more +direct route exists for a particular destination. These messages modify the +host's route table and are unauthenticated. An illicit ICMP redirect +message could result in a man-in-the-middle attack. +This feature of the IPv4 protocol has few legitimate uses. It should +be disabled unless absolutely required. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Comment out any occurrences of net.ipv4.conf.default.accept_redirects from /etc/sysctl.d/*.conf files + +for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do + + + # skip systemd-sysctl symlink (/etc/sysctl.d/99-sysctl.conf -> /etc/sysctl.conf) + if [[ "$(readlink -f "$f")" == "/etc/sysctl.conf" ]]; then continue; fi + + matching_list=$(grep -P '^(?!#).*[\s]*net.ipv4.conf.default.accept_redirects.*$' $f | uniq ) + if ! test -z "$matching_list"; then + while IFS= read -r entry; do + escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") + # comment out "net.ipv4.conf.default.accept_redirects" matches to preserve user data + sed -i --follow-symlinks "s/^${escaped_entry}$/# &/g" $f + done <<< "$matching_list" + fi +done + +# +# Set sysctl config file which to save the desired value +# + +SYSCONFIG_FILE="/etc/sysctl.conf" + +sysctl_net_ipv4_conf_default_accept_redirects_value='' + + +# +# Set runtime for net.ipv4.conf.default.accept_redirects +# +if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then + /sbin/sysctl -q -n -w net.ipv4.conf.default.accept_redirects="$sysctl_net_ipv4_conf_default_accept_redirects_value" +fi + +# +# If net.ipv4.conf.default.accept_redirects present in /etc/sysctl.conf, change value to appropriate value +# else, add "net.ipv4.conf.default.accept_redirects = value" to /etc/sysctl.conf +# + +# Strip any search characters in the key arg so that the key can be replaced without +# adding any search characters to the config file. +stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv4.conf.default.accept_redirects") + +# shellcheck disable=SC2059 +printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv4_conf_default_accept_redirects_value" + +# If the key exists, change it. Otherwise, add it to the config_file. +# We search for the key string followed by a word boundary (matched by \>), +# so if we search for 'setting', 'setting2' won't match. +if LC_ALL=C grep -q -m 1 -i -e "^net.ipv4.conf.default.accept_redirects\\>" "${SYSCONFIG_FILE}"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + LC_ALL=C sed -i --follow-symlinks "s/^net.ipv4.conf.default.accept_redirects\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" +else + if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" + fi + printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - CJIS-5.10.1.1 + - DISA-STIG-OL09-00-006025 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-7(a) + - PCI-DSS-Req-1.4.3 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.3 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_default_accept_redirects + +- name: List /etc/sysctl.d/*.conf files + find: + paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + contains: ^[\s]*net.ipv4.conf.default.accept_redirects.*$ + patterns: '*.conf' + file_type: any + register: find_sysctl_d + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.10.1.1 + - DISA-STIG-OL09-00-006025 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-7(a) + - PCI-DSS-Req-1.4.3 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.3 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_default_accept_redirects + +- name: Comment out any occurrences of net.ipv4.conf.default.accept_redirects from + config files + replace: + path: '{{ item.path }}' + regexp: ^[\s]*net.ipv4.conf.default.accept_redirects + replace: '#net.ipv4.conf.default.accept_redirects' + loop: '{{ find_sysctl_d.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.10.1.1 + - DISA-STIG-OL09-00-006025 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-7(a) + - PCI-DSS-Req-1.4.3 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.3 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_default_accept_redirects +- name: XCCDF Value sysctl_net_ipv4_conf_default_accept_redirects_value # promote to variable + set_fact: + sysctl_net_ipv4_conf_default_accept_redirects_value: !!str + tags: + - always + +- name: Ensure sysctl net.ipv4.conf.default.accept_redirects is set + sysctl: + name: net.ipv4.conf.default.accept_redirects + value: '{{ sysctl_net_ipv4_conf_default_accept_redirects_value }}' + sysctl_file: /etc/sysctl.conf + state: present + reload: true + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.10.1.1 + - DISA-STIG-OL09-00-006025 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-7(a) + - PCI-DSS-Req-1.4.3 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.3 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_default_accept_redirects + + + + + + + + + + + Disable Kernel Parameter for Accepting Source-Routed Packets on IPv4 Interfaces by Default + To set the runtime status of the net.ipv4.conf.default.accept_source_route kernel parameter, run the following command: $ sudo sysctl -w net.ipv4.conf.default.accept_source_route=0 +To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv4.conf.default.accept_source_route = 0 + + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 18 + 2 + 3 + 4 + 6 + 7 + 8 + 9 + 5.10.1.1 + APO01.06 + APO13.01 + BAI04.04 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS01.03 + DSS01.05 + DSS03.01 + DSS03.05 + DSS05.02 + DSS05.04 + DSS05.05 + DSS05.07 + DSS06.02 + DSS06.06 + 3.1.20 + CCI-000366 + 4.2.3.4 + 4.3.3.4 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.2 + 4.3.4.3.3 + 4.4.3.3 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 6.2 + SR 7.1 + SR 7.2 + SR 7.6 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.12.1.1 + A.12.1.2 + A.12.1.3 + A.12.5.1 + A.12.6.2 + A.13.1.1 + A.13.1.2 + A.13.1.3 + A.13.2.1 + A.13.2.2 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.17.2.1 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CIP-007-3 R4 + CIP-007-3 R4.1 + CIP-007-3 R4.2 + CIP-007-3 R5.1 + CM-7(a) + CM-7(b) + SC-5 + SC-7(a) + DE.AE-1 + DE.CM-1 + ID.AM-3 + PR.AC-5 + PR.DS-4 + PR.DS-5 + PR.IP-1 + PR.PT-3 + PR.PT-4 + SRG-OS-000480-GPOS-00227 + R12 + A.8.SEC-OL6 + OL09-00-006026 + SV-271870r1092322_rule + Source-routed packets allow the source of the packet to suggest routers +forward the packet along a different path than configured on the router, +which can be used to bypass network security measures. + +Accepting source-routed packets in the IPv4 protocol has few legitimate +uses. It should be disabled unless it is absolutely required, such as when +IPv4 forwarding is enabled and the system is legitimately functioning as a +router. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Comment out any occurrences of net.ipv4.conf.default.accept_source_route from /etc/sysctl.d/*.conf files + +for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do + + + # skip systemd-sysctl symlink (/etc/sysctl.d/99-sysctl.conf -> /etc/sysctl.conf) + if [[ "$(readlink -f "$f")" == "/etc/sysctl.conf" ]]; then continue; fi + + matching_list=$(grep -P '^(?!#).*[\s]*net.ipv4.conf.default.accept_source_route.*$' $f | uniq ) + if ! test -z "$matching_list"; then + while IFS= read -r entry; do + escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") + # comment out "net.ipv4.conf.default.accept_source_route" matches to preserve user data + sed -i --follow-symlinks "s/^${escaped_entry}$/# &/g" $f + done <<< "$matching_list" + fi +done + +# +# Set sysctl config file which to save the desired value +# + +SYSCONFIG_FILE="/etc/sysctl.conf" + +sysctl_net_ipv4_conf_default_accept_source_route_value='' + + +# +# Set runtime for net.ipv4.conf.default.accept_source_route +# +if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then + /sbin/sysctl -q -n -w net.ipv4.conf.default.accept_source_route="$sysctl_net_ipv4_conf_default_accept_source_route_value" +fi + +# +# If net.ipv4.conf.default.accept_source_route present in /etc/sysctl.conf, change value to appropriate value +# else, add "net.ipv4.conf.default.accept_source_route = value" to /etc/sysctl.conf +# + +# Strip any search characters in the key arg so that the key can be replaced without +# adding any search characters to the config file. +stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv4.conf.default.accept_source_route") + +# shellcheck disable=SC2059 +printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv4_conf_default_accept_source_route_value" + +# If the key exists, change it. Otherwise, add it to the config_file. +# We search for the key string followed by a word boundary (matched by \>), +# so if we search for 'setting', 'setting2' won't match. +if LC_ALL=C grep -q -m 1 -i -e "^net.ipv4.conf.default.accept_source_route\\>" "${SYSCONFIG_FILE}"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + LC_ALL=C sed -i --follow-symlinks "s/^net.ipv4.conf.default.accept_source_route\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" +else + if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" + fi + printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - CJIS-5.10.1.1 + - DISA-STIG-OL09-00-006026 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - NIST-800-53-SC-7(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_default_accept_source_route + +- name: List /etc/sysctl.d/*.conf files + find: + paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + contains: ^[\s]*net.ipv4.conf.default.accept_source_route.*$ + patterns: '*.conf' + file_type: any + register: find_sysctl_d + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.10.1.1 + - DISA-STIG-OL09-00-006026 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - NIST-800-53-SC-7(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_default_accept_source_route + +- name: Comment out any occurrences of net.ipv4.conf.default.accept_source_route from + config files + replace: + path: '{{ item.path }}' + regexp: ^[\s]*net.ipv4.conf.default.accept_source_route + replace: '#net.ipv4.conf.default.accept_source_route' + loop: '{{ find_sysctl_d.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.10.1.1 + - DISA-STIG-OL09-00-006026 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - NIST-800-53-SC-7(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_default_accept_source_route +- name: XCCDF Value sysctl_net_ipv4_conf_default_accept_source_route_value # promote to variable + set_fact: + sysctl_net_ipv4_conf_default_accept_source_route_value: !!str + tags: + - always + +- name: Ensure sysctl net.ipv4.conf.default.accept_source_route is set + sysctl: + name: net.ipv4.conf.default.accept_source_route + value: '{{ sysctl_net_ipv4_conf_default_accept_source_route_value }}' + sysctl_file: /etc/sysctl.conf + state: present + reload: true + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.10.1.1 + - DISA-STIG-OL09-00-006026 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - NIST-800-53-SC-7(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_default_accept_source_route + + + + + + + + + + + Enable Kernel Paremeter to Log Martian Packets on all IPv4 Interfaces by Default + To set the runtime status of the net.ipv4.conf.default.log_martians kernel parameter, run the following command: $ sudo sysctl -w net.ipv4.conf.default.log_martians=1 +To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv4.conf.default.log_martians = 1 + + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 2 + 3 + 7 + 8 + 9 + APO13.01 + BAI04.04 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS01.03 + DSS01.04 + DSS03.05 + DSS05.02 + DSS05.03 + DSS05.05 + DSS05.07 + DSS06.06 + 3.1.20 + CCI-000366 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.2 + 4.3.4.3.3 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 6.2 + SR 7.1 + SR 7.2 + SR 7.6 + A.11.2.6 + A.12.1.2 + A.12.1.3 + A.12.5.1 + A.12.6.2 + A.13.1.1 + A.13.2.1 + A.14.1.3 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.17.2.1 + A.6.2.1 + A.6.2.2 + A.9.1.2 + CM-7(a) + CM-7(b) + SC-5(3)(a) + DE.CM-1 + PR.AC-3 + PR.DS-4 + PR.IP-1 + PR.PT-3 + PR.PT-4 + SRG-OS-000480-GPOS-00227 + A.8.SEC-OL6 + OL09-00-006023 + SV-271867r1092313_rule + The presence of "martian" packets (which have impossible addresses) +as well as spoofed packets, source-routed packets, and redirects could be a +sign of nefarious network activity. Logging these packets enables this activity +to be detected. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Comment out any occurrences of net.ipv4.conf.default.log_martians from /etc/sysctl.d/*.conf files + +for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do + + + # skip systemd-sysctl symlink (/etc/sysctl.d/99-sysctl.conf -> /etc/sysctl.conf) + if [[ "$(readlink -f "$f")" == "/etc/sysctl.conf" ]]; then continue; fi + + matching_list=$(grep -P '^(?!#).*[\s]*net.ipv4.conf.default.log_martians.*$' $f | uniq ) + if ! test -z "$matching_list"; then + while IFS= read -r entry; do + escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") + # comment out "net.ipv4.conf.default.log_martians" matches to preserve user data + sed -i --follow-symlinks "s/^${escaped_entry}$/# &/g" $f + done <<< "$matching_list" + fi +done + +# +# Set sysctl config file which to save the desired value +# + +SYSCONFIG_FILE="/etc/sysctl.conf" + +sysctl_net_ipv4_conf_default_log_martians_value='' + + +# +# Set runtime for net.ipv4.conf.default.log_martians +# +if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then + /sbin/sysctl -q -n -w net.ipv4.conf.default.log_martians="$sysctl_net_ipv4_conf_default_log_martians_value" +fi + +# +# If net.ipv4.conf.default.log_martians present in /etc/sysctl.conf, change value to appropriate value +# else, add "net.ipv4.conf.default.log_martians = value" to /etc/sysctl.conf +# + +# Strip any search characters in the key arg so that the key can be replaced without +# adding any search characters to the config file. +stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv4.conf.default.log_martians") + +# shellcheck disable=SC2059 +printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv4_conf_default_log_martians_value" + +# If the key exists, change it. Otherwise, add it to the config_file. +# We search for the key string followed by a word boundary (matched by \>), +# so if we search for 'setting', 'setting2' won't match. +if LC_ALL=C grep -q -m 1 -i -e "^net.ipv4.conf.default.log_martians\\>" "${SYSCONFIG_FILE}"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + LC_ALL=C sed -i --follow-symlinks "s/^net.ipv4.conf.default.log_martians\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" +else + if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" + fi + printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-006023 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5(3)(a) + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv4_conf_default_log_martians + - unknown_severity + +- name: List /etc/sysctl.d/*.conf files + find: + paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + contains: ^[\s]*net.ipv4.conf.default.log_martians.*$ + patterns: '*.conf' + file_type: any + register: find_sysctl_d + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006023 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5(3)(a) + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv4_conf_default_log_martians + - unknown_severity + +- name: Comment out any occurrences of net.ipv4.conf.default.log_martians from config + files + replace: + path: '{{ item.path }}' + regexp: ^[\s]*net.ipv4.conf.default.log_martians + replace: '#net.ipv4.conf.default.log_martians' + loop: '{{ find_sysctl_d.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006023 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5(3)(a) + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv4_conf_default_log_martians + - unknown_severity +- name: XCCDF Value sysctl_net_ipv4_conf_default_log_martians_value # promote to variable + set_fact: + sysctl_net_ipv4_conf_default_log_martians_value: !!str + tags: + - always + +- name: Ensure sysctl net.ipv4.conf.default.log_martians is set + sysctl: + name: net.ipv4.conf.default.log_martians + value: '{{ sysctl_net_ipv4_conf_default_log_martians_value }}' + sysctl_file: /etc/sysctl.conf + state: present + reload: true + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006023 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5(3)(a) + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv4_conf_default_log_martians + - unknown_severity + + + + + + + + + + + Enable Kernel Parameter to Use Reverse Path Filtering on all IPv4 Interfaces by Default + To set the runtime status of the net.ipv4.conf.default.rp_filter kernel parameter, run the following command: $ sudo sysctl -w net.ipv4.conf.default.rp_filter=1 +To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv4.conf.default.rp_filter = 1 + + 1 + 12 + 13 + 14 + 15 + 16 + 18 + 2 + 4 + 6 + 7 + 8 + 9 + APO01.06 + APO13.01 + BAI04.04 + DSS01.03 + DSS01.05 + DSS03.01 + DSS03.05 + DSS05.02 + DSS05.04 + DSS05.07 + DSS06.02 + 3.1.20 + CCI-000366 + 4.2.3.4 + 4.3.3.4 + 4.4.3.3 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 6.2 + SR 7.1 + SR 7.2 + SR 7.6 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.12.1.1 + A.12.1.2 + A.12.1.3 + A.13.1.1 + A.13.1.2 + A.13.1.3 + A.13.2.1 + A.13.2.2 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.17.2.1 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CM-7(a) + CM-7(b) + CM-6(a) + SC-7(a) + DE.AE-1 + DE.CM-1 + ID.AM-3 + PR.AC-5 + PR.DS-4 + PR.DS-5 + PR.PT-4 + SRG-OS-000480-GPOS-00227 + R12 + A.8.SEC-OL6 + OL09-00-006027 + SV-271871r1092325_rule + Enabling reverse path filtering drops packets with source addresses +that should not have been able to be received on the interface they were +received on. It should not be used on systems which are routers for +complicated networks, but is helpful for end hosts and routers serving small +networks. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Comment out any occurrences of net.ipv4.conf.default.rp_filter from /etc/sysctl.d/*.conf files + +for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do + + + # skip systemd-sysctl symlink (/etc/sysctl.d/99-sysctl.conf -> /etc/sysctl.conf) + if [[ "$(readlink -f "$f")" == "/etc/sysctl.conf" ]]; then continue; fi + + matching_list=$(grep -P '^(?!#).*[\s]*net.ipv4.conf.default.rp_filter.*$' $f | uniq ) + if ! test -z "$matching_list"; then + while IFS= read -r entry; do + escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") + # comment out "net.ipv4.conf.default.rp_filter" matches to preserve user data + sed -i --follow-symlinks "s/^${escaped_entry}$/# &/g" $f + done <<< "$matching_list" + fi +done + +# +# Set sysctl config file which to save the desired value +# + +SYSCONFIG_FILE="/etc/sysctl.conf" + +sysctl_net_ipv4_conf_default_rp_filter_value='' + + +# +# Set runtime for net.ipv4.conf.default.rp_filter +# +if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then + /sbin/sysctl -q -n -w net.ipv4.conf.default.rp_filter="$sysctl_net_ipv4_conf_default_rp_filter_value" +fi + +# +# If net.ipv4.conf.default.rp_filter present in /etc/sysctl.conf, change value to appropriate value +# else, add "net.ipv4.conf.default.rp_filter = value" to /etc/sysctl.conf +# + +# Strip any search characters in the key arg so that the key can be replaced without +# adding any search characters to the config file. +stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv4.conf.default.rp_filter") + +# shellcheck disable=SC2059 +printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv4_conf_default_rp_filter_value" + +# If the key exists, change it. Otherwise, add it to the config_file. +# We search for the key string followed by a word boundary (matched by \>), +# so if we search for 'setting', 'setting2' won't match. +if LC_ALL=C grep -q -m 1 -i -e "^net.ipv4.conf.default.rp_filter\\>" "${SYSCONFIG_FILE}"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + LC_ALL=C sed -i --follow-symlinks "s/^net.ipv4.conf.default.rp_filter\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" +else + if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" + fi + printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-006027 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-7(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_default_rp_filter + +- name: List /etc/sysctl.d/*.conf files + find: + paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + contains: ^[\s]*net.ipv4.conf.default.rp_filter.*$ + patterns: '*.conf' + file_type: any + register: find_sysctl_d + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006027 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-7(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_default_rp_filter + +- name: Comment out any occurrences of net.ipv4.conf.default.rp_filter from config + files + replace: + path: '{{ item.path }}' + regexp: ^[\s]*net.ipv4.conf.default.rp_filter + replace: '#net.ipv4.conf.default.rp_filter' + loop: '{{ find_sysctl_d.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006027 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-7(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_default_rp_filter +- name: XCCDF Value sysctl_net_ipv4_conf_default_rp_filter_value # promote to variable + set_fact: + sysctl_net_ipv4_conf_default_rp_filter_value: !!str + tags: + - always + +- name: Ensure sysctl net.ipv4.conf.default.rp_filter is set + sysctl: + name: net.ipv4.conf.default.rp_filter + value: '{{ sysctl_net_ipv4_conf_default_rp_filter_value }}' + sysctl_file: /etc/sysctl.conf + state: present + reload: true + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006027 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-7(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_default_rp_filter + + + + + + + + + + + Configure Kernel Parameter for Accepting Secure Redirects By Default + To set the runtime status of the net.ipv4.conf.default.secure_redirects kernel parameter, run the following command: $ sudo sysctl -w net.ipv4.conf.default.secure_redirects=0 +To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv4.conf.default.secure_redirects = 0 + + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 18 + 2 + 3 + 4 + 6 + 7 + 8 + 9 + APO01.06 + APO13.01 + BAI04.04 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS01.03 + DSS01.05 + DSS03.01 + DSS03.05 + DSS05.02 + DSS05.04 + DSS05.05 + DSS05.07 + DSS06.02 + DSS06.06 + 3.1.20 + CCI-001551 + 4.2.3.4 + 4.3.3.4 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.2 + 4.3.4.3.3 + 4.4.3.3 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 6.2 + SR 7.1 + SR 7.2 + SR 7.6 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.12.1.1 + A.12.1.2 + A.12.1.3 + A.12.5.1 + A.12.6.2 + A.13.1.1 + A.13.1.2 + A.13.1.3 + A.13.2.1 + A.13.2.2 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.17.2.1 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CIP-007-3 R4 + CIP-007-3 R4.1 + CIP-007-3 R4.2 + CIP-007-3 R5.1 + CM-7(a) + CM-7(b) + SC-5 + SC-7(a) + DE.AE-1 + DE.CM-1 + ID.AM-3 + PR.AC-5 + PR.DS-4 + PR.DS-5 + PR.IP-1 + PR.PT-3 + PR.PT-4 + SRG-OS-000480-GPOS-00227 + R12 + A.8.SEC-OL6 + Accepting "secure" ICMP redirects (from those gateways listed as +default gateways) has few legitimate uses. It should be disabled unless it is +absolutely required. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Comment out any occurrences of net.ipv4.conf.default.secure_redirects from /etc/sysctl.d/*.conf files + +for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do + + + # skip systemd-sysctl symlink (/etc/sysctl.d/99-sysctl.conf -> /etc/sysctl.conf) + if [[ "$(readlink -f "$f")" == "/etc/sysctl.conf" ]]; then continue; fi + + matching_list=$(grep -P '^(?!#).*[\s]*net.ipv4.conf.default.secure_redirects.*$' $f | uniq ) + if ! test -z "$matching_list"; then + while IFS= read -r entry; do + escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") + # comment out "net.ipv4.conf.default.secure_redirects" matches to preserve user data + sed -i --follow-symlinks "s/^${escaped_entry}$/# &/g" $f + done <<< "$matching_list" + fi +done + +# +# Set sysctl config file which to save the desired value +# + +SYSCONFIG_FILE="/etc/sysctl.conf" + +sysctl_net_ipv4_conf_default_secure_redirects_value='' + + +# +# Set runtime for net.ipv4.conf.default.secure_redirects +# +if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then + /sbin/sysctl -q -n -w net.ipv4.conf.default.secure_redirects="$sysctl_net_ipv4_conf_default_secure_redirects_value" +fi + +# +# If net.ipv4.conf.default.secure_redirects present in /etc/sysctl.conf, change value to appropriate value +# else, add "net.ipv4.conf.default.secure_redirects = value" to /etc/sysctl.conf +# + +# Strip any search characters in the key arg so that the key can be replaced without +# adding any search characters to the config file. +stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv4.conf.default.secure_redirects") + +# shellcheck disable=SC2059 +printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv4_conf_default_secure_redirects_value" + +# If the key exists, change it. Otherwise, add it to the config_file. +# We search for the key string followed by a word boundary (matched by \>), +# so if we search for 'setting', 'setting2' won't match. +if LC_ALL=C grep -q -m 1 -i -e "^net.ipv4.conf.default.secure_redirects\\>" "${SYSCONFIG_FILE}"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + LC_ALL=C sed -i --follow-symlinks "s/^net.ipv4.conf.default.secure_redirects\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" +else + if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" + fi + printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-171-3.1.20 + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - NIST-800-53-SC-7(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_default_secure_redirects + +- name: List /etc/sysctl.d/*.conf files + find: + paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + contains: ^[\s]*net.ipv4.conf.default.secure_redirects.*$ + patterns: '*.conf' + file_type: any + register: find_sysctl_d + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-171-3.1.20 + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - NIST-800-53-SC-7(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_default_secure_redirects + +- name: Comment out any occurrences of net.ipv4.conf.default.secure_redirects from + config files + replace: + path: '{{ item.path }}' + regexp: ^[\s]*net.ipv4.conf.default.secure_redirects + replace: '#net.ipv4.conf.default.secure_redirects' + loop: '{{ find_sysctl_d.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-171-3.1.20 + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - NIST-800-53-SC-7(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_default_secure_redirects +- name: XCCDF Value sysctl_net_ipv4_conf_default_secure_redirects_value # promote to variable + set_fact: + sysctl_net_ipv4_conf_default_secure_redirects_value: !!str + tags: + - always + +- name: Ensure sysctl net.ipv4.conf.default.secure_redirects is set + sysctl: + name: net.ipv4.conf.default.secure_redirects + value: '{{ sysctl_net_ipv4_conf_default_secure_redirects_value }}' + sysctl_file: /etc/sysctl.conf + state: present + reload: true + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-171-3.1.20 + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - NIST-800-53-SC-7(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_default_secure_redirects + + + + + + + + + + + Configure Sending and Accepting Shared Media Redirects by Default + To set the runtime status of the net.ipv4.conf.default.shared_media kernel parameter, run the following command: $ sudo sysctl -w net.ipv4.conf.default.shared_media= + +To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv4.conf.default.shared_media = + + + R12 + This setting should be aligned with net.ipv4.conf.default.secure_redirects because it overrides it. +If shared_media is enabled for an interface secure_redirects will be enabled too. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Comment out any occurrences of net.ipv4.conf.default.shared_media from /etc/sysctl.d/*.conf files + +for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do + + + # skip systemd-sysctl symlink (/etc/sysctl.d/99-sysctl.conf -> /etc/sysctl.conf) + if [[ "$(readlink -f "$f")" == "/etc/sysctl.conf" ]]; then continue; fi + + matching_list=$(grep -P '^(?!#).*[\s]*net.ipv4.conf.default.shared_media.*$' $f | uniq ) + if ! test -z "$matching_list"; then + while IFS= read -r entry; do + escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") + # comment out "net.ipv4.conf.default.shared_media" matches to preserve user data + sed -i --follow-symlinks "s/^${escaped_entry}$/# &/g" $f + done <<< "$matching_list" + fi +done + +# +# Set sysctl config file which to save the desired value +# + +SYSCONFIG_FILE="/etc/sysctl.conf" + +sysctl_net_ipv4_conf_default_shared_media_value='' + + +# +# Set runtime for net.ipv4.conf.default.shared_media +# +if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then + /sbin/sysctl -q -n -w net.ipv4.conf.default.shared_media="$sysctl_net_ipv4_conf_default_shared_media_value" +fi + +# +# If net.ipv4.conf.default.shared_media present in /etc/sysctl.conf, change value to appropriate value +# else, add "net.ipv4.conf.default.shared_media = value" to /etc/sysctl.conf +# + +# Strip any search characters in the key arg so that the key can be replaced without +# adding any search characters to the config file. +stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv4.conf.default.shared_media") + +# shellcheck disable=SC2059 +printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv4_conf_default_shared_media_value" + +# If the key exists, change it. Otherwise, add it to the config_file. +# We search for the key string followed by a word boundary (matched by \>), +# so if we search for 'setting', 'setting2' won't match. +if LC_ALL=C grep -q -m 1 -i -e "^net.ipv4.conf.default.shared_media\\>" "${SYSCONFIG_FILE}"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + LC_ALL=C sed -i --follow-symlinks "s/^net.ipv4.conf.default.shared_media\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" +else + if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" + fi + printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_default_shared_media + +- name: List /etc/sysctl.d/*.conf files + find: + paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + contains: ^[\s]*net.ipv4.conf.default.shared_media.*$ + patterns: '*.conf' + file_type: any + register: find_sysctl_d + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_default_shared_media + +- name: Comment out any occurrences of net.ipv4.conf.default.shared_media from config + files + replace: + path: '{{ item.path }}' + regexp: ^[\s]*net.ipv4.conf.default.shared_media + replace: '#net.ipv4.conf.default.shared_media' + loop: '{{ find_sysctl_d.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_default_shared_media +- name: XCCDF Value sysctl_net_ipv4_conf_default_shared_media_value # promote to variable + set_fact: + sysctl_net_ipv4_conf_default_shared_media_value: !!str + tags: + - always + +- name: Ensure sysctl net.ipv4.conf.default.shared_media is set + sysctl: + name: net.ipv4.conf.default.shared_media + value: '{{ sysctl_net_ipv4_conf_default_shared_media_value }}' + sysctl_file: /etc/sysctl.conf + state: present + reload: true + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_default_shared_media + + + + + + + + + + + Enable Kernel Parameter to Ignore ICMP Broadcast Echo Requests on IPv4 Interfaces + To set the runtime status of the net.ipv4.icmp_echo_ignore_broadcasts kernel parameter, run the following command: $ sudo sysctl -w net.ipv4.icmp_echo_ignore_broadcasts=1 +To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv4.icmp_echo_ignore_broadcasts = 1 + + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 18 + 2 + 3 + 4 + 6 + 7 + 8 + 9 + 5.10.1.1 + APO01.06 + APO13.01 + BAI04.04 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS01.03 + DSS01.05 + DSS03.01 + DSS03.05 + DSS05.02 + DSS05.04 + DSS05.05 + DSS05.07 + DSS06.02 + DSS06.06 + 3.1.20 + CCI-000366 + 4.2.3.4 + 4.3.3.4 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.2 + 4.3.4.3.3 + 4.4.3.3 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 6.2 + SR 7.1 + SR 7.2 + SR 7.6 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.12.1.1 + A.12.1.2 + A.12.1.3 + A.12.5.1 + A.12.6.2 + A.13.1.1 + A.13.1.2 + A.13.1.3 + A.13.2.1 + A.13.2.2 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.17.2.1 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CIP-007-3 R4 + CIP-007-3 R4.1 + CIP-007-3 R4.2 + CIP-007-3 R5.1 + CM-7(a) + CM-7(b) + SC-5 + DE.AE-1 + DE.CM-1 + ID.AM-3 + PR.AC-5 + PR.DS-4 + PR.DS-5 + PR.IP-1 + PR.PT-3 + PR.PT-4 + Req-1.4.3 + SRG-OS-000480-GPOS-00227 + A.8.SEC-OL6 + 1.4.2 + 1.4 + OL09-00-006030 + SV-271873r1092331_rule + Responding to broadcast (ICMP) echoes facilitates network mapping +and provides a vector for amplification attacks. + +Ignoring ICMP echo requests (pings) sent to broadcast or multicast +addresses makes the system slightly more difficult to enumerate on the network. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Comment out any occurrences of net.ipv4.icmp_echo_ignore_broadcasts from /etc/sysctl.d/*.conf files + +for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do + + + # skip systemd-sysctl symlink (/etc/sysctl.d/99-sysctl.conf -> /etc/sysctl.conf) + if [[ "$(readlink -f "$f")" == "/etc/sysctl.conf" ]]; then continue; fi + + matching_list=$(grep -P '^(?!#).*[\s]*net.ipv4.icmp_echo_ignore_broadcasts.*$' $f | uniq ) + if ! test -z "$matching_list"; then + while IFS= read -r entry; do + escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") + # comment out "net.ipv4.icmp_echo_ignore_broadcasts" matches to preserve user data + sed -i --follow-symlinks "s/^${escaped_entry}$/# &/g" $f + done <<< "$matching_list" + fi +done + +# +# Set sysctl config file which to save the desired value +# + +SYSCONFIG_FILE="/etc/sysctl.conf" + +sysctl_net_ipv4_icmp_echo_ignore_broadcasts_value='' + + +# +# Set runtime for net.ipv4.icmp_echo_ignore_broadcasts +# +if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then + /sbin/sysctl -q -n -w net.ipv4.icmp_echo_ignore_broadcasts="$sysctl_net_ipv4_icmp_echo_ignore_broadcasts_value" +fi + +# +# If net.ipv4.icmp_echo_ignore_broadcasts present in /etc/sysctl.conf, change value to appropriate value +# else, add "net.ipv4.icmp_echo_ignore_broadcasts = value" to /etc/sysctl.conf +# + +# Strip any search characters in the key arg so that the key can be replaced without +# adding any search characters to the config file. +stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv4.icmp_echo_ignore_broadcasts") + +# shellcheck disable=SC2059 +printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv4_icmp_echo_ignore_broadcasts_value" + +# If the key exists, change it. Otherwise, add it to the config_file. +# We search for the key string followed by a word boundary (matched by \>), +# so if we search for 'setting', 'setting2' won't match. +if LC_ALL=C grep -q -m 1 -i -e "^net.ipv4.icmp_echo_ignore_broadcasts\\>" "${SYSCONFIG_FILE}"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + LC_ALL=C sed -i --follow-symlinks "s/^net.ipv4.icmp_echo_ignore_broadcasts\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" +else + if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" + fi + printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - CJIS-5.10.1.1 + - DISA-STIG-OL09-00-006030 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - PCI-DSS-Req-1.4.3 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.2 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_icmp_echo_ignore_broadcasts + +- name: List /etc/sysctl.d/*.conf files + find: + paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + contains: ^[\s]*net.ipv4.icmp_echo_ignore_broadcasts.*$ + patterns: '*.conf' + file_type: any + register: find_sysctl_d + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.10.1.1 + - DISA-STIG-OL09-00-006030 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - PCI-DSS-Req-1.4.3 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.2 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_icmp_echo_ignore_broadcasts + +- name: Comment out any occurrences of net.ipv4.icmp_echo_ignore_broadcasts from config + files + replace: + path: '{{ item.path }}' + regexp: ^[\s]*net.ipv4.icmp_echo_ignore_broadcasts + replace: '#net.ipv4.icmp_echo_ignore_broadcasts' + loop: '{{ find_sysctl_d.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.10.1.1 + - DISA-STIG-OL09-00-006030 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - PCI-DSS-Req-1.4.3 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.2 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_icmp_echo_ignore_broadcasts +- name: XCCDF Value sysctl_net_ipv4_icmp_echo_ignore_broadcasts_value # promote to variable + set_fact: + sysctl_net_ipv4_icmp_echo_ignore_broadcasts_value: !!str + tags: + - always + +- name: Ensure sysctl net.ipv4.icmp_echo_ignore_broadcasts is set + sysctl: + name: net.ipv4.icmp_echo_ignore_broadcasts + value: '{{ sysctl_net_ipv4_icmp_echo_ignore_broadcasts_value }}' + sysctl_file: /etc/sysctl.conf + state: present + reload: true + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.10.1.1 + - DISA-STIG-OL09-00-006030 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - PCI-DSS-Req-1.4.3 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.2 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_icmp_echo_ignore_broadcasts + + + + + + + + + + + Enable Kernel Parameter to Ignore Bogus ICMP Error Responses on IPv4 Interfaces + To set the runtime status of the net.ipv4.icmp_ignore_bogus_error_responses kernel parameter, run the following command: $ sudo sysctl -w net.ipv4.icmp_ignore_bogus_error_responses=1 +To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv4.icmp_ignore_bogus_error_responses = 1 + + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 2 + 3 + 7 + 8 + 9 + APO13.01 + BAI04.04 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS01.03 + DSS03.05 + DSS05.02 + DSS05.05 + DSS05.07 + DSS06.06 + 3.1.20 + CCI-000366 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.2 + 4.3.4.3.3 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 6.2 + SR 7.1 + SR 7.2 + SR 7.6 + A.12.1.2 + A.12.1.3 + A.12.5.1 + A.12.6.2 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.17.2.1 + A.9.1.2 + CIP-007-3 R4 + CIP-007-3 R4.1 + CIP-007-3 R4.2 + CIP-007-3 R5.1 + CM-7(a) + CM-7(b) + SC-5 + DE.CM-1 + PR.DS-4 + PR.IP-1 + PR.PT-3 + Req-1.4.3 + SRG-OS-000480-GPOS-00227 + R12 + A.8.SEC-OL6 + 1.4.2 + 1.4 + OL09-00-006031 + SV-271874r1092612_rule + Ignoring bogus ICMP error responses reduces +log size, although some activity would not be logged. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Comment out any occurrences of net.ipv4.icmp_ignore_bogus_error_responses from /etc/sysctl.d/*.conf files + +for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do + + + # skip systemd-sysctl symlink (/etc/sysctl.d/99-sysctl.conf -> /etc/sysctl.conf) + if [[ "$(readlink -f "$f")" == "/etc/sysctl.conf" ]]; then continue; fi + + matching_list=$(grep -P '^(?!#).*[\s]*net.ipv4.icmp_ignore_bogus_error_responses.*$' $f | uniq ) + if ! test -z "$matching_list"; then + while IFS= read -r entry; do + escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") + # comment out "net.ipv4.icmp_ignore_bogus_error_responses" matches to preserve user data + sed -i --follow-symlinks "s/^${escaped_entry}$/# &/g" $f + done <<< "$matching_list" + fi +done + +# +# Set sysctl config file which to save the desired value +# + +SYSCONFIG_FILE="/etc/sysctl.conf" + +sysctl_net_ipv4_icmp_ignore_bogus_error_responses_value='' + + +# +# Set runtime for net.ipv4.icmp_ignore_bogus_error_responses +# +if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then + /sbin/sysctl -q -n -w net.ipv4.icmp_ignore_bogus_error_responses="$sysctl_net_ipv4_icmp_ignore_bogus_error_responses_value" +fi + +# +# If net.ipv4.icmp_ignore_bogus_error_responses present in /etc/sysctl.conf, change value to appropriate value +# else, add "net.ipv4.icmp_ignore_bogus_error_responses = value" to /etc/sysctl.conf +# + +# Strip any search characters in the key arg so that the key can be replaced without +# adding any search characters to the config file. +stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv4.icmp_ignore_bogus_error_responses") + +# shellcheck disable=SC2059 +printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv4_icmp_ignore_bogus_error_responses_value" + +# If the key exists, change it. Otherwise, add it to the config_file. +# We search for the key string followed by a word boundary (matched by \>), +# so if we search for 'setting', 'setting2' won't match. +if LC_ALL=C grep -q -m 1 -i -e "^net.ipv4.icmp_ignore_bogus_error_responses\\>" "${SYSCONFIG_FILE}"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + LC_ALL=C sed -i --follow-symlinks "s/^net.ipv4.icmp_ignore_bogus_error_responses\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" +else + if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" + fi + printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-006031 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - PCI-DSS-Req-1.4.3 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.2 + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv4_icmp_ignore_bogus_error_responses + - unknown_severity + +- name: List /etc/sysctl.d/*.conf files + find: + paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + contains: ^[\s]*net.ipv4.icmp_ignore_bogus_error_responses.*$ + patterns: '*.conf' + file_type: any + register: find_sysctl_d + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006031 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - PCI-DSS-Req-1.4.3 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.2 + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv4_icmp_ignore_bogus_error_responses + - unknown_severity + +- name: Comment out any occurrences of net.ipv4.icmp_ignore_bogus_error_responses + from config files + replace: + path: '{{ item.path }}' + regexp: ^[\s]*net.ipv4.icmp_ignore_bogus_error_responses + replace: '#net.ipv4.icmp_ignore_bogus_error_responses' + loop: '{{ find_sysctl_d.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006031 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - PCI-DSS-Req-1.4.3 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.2 + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv4_icmp_ignore_bogus_error_responses + - unknown_severity +- name: XCCDF Value sysctl_net_ipv4_icmp_ignore_bogus_error_responses_value # promote to variable + set_fact: + sysctl_net_ipv4_icmp_ignore_bogus_error_responses_value: !!str + tags: + - always + +- name: Ensure sysctl net.ipv4.icmp_ignore_bogus_error_responses is set + sysctl: + name: net.ipv4.icmp_ignore_bogus_error_responses + value: '{{ sysctl_net_ipv4_icmp_ignore_bogus_error_responses_value }}' + sysctl_file: /etc/sysctl.conf + state: present + reload: true + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006031 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - PCI-DSS-Req-1.4.3 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.2 + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv4_icmp_ignore_bogus_error_responses + - unknown_severity + + + + + + + + + + + Set Kernel Parameter to Increase Local Port Range + To set the runtime status of the net.ipv4.ip_local_port_range kernel parameter, run the following command: $ sudo sysctl -w net.ipv4.ip_local_port_range=32768 65535 +To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv4.ip_local_port_range = 32768 65535 + + R12 + This setting defines the local port range that is used by TCP and UDP to +choose the local port. The first number is the first, the second the last +local port number. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Comment out any occurrences of net.ipv4.ip_local_port_range from /etc/sysctl.d/*.conf files + +for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do + + + # skip systemd-sysctl symlink (/etc/sysctl.d/99-sysctl.conf -> /etc/sysctl.conf) + if [[ "$(readlink -f "$f")" == "/etc/sysctl.conf" ]]; then continue; fi + + matching_list=$(grep -P '^(?!#).*[\s]*net.ipv4.ip_local_port_range.*$' $f | uniq ) + if ! test -z "$matching_list"; then + while IFS= read -r entry; do + escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") + # comment out "net.ipv4.ip_local_port_range" matches to preserve user data + sed -i --follow-symlinks "s/^${escaped_entry}$/# &/g" $f + done <<< "$matching_list" + fi +done + +# +# Set sysctl config file which to save the desired value +# + +SYSCONFIG_FILE="/etc/sysctl.conf" + + +# +# Set runtime for net.ipv4.ip_local_port_range +# +if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then + /sbin/sysctl -q -n -w net.ipv4.ip_local_port_range="32768 65535" +fi + +# +# If net.ipv4.ip_local_port_range present in /etc/sysctl.conf, change value to "32768 65535" +# else, add "net.ipv4.ip_local_port_range = 32768 65535" to /etc/sysctl.conf +# + +# Strip any search characters in the key arg so that the key can be replaced without +# adding any search characters to the config file. +stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv4.ip_local_port_range") + +# shellcheck disable=SC2059 +printf -v formatted_output "%s = %s" "$stripped_key" "32768 65535" + +# If the key exists, change it. Otherwise, add it to the config_file. +# We search for the key string followed by a word boundary (matched by \>), +# so if we search for 'setting', 'setting2' won't match. +if LC_ALL=C grep -q -m 1 -i -e "^net.ipv4.ip_local_port_range\\>" "${SYSCONFIG_FILE}"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + LC_ALL=C sed -i --follow-symlinks "s/^net.ipv4.ip_local_port_range\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" +else + if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" + fi + printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_ip_local_port_range + +- name: List /etc/sysctl.d/*.conf files + find: + paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + contains: ^[\s]*net.ipv4.ip_local_port_range.*$ + patterns: '*.conf' + file_type: any + register: find_sysctl_d + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_ip_local_port_range + +- name: Comment out any occurrences of net.ipv4.ip_local_port_range from config files + replace: + path: '{{ item.path }}' + regexp: ^[\s]*net.ipv4.ip_local_port_range + replace: '#net.ipv4.ip_local_port_range' + loop: '{{ find_sysctl_d.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_ip_local_port_range + +- name: Ensure sysctl net.ipv4.ip_local_port_range is set to 32768 65535 + sysctl: + name: net.ipv4.ip_local_port_range + value: 32768 65535 + sysctl_file: /etc/sysctl.conf + state: present + reload: true + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_ip_local_port_range + + + + + + + + + + Enable Kernel Parameter to Use TCP RFC 1337 on IPv4 Interfaces + To set the runtime status of the net.ipv4.tcp_rfc1337 kernel parameter, run the following command: $ sudo sysctl -w net.ipv4.tcp_rfc1337=1 +To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv4.tcp_rfc1337 = 1 + + R12 + Enable TCP behavior conformant with RFC 1337. When disabled, if a RST is +received in TIME_WAIT state, we close the socket immediately without waiting +for the end of the TIME_WAIT period. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Comment out any occurrences of net.ipv4.tcp_rfc1337 from /etc/sysctl.d/*.conf files + +for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do + + + # skip systemd-sysctl symlink (/etc/sysctl.d/99-sysctl.conf -> /etc/sysctl.conf) + if [[ "$(readlink -f "$f")" == "/etc/sysctl.conf" ]]; then continue; fi + + matching_list=$(grep -P '^(?!#).*[\s]*net.ipv4.tcp_rfc1337.*$' $f | uniq ) + if ! test -z "$matching_list"; then + while IFS= read -r entry; do + escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") + # comment out "net.ipv4.tcp_rfc1337" matches to preserve user data + sed -i --follow-symlinks "s/^${escaped_entry}$/# &/g" $f + done <<< "$matching_list" + fi +done + +# +# Set sysctl config file which to save the desired value +# + +SYSCONFIG_FILE="/etc/sysctl.conf" + +sysctl_net_ipv4_tcp_rfc1337_value='' + + +# +# Set runtime for net.ipv4.tcp_rfc1337 +# +if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then + /sbin/sysctl -q -n -w net.ipv4.tcp_rfc1337="$sysctl_net_ipv4_tcp_rfc1337_value" +fi + +# +# If net.ipv4.tcp_rfc1337 present in /etc/sysctl.conf, change value to appropriate value +# else, add "net.ipv4.tcp_rfc1337 = value" to /etc/sysctl.conf +# + +# Strip any search characters in the key arg so that the key can be replaced without +# adding any search characters to the config file. +stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv4.tcp_rfc1337") + +# shellcheck disable=SC2059 +printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv4_tcp_rfc1337_value" + +# If the key exists, change it. Otherwise, add it to the config_file. +# We search for the key string followed by a word boundary (matched by \>), +# so if we search for 'setting', 'setting2' won't match. +if LC_ALL=C grep -q -m 1 -i -e "^net.ipv4.tcp_rfc1337\\>" "${SYSCONFIG_FILE}"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + LC_ALL=C sed -i --follow-symlinks "s/^net.ipv4.tcp_rfc1337\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" +else + if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" + fi + printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_tcp_rfc1337 + +- name: List /etc/sysctl.d/*.conf files + find: + paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + contains: ^[\s]*net.ipv4.tcp_rfc1337.*$ + patterns: '*.conf' + file_type: any + register: find_sysctl_d + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_tcp_rfc1337 + +- name: Comment out any occurrences of net.ipv4.tcp_rfc1337 from config files + replace: + path: '{{ item.path }}' + regexp: ^[\s]*net.ipv4.tcp_rfc1337 + replace: '#net.ipv4.tcp_rfc1337' + loop: '{{ find_sysctl_d.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_tcp_rfc1337 +- name: XCCDF Value sysctl_net_ipv4_tcp_rfc1337_value # promote to variable + set_fact: + sysctl_net_ipv4_tcp_rfc1337_value: !!str + tags: + - always + +- name: Ensure sysctl net.ipv4.tcp_rfc1337 is set + sysctl: + name: net.ipv4.tcp_rfc1337 + value: '{{ sysctl_net_ipv4_tcp_rfc1337_value }}' + sysctl_file: /etc/sysctl.conf + state: present + reload: true + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_tcp_rfc1337 + + + + + + + + + + + Enable Kernel Parameter to Use TCP Syncookies on Network Interfaces + To set the runtime status of the net.ipv4.tcp_syncookies kernel parameter, run the following command: $ sudo sysctl -w net.ipv4.tcp_syncookies=1 +To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv4.tcp_syncookies = 1 + + 1 + 12 + 13 + 14 + 15 + 16 + 18 + 2 + 4 + 6 + 7 + 8 + 9 + 5.10.1.1 + APO01.06 + APO13.01 + BAI04.04 + DSS01.03 + DSS01.05 + DSS03.01 + DSS03.05 + DSS05.02 + DSS05.04 + DSS05.07 + DSS06.02 + 3.1.20 + CCI-001095 + CCI-000366 + CCI-002385 + 4.2.3.4 + 4.3.3.4 + 4.4.3.3 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 6.2 + SR 7.1 + SR 7.2 + SR 7.6 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.12.1.1 + A.12.1.2 + A.12.1.3 + A.13.1.1 + A.13.1.2 + A.13.1.3 + A.13.2.1 + A.13.2.2 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.17.2.1 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CM-7(a) + CM-7(b) + SC-5(1) + SC-5(2) + SC-5(3)(a) + CM-6(a) + DE.AE-1 + DE.CM-1 + ID.AM-3 + PR.AC-5 + PR.DS-4 + PR.DS-5 + PR.PT-4 + Req-1.4.1 + SRG-OS-000480-GPOS-00227 + SRG-OS-000420-GPOS-00186 + SRG-OS-000142-GPOS-00071 + R12 + A.8.SEC-OL6 + 1.4.3 + 1.4 + OL09-00-006050 + SV-271884r1092364_rule + A TCP SYN flood attack can cause a denial of service by filling a +system's TCP connection table with connections in the SYN_RCVD state. +Syncookies can be used to track a connection when a subsequent ACK is received, +verifying the initiator is attempting a valid connection and is not a flood +source. This feature is activated when a flood condition is detected, and +enables the system to continue servicing valid connection requests. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Comment out any occurrences of net.ipv4.tcp_syncookies from /etc/sysctl.d/*.conf files + +for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do + + + # skip systemd-sysctl symlink (/etc/sysctl.d/99-sysctl.conf -> /etc/sysctl.conf) + if [[ "$(readlink -f "$f")" == "/etc/sysctl.conf" ]]; then continue; fi + + matching_list=$(grep -P '^(?!#).*[\s]*net.ipv4.tcp_syncookies.*$' $f | uniq ) + if ! test -z "$matching_list"; then + while IFS= read -r entry; do + escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") + # comment out "net.ipv4.tcp_syncookies" matches to preserve user data + sed -i --follow-symlinks "s/^${escaped_entry}$/# &/g" $f + done <<< "$matching_list" + fi +done + +# +# Set sysctl config file which to save the desired value +# + +SYSCONFIG_FILE="/etc/sysctl.conf" + +sysctl_net_ipv4_tcp_syncookies_value='' + + +# +# Set runtime for net.ipv4.tcp_syncookies +# +if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then + /sbin/sysctl -q -n -w net.ipv4.tcp_syncookies="$sysctl_net_ipv4_tcp_syncookies_value" +fi + +# +# If net.ipv4.tcp_syncookies present in /etc/sysctl.conf, change value to appropriate value +# else, add "net.ipv4.tcp_syncookies = value" to /etc/sysctl.conf +# + +# Strip any search characters in the key arg so that the key can be replaced without +# adding any search characters to the config file. +stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv4.tcp_syncookies") + +# shellcheck disable=SC2059 +printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv4_tcp_syncookies_value" + +# If the key exists, change it. Otherwise, add it to the config_file. +# We search for the key string followed by a word boundary (matched by \>), +# so if we search for 'setting', 'setting2' won't match. +if LC_ALL=C grep -q -m 1 -i -e "^net.ipv4.tcp_syncookies\\>" "${SYSCONFIG_FILE}"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + LC_ALL=C sed -i --follow-symlinks "s/^net.ipv4.tcp_syncookies\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" +else + if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" + fi + printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - CJIS-5.10.1.1 + - DISA-STIG-OL09-00-006050 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5(1) + - NIST-800-53-SC-5(2) + - NIST-800-53-SC-5(3)(a) + - PCI-DSS-Req-1.4.1 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.3 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_tcp_syncookies + +- name: List /etc/sysctl.d/*.conf files + find: + paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + contains: ^[\s]*net.ipv4.tcp_syncookies.*$ + patterns: '*.conf' + file_type: any + register: find_sysctl_d + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.10.1.1 + - DISA-STIG-OL09-00-006050 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5(1) + - NIST-800-53-SC-5(2) + - NIST-800-53-SC-5(3)(a) + - PCI-DSS-Req-1.4.1 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.3 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_tcp_syncookies + +- name: Comment out any occurrences of net.ipv4.tcp_syncookies from config files + replace: + path: '{{ item.path }}' + regexp: ^[\s]*net.ipv4.tcp_syncookies + replace: '#net.ipv4.tcp_syncookies' + loop: '{{ find_sysctl_d.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.10.1.1 + - DISA-STIG-OL09-00-006050 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5(1) + - NIST-800-53-SC-5(2) + - NIST-800-53-SC-5(3)(a) + - PCI-DSS-Req-1.4.1 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.3 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_tcp_syncookies +- name: XCCDF Value sysctl_net_ipv4_tcp_syncookies_value # promote to variable + set_fact: + sysctl_net_ipv4_tcp_syncookies_value: !!str + tags: + - always + +- name: Ensure sysctl net.ipv4.tcp_syncookies is set + sysctl: + name: net.ipv4.tcp_syncookies + value: '{{ sysctl_net_ipv4_tcp_syncookies_value }}' + sysctl_file: /etc/sysctl.conf + state: present + reload: true + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.10.1.1 + - DISA-STIG-OL09-00-006050 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5(1) + - NIST-800-53-SC-5(2) + - NIST-800-53-SC-5(3)(a) + - PCI-DSS-Req-1.4.1 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.3 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_tcp_syncookies + + + + + + + + + + + + Network Parameters for Hosts Only + If the system is not going to be used as a router, then setting certain +kernel parameters ensure that the host will not perform routing +of network traffic. + + + Disable Kernel Parameter for Sending ICMP Redirects on all IPv4 Interfaces + To set the runtime status of the net.ipv4.conf.all.send_redirects kernel parameter, run the following command: $ sudo sysctl -w net.ipv4.conf.all.send_redirects=0 +To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv4.conf.all.send_redirects = 0 + + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 18 + 2 + 3 + 4 + 6 + 7 + 8 + 9 + 5.10.1.1 + APO01.06 + APO13.01 + BAI04.04 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS01.03 + DSS01.05 + DSS03.01 + DSS03.05 + DSS05.02 + DSS05.04 + DSS05.05 + DSS05.07 + DSS06.02 + DSS06.06 + 3.1.20 + CCI-000366 + 4.2.3.4 + 4.3.3.4 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.2 + 4.3.4.3.3 + 4.4.3.3 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 6.2 + SR 7.1 + SR 7.2 + SR 7.6 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.12.1.1 + A.12.1.2 + A.12.1.3 + A.12.5.1 + A.12.6.2 + A.13.1.1 + A.13.1.2 + A.13.1.3 + A.13.2.1 + A.13.2.2 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.17.2.1 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CIP-007-3 R4 + CIP-007-3 R4.1 + CIP-007-3 R4.2 + CIP-007-3 R5.1 + CM-7(a) + CM-7(b) + SC-5 + CM-6(a) + SC-7(a) + DE.AE-1 + DE.CM-1 + ID.AM-3 + PR.AC-5 + PR.DS-4 + PR.DS-5 + PR.IP-1 + PR.PT-3 + PR.PT-4 + SRG-OS-000480-GPOS-00227 + R12 + A.8.SEC-OL6 + 1.4.5 + 1.4 + OL09-00-006032 + SV-271875r1092337_rule + ICMP redirect messages are used by routers to inform hosts that a more +direct route exists for a particular destination. These messages contain information +from the system's route table possibly revealing portions of the network topology. + +The ability to send ICMP redirects is only appropriate for systems acting as routers. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Comment out any occurrences of net.ipv4.conf.all.send_redirects from /etc/sysctl.d/*.conf files + +for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do + + + # skip systemd-sysctl symlink (/etc/sysctl.d/99-sysctl.conf -> /etc/sysctl.conf) + if [[ "$(readlink -f "$f")" == "/etc/sysctl.conf" ]]; then continue; fi + + matching_list=$(grep -P '^(?!#).*[\s]*net.ipv4.conf.all.send_redirects.*$' $f | uniq ) + if ! test -z "$matching_list"; then + while IFS= read -r entry; do + escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") + # comment out "net.ipv4.conf.all.send_redirects" matches to preserve user data + sed -i --follow-symlinks "s/^${escaped_entry}$/# &/g" $f + done <<< "$matching_list" + fi +done + +# +# Set sysctl config file which to save the desired value +# + +SYSCONFIG_FILE="/etc/sysctl.conf" + + +# +# Set runtime for net.ipv4.conf.all.send_redirects +# +if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then + /sbin/sysctl -q -n -w net.ipv4.conf.all.send_redirects="0" +fi + +# +# If net.ipv4.conf.all.send_redirects present in /etc/sysctl.conf, change value to "0" +# else, add "net.ipv4.conf.all.send_redirects = 0" to /etc/sysctl.conf +# + +# Strip any search characters in the key arg so that the key can be replaced without +# adding any search characters to the config file. +stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv4.conf.all.send_redirects") + +# shellcheck disable=SC2059 +printf -v formatted_output "%s = %s" "$stripped_key" "0" + +# If the key exists, change it. Otherwise, add it to the config_file. +# We search for the key string followed by a word boundary (matched by \>), +# so if we search for 'setting', 'setting2' won't match. +if LC_ALL=C grep -q -m 1 -i -e "^net.ipv4.conf.all.send_redirects\\>" "${SYSCONFIG_FILE}"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + LC_ALL=C sed -i --follow-symlinks "s/^net.ipv4.conf.all.send_redirects\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" +else + if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" + fi + printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - CJIS-5.10.1.1 + - DISA-STIG-OL09-00-006032 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - NIST-800-53-SC-7(a) + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.5 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_send_redirects + +- name: List /etc/sysctl.d/*.conf files + find: + paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + contains: ^[\s]*net.ipv4.conf.all.send_redirects.*$ + patterns: '*.conf' + file_type: any + register: find_sysctl_d + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.10.1.1 + - DISA-STIG-OL09-00-006032 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - NIST-800-53-SC-7(a) + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.5 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_send_redirects + +- name: Comment out any occurrences of net.ipv4.conf.all.send_redirects from config + files + replace: + path: '{{ item.path }}' + regexp: ^[\s]*net.ipv4.conf.all.send_redirects + replace: '#net.ipv4.conf.all.send_redirects' + loop: '{{ find_sysctl_d.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.10.1.1 + - DISA-STIG-OL09-00-006032 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - NIST-800-53-SC-7(a) + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.5 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_send_redirects + +- name: Ensure sysctl net.ipv4.conf.all.send_redirects is set to 0 + sysctl: + name: net.ipv4.conf.all.send_redirects + value: '0' + sysctl_file: /etc/sysctl.conf + state: present + reload: true + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.10.1.1 + - DISA-STIG-OL09-00-006032 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - NIST-800-53-SC-7(a) + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.5 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_send_redirects + + + + + + + + + + Disable Kernel Parameter for Sending ICMP Redirects on all IPv4 Interfaces by Default + To set the runtime status of the net.ipv4.conf.default.send_redirects kernel parameter, run the following command: $ sudo sysctl -w net.ipv4.conf.default.send_redirects=0 +To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv4.conf.default.send_redirects = 0 + + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 18 + 2 + 3 + 4 + 6 + 7 + 8 + 9 + 5.10.1.1 + APO01.06 + APO13.01 + BAI04.04 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS01.03 + DSS01.05 + DSS03.01 + DSS03.05 + DSS05.02 + DSS05.04 + DSS05.05 + DSS05.07 + DSS06.02 + DSS06.06 + 3.1.20 + CCI-000366 + 4.2.3.4 + 4.3.3.4 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.2 + 4.3.4.3.3 + 4.4.3.3 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 6.2 + SR 7.1 + SR 7.2 + SR 7.6 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.12.1.1 + A.12.1.2 + A.12.1.3 + A.12.5.1 + A.12.6.2 + A.13.1.1 + A.13.1.2 + A.13.1.3 + A.13.2.1 + A.13.2.2 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.17.2.1 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CIP-007-3 R4 + CIP-007-3 R4.1 + CIP-007-3 R4.2 + CIP-007-3 R5.1 + CM-7(a) + CM-7(b) + SC-5 + CM-6(a) + SC-7(a) + DE.AE-1 + DE.CM-1 + ID.AM-3 + PR.AC-5 + PR.DS-4 + PR.DS-5 + PR.IP-1 + PR.PT-3 + PR.PT-4 + SRG-OS-000480-GPOS-00227 + R12 + A.8.SEC-OL6 + 1.4.5 + 1.4 + OL09-00-006033 + SV-271876r1092641_rule + ICMP redirect messages are used by routers to inform hosts that a more +direct route exists for a particular destination. These messages contain information +from the system's route table possibly revealing portions of the network topology. + +The ability to send ICMP redirects is only appropriate for systems acting as routers. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Comment out any occurrences of net.ipv4.conf.default.send_redirects from /etc/sysctl.d/*.conf files + +for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do + + + # skip systemd-sysctl symlink (/etc/sysctl.d/99-sysctl.conf -> /etc/sysctl.conf) + if [[ "$(readlink -f "$f")" == "/etc/sysctl.conf" ]]; then continue; fi + + matching_list=$(grep -P '^(?!#).*[\s]*net.ipv4.conf.default.send_redirects.*$' $f | uniq ) + if ! test -z "$matching_list"; then + while IFS= read -r entry; do + escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") + # comment out "net.ipv4.conf.default.send_redirects" matches to preserve user data + sed -i --follow-symlinks "s/^${escaped_entry}$/# &/g" $f + done <<< "$matching_list" + fi +done + +# +# Set sysctl config file which to save the desired value +# + +SYSCONFIG_FILE="/etc/sysctl.conf" + + +# +# Set runtime for net.ipv4.conf.default.send_redirects +# +if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then + /sbin/sysctl -q -n -w net.ipv4.conf.default.send_redirects="0" +fi + +# +# If net.ipv4.conf.default.send_redirects present in /etc/sysctl.conf, change value to "0" +# else, add "net.ipv4.conf.default.send_redirects = 0" to /etc/sysctl.conf +# + +# Strip any search characters in the key arg so that the key can be replaced without +# adding any search characters to the config file. +stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv4.conf.default.send_redirects") + +# shellcheck disable=SC2059 +printf -v formatted_output "%s = %s" "$stripped_key" "0" + +# If the key exists, change it. Otherwise, add it to the config_file. +# We search for the key string followed by a word boundary (matched by \>), +# so if we search for 'setting', 'setting2' won't match. +if LC_ALL=C grep -q -m 1 -i -e "^net.ipv4.conf.default.send_redirects\\>" "${SYSCONFIG_FILE}"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + LC_ALL=C sed -i --follow-symlinks "s/^net.ipv4.conf.default.send_redirects\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" +else + if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" + fi + printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - CJIS-5.10.1.1 + - DISA-STIG-OL09-00-006033 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - NIST-800-53-SC-7(a) + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.5 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_default_send_redirects + +- name: List /etc/sysctl.d/*.conf files + find: + paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + contains: ^[\s]*net.ipv4.conf.default.send_redirects.*$ + patterns: '*.conf' + file_type: any + register: find_sysctl_d + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.10.1.1 + - DISA-STIG-OL09-00-006033 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - NIST-800-53-SC-7(a) + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.5 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_default_send_redirects + +- name: Comment out any occurrences of net.ipv4.conf.default.send_redirects from config + files + replace: + path: '{{ item.path }}' + regexp: ^[\s]*net.ipv4.conf.default.send_redirects + replace: '#net.ipv4.conf.default.send_redirects' + loop: '{{ find_sysctl_d.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.10.1.1 + - DISA-STIG-OL09-00-006033 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - NIST-800-53-SC-7(a) + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.5 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_default_send_redirects + +- name: Ensure sysctl net.ipv4.conf.default.send_redirects is set to 0 + sysctl: + name: net.ipv4.conf.default.send_redirects + value: '0' + sysctl_file: /etc/sysctl.conf + state: present + reload: true + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.10.1.1 + - DISA-STIG-OL09-00-006033 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - NIST-800-53-SC-7(a) + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.5 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_default_send_redirects + + + + + + + + + + Disable Kernel Parameter for IP Forwarding on IPv4 Interfaces + To set the runtime status of the net.ipv4.ip_forward kernel parameter, run the following command: $ sudo sysctl -w net.ipv4.ip_forward=0 +To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv4.ip_forward = 0 + + Certain technologies such as virtual machines, containers, etc. rely on IPv4 forwarding to enable and use networking. +Disabling IPv4 forwarding would cause those technologies to stop working. Therefore, this rule should not be used in +profiles or benchmarks that target usage of IPv4 forwarding. + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 2 + 3 + 7 + 8 + 9 + APO13.01 + BAI04.04 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS01.03 + DSS03.05 + DSS05.02 + DSS05.05 + DSS05.07 + DSS06.06 + 3.1.20 + CCI-000366 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.2 + 4.3.4.3.3 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 6.2 + SR 7.1 + SR 7.2 + SR 7.6 + A.12.1.2 + A.12.1.3 + A.12.5.1 + A.12.6.2 + A.13.1.1 + A.13.2.1 + A.14.1.3 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.17.2.1 + A.9.1.2 + CIP-007-3 R4 + CIP-007-3 R4.1 + CIP-007-3 R4.2 + CIP-007-3 R5.1 + CM-7(a) + CM-7(b) + SC-5 + CM-6(a) + SC-7(a) + DE.CM-1 + PR.DS-4 + PR.IP-1 + PR.PT-3 + PR.PT-4 + Req-1.3.1 + Req-1.3.2 + SRG-OS-000480-GPOS-00227 + R12 + A.8.SEC-OL6 + 1.4.3 + 1.4 + Routing protocol daemons are typically used on routers to exchange +network topology information with other routers. If this capability is used when +not required, system network information may be unnecessarily transmitted across +the network. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Comment out any occurrences of net.ipv4.ip_forward from /etc/sysctl.d/*.conf files + +for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do + + + # skip systemd-sysctl symlink (/etc/sysctl.d/99-sysctl.conf -> /etc/sysctl.conf) + if [[ "$(readlink -f "$f")" == "/etc/sysctl.conf" ]]; then continue; fi + + matching_list=$(grep -P '^(?!#).*[\s]*net.ipv4.ip_forward.*$' $f | uniq ) + if ! test -z "$matching_list"; then + while IFS= read -r entry; do + escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") + # comment out "net.ipv4.ip_forward" matches to preserve user data + sed -i --follow-symlinks "s/^${escaped_entry}$/# &/g" $f + done <<< "$matching_list" + fi +done + +# +# Set sysctl config file which to save the desired value +# + +SYSCONFIG_FILE="/etc/sysctl.conf" + + +# +# Set runtime for net.ipv4.ip_forward +# +if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then + /sbin/sysctl -q -n -w net.ipv4.ip_forward="0" +fi + +# +# If net.ipv4.ip_forward present in /etc/sysctl.conf, change value to "0" +# else, add "net.ipv4.ip_forward = 0" to /etc/sysctl.conf +# + +# Strip any search characters in the key arg so that the key can be replaced without +# adding any search characters to the config file. +stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv4.ip_forward") + +# shellcheck disable=SC2059 +printf -v formatted_output "%s = %s" "$stripped_key" "0" + +# If the key exists, change it. Otherwise, add it to the config_file. +# We search for the key string followed by a word boundary (matched by \>), +# so if we search for 'setting', 'setting2' won't match. +if LC_ALL=C grep -q -m 1 -i -e "^net.ipv4.ip_forward\\>" "${SYSCONFIG_FILE}"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + LC_ALL=C sed -i --follow-symlinks "s/^net.ipv4.ip_forward\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" +else + if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" + fi + printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - NIST-800-53-SC-7(a) + - PCI-DSS-Req-1.3.1 + - PCI-DSS-Req-1.3.2 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.3 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_ip_forward + +- name: List /etc/sysctl.d/*.conf files + find: + paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + contains: ^[\s]*net.ipv4.ip_forward.*$ + patterns: '*.conf' + file_type: any + register: find_sysctl_d + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - NIST-800-53-SC-7(a) + - PCI-DSS-Req-1.3.1 + - PCI-DSS-Req-1.3.2 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.3 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_ip_forward + +- name: Comment out any occurrences of net.ipv4.ip_forward from config files + replace: + path: '{{ item.path }}' + regexp: ^[\s]*net.ipv4.ip_forward + replace: '#net.ipv4.ip_forward' + loop: '{{ find_sysctl_d.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - NIST-800-53-SC-7(a) + - PCI-DSS-Req-1.3.1 + - PCI-DSS-Req-1.3.2 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.3 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_ip_forward + +- name: Ensure sysctl net.ipv4.ip_forward is set to 0 + sysctl: + name: net.ipv4.ip_forward + value: '0' + sysctl_file: /etc/sysctl.conf + state: present + reload: true + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - NIST-800-53-SC-7(a) + - PCI-DSS-Req-1.3.1 + - PCI-DSS-Req-1.3.2 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.3 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_ip_forward + + + + + + + + + + + + nftables + If firewalld or iptables are being used in your environment, please follow the guidance in their +respective section and pass-over the guidance in this section. +nftables is a subsystem of the Linux kernel providing filtering and classification of network +packets/datagrams/frames and is the successor to iptables. The biggest change with the +successor nftables is its simplicity. With iptables, we have to configure every single rule and +use the syntax which can be compared with normal commands. With nftables, the simpler +syntax, much like BPF (Berkely Packet Filter) means shorter lines and less repetition. +Support for nftables should also be compiled into the kernel, together with the related +nftables modules. + + +It is available in Linux kernels >= 3.13. Please ensure that your kernel +supports nftables before choosing this option. + + + Install nftables Package + nftables provides a new in-kernel packet classification framework that is based on a +network-specific Virtual Machine (VM) and a new nft userspace command line tool. +nftables reuses the existing Netfilter subsystems such as the existing hook infrastructure, +the connection tracking system, NAT, userspace queuing and logging subsystem. +The nftables package can be installed with the following command: + +$ sudo yum install nftables + + 1.2.1 + 1.2 + nftables is a subsystem of the Linux kernel that can protect against threats +originating from within a corporate network to include malicious mobile code and poorly +configured software on a host. + + # Remediation is applicable only in certain platforms +if ( rpm --quiet -q kernel || rpm --quiet -q kernel-uek ); then + +if ! rpm -q --quiet "nftables" ; then + yum install -y "nftables" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - PCI-DSSv4-1.2 + - PCI-DSSv4-1.2.1 + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - package_nftables_installed + +- name: Ensure nftables is installed + package: + name: nftables + state: present + when: ( ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + ) + tags: + - PCI-DSSv4-1.2 + - PCI-DSSv4-1.2.1 + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - package_nftables_installed + + include install_nftables + +class install_nftables { + package { 'nftables': + ensure => 'installed', + } +} + + +package --add=nftables + + +[[packages]] +name = "nftables" +version = "*" + + + + + + + + + + Verify nftables Service is Disabled + nftables is a subsystem of the Linux kernel providing filtering and classification of network +packets/datagrams/frames and is the successor to iptables. +The nftables service can be disabled with the following command: +systemctl disable nftables + + A.8.SEC-OL3 + 1.2.1 + 1.2 + Running both firewalld and nftables may lead to conflict. nftables +is actually one of the backends for firewalld management tools. + + # Remediation is applicable only in certain platforms +if ( rpm --quiet -q firewalld && rpm --quiet -q nftables && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ); then + +SYSTEMCTL_EXEC='/usr/bin/systemctl' +if [[ $("$SYSTEMCTL_EXEC" is-system-running) != "offline" ]]; then + "$SYSTEMCTL_EXEC" stop 'nftables.service' +fi +"$SYSTEMCTL_EXEC" disable 'nftables.service' +"$SYSTEMCTL_EXEC" mask 'nftables.service' +# Disable socket activation if we have a unit file for it +if "$SYSTEMCTL_EXEC" -q list-unit-files nftables.socket; then + if [[ $("$SYSTEMCTL_EXEC" is-system-running) != "offline" ]]; then + "$SYSTEMCTL_EXEC" stop 'nftables.socket' + fi + "$SYSTEMCTL_EXEC" mask 'nftables.socket' +fi +# The service may not be running because it has been started and failed, +# so let's reset the state so OVAL checks pass. +# Service should be 'inactive', not 'failed' after reboot though. +"$SYSTEMCTL_EXEC" reset-failed 'nftables.service' || true + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - PCI-DSSv4-1.2 + - PCI-DSSv4-1.2.1 + - disable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_nftables_disabled + +- name: Verify nftables Service is Disabled - Collect systemd Services Present in + the System + ansible.builtin.command: systemctl -q list-unit-files --type service + register: service_exists + changed_when: false + failed_when: service_exists.rc not in [0, 1] + check_mode: false + when: ( "firewalld" in ansible_facts.packages and "nftables" in ansible_facts.packages + and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + ) + tags: + - PCI-DSSv4-1.2 + - PCI-DSSv4-1.2.1 + - disable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_nftables_disabled + +- name: Verify nftables Service is Disabled - Ensure nftables.service is Masked + ansible.builtin.systemd: + name: nftables.service + state: stopped + enabled: false + masked: true + when: + - ( "firewalld" in ansible_facts.packages and "nftables" in ansible_facts.packages + and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + ) + - service_exists.stdout_lines is search("nftables.service", multiline=True) + tags: + - PCI-DSSv4-1.2 + - PCI-DSSv4-1.2.1 + - disable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_nftables_disabled + +- name: Unit Socket Exists - nftables.socket + ansible.builtin.command: systemctl -q list-unit-files nftables.socket + register: socket_file_exists + changed_when: false + failed_when: socket_file_exists.rc not in [0, 1] + check_mode: false + when: ( "firewalld" in ansible_facts.packages and "nftables" in ansible_facts.packages + and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + ) + tags: + - PCI-DSSv4-1.2 + - PCI-DSSv4-1.2.1 + - disable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_nftables_disabled + +- name: Verify nftables Service is Disabled - Disable Socket nftables + ansible.builtin.systemd: + name: nftables.socket + enabled: false + state: stopped + masked: true + when: + - ( "firewalld" in ansible_facts.packages and "nftables" in ansible_facts.packages + and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + ) + - socket_file_exists.stdout_lines is search("nftables.socket", multiline=True) + tags: + - PCI-DSSv4-1.2 + - PCI-DSSv4-1.2.1 + - disable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_nftables_disabled + + include disable_nftables + +class disable_nftables { + service {'nftables': + enable => false, + ensure => 'stopped', + } +} + + +[customizations.services] +masked = ["nftables"] + + + + + + + + + + Verify Group Who Owns /etc/nftables Directory + To properly set the group owner of /etc/nftables, run the command: $ sudo chgrp root /etc/nftables + + R50 + The ownership of the /etc/nftables directory by the root group is important +because this directory hosts nftables configuration. Protection of this +directory is critical for system security. Assigning the ownership to root +ensures exclusive control of the nftables configuration. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q nftables; then + +find -H /etc/nftables/ -maxdepth 1 -type d -exec chgrp -L root {} \; + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - configure_strategy + - directory_groupowner_etc_nftables + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure group owner on /etc/nftables/ + file: + path: /etc/nftables/ + state: directory + group: root + when: '"nftables" in ansible_facts.packages' + tags: + - configure_strategy + - directory_groupowner_etc_nftables + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify User Who Owns /etc/nftables Directory + To properly set the owner of /etc/nftables, run the command: $ sudo chown root /etc/nftables + + R50 + The ownership of the /etc/nftables directory by the root user is important +because this directory hosts nftables configuration. Protection of this +directory is critical for system security. Assigning the ownership to root +ensures exclusive control of the nftables configuration. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q nftables; then + +find -H /etc/nftables/ -maxdepth 1 -type d -exec chown -L 0 {} \; + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - configure_strategy + - directory_owner_etc_nftables + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure owner on directory /etc/nftables/ + file: + path: /etc/nftables/ + state: directory + owner: '0' + when: '"nftables" in ansible_facts.packages' + tags: + - configure_strategy + - directory_owner_etc_nftables + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify Permissions On /etc/nftables Directory + To properly set the permissions of /etc/nftables, run the command: $ sudo chmod 0700 /etc/nftables + + R50 + Setting correct permissions on the /etc/nftables directory is important +because this directory hosts nftables configuration. Protection of this +directory is critical for system security. Restricting the permissions +ensures exclusive control of the nftables configuration. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q nftables; then + +find -H /etc/nftables/ -maxdepth 1 -perm /u+s,g+xwrs,o+xwrt -type d -exec chmod u-s,g-xwrs,o-xwrt {} \; + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - configure_strategy + - directory_permissions_etc_nftables + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Find /etc/nftables/ file(s) + command: 'find -H /etc/nftables/ -maxdepth 1 -perm /u+s,g+xwrs,o+xwrt -type d ' + register: files_found + changed_when: false + failed_when: false + check_mode: false + when: '"nftables" in ansible_facts.packages' + tags: + - configure_strategy + - directory_permissions_etc_nftables + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Set permissions for /etc/nftables/ file(s) + file: + path: '{{ item }}' + mode: u-s,g-xwrs,o-xwrt + state: directory + with_items: + - '{{ files_found.stdout_lines }}' + when: '"nftables" in ansible_facts.packages' + tags: + - configure_strategy + - directory_permissions_etc_nftables + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + + Uncomplicated Firewall (ufw) + The Linux kernel in Ubuntu provides a packet filtering system called +netfilter, and the traditional interface for manipulating netfilter are +the iptables suite of commands. iptables provide a complete firewall +solution that is both highly configurable and highly flexible. + +Becoming proficient in iptables takes time, and getting started with +netfilter firewalling using only iptables can be a daunting task. As a +result, many frontends for iptables have been created over the years, +each trying to achieve a different result and targeting a different +audience. + +The Uncomplicated Firewall (ufw) is a frontend for iptables and is +particularly well-suited for host-based firewalls. ufw provides a +framework for managing netfilter, as well as a command-line interface +for manipulating the firewall. ufw aims to provide an easy to use +interface for people unfamiliar with firewall concepts, while at the +same time simplifies complicated iptables commands to help an +administrator who knows what he or she is doing. ufw is an upstream +for other distributions and graphical frontends. + + + Verify ufw Enabled + +The ufw service can be enabled with the following command: +$ sudo systemctl enable ufw.service + + CCI-002314 + SRG-OS-000297-GPOS-00115 + The ufw service must be enabled and running in order for ufw to protect the system + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { ( rpm --quiet -q ufw && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ); }; then + +SYSTEMCTL_EXEC='/usr/bin/systemctl' +"$SYSTEMCTL_EXEC" unmask 'ufw.service' +if [[ $("$SYSTEMCTL_EXEC" is-system-running) != "offline" ]]; then + "$SYSTEMCTL_EXEC" start 'ufw.service' +fi +"$SYSTEMCTL_EXEC" enable 'ufw.service' + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_ufw_enabled + +- name: Verify ufw Enabled - Enable service ufw + block: + + - name: Gather the package facts + package_facts: + manager: auto + + - name: Verify ufw Enabled - Enable Service ufw + ansible.builtin.systemd: + name: ufw + enabled: true + state: started + masked: false + when: + - '"ufw" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - ( "ufw" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" + in ansible_facts.packages) ) + tags: + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_ufw_enabled + + include enable_ufw + +class enable_ufw { + service {'ufw': + enable => true, + ensure => 'running', + } +} + + +[customizations.services] +enabled = ["ufw"] + + + + + + + + + + + Uncommon Network Protocols + The system includes support for several network protocols which are not commonly used. +Although security vulnerabilities in kernel networking code are not frequently discovered, +the consequences can be dramatic. Ensuring uncommon network protocols are disabled +reduces the system's risk to attacks targeted at its implementation of those protocols. + Although these protocols are not commonly used, avoid disruption +in your network environment by ensuring they are not needed +prior to disabling them. + + + Disable ATM Support + The Asynchronous Transfer Mode (ATM) is a protocol operating on +network, data link, and physical layers, based on virtual circuits +and virtual paths. + +To configure the system to prevent the atm +kernel module from being loaded, add the following line to the file /etc/modprobe.d/atm.conf: +install atm /bin/false + +To configure the system to prevent the atm from being used, +add the following line to file /etc/modprobe.d/atm.conf: +blacklist atm + + CCI-000381 + AC-18 + SRG-OS-000095-GPOS-00049 + SRG-OS-000480-GPOS-00227 + OL09-00-000040 + SV-271443r1092463_rule + Disabling ATM protects the system against exploitation of any +flaws in its implementation. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +if LC_ALL=C grep -q -m 1 "^install atm" /etc/modprobe.d/atm.conf ; then + + sed -i 's#^install atm.*#install atm /bin/false#g' /etc/modprobe.d/atm.conf +else + echo -e "\n# Disable per security requirements" >> /etc/modprobe.d/atm.conf + echo "install atm /bin/false" >> /etc/modprobe.d/atm.conf +fi + +if ! LC_ALL=C grep -q -m 1 "^blacklist atm$" /etc/modprobe.d/atm.conf ; then + echo "blacklist atm" >> /etc/modprobe.d/atm.conf +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-000040 + - NIST-800-53-AC-18 + - disable_strategy + - kernel_module_atm_disabled + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + +- name: Ensure kernel module 'atm' is disabled + lineinfile: + create: true + dest: /etc/modprobe.d/atm.conf + regexp: install\s+atm + line: install atm /bin/false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-000040 + - NIST-800-53-AC-18 + - disable_strategy + - kernel_module_atm_disabled + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + +- name: Ensure kernel module 'atm' is blacklisted + lineinfile: + create: true + dest: /etc/modprobe.d/atm.conf + regexp: ^blacklist atm$ + line: blacklist atm + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-000040 + - NIST-800-53-AC-18 + - disable_strategy + - kernel_module_atm_disabled + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + + + + + + + + + + Disable CAN Support + The Controller Area Network (CAN) is a serial communications +protocol which was initially developed for automotive and +is now also used in marine, industrial, and medical applications. + +To configure the system to prevent the can +kernel module from being loaded, add the following line to the file /etc/modprobe.d/can.conf: +install can /bin/false + +To configure the system to prevent the can from being used, +add the following line to file /etc/modprobe.d/can.conf: +blacklist can + + CCI-000381 + AC-18 + FMT_SMF_EXT.1 + SRG-OS-000095-GPOS-00049 + SRG-OS-000480-GPOS-00227 + OL09-00-000041 + SV-271444r1091044_rule + Disabling CAN protects the system against exploitation of any +flaws in its implementation. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +if LC_ALL=C grep -q -m 1 "^install can" /etc/modprobe.d/can.conf ; then + + sed -i 's#^install can.*#install can /bin/false#g' /etc/modprobe.d/can.conf +else + echo -e "\n# Disable per security requirements" >> /etc/modprobe.d/can.conf + echo "install can /bin/false" >> /etc/modprobe.d/can.conf +fi + +if ! LC_ALL=C grep -q -m 1 "^blacklist can$" /etc/modprobe.d/can.conf ; then + echo "blacklist can" >> /etc/modprobe.d/can.conf +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-000041 + - NIST-800-53-AC-18 + - disable_strategy + - kernel_module_can_disabled + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + +- name: Ensure kernel module 'can' is disabled + lineinfile: + create: true + dest: /etc/modprobe.d/can.conf + regexp: install\s+can + line: install can /bin/false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-000041 + - NIST-800-53-AC-18 + - disable_strategy + - kernel_module_can_disabled + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + +- name: Ensure kernel module 'can' is blacklisted + lineinfile: + create: true + dest: /etc/modprobe.d/can.conf + regexp: ^blacklist can$ + line: blacklist can + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-000041 + - NIST-800-53-AC-18 + - disable_strategy + - kernel_module_can_disabled + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + + + + + + + + + + Disable DCCP Support + The Datagram Congestion Control Protocol (DCCP) is a +relatively new transport layer protocol, designed to support +streaming media and telephony. + +To configure the system to prevent the dccp +kernel module from being loaded, add the following line to the file /etc/modprobe.d/dccp.conf: +install dccp /bin/false + +To configure the system to prevent the dccp from being used, +add the following line to file /etc/modprobe.d/dccp.conf: +blacklist dccp + + 11 + 14 + 3 + 9 + 5.10.1 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS05.02 + DSS05.05 + DSS06.06 + 3.4.6 + CCI-001958 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.2 + 4.3.4.3.3 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 7.6 + A.12.1.2 + A.12.5.1 + A.12.6.2 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.9.1.2 + CM-7(a) + CM-7(b) + CM-6(a) + PR.IP-1 + PR.PT-3 + Req-1.4.2 + SRG-OS-000096-GPOS-00050 + SRG-OS-000378-GPOS-00163 + 1.4.2 + 1.4 + Disabling DCCP protects +the system against exploitation of any flaws in its implementation. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +if LC_ALL=C grep -q -m 1 "^install dccp" /etc/modprobe.d/dccp.conf ; then + + sed -i 's#^install dccp.*#install dccp /bin/false#g' /etc/modprobe.d/dccp.conf +else + echo -e "\n# Disable per security requirements" >> /etc/modprobe.d/dccp.conf + echo "install dccp /bin/false" >> /etc/modprobe.d/dccp.conf +fi + +if ! LC_ALL=C grep -q -m 1 "^blacklist dccp$" /etc/modprobe.d/dccp.conf ; then + echo "blacklist dccp" >> /etc/modprobe.d/dccp.conf +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - CJIS-5.10.1 + - NIST-800-171-3.4.6 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - PCI-DSS-Req-1.4.2 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.2 + - disable_strategy + - kernel_module_dccp_disabled + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + +- name: Ensure kernel module 'dccp' is disabled + lineinfile: + create: true + dest: /etc/modprobe.d/dccp.conf + regexp: install\s+dccp + line: install dccp /bin/false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.10.1 + - NIST-800-171-3.4.6 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - PCI-DSS-Req-1.4.2 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.2 + - disable_strategy + - kernel_module_dccp_disabled + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + +- name: Ensure kernel module 'dccp' is blacklisted + lineinfile: + create: true + dest: /etc/modprobe.d/dccp.conf + regexp: ^blacklist dccp$ + line: blacklist dccp + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.10.1 + - NIST-800-171-3.4.6 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - PCI-DSS-Req-1.4.2 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.2 + - disable_strategy + - kernel_module_dccp_disabled + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + + + + + + + + + + Disable IEEE 1394 (FireWire) Support + The IEEE 1394 (FireWire) is a serial bus standard for +high-speed real-time communication. + +To configure the system to prevent the firewire-core +kernel module from being loaded, add the following line to the file /etc/modprobe.d/firewire-core.conf: +install firewire-core /bin/false + +To configure the system to prevent the firewire-core from being used, +add the following line to file /etc/modprobe.d/firewire-core.conf: +blacklist firewire-core + + CCI-000381 + AC-18 + SRG-OS-000095-GPOS-00049 + OL09-00-000042 + SV-271445r1091047_rule + Disabling FireWire protects the system against exploitation of any +flaws in its implementation. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +if LC_ALL=C grep -q -m 1 "^install firewire-core" /etc/modprobe.d/firewire-core.conf ; then + + sed -i 's#^install firewire-core.*#install firewire-core /bin/false#g' /etc/modprobe.d/firewire-core.conf +else + echo -e "\n# Disable per security requirements" >> /etc/modprobe.d/firewire-core.conf + echo "install firewire-core /bin/false" >> /etc/modprobe.d/firewire-core.conf +fi + +if ! LC_ALL=C grep -q -m 1 "^blacklist firewire-core$" /etc/modprobe.d/firewire-core.conf ; then + echo "blacklist firewire-core" >> /etc/modprobe.d/firewire-core.conf +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-000042 + - NIST-800-53-AC-18 + - disable_strategy + - kernel_module_firewire-core_disabled + - low_complexity + - low_severity + - medium_disruption + - reboot_required + +- name: Ensure kernel module 'firewire-core' is disabled + lineinfile: + create: true + dest: /etc/modprobe.d/firewire-core.conf + regexp: install\s+firewire-core + line: install firewire-core /bin/false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-000042 + - NIST-800-53-AC-18 + - disable_strategy + - kernel_module_firewire-core_disabled + - low_complexity + - low_severity + - medium_disruption + - reboot_required + +- name: Ensure kernel module 'firewire-core' is blacklisted + lineinfile: + create: true + dest: /etc/modprobe.d/firewire-core.conf + regexp: ^blacklist firewire-core$ + line: blacklist firewire-core + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-000042 + - NIST-800-53-AC-18 + - disable_strategy + - kernel_module_firewire-core_disabled + - low_complexity + - low_severity + - medium_disruption + - reboot_required + + + + + + + + + + Disable RDS Support + The Reliable Datagram Sockets (RDS) protocol is a transport +layer protocol designed to provide reliable high-bandwidth, +low-latency communications between nodes in a cluster. + +To configure the system to prevent the rds +kernel module from being loaded, add the following line to the file /etc/modprobe.d/rds.conf: +install rds /bin/false + +To configure the system to prevent the rds from being used, +add the following line to file /etc/modprobe.d/rds.conf: +blacklist rds + + 11 + 14 + 3 + 9 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS05.02 + DSS05.05 + DSS06.06 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.2 + 4.3.4.3.3 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 7.6 + A.12.1.2 + A.12.5.1 + A.12.6.2 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.9.1.2 + CM-7(a) + CM-7(b) + CM-6(a) + PR.IP-1 + PR.PT-3 + Disabling RDS protects +the system against exploitation of any flaws in its implementation. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +if LC_ALL=C grep -q -m 1 "^install rds" /etc/modprobe.d/rds.conf ; then + + sed -i 's#^install rds.*#install rds /bin/false#g' /etc/modprobe.d/rds.conf +else + echo -e "\n# Disable per security requirements" >> /etc/modprobe.d/rds.conf + echo "install rds /bin/false" >> /etc/modprobe.d/rds.conf +fi + +if ! LC_ALL=C grep -q -m 1 "^blacklist rds$" /etc/modprobe.d/rds.conf ; then + echo "blacklist rds" >> /etc/modprobe.d/rds.conf +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - kernel_module_rds_disabled + - low_complexity + - low_severity + - medium_disruption + - reboot_required + +- name: Ensure kernel module 'rds' is disabled + lineinfile: + create: true + dest: /etc/modprobe.d/rds.conf + regexp: install\s+rds + line: install rds /bin/false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - kernel_module_rds_disabled + - low_complexity + - low_severity + - medium_disruption + - reboot_required + +- name: Ensure kernel module 'rds' is blacklisted + lineinfile: + create: true + dest: /etc/modprobe.d/rds.conf + regexp: ^blacklist rds$ + line: blacklist rds + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - kernel_module_rds_disabled + - low_complexity + - low_severity + - medium_disruption + - reboot_required + + + + + + + + + + Disable SCTP Support + The Stream Control Transmission Protocol (SCTP) is a +transport layer protocol, designed to support the idea of +message-oriented communication, with several streams of messages +within one connection. + +To configure the system to prevent the sctp +kernel module from being loaded, add the following line to the file /etc/modprobe.d/sctp.conf: +install sctp /bin/false + +To configure the system to prevent the sctp from being used, +add the following line to file /etc/modprobe.d/sctp.conf: +blacklist sctp + + 11 + 14 + 3 + 9 + 5.10.1 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS05.02 + DSS05.05 + DSS06.06 + 3.4.6 + CCI-000381 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.2 + 4.3.4.3.3 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 7.6 + A.12.1.2 + A.12.5.1 + A.12.6.2 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.9.1.2 + CM-7(a) + CM-7(b) + CM-6(a) + PR.IP-1 + PR.PT-3 + FMT_SMF_EXT.1 + Req-1.4.2 + SRG-OS-000095-GPOS-00049 + SRG-OS-000480-GPOS-00227 + 1.4.2 + 1.4 + OL09-00-000043 + SV-271446r1091050_rule + Disabling SCTP protects +the system against exploitation of any flaws in its implementation. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +if LC_ALL=C grep -q -m 1 "^install sctp" /etc/modprobe.d/sctp.conf ; then + + sed -i 's#^install sctp.*#install sctp /bin/false#g' /etc/modprobe.d/sctp.conf +else + echo -e "\n# Disable per security requirements" >> /etc/modprobe.d/sctp.conf + echo "install sctp /bin/false" >> /etc/modprobe.d/sctp.conf +fi + +if ! LC_ALL=C grep -q -m 1 "^blacklist sctp$" /etc/modprobe.d/sctp.conf ; then + echo "blacklist sctp" >> /etc/modprobe.d/sctp.conf +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - CJIS-5.10.1 + - DISA-STIG-OL09-00-000043 + - NIST-800-171-3.4.6 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - PCI-DSS-Req-1.4.2 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.2 + - disable_strategy + - kernel_module_sctp_disabled + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + +- name: Ensure kernel module 'sctp' is disabled + lineinfile: + create: true + dest: /etc/modprobe.d/sctp.conf + regexp: install\s+sctp + line: install sctp /bin/false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.10.1 + - DISA-STIG-OL09-00-000043 + - NIST-800-171-3.4.6 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - PCI-DSS-Req-1.4.2 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.2 + - disable_strategy + - kernel_module_sctp_disabled + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + +- name: Ensure kernel module 'sctp' is blacklisted + lineinfile: + create: true + dest: /etc/modprobe.d/sctp.conf + regexp: ^blacklist sctp$ + line: blacklist sctp + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.10.1 + - DISA-STIG-OL09-00-000043 + - NIST-800-171-3.4.6 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - PCI-DSS-Req-1.4.2 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.2 + - disable_strategy + - kernel_module_sctp_disabled + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + + + + + + + + + + Disable TIPC Support + The Transparent Inter-Process Communication (TIPC) protocol +is designed to provide communications between nodes in a +cluster. + +To configure the system to prevent the tipc +kernel module from being loaded, add the following line to the file /etc/modprobe.d/tipc.conf: +install tipc /bin/false + +To configure the system to prevent the tipc from being used, +add the following line to file /etc/modprobe.d/tipc.conf: +blacklist tipc + + This configuration baseline was created to deploy the base operating system for general purpose +workloads. When the operating system is configured for certain purposes, such as +a node in High Performance Computing cluster, it is expected that +the tipc kernel module will be loaded. + 11 + 14 + 3 + 9 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS05.02 + DSS05.05 + DSS06.06 + CCI-000381 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.2 + 4.3.4.3.3 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 7.6 + A.12.1.2 + A.12.5.1 + A.12.6.2 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.9.1.2 + CM-7(a) + CM-7(b) + CM-6(a) + PR.IP-1 + PR.PT-3 + FMT_SMF_EXT.1 + SRG-OS-000095-GPOS-00049 + OL09-00-000044 + SV-271447r1092464_rule + Disabling TIPC protects +the system against exploitation of any flaws in its implementation. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +if LC_ALL=C grep -q -m 1 "^install tipc" /etc/modprobe.d/tipc.conf ; then + + sed -i 's#^install tipc.*#install tipc /bin/false#g' /etc/modprobe.d/tipc.conf +else + echo -e "\n# Disable per security requirements" >> /etc/modprobe.d/tipc.conf + echo "install tipc /bin/false" >> /etc/modprobe.d/tipc.conf +fi + +if ! LC_ALL=C grep -q -m 1 "^blacklist tipc$" /etc/modprobe.d/tipc.conf ; then + echo "blacklist tipc" >> /etc/modprobe.d/tipc.conf +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-000044 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - kernel_module_tipc_disabled + - low_complexity + - low_severity + - medium_disruption + - reboot_required + +- name: Ensure kernel module 'tipc' is disabled + lineinfile: + create: true + dest: /etc/modprobe.d/tipc.conf + regexp: install\s+tipc + line: install tipc /bin/false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-000044 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - kernel_module_tipc_disabled + - low_complexity + - low_severity + - medium_disruption + - reboot_required + +- name: Ensure kernel module 'tipc' is blacklisted + lineinfile: + create: true + dest: /etc/modprobe.d/tipc.conf + regexp: ^blacklist tipc$ + line: blacklist tipc + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-000044 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - kernel_module_tipc_disabled + - low_complexity + - low_severity + - medium_disruption + - reboot_required + + + + + + + + + + + Wireless Networking + Wireless networking, such as 802.11 +(WiFi) and Bluetooth, can present a security risk to sensitive or +classified systems and networks. Wireless networking hardware is +much more likely to be included in laptop or portable systems than +in desktops or servers. + + +Removal of hardware provides the greatest assurance that the wireless +capability remains disabled. Acquisition policies often include provisions to +prevent the purchase of equipment that will be used in sensitive spaces and +includes wireless capabilities. If it is impractical to remove the wireless +hardware, and policy permits the device to enter sensitive spaces as long +as wireless is disabled, efforts should instead focus on disabling wireless capability +via software. + + Disable Wireless Through Software Configuration + If it is impossible to remove the wireless hardware +from the device in question, disable as much of it as possible +through software. The following methods can disable software +support for wireless networking, but note that these methods do not +prevent malicious software or careless users from re-activating the +devices. + + Disable Bluetooth Kernel Module + The kernel's module loading system can be configured to prevent +loading of the Bluetooth module. Add the following to +the appropriate /etc/modprobe.d configuration file +to prevent the loading of the Bluetooth module: +install bluetooth /bin/true + + 11 + 12 + 14 + 15 + 3 + 8 + 9 + 5.13.1.3 + APO13.01 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS01.04 + DSS05.02 + DSS05.03 + DSS05.05 + DSS06.06 + 3.1.16 + CCI-001443 + CCI-000381 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.2 + 4.3.4.3.3 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 7.1 + SR 7.6 + A.11.2.6 + A.12.1.2 + A.12.5.1 + A.12.6.2 + A.13.1.1 + A.13.2.1 + A.14.1.3 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.6.2.1 + A.6.2.2 + A.9.1.2 + AC-18(a) + AC-18(3) + CM-7(a) + CM-7(b) + CM-6(a) + MP-7 + PR.AC-3 + PR.IP-1 + PR.PT-3 + PR.PT-4 + FMT_SMF_EXT.1 + SRG-OS-000095-GPOS-00049 + SRG-OS-000300-GPOS-00118 + OL09-00-000046 + SV-271449r1091059_rule + If Bluetooth functionality must be disabled, preventing the kernel +from loading the kernel module provides an additional safeguard against its +activation. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +if LC_ALL=C grep -q -m 1 "^install bluetooth" /etc/modprobe.d/bluetooth.conf ; then + + sed -i 's#^install bluetooth.*#install bluetooth /bin/false#g' /etc/modprobe.d/bluetooth.conf +else + echo -e "\n# Disable per security requirements" >> /etc/modprobe.d/bluetooth.conf + echo "install bluetooth /bin/false" >> /etc/modprobe.d/bluetooth.conf +fi + +if ! LC_ALL=C grep -q -m 1 "^blacklist bluetooth$" /etc/modprobe.d/bluetooth.conf ; then + echo "blacklist bluetooth" >> /etc/modprobe.d/bluetooth.conf +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - CJIS-5.13.1.3 + - DISA-STIG-OL09-00-000046 + - NIST-800-171-3.1.16 + - NIST-800-53-AC-18(3) + - NIST-800-53-AC-18(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - disable_strategy + - kernel_module_bluetooth_disabled + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + +- name: Ensure kernel module 'bluetooth' is disabled + lineinfile: + create: true + dest: /etc/modprobe.d/bluetooth.conf + regexp: install\s+bluetooth + line: install bluetooth /bin/false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.13.1.3 + - DISA-STIG-OL09-00-000046 + - NIST-800-171-3.1.16 + - NIST-800-53-AC-18(3) + - NIST-800-53-AC-18(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - disable_strategy + - kernel_module_bluetooth_disabled + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + +- name: Ensure kernel module 'bluetooth' is blacklisted + lineinfile: + create: true + dest: /etc/modprobe.d/bluetooth.conf + regexp: ^blacklist bluetooth$ + line: blacklist bluetooth + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.13.1.3 + - DISA-STIG-OL09-00-000046 + - NIST-800-171-3.1.16 + - NIST-800-53-AC-18(3) + - NIST-800-53-AC-18(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - disable_strategy + - kernel_module_bluetooth_disabled + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + + + + + + + + + + Deactivate Wireless Network Interfaces + Deactivating wireless network interfaces should prevent normal usage of the wireless +capability. + + + +Configure the system to disable all wireless network interfaces with the following command: +$ sudo nmcli radio all off + + 11 + 12 + 14 + 15 + 3 + 8 + 9 + APO13.01 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS01.04 + DSS05.02 + DSS05.03 + DSS05.05 + DSS06.06 + 3.1.16 + CCI-001443 + CCI-001444 + CCI-002421 + CCI-002418 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.2 + 4.3.4.3.3 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 7.1 + SR 7.6 + 1315 + 1319 + A.11.2.6 + A.12.1.2 + A.12.5.1 + A.12.6.2 + A.13.1.1 + A.13.2.1 + A.14.1.3 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.6.2.1 + A.6.2.2 + A.9.1.2 + AC-18(a) + AC-18(3) + CM-7(a) + CM-7(b) + CM-6(a) + MP-7 + PR.AC-3 + PR.IP-1 + PR.PT-3 + PR.PT-4 + Req-1.3.3 + SRG-OS-000299-GPOS-00117 + SRG-OS-000300-GPOS-00118 + SRG-OS-000424-GPOS-00188 + SRG-OS-000481-GPOS-000481 + 1.3.3 + 1.3 + OL09-00-006001 + SV-271859r1092289_rule + The use of wireless networking can introduce many different attack vectors into +the organization's network. Common attack vectors such as malicious association +and ad hoc networks will allow an attacker to spoof a wireless access point +(AP), allowing validated systems to connect to the malicious AP and enabling the +attacker to monitor and record network traffic. These malicious APs can also +serve to create a man-in-the-middle attack or be used to create a denial of +service to valid network resources. + + +if ! rpm -q --quiet "NetworkManager" ; then + yum install -y "NetworkManager" +fi + +if command -v nmcli >/dev/null 2>&1 && systemctl is-active NetworkManager >/dev/null 2>&1; then + nmcli radio all off +fi + +if command -v wicked >/dev/null 2>&1 && systemctl is-active wickedd >/dev/null 2>&1; then + if [ -n "$(find /sys/class/net/*/ -type d -name wireless)" ]; then + interfaces=$(find /sys/class/net/*/wireless -type d -name wireless | xargs -0 dirname | xargs basename) + for iface in $interfaces; do + wicked ifdown $iface + sed -i 's/STARTMODE=.*/STARTMODE=off/' /etc/sysconfig/network/ifcfg-$iface + done + fi +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-006001 + - NIST-800-171-3.1.16 + - NIST-800-53-AC-18(3) + - NIST-800-53-AC-18(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - PCI-DSS-Req-1.3.3 + - PCI-DSSv4-1.3 + - PCI-DSSv4-1.3.3 + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - unknown_strategy + - wireless_disable_interfaces + +- name: Service facts + ansible.builtin.service_facts: null + tags: + - DISA-STIG-OL09-00-006001 + - NIST-800-171-3.1.16 + - NIST-800-53-AC-18(3) + - NIST-800-53-AC-18(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - PCI-DSS-Req-1.3.3 + - PCI-DSSv4-1.3 + - PCI-DSSv4-1.3.3 + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - unknown_strategy + - wireless_disable_interfaces + +- name: Ensure NetworkManager is installed + ansible.builtin.package: + name: '{{ item }}' + state: present + with_items: + - NetworkManager + tags: + - DISA-STIG-OL09-00-006001 + - NIST-800-171-3.1.16 + - NIST-800-53-AC-18(3) + - NIST-800-53-AC-18(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - PCI-DSS-Req-1.3.3 + - PCI-DSSv4-1.3 + - PCI-DSSv4-1.3.3 + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - unknown_strategy + - wireless_disable_interfaces + +- name: NetworkManager Deactivate Wireless Network Interfaces + command: nmcli radio wifi off + when: + - '''NetworkManager'' in ansible_facts.packages' + - ansible_facts.services['NetworkManager.service'].state == 'running' + tags: + - DISA-STIG-OL09-00-006001 + - NIST-800-171-3.1.16 + - NIST-800-53-AC-18(3) + - NIST-800-53-AC-18(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - PCI-DSS-Req-1.3.3 + - PCI-DSSv4-1.3 + - PCI-DSSv4-1.3.3 + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - unknown_strategy + - wireless_disable_interfaces + + + + + + + + + + + + Network Manager + The NetworkManager daemon configures a variety of network connections. +This section discusses how to configure NetworkManager. + + NetworkManager DNS Mode + This sets how NetworkManager handles DNS. + +none - NetworkManager will not modify resolv.conf. +default - NetworkManager will update /etc/resolv.conf to reflect the nameservers provided by currently active connections. + none + default + default + + + NetworkManager DNS Mode Must Be Must Configured + The DNS processing mode in NetworkManager describes how DNS is processed on the system. Depending the mode some changes the system's DNS may not be respected. + CCI-000366 + CM-6(b) + SRG-OS-000480-GPOS-00227 + OL09-00-006002 + SV-271860r1092292_rule + To ensure that DNS resolver settings are respected, a DNS mode in NetworkManager must be configured. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q NetworkManager; then + +var_networkmanager_dns_mode='' + + + +# Try find '[main]' and 'dns' in '/etc/NetworkManager/NetworkManager.conf', if it exists, set +# to '$var_networkmanager_dns_mode', if it isn't here, add it, if '[main]' doesn't exist, add it there +if grep -qzosP '[[:space:]]*\[main]([^\n\[]*\n+)+?[[:space:]]*dns' '/etc/NetworkManager/NetworkManager.conf'; then + + sed -i "s/dns[^(\n)]*/dns=$var_networkmanager_dns_mode/" '/etc/NetworkManager/NetworkManager.conf' +elif grep -qs '[[:space:]]*\[main]' '/etc/NetworkManager/NetworkManager.conf'; then + sed -i "/[[:space:]]*\[main]/a dns=$var_networkmanager_dns_mode" '/etc/NetworkManager/NetworkManager.conf' +else + if test -d "/etc/NetworkManager"; then + printf '%s\n' '[main]' "dns=$var_networkmanager_dns_mode" >> '/etc/NetworkManager/NetworkManager.conf' + else + echo "Config file directory '/etc/NetworkManager' doesnt exist, not remediating, assuming non-applicability." >&2 + fi +fi + +if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then + systemctl reload NetworkManager +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-006002 + - NIST-800-53-CM-6(b) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - networkmanager_dns_mode + - no_reboot_needed +- name: XCCDF Value var_networkmanager_dns_mode # promote to variable + set_fact: + var_networkmanager_dns_mode: !!str + tags: + - always + +- name: Set 'dns' to '{{ var_networkmanager_dns_mode }}' in the [main] section of + '/etc/NetworkManager/NetworkManager.conf' + ini_file: + path: /etc/NetworkManager/NetworkManager.conf + section: main + option: dns + value: '{{ var_networkmanager_dns_mode }}' + create: true + mode: 420 + no_extra_spaces: true + when: '"NetworkManager" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-006002 + - NIST-800-53-CM-6(b) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - networkmanager_dns_mode + - no_reboot_needed + +- name: NetworkManager DNS Mode Must Be Must Configured - Ensure Network Manager + ansible.builtin.systemd: + name: NetworkManager + state: reloaded + when: '"NetworkManager" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-006002 + - NIST-800-53-CM-6(b) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - networkmanager_dns_mode + - no_reboot_needed + + + + + + + + + + + + File Permissions and Masks + Traditional Unix security relies heavily on file and +directory permissions to prevent unauthorized users from reading or +modifying files to which they should not have access. + + +Several of the commands in this section search filesystems +for files or directories with certain characteristics, and are +intended to be run on every local partition on a given system. +When the variable PART appears in one of the commands below, +it means that the command is intended to be run repeatedly, with the +name of each local partition substituted for PART in turn. + + +The following command prints a list of all xfs partitions on the local +system, which is the default filesystem for Oracle Linux 9 +installations: +$ mount -t xfs | awk '{print $3}' +For any systems that use a different +local filesystem type, modify this command as appropriate. + + Verify Permissions on Important Files and +Directories + Permissions for many files on a system must be set +restrictively to ensure sensitive information is properly protected. +This section discusses important +permission restrictions which can be verified +to ensure that no harmful discrepancies have +arisen. + + Ensure All World-Writable Directories Are Owned by root User + All directories in local partitions which are world-writable should be owned by root. +If any world-writable directories are not owned by root, this should be investigated. +Following this, the files should be deleted or assigned to root user. + CCI-000366 + CCI-001090 + SRG-OS-000480-GPOS-00227 + SRG-OS-000138-GPOS-00069 + R54 + OL09-00-002516 + SV-271785r1092067_rule + Allowing a user account to own a world-writable directory is undesirable because it allows the +owner of that directory to remove or replace any files that may be placed in the directory by +other users. + +# At least under containerized env /proc can have files w/o possilibity to +# modify even as root. And touching /proc is not good idea anyways. +find / -path /proc -prune -o \ + -not -fstype afs -not -fstype ceph -not -fstype cifs -not -fstype smb3 -not -fstype smbfs \ + -not -fstype sshfs -not -fstype ncpfs -not -fstype ncp -not -fstype nfs -not -fstype nfs4 \ + -not -fstype gfs -not -fstype gfs2 -not -fstype glusterfs -not -fstype gpfs \ + -not -fstype pvfs2 -not -fstype ocfs2 -not -fstype lustre -not -fstype davfs \ + -not -fstype fuse.sshfs -type d -perm -0002 -uid +0 -exec chown root {} \; + + - name: Ensure All World-Writable Directories Are Owned by root User - Define Excluded + (Non-Local) File Systems and Paths + ansible.builtin.set_fact: + excluded_fstypes: + - afs + - ceph + - cifs + - smb3 + - smbfs + - sshfs + - ncpfs + - ncp + - nfs + - nfs4 + - gfs + - gfs2 + - glusterfs + - gpfs + - pvfs2 + - ocfs2 + - lustre + - davfs + - fuse.sshfs + excluded_paths: + - dev + - proc + - run + - sys + search_paths: [] + tags: + - DISA-STIG-OL09-00-002516 + - dir_perms_world_writable_root_owned + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure All World-Writable Directories Are Owned by root User - Find Relevant + Root Directories Ignoring Pre-Defined Excluded Paths + ansible.builtin.find: + paths: / + file_type: directory + excludes: '{{ excluded_paths }}' + hidden: true + recurse: false + register: result_relevant_root_dirs + tags: + - DISA-STIG-OL09-00-002516 + - dir_perms_world_writable_root_owned + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure All World-Writable Directories Are Owned by root User - Include Relevant + Root Directories in a List of Paths to be Searched + ansible.builtin.set_fact: + search_paths: '{{ search_paths | union([item.path]) }}' + loop: '{{ result_relevant_root_dirs.files }}' + tags: + - DISA-STIG-OL09-00-002516 + - dir_perms_world_writable_root_owned + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure All World-Writable Directories Are Owned by root User - Increment Search + Paths List with Local Partitions Mount Points + ansible.builtin.set_fact: + search_paths: '{{ search_paths | union([item.mount]) }}' + loop: '{{ ansible_mounts }}' + when: + - item.fstype not in excluded_fstypes + - item.mount != '/' + tags: + - DISA-STIG-OL09-00-002516 + - dir_perms_world_writable_root_owned + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure All World-Writable Directories Are Owned by root User - Increment Search + Paths List with Local NFS File System Targets + ansible.builtin.set_fact: + search_paths: '{{ search_paths | union([item.device.split('':'')[1]]) }}' + loop: '{{ ansible_mounts }}' + when: item.device is search("localhost:") + tags: + - DISA-STIG-OL09-00-002516 + - dir_perms_world_writable_root_owned + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure All World-Writable Directories Are Owned by root User - Define Rule + Specific Facts + ansible.builtin.set_fact: + world_writable_dirs: [] + tags: + - DISA-STIG-OL09-00-002516 + - dir_perms_world_writable_root_owned + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure All World-Writable Directories Are Owned by root User - Find All Uncompliant + Directories in Local File Systems + ansible.builtin.command: + cmd: find {{ item }} -xdev -type d -perm -0002 -uid +0 + loop: '{{ search_paths }}' + changed_when: false + register: result_found_dirs + tags: + - DISA-STIG-OL09-00-002516 + - dir_perms_world_writable_root_owned + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure All World-Writable Directories Are Owned by root User - Create List + of World Writable Directories Not Owned by root + ansible.builtin.set_fact: + world_writable_dirs: '{{ world_writable_dirs | union(item.stdout_lines) | list + }}' + loop: '{{ result_found_dirs.results }}' + when: item is not skipped + tags: + - DISA-STIG-OL09-00-002516 + - dir_perms_world_writable_root_owned + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure All World-Writable Directories Are Owned by root User - Ensure root + Ownership on Local World Writable Directories + ansible.builtin.file: + path: '{{ item }}' + owner: root + loop: '{{ world_writable_dirs }}' + tags: + - DISA-STIG-OL09-00-002516 + - dir_perms_world_writable_root_owned + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + + + + + + + + + + Verify that All World-Writable Directories Have Sticky Bits Set + When the so-called 'sticky bit' is set on a directory, only the owner of a given file may +remove that file from the directory. Without the sticky bit, any user with write access to a +directory may remove any file in the directory. Setting the sticky bit prevents users from +removing each other's files. In cases where there is no reason for a directory to be +world-writable, a better solution is to remove that permission rather than to set the sticky +bit. However, if a directory is used by a particular application, consult that application's +documentation instead of blindly changing modes. + +To set the sticky bit on a world-writable directory DIR, run the following command: +$ sudo chmod +t DIR + + + This rule can take a long time to perform the check and might consume a considerable +amount of resources depending on the number of directories present on the system. It is +not a problem in most cases, but especially systems with a large number of directories can +be affected. See https://access.redhat.com/articles/6999111. + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + APO01.06 + DSS05.04 + DSS05.07 + DSS06.02 + CCI-001090 + 4.3.3.7.3 + SR 2.1 + SR 5.2 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 + CM-6(a) + AC-6(1) + PR.AC-4 + PR.DS-5 + SRG-OS-000138-GPOS-00069 + R54 + 2.2.6 + 2.2 + OL09-00-002510 + SV-271779r1092049_rule + Failing to set the sticky bit on public directories allows unauthorized users to delete files +in the directory structure. + + +The only authorized public directories are those temporary directories supplied with the +system, or those designed to be temporary file repositories. The setting is normally reserved +for directories used by the system, by users for temporary file storage (such as /tmp), +and for directories requiring global read/write access. + df --local -P | awk '{if (NR!=1) print $6}' \ +| xargs -I '$6' find '$6' -xdev -type d \ +\( -perm -0002 -a ! -perm -1000 \) 2>/dev/null \ +-exec chmod a+t {} + + + - name: Verify that All World-Writable Directories Have Sticky Bits Set - Define Excluded + (Non-Local) File Systems and Paths + ansible.builtin.set_fact: + excluded_fstypes: + - afs + - ceph + - cifs + - smb3 + - smbfs + - sshfs + - ncpfs + - ncp + - nfs + - nfs4 + - gfs + - gfs2 + - glusterfs + - gpfs + - pvfs2 + - ocfs2 + - lustre + - davfs + - fuse.sshfs + excluded_paths: + - dev + - proc + - run + - sys + search_paths: [] + tags: + - DISA-STIG-OL09-00-002510 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - dir_perms_world_writable_sticky_bits + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Verify that All World-Writable Directories Have Sticky Bits Set - Find Relevant + Root Directories Ignoring Pre-Defined Excluded Paths + ansible.builtin.find: + paths: / + file_type: directory + excludes: '{{ excluded_paths }}' + hidden: true + recurse: false + register: result_relevant_root_dirs + tags: + - DISA-STIG-OL09-00-002510 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - dir_perms_world_writable_sticky_bits + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Verify that All World-Writable Directories Have Sticky Bits Set - Include + Relevant Root Directories in a List of Paths to be Searched + ansible.builtin.set_fact: + search_paths: '{{ search_paths | union([item.path]) }}' + loop: '{{ result_relevant_root_dirs.files }}' + tags: + - DISA-STIG-OL09-00-002510 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - dir_perms_world_writable_sticky_bits + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Verify that All World-Writable Directories Have Sticky Bits Set - Increment + Search Paths List with Local Partitions Mount Points + ansible.builtin.set_fact: + search_paths: '{{ search_paths | union([item.mount]) }}' + loop: '{{ ansible_mounts }}' + when: + - item.fstype not in excluded_fstypes + - item.mount != '/' + tags: + - DISA-STIG-OL09-00-002510 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - dir_perms_world_writable_sticky_bits + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Verify that All World-Writable Directories Have Sticky Bits Set - Increment + Search Paths List with Local NFS File System Targets + ansible.builtin.set_fact: + search_paths: '{{ search_paths | union([item.device.split('':'')[1]]) }}' + loop: '{{ ansible_mounts }}' + when: item.device is search("localhost:") + tags: + - DISA-STIG-OL09-00-002510 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - dir_perms_world_writable_sticky_bits + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Verify that All World-Writable Directories Have Sticky Bits Set - Define Rule + Specific Facts + ansible.builtin.set_fact: + world_writable_dirs: [] + tags: + - DISA-STIG-OL09-00-002510 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - dir_perms_world_writable_sticky_bits + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Verify that All World-Writable Directories Have Sticky Bits Set - Find All + Uncompliant Directories in Local File Systems + ansible.builtin.command: + cmd: find {{ item }} -xdev -type d ( -perm -0002 -a ! -perm -1000 ) + loop: '{{ search_paths }}' + changed_when: false + register: result_found_dirs + tags: + - DISA-STIG-OL09-00-002510 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - dir_perms_world_writable_sticky_bits + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Verify that All World-Writable Directories Have Sticky Bits Set - Create List + of World Writable Directories Without Sticky Bit + ansible.builtin.set_fact: + world_writable_dirs: '{{ world_writable_dirs | union(item.stdout_lines) | list + }}' + loop: '{{ result_found_dirs.results }}' + when: result_found_dirs is not skipped and item is not skipped + tags: + - DISA-STIG-OL09-00-002510 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - dir_perms_world_writable_sticky_bits + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Verify that All World-Writable Directories Have Sticky Bits Set - Ensure Sticky + Bit is Set on Local World Writable Directories + ansible.builtin.file: + path: '{{ item }}' + mode: a+t + loop: '{{ world_writable_dirs }}' + tags: + - DISA-STIG-OL09-00-002510 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - dir_perms_world_writable_sticky_bits + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + + + + + + + + + + Verify that system commands directories have root as a group owner + System commands are stored in the following directories: +by default: +/bin +/sbin +/usr/bin +/usr/sbin +/usr/local/bin +/usr/local/sbin + +All these directories should have root user as a group owner. +If any system command directory is not group owned by a user other than root +correct its ownership with the following command: +$ sudo chgrp root DIR + + + CCI-001499 + CM-5(6) + CM-5(6).1 + SRG-OS-000259-GPOS-00100 + R50 + If the operating system were to allow any user to make changes to +software libraries, then those changes might be implemented without +undergoing the appropriate testing and approvals that are part of a +robust change management process. + +This requirement applies to operating systems with software libraries +that are accessible and configurable, as in the case of interpreted languages. +Software libraries also include privileged programs which execute with escalated +privileges. Only qualified and authorized individuals must be allowed to obtain +access to information system components for purposes of initiating changes, +including upgrades and modifications. + + + + + + + + + Verify that system commands directories have root ownership + System commands are stored in the following directories by default: +/bin +/sbin +/usr/bin +/usr/sbin +/usr/local/bin +/usr/local/sbin + +All these directories should be owned by the root user. +If any system command directory is not owned by a user other than root +correct its ownership with the following command: +$ sudo chown root DIR + + + CCI-001499 + CM-5(6) + CM-5(6).1 + SRG-OS-000259-GPOS-00100 + R50 + If the operating system were to allow any user to make changes to +software libraries, then those changes might be implemented without +undergoing the appropriate testing and approvals that are part of a +robust change management process. + +This requirement applies to operating systems with software libraries +that are accessible and configurable, as in the case of interpreted languages. +Software libraries also include privileged programs which execute with escalated +privileges. Only qualified and authorized individuals must be allowed to obtain +access to information system components for purposes of initiating changes, +including upgrades and modifications. + + + + + + + + + Verify Group Who Owns /etc/crypttab File + To properly set the group owner of /etc/crypttab, run the command: $ sudo chgrp root /etc/crypttab + + R50 + The ownership of the /etc/crypttab file by the root group is important +because this file hosts encrypted block devices configuration. Protection +of this file is critical for system security. Assigning the ownership to +root ensures exclusive control of the encrypted block devices +configuration. + chgrp root /etc/crypttab + + - name: Test for existence /etc/crypttab + stat: + path: /etc/crypttab + register: file_exists + tags: + - configure_strategy + - file_groupowner_etc_crypttab + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure group owner root on /etc/crypttab + file: + path: /etc/crypttab + group: root + when: file_exists.stat is defined and file_exists.stat.exists + tags: + - configure_strategy + - file_groupowner_etc_crypttab + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify Group Who Owns System.map Files + The System.map files are symbol map files generated during the compilation of the Linux +kernel. They contain the mapping between kernel symbols and their corresponding memory +addresses. These files must be group-owned by root. + + +To properly set the group owner of /boot/System.map*, run the command: +$ sudo chgrp root /boot/System.map* + + R29 + The purpose of System.map files is primarily for debugging and profiling the kernel. +Unrestricted access to these files might disclose information useful to attackers and +malicious software leading to more sophisticated exploitation. + +find -L /boot/ -maxdepth 1 -type f ! -group root -regextype posix-extended -regex '^.*System\.map.*$' -exec chgrp -L root {} \; + + - name: Find /boot/ file(s) matching ^.*System\.map.*$ + command: find -H /boot/ -maxdepth 1 -type f ! -group root -regextype posix-extended + -regex "^.*System\.map.*$" + register: files_found + changed_when: false + failed_when: false + check_mode: false + tags: + - configure_strategy + - file_groupowner_systemmap + - low_complexity + - low_disruption + - low_severity + - no_reboot_needed + +- name: Ensure group owner on /boot/ file(s) matching ^.*System\.map.*$ + file: + path: '{{ item }}' + group: root + state: file + with_items: + - '{{ files_found.stdout_lines }}' + tags: + - configure_strategy + - file_groupowner_systemmap + - low_complexity + - low_disruption + - low_severity + - no_reboot_needed + + + + + + + + + + Verify User Who Owns /etc/crypttab File + To properly set the owner of /etc/crypttab, run the command: $ sudo chown root /etc/crypttab + + R50 + The ownership of the /etc/crypttab file by the root user is important +because this file hosts encrypted block devices configuration. Protection +of this file is critical for system security. Assigning the ownership to +root ensures exclusive control of the encrypted block devices +configuration. + chown 0 /etc/crypttab + + - name: Test for existence /etc/crypttab + stat: + path: /etc/crypttab + register: file_exists + tags: + - configure_strategy + - file_owner_etc_crypttab + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure owner 0 on /etc/crypttab + file: + path: /etc/crypttab + owner: '0' + when: file_exists.stat is defined and file_exists.stat.exists + tags: + - configure_strategy + - file_owner_etc_crypttab + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify User Who Owns System.map Files + The System.map files are symbol map files generated during the compilation of the Linux +kernel. They contain the mapping between kernel symbols and their corresponding memory +addresses. These files must be owned by root. + + +To properly set the owner of /boot/System.map*, run the command: +$ sudo chown root /boot/System.map* + + R29 + The purpose of System.map files is primarily for debugging and profiling the kernel. +Unrestricted access to these files might disclose information useful to attackers and +malicious software leading to more sophisticated exploitation. + +find -L /boot/ -maxdepth 1 -type f ! -uid 0 -regextype posix-extended -regex '^.*System\.map.*$' -exec chown -L 0 {} \; + + - name: Find /boot/ file(s) matching ^.*System\.map.*$ + command: find -H /boot/ -maxdepth 1 -type f ! -uid 0 -regextype posix-extended -regex + "^.*System\.map.*$" + register: files_found + changed_when: false + failed_when: false + check_mode: false + tags: + - configure_strategy + - file_owner_systemmap + - low_complexity + - low_disruption + - low_severity + - no_reboot_needed + +- name: Ensure owner on /boot/ file(s) matching ^.*System\.map.*$ + file: + path: '{{ item }}' + owner: '0' + state: file + with_items: + - '{{ files_found.stdout_lines }}' + tags: + - configure_strategy + - file_owner_systemmap + - low_complexity + - low_disruption + - low_severity + - no_reboot_needed + + + + + + + + + + Verify Permissions On /etc/crypttab File + To properly set the permissions of /etc/crypttab, run the command: $ sudo chmod 0600 /etc/crypttab + + R50 + Setting correct permissions on the /etc/crypttab file is important +because this file hosts encrypted block devices configuration. Protection +of this file is critical for system security. Assigning the ownership to +root ensures exclusive control of the encrypted block devices +configuration. + + + + +chmod u-xs,g-xwrs,o-xwrt /etc/crypttab + + - name: Test for existence /etc/crypttab + stat: + path: /etc/crypttab + register: file_exists + tags: + - configure_strategy + - file_permissions_etc_crypttab + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure permission u-xs,g-xwrs,o-xwrt on /etc/crypttab + file: + path: /etc/crypttab + mode: u-xs,g-xwrs,o-xwrt + when: file_exists.stat is defined and file_exists.stat.exists + tags: + - configure_strategy + - file_permissions_etc_crypttab + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify Permissions on System.map Files + The System.map files are symbol map files generated during the compilation of the Linux +kernel. They contain the mapping between kernel symbols and their corresponding memory +addresses. In general, there is no need for non-root users to read these files. + + +To properly set the permissions of /boot/System.map*, run the command: +$ sudo chmod 0600 /boot/System.map* + + R29 + The purpose of System.map files is primarily for debugging and profiling the kernel. +Unrestricted access to these files might disclose information useful to attackers and +malicious software leading to more sophisticated exploitation. + + + + +find -L /boot/ -maxdepth 1 -perm /u+xs,g+xwrs,o+xwrt -type f -regextype posix-extended -regex '^.*System\.map.*$' -exec chmod u-xs,g-xwrs,o-xwrt {} \; + + - name: Find /boot/ file(s) + command: find -H /boot/ -maxdepth 1 -perm /u+xs,g+xwrs,o+xwrt -type f -regextype + posix-extended -regex "^.*System\.map.*$" + register: files_found + changed_when: false + failed_when: false + check_mode: false + tags: + - configure_strategy + - file_permissions_systemmap + - low_complexity + - low_disruption + - low_severity + - no_reboot_needed + +- name: Set permissions for /boot/ file(s) + file: + path: '{{ item }}' + mode: u-xs,g-xwrs,o-xwrt + state: file + with_items: + - '{{ files_found.stdout_lines }}' + tags: + - configure_strategy + - file_permissions_systemmap + - low_complexity + - low_disruption + - low_severity + - no_reboot_needed + + + + + + + + + + Ensure All SGID Executables Are Authorized + The SGID (set group id) bit should be set only on files that were installed via authorized +means. A straightforward means of identifying unauthorized SGID files is determine if any were +not installed as part of an RPM package, which is cryptographically verified. Investigate the +origin of any unpackaged SGID files. This configuration check considers authorized SGID files +those which were installed via RPM. It is assumed that when an individual has sudo access to +install an RPM and all packages are signed with an organizationally-recognized GPG key, the +software should be considered an approved package on the system. Any SGID file not deployed +through an RPM will be flagged for further review. + This rule can take a long time to perform the check and might consume a considerable +amount of resources depending on the number of files present on the system. It is not a +problem in most cases, but especially systems with a large number of files can be affected. +See https://access.redhat.com/articles/6999111. + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + APO01.06 + DSS05.04 + DSS05.07 + DSS06.02 + 4.3.3.7.3 + SR 2.1 + SR 5.2 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CM-6(a) + AC-6(1) + PR.AC-4 + PR.DS-5 + R56 + Executable files with the SGID permission run with the privileges of the owner of the file. +SGID files of uncertain provenance could allow for unprivileged users to elevate privileges. +The presence of these files should be strictly controlled on the system. + + + + + + + + + Ensure All SUID Executables Are Authorized + The SUID (set user id) bit should be set only on files that were installed via authorized +means. A straightforward means of identifying unauthorized SUID files is determine if any were +not installed as part of an RPM package, which is cryptographically verified. Investigate the +origin of any unpackaged SUID files. This configuration check considers authorized SUID files +those which were installed via RPM. It is assumed that when an individual has sudo access to +install an RPM and all packages are signed with an organizationally-recognized GPG key, the +software should be considered an approved package on the system. Any SUID file not deployed +through an RPM will be flagged for further review. + This rule can take a long time to perform the check and might consume a considerable +amount of resources depending on the number of files present on the system. It is not a +problem in most cases, but especially systems with a large number of files can be affected. +See https://access.redhat.com/articles/6999111. + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + APO01.06 + DSS05.04 + DSS05.07 + DSS06.02 + 4.3.3.7.3 + SR 2.1 + SR 5.2 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CM-6(a) + AC-6(1) + PR.AC-4 + PR.DS-5 + R56 + Executable files with the SUID permission run with the privileges of the owner of the file. +SUID files of uncertain provenance could allow for unprivileged users to elevate privileges. +The presence of these files should be strictly controlled on the system. + + + + + + + + + Ensure No World-Writable Files Exist + It is generally a good idea to remove global (other) write access to a file when it is +discovered. However, check with documentation for specific applications before making changes. +Also, monitor for recurring world-writable files, as these may be symptoms of a misconfigured +application or user account. Finally, this applies to real files and not virtual files that +are a part of pseudo file systems such as sysfs or procfs. + This rule can take a long time to perform the check and might consume a considerable +amount of resources depending on the number of files present on the system. It is not a +problem in most cases, but especially systems with a large number of files can be affected. +See https://access.redhat.com/articles/6999111. + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + APO01.06 + DSS05.04 + DSS05.07 + DSS06.02 + 4.3.3.7.3 + SR 2.1 + SR 5.2 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 + CM-6(a) + AC-6(1) + PR.AC-4 + PR.DS-5 + R54 + 2.2.6 + 2.2 + Data in world-writable files can be modified by any user on the system. In almost all +circumstances, files can be configured using a combination of user and group permissions to +support whatever legitimate access is needed without the risk caused by world-writable files. + +FILTER_NODEV=$(awk '/nodev/ { print $2 }' /proc/filesystems | paste -sd,) + +# Do not consider /sysroot partition because it contains only the physical +# read-only root on bootable containers. +PARTITIONS=$(findmnt -n -l -k -it $FILTER_NODEV | awk '{ print $1 }' | grep -v "/sysroot") + +for PARTITION in $PARTITIONS; do + find "${PARTITION}" -xdev -type f -perm -002 -exec chmod o-w {} \; 2>/dev/null +done + +# Ensure /tmp is also fixed when tmpfs is used. +if grep "^tmpfs /tmp" /proc/mounts; then + find /tmp -xdev -type f -perm -002 -exec chmod o-w {} \; 2>/dev/null +fi + + + + + + + + + + Ensure All Files Are Owned by a Group + If any file is not group-owned by a valid defined group, the cause of the lack of +group-ownership must be investigated. Following this, those files should be deleted or +assigned to an appropriate group. The groups need to be defined in /etc/group +or in /usr/lib/group if nss-altfiles are configured to be used +in /etc/nsswitch.conf. + +Locate the mount points related to local devices by the following command: +$ findmnt -n -l -k -it $(awk '/nodev/ { print $2 }' /proc/filesystems | paste -sd,) + +For all mount points listed by the previous command, it is necessary to search for files which +do not belong to a valid group using the following command: +$ sudo find MOUNTPOINT -xdev -nogroup 2>/dev/null + + This rule only considers local groups as valid groups. +If you have your groups defined outside /etc/group or /usr/lib/group, the rule won't consider those. + This rule can take a long time to perform the check and might consume a considerable +amount of resources depending on the number of files present on the system. It is not a +problem in most cases, but especially systems with a large number of files can be affected. +See https://access.redhat.com/articles/6999111. + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + APO01.06 + DSS05.02 + DSS05.04 + DSS05.05 + DSS05.07 + DSS05.10 + DSS06.02 + DSS06.03 + DSS06.06 + DSS06.10 + CCI-000366 + 4.3.3.2.2 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 5.2 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.18.1.4 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.1 + A.9.2.2 + A.9.2.3 + A.9.2.4 + A.9.2.6 + A.9.3.1 + A.9.4.1 + A.9.4.2 + A.9.4.3 + A.9.4.4 + A.9.4.5 + CM-6(a) + AC-6(1) + PR.AC-1 + PR.AC-4 + PR.AC-6 + PR.AC-7 + PR.DS-5 + PR.PT-3 + SRG-OS-000480-GPOS-00227 + R53 + 2.2.6 + 2.2 + OL09-00-002511 + SV-271780r1092052_rule + Unowned files do not directly imply a security problem, but they are generally a sign that +something is amiss. They may be caused by an intruder, by incorrect software installation or +draft software removal, or by failure to remove all files belonging to a deleted account, or +other similar cases. The files should be repaired so they will not cause problems when +accounts are created in the future, and the cause should be discovered and addressed. + + + + + + + + + Ensure All Files Are Owned by a User + If any files are not owned by a user, then the cause of their lack of ownership should be +investigated. Following this, the files should be deleted or assigned to an appropriate user. + +Locate the mount points related to local devices by the following command: +$ findmnt -n -l -k -it $(awk '/nodev/ { print $2 }' /proc/filesystems | paste -sd,) + +For all mount points listed by the previous command, it is necessary to search for files which +do not belong to a valid user using the following command: +$ sudo find MOUNTPOINT -xdev -nouser 2>/dev/null + + For this rule to evaluate centralized user accounts, getent must be working properly +so that running the command getent passwd returns a list of all users in your organization. +If using the System Security Services Daemon (SSSD), enumerate = true must be configured +in your organization's domain to return a complete list of users + This rule can take a long time to perform the check and might consume a considerable +amount of resources depending on the number of files present on the system. It is not a +problem in most cases, but especially systems with a large number of files can be affected. +See https://access.redhat.com/articles/6999111. + 11 + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + 9 + APO01.06 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS05.02 + DSS05.04 + DSS05.05 + DSS05.07 + DSS06.02 + DSS06.03 + DSS06.06 + CCI-000366 + 4.3.3.2.2 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.2 + 4.3.4.3.3 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 5.2 + SR 7.6 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.12.1.2 + A.12.5.1 + A.12.6.2 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.1 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CM-6(a) + AC-6(1) + PR.AC-4 + PR.AC-6 + PR.DS-5 + PR.IP-1 + PR.PT-3 + SRG-OS-000480-GPOS-00227 + R53 + 2.2.6 + 2.2 + OL09-00-002512 + SV-271781r1092055_rule + Unowned files do not directly imply a security problem, but they are generally a sign that +something is amiss. They may be caused by an intruder, by incorrect software installation or +draft software removal, or by failure to remove all files belonging to a deleted account, or +other similar cases. The files should be repaired so they will not cause problems when +accounts are created in the future, and the cause should be discovered and addressed. + + + + + + + + + + Enable Kernel Parameter to Enforce DAC on FIFOs + To set the runtime status of the fs.protected_fifos kernel parameter, run the following command: $ sudo sysctl -w fs.protected_fifos=2 +To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: fs.protected_fifos = 2 + + CM-6(a) + AC-6(1) + R14 + This parameter is available since Linux Kernel 4.19 and allows to prohibit opening +FIFOs that are not owned by the user in world and group writeable sticky directories. +It avoids unintentional writes to an attacker-controlled FIFO where a program expects +to create the regular file. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Comment out any occurrences of fs.protected_fifos from /etc/sysctl.d/*.conf files + +for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do + + + # skip systemd-sysctl symlink (/etc/sysctl.d/99-sysctl.conf -> /etc/sysctl.conf) + if [[ "$(readlink -f "$f")" == "/etc/sysctl.conf" ]]; then continue; fi + + matching_list=$(grep -P '^(?!#).*[\s]*fs.protected_fifos.*$' $f | uniq ) + if ! test -z "$matching_list"; then + while IFS= read -r entry; do + escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") + # comment out "fs.protected_fifos" matches to preserve user data + sed -i --follow-symlinks "s/^${escaped_entry}$/# &/g" $f + done <<< "$matching_list" + fi +done + +# +# Set sysctl config file which to save the desired value +# + +SYSCONFIG_FILE="/etc/sysctl.conf" + + +# +# Set runtime for fs.protected_fifos +# +if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then + /sbin/sysctl -q -n -w fs.protected_fifos="2" +fi + +# +# If fs.protected_fifos present in /etc/sysctl.conf, change value to "2" +# else, add "fs.protected_fifos = 2" to /etc/sysctl.conf +# + +# Strip any search characters in the key arg so that the key can be replaced without +# adding any search characters to the config file. +stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^fs.protected_fifos") + +# shellcheck disable=SC2059 +printf -v formatted_output "%s = %s" "$stripped_key" "2" + +# If the key exists, change it. Otherwise, add it to the config_file. +# We search for the key string followed by a word boundary (matched by \>), +# so if we search for 'setting', 'setting2' won't match. +if LC_ALL=C grep -q -m 1 -i -e "^fs.protected_fifos\\>" "${SYSCONFIG_FILE}"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + LC_ALL=C sed -i --follow-symlinks "s/^fs.protected_fifos\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" +else + if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" + fi + printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_fs_protected_fifos + +- name: List /etc/sysctl.d/*.conf files + find: + paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + contains: ^[\s]*fs.protected_fifos.*$ + patterns: '*.conf' + file_type: any + register: find_sysctl_d + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_fs_protected_fifos + +- name: Comment out any occurrences of fs.protected_fifos from config files + replace: + path: '{{ item.path }}' + regexp: ^[\s]*fs.protected_fifos + replace: '#fs.protected_fifos' + loop: '{{ find_sysctl_d.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_fs_protected_fifos + +- name: Ensure sysctl fs.protected_fifos is set to 2 + sysctl: + name: fs.protected_fifos + value: '2' + sysctl_file: /etc/sysctl.conf + state: present + reload: true + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_fs_protected_fifos + + + + + + + + + + Enable Kernel Parameter to Enforce DAC on Hardlinks + To set the runtime status of the fs.protected_hardlinks kernel parameter, run the following command: $ sudo sysctl -w fs.protected_hardlinks=1 +To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: fs.protected_hardlinks = 1 + + CCI-002235 + CCI-002165 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 + CM-6(a) + AC-6(1) + SRG-OS-000312-GPOS-00122 + SRG-OS-000312-GPOS-00123 + SRG-OS-000324-GPOS-00125 + R14 + OL09-00-002401 + SV-271740r1091932_rule + By enabling this kernel parameter, users can no longer create soft or hard links to +files which they do not own. Disallowing such hardlinks mitigate vulnerabilities +based on insecure file system accessed by privileged programs, avoiding an +exploitation vector exploiting unsafe use of open() or creat(). + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Comment out any occurrences of fs.protected_hardlinks from /etc/sysctl.d/*.conf files + +for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do + + + # skip systemd-sysctl symlink (/etc/sysctl.d/99-sysctl.conf -> /etc/sysctl.conf) + if [[ "$(readlink -f "$f")" == "/etc/sysctl.conf" ]]; then continue; fi + + matching_list=$(grep -P '^(?!#).*[\s]*fs.protected_hardlinks.*$' $f | uniq ) + if ! test -z "$matching_list"; then + while IFS= read -r entry; do + escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") + # comment out "fs.protected_hardlinks" matches to preserve user data + sed -i --follow-symlinks "s/^${escaped_entry}$/# &/g" $f + done <<< "$matching_list" + fi +done + +# +# Set sysctl config file which to save the desired value +# + +SYSCONFIG_FILE="/etc/sysctl.conf" + + +# +# Set runtime for fs.protected_hardlinks +# +if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then + /sbin/sysctl -q -n -w fs.protected_hardlinks="1" +fi + +# +# If fs.protected_hardlinks present in /etc/sysctl.conf, change value to "1" +# else, add "fs.protected_hardlinks = 1" to /etc/sysctl.conf +# + +# Strip any search characters in the key arg so that the key can be replaced without +# adding any search characters to the config file. +stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^fs.protected_hardlinks") + +# shellcheck disable=SC2059 +printf -v formatted_output "%s = %s" "$stripped_key" "1" + +# If the key exists, change it. Otherwise, add it to the config_file. +# We search for the key string followed by a word boundary (matched by \>), +# so if we search for 'setting', 'setting2' won't match. +if LC_ALL=C grep -q -m 1 -i -e "^fs.protected_hardlinks\\>" "${SYSCONFIG_FILE}"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + LC_ALL=C sed -i --follow-symlinks "s/^fs.protected_hardlinks\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" +else + if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" + fi + printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002401 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_fs_protected_hardlinks + +- name: List /etc/sysctl.d/*.conf files + find: + paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + contains: ^[\s]*fs.protected_hardlinks.*$ + patterns: '*.conf' + file_type: any + register: find_sysctl_d + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002401 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_fs_protected_hardlinks + +- name: Comment out any occurrences of fs.protected_hardlinks from config files + replace: + path: '{{ item.path }}' + regexp: ^[\s]*fs.protected_hardlinks + replace: '#fs.protected_hardlinks' + loop: '{{ find_sysctl_d.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002401 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_fs_protected_hardlinks + +- name: Ensure sysctl fs.protected_hardlinks is set to 1 + sysctl: + name: fs.protected_hardlinks + value: '1' + sysctl_file: /etc/sysctl.conf + state: present + reload: true + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002401 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_fs_protected_hardlinks + + + + + + + + + + Enable Kernel Parameter to Enforce DAC on Regular files + To set the runtime status of the fs.protected_regular kernel parameter, run the following command: $ sudo sysctl -w fs.protected_regular=2 +To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: fs.protected_regular = 2 + + CM-6(a) + AC-6(1) + R14 + This parameter is available since Linux Kernel 4.19 and allows to prohibit opening +"regular" files that are not owned by the user in world and group writeable sticky +directories. It avoids writes to an attacker-controlled regular file, for example, +when a program expects to create the regular file. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Comment out any occurrences of fs.protected_regular from /etc/sysctl.d/*.conf files + +for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do + + + # skip systemd-sysctl symlink (/etc/sysctl.d/99-sysctl.conf -> /etc/sysctl.conf) + if [[ "$(readlink -f "$f")" == "/etc/sysctl.conf" ]]; then continue; fi + + matching_list=$(grep -P '^(?!#).*[\s]*fs.protected_regular.*$' $f | uniq ) + if ! test -z "$matching_list"; then + while IFS= read -r entry; do + escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") + # comment out "fs.protected_regular" matches to preserve user data + sed -i --follow-symlinks "s/^${escaped_entry}$/# &/g" $f + done <<< "$matching_list" + fi +done + +# +# Set sysctl config file which to save the desired value +# + +SYSCONFIG_FILE="/etc/sysctl.conf" + + +# +# Set runtime for fs.protected_regular +# +if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then + /sbin/sysctl -q -n -w fs.protected_regular="2" +fi + +# +# If fs.protected_regular present in /etc/sysctl.conf, change value to "2" +# else, add "fs.protected_regular = 2" to /etc/sysctl.conf +# + +# Strip any search characters in the key arg so that the key can be replaced without +# adding any search characters to the config file. +stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^fs.protected_regular") + +# shellcheck disable=SC2059 +printf -v formatted_output "%s = %s" "$stripped_key" "2" + +# If the key exists, change it. Otherwise, add it to the config_file. +# We search for the key string followed by a word boundary (matched by \>), +# so if we search for 'setting', 'setting2' won't match. +if LC_ALL=C grep -q -m 1 -i -e "^fs.protected_regular\\>" "${SYSCONFIG_FILE}"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + LC_ALL=C sed -i --follow-symlinks "s/^fs.protected_regular\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" +else + if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" + fi + printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_fs_protected_regular + +- name: List /etc/sysctl.d/*.conf files + find: + paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + contains: ^[\s]*fs.protected_regular.*$ + patterns: '*.conf' + file_type: any + register: find_sysctl_d + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_fs_protected_regular + +- name: Comment out any occurrences of fs.protected_regular from config files + replace: + path: '{{ item.path }}' + regexp: ^[\s]*fs.protected_regular + replace: '#fs.protected_regular' + loop: '{{ find_sysctl_d.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_fs_protected_regular + +- name: Ensure sysctl fs.protected_regular is set to 2 + sysctl: + name: fs.protected_regular + value: '2' + sysctl_file: /etc/sysctl.conf + state: present + reload: true + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_fs_protected_regular + + + + + + + + + + Enable Kernel Parameter to Enforce DAC on Symlinks + To set the runtime status of the fs.protected_symlinks kernel parameter, run the following command: $ sudo sysctl -w fs.protected_symlinks=1 +To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: fs.protected_symlinks = 1 + + CCI-002235 + CCI-002165 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 + CM-6(a) + AC-6(1) + SRG-OS-000312-GPOS-00122 + SRG-OS-000312-GPOS-00123 + SRG-OS-000324-GPOS-00125 + R14 + OL09-00-002402 + SV-271741r1091935_rule + By enabling this kernel parameter, symbolic links are permitted to be followed +only when outside a sticky world-writable directory, or when the UID of the +link and follower match, or when the directory owner matches the symlink's owner. +Disallowing such symlinks helps mitigate vulnerabilities based on insecure file system +accessed by privileged programs, avoiding an exploitation vector exploiting unsafe use of +open() or creat(). + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Comment out any occurrences of fs.protected_symlinks from /etc/sysctl.d/*.conf files + +for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do + + + # skip systemd-sysctl symlink (/etc/sysctl.d/99-sysctl.conf -> /etc/sysctl.conf) + if [[ "$(readlink -f "$f")" == "/etc/sysctl.conf" ]]; then continue; fi + + matching_list=$(grep -P '^(?!#).*[\s]*fs.protected_symlinks.*$' $f | uniq ) + if ! test -z "$matching_list"; then + while IFS= read -r entry; do + escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") + # comment out "fs.protected_symlinks" matches to preserve user data + sed -i --follow-symlinks "s/^${escaped_entry}$/# &/g" $f + done <<< "$matching_list" + fi +done + +# +# Set sysctl config file which to save the desired value +# + +SYSCONFIG_FILE="/etc/sysctl.conf" + + +# +# Set runtime for fs.protected_symlinks +# +if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then + /sbin/sysctl -q -n -w fs.protected_symlinks="1" +fi + +# +# If fs.protected_symlinks present in /etc/sysctl.conf, change value to "1" +# else, add "fs.protected_symlinks = 1" to /etc/sysctl.conf +# + +# Strip any search characters in the key arg so that the key can be replaced without +# adding any search characters to the config file. +stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^fs.protected_symlinks") + +# shellcheck disable=SC2059 +printf -v formatted_output "%s = %s" "$stripped_key" "1" + +# If the key exists, change it. Otherwise, add it to the config_file. +# We search for the key string followed by a word boundary (matched by \>), +# so if we search for 'setting', 'setting2' won't match. +if LC_ALL=C grep -q -m 1 -i -e "^fs.protected_symlinks\\>" "${SYSCONFIG_FILE}"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + LC_ALL=C sed -i --follow-symlinks "s/^fs.protected_symlinks\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" +else + if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" + fi + printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002402 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_fs_protected_symlinks + +- name: List /etc/sysctl.d/*.conf files + find: + paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + contains: ^[\s]*fs.protected_symlinks.*$ + patterns: '*.conf' + file_type: any + register: find_sysctl_d + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002402 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_fs_protected_symlinks + +- name: Comment out any occurrences of fs.protected_symlinks from config files + replace: + path: '{{ item.path }}' + regexp: ^[\s]*fs.protected_symlinks + replace: '#fs.protected_symlinks' + loop: '{{ find_sysctl_d.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002402 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_fs_protected_symlinks + +- name: Ensure sysctl fs.protected_symlinks is set to 1 + sysctl: + name: fs.protected_symlinks + value: '1' + sysctl_file: /etc/sysctl.conf + state: present + reload: true + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002402 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_fs_protected_symlinks + + + + + + + + + + Verify Permissions on Files with Local Account Information and Credentials + The default restrictive permissions for files which act as +important security databases such as passwd, shadow, +group, and gshadow files must be maintained. Many utilities +need read access to the passwd file in order to function properly, but +read access to the shadow file allows malicious attacks against system +passwords, and should never be enabled. + + Verify Group Who Owns Backup group File + To properly set the group owner of /etc/group-, run the command: $ sudo chgrp root /etc/group- + + CCI-000366 + AC-6 (1) + Req-8.7 + SRG-OS-000480-GPOS-00227 + 2.2.6 + 2.2 + OL09-00-002533 + SV-271795r1092097_rule + The /etc/group- file is a backup file of /etc/group, and as such, +it contains information regarding groups that are configured on the system. +Protection of this file is important for system security. + chgrp 0 /etc/group- + + - name: Test for existence /etc/group- + stat: + path: /etc/group- + register: file_exists + tags: + - DISA-STIG-OL09-00-002533 + - NIST-800-53-AC-6 (1) + - PCI-DSS-Req-8.7 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_groupowner_backup_etc_group + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure group owner 0 on /etc/group- + file: + path: /etc/group- + group: '0' + when: file_exists.stat is defined and file_exists.stat.exists + tags: + - DISA-STIG-OL09-00-002533 + - NIST-800-53-AC-6 (1) + - PCI-DSS-Req-8.7 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_groupowner_backup_etc_group + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify Group Who Owns Backup gshadow File + To properly set the group owner of /etc/gshadow-, run the command: $ sudo chgrp root /etc/gshadow- + + CCI-000366 + AC-6 (1) + Req-8.7 + SRG-OS-000480-GPOS-00227 + OL09-00-002539 + SV-271801r1092115_rule + The /etc/gshadow- file is a backup of /etc/gshadow, and as such, +it contains group password hashes. Protection of this file is critical for system security. + chgrp 0 /etc/gshadow- + + - name: Test for existence /etc/gshadow- + stat: + path: /etc/gshadow- + register: file_exists + tags: + - DISA-STIG-OL09-00-002539 + - NIST-800-53-AC-6 (1) + - PCI-DSS-Req-8.7 + - configure_strategy + - file_groupowner_backup_etc_gshadow + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure group owner 0 on /etc/gshadow- + file: + path: /etc/gshadow- + group: '0' + when: file_exists.stat is defined and file_exists.stat.exists + tags: + - DISA-STIG-OL09-00-002539 + - NIST-800-53-AC-6 (1) + - PCI-DSS-Req-8.7 + - configure_strategy + - file_groupowner_backup_etc_gshadow + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify Group Who Owns Backup passwd File + To properly set the group owner of /etc/passwd-, run the command: $ sudo chgrp root /etc/passwd- + + CCI-000366 + AC-6 (1) + Req-8.7 + SRG-OS-000480-GPOS-00227 + 2.2.6 + 2.2 + OL09-00-002545 + SV-271807r1092133_rule + The /etc/passwd- file is a backup file of /etc/passwd, and as such, +it contains information about the users that are configured on the system. +Protection of this file is critical for system security. + chgrp 0 /etc/passwd- + + - name: Test for existence /etc/passwd- + stat: + path: /etc/passwd- + register: file_exists + tags: + - DISA-STIG-OL09-00-002545 + - NIST-800-53-AC-6 (1) + - PCI-DSS-Req-8.7 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_groupowner_backup_etc_passwd + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure group owner 0 on /etc/passwd- + file: + path: /etc/passwd- + group: '0' + when: file_exists.stat is defined and file_exists.stat.exists + tags: + - DISA-STIG-OL09-00-002545 + - NIST-800-53-AC-6 (1) + - PCI-DSS-Req-8.7 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_groupowner_backup_etc_passwd + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify User Who Owns Backup shadow File + To properly set the group owner of /etc/shadow-, run the command: $ sudo chgrp root /etc/shadow- + + CCI-000366 + Req-8.7 + SRG-OS-000480-GPOS-00227 + 2.2.6 + 2.2 + OL09-00-002551 + SV-271813r1092151_rule + The /etc/shadow- file is a backup file of /etc/shadow, and as such, +it contains the list of local system accounts and password hashes. +Protection of this file is critical for system security. + chgrp 0 /etc/shadow- + + - name: Test for existence /etc/shadow- + stat: + path: /etc/shadow- + register: file_exists + tags: + - DISA-STIG-OL09-00-002551 + - PCI-DSS-Req-8.7 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_groupowner_backup_etc_shadow + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure group owner 0 on /etc/shadow- + file: + path: /etc/shadow- + group: '0' + when: file_exists.stat is defined and file_exists.stat.exists + tags: + - DISA-STIG-OL09-00-002551 + - PCI-DSS-Req-8.7 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_groupowner_backup_etc_shadow + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify Group Who Owns group File + To properly set the group owner of /etc/group, run the command: $ sudo chgrp root /etc/group + + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + 5.5.2.2 + APO01.06 + DSS05.04 + DSS05.07 + DSS06.02 + CCI-000366 + 4.3.3.7.3 + SR 2.1 + SR 5.2 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 + CM-6(a) + AC-6(1) + PR.AC-4 + PR.DS-5 + Req-8.7.c + SRG-OS-000480-GPOS-00227 + R50 + 2.2.6 + 2.2 + OL09-00-002532 + SV-271794r1092094_rule + The /etc/group file contains information regarding groups that are configured +on the system. Protection of this file is important for system security. + chgrp 0 /etc/group + + - name: Test for existence /etc/group + stat: + path: /etc/group + register: file_exists + tags: + - CJIS-5.5.2.2 + - DISA-STIG-OL09-00-002532 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-8.7.c + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_groupowner_etc_group + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure group owner 0 on /etc/group + file: + path: /etc/group + group: '0' + when: file_exists.stat is defined and file_exists.stat.exists + tags: + - CJIS-5.5.2.2 + - DISA-STIG-OL09-00-002532 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-8.7.c + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_groupowner_etc_group + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify Group Who Owns gshadow File + To properly set the group owner of /etc/gshadow, run the command: $ sudo chgrp root /etc/gshadow + + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + APO01.06 + DSS05.04 + DSS05.07 + DSS06.02 + CCI-000366 + 4.3.3.7.3 + SR 2.1 + SR 5.2 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 + CM-6(a) + AC-6(1) + PR.AC-4 + PR.DS-5 + SRG-OS-000480-GPOS-00227 + R50 + OL09-00-002538 + SV-271800r1092112_rule + The /etc/gshadow file contains group password hashes. Protection of this file +is critical for system security. + chgrp 0 /etc/gshadow + + - name: Test for existence /etc/gshadow + stat: + path: /etc/gshadow + register: file_exists + tags: + - DISA-STIG-OL09-00-002538 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - configure_strategy + - file_groupowner_etc_gshadow + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure group owner 0 on /etc/gshadow + file: + path: /etc/gshadow + group: '0' + when: file_exists.stat is defined and file_exists.stat.exists + tags: + - DISA-STIG-OL09-00-002538 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - configure_strategy + - file_groupowner_etc_gshadow + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify Group Who Owns passwd File + To properly set the group owner of /etc/passwd, run the command: $ sudo chgrp root /etc/passwd + + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + 5.5.2.2 + APO01.06 + DSS05.04 + DSS05.07 + DSS06.02 + CCI-000366 + 4.3.3.7.3 + SR 2.1 + SR 5.2 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 + CM-6(a) + AC-6(1) + PR.AC-4 + PR.DS-5 + Req-8.7.c + SRG-OS-000480-GPOS-00227 + R50 + 2.2.6 + 2.2 + OL09-00-002544 + SV-271806r1092130_rule + The /etc/passwd file contains information about the users that are configured on +the system. Protection of this file is critical for system security. + chgrp 0 /etc/passwd + + - name: Test for existence /etc/passwd + stat: + path: /etc/passwd + register: file_exists + tags: + - CJIS-5.5.2.2 + - DISA-STIG-OL09-00-002544 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-8.7.c + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_groupowner_etc_passwd + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure group owner 0 on /etc/passwd + file: + path: /etc/passwd + group: '0' + when: file_exists.stat is defined and file_exists.stat.exists + tags: + - CJIS-5.5.2.2 + - DISA-STIG-OL09-00-002544 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-8.7.c + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_groupowner_etc_passwd + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify Group Who Owns shadow File + To properly set the group owner of /etc/shadow, run the command: $ sudo chgrp root /etc/shadow + + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + 5.5.2.2 + APO01.06 + DSS05.04 + DSS05.07 + DSS06.02 + CCI-000366 + 4.3.3.7.3 + SR 2.1 + SR 5.2 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 + CM-6(a) + AC-6(1) + PR.AC-4 + PR.DS-5 + Req-8.7.c + SRG-OS-000480-GPOS-00227 + R50 + 2.2.6 + 2.2 + OL09-00-002550 + SV-271812r1092148_rule + The /etc/shadow file stores password hashes. Protection of this file is +critical for system security. + chgrp 0 /etc/shadow + + - name: Test for existence /etc/shadow + stat: + path: /etc/shadow + register: file_exists + tags: + - CJIS-5.5.2.2 + - DISA-STIG-OL09-00-002550 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-8.7.c + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_groupowner_etc_shadow + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure group owner 0 on /etc/shadow + file: + path: /etc/shadow + group: '0' + when: file_exists.stat is defined and file_exists.stat.exists + tags: + - CJIS-5.5.2.2 + - DISA-STIG-OL09-00-002550 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-8.7.c + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_groupowner_etc_shadow + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify Group Who Owns /etc/shells File + +To properly set the group owner of /etc/shells, run the command: +$ sudo chgrp root /etc/shells + + AC-3 + MP-2 + R50 + The /etc/shells file contains the list of full pathnames to shells on the system. +Since this file is used by many system programs this file should be protected. + chgrp 0 /etc/shells + + - name: Test for existence /etc/shells + stat: + path: /etc/shells + register: file_exists + tags: + - NIST-800-53-AC-3 + - NIST-800-53-MP-2 + - configure_strategy + - file_groupowner_etc_shells + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure group owner 0 on /etc/shells + file: + path: /etc/shells + group: '0' + when: file_exists.stat is defined and file_exists.stat.exists + tags: + - NIST-800-53-AC-3 + - NIST-800-53-MP-2 + - configure_strategy + - file_groupowner_etc_shells + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify User Who Owns Backup group File + To properly set the owner of /etc/group-, run the command: $ sudo chown root /etc/group- + + CCI-000366 + AC-6 (1) + Req-8.7.c + SRG-OS-000480-GPOS-00227 + 2.2.6 + 2.2 + OL09-00-002535 + SV-271797r1092103_rule + The /etc/group- file is a backup file of /etc/group, and as such, +it contains information regarding groups that are configured on the system. +Protection of this file is important for system security. + chown 0 /etc/group- + + - name: Test for existence /etc/group- + stat: + path: /etc/group- + register: file_exists + tags: + - DISA-STIG-OL09-00-002535 + - NIST-800-53-AC-6 (1) + - PCI-DSS-Req-8.7.c + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_owner_backup_etc_group + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure owner 0 on /etc/group- + file: + path: /etc/group- + owner: '0' + when: file_exists.stat is defined and file_exists.stat.exists + tags: + - DISA-STIG-OL09-00-002535 + - NIST-800-53-AC-6 (1) + - PCI-DSS-Req-8.7.c + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_owner_backup_etc_group + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify User Who Owns Backup gshadow File + To properly set the owner of /etc/gshadow-, run the command: $ sudo chown root /etc/gshadow- + + CCI-000366 + AC-6 (1) + Req-8.7 + SRG-OS-000480-GPOS-00227 + OL09-00-002541 + SV-271803r1092121_rule + The /etc/gshadow- file is a backup of /etc/gshadow, and as such, +it contains group password hashes. Protection of this file is critical for system security. + chown 0 /etc/gshadow- + + - name: Test for existence /etc/gshadow- + stat: + path: /etc/gshadow- + register: file_exists + tags: + - DISA-STIG-OL09-00-002541 + - NIST-800-53-AC-6 (1) + - PCI-DSS-Req-8.7 + - configure_strategy + - file_owner_backup_etc_gshadow + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure owner 0 on /etc/gshadow- + file: + path: /etc/gshadow- + owner: '0' + when: file_exists.stat is defined and file_exists.stat.exists + tags: + - DISA-STIG-OL09-00-002541 + - NIST-800-53-AC-6 (1) + - PCI-DSS-Req-8.7 + - configure_strategy + - file_owner_backup_etc_gshadow + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify User Who Owns Backup passwd File + To properly set the owner of /etc/passwd-, run the command: $ sudo chown root /etc/passwd- + + CCI-000366 + AC-6 (1) + Req-8.7.c + SRG-OS-000480-GPOS-00227 + 2.2.6 + 2.2 + OL09-00-002547 + SV-271809r1092139_rule + The /etc/passwd- file is a backup file of /etc/passwd, and as such, +it contains information about the users that are configured on the system. +Protection of this file is critical for system security. + chown 0 /etc/passwd- + + - name: Test for existence /etc/passwd- + stat: + path: /etc/passwd- + register: file_exists + tags: + - DISA-STIG-OL09-00-002547 + - NIST-800-53-AC-6 (1) + - PCI-DSS-Req-8.7.c + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_owner_backup_etc_passwd + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure owner 0 on /etc/passwd- + file: + path: /etc/passwd- + owner: '0' + when: file_exists.stat is defined and file_exists.stat.exists + tags: + - DISA-STIG-OL09-00-002547 + - NIST-800-53-AC-6 (1) + - PCI-DSS-Req-8.7.c + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_owner_backup_etc_passwd + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify Group Who Owns Backup shadow File + To properly set the owner of /etc/shadow-, run the command: $ sudo chown root /etc/shadow- + + CCI-000366 + AC-6 (1) + Req-8.7.c + SRG-OS-000480-GPOS-00227 + 2.2.6 + 2.2 + OL09-00-002553 + SV-271815r1092157_rule + The /etc/shadow- file is a backup file of /etc/shadow, and as such, +it contains the list of local system accounts and password hashes. +Protection of this file is critical for system security. + chown 0 /etc/shadow- + + - name: Test for existence /etc/shadow- + stat: + path: /etc/shadow- + register: file_exists + tags: + - DISA-STIG-OL09-00-002553 + - NIST-800-53-AC-6 (1) + - PCI-DSS-Req-8.7.c + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_owner_backup_etc_shadow + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure owner 0 on /etc/shadow- + file: + path: /etc/shadow- + owner: '0' + when: file_exists.stat is defined and file_exists.stat.exists + tags: + - DISA-STIG-OL09-00-002553 + - NIST-800-53-AC-6 (1) + - PCI-DSS-Req-8.7.c + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_owner_backup_etc_shadow + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify User Who Owns group File + To properly set the owner of /etc/group, run the command: $ sudo chown root /etc/group + + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + 5.5.2.2 + APO01.06 + DSS05.04 + DSS05.07 + DSS06.02 + CCI-000366 + 4.3.3.7.3 + SR 2.1 + SR 5.2 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 + CM-6(a) + AC-6(1) + PR.AC-4 + PR.DS-5 + Req-8.7.c + SRG-OS-000480-GPOS-00227 + R50 + 2.2.6 + 2.2 + OL09-00-002534 + SV-271796r1092100_rule + The /etc/group file contains information regarding groups that are configured +on the system. Protection of this file is important for system security. + chown 0 /etc/group + + - name: Test for existence /etc/group + stat: + path: /etc/group + register: file_exists + tags: + - CJIS-5.5.2.2 + - DISA-STIG-OL09-00-002534 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-8.7.c + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_owner_etc_group + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure owner 0 on /etc/group + file: + path: /etc/group + owner: '0' + when: file_exists.stat is defined and file_exists.stat.exists + tags: + - CJIS-5.5.2.2 + - DISA-STIG-OL09-00-002534 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-8.7.c + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_owner_etc_group + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify User Who Owns gshadow File + To properly set the owner of /etc/gshadow, run the command: $ sudo chown root /etc/gshadow + + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + APO01.06 + DSS05.04 + DSS05.07 + DSS06.02 + CCI-000366 + 4.3.3.7.3 + SR 2.1 + SR 5.2 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 + CM-6(a) + AC-6(1) + PR.AC-4 + PR.DS-5 + SRG-OS-000480-GPOS-00227 + R50 + OL09-00-002540 + SV-271802r1092118_rule + The /etc/gshadow file contains group password hashes. Protection of this file +is critical for system security. + chown 0 /etc/gshadow + + - name: Test for existence /etc/gshadow + stat: + path: /etc/gshadow + register: file_exists + tags: + - DISA-STIG-OL09-00-002540 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - configure_strategy + - file_owner_etc_gshadow + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure owner 0 on /etc/gshadow + file: + path: /etc/gshadow + owner: '0' + when: file_exists.stat is defined and file_exists.stat.exists + tags: + - DISA-STIG-OL09-00-002540 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - configure_strategy + - file_owner_etc_gshadow + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify User Who Owns passwd File + To properly set the owner of /etc/passwd, run the command: $ sudo chown root /etc/passwd + + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + 5.5.2.2 + APO01.06 + DSS05.04 + DSS05.07 + DSS06.02 + CCI-000366 + 4.3.3.7.3 + SR 2.1 + SR 5.2 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 + CM-6(a) + AC-6(1) + PR.AC-4 + PR.DS-5 + Req-8.7.c + SRG-OS-000480-GPOS-00227 + R50 + 2.2.6 + 2.2 + OL09-00-002546 + SV-271808r1092136_rule + The /etc/passwd file contains information about the users that are configured on +the system. Protection of this file is critical for system security. + chown 0 /etc/passwd + + - name: Test for existence /etc/passwd + stat: + path: /etc/passwd + register: file_exists + tags: + - CJIS-5.5.2.2 + - DISA-STIG-OL09-00-002546 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-8.7.c + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_owner_etc_passwd + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure owner 0 on /etc/passwd + file: + path: /etc/passwd + owner: '0' + when: file_exists.stat is defined and file_exists.stat.exists + tags: + - CJIS-5.5.2.2 + - DISA-STIG-OL09-00-002546 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-8.7.c + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_owner_etc_passwd + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify User Who Owns shadow File + To properly set the owner of /etc/shadow, run the command: $ sudo chown root /etc/shadow + + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + 5.5.2.2 + APO01.06 + DSS05.04 + DSS05.07 + DSS06.02 + CCI-000366 + 4.3.3.7.3 + SR 2.1 + SR 5.2 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 + CM-6(a) + AC-6(1) + PR.AC-4 + PR.DS-5 + Req-8.7.c + SRG-OS-000480-GPOS-00227 + R50 + 2.2.6 + 2.2 + OL09-00-002552 + SV-271814r1092154_rule + The /etc/shadow file contains the list of local +system accounts and stores password hashes. Protection of this file is +critical for system security. Failure to give ownership of this file +to root provides the designated owner with access to sensitive information +which could weaken the system security posture. + chown 0 /etc/shadow + + - name: Test for existence /etc/shadow + stat: + path: /etc/shadow + register: file_exists + tags: + - CJIS-5.5.2.2 + - DISA-STIG-OL09-00-002552 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-8.7.c + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_owner_etc_shadow + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure owner 0 on /etc/shadow + file: + path: /etc/shadow + owner: '0' + when: file_exists.stat is defined and file_exists.stat.exists + tags: + - CJIS-5.5.2.2 + - DISA-STIG-OL09-00-002552 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-8.7.c + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_owner_etc_shadow + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify Who Owns /etc/shells File + +To properly set the owner of /etc/shells, run the command: +$ sudo chown root /etc/shells + + AC-3 + MP-2 + R50 + The /etc/shells file contains the list of full pathnames to shells on the system. +Since this file is used by many system programs this file should be protected. + chown 0 /etc/shells + + - name: Test for existence /etc/shells + stat: + path: /etc/shells + register: file_exists + tags: + - NIST-800-53-AC-3 + - NIST-800-53-MP-2 + - configure_strategy + - file_owner_etc_shells + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure owner 0 on /etc/shells + file: + path: /etc/shells + owner: '0' + when: file_exists.stat is defined and file_exists.stat.exists + tags: + - NIST-800-53-AC-3 + - NIST-800-53-MP-2 + - configure_strategy + - file_owner_etc_shells + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify Permissions on Backup group File + +To properly set the permissions of /etc/group-, run the command: +$ sudo chmod 0644 /etc/group- + + CCI-000366 + AC-6 (1) + Req-8.7.c + SRG-OS-000480-GPOS-00227 + 2.2.6 + 2.2 + OL09-00-002537 + SV-271799r1092109_rule + The /etc/group- file is a backup file of /etc/group, and as such, +it contains information regarding groups that are configured on the system. +Protection of this file is important for system security. + + + + +chmod u-xs,g-xws,o-xwt /etc/group- + + - name: Test for existence /etc/group- + stat: + path: /etc/group- + register: file_exists + tags: + - DISA-STIG-OL09-00-002537 + - NIST-800-53-AC-6 (1) + - PCI-DSS-Req-8.7.c + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_permissions_backup_etc_group + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure permission u-xs,g-xws,o-xwt on /etc/group- + file: + path: /etc/group- + mode: u-xs,g-xws,o-xwt + when: file_exists.stat is defined and file_exists.stat.exists + tags: + - DISA-STIG-OL09-00-002537 + - NIST-800-53-AC-6 (1) + - PCI-DSS-Req-8.7.c + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_permissions_backup_etc_group + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify Permissions on Backup gshadow File + +To properly set the permissions of /etc/gshadow-, run the command: +$ sudo chmod 0000 /etc/gshadow- + + CCI-000366 + AC-6 (1) + SRG-OS-000480-GPOS-00227 + OL09-00-002543 + SV-271805r1092127_rule + The /etc/gshadow- file is a backup of /etc/gshadow, and as such, +it contains group password hashes. Protection of this file is critical for system security. + + + + +chmod u-xwrs,g-xwrs,o-xwrt /etc/gshadow- + + - name: Test for existence /etc/gshadow- + stat: + path: /etc/gshadow- + register: file_exists + tags: + - DISA-STIG-OL09-00-002543 + - NIST-800-53-AC-6 (1) + - configure_strategy + - file_permissions_backup_etc_gshadow + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure permission u-xwrs,g-xwrs,o-xwrt on /etc/gshadow- + file: + path: /etc/gshadow- + mode: u-xwrs,g-xwrs,o-xwrt + when: file_exists.stat is defined and file_exists.stat.exists + tags: + - DISA-STIG-OL09-00-002543 + - NIST-800-53-AC-6 (1) + - configure_strategy + - file_permissions_backup_etc_gshadow + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify Permissions on Backup passwd File + +To properly set the permissions of /etc/passwd-, run the command: +$ sudo chmod 0644 /etc/passwd- + + CCI-000366 + AC-6 (1) + Req-8.7.c + SRG-OS-000480-GPOS-00227 + 2.2.6 + 2.2 + OL09-00-002549 + SV-271811r1092145_rule + The /etc/passwd- file is a backup file of /etc/passwd, and as such, +it contains information about the users that are configured on the system. +Protection of this file is critical for system security. + + + + +chmod u-xs,g-xws,o-xwt /etc/passwd- + + - name: Test for existence /etc/passwd- + stat: + path: /etc/passwd- + register: file_exists + tags: + - DISA-STIG-OL09-00-002549 + - NIST-800-53-AC-6 (1) + - PCI-DSS-Req-8.7.c + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_permissions_backup_etc_passwd + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure permission u-xs,g-xws,o-xwt on /etc/passwd- + file: + path: /etc/passwd- + mode: u-xs,g-xws,o-xwt + when: file_exists.stat is defined and file_exists.stat.exists + tags: + - DISA-STIG-OL09-00-002549 + - NIST-800-53-AC-6 (1) + - PCI-DSS-Req-8.7.c + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_permissions_backup_etc_passwd + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify Permissions on Backup shadow File + +To properly set the permissions of /etc/shadow-, run the command: +$ sudo chmod 0000 /etc/shadow- + + CCI-000366 + AC-6 (1) + Req-8.7.c + SRG-OS-000480-GPOS-00227 + 2.2.6 + 2.2 + OL09-00-002554 + SV-271816r1092160_rule + The /etc/shadow- file is a backup file of /etc/shadow, and as such, +it contains the list of local system accounts and password hashes. +Protection of this file is critical for system security. + + + + +chmod u-xwrs,g-xwrs,o-xwrt /etc/shadow- + + - name: Test for existence /etc/shadow- + stat: + path: /etc/shadow- + register: file_exists + tags: + - DISA-STIG-OL09-00-002554 + - NIST-800-53-AC-6 (1) + - PCI-DSS-Req-8.7.c + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_permissions_backup_etc_shadow + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure permission u-xwrs,g-xwrs,o-xwrt on /etc/shadow- + file: + path: /etc/shadow- + mode: u-xwrs,g-xwrs,o-xwrt + when: file_exists.stat is defined and file_exists.stat.exists + tags: + - DISA-STIG-OL09-00-002554 + - NIST-800-53-AC-6 (1) + - PCI-DSS-Req-8.7.c + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_permissions_backup_etc_shadow + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify Permissions on group File + +To properly set the permissions of /etc/group, run the command: +$ sudo chmod 0644 /etc/group + + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + 5.5.2.2 + APO01.06 + DSS05.04 + DSS05.07 + DSS06.02 + CCI-000366 + 4.3.3.7.3 + SR 2.1 + SR 5.2 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 + CM-6(a) + AC-6(1) + PR.AC-4 + PR.DS-5 + Req-8.7.c + SRG-OS-000480-GPOS-00227 + R50 + 2.2.6 + 2.2 + OL09-00-002536 + SV-271798r1092106_rule + The /etc/group file contains information regarding groups that are configured +on the system. Protection of this file is important for system security. + + + + +chmod u-xs,g-xws,o-xwt /etc/group + + - name: Test for existence /etc/group + stat: + path: /etc/group + register: file_exists + tags: + - CJIS-5.5.2.2 + - DISA-STIG-OL09-00-002536 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-8.7.c + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_permissions_etc_group + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure permission u-xs,g-xws,o-xwt on /etc/group + file: + path: /etc/group + mode: u-xs,g-xws,o-xwt + when: file_exists.stat is defined and file_exists.stat.exists + tags: + - CJIS-5.5.2.2 + - DISA-STIG-OL09-00-002536 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-8.7.c + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_permissions_etc_group + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify Permissions on gshadow File + +To properly set the permissions of /etc/gshadow, run the command: +$ sudo chmod 0000 /etc/gshadow + + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + APO01.06 + DSS05.04 + DSS05.07 + DSS06.02 + CCI-000366 + 4.3.3.7.3 + SR 2.1 + SR 5.2 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 + CM-6(a) + AC-6(1) + PR.AC-4 + PR.DS-5 + SRG-OS-000480-GPOS-00227 + R50 + OL09-00-002542 + SV-271804r1092124_rule + The /etc/gshadow file contains group password hashes. Protection of this file +is critical for system security. + + + + +chmod u-xwrs,g-xwrs,o-xwrt /etc/gshadow + + - name: Test for existence /etc/gshadow + stat: + path: /etc/gshadow + register: file_exists + tags: + - DISA-STIG-OL09-00-002542 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - configure_strategy + - file_permissions_etc_gshadow + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure permission u-xwrs,g-xwrs,o-xwrt on /etc/gshadow + file: + path: /etc/gshadow + mode: u-xwrs,g-xwrs,o-xwrt + when: file_exists.stat is defined and file_exists.stat.exists + tags: + - DISA-STIG-OL09-00-002542 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - configure_strategy + - file_permissions_etc_gshadow + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify Permissions on passwd File + +To properly set the permissions of /etc/passwd, run the command: +$ sudo chmod 0644 /etc/passwd + + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + 5.5.2.2 + APO01.06 + DSS05.04 + DSS05.07 + DSS06.02 + CCI-000366 + 4.3.3.7.3 + SR 2.1 + SR 5.2 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 + CM-6(a) + AC-6(1) + PR.AC-4 + PR.DS-5 + Req-8.7.c + SRG-OS-000480-GPOS-00227 + R50 + 2.2.6 + 2.2 + OL09-00-002548 + SV-271810r1092142_rule + If the /etc/passwd file is writable by a group-owner or the +world the risk of its compromise is increased. The file contains the list of +accounts on the system and associated information, and protection of this file +is critical for system security. + + + + +chmod u-xs,g-xws,o-xwt /etc/passwd + + - name: Test for existence /etc/passwd + stat: + path: /etc/passwd + register: file_exists + tags: + - CJIS-5.5.2.2 + - DISA-STIG-OL09-00-002548 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-8.7.c + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_permissions_etc_passwd + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure permission u-xs,g-xws,o-xwt on /etc/passwd + file: + path: /etc/passwd + mode: u-xs,g-xws,o-xwt + when: file_exists.stat is defined and file_exists.stat.exists + tags: + - CJIS-5.5.2.2 + - DISA-STIG-OL09-00-002548 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-8.7.c + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_permissions_etc_passwd + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify Permissions on shadow File + +To properly set the permissions of /etc/shadow, run the command: +$ sudo chmod 0000 /etc/shadow + + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + 5.5.2.2 + APO01.06 + DSS05.04 + DSS05.07 + DSS06.02 + CCI-000366 + 4.3.3.7.3 + SR 2.1 + SR 5.2 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 + CM-6(a) + AC-6(1) + PR.AC-4 + PR.DS-5 + Req-8.7.c + SRG-OS-000480-GPOS-00227 + R50 + 2.2.6 + 2.2 + OL09-00-002555 + SV-271817r1092163_rule + The /etc/shadow file contains the list of local +system accounts and stores password hashes. Protection of this file is +critical for system security. Failure to give ownership of this file +to root provides the designated owner with access to sensitive information +which could weaken the system security posture. + + + + +chmod u-xwrs,g-xwrs,o-xwrt /etc/shadow + + - name: Test for existence /etc/shadow + stat: + path: /etc/shadow + register: file_exists + tags: + - CJIS-5.5.2.2 + - DISA-STIG-OL09-00-002555 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-8.7.c + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_permissions_etc_shadow + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure permission u-xwrs,g-xwrs,o-xwrt on /etc/shadow + file: + path: /etc/shadow + mode: u-xwrs,g-xwrs,o-xwrt + when: file_exists.stat is defined and file_exists.stat.exists + tags: + - CJIS-5.5.2.2 + - DISA-STIG-OL09-00-002555 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-8.7.c + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_permissions_etc_shadow + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify Permissions on /etc/shells File + +To properly set the permissions of /etc/shells, run the command: +$ sudo chmod 0644 /etc/shells + + AC-3 + MP-2 + R50 + The /etc/shells file contains the list of full pathnames to shells on the system. +Since this file is used by many system programs this file should be protected. + + + + +chmod u-xs,g-xws,o-xwt /etc/shells + + - name: Test for existence /etc/shells + stat: + path: /etc/shells + register: file_exists + tags: + - NIST-800-53-AC-3 + - NIST-800-53-MP-2 + - configure_strategy + - file_permissions_etc_shells + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure permission u-xs,g-xws,o-xwt on /etc/shells + file: + path: /etc/shells + mode: u-xs,g-xws,o-xwt + when: file_exists.stat is defined and file_exists.stat.exists + tags: + - NIST-800-53-AC-3 + - NIST-800-53-MP-2 + - configure_strategy + - file_permissions_etc_shells + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + + Verify Permissions on Files within /var/log Directory + The /var/log directory contains files with logs of error +messages in the system and should only be accessed by authorized +personnel. + + Verify Group Who Owns /var/log Directory + To properly set the group owner of /var/log, run the command: $ sudo chgrp root /var/log + + CCI-001314 + SRG-OS-000206-GPOS-00084 + SRG-APP-000118-CTR-000240 + OL09-00-002560 + SV-271818r1092166_rule + The /var/log directory contains files with logs of error +messages in the system and should only be accessed by authorized +personnel. + find -H /var/log/ -maxdepth 1 -type d -exec chgrp -L 0 {} \; + + - name: Ensure group owner on /var/log/ + file: + path: /var/log/ + state: directory + group: '0' + tags: + - DISA-STIG-OL09-00-002560 + - configure_strategy + - file_groupowner_var_log + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify Group Who Owns /var/log/messages File + To properly set the group owner of /var/log/messages, run the command: $ sudo chgrp root /var/log/messages + + CCI-001314 + SRG-OS-000206-GPOS-00084 + OL09-00-002563 + SV-271821r1092175_rule + The /var/log/messages file contains logs of error messages in +the system and should only be accessed by authorized personnel. + chgrp 0 /var/log/messages + + - name: Test for existence /var/log/messages + stat: + path: /var/log/messages + register: file_exists + tags: + - DISA-STIG-OL09-00-002563 + - configure_strategy + - file_groupowner_var_log_messages + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure group owner 0 on /var/log/messages + file: + path: /var/log/messages + group: '0' + when: file_exists.stat is defined and file_exists.stat.exists + tags: + - DISA-STIG-OL09-00-002563 + - configure_strategy + - file_groupowner_var_log_messages + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify Group Who Owns /var/log/syslog File + To properly set the group owner of /var/log/syslog, run the command: $ sudo chgrp adm /var/log/syslog + + CCI-001314 + SRG-OS-000206-GPOS-00084 + The /var/log/syslog file contains logs of error messages in +the system and should only be accessed by authorized personnel. + chgrp 4 /var/log/syslog + + - name: Test for existence /var/log/syslog + stat: + path: /var/log/syslog + register: file_exists + tags: + - configure_strategy + - file_groupowner_var_log_syslog + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure group owner 4 on /var/log/syslog + file: + path: /var/log/syslog + group: '4' + when: file_exists.stat is defined and file_exists.stat.exists + tags: + - configure_strategy + - file_groupowner_var_log_syslog + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify User Who Owns /var/log Directory + To properly set the owner of /var/log, run the command: $ sudo chown root /var/log + + CCI-001314 + SRG-OS-000206-GPOS-00084 + SRG-APP-000118-CTR-000240 + OL09-00-002561 + SV-271819r1092169_rule + The /var/log directory contains files with logs of error +messages in the system and should only be accessed by authorized +personnel. + find -H /var/log/ -maxdepth 1 -type d -exec chown -L 0 {} \; + + - name: Ensure owner on directory /var/log/ + file: + path: /var/log/ + state: directory + owner: '0' + tags: + - DISA-STIG-OL09-00-002561 + - configure_strategy + - file_owner_var_log + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify User Who Owns /var/log/messages File + To properly set the owner of /var/log/messages, run the command: $ sudo chown root /var/log/messages + + CCI-001314 + SRG-OS-000206-GPOS-00084 + OL09-00-002564 + SV-271822r1092178_rule + The /var/log/messages file contains logs of error messages in +the system and should only be accessed by authorized personnel. + chown 0 /var/log/messages + + - name: Test for existence /var/log/messages + stat: + path: /var/log/messages + register: file_exists + tags: + - DISA-STIG-OL09-00-002564 + - configure_strategy + - file_owner_var_log_messages + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure owner 0 on /var/log/messages + file: + path: /var/log/messages + owner: '0' + when: file_exists.stat is defined and file_exists.stat.exists + tags: + - DISA-STIG-OL09-00-002564 + - configure_strategy + - file_owner_var_log_messages + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify User Who Owns /var/log/syslog File + To properly set the owner of /var/log/syslog, run the command: $ sudo chown syslog /var/log/syslog + + CCI-001314 + SRG-OS-000206-GPOS-00084 + The /var/log/syslog file contains logs of error messages in +the system and should only be accessed by authorized personnel. + chown 104 /var/log/syslog + + - name: Test for existence /var/log/syslog + stat: + path: /var/log/syslog + register: file_exists + tags: + - configure_strategy + - file_owner_var_log_syslog + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure owner 104 on /var/log/syslog + file: + path: /var/log/syslog + owner: '104' + when: file_exists.stat is defined and file_exists.stat.exists + tags: + - configure_strategy + - file_owner_var_log_syslog + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify Permissions on /var/log Directory + +To properly set the permissions of /var/log, run the command: +$ sudo chmod 0755 /var/log + + CCI-001314 + SRG-OS-000206-GPOS-00084 + SRG-APP-000118-CTR-000240 + OL09-00-002562 + SV-271820r1092172_rule + The /var/log directory contains files with logs of error +messages in the system and should only be accessed by authorized +personnel. + + + + +find -H /var/log/ -maxdepth 1 -perm /u+s,g+ws,o+wt -type d -exec chmod u-s,g-ws,o-wt {} \; + + - name: Find /var/log/ file(s) + command: 'find -H /var/log/ -maxdepth 1 -perm /u+s,g+ws,o+wt -type d ' + register: files_found + changed_when: false + failed_when: false + check_mode: false + tags: + - DISA-STIG-OL09-00-002562 + - configure_strategy + - file_permissions_var_log + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Set permissions for /var/log/ file(s) + file: + path: '{{ item }}' + mode: u-s,g-ws,o-wt + state: directory + with_items: + - '{{ files_found.stdout_lines }}' + tags: + - DISA-STIG-OL09-00-002562 + - configure_strategy + - file_permissions_var_log + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify Permissions on /var/log/messages File + +To properly set the permissions of /var/log/messages, run the command: +$ sudo chmod 0600 /var/log/messages + + CCI-001314 + SRG-OS-000206-GPOS-00084 + OL09-00-002565 + SV-271823r1092181_rule + The /var/log/messages file contains logs of error messages in +the system and should only be accessed by authorized personnel. + + + + +chmod u-xs,g-xwrs,o-xwrt /var/log/messages + + - name: Test for existence /var/log/messages + stat: + path: /var/log/messages + register: file_exists + tags: + - DISA-STIG-OL09-00-002565 + - configure_strategy + - file_permissions_var_log_messages + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure permission u-xs,g-xwrs,o-xwrt on /var/log/messages + file: + path: /var/log/messages + mode: u-xs,g-xwrs,o-xwrt + when: file_exists.stat is defined and file_exists.stat.exists + tags: + - DISA-STIG-OL09-00-002565 + - configure_strategy + - file_permissions_var_log_messages + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify Permissions on /var/log/syslog File + +To properly set the permissions of /var/log/syslog, run the command: +$ sudo chmod 0640 /var/log/syslog + + CCI-001314 + SRG-OS-000206-GPOS-00084 + The /var/log/syslog file contains logs of error messages in +the system and should only be accessed by authorized personnel. + + + + +chmod u-xs,g-xws,o-xwrt /var/log/syslog + + - name: Test for existence /var/log/syslog + stat: + path: /var/log/syslog + register: file_exists + tags: + - configure_strategy + - file_permissions_var_log_syslog + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure permission u-xs,g-xws,o-xwrt on /var/log/syslog + file: + path: /var/log/syslog + mode: u-xs,g-xws,o-xwrt + when: file_exists.stat is defined and file_exists.stat.exists + tags: + - configure_strategy + - file_permissions_var_log_syslog + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + + Verify File Permissions Within Some Important Directories + Some directories contain files whose confidentiality or integrity +is notably important and may also be susceptible to misconfiguration over time, particularly if +unpackaged software is installed. As such, +an argument exists to verify that files' permissions within these directories remain +configured correctly and restrictively. + + Verify that Shared Library Directories Have Root Group Ownership + System-wide shared library files, which are linked to executables +during process load time or run time, are stored in the following directories +by default: +/lib +/lib64 +/usr/lib +/usr/lib64 + +Kernel modules, which can be added to the kernel during runtime, are also +stored in /lib/modules. All files in these directories should be +group-owned by the root user. If the directories, is found to be owned +by a user other than root correct its +ownership with the following command: +$ sudo chgrp root DIR + + + CCI-001499 + CM-5(6) + CM-5(6).1 + SRG-OS-000259-GPOS-00100 + OL09-00-002520 + SV-271786r1092070_rule + Files from shared library directories are loaded into the address +space of processes (including privileged ones) or of the kernel itself at +runtime. Proper ownership of library directories is necessary to protect +the integrity of the system. + find -H /lib/ -type d -exec chgrp -L 0 {} \; +find -H /lib64/ -type d -exec chgrp -L 0 {} \; +find -H /usr/lib/ -type d -exec chgrp -L 0 {} \; +find -H /usr/lib64/ -type d -exec chgrp -L 0 {} \; + + - name: Ensure group owner on /lib/ recursively + file: + path: /lib/ + state: directory + recurse: true + group: '0' + tags: + - DISA-STIG-OL09-00-002520 + - NIST-800-53-CM-5(6) + - NIST-800-53-CM-5(6).1 + - configure_strategy + - dir_group_ownership_library_dirs + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure group owner on /lib64/ recursively + file: + path: /lib64/ + state: directory + recurse: true + group: '0' + tags: + - DISA-STIG-OL09-00-002520 + - NIST-800-53-CM-5(6) + - NIST-800-53-CM-5(6).1 + - configure_strategy + - dir_group_ownership_library_dirs + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure group owner on /usr/lib/ recursively + file: + path: /usr/lib/ + state: directory + recurse: true + group: '0' + tags: + - DISA-STIG-OL09-00-002520 + - NIST-800-53-CM-5(6) + - NIST-800-53-CM-5(6).1 + - configure_strategy + - dir_group_ownership_library_dirs + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure group owner on /usr/lib64/ recursively + file: + path: /usr/lib64/ + state: directory + recurse: true + group: '0' + tags: + - DISA-STIG-OL09-00-002520 + - NIST-800-53-CM-5(6) + - NIST-800-53-CM-5(6).1 + - configure_strategy + - dir_group_ownership_library_dirs + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify that System Executable Have Root Ownership + /bin +/sbin +/usr/bin +/usr/sbin +/usr/local/bin +/usr/local/sbin +All these directories should be owned by the root user. +If any directory DIR in these directories is found +to be owned by a user other than root, correct its ownership with the +following command: +$ sudo chown root DIR + + + CCI-001495 + SRG-OS-000258-GPOS-00099 + System binaries are executed by privileged users as well as system services, +and restrictive permissions are necessary to ensure that their +execution of these programs cannot be co-opted. + find -H /bin/ -type d -exec chown -L 0 {} \; +find -H /sbin/ -type d -exec chown -L 0 {} \; +find -H /usr/bin/ -type d -exec chown -L 0 {} \; +find -H /usr/sbin/ -type d -exec chown -L 0 {} \; +find -H /usr/local/bin/ -type d -exec chown -L 0 {} \; +find -H /usr/local/sbin/ -type d -exec chown -L 0 {} \; + + - name: Ensure owner on directory /bin/ recursively + file: + path: /bin/ + state: directory + recurse: true + owner: '0' + tags: + - configure_strategy + - dir_ownership_binary_dirs + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure owner on directory /sbin/ recursively + file: + path: /sbin/ + state: directory + recurse: true + owner: '0' + tags: + - configure_strategy + - dir_ownership_binary_dirs + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure owner on directory /usr/bin/ recursively + file: + path: /usr/bin/ + state: directory + recurse: true + owner: '0' + tags: + - configure_strategy + - dir_ownership_binary_dirs + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure owner on directory /usr/sbin/ recursively + file: + path: /usr/sbin/ + state: directory + recurse: true + owner: '0' + tags: + - configure_strategy + - dir_ownership_binary_dirs + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure owner on directory /usr/local/bin/ recursively + file: + path: /usr/local/bin/ + state: directory + recurse: true + owner: '0' + tags: + - configure_strategy + - dir_ownership_binary_dirs + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure owner on directory /usr/local/sbin/ recursively + file: + path: /usr/local/sbin/ + state: directory + recurse: true + owner: '0' + tags: + - configure_strategy + - dir_ownership_binary_dirs + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify that Shared Library Directories Have Root Ownership + System-wide shared library files, which are linked to executables +during process load time or run time, are stored in the following directories +by default: +/lib +/lib64 +/usr/lib +/usr/lib64 + +Kernel modules, which can be added to the kernel during runtime, are also +stored in /lib/modules. All files in these directories should be +owned by the root user. If the directories, is found to be owned +by a user other than root correct its +ownership with the following command: +$ sudo chown root DIR + + + CCI-001499 + CM-5(6) + CM-5(6).1 + SRG-OS-000259-GPOS-00100 + OL09-00-002521 + SV-271787r1092073_rule + Files from shared library directories are loaded into the address +space of processes (including privileged ones) or of the kernel itself at +runtime. Proper ownership of library directories is necessary to protect +the integrity of the system. + find -H /lib/ -type d -exec chown -L 0 {} \; +find -H /lib64/ -type d -exec chown -L 0 {} \; +find -H /usr/lib/ -type d -exec chown -L 0 {} \; +find -H /usr/lib64/ -type d -exec chown -L 0 {} \; + + - name: Ensure owner on directory /lib/ recursively + file: + path: /lib/ + state: directory + recurse: true + owner: '0' + tags: + - DISA-STIG-OL09-00-002521 + - NIST-800-53-CM-5(6) + - NIST-800-53-CM-5(6).1 + - configure_strategy + - dir_ownership_library_dirs + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure owner on directory /lib64/ recursively + file: + path: /lib64/ + state: directory + recurse: true + owner: '0' + tags: + - DISA-STIG-OL09-00-002521 + - NIST-800-53-CM-5(6) + - NIST-800-53-CM-5(6).1 + - configure_strategy + - dir_ownership_library_dirs + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure owner on directory /usr/lib/ recursively + file: + path: /usr/lib/ + state: directory + recurse: true + owner: '0' + tags: + - DISA-STIG-OL09-00-002521 + - NIST-800-53-CM-5(6) + - NIST-800-53-CM-5(6).1 + - configure_strategy + - dir_ownership_library_dirs + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure owner on directory /usr/lib64/ recursively + file: + path: /usr/lib64/ + state: directory + recurse: true + owner: '0' + tags: + - DISA-STIG-OL09-00-002521 + - NIST-800-53-CM-5(6) + - NIST-800-53-CM-5(6).1 + - configure_strategy + - dir_ownership_library_dirs + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify that System Executable Directories Have Restrictive Permissions + System executables are stored in the following directories by default: +/bin +/sbin +/usr/bin +/usr/sbin +/usr/local/bin +/usr/local/sbin +These directories should not be group-writable or world-writable. +If any directory DIR in these directories is found to be +group-writable or world-writable, correct its permission with the +following command: +$ sudo chmod go-w DIR + + + CCI-001495 + SRG-OS-000258-GPOS-00099 + System binaries are executed by privileged users, as well as system services, +and restrictive permissions are necessary to ensure execution of these programs +cannot be co-opted. + + + + +find -H /bin/ -perm /u+s,g+ws,o+wt -type d -exec chmod u-s,g-ws,o-wt {} \; + +find -H /sbin/ -perm /u+s,g+ws,o+wt -type d -exec chmod u-s,g-ws,o-wt {} \; + +find -H /usr/bin/ -perm /u+s,g+ws,o+wt -type d -exec chmod u-s,g-ws,o-wt {} \; + +find -H /usr/sbin/ -perm /u+s,g+ws,o+wt -type d -exec chmod u-s,g-ws,o-wt {} \; + +find -H /usr/local/bin/ -perm /u+s,g+ws,o+wt -type d -exec chmod u-s,g-ws,o-wt {} \; + +find -H /usr/local/sbin/ -perm /u+s,g+ws,o+wt -type d -exec chmod u-s,g-ws,o-wt {} \; + + - name: Find /bin/ file(s) recursively + command: 'find -H /bin/ -perm /u+s,g+ws,o+wt -type d ' + register: files_found + changed_when: false + failed_when: false + check_mode: false + tags: + - configure_strategy + - dir_permissions_binary_dirs + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Set permissions for /bin/ file(s) + file: + path: '{{ item }}' + mode: u-s,g-ws,o-wt + state: directory + with_items: + - '{{ files_found.stdout_lines }}' + tags: + - configure_strategy + - dir_permissions_binary_dirs + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Find /sbin/ file(s) recursively + command: 'find -H /sbin/ -perm /u+s,g+ws,o+wt -type d ' + register: files_found + changed_when: false + failed_when: false + check_mode: false + tags: + - configure_strategy + - dir_permissions_binary_dirs + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Set permissions for /sbin/ file(s) + file: + path: '{{ item }}' + mode: u-s,g-ws,o-wt + state: directory + with_items: + - '{{ files_found.stdout_lines }}' + tags: + - configure_strategy + - dir_permissions_binary_dirs + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Find /usr/bin/ file(s) recursively + command: 'find -H /usr/bin/ -perm /u+s,g+ws,o+wt -type d ' + register: files_found + changed_when: false + failed_when: false + check_mode: false + tags: + - configure_strategy + - dir_permissions_binary_dirs + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Set permissions for /usr/bin/ file(s) + file: + path: '{{ item }}' + mode: u-s,g-ws,o-wt + state: directory + with_items: + - '{{ files_found.stdout_lines }}' + tags: + - configure_strategy + - dir_permissions_binary_dirs + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Find /usr/sbin/ file(s) recursively + command: 'find -H /usr/sbin/ -perm /u+s,g+ws,o+wt -type d ' + register: files_found + changed_when: false + failed_when: false + check_mode: false + tags: + - configure_strategy + - dir_permissions_binary_dirs + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Set permissions for /usr/sbin/ file(s) + file: + path: '{{ item }}' + mode: u-s,g-ws,o-wt + state: directory + with_items: + - '{{ files_found.stdout_lines }}' + tags: + - configure_strategy + - dir_permissions_binary_dirs + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Find /usr/local/bin/ file(s) recursively + command: 'find -H /usr/local/bin/ -perm /u+s,g+ws,o+wt -type d ' + register: files_found + changed_when: false + failed_when: false + check_mode: false + tags: + - configure_strategy + - dir_permissions_binary_dirs + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Set permissions for /usr/local/bin/ file(s) + file: + path: '{{ item }}' + mode: u-s,g-ws,o-wt + state: directory + with_items: + - '{{ files_found.stdout_lines }}' + tags: + - configure_strategy + - dir_permissions_binary_dirs + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Find /usr/local/sbin/ file(s) recursively + command: 'find -H /usr/local/sbin/ -perm /u+s,g+ws,o+wt -type d ' + register: files_found + changed_when: false + failed_when: false + check_mode: false + tags: + - configure_strategy + - dir_permissions_binary_dirs + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Set permissions for /usr/local/sbin/ file(s) + file: + path: '{{ item }}' + mode: u-s,g-ws,o-wt + state: directory + with_items: + - '{{ files_found.stdout_lines }}' + tags: + - configure_strategy + - dir_permissions_binary_dirs + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify that Shared Library Directories Have Restrictive Permissions + System-wide shared library directories, which contain are linked to executables +during process load time or run time, are stored in the following directories +by default: +/lib +/lib64 +/usr/lib +/usr/lib64 + +Kernel modules, which can be added to the kernel during runtime, are +stored in /lib/modules. All sub-directories in these directories +should not be group-writable or world-writable. If any file in these +directories is found to be group-writable or world-writable, correct +its permission with the following command: +$ sudo chmod go-w DIR + + + CCI-001499 + CIP-003-8 R6 + CM-5 + CM-5(6) + CM-5(6).1 + SRG-OS-000259-GPOS-00100 + OL09-00-002522 + SV-271788r1092076_rule + If the operating system were to allow any user to make changes to software libraries, +then those changes might be implemented without undergoing the appropriate testing +and approvals that are part of a robust change management process. + +This requirement applies to operating systems with software libraries that are accessible +and configurable, as in the case of interpreted languages. Software libraries also include +privileged programs which execute with escalated privileges. Only qualified and authorized +individuals must be allowed to obtain access to information system components for purposes +of initiating changes, including upgrades and modifications. + + + + +find -H /lib/ -perm /g+w,o+w -type d -exec chmod g-w,o-w {} \; + +find -H /lib64/ -perm /g+w,o+w -type d -exec chmod g-w,o-w {} \; + +find -H /usr/lib/ -perm /g+w,o+w -type d -exec chmod g-w,o-w {} \; + +find -H /usr/lib64/ -perm /g+w,o+w -type d -exec chmod g-w,o-w {} \; + + - name: Find /lib/ file(s) recursively + command: 'find -H /lib/ -perm /g+w,o+w -type d ' + register: files_found + changed_when: false + failed_when: false + check_mode: false + tags: + - DISA-STIG-OL09-00-002522 + - NIST-800-53-CM-5 + - NIST-800-53-CM-5(6) + - NIST-800-53-CM-5(6).1 + - configure_strategy + - dir_permissions_library_dirs + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Set permissions for /lib/ file(s) + file: + path: '{{ item }}' + mode: g-w,o-w + state: directory + with_items: + - '{{ files_found.stdout_lines }}' + tags: + - DISA-STIG-OL09-00-002522 + - NIST-800-53-CM-5 + - NIST-800-53-CM-5(6) + - NIST-800-53-CM-5(6).1 + - configure_strategy + - dir_permissions_library_dirs + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Find /lib64/ file(s) recursively + command: 'find -H /lib64/ -perm /g+w,o+w -type d ' + register: files_found + changed_when: false + failed_when: false + check_mode: false + tags: + - DISA-STIG-OL09-00-002522 + - NIST-800-53-CM-5 + - NIST-800-53-CM-5(6) + - NIST-800-53-CM-5(6).1 + - configure_strategy + - dir_permissions_library_dirs + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Set permissions for /lib64/ file(s) + file: + path: '{{ item }}' + mode: g-w,o-w + state: directory + with_items: + - '{{ files_found.stdout_lines }}' + tags: + - DISA-STIG-OL09-00-002522 + - NIST-800-53-CM-5 + - NIST-800-53-CM-5(6) + - NIST-800-53-CM-5(6).1 + - configure_strategy + - dir_permissions_library_dirs + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Find /usr/lib/ file(s) recursively + command: 'find -H /usr/lib/ -perm /g+w,o+w -type d ' + register: files_found + changed_when: false + failed_when: false + check_mode: false + tags: + - DISA-STIG-OL09-00-002522 + - NIST-800-53-CM-5 + - NIST-800-53-CM-5(6) + - NIST-800-53-CM-5(6).1 + - configure_strategy + - dir_permissions_library_dirs + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Set permissions for /usr/lib/ file(s) + file: + path: '{{ item }}' + mode: g-w,o-w + state: directory + with_items: + - '{{ files_found.stdout_lines }}' + tags: + - DISA-STIG-OL09-00-002522 + - NIST-800-53-CM-5 + - NIST-800-53-CM-5(6) + - NIST-800-53-CM-5(6).1 + - configure_strategy + - dir_permissions_library_dirs + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Find /usr/lib64/ file(s) recursively + command: 'find -H /usr/lib64/ -perm /g+w,o+w -type d ' + register: files_found + changed_when: false + failed_when: false + check_mode: false + tags: + - DISA-STIG-OL09-00-002522 + - NIST-800-53-CM-5 + - NIST-800-53-CM-5(6) + - NIST-800-53-CM-5(6).1 + - configure_strategy + - dir_permissions_library_dirs + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Set permissions for /usr/lib64/ file(s) + file: + path: '{{ item }}' + mode: g-w,o-w + state: directory + with_items: + - '{{ files_found.stdout_lines }}' + tags: + - DISA-STIG-OL09-00-002522 + - NIST-800-53-CM-5 + - NIST-800-53-CM-5(6) + - NIST-800-53-CM-5(6).1 + - configure_strategy + - dir_permissions_library_dirs + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify Group Who Owns /etc/sysctl.d Directory + To properly set the group owner of /etc/sysctl.d, run the command: $ sudo chgrp root /etc/sysctl.d + + R50 + The ownership of the /etc/sysctl.d directory by the root group is important +because this directory hosts kernel configuration. Protection of this +directory is critical for system security. Assigning the ownership to root +ensures exclusive control of the kernel configuration. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +find -H /etc/sysctl.d/ -maxdepth 1 -type d -exec chgrp -L root {} \; + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - configure_strategy + - directory_groupowner_etc_sysctld + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure group owner on /etc/sysctl.d/ + file: + path: /etc/sysctl.d/ + state: directory + group: root + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - configure_strategy + - directory_groupowner_etc_sysctld + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify User Who Owns /etc/sysctl.d Directory + To properly set the owner of /etc/sysctl.d, run the command: $ sudo chown root /etc/sysctl.d + + R50 + The ownership of the /etc/sysctl.d directory by the root user is important +because this directory hosts kernel configuration. Protection of this +directory is critical for system security. Assigning the ownership to root +ensures exclusive control of the kernel configuration. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +find -H /etc/sysctl.d/ -maxdepth 1 -type d -exec chown -L 0 {} \; + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - configure_strategy + - directory_owner_etc_sysctld + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure owner on directory /etc/sysctl.d/ + file: + path: /etc/sysctl.d/ + state: directory + owner: '0' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - configure_strategy + - directory_owner_etc_sysctld + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify Permissions On /etc/sysctl.d Directory + To properly set the permissions of /etc/sysctl.d, run the command: $ sudo chmod 0755 /etc/sysctl.d + + R50 + Setting correct permissions on the /etc/sysctl.d directory is important +because this directory hosts kernel configuration. Protection of this +directory is critical for system security. Restricting the permissions +ensures exclusive control of the kernel configuration. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +find -H /etc/sysctl.d/ -maxdepth 1 -perm /u+s,g+ws,o+wt -type d -exec chmod u-s,g-ws,o-wt {} \; + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - configure_strategy + - directory_permissions_etc_sysctld + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Find /etc/sysctl.d/ file(s) + command: 'find -H /etc/sysctl.d/ -maxdepth 1 -perm /u+s,g+ws,o+wt -type d ' + register: files_found + changed_when: false + failed_when: false + check_mode: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - configure_strategy + - directory_permissions_etc_sysctld + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Set permissions for /etc/sysctl.d/ file(s) + file: + path: '{{ item }}' + mode: u-s,g-ws,o-wt + state: directory + with_items: + - '{{ files_found.stdout_lines }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - configure_strategy + - directory_permissions_etc_sysctld + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify that system commands files are group owned by root or a system account + System commands files are stored in the following directories by default: +/bin +/sbin +/usr/bin +/usr/sbin +/usr/local/bin +/usr/local/sbin + +All files in these directories should be owned by the root group, +or a system account. +If the directory, or any file in these directories, is found to be owned +by a group other than root or a a system account correct its ownership +with the following command: +$ sudo chgrp root FILE + + + CCI-001499 + CM-5(6) + CM-5(6).1 + SRG-OS-000259-GPOS-00100 + R50 + OL09-00-002504 + SV-271773r1092031_rule + If the operating system allows any user to make changes to software +libraries, then those changes might be implemented without undergoing the +appropriate testing and approvals that are part of a robust change management +process. +This requirement applies to operating systems with software libraries +that are accessible and configurable, as in the case of interpreted languages. +Software libraries also include privileged programs which execute with +escalated privileges. Only qualified and authorized individuals must be +allowed to obtain access to information system components for purposes +of initiating changes, including upgrades and modifications. + +for SYSCMDFILES in /bin /sbin /usr/bin /usr/sbin /usr/local/bin /usr/local/sbin +do + find -L $SYSCMDFILES \! -group root -type f -exec chgrp root '{}' \; +done + + - name: Retrieve the system command files and set their group ownership to root + command: find -L {{ item }} ! -group root -type f -exec chgrp root '{}' \; + with_items: + - /bin + - /sbin + - /usr/bin + - /usr/sbin + - /usr/local/bin + - /usr/local/sbin + changed_when: false + failed_when: false + check_mode: false + tags: + - DISA-STIG-OL09-00-002504 + - NIST-800-53-CM-5(6) + - NIST-800-53-CM-5(6).1 + - file_groupownership_system_commands_dirs + - medium_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + + + + + + + + + + Verify that System Executables Have Root Ownership + System executables are stored in the following directories by default: +/bin +/sbin +/usr/bin +/usr/libexec +/usr/local/bin +/usr/local/sbin +/usr/sbin +All files in these directories should be owned by the root user. +If any file FILE in these directories is found +to be owned by a user other than root, correct its ownership with the +following command: +$ sudo chown root FILE + + + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + APO01.06 + DSS05.04 + DSS05.07 + DSS06.02 + CCI-001499 + 4.3.3.7.3 + SR 2.1 + SR 5.2 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 + CM-5(6) + CM-5(6).1 + CM-6(a) + AC-6(1) + PR.AC-4 + PR.DS-5 + SRG-OS-000259-GPOS-00100 + R50 + OL09-00-002505 + SV-271774r1092034_rule + System binaries are executed by privileged users as well as system services, +and restrictive permissions are necessary to ensure that their +execution of these programs cannot be co-opted. + find /bin/ \ +/usr/bin/ \ +/usr/local/bin/ \ +/sbin/ \ +/usr/sbin/ \ +/usr/local/sbin/ \ +/usr/libexec \ +\! -user root -execdir chown root {} \; + + - name: Read list of system executables without root ownership + command: find /bin/ /usr/bin/ /usr/local/bin/ /sbin/ /usr/sbin/ /usr/local/sbin/ + /usr/libexec \! -user root + register: no_root_system_executables + changed_when: false + failed_when: false + check_mode: false + tags: + - DISA-STIG-OL09-00-002505 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-5(6) + - NIST-800-53-CM-5(6).1 + - NIST-800-53-CM-6(a) + - file_ownership_binary_dirs + - medium_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Set ownership to root of system executables + file: + path: '{{ item }}' + owner: root + with_items: '{{ no_root_system_executables.stdout_lines }}' + when: no_root_system_executables.stdout_lines | length > 0 + tags: + - DISA-STIG-OL09-00-002505 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-5(6) + - NIST-800-53-CM-5(6).1 + - NIST-800-53-CM-6(a) + - file_ownership_binary_dirs + - medium_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + + + + + + + + + + Verify that Shared Library Files Have Root Ownership + System-wide shared library files, which are linked to executables +during process load time or run time, are stored in the following directories +by default: +/lib +/lib64 +/usr/lib +/usr/lib64 + +Kernel modules, which can be added to the kernel during runtime, are also +stored in /lib/modules. All files in these directories should be +owned by the root user. If the directory, or any file in these +directories, is found to be owned by a user other than root correct its +ownership with the following command: +$ sudo chown root FILE + + + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + APO01.06 + DSS05.04 + DSS05.07 + DSS06.02 + CCI-001499 + 4.3.3.7.3 + SR 2.1 + SR 5.2 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 + CM-5(6) + CM-5(6).1 + CM-6(a) + AC-6(1) + PR.AC-4 + PR.DS-5 + SRG-OS-000259-GPOS-00100 + OL09-00-002524 + SV-271790r1092082_rule + Files from shared library directories are loaded into the address +space of processes (including privileged ones) or of the kernel itself at +runtime. Proper ownership is necessary to protect the integrity of the system. + +find /lib/ -type f ! -uid 0 -regextype posix-extended -regex '^.*$' -exec chown -L 0 {} \; + +find /lib64/ -type f ! -uid 0 -regextype posix-extended -regex '^.*$' -exec chown -L 0 {} \; + +find /usr/lib/ -type f ! -uid 0 -regextype posix-extended -regex '^.*$' -exec chown -L 0 {} \; + +find /usr/lib64/ -type f ! -uid 0 -regextype posix-extended -regex '^.*$' -exec chown -L 0 {} \; + + - name: Find /lib/ file(s) matching ^.*$ recursively + command: find -H /lib/ -type f ! -uid 0 -regextype posix-extended -regex "^.*$" + register: files_found + changed_when: false + failed_when: false + check_mode: false + tags: + - DISA-STIG-OL09-00-002524 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-5(6) + - NIST-800-53-CM-5(6).1 + - NIST-800-53-CM-6(a) + - configure_strategy + - file_ownership_library_dirs + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure owner on /lib/ file(s) matching ^.*$ + file: + path: '{{ item }}' + owner: '0' + state: file + with_items: + - '{{ files_found.stdout_lines }}' + tags: + - DISA-STIG-OL09-00-002524 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-5(6) + - NIST-800-53-CM-5(6).1 + - NIST-800-53-CM-6(a) + - configure_strategy + - file_ownership_library_dirs + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Find /lib64/ file(s) matching ^.*$ recursively + command: find -H /lib64/ -type f ! -uid 0 -regextype posix-extended -regex "^.*$" + register: files_found + changed_when: false + failed_when: false + check_mode: false + tags: + - DISA-STIG-OL09-00-002524 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-5(6) + - NIST-800-53-CM-5(6).1 + - NIST-800-53-CM-6(a) + - configure_strategy + - file_ownership_library_dirs + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure owner on /lib64/ file(s) matching ^.*$ + file: + path: '{{ item }}' + owner: '0' + state: file + with_items: + - '{{ files_found.stdout_lines }}' + tags: + - DISA-STIG-OL09-00-002524 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-5(6) + - NIST-800-53-CM-5(6).1 + - NIST-800-53-CM-6(a) + - configure_strategy + - file_ownership_library_dirs + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Find /usr/lib/ file(s) matching ^.*$ recursively + command: find -H /usr/lib/ -type f ! -uid 0 -regextype posix-extended -regex "^.*$" + register: files_found + changed_when: false + failed_when: false + check_mode: false + tags: + - DISA-STIG-OL09-00-002524 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-5(6) + - NIST-800-53-CM-5(6).1 + - NIST-800-53-CM-6(a) + - configure_strategy + - file_ownership_library_dirs + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure owner on /usr/lib/ file(s) matching ^.*$ + file: + path: '{{ item }}' + owner: '0' + state: file + with_items: + - '{{ files_found.stdout_lines }}' + tags: + - DISA-STIG-OL09-00-002524 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-5(6) + - NIST-800-53-CM-5(6).1 + - NIST-800-53-CM-6(a) + - configure_strategy + - file_ownership_library_dirs + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Find /usr/lib64/ file(s) matching ^.*$ recursively + command: find -H /usr/lib64/ -type f ! -uid 0 -regextype posix-extended -regex + "^.*$" + register: files_found + changed_when: false + failed_when: false + check_mode: false + tags: + - DISA-STIG-OL09-00-002524 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-5(6) + - NIST-800-53-CM-5(6).1 + - NIST-800-53-CM-6(a) + - configure_strategy + - file_ownership_library_dirs + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure owner on /usr/lib64/ file(s) matching ^.*$ + file: + path: '{{ item }}' + owner: '0' + state: file + with_items: + - '{{ files_found.stdout_lines }}' + tags: + - DISA-STIG-OL09-00-002524 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-5(6) + - NIST-800-53-CM-5(6).1 + - NIST-800-53-CM-6(a) + - configure_strategy + - file_ownership_library_dirs + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify that System Executables Have Restrictive Permissions + System executables are stored in the following directories by default: +/bin +/sbin +/usr/bin +/usr/libexec +/usr/local/bin +/usr/local/sbin +/usr/sbin +All files in these directories should not be group-writable or world-writable. +If any file FILE in these directories is found +to be group-writable or world-writable, correct its permission with the +following command: +$ sudo chmod go-w FILE + + + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + APO01.06 + DSS05.04 + DSS05.07 + DSS06.02 + CCI-001499 + 4.3.3.7.3 + SR 2.1 + SR 5.2 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 + CM-5(6) + CM-5(6).1 + CM-6(a) + AC-6(1) + PR.AC-4 + PR.DS-5 + SRG-OS-000259-GPOS-00100 + R50 + OL09-00-002506 + SV-271775r1092037_rule + System binaries are executed by privileged users, as well as system services, +and restrictive permissions are necessary to ensure execution of these programs +cannot be co-opted. + DIRS="/bin /usr/bin /usr/local/bin /sbin /usr/sbin /usr/local/sbin /usr/libexec" +for dirPath in $DIRS; do + find "$dirPath" -perm /022 -exec chmod go-w '{}' \; +done + + - name: Read list of world and group writable system executables + ansible.builtin.command: find /bin /usr/bin /usr/local/bin /sbin /usr/sbin /usr/local/sbin + /usr/libexec -perm /022 -type f + register: world_writable_library_files + changed_when: false + failed_when: false + check_mode: false + tags: + - DISA-STIG-OL09-00-002506 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-5(6) + - NIST-800-53-CM-5(6).1 + - NIST-800-53-CM-6(a) + - file_permissions_binary_dirs + - medium_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Remove world/group writability of system executables + ansible.builtin.file: + path: '{{ item }}' + mode: go-w + state: file + with_items: '{{ world_writable_library_files.stdout_lines }}' + when: world_writable_library_files.stdout_lines | length > 0 + tags: + - DISA-STIG-OL09-00-002506 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-5(6) + - NIST-800-53-CM-5(6).1 + - NIST-800-53-CM-6(a) + - file_permissions_binary_dirs + - medium_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + + + + + + + + + + Verify that Shared Library Files Have Restrictive Permissions + System-wide shared library files, which are linked to executables +during process load time or run time, are stored in the following directories +by default: +/lib +/lib64 +/usr/lib +/usr/lib64 + +Kernel modules, which can be added to the kernel during runtime, are +stored in /lib/modules. All files in these directories +should not be group-writable or world-writable. If any file in these +directories is found to be group-writable or world-writable, correct +its permission with the following command: +$ sudo chmod go-w FILE + + + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + APO01.06 + DSS05.04 + DSS05.07 + DSS06.02 + CCI-001499 + 4.3.3.7.3 + SR 2.1 + SR 5.2 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 + CM-6(a) + CM-5(6) + CM-5(6).1 + AC-6(1) + PR.AC-4 + PR.DS-5 + SRG-OS-000259-GPOS-00100 + OL09-00-002525 + SV-271791r1092085_rule + Files from shared library directories are loaded into the address +space of processes (including privileged ones) or of the kernel itself at +runtime. Restrictive permissions are necessary to protect the integrity of the system. + + + + +find /lib/ -perm /g+w,o+w -type f -regextype posix-extended -regex '^.*$' -exec chmod g-w,o-w {} \; + +find /lib64/ -perm /g+w,o+w -type f -regextype posix-extended -regex '^.*$' -exec chmod g-w,o-w {} \; + +find /usr/lib/ -perm /g+w,o+w -type f -regextype posix-extended -regex '^.*$' -exec chmod g-w,o-w {} \; + +find /usr/lib64/ -perm /g+w,o+w -type f -regextype posix-extended -regex '^.*$' -exec chmod g-w,o-w {} \; + + - name: Find /lib/ file(s) recursively + command: find -H /lib/ -perm /g+w,o+w -type f -regextype posix-extended -regex + "^.*$" + register: files_found + changed_when: false + failed_when: false + check_mode: false + tags: + - DISA-STIG-OL09-00-002525 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-5(6) + - NIST-800-53-CM-5(6).1 + - NIST-800-53-CM-6(a) + - configure_strategy + - file_permissions_library_dirs + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Set permissions for /lib/ file(s) + file: + path: '{{ item }}' + mode: g-w,o-w + state: file + with_items: + - '{{ files_found.stdout_lines }}' + tags: + - DISA-STIG-OL09-00-002525 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-5(6) + - NIST-800-53-CM-5(6).1 + - NIST-800-53-CM-6(a) + - configure_strategy + - file_permissions_library_dirs + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Find /lib64/ file(s) recursively + command: find -H /lib64/ -perm /g+w,o+w -type f -regextype posix-extended -regex + "^.*$" + register: files_found + changed_when: false + failed_when: false + check_mode: false + tags: + - DISA-STIG-OL09-00-002525 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-5(6) + - NIST-800-53-CM-5(6).1 + - NIST-800-53-CM-6(a) + - configure_strategy + - file_permissions_library_dirs + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Set permissions for /lib64/ file(s) + file: + path: '{{ item }}' + mode: g-w,o-w + state: file + with_items: + - '{{ files_found.stdout_lines }}' + tags: + - DISA-STIG-OL09-00-002525 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-5(6) + - NIST-800-53-CM-5(6).1 + - NIST-800-53-CM-6(a) + - configure_strategy + - file_permissions_library_dirs + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Find /usr/lib/ file(s) recursively + command: find -H /usr/lib/ -perm /g+w,o+w -type f -regextype posix-extended -regex + "^.*$" + register: files_found + changed_when: false + failed_when: false + check_mode: false + tags: + - DISA-STIG-OL09-00-002525 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-5(6) + - NIST-800-53-CM-5(6).1 + - NIST-800-53-CM-6(a) + - configure_strategy + - file_permissions_library_dirs + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Set permissions for /usr/lib/ file(s) + file: + path: '{{ item }}' + mode: g-w,o-w + state: file + with_items: + - '{{ files_found.stdout_lines }}' + tags: + - DISA-STIG-OL09-00-002525 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-5(6) + - NIST-800-53-CM-5(6).1 + - NIST-800-53-CM-6(a) + - configure_strategy + - file_permissions_library_dirs + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Find /usr/lib64/ file(s) recursively + command: find -H /usr/lib64/ -perm /g+w,o+w -type f -regextype posix-extended + -regex "^.*$" + register: files_found + changed_when: false + failed_when: false + check_mode: false + tags: + - DISA-STIG-OL09-00-002525 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-5(6) + - NIST-800-53-CM-5(6).1 + - NIST-800-53-CM-6(a) + - configure_strategy + - file_permissions_library_dirs + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Set permissions for /usr/lib64/ file(s) + file: + path: '{{ item }}' + mode: g-w,o-w + state: file + with_items: + - '{{ files_found.stdout_lines }}' + tags: + - DISA-STIG-OL09-00-002525 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-5(6) + - NIST-800-53-CM-5(6).1 + - NIST-800-53-CM-6(a) + - configure_strategy + - file_permissions_library_dirs + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify the system-wide library files in directories +"/lib", "/lib64", "/usr/lib/" and "/usr/lib64" are group-owned by root. + System-wide library files are stored in the following directories +by default: +/lib +/lib64 +/usr/lib +/usr/lib64 + +All system-wide shared library files should be protected from unauthorised +access. If any of these files is not group-owned by root, correct its group-owner with +the following command: +$ sudo chgrp root FILE + + + CCI-001499 + CM-5(6) + CM-5(6).1 + SRG-OS-000259-GPOS-00100 + OL09-00-002523 + SV-271789r1092079_rule + If the operating system were to allow any user to make changes to software libraries, +then those changes might be implemented without undergoing the appropriate testing and +approvals that are part of a robust change management process. + +This requirement applies to operating systems with software libraries that are +accessible and configurable, as in the case of interpreted languages. Software libraries +also include privileged programs which execute with escalated privileges. Only qualified +and authorized individuals must be allowed to obtain access to information system components +for purposes of initiating changes, including upgrades and modifications. + +find /lib/ -type f ! -group 0 -regextype posix-extended -regex '^.*$' -exec chgrp -L 0 {} \; + +find /lib64/ -type f ! -group 0 -regextype posix-extended -regex '^.*$' -exec chgrp -L 0 {} \; + +find /usr/lib/ -type f ! -group 0 -regextype posix-extended -regex '^.*$' -exec chgrp -L 0 {} \; + +find /usr/lib64/ -type f ! -group 0 -regextype posix-extended -regex '^.*$' -exec chgrp -L 0 {} \; + + - name: Find /lib/ file(s) matching ^.*$ recursively + command: find -H /lib/ -type f ! -group 0 -regextype posix-extended -regex "^.*$" + register: files_found + changed_when: false + failed_when: false + check_mode: false + tags: + - DISA-STIG-OL09-00-002523 + - NIST-800-53-CM-5(6) + - NIST-800-53-CM-5(6).1 + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - root_permissions_syslibrary_files + +- name: Ensure group owner on /lib/ file(s) matching ^.*$ + file: + path: '{{ item }}' + group: '0' + state: file + with_items: + - '{{ files_found.stdout_lines }}' + tags: + - DISA-STIG-OL09-00-002523 + - NIST-800-53-CM-5(6) + - NIST-800-53-CM-5(6).1 + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - root_permissions_syslibrary_files + +- name: Find /lib64/ file(s) matching ^.*$ recursively + command: find -H /lib64/ -type f ! -group 0 -regextype posix-extended -regex "^.*$" + register: files_found + changed_when: false + failed_when: false + check_mode: false + tags: + - DISA-STIG-OL09-00-002523 + - NIST-800-53-CM-5(6) + - NIST-800-53-CM-5(6).1 + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - root_permissions_syslibrary_files + +- name: Ensure group owner on /lib64/ file(s) matching ^.*$ + file: + path: '{{ item }}' + group: '0' + state: file + with_items: + - '{{ files_found.stdout_lines }}' + tags: + - DISA-STIG-OL09-00-002523 + - NIST-800-53-CM-5(6) + - NIST-800-53-CM-5(6).1 + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - root_permissions_syslibrary_files + +- name: Find /usr/lib/ file(s) matching ^.*$ recursively + command: find -H /usr/lib/ -type f ! -group 0 -regextype posix-extended -regex + "^.*$" + register: files_found + changed_when: false + failed_when: false + check_mode: false + tags: + - DISA-STIG-OL09-00-002523 + - NIST-800-53-CM-5(6) + - NIST-800-53-CM-5(6).1 + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - root_permissions_syslibrary_files + +- name: Ensure group owner on /usr/lib/ file(s) matching ^.*$ + file: + path: '{{ item }}' + group: '0' + state: file + with_items: + - '{{ files_found.stdout_lines }}' + tags: + - DISA-STIG-OL09-00-002523 + - NIST-800-53-CM-5(6) + - NIST-800-53-CM-5(6).1 + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - root_permissions_syslibrary_files + +- name: Find /usr/lib64/ file(s) matching ^.*$ recursively + command: find -H /usr/lib64/ -type f ! -group 0 -regextype posix-extended -regex + "^.*$" + register: files_found + changed_when: false + failed_when: false + check_mode: false + tags: + - DISA-STIG-OL09-00-002523 + - NIST-800-53-CM-5(6) + - NIST-800-53-CM-5(6).1 + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - root_permissions_syslibrary_files + +- name: Ensure group owner on /usr/lib64/ file(s) matching ^.*$ + file: + path: '{{ item }}' + group: '0' + state: file + with_items: + - '{{ files_found.stdout_lines }}' + tags: + - DISA-STIG-OL09-00-002523 + - NIST-800-53-CM-5(6) + - NIST-800-53-CM-5(6).1 + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - root_permissions_syslibrary_files + + + + + + + + + + + + Restrict Dynamic Mounting and Unmounting of +Filesystems + Linux includes a number of facilities for the automated addition +and removal of filesystems on a running system. These facilities may be +necessary in many environments, but this capability also carries some risk -- whether direct +risk from allowing users to introduce arbitrary filesystems, +or risk that software flaws in the automated mount facility itself could +allow an attacker to compromise the system. + + +This command can be used to list the types of filesystems that are +available to the currently executing kernel: +$ find /lib/modules/`uname -r`/kernel/fs -type f -name '*.ko' +If these filesystems are not required then they can be explicitly disabled +in a configuratio file in /etc/modprobe.d. + + Disable the Automounter + The autofs daemon mounts and unmounts filesystems, such as user +home directories shared via NFS, on demand. In addition, autofs can be used to handle +removable media, and the default configuration provides the cdrom device as /misc/cd. +However, this method of providing access to removable media is not common, so autofs +can almost always be disabled if NFS is not in use. Even if NFS is required, it may be +possible to configure filesystem mounts statically by editing /etc/fstab +rather than relying on the automounter. + + + +The autofs service can be disabled with the following command: +$ sudo systemctl mask --now autofs.service + + 1 + 12 + 15 + 16 + 5 + APO13.01 + DSS01.04 + DSS05.03 + DSS05.04 + DSS05.05 + DSS05.07 + DSS05.10 + DSS06.03 + DSS06.10 + 3.4.6 + CCI-000778 + CCI-000366 + CCI-001958 + 164.308(a)(3)(i) + 164.308(a)(3)(ii)(A) + 164.310(d)(1) + 164.310(d)(2) + 164.312(a)(1) + 164.312(a)(2)(iv) + 164.312(b) + 4.3.3.2.2 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.2 + 4.3.3.7.4 + SR 1.1 + SR 1.10 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.6 + A.11.2.6 + A.13.1.1 + A.13.2.1 + A.18.1.4 + A.6.2.1 + A.6.2.2 + A.7.1.1 + A.9.2.1 + A.9.2.2 + A.9.2.3 + A.9.2.4 + A.9.2.6 + A.9.3.1 + A.9.4.2 + A.9.4.3 + CM-7(a) + CM-7(b) + CM-6(a) + MP-7 + PR.AC-1 + PR.AC-3 + PR.AC-6 + PR.AC-7 + SRG-OS-000114-GPOS-00059 + SRG-OS-000378-GPOS-00163 + SRG-OS-000480-GPOS-00227 + OL09-00-002000 + SV-271639r1091629_rule + Disabling the automounter permits the administrator to +statically control filesystem mounting through /etc/fstab. + + +Additionally, automatically mounting filesystems permits easy introduction of +unknown devices, thereby facilitating malicious activity. + + # Remediation is applicable only in certain platforms +if ( rpm --quiet -q autofs && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ); then + +SYSTEMCTL_EXEC='/usr/bin/systemctl' +if [[ $("$SYSTEMCTL_EXEC" is-system-running) != "offline" ]]; then + "$SYSTEMCTL_EXEC" stop 'autofs.service' +fi +"$SYSTEMCTL_EXEC" disable 'autofs.service' +"$SYSTEMCTL_EXEC" mask 'autofs.service' +# Disable socket activation if we have a unit file for it +if "$SYSTEMCTL_EXEC" -q list-unit-files autofs.socket; then + if [[ $("$SYSTEMCTL_EXEC" is-system-running) != "offline" ]]; then + "$SYSTEMCTL_EXEC" stop 'autofs.socket' + fi + "$SYSTEMCTL_EXEC" mask 'autofs.socket' +fi +# The service may not be running because it has been started and failed, +# so let's reset the state so OVAL checks pass. +# Service should be 'inactive', not 'failed' after reboot though. +"$SYSTEMCTL_EXEC" reset-failed 'autofs.service' || true + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002000 + - NIST-800-171-3.4.6 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - disable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_autofs_disabled + +- name: Disable the Automounter - Collect systemd Services Present in the System + ansible.builtin.command: systemctl -q list-unit-files --type service + register: service_exists + changed_when: false + failed_when: service_exists.rc not in [0, 1] + check_mode: false + when: ( "autofs" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + tags: + - DISA-STIG-OL09-00-002000 + - NIST-800-171-3.4.6 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - disable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_autofs_disabled + +- name: Disable the Automounter - Ensure autofs.service is Masked + ansible.builtin.systemd: + name: autofs.service + state: stopped + enabled: false + masked: true + when: + - ( "autofs" in ansible_facts.packages and ("kernel" in ansible_facts.packages or + "kernel-uek" in ansible_facts.packages) ) + - service_exists.stdout_lines is search("autofs.service", multiline=True) + tags: + - DISA-STIG-OL09-00-002000 + - NIST-800-171-3.4.6 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - disable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_autofs_disabled + +- name: Unit Socket Exists - autofs.socket + ansible.builtin.command: systemctl -q list-unit-files autofs.socket + register: socket_file_exists + changed_when: false + failed_when: socket_file_exists.rc not in [0, 1] + check_mode: false + when: ( "autofs" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + tags: + - DISA-STIG-OL09-00-002000 + - NIST-800-171-3.4.6 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - disable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_autofs_disabled + +- name: Disable the Automounter - Disable Socket autofs + ansible.builtin.systemd: + name: autofs.socket + enabled: false + state: stopped + masked: true + when: + - ( "autofs" in ansible_facts.packages and ("kernel" in ansible_facts.packages or + "kernel-uek" in ansible_facts.packages) ) + - socket_file_exists.stdout_lines is search("autofs.socket", multiline=True) + tags: + - DISA-STIG-OL09-00-002000 + - NIST-800-171-3.4.6 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - disable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_autofs_disabled + + include disable_autofs + +class disable_autofs { + service {'autofs': + enable => false, + ensure => 'stopped', + } +} + + +[customizations.services] +masked = ["autofs"] + + + + + + + + + + Disable Mounting of cramfs + +To configure the system to prevent the cramfs +kernel module from being loaded, add the following line to the file /etc/modprobe.d/cramfs.conf: +install cramfs /bin/false + +To configure the system to prevent the cramfs from being used, +add the following line to file /etc/modprobe.d/cramfs.conf: +blacklist cramfs + +This effectively prevents usage of this uncommon filesystem. + +The cramfs filesystem type is a compressed read-only +Linux filesystem embedded in small footprint systems. A +cramfs image can be used without having to first +decompress the image. + 11 + 14 + 3 + 9 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS05.02 + DSS05.05 + DSS06.06 + 3.4.6 + CCI-000381 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.2 + 4.3.4.3.3 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 7.6 + A.12.1.2 + A.12.5.1 + A.12.6.2 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.9.1.2 + CM-7(a) + CM-7(b) + CM-6(a) + PR.IP-1 + PR.PT-3 + SRG-OS-000095-GPOS-00049 + OL09-00-000045 + SV-271448r1091056_rule + Removing support for unneeded filesystem types reduces the local attack surface +of the server. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +if LC_ALL=C grep -q -m 1 "^install cramfs" /etc/modprobe.d/cramfs.conf ; then + + sed -i 's#^install cramfs.*#install cramfs /bin/false#g' /etc/modprobe.d/cramfs.conf +else + echo -e "\n# Disable per security requirements" >> /etc/modprobe.d/cramfs.conf + echo "install cramfs /bin/false" >> /etc/modprobe.d/cramfs.conf +fi + +if ! LC_ALL=C grep -q -m 1 "^blacklist cramfs$" /etc/modprobe.d/cramfs.conf ; then + echo "blacklist cramfs" >> /etc/modprobe.d/cramfs.conf +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-000045 + - NIST-800-171-3.4.6 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - kernel_module_cramfs_disabled + - low_complexity + - low_severity + - medium_disruption + - reboot_required + +- name: Ensure kernel module 'cramfs' is disabled + lineinfile: + create: true + dest: /etc/modprobe.d/cramfs.conf + regexp: install\s+cramfs + line: install cramfs /bin/false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-000045 + - NIST-800-171-3.4.6 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - kernel_module_cramfs_disabled + - low_complexity + - low_severity + - medium_disruption + - reboot_required + +- name: Ensure kernel module 'cramfs' is blacklisted + lineinfile: + create: true + dest: /etc/modprobe.d/cramfs.conf + regexp: ^blacklist cramfs$ + line: blacklist cramfs + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-000045 + - NIST-800-171-3.4.6 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - kernel_module_cramfs_disabled + - low_complexity + - low_severity + - medium_disruption + - reboot_required + + + + + + + + + + Disable Mounting of squashfs + +To configure the system to prevent the squashfs +kernel module from being loaded, add the following line to the file /etc/modprobe.d/squashfs.conf: +install squashfs /bin/false + +To configure the system to prevent the squashfs from being used, +add the following line to file /etc/modprobe.d/squashfs.conf: +blacklist squashfs + +This effectively prevents usage of this uncommon filesystem. + +The squashfs filesystem type is a compressed read-only Linux +filesystem embedded in small footprint systems (similar to +cramfs). A squashfs image can be used without having +to first decompress the image. + 11 + 14 + 3 + 9 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS05.02 + DSS05.05 + DSS06.06 + 3.4.6 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.2 + 4.3.4.3.3 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 7.6 + A.12.1.2 + A.12.5.1 + A.12.6.2 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.9.1.2 + CM-7(a) + CM-7(b) + CM-6(a) + PR.IP-1 + PR.PT-3 + A.8.SEC-OL4 + Removing support for unneeded filesystem types reduces the local attack +surface of the system. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +if LC_ALL=C grep -q -m 1 "^install squashfs" /etc/modprobe.d/squashfs.conf ; then + + sed -i 's#^install squashfs.*#install squashfs /bin/false#g' /etc/modprobe.d/squashfs.conf +else + echo -e "\n# Disable per security requirements" >> /etc/modprobe.d/squashfs.conf + echo "install squashfs /bin/false" >> /etc/modprobe.d/squashfs.conf +fi + +if ! LC_ALL=C grep -q -m 1 "^blacklist squashfs$" /etc/modprobe.d/squashfs.conf ; then + echo "blacklist squashfs" >> /etc/modprobe.d/squashfs.conf +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-171-3.4.6 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - kernel_module_squashfs_disabled + - low_complexity + - low_severity + - medium_disruption + - reboot_required + +- name: Ensure kernel module 'squashfs' is disabled + lineinfile: + create: true + dest: /etc/modprobe.d/squashfs.conf + regexp: install\s+squashfs + line: install squashfs /bin/false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-171-3.4.6 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - kernel_module_squashfs_disabled + - low_complexity + - low_severity + - medium_disruption + - reboot_required + +- name: Ensure kernel module 'squashfs' is blacklisted + lineinfile: + create: true + dest: /etc/modprobe.d/squashfs.conf + regexp: ^blacklist squashfs$ + line: blacklist squashfs + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-171-3.4.6 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - kernel_module_squashfs_disabled + - low_complexity + - low_severity + - medium_disruption + - reboot_required + + + + + + + Disable Mounting of udf + +To configure the system to prevent the udf +kernel module from being loaded, add the following line to the file /etc/modprobe.d/udf.conf: +install udf /bin/false + +To configure the system to prevent the udf from being used, +add the following line to file /etc/modprobe.d/udf.conf: +blacklist udf + +This effectively prevents usage of this uncommon filesystem. + +The udf filesystem type is the universal disk format +used to implement the ISO/IEC 13346 and ECMA-167 specifications. +This is an open vendor filesystem type for data storage on a broad +range of media. This filesystem type is neccessary to support +writing DVDs and newer optical disc formats. + 11 + 14 + 3 + 9 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS05.02 + DSS05.05 + DSS06.06 + 3.4.6 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.2 + 4.3.4.3.3 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 7.6 + A.12.1.2 + A.12.5.1 + A.12.6.2 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.9.1.2 + CM-7(a) + CM-7(b) + CM-6(a) + PR.IP-1 + PR.PT-3 + A.8.SEC-OL4 + Removing support for unneeded filesystem types reduces the local +attack surface of the system. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +if LC_ALL=C grep -q -m 1 "^install udf" /etc/modprobe.d/udf.conf ; then + + sed -i 's#^install udf.*#install udf /bin/false#g' /etc/modprobe.d/udf.conf +else + echo -e "\n# Disable per security requirements" >> /etc/modprobe.d/udf.conf + echo "install udf /bin/false" >> /etc/modprobe.d/udf.conf +fi + +if ! LC_ALL=C grep -q -m 1 "^blacklist udf$" /etc/modprobe.d/udf.conf ; then + echo "blacklist udf" >> /etc/modprobe.d/udf.conf +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-171-3.4.6 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - kernel_module_udf_disabled + - low_complexity + - low_severity + - medium_disruption + - reboot_required + +- name: Ensure kernel module 'udf' is disabled + lineinfile: + create: true + dest: /etc/modprobe.d/udf.conf + regexp: install\s+udf + line: install udf /bin/false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-171-3.4.6 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - kernel_module_udf_disabled + - low_complexity + - low_severity + - medium_disruption + - reboot_required + +- name: Ensure kernel module 'udf' is blacklisted + lineinfile: + create: true + dest: /etc/modprobe.d/udf.conf + regexp: ^blacklist udf$ + line: blacklist udf + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-171-3.4.6 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - kernel_module_udf_disabled + - low_complexity + - low_severity + - medium_disruption + - reboot_required + + + + + + + Disable Modprobe Loading of USB Storage Driver + To prevent USB storage devices from being used, configure the kernel module loading system +to prevent automatic loading of the USB storage driver. + +To configure the system to prevent the usb-storage +kernel module from being loaded, add the following line to the file /etc/modprobe.d/usb-storage.conf: +install usb-storage /bin/false + +To configure the system to prevent the usb-storage from being used, +add the following line to file /etc/modprobe.d/usb-storage.conf: +blacklist usb-storage + +This will prevent the modprobe program from loading the usb-storage +module, but will not prevent an administrator (or another program) from using the +insmod program to load the module manually. + 1 + 12 + 15 + 16 + 5 + APO13.01 + DSS01.04 + DSS05.03 + DSS05.04 + DSS05.05 + DSS05.07 + DSS05.10 + DSS06.03 + DSS06.10 + 3.1.21 + CCI-000778 + CCI-001958 + CCI-003959 + 164.308(a)(3)(i) + 164.308(a)(3)(ii)(A) + 164.310(d)(1) + 164.310(d)(2) + 164.312(a)(1) + 164.312(a)(2)(iv) + 164.312(b) + 4.3.3.2.2 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.2 + 4.3.3.7.4 + SR 1.1 + SR 1.10 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.6 + A.11.2.6 + A.13.1.1 + A.13.2.1 + A.18.1.4 + A.6.2.1 + A.6.2.2 + A.7.1.1 + A.9.2.1 + A.9.2.2 + A.9.2.3 + A.9.2.4 + A.9.2.6 + A.9.3.1 + A.9.4.2 + A.9.4.3 + CM-7(a) + CM-7(b) + CM-6(a) + MP-7 + PR.AC-1 + PR.AC-3 + PR.AC-6 + PR.AC-7 + SRG-OS-000114-GPOS-00059 + SRG-OS-000378-GPOS-00163 + SRG-OS-000480-GPOS-00227 + SRG-APP-000141-CTR-000315 + A.15.SEC-OL1 + 3.4.2 + 3.4 + OL09-00-000047 + OL09-00-002332 + SV-271450r1092466_rule + SV-271702r1091818_rule + USB storage devices such as thumb drives can be used to introduce +malicious software. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +if LC_ALL=C grep -q -m 1 "^install usb-storage" /etc/modprobe.d/usb-storage.conf ; then + + sed -i 's#^install usb-storage.*#install usb-storage /bin/false#g' /etc/modprobe.d/usb-storage.conf +else + echo -e "\n# Disable per security requirements" >> /etc/modprobe.d/usb-storage.conf + echo "install usb-storage /bin/false" >> /etc/modprobe.d/usb-storage.conf +fi + +if ! LC_ALL=C grep -q -m 1 "^blacklist usb-storage$" /etc/modprobe.d/usb-storage.conf ; then + echo "blacklist usb-storage" >> /etc/modprobe.d/usb-storage.conf +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-000047 + - DISA-STIG-OL09-00-002332 + - NIST-800-171-3.1.21 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - PCI-DSSv4-3.4 + - PCI-DSSv4-3.4.2 + - disable_strategy + - kernel_module_usb-storage_disabled + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + +- name: Ensure kernel module 'usb-storage' is disabled + lineinfile: + create: true + dest: /etc/modprobe.d/usb-storage.conf + regexp: install\s+usb-storage + line: install usb-storage /bin/false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-000047 + - DISA-STIG-OL09-00-002332 + - NIST-800-171-3.1.21 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - PCI-DSSv4-3.4 + - PCI-DSSv4-3.4.2 + - disable_strategy + - kernel_module_usb-storage_disabled + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + +- name: Ensure kernel module 'usb-storage' is blacklisted + lineinfile: + create: true + dest: /etc/modprobe.d/usb-storage.conf + regexp: ^blacklist usb-storage$ + line: blacklist usb-storage + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-000047 + - DISA-STIG-OL09-00-002332 + - NIST-800-171-3.1.21 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - PCI-DSSv4-3.4 + - PCI-DSSv4-3.4.2 + - disable_strategy + - kernel_module_usb-storage_disabled + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + + + + + + + + + + + Restrict Partition Mount Options + System partitions can be mounted with certain options +that limit what files on those partitions can do. These options +are set in the /etc/fstab configuration file, and can be +used to make certain types of malicious behavior more difficult. + + + Removable Partition + This value is used by the checks mount_option_nodev_removable_partitions, mount_option_nodev_removable_partitions, +and mount_option_nodev_removable_partitions to ensure that the correct mount options are set on partitions mounted from +removable media such as CD-ROMs, USB keys, and floppy drives. This value should be modified to reflect any removable +partitions that are required on the local system. + /dev/cdrom + /dev/cdrom + + + Add nosuid Option to /boot/efi + The nosuid mount option can be used to prevent +execution of setuid programs in /boot/efi. The SUID and SGID permissions +should not be required on the boot partition. +Add the nosuid option to the fourth column of +/etc/fstab for the line which controls mounting of +/boot/efi. + CCI-000366 + CCI-001764 + CM-6(b) + CM-6.1(iv) + SRG-OS-000480-GPOS-00227 + OL09-00-002032 + SV-271649r1091659_rule + The presence of SUID and SGID executables should be tightly controlled. Users +should not be able to execute SUID or SGID binaries from boot partitions. + # Remediation is applicable only in certain platforms +if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ); then + +function perform_remediation { + + # the mount point /boot/efi has to be defined in /etc/fstab + # before this remediation can be executed. In case it is not defined, the + # remediation aborts and no changes regarding the mount point are done. + mount_point_match_regexp="$(printf "^[[:space:]]*[^#].*[[:space:]]%s[[:space:]]" "/boot/efi")" + + grep "$mount_point_match_regexp" -q /etc/fstab \ + || { echo "The mount point '/boot/efi' is not even in /etc/fstab, so we can't set up mount options" >&2; + echo "Not remediating, because there is no record of /boot/efi in /etc/fstab" >&2; return 1; } + + + + mount_point_match_regexp="$(printf "^[[:space:]]*[^#].*[[:space:]]%s[[:space:]]" /boot/efi)" + + # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab + if ! grep -q "$mount_point_match_regexp" /etc/fstab; then + # runtime opts without some automatic kernel/userspace-added defaults + previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 | awk '{print $4}' \ + | sed -E "s/(rw|defaults|seclabel|nosuid)(,|$)//g;s/,$//") + [ "$previous_mount_opts" ] && previous_mount_opts+="," + # In iso9660 filesystems mtab could describe a "blocksize" value, this should be reflected in + # fstab as "block". The next variable is to satisfy shellcheck SC2050. + fs_type="" + if [ "$fs_type" == "iso9660" ] ; then + previous_mount_opts=$(sed 's/blocksize=/block=/' <<< "$previous_mount_opts") + fi + echo " /boot/efi defaults,${previous_mount_opts}nosuid 0 0" >> /etc/fstab + # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it + elif ! grep "$mount_point_match_regexp" /etc/fstab | grep -q "nosuid"; then + previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}') + sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,nosuid|" /etc/fstab + fi + + + if mkdir -p "/boot/efi"; then + if mountpoint -q "/boot/efi"; then + mount -o remount --target "/boot/efi" + fi + fi +} + +perform_remediation + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002032 + - NIST-800-53-CM-6(b) + - NIST-800-53-CM-6.1(iv) + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_boot_efi_nosuid + - no_reboot_needed + +- name: 'Add nosuid Option to /boot/efi: Check information associated to mountpoint' + command: findmnt --fstab '/boot/efi' + register: device_name + failed_when: device_name.rc > 1 + changed_when: false + when: ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + tags: + - DISA-STIG-OL09-00-002032 + - NIST-800-53-CM-6(b) + - NIST-800-53-CM-6.1(iv) + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_boot_efi_nosuid + - no_reboot_needed + +- name: 'Add nosuid Option to /boot/efi: Create mount_info dictionary variable' + set_fact: + mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' + with_together: + - '{{ device_name.stdout_lines[0].split() | list | lower }}' + - '{{ device_name.stdout_lines[1].split() | list }}' + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - device_name.stdout is defined and device_name.stdout_lines is defined + - (device_name.stdout | length > 0) + tags: + - DISA-STIG-OL09-00-002032 + - NIST-800-53-CM-6(b) + - NIST-800-53-CM-6.1(iv) + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_boot_efi_nosuid + - no_reboot_needed + +- name: 'Add nosuid Option to /boot/efi: If /boot/efi not mounted, craft mount_info + manually' + set_fact: + mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' + with_together: + - - target + - source + - fstype + - options + - - /boot/efi + - '' + - '' + - defaults + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - ("--fstab" | length == 0) + - device_name.stdout is defined and device_name.stdout_lines is defined + - (device_name.stdout | length == 0) + tags: + - DISA-STIG-OL09-00-002032 + - NIST-800-53-CM-6(b) + - NIST-800-53-CM-6.1(iv) + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_boot_efi_nosuid + - no_reboot_needed + +- name: 'Add nosuid Option to /boot/efi: Make sure nosuid option is part of the to + /boot/efi options' + set_fact: + mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',nosuid'' + }) }}' + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - mount_info is defined and "nosuid" not in mount_info.options + tags: + - DISA-STIG-OL09-00-002032 + - NIST-800-53-CM-6(b) + - NIST-800-53-CM-6.1(iv) + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_boot_efi_nosuid + - no_reboot_needed + +- name: 'Add nosuid Option to /boot/efi: Ensure /boot/efi is mounted with nosuid option' + mount: + path: /boot/efi + src: '{{ mount_info.source }}' + opts: '{{ mount_info.options }}' + state: mounted + fstype: '{{ mount_info.fstype }}' + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - mount_info is defined + - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" + | length == 0) + tags: + - DISA-STIG-OL09-00-002032 + - NIST-800-53-CM-6(b) + - NIST-800-53-CM-6.1(iv) + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_boot_efi_nosuid + - no_reboot_needed + + + + + + + + + + Add nodev Option to /boot + The nodev mount option can be used to prevent device files from +being created in /boot. +Legitimate character and block devices should exist only in +the /dev directory on the root partition or within chroot +jails built for system services. +Add the nodev option to the fourth column of +/etc/fstab for the line which controls mounting of +/boot. + CCI-001764 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 + CM-7(a) + CM-7(b) + CM-6(a) + AC-6 + AC-6(1) + MP-7 + PR.IP-1 + PR.PT-2 + PR.PT-3 + SRG-OS-000368-GPOS-00154 + OL09-00-002030 + SV-271647r1091653_rule + The only legitimate location for device files is the /dev directory +located on the root partition. The only exception to this is chroot jails. + # Remediation is applicable only in certain platforms +if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ); then + +function perform_remediation { + + # the mount point /boot has to be defined in /etc/fstab + # before this remediation can be executed. In case it is not defined, the + # remediation aborts and no changes regarding the mount point are done. + mount_point_match_regexp="$(printf "^[[:space:]]*[^#].*[[:space:]]%s[[:space:]]" "/boot")" + + grep "$mount_point_match_regexp" -q /etc/fstab \ + || { echo "The mount point '/boot' is not even in /etc/fstab, so we can't set up mount options" >&2; + echo "Not remediating, because there is no record of /boot in /etc/fstab" >&2; return 1; } + + + + mount_point_match_regexp="$(printf "^[[:space:]]*[^#].*[[:space:]]%s[[:space:]]" /boot)" + + # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab + if ! grep -q "$mount_point_match_regexp" /etc/fstab; then + # runtime opts without some automatic kernel/userspace-added defaults + previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 | awk '{print $4}' \ + | sed -E "s/(rw|defaults|seclabel|nodev)(,|$)//g;s/,$//") + [ "$previous_mount_opts" ] && previous_mount_opts+="," + # In iso9660 filesystems mtab could describe a "blocksize" value, this should be reflected in + # fstab as "block". The next variable is to satisfy shellcheck SC2050. + fs_type="" + if [ "$fs_type" == "iso9660" ] ; then + previous_mount_opts=$(sed 's/blocksize=/block=/' <<< "$previous_mount_opts") + fi + echo " /boot defaults,${previous_mount_opts}nodev 0 0" >> /etc/fstab + # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it + elif ! grep "$mount_point_match_regexp" /etc/fstab | grep -q "nodev"; then + previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}') + sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,nodev|" /etc/fstab + fi + + + if mkdir -p "/boot"; then + if mountpoint -q "/boot"; then + mount -o remount --target "/boot" + fi + fi +} + +perform_remediation + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002030 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_boot_nodev + - no_reboot_needed + +- name: 'Add nodev Option to /boot: Check information associated to mountpoint' + command: findmnt --fstab '/boot' + register: device_name + failed_when: device_name.rc > 1 + changed_when: false + when: ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + tags: + - DISA-STIG-OL09-00-002030 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_boot_nodev + - no_reboot_needed + +- name: 'Add nodev Option to /boot: Create mount_info dictionary variable' + set_fact: + mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' + with_together: + - '{{ device_name.stdout_lines[0].split() | list | lower }}' + - '{{ device_name.stdout_lines[1].split() | list }}' + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - device_name.stdout is defined and device_name.stdout_lines is defined + - (device_name.stdout | length > 0) + tags: + - DISA-STIG-OL09-00-002030 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_boot_nodev + - no_reboot_needed + +- name: 'Add nodev Option to /boot: If /boot not mounted, craft mount_info manually' + set_fact: + mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' + with_together: + - - target + - source + - fstype + - options + - - /boot + - '' + - '' + - defaults + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - ("--fstab" | length == 0) + - device_name.stdout is defined and device_name.stdout_lines is defined + - (device_name.stdout | length == 0) + tags: + - DISA-STIG-OL09-00-002030 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_boot_nodev + - no_reboot_needed + +- name: 'Add nodev Option to /boot: Make sure nodev option is part of the to /boot + options' + set_fact: + mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',nodev'' + }) }}' + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - mount_info is defined and "nodev" not in mount_info.options + tags: + - DISA-STIG-OL09-00-002030 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_boot_nodev + - no_reboot_needed + +- name: 'Add nodev Option to /boot: Ensure /boot is mounted with nodev option' + mount: + path: /boot + src: '{{ mount_info.source }}' + opts: '{{ mount_info.options }}' + state: mounted + fstype: '{{ mount_info.fstype }}' + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - mount_info is defined + - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" + | length == 0) + tags: + - DISA-STIG-OL09-00-002030 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_boot_nodev + - no_reboot_needed + + +part /boot --mountoptions="nodev" + + + + + + + + + + Add noexec Option to /boot + The noexec mount option can be used to prevent binaries from being +executed out of /boot. +Add the noexec option to the fourth column of +/etc/fstab for the line which controls mounting of +/boot. + R28 + The /boot partition contains the kernel and the bootloader. No +binaries should be executed from this partition after the booting process +finishes. + # Remediation is applicable only in certain platforms +if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ); then + +function perform_remediation { + + # the mount point /boot has to be defined in /etc/fstab + # before this remediation can be executed. In case it is not defined, the + # remediation aborts and no changes regarding the mount point are done. + mount_point_match_regexp="$(printf "^[[:space:]]*[^#].*[[:space:]]%s[[:space:]]" "/boot")" + + grep "$mount_point_match_regexp" -q /etc/fstab \ + || { echo "The mount point '/boot' is not even in /etc/fstab, so we can't set up mount options" >&2; + echo "Not remediating, because there is no record of /boot in /etc/fstab" >&2; return 1; } + + + + mount_point_match_regexp="$(printf "^[[:space:]]*[^#].*[[:space:]]%s[[:space:]]" /boot)" + + # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab + if ! grep -q "$mount_point_match_regexp" /etc/fstab; then + # runtime opts without some automatic kernel/userspace-added defaults + previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 | awk '{print $4}' \ + | sed -E "s/(rw|defaults|seclabel|noexec)(,|$)//g;s/,$//") + [ "$previous_mount_opts" ] && previous_mount_opts+="," + # In iso9660 filesystems mtab could describe a "blocksize" value, this should be reflected in + # fstab as "block". The next variable is to satisfy shellcheck SC2050. + fs_type="" + if [ "$fs_type" == "iso9660" ] ; then + previous_mount_opts=$(sed 's/blocksize=/block=/' <<< "$previous_mount_opts") + fi + echo " /boot defaults,${previous_mount_opts}noexec 0 0" >> /etc/fstab + # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it + elif ! grep "$mount_point_match_regexp" /etc/fstab | grep -q "noexec"; then + previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}') + sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,noexec|" /etc/fstab + fi + + + if mkdir -p "/boot"; then + if mountpoint -q "/boot"; then + mount -o remount --target "/boot" + fi + fi +} + +perform_remediation + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_boot_noexec + - no_reboot_needed + +- name: 'Add noexec Option to /boot: Check information associated to mountpoint' + command: findmnt --fstab '/boot' + register: device_name + failed_when: device_name.rc > 1 + changed_when: false + when: ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + tags: + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_boot_noexec + - no_reboot_needed + +- name: 'Add noexec Option to /boot: Create mount_info dictionary variable' + set_fact: + mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' + with_together: + - '{{ device_name.stdout_lines[0].split() | list | lower }}' + - '{{ device_name.stdout_lines[1].split() | list }}' + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - device_name.stdout is defined and device_name.stdout_lines is defined + - (device_name.stdout | length > 0) + tags: + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_boot_noexec + - no_reboot_needed + +- name: 'Add noexec Option to /boot: If /boot not mounted, craft mount_info manually' + set_fact: + mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' + with_together: + - - target + - source + - fstype + - options + - - /boot + - '' + - '' + - defaults + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - ("--fstab" | length == 0) + - device_name.stdout is defined and device_name.stdout_lines is defined + - (device_name.stdout | length == 0) + tags: + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_boot_noexec + - no_reboot_needed + +- name: 'Add noexec Option to /boot: Make sure noexec option is part of the to /boot + options' + set_fact: + mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',noexec'' + }) }}' + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - mount_info is defined and "noexec" not in mount_info.options + tags: + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_boot_noexec + - no_reboot_needed + +- name: 'Add noexec Option to /boot: Ensure /boot is mounted with noexec option' + mount: + path: /boot + src: '{{ mount_info.source }}' + opts: '{{ mount_info.options }}' + state: mounted + fstype: '{{ mount_info.fstype }}' + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - mount_info is defined + - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" + | length == 0) + tags: + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_boot_noexec + - no_reboot_needed + + +part /boot --mountoptions="noexec" + + + + + + + + + + Add nosuid Option to /boot + The nosuid mount option can be used to prevent +execution of setuid programs in /boot. The SUID and SGID permissions +should not be required on the boot partition. +Add the nosuid option to the fourth column of +/etc/fstab for the line which controls mounting of +/boot. + CCI-000366 + CCI-001764 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 + CM-7(a) + CM-7(b) + CM-6(a) + AC-6 + AC-6(1) + MP-7 + PR.IP-1 + PR.PT-2 + PR.PT-3 + SRG-OS-000368-GPOS-00154 + SRG-OS-000480-GPOS-00227 + R28 + OL09-00-002031 + SV-271648r1091656_rule + The presence of SUID and SGID executables should be tightly controlled. Users +should not be able to execute SUID or SGID binaries from boot partitions. + # Remediation is applicable only in certain platforms +if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ); then + +function perform_remediation { + + # the mount point /boot has to be defined in /etc/fstab + # before this remediation can be executed. In case it is not defined, the + # remediation aborts and no changes regarding the mount point are done. + mount_point_match_regexp="$(printf "^[[:space:]]*[^#].*[[:space:]]%s[[:space:]]" "/boot")" + + grep "$mount_point_match_regexp" -q /etc/fstab \ + || { echo "The mount point '/boot' is not even in /etc/fstab, so we can't set up mount options" >&2; + echo "Not remediating, because there is no record of /boot in /etc/fstab" >&2; return 1; } + + + + mount_point_match_regexp="$(printf "^[[:space:]]*[^#].*[[:space:]]%s[[:space:]]" /boot)" + + # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab + if ! grep -q "$mount_point_match_regexp" /etc/fstab; then + # runtime opts without some automatic kernel/userspace-added defaults + previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 | awk '{print $4}' \ + | sed -E "s/(rw|defaults|seclabel|nosuid)(,|$)//g;s/,$//") + [ "$previous_mount_opts" ] && previous_mount_opts+="," + # In iso9660 filesystems mtab could describe a "blocksize" value, this should be reflected in + # fstab as "block". The next variable is to satisfy shellcheck SC2050. + fs_type="" + if [ "$fs_type" == "iso9660" ] ; then + previous_mount_opts=$(sed 's/blocksize=/block=/' <<< "$previous_mount_opts") + fi + echo " /boot defaults,${previous_mount_opts}nosuid 0 0" >> /etc/fstab + # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it + elif ! grep "$mount_point_match_regexp" /etc/fstab | grep -q "nosuid"; then + previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}') + sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,nosuid|" /etc/fstab + fi + + + if mkdir -p "/boot"; then + if mountpoint -q "/boot"; then + mount -o remount --target "/boot" + fi + fi +} + +perform_remediation + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002031 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_boot_nosuid + - no_reboot_needed + +- name: 'Add nosuid Option to /boot: Check information associated to mountpoint' + command: findmnt --fstab '/boot' + register: device_name + failed_when: device_name.rc > 1 + changed_when: false + when: ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + tags: + - DISA-STIG-OL09-00-002031 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_boot_nosuid + - no_reboot_needed + +- name: 'Add nosuid Option to /boot: Create mount_info dictionary variable' + set_fact: + mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' + with_together: + - '{{ device_name.stdout_lines[0].split() | list | lower }}' + - '{{ device_name.stdout_lines[1].split() | list }}' + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - device_name.stdout is defined and device_name.stdout_lines is defined + - (device_name.stdout | length > 0) + tags: + - DISA-STIG-OL09-00-002031 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_boot_nosuid + - no_reboot_needed + +- name: 'Add nosuid Option to /boot: If /boot not mounted, craft mount_info manually' + set_fact: + mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' + with_together: + - - target + - source + - fstype + - options + - - /boot + - '' + - '' + - defaults + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - ("--fstab" | length == 0) + - device_name.stdout is defined and device_name.stdout_lines is defined + - (device_name.stdout | length == 0) + tags: + - DISA-STIG-OL09-00-002031 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_boot_nosuid + - no_reboot_needed + +- name: 'Add nosuid Option to /boot: Make sure nosuid option is part of the to /boot + options' + set_fact: + mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',nosuid'' + }) }}' + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - mount_info is defined and "nosuid" not in mount_info.options + tags: + - DISA-STIG-OL09-00-002031 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_boot_nosuid + - no_reboot_needed + +- name: 'Add nosuid Option to /boot: Ensure /boot is mounted with nosuid option' + mount: + path: /boot + src: '{{ mount_info.source }}' + opts: '{{ mount_info.options }}' + state: mounted + fstype: '{{ mount_info.fstype }}' + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - mount_info is defined + - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" + | length == 0) + tags: + - DISA-STIG-OL09-00-002031 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_boot_nosuid + - no_reboot_needed + + +part /boot --mountoptions="nosuid" + + + + + + + + + + Add nodev Option to /dev/shm + The nodev mount option can be used to prevent creation of device +files in /dev/shm. Legitimate character and block devices should +not exist within temporary directories like /dev/shm. +Add the nodev option to the fourth column of +/etc/fstab for the line which controls mounting of +/dev/shm. + 11 + 13 + 14 + 3 + 8 + 9 + APO13.01 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS05.02 + DSS05.05 + DSS05.06 + DSS06.06 + CCI-001764 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.2 + 4.3.4.3.3 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 7.6 + A.11.2.9 + A.12.1.2 + A.12.5.1 + A.12.6.2 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.8.2.1 + A.8.2.2 + A.8.2.3 + A.8.3.1 + A.8.3.3 + A.9.1.2 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 + CM-7(a) + CM-7(b) + CM-6(a) + AC-6 + AC-6(1) + MP-7 + PR.IP-1 + PR.PT-2 + PR.PT-3 + SRG-OS-000368-GPOS-00154 + OL09-00-002040 + SV-271650r1091662_rule + The only legitimate location for device files is the /dev directory +located on the root partition. The only exception to this is chroot jails. + # Remediation is applicable only in certain platforms +if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ); then + +function perform_remediation { + + + + mount_point_match_regexp="$(printf "^[[:space:]]*[^#].*[[:space:]]%s[[:space:]]" /dev/shm)" + + # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab + if ! grep -q "$mount_point_match_regexp" /etc/fstab; then + # runtime opts without some automatic kernel/userspace-added defaults + previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 | awk '{print $4}' \ + | sed -E "s/(rw|defaults|seclabel|nodev)(,|$)//g;s/,$//") + [ "$previous_mount_opts" ] && previous_mount_opts+="," + # In iso9660 filesystems mtab could describe a "blocksize" value, this should be reflected in + # fstab as "block". The next variable is to satisfy shellcheck SC2050. + fs_type="tmpfs" + if [ "$fs_type" == "iso9660" ] ; then + previous_mount_opts=$(sed 's/blocksize=/block=/' <<< "$previous_mount_opts") + fi + echo "tmpfs /dev/shm tmpfs defaults,${previous_mount_opts}nodev 0 0" >> /etc/fstab + # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it + elif ! grep "$mount_point_match_regexp" /etc/fstab | grep -q "nodev"; then + previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}') + sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,nodev|" /etc/fstab + fi + + + if mkdir -p "/dev/shm"; then + if mountpoint -q "/dev/shm"; then + mount -o remount --target "/dev/shm" + fi + fi +} + +perform_remediation + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002040 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_dev_shm_nodev + - no_reboot_needed + +- name: 'Add nodev Option to /dev/shm: Check information associated to mountpoint' + command: findmnt '/dev/shm' + register: device_name + failed_when: device_name.rc > 1 + changed_when: false + when: ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + tags: + - DISA-STIG-OL09-00-002040 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_dev_shm_nodev + - no_reboot_needed + +- name: 'Add nodev Option to /dev/shm: Create mount_info dictionary variable' + set_fact: + mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' + with_together: + - '{{ device_name.stdout_lines[0].split() | list | lower }}' + - '{{ device_name.stdout_lines[1].split() | list }}' + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - device_name.stdout is defined and device_name.stdout_lines is defined + - (device_name.stdout | length > 0) + tags: + - DISA-STIG-OL09-00-002040 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_dev_shm_nodev + - no_reboot_needed + +- name: 'Add nodev Option to /dev/shm: If /dev/shm not mounted, craft mount_info manually' + set_fact: + mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' + with_together: + - - target + - source + - fstype + - options + - - /dev/shm + - tmpfs + - tmpfs + - defaults + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - ("" | length == 0) + - device_name.stdout is defined and device_name.stdout_lines is defined + - (device_name.stdout | length == 0) + tags: + - DISA-STIG-OL09-00-002040 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_dev_shm_nodev + - no_reboot_needed + +- name: 'Add nodev Option to /dev/shm: Make sure nodev option is part of the to /dev/shm + options' + set_fact: + mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',nodev'' + }) }}' + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - mount_info is defined and "nodev" not in mount_info.options + tags: + - DISA-STIG-OL09-00-002040 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_dev_shm_nodev + - no_reboot_needed + +- name: 'Add nodev Option to /dev/shm: Ensure /dev/shm is mounted with nodev option' + mount: + path: /dev/shm + src: '{{ mount_info.source }}' + opts: '{{ mount_info.options }}' + state: mounted + fstype: '{{ mount_info.fstype }}' + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - mount_info is defined + - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("" | + length == 0) + tags: + - DISA-STIG-OL09-00-002040 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_dev_shm_nodev + - no_reboot_needed + + + + + + + + + + Add noexec Option to /dev/shm + The noexec mount option can be used to prevent binaries +from being executed out of /dev/shm. +It can be dangerous to allow the execution of binaries +from world-writable temporary storage directories such as /dev/shm. +Add the noexec option to the fourth column of +/etc/fstab for the line which controls mounting of +/dev/shm. + 11 + 13 + 14 + 3 + 8 + 9 + APO13.01 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS05.02 + DSS05.05 + DSS05.06 + DSS06.06 + CCI-001764 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.2 + 4.3.4.3.3 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 7.6 + A.11.2.9 + A.12.1.2 + A.12.5.1 + A.12.6.2 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.8.2.1 + A.8.2.2 + A.8.2.3 + A.8.3.1 + A.8.3.3 + A.9.1.2 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 + CM-7(a) + CM-7(b) + CM-6(a) + AC-6 + AC-6(1) + MP-7 + PR.IP-1 + PR.PT-2 + PR.PT-3 + SRG-OS-000368-GPOS-00154 + OL09-00-002041 + SV-271651r1091665_rule + Allowing users to execute binaries from world-writable directories +such as /dev/shm can expose the system to potential compromise. + # Remediation is applicable only in certain platforms +if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ); then + +function perform_remediation { + + + + mount_point_match_regexp="$(printf "^[[:space:]]*[^#].*[[:space:]]%s[[:space:]]" /dev/shm)" + + # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab + if ! grep -q "$mount_point_match_regexp" /etc/fstab; then + # runtime opts without some automatic kernel/userspace-added defaults + previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 | awk '{print $4}' \ + | sed -E "s/(rw|defaults|seclabel|noexec)(,|$)//g;s/,$//") + [ "$previous_mount_opts" ] && previous_mount_opts+="," + # In iso9660 filesystems mtab could describe a "blocksize" value, this should be reflected in + # fstab as "block". The next variable is to satisfy shellcheck SC2050. + fs_type="tmpfs" + if [ "$fs_type" == "iso9660" ] ; then + previous_mount_opts=$(sed 's/blocksize=/block=/' <<< "$previous_mount_opts") + fi + echo "tmpfs /dev/shm tmpfs defaults,${previous_mount_opts}noexec 0 0" >> /etc/fstab + # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it + elif ! grep "$mount_point_match_regexp" /etc/fstab | grep -q "noexec"; then + previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}') + sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,noexec|" /etc/fstab + fi + + + if mkdir -p "/dev/shm"; then + if mountpoint -q "/dev/shm"; then + mount -o remount --target "/dev/shm" + fi + fi +} + +perform_remediation + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002041 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_dev_shm_noexec + - no_reboot_needed + +- name: 'Add noexec Option to /dev/shm: Check information associated to mountpoint' + command: findmnt '/dev/shm' + register: device_name + failed_when: device_name.rc > 1 + changed_when: false + when: ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + tags: + - DISA-STIG-OL09-00-002041 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_dev_shm_noexec + - no_reboot_needed + +- name: 'Add noexec Option to /dev/shm: Create mount_info dictionary variable' + set_fact: + mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' + with_together: + - '{{ device_name.stdout_lines[0].split() | list | lower }}' + - '{{ device_name.stdout_lines[1].split() | list }}' + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - device_name.stdout is defined and device_name.stdout_lines is defined + - (device_name.stdout | length > 0) + tags: + - DISA-STIG-OL09-00-002041 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_dev_shm_noexec + - no_reboot_needed + +- name: 'Add noexec Option to /dev/shm: If /dev/shm not mounted, craft mount_info + manually' + set_fact: + mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' + with_together: + - - target + - source + - fstype + - options + - - /dev/shm + - tmpfs + - tmpfs + - defaults + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - ("" | length == 0) + - device_name.stdout is defined and device_name.stdout_lines is defined + - (device_name.stdout | length == 0) + tags: + - DISA-STIG-OL09-00-002041 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_dev_shm_noexec + - no_reboot_needed + +- name: 'Add noexec Option to /dev/shm: Make sure noexec option is part of the to + /dev/shm options' + set_fact: + mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',noexec'' + }) }}' + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - mount_info is defined and "noexec" not in mount_info.options + tags: + - DISA-STIG-OL09-00-002041 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_dev_shm_noexec + - no_reboot_needed + +- name: 'Add noexec Option to /dev/shm: Ensure /dev/shm is mounted with noexec option' + mount: + path: /dev/shm + src: '{{ mount_info.source }}' + opts: '{{ mount_info.options }}' + state: mounted + fstype: '{{ mount_info.fstype }}' + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - mount_info is defined + - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("" | + length == 0) + tags: + - DISA-STIG-OL09-00-002041 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_dev_shm_noexec + - no_reboot_needed + + + + + + + + + + Add nosuid Option to /dev/shm + The nosuid mount option can be used to prevent execution +of setuid programs in /dev/shm. The SUID and SGID permissions should not +be required in these world-writable directories. +Add the nosuid option to the fourth column of +/etc/fstab for the line which controls mounting of +/dev/shm. + 11 + 13 + 14 + 3 + 8 + 9 + APO13.01 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS05.02 + DSS05.05 + DSS05.06 + DSS06.06 + CCI-001764 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.2 + 4.3.4.3.3 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 7.6 + A.11.2.9 + A.12.1.2 + A.12.5.1 + A.12.6.2 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.8.2.1 + A.8.2.2 + A.8.2.3 + A.8.3.1 + A.8.3.3 + A.9.1.2 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 + CM-7(a) + CM-7(b) + CM-6(a) + AC-6 + AC-6(1) + MP-7 + PR.IP-1 + PR.PT-2 + PR.PT-3 + SRG-OS-000368-GPOS-00154 + OL09-00-002042 + SV-271652r1094966_rule + The presence of SUID and SGID executables should be tightly controlled. Users +should not be able to execute SUID or SGID binaries from temporary storage partitions. + # Remediation is applicable only in certain platforms +if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ); then + +function perform_remediation { + + + + mount_point_match_regexp="$(printf "^[[:space:]]*[^#].*[[:space:]]%s[[:space:]]" /dev/shm)" + + # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab + if ! grep -q "$mount_point_match_regexp" /etc/fstab; then + # runtime opts without some automatic kernel/userspace-added defaults + previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 | awk '{print $4}' \ + | sed -E "s/(rw|defaults|seclabel|nosuid)(,|$)//g;s/,$//") + [ "$previous_mount_opts" ] && previous_mount_opts+="," + # In iso9660 filesystems mtab could describe a "blocksize" value, this should be reflected in + # fstab as "block". The next variable is to satisfy shellcheck SC2050. + fs_type="tmpfs" + if [ "$fs_type" == "iso9660" ] ; then + previous_mount_opts=$(sed 's/blocksize=/block=/' <<< "$previous_mount_opts") + fi + echo "tmpfs /dev/shm tmpfs defaults,${previous_mount_opts}nosuid 0 0" >> /etc/fstab + # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it + elif ! grep "$mount_point_match_regexp" /etc/fstab | grep -q "nosuid"; then + previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}') + sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,nosuid|" /etc/fstab + fi + + + if mkdir -p "/dev/shm"; then + if mountpoint -q "/dev/shm"; then + mount -o remount --target "/dev/shm" + fi + fi +} + +perform_remediation + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002042 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_dev_shm_nosuid + - no_reboot_needed + +- name: 'Add nosuid Option to /dev/shm: Check information associated to mountpoint' + command: findmnt '/dev/shm' + register: device_name + failed_when: device_name.rc > 1 + changed_when: false + when: ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + tags: + - DISA-STIG-OL09-00-002042 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_dev_shm_nosuid + - no_reboot_needed + +- name: 'Add nosuid Option to /dev/shm: Create mount_info dictionary variable' + set_fact: + mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' + with_together: + - '{{ device_name.stdout_lines[0].split() | list | lower }}' + - '{{ device_name.stdout_lines[1].split() | list }}' + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - device_name.stdout is defined and device_name.stdout_lines is defined + - (device_name.stdout | length > 0) + tags: + - DISA-STIG-OL09-00-002042 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_dev_shm_nosuid + - no_reboot_needed + +- name: 'Add nosuid Option to /dev/shm: If /dev/shm not mounted, craft mount_info + manually' + set_fact: + mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' + with_together: + - - target + - source + - fstype + - options + - - /dev/shm + - tmpfs + - tmpfs + - defaults + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - ("" | length == 0) + - device_name.stdout is defined and device_name.stdout_lines is defined + - (device_name.stdout | length == 0) + tags: + - DISA-STIG-OL09-00-002042 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_dev_shm_nosuid + - no_reboot_needed + +- name: 'Add nosuid Option to /dev/shm: Make sure nosuid option is part of the to + /dev/shm options' + set_fact: + mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',nosuid'' + }) }}' + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - mount_info is defined and "nosuid" not in mount_info.options + tags: + - DISA-STIG-OL09-00-002042 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_dev_shm_nosuid + - no_reboot_needed + +- name: 'Add nosuid Option to /dev/shm: Ensure /dev/shm is mounted with nosuid option' + mount: + path: /dev/shm + src: '{{ mount_info.source }}' + opts: '{{ mount_info.options }}' + state: mounted + fstype: '{{ mount_info.fstype }}' + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - mount_info is defined + - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("" | + length == 0) + tags: + - DISA-STIG-OL09-00-002042 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_dev_shm_nosuid + - no_reboot_needed + + + + + + + + + + Add grpquota Option to /home + The grpquota mount option allows for the filesystem to have disk quotas configured. +Add the grpquota option to the fourth column of +/etc/fstab for the line which controls mounting of +/home. + The quota options for XFS file systems can only be activated when mounting the partition. +It is not possible to enable them by remounting an already mounted partition. Therefore, +if the desired options were not defined before mounting the partition, dismount and mount +it again to apply the quota options. + OVAL looks for partitions whose mount point is a substring of any interactive user's home +directory and validates that grpquota option is there. Because of this, there could be +false negatives when several partitions share a base substring. For example, if there is a +home directory in /var/tmp/user1 and there are partitions mounted in +/var and /var/tmp. The grpquota option is only expected in +/var/tmp, but OVAL will check both. +Bash remediation uses the df command to find out the partition where the home +directory is mounted. However, if the directory doesn't exist the remediation won't be +applied. + CM-6(b) + To ensure the availability of disk space on /home, it is important to limit the impact a +single user or group can cause for other users (or the wider system) by intentionally or +accidentally filling up the partition. Quotas can also be applied to inodes for filesystems +where inode exhaustion is a concern. + # Remediation is applicable only in certain platforms +if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ); then + +function perform_remediation (){ + + mount_point_match_regexp="$(printf "^[[:space:]]*[^#].*[[:space:]]%s[[:space:]]" $1)" + + # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab + if ! grep -q "$mount_point_match_regexp" /etc/fstab; then + # runtime opts without some automatic kernel/userspace-added defaults + previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 | awk '{print $4}' \ + | sed -E "s/(rw|defaults|seclabel|grpquota)(,|$)//g;s/,$//") + [ "$previous_mount_opts" ] && previous_mount_opts+="," + # In iso9660 filesystems mtab could describe a "blocksize" value, this should be reflected in + # fstab as "block". The next variable is to satisfy shellcheck SC2050. + fs_type="" + if [ "$fs_type" == "iso9660" ] ; then + previous_mount_opts=$(sed 's/blocksize=/block=/' <<< "$previous_mount_opts") + fi + echo " $1 defaults,${previous_mount_opts}grpquota 0 0" >> /etc/fstab + # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it + elif ! grep "$mount_point_match_regexp" /etc/fstab | grep -q "grpquota"; then + previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}') + sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,grpquota|" /etc/fstab + fi + + if mkdir -p "$1"; then + if mountpoint -q "$1"; then + mount -o remount --target "$1" + fi + fi +} + +readarray -t home_directories < \ + <(awk -F':' '{if ($3>=1000 && $3!= 65534) print $6}' /etc/passwd ) + + +for home_directory in "${home_directories[@]}" +do + if [ -d $home_directory ]; then + fstab_mount_point=$(df $home_directory | awk '/^\/dev/ {print $6}') + if ! grep -qP "^/$|^/lib$|^/opt$|^/usr$|^/bin$|^/sbin$|^/boot$|^/dev$|^/proc$" <<< $fstab_mount_point + then + perform_remediation "$fstab_mount_point" + fi + fi +done + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-53-CM-6(b) + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_home_grpquota + - no_reboot_needed + +- name: Add grpquota Option to /home - Initialize variables + ansible.builtin.set_fact: + non_allowed_partitions: + - / + - /lib + - /opt + - /usr + - /bin + - /sbin + - /boot + - /dev + - /proc + home_directories: [] + allowed_mount_point: [] + fstab_mount_point_info: [] + when: ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + tags: + - NIST-800-53-CM-6(b) + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_home_grpquota + - no_reboot_needed + +- name: Add grpquota Option to /home - Get home directories from passwd + ansible.builtin.getent: + database: passwd + when: ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + tags: + - NIST-800-53-CM-6(b) + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_home_grpquota + - no_reboot_needed + +- name: Add grpquota Option to /home - Filter home directories based on UID range + ansible.builtin.set_fact: + home_directories: '{{ home_directories + [item.data[4]] }}' + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - item.data[4] is defined + - item.data[2]|int >= 1000 + - item.data[2]|int != 65534 + - item.data[4] not in non_allowed_partitions + with_items: '{{ ansible_facts.getent_passwd | dict2items(key_name=''user'', value_name=''data'')}}' + tags: + - NIST-800-53-CM-6(b) + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_home_grpquota + - no_reboot_needed + +- name: Add grpquota Option to /home - Gather mount points + ansible.builtin.setup: + filter: ansible_mounts + when: ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + tags: + - NIST-800-53-CM-6(b) + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_home_grpquota + - no_reboot_needed + +- name: Add grpquota Option to /home - Ensure mount options for home directories + block: + + - name: ' Add grpquota Option to /home - Obtain mount point using df and shell' + ansible.builtin.shell: | + df {{ item }} | awk '/^\/dev/ {print $6}' + register: df_output + with_items: '{{ home_directories }}' + + - name: Add grpquota Option to /home - Set mount point for each home directory + ansible.builtin.set_fact: + allowed_mount_point: '{{ allowed_mount_point + [item.stdout_lines[0]] }}' + with_items: '{{ df_output.results }}' + when: + - item.stdout_lines is defined + - item.stdout_lines | length > 0 + - item.stdout_lines[0] != "" + + - name: Add grpquota Option to /home - Obtain full mount information for allowed + mount point + ansible.builtin.set_fact: + fstab_mount_point_info: '{{ fstab_mount_point_info + [ ansible_mounts | selectattr(''mount'', + ''equalto'', item) | first ]}}' + with_items: '{{ allowed_mount_point }}' + when: allowed_mount_point is defined + + - name: Add grpquota Option to /home - Ensure mount option grpquota is in fstab + for allowed mount point + ansible.builtin.mount: + path: '{{ item.mount }}' + src: '{{ item.device }}' + opts: '{{ item.options }},grpquota' + state: mounted + fstype: '{{ item.fstype }}' + with_items: '{{ fstab_mount_point_info }}' + when: + - allowed_mount_point is defined + - item.mount not in non_allowed_partitions + - '''grpquota'' not in item.options' + when: ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + tags: + - NIST-800-53-CM-6(b) + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_home_grpquota + - no_reboot_needed + + + + + + + + + + Add nodev Option to /home + The nodev mount option can be used to prevent device files from +being created in /home. +Legitimate character and block devices should exist only in +the /dev directory on the root partition or within chroot +jails built for system services. +Add the nodev option to the fourth column of +/etc/fstab for the line which controls mounting of +/home. + CCI-001764 + SRG-OS-000368-GPOS-00154 + OL09-00-002070 + SV-271666r1091710_rule + The only legitimate location for device files is the /dev directory +located on the root partition. The only exception to this is chroot jails. + + # Remediation is applicable only in certain platforms +if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/home" > /dev/null || findmnt --fstab "/home" > /dev/null; }; then + +function perform_remediation { + + # the mount point /home has to be defined in /etc/fstab + # before this remediation can be executed. In case it is not defined, the + # remediation aborts and no changes regarding the mount point are done. + mount_point_match_regexp="$(printf "^[[:space:]]*[^#].*[[:space:]]%s[[:space:]]" "/home")" + + grep "$mount_point_match_regexp" -q /etc/fstab \ + || { echo "The mount point '/home' is not even in /etc/fstab, so we can't set up mount options" >&2; + echo "Not remediating, because there is no record of /home in /etc/fstab" >&2; return 1; } + + + + mount_point_match_regexp="$(printf "^[[:space:]]*[^#].*[[:space:]]%s[[:space:]]" /home)" + + # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab + if ! grep -q "$mount_point_match_regexp" /etc/fstab; then + # runtime opts without some automatic kernel/userspace-added defaults + previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 | awk '{print $4}' \ + | sed -E "s/(rw|defaults|seclabel|nodev)(,|$)//g;s/,$//") + [ "$previous_mount_opts" ] && previous_mount_opts+="," + # In iso9660 filesystems mtab could describe a "blocksize" value, this should be reflected in + # fstab as "block". The next variable is to satisfy shellcheck SC2050. + fs_type="" + if [ "$fs_type" == "iso9660" ] ; then + previous_mount_opts=$(sed 's/blocksize=/block=/' <<< "$previous_mount_opts") + fi + echo " /home defaults,${previous_mount_opts}nodev 0 0" >> /etc/fstab + # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it + elif ! grep "$mount_point_match_regexp" /etc/fstab | grep -q "nodev"; then + previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}') + sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,nodev|" /etc/fstab + fi + + + if mkdir -p "/home"; then + if mountpoint -q "/home"; then + mount -o remount --target "/home" + fi + fi +} + +perform_remediation + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002070 + - configure_strategy + - high_disruption + - low_complexity + - mount_option_home_nodev + - no_reboot_needed + - unknown_severity + +- name: 'Add nodev Option to /home: Check information associated to mountpoint' + command: findmnt --fstab '/home' + register: device_name + failed_when: device_name.rc > 1 + changed_when: false + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/home" in ansible_mounts | map(attribute="mount") | list' + tags: + - DISA-STIG-OL09-00-002070 + - configure_strategy + - high_disruption + - low_complexity + - mount_option_home_nodev + - no_reboot_needed + - unknown_severity + +- name: 'Add nodev Option to /home: Create mount_info dictionary variable' + set_fact: + mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' + with_together: + - '{{ device_name.stdout_lines[0].split() | list | lower }}' + - '{{ device_name.stdout_lines[1].split() | list }}' + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/home" in ansible_mounts | map(attribute="mount") | list' + - device_name.stdout is defined and device_name.stdout_lines is defined + - (device_name.stdout | length > 0) + tags: + - DISA-STIG-OL09-00-002070 + - configure_strategy + - high_disruption + - low_complexity + - mount_option_home_nodev + - no_reboot_needed + - unknown_severity + +- name: 'Add nodev Option to /home: If /home not mounted, craft mount_info manually' + set_fact: + mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' + with_together: + - - target + - source + - fstype + - options + - - /home + - '' + - '' + - defaults + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/home" in ansible_mounts | map(attribute="mount") | list' + - ("--fstab" | length == 0) + - device_name.stdout is defined and device_name.stdout_lines is defined + - (device_name.stdout | length == 0) + tags: + - DISA-STIG-OL09-00-002070 + - configure_strategy + - high_disruption + - low_complexity + - mount_option_home_nodev + - no_reboot_needed + - unknown_severity + +- name: 'Add nodev Option to /home: Make sure nodev option is part of the to /home + options' + set_fact: + mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',nodev'' + }) }}' + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/home" in ansible_mounts | map(attribute="mount") | list' + - mount_info is defined and "nodev" not in mount_info.options + tags: + - DISA-STIG-OL09-00-002070 + - configure_strategy + - high_disruption + - low_complexity + - mount_option_home_nodev + - no_reboot_needed + - unknown_severity + +- name: 'Add nodev Option to /home: Ensure /home is mounted with nodev option' + mount: + path: /home + src: '{{ mount_info.source }}' + opts: '{{ mount_info.options }}' + state: mounted + fstype: '{{ mount_info.fstype }}' + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/home" in ansible_mounts | map(attribute="mount") | list' + - mount_info is defined + - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" + | length == 0) + tags: + - DISA-STIG-OL09-00-002070 + - configure_strategy + - high_disruption + - low_complexity + - mount_option_home_nodev + - no_reboot_needed + - unknown_severity + + +part /home --mountoptions="nodev" + + + + + + + + + + Add noexec Option to /home + The noexec mount option can be used to prevent binaries from being +executed out of /home. +Add the noexec option to the fourth column of +/etc/fstab for the line which controls mounting of +/home. + OVAL looks for partitions whose mount point is a substring of any interactive user's home +directory and validates that noexec option is there. Because of this, there could be false +negatives when several partitions share a base substring. For example, if there is a home +directory in /var/tmp/user1 and there are partitions mounted in /var and +/var/tmp. The noexec option is only expected in /var/tmp, but OVAL will +check both. +Bash remediation uses the df command to find out the partition where the home +directory is mounted. However, if the directory doesn't exist the remediation won't be +applied. + CCI-000366 + CM-6(b) + SRG-OS-000480-GPOS-00227 + R28 + OL09-00-002072 + SV-271668r1091716_rule + The /home directory contains data of individual users. Binaries in +this directory should not be considered as trusted and users should not be +able to execute them. + # Remediation is applicable only in certain platforms +if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ); then + +function perform_remediation (){ + + mount_point_match_regexp="$(printf "^[[:space:]]*[^#].*[[:space:]]%s[[:space:]]" $1)" + + # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab + if ! grep -q "$mount_point_match_regexp" /etc/fstab; then + # runtime opts without some automatic kernel/userspace-added defaults + previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 | awk '{print $4}' \ + | sed -E "s/(rw|defaults|seclabel|noexec)(,|$)//g;s/,$//") + [ "$previous_mount_opts" ] && previous_mount_opts+="," + # In iso9660 filesystems mtab could describe a "blocksize" value, this should be reflected in + # fstab as "block". The next variable is to satisfy shellcheck SC2050. + fs_type="" + if [ "$fs_type" == "iso9660" ] ; then + previous_mount_opts=$(sed 's/blocksize=/block=/' <<< "$previous_mount_opts") + fi + echo " $1 defaults,${previous_mount_opts}noexec 0 0" >> /etc/fstab + # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it + elif ! grep "$mount_point_match_regexp" /etc/fstab | grep -q "noexec"; then + previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}') + sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,noexec|" /etc/fstab + fi + + if mkdir -p "$1"; then + if mountpoint -q "$1"; then + mount -o remount --target "$1" + fi + fi +} + +readarray -t home_directories < \ + <(awk -F':' '{if ($3>=1000 && $3!= 65534) print $6}' /etc/passwd ) + + +for home_directory in "${home_directories[@]}" +do + if [ -d $home_directory ]; then + fstab_mount_point=$(df $home_directory | awk '/^\/dev/ {print $6}') + if ! grep -qP "^/$|^/lib$|^/opt$|^/usr$|^/bin$|^/sbin$|^/boot$|^/dev$|^/proc$" <<< $fstab_mount_point + then + perform_remediation "$fstab_mount_point" + fi + fi +done + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002072 + - NIST-800-53-CM-6(b) + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_home_noexec + - no_reboot_needed + +- name: Add noexec Option to /home - Initialize variables + ansible.builtin.set_fact: + non_allowed_partitions: + - / + - /lib + - /opt + - /usr + - /bin + - /sbin + - /boot + - /dev + - /proc + home_directories: [] + allowed_mount_point: [] + fstab_mount_point_info: [] + when: ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + tags: + - DISA-STIG-OL09-00-002072 + - NIST-800-53-CM-6(b) + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_home_noexec + - no_reboot_needed + +- name: Add noexec Option to /home - Get home directories from passwd + ansible.builtin.getent: + database: passwd + when: ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + tags: + - DISA-STIG-OL09-00-002072 + - NIST-800-53-CM-6(b) + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_home_noexec + - no_reboot_needed + +- name: Add noexec Option to /home - Filter home directories based on UID range + ansible.builtin.set_fact: + home_directories: '{{ home_directories + [item.data[4]] }}' + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - item.data[4] is defined + - item.data[2]|int >= 1000 + - item.data[2]|int != 65534 + - item.data[4] not in non_allowed_partitions + with_items: '{{ ansible_facts.getent_passwd | dict2items(key_name=''user'', value_name=''data'')}}' + tags: + - DISA-STIG-OL09-00-002072 + - NIST-800-53-CM-6(b) + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_home_noexec + - no_reboot_needed + +- name: Add noexec Option to /home - Gather mount points + ansible.builtin.setup: + filter: ansible_mounts + when: ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + tags: + - DISA-STIG-OL09-00-002072 + - NIST-800-53-CM-6(b) + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_home_noexec + - no_reboot_needed + +- name: Add noexec Option to /home - Ensure mount options for home directories + block: + + - name: ' Add noexec Option to /home - Obtain mount point using df and shell' + ansible.builtin.shell: | + df {{ item }} | awk '/^\/dev/ {print $6}' + register: df_output + with_items: '{{ home_directories }}' + + - name: Add noexec Option to /home - Set mount point for each home directory + ansible.builtin.set_fact: + allowed_mount_point: '{{ allowed_mount_point + [item.stdout_lines[0]] }}' + with_items: '{{ df_output.results }}' + when: + - item.stdout_lines is defined + - item.stdout_lines | length > 0 + - item.stdout_lines[0] != "" + + - name: Add noexec Option to /home - Obtain full mount information for allowed mount + point + ansible.builtin.set_fact: + fstab_mount_point_info: '{{ fstab_mount_point_info + [ ansible_mounts | selectattr(''mount'', + ''equalto'', item) | first ]}}' + with_items: '{{ allowed_mount_point }}' + when: allowed_mount_point is defined + + - name: Add noexec Option to /home - Ensure mount option noexec is in fstab for + allowed mount point + ansible.builtin.mount: + path: '{{ item.mount }}' + src: '{{ item.device }}' + opts: '{{ item.options }},noexec' + state: mounted + fstype: '{{ item.fstype }}' + with_items: '{{ fstab_mount_point_info }}' + when: + - allowed_mount_point is defined + - item.mount not in non_allowed_partitions + - '''noexec'' not in item.options' + when: ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + tags: + - DISA-STIG-OL09-00-002072 + - NIST-800-53-CM-6(b) + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_home_noexec + - no_reboot_needed + + + + + + + + + + Add nosuid Option to /home + The nosuid mount option can be used to prevent +execution of setuid programs in /home. The SUID and SGID permissions +should not be required in these user data directories. +Add the nosuid option to the fourth column of +/etc/fstab for the line which controls mounting of +/home. + OVAL looks for partitions whose mount point is a substring of any interactive user's home +directory and validates that noexec option is there. Because of this, there could be false +negatives when several partitions share a base substring. For example, if there is a home +directory in /var/tmp/user1 and there are partitions mounted in /var and +/var/tmp. The noexec option is only expected in /var/tmp, but OVAL will +check both. +Bash remediation uses the df command to find out the partition where the home +directory is mounted. However, if the directory doesn't exist the remediation won't be +applied. + 11 + 13 + 14 + 3 + 8 + 9 + APO13.01 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS05.02 + DSS05.05 + DSS05.06 + DSS06.06 + CCI-000366 + CCI-001764 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.2 + 4.3.4.3.3 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 7.6 + A.11.2.9 + A.12.1.2 + A.12.5.1 + A.12.6.2 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.8.2.1 + A.8.2.2 + A.8.2.3 + A.8.3.1 + A.8.3.3 + A.9.1.2 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 + CM-7(a) + CM-7(b) + CM-6(a) + AC-6 + AC-6(1) + MP-7 + PR.IP-1 + PR.PT-2 + PR.PT-3 + SRG-OS-000368-GPOS-00154 + SRG-OS-000480-GPOS-00227 + R28 + OL09-00-002071 + SV-271667r1091713_rule + The presence of SUID and SGID executables should be tightly controlled. Users +should not be able to execute SUID or SGID binaries from user home directory partitions. + # Remediation is applicable only in certain platforms +if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ); then + +function perform_remediation (){ + + mount_point_match_regexp="$(printf "^[[:space:]]*[^#].*[[:space:]]%s[[:space:]]" $1)" + + # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab + if ! grep -q "$mount_point_match_regexp" /etc/fstab; then + # runtime opts without some automatic kernel/userspace-added defaults + previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 | awk '{print $4}' \ + | sed -E "s/(rw|defaults|seclabel|nosuid)(,|$)//g;s/,$//") + [ "$previous_mount_opts" ] && previous_mount_opts+="," + # In iso9660 filesystems mtab could describe a "blocksize" value, this should be reflected in + # fstab as "block". The next variable is to satisfy shellcheck SC2050. + fs_type="" + if [ "$fs_type" == "iso9660" ] ; then + previous_mount_opts=$(sed 's/blocksize=/block=/' <<< "$previous_mount_opts") + fi + echo " $1 defaults,${previous_mount_opts}nosuid 0 0" >> /etc/fstab + # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it + elif ! grep "$mount_point_match_regexp" /etc/fstab | grep -q "nosuid"; then + previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}') + sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,nosuid|" /etc/fstab + fi + + if mkdir -p "$1"; then + if mountpoint -q "$1"; then + mount -o remount --target "$1" + fi + fi +} + +readarray -t home_directories < \ + <(awk -F':' '{if ($3>=1000 && $3!= 65534) print $6}' /etc/passwd ) + + +for home_directory in "${home_directories[@]}" +do + if [ -d $home_directory ]; then + fstab_mount_point=$(df $home_directory | awk '/^\/dev/ {print $6}') + if ! grep -qP "^/$|^/lib$|^/opt$|^/usr$|^/bin$|^/sbin$|^/boot$|^/dev$|^/proc$" <<< $fstab_mount_point + then + perform_remediation "$fstab_mount_point" + fi + fi +done + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002071 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_home_nosuid + - no_reboot_needed + +- name: Add nosuid Option to /home - Initialize variables + ansible.builtin.set_fact: + non_allowed_partitions: + - / + - /lib + - /opt + - /usr + - /bin + - /sbin + - /boot + - /dev + - /proc + home_directories: [] + allowed_mount_point: [] + fstab_mount_point_info: [] + when: ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + tags: + - DISA-STIG-OL09-00-002071 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_home_nosuid + - no_reboot_needed + +- name: Add nosuid Option to /home - Get home directories from passwd + ansible.builtin.getent: + database: passwd + when: ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + tags: + - DISA-STIG-OL09-00-002071 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_home_nosuid + - no_reboot_needed + +- name: Add nosuid Option to /home - Filter home directories based on UID range + ansible.builtin.set_fact: + home_directories: '{{ home_directories + [item.data[4]] }}' + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - item.data[4] is defined + - item.data[2]|int >= 1000 + - item.data[2]|int != 65534 + - item.data[4] not in non_allowed_partitions + with_items: '{{ ansible_facts.getent_passwd | dict2items(key_name=''user'', value_name=''data'')}}' + tags: + - DISA-STIG-OL09-00-002071 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_home_nosuid + - no_reboot_needed + +- name: Add nosuid Option to /home - Gather mount points + ansible.builtin.setup: + filter: ansible_mounts + when: ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + tags: + - DISA-STIG-OL09-00-002071 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_home_nosuid + - no_reboot_needed + +- name: Add nosuid Option to /home - Ensure mount options for home directories + block: + + - name: ' Add nosuid Option to /home - Obtain mount point using df and shell' + ansible.builtin.shell: | + df {{ item }} | awk '/^\/dev/ {print $6}' + register: df_output + with_items: '{{ home_directories }}' + + - name: Add nosuid Option to /home - Set mount point for each home directory + ansible.builtin.set_fact: + allowed_mount_point: '{{ allowed_mount_point + [item.stdout_lines[0]] }}' + with_items: '{{ df_output.results }}' + when: + - item.stdout_lines is defined + - item.stdout_lines | length > 0 + - item.stdout_lines[0] != "" + + - name: Add nosuid Option to /home - Obtain full mount information for allowed mount + point + ansible.builtin.set_fact: + fstab_mount_point_info: '{{ fstab_mount_point_info + [ ansible_mounts | selectattr(''mount'', + ''equalto'', item) | first ]}}' + with_items: '{{ allowed_mount_point }}' + when: allowed_mount_point is defined + + - name: Add nosuid Option to /home - Ensure mount option nosuid is in fstab for + allowed mount point + ansible.builtin.mount: + path: '{{ item.mount }}' + src: '{{ item.device }}' + opts: '{{ item.options }},nosuid' + state: mounted + fstype: '{{ item.fstype }}' + with_items: '{{ fstab_mount_point_info }}' + when: + - allowed_mount_point is defined + - item.mount not in non_allowed_partitions + - '''nosuid'' not in item.options' + when: ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + tags: + - DISA-STIG-OL09-00-002071 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_home_nosuid + - no_reboot_needed + + + + + + + + + + Add usrquota Option to /home + The usrquota mount option allows for the filesystem to have disk quotas configured. +Add the usrquota option to the fourth column of +/etc/fstab for the line which controls mounting of +/home. + The quota options for XFS file systems can only be activated when mounting the partition. +It is not possible to enable them by remounting an already mounted partition. Therefore, +if the desired options were not defined before mounting the partition, dismount and mount +it again to apply the quota options. + OVAL looks for partitions whose mount point is a substring of any interactive user's home +directory and validates that usrquota option is there. Because of this, there could be +false negatives when several partitions share a base substring. For example, if there is a +home directory in /var/tmp/user1 and there are partitions mounted in +/var and /var/tmp. The usrquota option is only expected in +/var/tmp, but OVAL will check both. +Bash remediation uses the df command to find out the partition where the home +directory is mounted. However, if the directory doesn't exist the remediation won't be +applied. + CM-6(b) + To ensure the availability of disk space on /home, it is important to limit the impact a +single user or group can cause for other users (or the wider system) by intentionally or +accidentally filling up the partition. Quotas can also be applied to inodes for filesystems +where inode exhaustion is a concern. + # Remediation is applicable only in certain platforms +if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ); then + +function perform_remediation (){ + + mount_point_match_regexp="$(printf "^[[:space:]]*[^#].*[[:space:]]%s[[:space:]]" $1)" + + # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab + if ! grep -q "$mount_point_match_regexp" /etc/fstab; then + # runtime opts without some automatic kernel/userspace-added defaults + previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 | awk '{print $4}' \ + | sed -E "s/(rw|defaults|seclabel|usrquota)(,|$)//g;s/,$//") + [ "$previous_mount_opts" ] && previous_mount_opts+="," + # In iso9660 filesystems mtab could describe a "blocksize" value, this should be reflected in + # fstab as "block". The next variable is to satisfy shellcheck SC2050. + fs_type="" + if [ "$fs_type" == "iso9660" ] ; then + previous_mount_opts=$(sed 's/blocksize=/block=/' <<< "$previous_mount_opts") + fi + echo " $1 defaults,${previous_mount_opts}usrquota 0 0" >> /etc/fstab + # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it + elif ! grep "$mount_point_match_regexp" /etc/fstab | grep -q "usrquota"; then + previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}') + sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,usrquota|" /etc/fstab + fi + + if mkdir -p "$1"; then + if mountpoint -q "$1"; then + mount -o remount --target "$1" + fi + fi +} + +readarray -t home_directories < \ + <(awk -F':' '{if ($3>=1000 && $3!= 65534) print $6}' /etc/passwd ) + + +for home_directory in "${home_directories[@]}" +do + if [ -d $home_directory ]; then + fstab_mount_point=$(df $home_directory | awk '/^\/dev/ {print $6}') + if ! grep -qP "^/$|^/lib$|^/opt$|^/usr$|^/bin$|^/sbin$|^/boot$|^/dev$|^/proc$" <<< $fstab_mount_point + then + perform_remediation "$fstab_mount_point" + fi + fi +done + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-53-CM-6(b) + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_home_usrquota + - no_reboot_needed + +- name: Add usrquota Option to /home - Initialize variables + ansible.builtin.set_fact: + non_allowed_partitions: + - / + - /lib + - /opt + - /usr + - /bin + - /sbin + - /boot + - /dev + - /proc + home_directories: [] + allowed_mount_point: [] + fstab_mount_point_info: [] + when: ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + tags: + - NIST-800-53-CM-6(b) + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_home_usrquota + - no_reboot_needed + +- name: Add usrquota Option to /home - Get home directories from passwd + ansible.builtin.getent: + database: passwd + when: ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + tags: + - NIST-800-53-CM-6(b) + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_home_usrquota + - no_reboot_needed + +- name: Add usrquota Option to /home - Filter home directories based on UID range + ansible.builtin.set_fact: + home_directories: '{{ home_directories + [item.data[4]] }}' + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - item.data[4] is defined + - item.data[2]|int >= 1000 + - item.data[2]|int != 65534 + - item.data[4] not in non_allowed_partitions + with_items: '{{ ansible_facts.getent_passwd | dict2items(key_name=''user'', value_name=''data'')}}' + tags: + - NIST-800-53-CM-6(b) + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_home_usrquota + - no_reboot_needed + +- name: Add usrquota Option to /home - Gather mount points + ansible.builtin.setup: + filter: ansible_mounts + when: ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + tags: + - NIST-800-53-CM-6(b) + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_home_usrquota + - no_reboot_needed + +- name: Add usrquota Option to /home - Ensure mount options for home directories + block: + + - name: ' Add usrquota Option to /home - Obtain mount point using df and shell' + ansible.builtin.shell: | + df {{ item }} | awk '/^\/dev/ {print $6}' + register: df_output + with_items: '{{ home_directories }}' + + - name: Add usrquota Option to /home - Set mount point for each home directory + ansible.builtin.set_fact: + allowed_mount_point: '{{ allowed_mount_point + [item.stdout_lines[0]] }}' + with_items: '{{ df_output.results }}' + when: + - item.stdout_lines is defined + - item.stdout_lines | length > 0 + - item.stdout_lines[0] != "" + + - name: Add usrquota Option to /home - Obtain full mount information for allowed + mount point + ansible.builtin.set_fact: + fstab_mount_point_info: '{{ fstab_mount_point_info + [ ansible_mounts | selectattr(''mount'', + ''equalto'', item) | first ]}}' + with_items: '{{ allowed_mount_point }}' + when: allowed_mount_point is defined + + - name: Add usrquota Option to /home - Ensure mount option usrquota is in fstab + for allowed mount point + ansible.builtin.mount: + path: '{{ item.mount }}' + src: '{{ item.device }}' + opts: '{{ item.options }},usrquota' + state: mounted + fstype: '{{ item.fstype }}' + with_items: '{{ fstab_mount_point_info }}' + when: + - allowed_mount_point is defined + - item.mount not in non_allowed_partitions + - '''usrquota'' not in item.options' + when: ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + tags: + - NIST-800-53-CM-6(b) + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_home_usrquota + - no_reboot_needed + + + + + + + + + + Add nodev Option to Non-Root Local Partitions + The nodev mount option prevents files from being interpreted as +character or block devices. Legitimate character and block devices should +exist only in the /dev directory on the root partition or within +chroot jails built for system services. +Add the nodev option to the fourth column of +/etc/fstab for the line which controls mounting of + + any non-root local partitions. + 11 + 14 + 3 + 9 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS05.02 + DSS05.05 + DSS06.06 + CCI-000366 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.2 + 4.3.4.3.3 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 7.6 + A.12.1.2 + A.12.5.1 + A.12.6.2 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.9.1.2 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 + CM-7(a) + CM-7(b) + CM-6(a) + AC-6 + AC-6(1) + MP-7 + PR.IP-1 + PR.PT-3 + SRG-OS-000368-GPOS-00154 + SRG-OS-000480-GPOS-00227 + R28 + OL09-00-002080 + SV-271669r1091719_rule + The nodev mount option prevents files from being +interpreted as character or block devices. The only legitimate location +for device files is the /dev directory located on the root partition. +The only exception to this is chroot jails, for which it is not advised +to set nodev on these filesystems. + # Remediation is applicable only in certain platforms +if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ); then + +MOUNT_OPTION="nodev" +# Create array of local non-root partitions +readarray -t partitions_records < <(findmnt --mtab --raw --evaluate | grep "^/\w" | grep -v "^/proc" | grep "\s/dev/\w") + +# Create array of polyinstantiated directories, in case one of them is found in mtab +readarray -t polyinstantiated_dirs < \ + <(grep -oP "^\s*[^#\s]+\s+\S+" /etc/security/namespace.conf | grep -oP "(?<=\s)\S+?(?=/?\$)") + + +for partition_record in "${partitions_records[@]}"; do + # Get all important information for fstab + mount_point="$(echo ${partition_record} | cut -d " " -f1)" + device="$(echo ${partition_record} | cut -d " " -f2)" + device_type="$(echo ${partition_record} | cut -d " " -f3)" + if ! printf '%s\0' "${polyinstantiated_dirs[@]}" | grep -qxzF "$mount_point"; then + # device and device_type will be used only in case when the device doesn't have fstab record + mount_point_match_regexp="$(printf "^[[:space:]]*[^#].*[[:space:]]%s[[:space:]]" $mount_point)" + + # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab + if ! grep -q "$mount_point_match_regexp" /etc/fstab; then + # runtime opts without some automatic kernel/userspace-added defaults + previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 | awk '{print $4}' \ + | sed -E "s/(rw|defaults|seclabel|$MOUNT_OPTION)(,|$)//g;s/,$//") + [ "$previous_mount_opts" ] && previous_mount_opts+="," + # In iso9660 filesystems mtab could describe a "blocksize" value, this should be reflected in + # fstab as "block". The next variable is to satisfy shellcheck SC2050. + fs_type="$device_type" + if [ "$fs_type" == "iso9660" ] ; then + previous_mount_opts=$(sed 's/blocksize=/block=/' <<< "$previous_mount_opts") + fi + echo "$device $mount_point $device_type defaults,${previous_mount_opts}$MOUNT_OPTION 0 0" >> /etc/fstab + # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it + elif ! grep "$mount_point_match_regexp" /etc/fstab | grep -q "$MOUNT_OPTION"; then + previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}') + sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,$MOUNT_OPTION|" /etc/fstab + fi + if mkdir -p "$mount_point"; then + if mountpoint -q "$mount_point"; then + mount -o remount --target "$mount_point" + fi + fi + fi +done + +# Remediate unmounted /etc/fstab entries +sed -i -E '/nodev/! s;^\s*(/dev/\S+|UUID=\S+)\s+(/\w\S*)\s+(\S+)\s+(\S+)(.*)$;\1 \2 \3 \4,nodev \5;' /etc/fstab + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002080 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_nodev_nonroot_local_partitions + - no_reboot_needed + +- name: 'Add nodev Option to Non-Root Local Partitions: Refresh facts' + setup: + gather_subset: mounts + when: ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + tags: + - DISA-STIG-OL09-00-002080 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_nodev_nonroot_local_partitions + - no_reboot_needed + +- name: 'Add nodev Option to Non-Root Local Partitions: Ensure non-root local partitions + are mounted with nodev option' + mount: + path: '{{ item.mount }}' + src: '{{ item.device }}' + opts: '{{ item.options }},nodev' + state: mounted + fstype: '{{ item.fstype }}' + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - item.mount is match('/\w') + - item.options is not search('nodev') + with_items: + - '{{ ansible_facts.mounts }}' + tags: + - DISA-STIG-OL09-00-002080 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_nodev_nonroot_local_partitions + - no_reboot_needed + +- name: 'Add nodev Option to Non-Root Local Partitions: Ensure non-root local partitions + are present with nodev option in /etc/fstab' + ansible.builtin.replace: + path: /etc/fstab + regexp: ^\s*(?!#)(/dev/\S+|UUID=\S+)\s+(/\w\S*)\s+(\S+)\s+(?!nodev)(\S+)(.*)$ + replace: \1 \2 \3 \4,nodev \5 + when: ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + tags: + - DISA-STIG-OL09-00-002080 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_nodev_nonroot_local_partitions + - no_reboot_needed + + + + + + + + + + Add nodev Option to Removable Media Partitions + The nodev mount option prevents files from being +interpreted as character or block devices. +Legitimate character and block devices should exist only in +the /dev directory on the root partition or within chroot +jails built for system services. +Add the nodev option to the fourth column of +/etc/fstab for the line which controls mounting of + + any removable media partitions. + 11 + 12 + 13 + 14 + 16 + 3 + 8 + 9 + APO13.01 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS01.04 + DSS05.02 + DSS05.03 + DSS05.04 + DSS05.05 + DSS05.06 + DSS05.07 + DSS06.03 + DSS06.06 + CCI-000366 + 4.3.3.2.2 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.2 + 4.3.4.3.3 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 7.6 + A.11.2.6 + A.11.2.9 + A.12.1.2 + A.12.5.1 + A.12.6.2 + A.13.1.1 + A.13.2.1 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.6.2.1 + A.6.2.2 + A.7.1.1 + A.8.2.1 + A.8.2.2 + A.8.2.3 + A.8.3.1 + A.8.3.3 + A.9.1.2 + A.9.2.1 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 + CM-7(a) + CM-7(b) + CM-6(a) + AC-6 + AC-6(1) + MP-7 + PR.AC-3 + PR.AC-6 + PR.IP-1 + PR.PT-2 + PR.PT-3 + SRG-OS-000480-GPOS-00227 + OL09-00-002021 + SV-271645r1091647_rule + The only legitimate location for device files is the /dev directory +located on the root partition. An exception to this is chroot jails, and it is +not advised to set nodev on partitions which contain their root +filesystems. + # Remediation is applicable only in certain platforms +if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ); then + +var_removable_partition='' + + +device_regex="^\s*$var_removable_partition\s\+" +mount_option="nodev" + +if grep -q $device_regex /etc/fstab ; then + previous_opts=$(grep $device_regex /etc/fstab | awk '{print $4}') + sed -i "s|\($device_regex.*$previous_opts\)|\1,$mount_option|" /etc/fstab +else + echo "Not remediating, because there is no record of $var_removable_partition in /etc/fstab" >&2 +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002021 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_nodev_removable_partitions + - no_reboot_needed +- name: XCCDF Value var_removable_partition # promote to variable + set_fact: + var_removable_partition: !!str + tags: + - always + +- name: Ensure permission nodev are set on var_removable_partition + lineinfile: + path: /etc/fstab + regexp: ^\s*({{ var_removable_partition }})\s+([^\s]*)\s+([^\s]*)\s+([^\s]*)(.*)$ + backrefs: true + line: \1 \2 \3 \4,nodev \5 + when: ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + tags: + - DISA-STIG-OL09-00-002021 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_nodev_removable_partitions + - no_reboot_needed + + + + + + + + + + + Add noexec Option to Removable Media Partitions + The noexec mount option prevents the direct execution of binaries +on the mounted filesystem. Preventing the direct execution of binaries from +removable media (such as a USB key) provides a defense against malicious +software that may be present on such untrusted media. +Add the noexec option to the fourth column of +/etc/fstab for the line which controls mounting of + + any removable media partitions. + 11 + 12 + 13 + 14 + 16 + 3 + 8 + 9 + APO13.01 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS01.04 + DSS05.02 + DSS05.03 + DSS05.04 + DSS05.05 + DSS05.06 + DSS05.07 + DSS06.03 + DSS06.06 + CCI-000366 + 4.3.3.2.2 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.2 + 4.3.4.3.3 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 7.6 + A.11.2.6 + A.11.2.9 + A.12.1.2 + A.12.5.1 + A.12.6.2 + A.13.1.1 + A.13.2.1 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.6.2.1 + A.6.2.2 + A.7.1.1 + A.8.2.1 + A.8.2.2 + A.8.2.3 + A.8.3.1 + A.8.3.3 + A.9.1.2 + A.9.2.1 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 + CM-7(a) + CM-7(b) + CM-6(a) + AC-6 + AC-6(1) + MP-7 + PR.AC-3 + PR.AC-6 + PR.IP-1 + PR.PT-2 + PR.PT-3 + SRG-OS-000480-GPOS-00227 + OL09-00-002020 + SV-271644r1091644_rule + Allowing users to execute binaries from removable media such as USB keys exposes +the system to potential compromise. + # Remediation is applicable only in certain platforms +if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ); then + +var_removable_partition='' + + +device_regex="^\s*$var_removable_partition\s\+" +mount_option="noexec" + +if grep -q $device_regex /etc/fstab ; then + previous_opts=$(grep $device_regex /etc/fstab | awk '{print $4}') + sed -i "s|\($device_regex.*$previous_opts\)|\1,$mount_option|" /etc/fstab +else + echo "Not remediating, because there is no record of $var_removable_partition in /etc/fstab" >&2 +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002020 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_noexec_removable_partitions + - no_reboot_needed +- name: XCCDF Value var_removable_partition # promote to variable + set_fact: + var_removable_partition: !!str + tags: + - always + +- name: Ensure permission noexec are set on var_removable_partition + lineinfile: + path: /etc/fstab + regexp: ^\s*({{ var_removable_partition }})\s+([^\s]*)\s+([^\s]*)\s+([^\s]*)(.*)$ + backrefs: true + line: \1 \2 \3 \4,noexec \5 + when: ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + tags: + - DISA-STIG-OL09-00-002020 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_noexec_removable_partitions + - no_reboot_needed + + + + + + + + + + + Add nosuid Option to Removable Media Partitions + The nosuid mount option prevents set-user-identifier (SUID) +and set-group-identifier (SGID) permissions from taking effect. These permissions +allow users to execute binaries with the same permissions as the owner and group +of the file respectively. Users should not be allowed to introduce SUID and SGID +files into the system via partitions mounted from removeable media. +Add the nosuid option to the fourth column of +/etc/fstab for the line which controls mounting of + + any removable media partitions. + 11 + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + 8 + 9 + APO01.06 + APO13.01 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS01.04 + DSS05.02 + DSS05.03 + DSS05.04 + DSS05.05 + DSS05.06 + DSS05.07 + DSS06.02 + DSS06.03 + DSS06.06 + CCI-000366 + 4.3.3.2.2 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.2 + 4.3.4.3.3 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 5.2 + SR 7.6 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.11.2.6 + A.11.2.9 + A.12.1.2 + A.12.5.1 + A.12.6.2 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.6.1.2 + A.6.2.1 + A.6.2.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.1 + A.8.2.2 + A.8.2.3 + A.8.3.1 + A.8.3.3 + A.9.1.1 + A.9.1.2 + A.9.2.1 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 + CM-7(a) + CM-7(b) + CM-6(a) + AC-6 + AC-6(1) + MP-7 + PR.AC-3 + PR.AC-4 + PR.AC-6 + PR.DS-5 + PR.IP-1 + PR.PT-2 + PR.PT-3 + SRG-OS-000480-GPOS-00227 + OL09-00-002022 + SV-271646r1091650_rule + The presence of SUID and SGID executables should be tightly controlled. Allowing +users to introduce SUID or SGID binaries from partitions mounted off of +removable media would allow them to introduce their own highly-privileged programs. + # Remediation is applicable only in certain platforms +if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ); then + +var_removable_partition='' + + +device_regex="^\s*$var_removable_partition\s\+" +mount_option="nosuid" + +if grep -q $device_regex /etc/fstab ; then + previous_opts=$(grep $device_regex /etc/fstab | awk '{print $4}') + sed -i "s|\($device_regex.*$previous_opts\)|\1,$mount_option|" /etc/fstab +else + echo "Not remediating, because there is no record of $var_removable_partition in /etc/fstab" >&2 +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002022 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_nosuid_removable_partitions + - no_reboot_needed +- name: XCCDF Value var_removable_partition # promote to variable + set_fact: + var_removable_partition: !!str + tags: + - always + +- name: Ensure permission nosuid are set on var_removable_partition + lineinfile: + path: /etc/fstab + regexp: ^\s*({{ var_removable_partition }})\s+([^\s]*)\s+([^\s]*)\s+([^\s]*)(.*)$ + backrefs: true + line: \1 \2 \3 \4,nosuid \5 + when: ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + tags: + - DISA-STIG-OL09-00-002022 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_nosuid_removable_partitions + - no_reboot_needed + + + + + + + + + + + Add nosuid Option to /opt + The nosuid mount option can be used to prevent +execution of setuid programs in /opt. The SUID and SGID permissions +should not be required in this directory. +Add the nosuid option to the fourth column of +/etc/fstab for the line which controls mounting of +/opt. + R28 + The presence of SUID and SGID executables should be tightly controlled. The +/opt directory contains additional software packages. Users should +not be able to execute SUID or SGID binaries from this directory. + + # Remediation is applicable only in certain platforms +if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/opt" > /dev/null || findmnt --fstab "/opt" > /dev/null; }; then + +function perform_remediation { + + # the mount point /opt has to be defined in /etc/fstab + # before this remediation can be executed. In case it is not defined, the + # remediation aborts and no changes regarding the mount point are done. + mount_point_match_regexp="$(printf "^[[:space:]]*[^#].*[[:space:]]%s[[:space:]]" "/opt")" + + grep "$mount_point_match_regexp" -q /etc/fstab \ + || { echo "The mount point '/opt' is not even in /etc/fstab, so we can't set up mount options" >&2; + echo "Not remediating, because there is no record of /opt in /etc/fstab" >&2; return 1; } + + + + mount_point_match_regexp="$(printf "^[[:space:]]*[^#].*[[:space:]]%s[[:space:]]" /opt)" + + # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab + if ! grep -q "$mount_point_match_regexp" /etc/fstab; then + # runtime opts without some automatic kernel/userspace-added defaults + previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 | awk '{print $4}' \ + | sed -E "s/(rw|defaults|seclabel|nosuid)(,|$)//g;s/,$//") + [ "$previous_mount_opts" ] && previous_mount_opts+="," + # In iso9660 filesystems mtab could describe a "blocksize" value, this should be reflected in + # fstab as "block". The next variable is to satisfy shellcheck SC2050. + fs_type="" + if [ "$fs_type" == "iso9660" ] ; then + previous_mount_opts=$(sed 's/blocksize=/block=/' <<< "$previous_mount_opts") + fi + echo " /opt defaults,${previous_mount_opts}nosuid 0 0" >> /etc/fstab + # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it + elif ! grep "$mount_point_match_regexp" /etc/fstab | grep -q "nosuid"; then + previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}') + sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,nosuid|" /etc/fstab + fi + + + if mkdir -p "/opt"; then + if mountpoint -q "/opt"; then + mount -o remount --target "/opt" + fi + fi +} + +perform_remediation + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_opt_nosuid + - no_reboot_needed + +- name: 'Add nosuid Option to /opt: Check information associated to mountpoint' + command: findmnt --fstab '/opt' + register: device_name + failed_when: device_name.rc > 1 + changed_when: false + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/opt" in ansible_mounts | map(attribute="mount") | list' + tags: + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_opt_nosuid + - no_reboot_needed + +- name: 'Add nosuid Option to /opt: Create mount_info dictionary variable' + set_fact: + mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' + with_together: + - '{{ device_name.stdout_lines[0].split() | list | lower }}' + - '{{ device_name.stdout_lines[1].split() | list }}' + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/opt" in ansible_mounts | map(attribute="mount") | list' + - device_name.stdout is defined and device_name.stdout_lines is defined + - (device_name.stdout | length > 0) + tags: + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_opt_nosuid + - no_reboot_needed + +- name: 'Add nosuid Option to /opt: If /opt not mounted, craft mount_info manually' + set_fact: + mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' + with_together: + - - target + - source + - fstype + - options + - - /opt + - '' + - '' + - defaults + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/opt" in ansible_mounts | map(attribute="mount") | list' + - ("--fstab" | length == 0) + - device_name.stdout is defined and device_name.stdout_lines is defined + - (device_name.stdout | length == 0) + tags: + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_opt_nosuid + - no_reboot_needed + +- name: 'Add nosuid Option to /opt: Make sure nosuid option is part of the to /opt + options' + set_fact: + mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',nosuid'' + }) }}' + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/opt" in ansible_mounts | map(attribute="mount") | list' + - mount_info is defined and "nosuid" not in mount_info.options + tags: + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_opt_nosuid + - no_reboot_needed + +- name: 'Add nosuid Option to /opt: Ensure /opt is mounted with nosuid option' + mount: + path: /opt + src: '{{ mount_info.source }}' + opts: '{{ mount_info.options }}' + state: mounted + fstype: '{{ mount_info.fstype }}' + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/opt" in ansible_mounts | map(attribute="mount") | list' + - mount_info is defined + - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" + | length == 0) + tags: + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_opt_nosuid + - no_reboot_needed + + +part /opt --mountoptions="nosuid" + + + + + + + + + + Add nosuid Option to /srv + The nosuid mount option can be used to prevent +execution of setuid programs in /srv. The SUID and SGID permissions +should not be required in this directory. +Add the nosuid option to the fourth column of +/etc/fstab for the line which controls mounting of +/srv. + R28 + The presence of SUID and SGID executables should be tightly controlled. The +/srv directory contains files served by various network services such as FTP. Users should +not be able to execute SUID or SGID binaries from this directory. + + # Remediation is applicable only in certain platforms +if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/srv" > /dev/null || findmnt --fstab "/srv" > /dev/null; }; then + +function perform_remediation { + + # the mount point /srv has to be defined in /etc/fstab + # before this remediation can be executed. In case it is not defined, the + # remediation aborts and no changes regarding the mount point are done. + mount_point_match_regexp="$(printf "^[[:space:]]*[^#].*[[:space:]]%s[[:space:]]" "/srv")" + + grep "$mount_point_match_regexp" -q /etc/fstab \ + || { echo "The mount point '/srv' is not even in /etc/fstab, so we can't set up mount options" >&2; + echo "Not remediating, because there is no record of /srv in /etc/fstab" >&2; return 1; } + + + + mount_point_match_regexp="$(printf "^[[:space:]]*[^#].*[[:space:]]%s[[:space:]]" /srv)" + + # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab + if ! grep -q "$mount_point_match_regexp" /etc/fstab; then + # runtime opts without some automatic kernel/userspace-added defaults + previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 | awk '{print $4}' \ + | sed -E "s/(rw|defaults|seclabel|nosuid)(,|$)//g;s/,$//") + [ "$previous_mount_opts" ] && previous_mount_opts+="," + # In iso9660 filesystems mtab could describe a "blocksize" value, this should be reflected in + # fstab as "block". The next variable is to satisfy shellcheck SC2050. + fs_type="" + if [ "$fs_type" == "iso9660" ] ; then + previous_mount_opts=$(sed 's/blocksize=/block=/' <<< "$previous_mount_opts") + fi + echo " /srv defaults,${previous_mount_opts}nosuid 0 0" >> /etc/fstab + # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it + elif ! grep "$mount_point_match_regexp" /etc/fstab | grep -q "nosuid"; then + previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}') + sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,nosuid|" /etc/fstab + fi + + + if mkdir -p "/srv"; then + if mountpoint -q "/srv"; then + mount -o remount --target "/srv" + fi + fi +} + +perform_remediation + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_srv_nosuid + - no_reboot_needed + +- name: 'Add nosuid Option to /srv: Check information associated to mountpoint' + command: findmnt --fstab '/srv' + register: device_name + failed_when: device_name.rc > 1 + changed_when: false + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/srv" in ansible_mounts | map(attribute="mount") | list' + tags: + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_srv_nosuid + - no_reboot_needed + +- name: 'Add nosuid Option to /srv: Create mount_info dictionary variable' + set_fact: + mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' + with_together: + - '{{ device_name.stdout_lines[0].split() | list | lower }}' + - '{{ device_name.stdout_lines[1].split() | list }}' + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/srv" in ansible_mounts | map(attribute="mount") | list' + - device_name.stdout is defined and device_name.stdout_lines is defined + - (device_name.stdout | length > 0) + tags: + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_srv_nosuid + - no_reboot_needed + +- name: 'Add nosuid Option to /srv: If /srv not mounted, craft mount_info manually' + set_fact: + mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' + with_together: + - - target + - source + - fstype + - options + - - /srv + - '' + - '' + - defaults + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/srv" in ansible_mounts | map(attribute="mount") | list' + - ("--fstab" | length == 0) + - device_name.stdout is defined and device_name.stdout_lines is defined + - (device_name.stdout | length == 0) + tags: + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_srv_nosuid + - no_reboot_needed + +- name: 'Add nosuid Option to /srv: Make sure nosuid option is part of the to /srv + options' + set_fact: + mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',nosuid'' + }) }}' + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/srv" in ansible_mounts | map(attribute="mount") | list' + - mount_info is defined and "nosuid" not in mount_info.options + tags: + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_srv_nosuid + - no_reboot_needed + +- name: 'Add nosuid Option to /srv: Ensure /srv is mounted with nosuid option' + mount: + path: /srv + src: '{{ mount_info.source }}' + opts: '{{ mount_info.options }}' + state: mounted + fstype: '{{ mount_info.fstype }}' + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/srv" in ansible_mounts | map(attribute="mount") | list' + - mount_info is defined + - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" + | length == 0) + tags: + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_srv_nosuid + - no_reboot_needed + + +part /srv --mountoptions="nosuid" + + + + + + + + + + Add nodev Option to /tmp + The nodev mount option can be used to prevent device files from +being created in /tmp. Legitimate character and block devices +should not exist within temporary directories like /tmp. +Add the nodev option to the fourth column of +/etc/fstab for the line which controls mounting of +/tmp. + 11 + 13 + 14 + 3 + 8 + 9 + APO13.01 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS05.02 + DSS05.05 + DSS05.06 + DSS06.06 + CCI-001764 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.2 + 4.3.4.3.3 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 7.6 + A.11.2.9 + A.12.1.2 + A.12.5.1 + A.12.6.2 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.8.2.1 + A.8.2.2 + A.8.2.3 + A.8.3.1 + A.8.3.3 + A.9.1.2 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 + CM-7(a) + CM-7(b) + CM-6(a) + AC-6 + AC-6(1) + MP-7 + PR.IP-1 + PR.PT-2 + PR.PT-3 + SRG-OS-000368-GPOS-00154 + OL09-00-002050 + SV-271653r1091671_rule + The only legitimate location for device files is the /dev directory +located on the root partition. The only exception to this is chroot jails. + + # Remediation is applicable only in certain platforms +if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/tmp" > /dev/null || findmnt --fstab "/tmp" > /dev/null; }; then + +function perform_remediation { + + # the mount point /tmp has to be defined in /etc/fstab + # before this remediation can be executed. In case it is not defined, the + # remediation aborts and no changes regarding the mount point are done. + mount_point_match_regexp="$(printf "^[[:space:]]*[^#].*[[:space:]]%s[[:space:]]" "/tmp")" + + grep "$mount_point_match_regexp" -q /etc/fstab \ + || { echo "The mount point '/tmp' is not even in /etc/fstab, so we can't set up mount options" >&2; + echo "Not remediating, because there is no record of /tmp in /etc/fstab" >&2; return 1; } + + + + mount_point_match_regexp="$(printf "^[[:space:]]*[^#].*[[:space:]]%s[[:space:]]" /tmp)" + + # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab + if ! grep -q "$mount_point_match_regexp" /etc/fstab; then + # runtime opts without some automatic kernel/userspace-added defaults + previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 | awk '{print $4}' \ + | sed -E "s/(rw|defaults|seclabel|nodev)(,|$)//g;s/,$//") + [ "$previous_mount_opts" ] && previous_mount_opts+="," + # In iso9660 filesystems mtab could describe a "blocksize" value, this should be reflected in + # fstab as "block". The next variable is to satisfy shellcheck SC2050. + fs_type="" + if [ "$fs_type" == "iso9660" ] ; then + previous_mount_opts=$(sed 's/blocksize=/block=/' <<< "$previous_mount_opts") + fi + echo " /tmp defaults,${previous_mount_opts}nodev 0 0" >> /etc/fstab + # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it + elif ! grep "$mount_point_match_regexp" /etc/fstab | grep -q "nodev"; then + previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}') + sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,nodev|" /etc/fstab + fi + + + if mkdir -p "/tmp"; then + if mountpoint -q "/tmp"; then + mount -o remount --target "/tmp" + fi + fi +} + +perform_remediation + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002050 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_tmp_nodev + - no_reboot_needed + +- name: 'Add nodev Option to /tmp: Check information associated to mountpoint' + command: findmnt --fstab '/tmp' + register: device_name + failed_when: device_name.rc > 1 + changed_when: false + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/tmp" in ansible_mounts | map(attribute="mount") | list' + tags: + - DISA-STIG-OL09-00-002050 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_tmp_nodev + - no_reboot_needed + +- name: 'Add nodev Option to /tmp: Create mount_info dictionary variable' + set_fact: + mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' + with_together: + - '{{ device_name.stdout_lines[0].split() | list | lower }}' + - '{{ device_name.stdout_lines[1].split() | list }}' + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/tmp" in ansible_mounts | map(attribute="mount") | list' + - device_name.stdout is defined and device_name.stdout_lines is defined + - (device_name.stdout | length > 0) + tags: + - DISA-STIG-OL09-00-002050 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_tmp_nodev + - no_reboot_needed + +- name: 'Add nodev Option to /tmp: If /tmp not mounted, craft mount_info manually' + set_fact: + mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' + with_together: + - - target + - source + - fstype + - options + - - /tmp + - '' + - '' + - defaults + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/tmp" in ansible_mounts | map(attribute="mount") | list' + - ("--fstab" | length == 0) + - device_name.stdout is defined and device_name.stdout_lines is defined + - (device_name.stdout | length == 0) + tags: + - DISA-STIG-OL09-00-002050 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_tmp_nodev + - no_reboot_needed + +- name: 'Add nodev Option to /tmp: Make sure nodev option is part of the to /tmp options' + set_fact: + mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',nodev'' + }) }}' + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/tmp" in ansible_mounts | map(attribute="mount") | list' + - mount_info is defined and "nodev" not in mount_info.options + tags: + - DISA-STIG-OL09-00-002050 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_tmp_nodev + - no_reboot_needed + +- name: 'Add nodev Option to /tmp: Ensure /tmp is mounted with nodev option' + mount: + path: /tmp + src: '{{ mount_info.source }}' + opts: '{{ mount_info.options }}' + state: mounted + fstype: '{{ mount_info.fstype }}' + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/tmp" in ansible_mounts | map(attribute="mount") | list' + - mount_info is defined + - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" + | length == 0) + tags: + - DISA-STIG-OL09-00-002050 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_tmp_nodev + - no_reboot_needed + + +part /tmp --mountoptions="nodev" + + + + + + + + + + Add noexec Option to /tmp + The noexec mount option can be used to prevent binaries +from being executed out of /tmp. +Add the noexec option to the fourth column of +/etc/fstab for the line which controls mounting of +/tmp. + 11 + 13 + 14 + 3 + 8 + 9 + APO13.01 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS05.02 + DSS05.05 + DSS05.06 + DSS06.06 + CCI-001764 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.2 + 4.3.4.3.3 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 7.6 + A.11.2.9 + A.12.1.2 + A.12.5.1 + A.12.6.2 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.8.2.1 + A.8.2.2 + A.8.2.3 + A.8.3.1 + A.8.3.3 + A.9.1.2 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 + CM-7(a) + CM-7(b) + CM-6(a) + AC-6 + AC-6(1) + MP-7 + PR.IP-1 + PR.PT-2 + PR.PT-3 + SRG-OS-000368-GPOS-00154 + R28 + OL09-00-002051 + SV-271654r1091674_rule + Allowing users to execute binaries from world-writable directories +such as /tmp should never be necessary in normal operation and +can expose the system to potential compromise. + + # Remediation is applicable only in certain platforms +if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/tmp" > /dev/null || findmnt --fstab "/tmp" > /dev/null; }; then + +function perform_remediation { + + # the mount point /tmp has to be defined in /etc/fstab + # before this remediation can be executed. In case it is not defined, the + # remediation aborts and no changes regarding the mount point are done. + mount_point_match_regexp="$(printf "^[[:space:]]*[^#].*[[:space:]]%s[[:space:]]" "/tmp")" + + grep "$mount_point_match_regexp" -q /etc/fstab \ + || { echo "The mount point '/tmp' is not even in /etc/fstab, so we can't set up mount options" >&2; + echo "Not remediating, because there is no record of /tmp in /etc/fstab" >&2; return 1; } + + + + mount_point_match_regexp="$(printf "^[[:space:]]*[^#].*[[:space:]]%s[[:space:]]" /tmp)" + + # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab + if ! grep -q "$mount_point_match_regexp" /etc/fstab; then + # runtime opts without some automatic kernel/userspace-added defaults + previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 | awk '{print $4}' \ + | sed -E "s/(rw|defaults|seclabel|noexec)(,|$)//g;s/,$//") + [ "$previous_mount_opts" ] && previous_mount_opts+="," + # In iso9660 filesystems mtab could describe a "blocksize" value, this should be reflected in + # fstab as "block". The next variable is to satisfy shellcheck SC2050. + fs_type="" + if [ "$fs_type" == "iso9660" ] ; then + previous_mount_opts=$(sed 's/blocksize=/block=/' <<< "$previous_mount_opts") + fi + echo " /tmp defaults,${previous_mount_opts}noexec 0 0" >> /etc/fstab + # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it + elif ! grep "$mount_point_match_regexp" /etc/fstab | grep -q "noexec"; then + previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}') + sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,noexec|" /etc/fstab + fi + + + if mkdir -p "/tmp"; then + if mountpoint -q "/tmp"; then + mount -o remount --target "/tmp" + fi + fi +} + +perform_remediation + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002051 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_tmp_noexec + - no_reboot_needed + +- name: 'Add noexec Option to /tmp: Check information associated to mountpoint' + command: findmnt --fstab '/tmp' + register: device_name + failed_when: device_name.rc > 1 + changed_when: false + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/tmp" in ansible_mounts | map(attribute="mount") | list' + tags: + - DISA-STIG-OL09-00-002051 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_tmp_noexec + - no_reboot_needed + +- name: 'Add noexec Option to /tmp: Create mount_info dictionary variable' + set_fact: + mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' + with_together: + - '{{ device_name.stdout_lines[0].split() | list | lower }}' + - '{{ device_name.stdout_lines[1].split() | list }}' + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/tmp" in ansible_mounts | map(attribute="mount") | list' + - device_name.stdout is defined and device_name.stdout_lines is defined + - (device_name.stdout | length > 0) + tags: + - DISA-STIG-OL09-00-002051 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_tmp_noexec + - no_reboot_needed + +- name: 'Add noexec Option to /tmp: If /tmp not mounted, craft mount_info manually' + set_fact: + mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' + with_together: + - - target + - source + - fstype + - options + - - /tmp + - '' + - '' + - defaults + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/tmp" in ansible_mounts | map(attribute="mount") | list' + - ("--fstab" | length == 0) + - device_name.stdout is defined and device_name.stdout_lines is defined + - (device_name.stdout | length == 0) + tags: + - DISA-STIG-OL09-00-002051 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_tmp_noexec + - no_reboot_needed + +- name: 'Add noexec Option to /tmp: Make sure noexec option is part of the to /tmp + options' + set_fact: + mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',noexec'' + }) }}' + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/tmp" in ansible_mounts | map(attribute="mount") | list' + - mount_info is defined and "noexec" not in mount_info.options + tags: + - DISA-STIG-OL09-00-002051 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_tmp_noexec + - no_reboot_needed + +- name: 'Add noexec Option to /tmp: Ensure /tmp is mounted with noexec option' + mount: + path: /tmp + src: '{{ mount_info.source }}' + opts: '{{ mount_info.options }}' + state: mounted + fstype: '{{ mount_info.fstype }}' + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/tmp" in ansible_mounts | map(attribute="mount") | list' + - mount_info is defined + - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" + | length == 0) + tags: + - DISA-STIG-OL09-00-002051 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_tmp_noexec + - no_reboot_needed + + +part /tmp --mountoptions="noexec" + + + + + + + + + + Add nosuid Option to /tmp + The nosuid mount option can be used to prevent +execution of setuid programs in /tmp. The SUID and SGID permissions +should not be required in these world-writable directories. +Add the nosuid option to the fourth column of +/etc/fstab for the line which controls mounting of +/tmp. + 11 + 13 + 14 + 3 + 8 + 9 + APO13.01 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS05.02 + DSS05.05 + DSS05.06 + DSS06.06 + CCI-001764 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.2 + 4.3.4.3.3 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 7.6 + A.11.2.9 + A.12.1.2 + A.12.5.1 + A.12.6.2 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.8.2.1 + A.8.2.2 + A.8.2.3 + A.8.3.1 + A.8.3.3 + A.9.1.2 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 + CM-7(a) + CM-7(b) + CM-6(a) + AC-6 + AC-6(1) + MP-7 + PR.IP-1 + PR.PT-2 + PR.PT-3 + SRG-OS-000368-GPOS-00154 + R28 + OL09-00-002052 + SV-271655r1091677_rule + The presence of SUID and SGID executables should be tightly controlled. Users +should not be able to execute SUID or SGID binaries from temporary storage partitions. + + # Remediation is applicable only in certain platforms +if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/tmp" > /dev/null || findmnt --fstab "/tmp" > /dev/null; }; then + +function perform_remediation { + + # the mount point /tmp has to be defined in /etc/fstab + # before this remediation can be executed. In case it is not defined, the + # remediation aborts and no changes regarding the mount point are done. + mount_point_match_regexp="$(printf "^[[:space:]]*[^#].*[[:space:]]%s[[:space:]]" "/tmp")" + + grep "$mount_point_match_regexp" -q /etc/fstab \ + || { echo "The mount point '/tmp' is not even in /etc/fstab, so we can't set up mount options" >&2; + echo "Not remediating, because there is no record of /tmp in /etc/fstab" >&2; return 1; } + + + + mount_point_match_regexp="$(printf "^[[:space:]]*[^#].*[[:space:]]%s[[:space:]]" /tmp)" + + # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab + if ! grep -q "$mount_point_match_regexp" /etc/fstab; then + # runtime opts without some automatic kernel/userspace-added defaults + previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 | awk '{print $4}' \ + | sed -E "s/(rw|defaults|seclabel|nosuid)(,|$)//g;s/,$//") + [ "$previous_mount_opts" ] && previous_mount_opts+="," + # In iso9660 filesystems mtab could describe a "blocksize" value, this should be reflected in + # fstab as "block". The next variable is to satisfy shellcheck SC2050. + fs_type="" + if [ "$fs_type" == "iso9660" ] ; then + previous_mount_opts=$(sed 's/blocksize=/block=/' <<< "$previous_mount_opts") + fi + echo " /tmp defaults,${previous_mount_opts}nosuid 0 0" >> /etc/fstab + # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it + elif ! grep "$mount_point_match_regexp" /etc/fstab | grep -q "nosuid"; then + previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}') + sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,nosuid|" /etc/fstab + fi + + + if mkdir -p "/tmp"; then + if mountpoint -q "/tmp"; then + mount -o remount --target "/tmp" + fi + fi +} + +perform_remediation + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002052 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_tmp_nosuid + - no_reboot_needed + +- name: 'Add nosuid Option to /tmp: Check information associated to mountpoint' + command: findmnt --fstab '/tmp' + register: device_name + failed_when: device_name.rc > 1 + changed_when: false + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/tmp" in ansible_mounts | map(attribute="mount") | list' + tags: + - DISA-STIG-OL09-00-002052 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_tmp_nosuid + - no_reboot_needed + +- name: 'Add nosuid Option to /tmp: Create mount_info dictionary variable' + set_fact: + mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' + with_together: + - '{{ device_name.stdout_lines[0].split() | list | lower }}' + - '{{ device_name.stdout_lines[1].split() | list }}' + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/tmp" in ansible_mounts | map(attribute="mount") | list' + - device_name.stdout is defined and device_name.stdout_lines is defined + - (device_name.stdout | length > 0) + tags: + - DISA-STIG-OL09-00-002052 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_tmp_nosuid + - no_reboot_needed + +- name: 'Add nosuid Option to /tmp: If /tmp not mounted, craft mount_info manually' + set_fact: + mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' + with_together: + - - target + - source + - fstype + - options + - - /tmp + - '' + - '' + - defaults + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/tmp" in ansible_mounts | map(attribute="mount") | list' + - ("--fstab" | length == 0) + - device_name.stdout is defined and device_name.stdout_lines is defined + - (device_name.stdout | length == 0) + tags: + - DISA-STIG-OL09-00-002052 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_tmp_nosuid + - no_reboot_needed + +- name: 'Add nosuid Option to /tmp: Make sure nosuid option is part of the to /tmp + options' + set_fact: + mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',nosuid'' + }) }}' + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/tmp" in ansible_mounts | map(attribute="mount") | list' + - mount_info is defined and "nosuid" not in mount_info.options + tags: + - DISA-STIG-OL09-00-002052 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_tmp_nosuid + - no_reboot_needed + +- name: 'Add nosuid Option to /tmp: Ensure /tmp is mounted with nosuid option' + mount: + path: /tmp + src: '{{ mount_info.source }}' + opts: '{{ mount_info.options }}' + state: mounted + fstype: '{{ mount_info.fstype }}' + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/tmp" in ansible_mounts | map(attribute="mount") | list' + - mount_info is defined + - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" + | length == 0) + tags: + - DISA-STIG-OL09-00-002052 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_tmp_nosuid + - no_reboot_needed + + +part /tmp --mountoptions="nosuid" + + + + + + + + + + Add nodev Option to /var/log/audit + The nodev mount option can be used to prevent device files from +being created in /var/log/audit. +Legitimate character and block devices should exist only in +the /dev directory on the root partition or within chroot +jails built for system services. +Add the nodev option to the fourth column of +/etc/fstab for the line which controls mounting of +/var/log/audit. + CCI-001764 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 + CM-7(a) + CM-7(b) + CM-6(a) + AC-6 + AC-6(1) + MP-7 + PR.IP-1 + PR.PT-2 + PR.PT-3 + FMT_SMF_EXT.1 + SRG-OS-000368-GPOS-00154 + OL09-00-002064 + SV-271660r1091692_rule + The only legitimate location for device files is the /dev directory +located on the root partition. The only exception to this is chroot jails. + + # Remediation is applicable only in certain platforms +if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/var/log/audit" > /dev/null || findmnt --fstab "/var/log/audit" > /dev/null; }; then + +function perform_remediation { + + # the mount point /var/log/audit has to be defined in /etc/fstab + # before this remediation can be executed. In case it is not defined, the + # remediation aborts and no changes regarding the mount point are done. + mount_point_match_regexp="$(printf "^[[:space:]]*[^#].*[[:space:]]%s[[:space:]]" "/var/log/audit")" + + grep "$mount_point_match_regexp" -q /etc/fstab \ + || { echo "The mount point '/var/log/audit' is not even in /etc/fstab, so we can't set up mount options" >&2; + echo "Not remediating, because there is no record of /var/log/audit in /etc/fstab" >&2; return 1; } + + + + mount_point_match_regexp="$(printf "^[[:space:]]*[^#].*[[:space:]]%s[[:space:]]" /var/log/audit)" + + # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab + if ! grep -q "$mount_point_match_regexp" /etc/fstab; then + # runtime opts without some automatic kernel/userspace-added defaults + previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 | awk '{print $4}' \ + | sed -E "s/(rw|defaults|seclabel|nodev)(,|$)//g;s/,$//") + [ "$previous_mount_opts" ] && previous_mount_opts+="," + # In iso9660 filesystems mtab could describe a "blocksize" value, this should be reflected in + # fstab as "block". The next variable is to satisfy shellcheck SC2050. + fs_type="" + if [ "$fs_type" == "iso9660" ] ; then + previous_mount_opts=$(sed 's/blocksize=/block=/' <<< "$previous_mount_opts") + fi + echo " /var/log/audit defaults,${previous_mount_opts}nodev 0 0" >> /etc/fstab + # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it + elif ! grep "$mount_point_match_regexp" /etc/fstab | grep -q "nodev"; then + previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}') + sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,nodev|" /etc/fstab + fi + + + if mkdir -p "/var/log/audit"; then + if mountpoint -q "/var/log/audit"; then + mount -o remount --target "/var/log/audit" + fi + fi +} + +perform_remediation + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002064 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_var_log_audit_nodev + - no_reboot_needed + +- name: 'Add nodev Option to /var/log/audit: Check information associated to mountpoint' + command: findmnt --fstab '/var/log/audit' + register: device_name + failed_when: device_name.rc > 1 + changed_when: false + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/var/log/audit" in ansible_mounts | map(attribute="mount") | list' + tags: + - DISA-STIG-OL09-00-002064 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_var_log_audit_nodev + - no_reboot_needed + +- name: 'Add nodev Option to /var/log/audit: Create mount_info dictionary variable' + set_fact: + mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' + with_together: + - '{{ device_name.stdout_lines[0].split() | list | lower }}' + - '{{ device_name.stdout_lines[1].split() | list }}' + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/var/log/audit" in ansible_mounts | map(attribute="mount") | list' + - device_name.stdout is defined and device_name.stdout_lines is defined + - (device_name.stdout | length > 0) + tags: + - DISA-STIG-OL09-00-002064 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_var_log_audit_nodev + - no_reboot_needed + +- name: 'Add nodev Option to /var/log/audit: If /var/log/audit not mounted, craft + mount_info manually' + set_fact: + mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' + with_together: + - - target + - source + - fstype + - options + - - /var/log/audit + - '' + - '' + - defaults + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/var/log/audit" in ansible_mounts | map(attribute="mount") | list' + - ("--fstab" | length == 0) + - device_name.stdout is defined and device_name.stdout_lines is defined + - (device_name.stdout | length == 0) + tags: + - DISA-STIG-OL09-00-002064 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_var_log_audit_nodev + - no_reboot_needed + +- name: 'Add nodev Option to /var/log/audit: Make sure nodev option is part of the + to /var/log/audit options' + set_fact: + mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',nodev'' + }) }}' + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/var/log/audit" in ansible_mounts | map(attribute="mount") | list' + - mount_info is defined and "nodev" not in mount_info.options + tags: + - DISA-STIG-OL09-00-002064 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_var_log_audit_nodev + - no_reboot_needed + +- name: 'Add nodev Option to /var/log/audit: Ensure /var/log/audit is mounted with + nodev option' + mount: + path: /var/log/audit + src: '{{ mount_info.source }}' + opts: '{{ mount_info.options }}' + state: mounted + fstype: '{{ mount_info.fstype }}' + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/var/log/audit" in ansible_mounts | map(attribute="mount") | list' + - mount_info is defined + - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" + | length == 0) + tags: + - DISA-STIG-OL09-00-002064 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_var_log_audit_nodev + - no_reboot_needed + + +part /var/log/audit --mountoptions="nodev" + + + + + + + + + + Add noexec Option to /var/log/audit + The noexec mount option can be used to prevent binaries +from being executed out of /var/log/audit. +Add the noexec option to the fourth column of +/etc/fstab for the line which controls mounting of +/var/log/audit. + CCI-001764 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 + CM-7(a) + CM-7(b) + CM-6(a) + AC-6 + AC-6(1) + MP-7 + PR.IP-1 + PR.PT-2 + PR.PT-3 + FMT_SMF_EXT.1 + SRG-OS-000368-GPOS-00154 + OL09-00-002065 + SV-271661r1091695_rule + Allowing users to execute binaries from directories containing audit log files +such as /var/log/audit should never be necessary in normal operation and +can expose the system to potential compromise. + + # Remediation is applicable only in certain platforms +if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/var/log/audit" > /dev/null || findmnt --fstab "/var/log/audit" > /dev/null; }; then + +function perform_remediation { + + # the mount point /var/log/audit has to be defined in /etc/fstab + # before this remediation can be executed. In case it is not defined, the + # remediation aborts and no changes regarding the mount point are done. + mount_point_match_regexp="$(printf "^[[:space:]]*[^#].*[[:space:]]%s[[:space:]]" "/var/log/audit")" + + grep "$mount_point_match_regexp" -q /etc/fstab \ + || { echo "The mount point '/var/log/audit' is not even in /etc/fstab, so we can't set up mount options" >&2; + echo "Not remediating, because there is no record of /var/log/audit in /etc/fstab" >&2; return 1; } + + + + mount_point_match_regexp="$(printf "^[[:space:]]*[^#].*[[:space:]]%s[[:space:]]" /var/log/audit)" + + # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab + if ! grep -q "$mount_point_match_regexp" /etc/fstab; then + # runtime opts without some automatic kernel/userspace-added defaults + previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 | awk '{print $4}' \ + | sed -E "s/(rw|defaults|seclabel|noexec)(,|$)//g;s/,$//") + [ "$previous_mount_opts" ] && previous_mount_opts+="," + # In iso9660 filesystems mtab could describe a "blocksize" value, this should be reflected in + # fstab as "block". The next variable is to satisfy shellcheck SC2050. + fs_type="" + if [ "$fs_type" == "iso9660" ] ; then + previous_mount_opts=$(sed 's/blocksize=/block=/' <<< "$previous_mount_opts") + fi + echo " /var/log/audit defaults,${previous_mount_opts}noexec 0 0" >> /etc/fstab + # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it + elif ! grep "$mount_point_match_regexp" /etc/fstab | grep -q "noexec"; then + previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}') + sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,noexec|" /etc/fstab + fi + + + if mkdir -p "/var/log/audit"; then + if mountpoint -q "/var/log/audit"; then + mount -o remount --target "/var/log/audit" + fi + fi +} + +perform_remediation + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002065 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_var_log_audit_noexec + - no_reboot_needed + +- name: 'Add noexec Option to /var/log/audit: Check information associated to mountpoint' + command: findmnt --fstab '/var/log/audit' + register: device_name + failed_when: device_name.rc > 1 + changed_when: false + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/var/log/audit" in ansible_mounts | map(attribute="mount") | list' + tags: + - DISA-STIG-OL09-00-002065 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_var_log_audit_noexec + - no_reboot_needed + +- name: 'Add noexec Option to /var/log/audit: Create mount_info dictionary variable' + set_fact: + mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' + with_together: + - '{{ device_name.stdout_lines[0].split() | list | lower }}' + - '{{ device_name.stdout_lines[1].split() | list }}' + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/var/log/audit" in ansible_mounts | map(attribute="mount") | list' + - device_name.stdout is defined and device_name.stdout_lines is defined + - (device_name.stdout | length > 0) + tags: + - DISA-STIG-OL09-00-002065 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_var_log_audit_noexec + - no_reboot_needed + +- name: 'Add noexec Option to /var/log/audit: If /var/log/audit not mounted, craft + mount_info manually' + set_fact: + mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' + with_together: + - - target + - source + - fstype + - options + - - /var/log/audit + - '' + - '' + - defaults + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/var/log/audit" in ansible_mounts | map(attribute="mount") | list' + - ("--fstab" | length == 0) + - device_name.stdout is defined and device_name.stdout_lines is defined + - (device_name.stdout | length == 0) + tags: + - DISA-STIG-OL09-00-002065 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_var_log_audit_noexec + - no_reboot_needed + +- name: 'Add noexec Option to /var/log/audit: Make sure noexec option is part of the + to /var/log/audit options' + set_fact: + mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',noexec'' + }) }}' + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/var/log/audit" in ansible_mounts | map(attribute="mount") | list' + - mount_info is defined and "noexec" not in mount_info.options + tags: + - DISA-STIG-OL09-00-002065 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_var_log_audit_noexec + - no_reboot_needed + +- name: 'Add noexec Option to /var/log/audit: Ensure /var/log/audit is mounted with + noexec option' + mount: + path: /var/log/audit + src: '{{ mount_info.source }}' + opts: '{{ mount_info.options }}' + state: mounted + fstype: '{{ mount_info.fstype }}' + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/var/log/audit" in ansible_mounts | map(attribute="mount") | list' + - mount_info is defined + - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" + | length == 0) + tags: + - DISA-STIG-OL09-00-002065 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_var_log_audit_noexec + - no_reboot_needed + + +part /var/log/audit --mountoptions="noexec" + + + + + + + + + + Add nosuid Option to /var/log/audit + The nosuid mount option can be used to prevent +execution of setuid programs in /var/log/audit. The SUID and SGID permissions +should not be required in directories containing audit log files. +Add the nosuid option to the fourth column of +/etc/fstab for the line which controls mounting of +/var/log/audit. + CCI-001764 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 + CM-7(a) + CM-7(b) + CM-6(a) + AC-6 + AC-6(1) + MP-7 + PR.IP-1 + PR.PT-2 + PR.PT-3 + FMT_SMF_EXT.1 + SRG-OS-000368-GPOS-00154 + OL09-00-002066 + SV-271662r1091698_rule + The presence of SUID and SGID executables should be tightly controlled. Users +should not be able to execute SUID or SGID binaries from partitions +designated for audit log files. + + # Remediation is applicable only in certain platforms +if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/var/log/audit" > /dev/null || findmnt --fstab "/var/log/audit" > /dev/null; }; then + +function perform_remediation { + + # the mount point /var/log/audit has to be defined in /etc/fstab + # before this remediation can be executed. In case it is not defined, the + # remediation aborts and no changes regarding the mount point are done. + mount_point_match_regexp="$(printf "^[[:space:]]*[^#].*[[:space:]]%s[[:space:]]" "/var/log/audit")" + + grep "$mount_point_match_regexp" -q /etc/fstab \ + || { echo "The mount point '/var/log/audit' is not even in /etc/fstab, so we can't set up mount options" >&2; + echo "Not remediating, because there is no record of /var/log/audit in /etc/fstab" >&2; return 1; } + + + + mount_point_match_regexp="$(printf "^[[:space:]]*[^#].*[[:space:]]%s[[:space:]]" /var/log/audit)" + + # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab + if ! grep -q "$mount_point_match_regexp" /etc/fstab; then + # runtime opts without some automatic kernel/userspace-added defaults + previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 | awk '{print $4}' \ + | sed -E "s/(rw|defaults|seclabel|nosuid)(,|$)//g;s/,$//") + [ "$previous_mount_opts" ] && previous_mount_opts+="," + # In iso9660 filesystems mtab could describe a "blocksize" value, this should be reflected in + # fstab as "block". The next variable is to satisfy shellcheck SC2050. + fs_type="" + if [ "$fs_type" == "iso9660" ] ; then + previous_mount_opts=$(sed 's/blocksize=/block=/' <<< "$previous_mount_opts") + fi + echo " /var/log/audit defaults,${previous_mount_opts}nosuid 0 0" >> /etc/fstab + # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it + elif ! grep "$mount_point_match_regexp" /etc/fstab | grep -q "nosuid"; then + previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}') + sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,nosuid|" /etc/fstab + fi + + + if mkdir -p "/var/log/audit"; then + if mountpoint -q "/var/log/audit"; then + mount -o remount --target "/var/log/audit" + fi + fi +} + +perform_remediation + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002066 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_var_log_audit_nosuid + - no_reboot_needed + +- name: 'Add nosuid Option to /var/log/audit: Check information associated to mountpoint' + command: findmnt --fstab '/var/log/audit' + register: device_name + failed_when: device_name.rc > 1 + changed_when: false + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/var/log/audit" in ansible_mounts | map(attribute="mount") | list' + tags: + - DISA-STIG-OL09-00-002066 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_var_log_audit_nosuid + - no_reboot_needed + +- name: 'Add nosuid Option to /var/log/audit: Create mount_info dictionary variable' + set_fact: + mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' + with_together: + - '{{ device_name.stdout_lines[0].split() | list | lower }}' + - '{{ device_name.stdout_lines[1].split() | list }}' + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/var/log/audit" in ansible_mounts | map(attribute="mount") | list' + - device_name.stdout is defined and device_name.stdout_lines is defined + - (device_name.stdout | length > 0) + tags: + - DISA-STIG-OL09-00-002066 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_var_log_audit_nosuid + - no_reboot_needed + +- name: 'Add nosuid Option to /var/log/audit: If /var/log/audit not mounted, craft + mount_info manually' + set_fact: + mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' + with_together: + - - target + - source + - fstype + - options + - - /var/log/audit + - '' + - '' + - defaults + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/var/log/audit" in ansible_mounts | map(attribute="mount") | list' + - ("--fstab" | length == 0) + - device_name.stdout is defined and device_name.stdout_lines is defined + - (device_name.stdout | length == 0) + tags: + - DISA-STIG-OL09-00-002066 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_var_log_audit_nosuid + - no_reboot_needed + +- name: 'Add nosuid Option to /var/log/audit: Make sure nosuid option is part of the + to /var/log/audit options' + set_fact: + mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',nosuid'' + }) }}' + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/var/log/audit" in ansible_mounts | map(attribute="mount") | list' + - mount_info is defined and "nosuid" not in mount_info.options + tags: + - DISA-STIG-OL09-00-002066 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_var_log_audit_nosuid + - no_reboot_needed + +- name: 'Add nosuid Option to /var/log/audit: Ensure /var/log/audit is mounted with + nosuid option' + mount: + path: /var/log/audit + src: '{{ mount_info.source }}' + opts: '{{ mount_info.options }}' + state: mounted + fstype: '{{ mount_info.fstype }}' + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/var/log/audit" in ansible_mounts | map(attribute="mount") | list' + - mount_info is defined + - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" + | length == 0) + tags: + - DISA-STIG-OL09-00-002066 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_var_log_audit_nosuid + - no_reboot_needed + + +part /var/log/audit --mountoptions="nosuid" + + + + + + + + + + Add nodev Option to /var/log + The nodev mount option can be used to prevent device files from +being created in /var/log. +Legitimate character and block devices should exist only in +the /dev directory on the root partition or within chroot +jails built for system services. +Add the nodev option to the fourth column of +/etc/fstab for the line which controls mounting of +/var/log. + CCI-001764 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 + CM-7(a) + CM-7(b) + CM-6(a) + AC-6 + AC-6(1) + MP-7 + PR.IP-1 + PR.PT-2 + PR.PT-3 + SRG-OS-000368-GPOS-00154 + OL09-00-002061 + SV-271657r1091683_rule + The only legitimate location for device files is the /dev directory +located on the root partition. The only exception to this is chroot jails. + + # Remediation is applicable only in certain platforms +if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/var/log" > /dev/null || findmnt --fstab "/var/log" > /dev/null; }; then + +function perform_remediation { + + # the mount point /var/log has to be defined in /etc/fstab + # before this remediation can be executed. In case it is not defined, the + # remediation aborts and no changes regarding the mount point are done. + mount_point_match_regexp="$(printf "^[[:space:]]*[^#].*[[:space:]]%s[[:space:]]" "/var/log")" + + grep "$mount_point_match_regexp" -q /etc/fstab \ + || { echo "The mount point '/var/log' is not even in /etc/fstab, so we can't set up mount options" >&2; + echo "Not remediating, because there is no record of /var/log in /etc/fstab" >&2; return 1; } + + + + mount_point_match_regexp="$(printf "^[[:space:]]*[^#].*[[:space:]]%s[[:space:]]" /var/log)" + + # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab + if ! grep -q "$mount_point_match_regexp" /etc/fstab; then + # runtime opts without some automatic kernel/userspace-added defaults + previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 | awk '{print $4}' \ + | sed -E "s/(rw|defaults|seclabel|nodev)(,|$)//g;s/,$//") + [ "$previous_mount_opts" ] && previous_mount_opts+="," + # In iso9660 filesystems mtab could describe a "blocksize" value, this should be reflected in + # fstab as "block". The next variable is to satisfy shellcheck SC2050. + fs_type="" + if [ "$fs_type" == "iso9660" ] ; then + previous_mount_opts=$(sed 's/blocksize=/block=/' <<< "$previous_mount_opts") + fi + echo " /var/log defaults,${previous_mount_opts}nodev 0 0" >> /etc/fstab + # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it + elif ! grep "$mount_point_match_regexp" /etc/fstab | grep -q "nodev"; then + previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}') + sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,nodev|" /etc/fstab + fi + + + if mkdir -p "/var/log"; then + if mountpoint -q "/var/log"; then + mount -o remount --target "/var/log" + fi + fi +} + +perform_remediation + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002061 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_var_log_nodev + - no_reboot_needed + +- name: 'Add nodev Option to /var/log: Check information associated to mountpoint' + command: findmnt --fstab '/var/log' + register: device_name + failed_when: device_name.rc > 1 + changed_when: false + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/var/log" in ansible_mounts | map(attribute="mount") | list' + tags: + - DISA-STIG-OL09-00-002061 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_var_log_nodev + - no_reboot_needed + +- name: 'Add nodev Option to /var/log: Create mount_info dictionary variable' + set_fact: + mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' + with_together: + - '{{ device_name.stdout_lines[0].split() | list | lower }}' + - '{{ device_name.stdout_lines[1].split() | list }}' + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/var/log" in ansible_mounts | map(attribute="mount") | list' + - device_name.stdout is defined and device_name.stdout_lines is defined + - (device_name.stdout | length > 0) + tags: + - DISA-STIG-OL09-00-002061 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_var_log_nodev + - no_reboot_needed + +- name: 'Add nodev Option to /var/log: If /var/log not mounted, craft mount_info manually' + set_fact: + mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' + with_together: + - - target + - source + - fstype + - options + - - /var/log + - '' + - '' + - defaults + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/var/log" in ansible_mounts | map(attribute="mount") | list' + - ("--fstab" | length == 0) + - device_name.stdout is defined and device_name.stdout_lines is defined + - (device_name.stdout | length == 0) + tags: + - DISA-STIG-OL09-00-002061 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_var_log_nodev + - no_reboot_needed + +- name: 'Add nodev Option to /var/log: Make sure nodev option is part of the to /var/log + options' + set_fact: + mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',nodev'' + }) }}' + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/var/log" in ansible_mounts | map(attribute="mount") | list' + - mount_info is defined and "nodev" not in mount_info.options + tags: + - DISA-STIG-OL09-00-002061 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_var_log_nodev + - no_reboot_needed + +- name: 'Add nodev Option to /var/log: Ensure /var/log is mounted with nodev option' + mount: + path: /var/log + src: '{{ mount_info.source }}' + opts: '{{ mount_info.options }}' + state: mounted + fstype: '{{ mount_info.fstype }}' + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/var/log" in ansible_mounts | map(attribute="mount") | list' + - mount_info is defined + - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" + | length == 0) + tags: + - DISA-STIG-OL09-00-002061 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_var_log_nodev + - no_reboot_needed + + +part /var/log --mountoptions="nodev" + + + + + + + + + + Add noexec Option to /var/log + The noexec mount option can be used to prevent binaries +from being executed out of /var/log. +Add the noexec option to the fourth column of +/etc/fstab for the line which controls mounting of +/var/log. + CCI-001764 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 + CM-7(a) + CM-7(b) + CM-6(a) + AC-6 + AC-6(1) + MP-7 + PR.IP-1 + PR.PT-2 + PR.PT-3 + SRG-OS-000368-GPOS-00154 + R28 + OL09-00-002062 + SV-271658r1091686_rule + Allowing users to execute binaries from directories containing log files +such as /var/log should never be necessary in normal operation and +can expose the system to potential compromise. + + # Remediation is applicable only in certain platforms +if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/var/log" > /dev/null || findmnt --fstab "/var/log" > /dev/null; }; then + +function perform_remediation { + + # the mount point /var/log has to be defined in /etc/fstab + # before this remediation can be executed. In case it is not defined, the + # remediation aborts and no changes regarding the mount point are done. + mount_point_match_regexp="$(printf "^[[:space:]]*[^#].*[[:space:]]%s[[:space:]]" "/var/log")" + + grep "$mount_point_match_regexp" -q /etc/fstab \ + || { echo "The mount point '/var/log' is not even in /etc/fstab, so we can't set up mount options" >&2; + echo "Not remediating, because there is no record of /var/log in /etc/fstab" >&2; return 1; } + + + + mount_point_match_regexp="$(printf "^[[:space:]]*[^#].*[[:space:]]%s[[:space:]]" /var/log)" + + # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab + if ! grep -q "$mount_point_match_regexp" /etc/fstab; then + # runtime opts without some automatic kernel/userspace-added defaults + previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 | awk '{print $4}' \ + | sed -E "s/(rw|defaults|seclabel|noexec)(,|$)//g;s/,$//") + [ "$previous_mount_opts" ] && previous_mount_opts+="," + # In iso9660 filesystems mtab could describe a "blocksize" value, this should be reflected in + # fstab as "block". The next variable is to satisfy shellcheck SC2050. + fs_type="" + if [ "$fs_type" == "iso9660" ] ; then + previous_mount_opts=$(sed 's/blocksize=/block=/' <<< "$previous_mount_opts") + fi + echo " /var/log defaults,${previous_mount_opts}noexec 0 0" >> /etc/fstab + # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it + elif ! grep "$mount_point_match_regexp" /etc/fstab | grep -q "noexec"; then + previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}') + sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,noexec|" /etc/fstab + fi + + + if mkdir -p "/var/log"; then + if mountpoint -q "/var/log"; then + mount -o remount --target "/var/log" + fi + fi +} + +perform_remediation + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002062 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_var_log_noexec + - no_reboot_needed + +- name: 'Add noexec Option to /var/log: Check information associated to mountpoint' + command: findmnt --fstab '/var/log' + register: device_name + failed_when: device_name.rc > 1 + changed_when: false + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/var/log" in ansible_mounts | map(attribute="mount") | list' + tags: + - DISA-STIG-OL09-00-002062 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_var_log_noexec + - no_reboot_needed + +- name: 'Add noexec Option to /var/log: Create mount_info dictionary variable' + set_fact: + mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' + with_together: + - '{{ device_name.stdout_lines[0].split() | list | lower }}' + - '{{ device_name.stdout_lines[1].split() | list }}' + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/var/log" in ansible_mounts | map(attribute="mount") | list' + - device_name.stdout is defined and device_name.stdout_lines is defined + - (device_name.stdout | length > 0) + tags: + - DISA-STIG-OL09-00-002062 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_var_log_noexec + - no_reboot_needed + +- name: 'Add noexec Option to /var/log: If /var/log not mounted, craft mount_info + manually' + set_fact: + mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' + with_together: + - - target + - source + - fstype + - options + - - /var/log + - '' + - '' + - defaults + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/var/log" in ansible_mounts | map(attribute="mount") | list' + - ("--fstab" | length == 0) + - device_name.stdout is defined and device_name.stdout_lines is defined + - (device_name.stdout | length == 0) + tags: + - DISA-STIG-OL09-00-002062 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_var_log_noexec + - no_reboot_needed + +- name: 'Add noexec Option to /var/log: Make sure noexec option is part of the to + /var/log options' + set_fact: + mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',noexec'' + }) }}' + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/var/log" in ansible_mounts | map(attribute="mount") | list' + - mount_info is defined and "noexec" not in mount_info.options + tags: + - DISA-STIG-OL09-00-002062 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_var_log_noexec + - no_reboot_needed + +- name: 'Add noexec Option to /var/log: Ensure /var/log is mounted with noexec option' + mount: + path: /var/log + src: '{{ mount_info.source }}' + opts: '{{ mount_info.options }}' + state: mounted + fstype: '{{ mount_info.fstype }}' + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/var/log" in ansible_mounts | map(attribute="mount") | list' + - mount_info is defined + - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" + | length == 0) + tags: + - DISA-STIG-OL09-00-002062 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_var_log_noexec + - no_reboot_needed + + +part /var/log --mountoptions="noexec" + + + + + + + + + + Add nosuid Option to /var/log + The nosuid mount option can be used to prevent +execution of setuid programs in /var/log. The SUID and SGID permissions +should not be required in directories containing log files. +Add the nosuid option to the fourth column of +/etc/fstab for the line which controls mounting of +/var/log. + CCI-001764 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 + CM-7(a) + CM-7(b) + CM-6(a) + AC-6 + AC-6(1) + MP-7 + PR.IP-1 + PR.PT-2 + PR.PT-3 + SRG-OS-000368-GPOS-00154 + R28 + OL09-00-002063 + SV-271659r1091689_rule + The presence of SUID and SGID executables should be tightly controlled. Users +should not be able to execute SUID or SGID binaries from partitions +designated for log files. + + # Remediation is applicable only in certain platforms +if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/var/log" > /dev/null || findmnt --fstab "/var/log" > /dev/null; }; then + +function perform_remediation { + + # the mount point /var/log has to be defined in /etc/fstab + # before this remediation can be executed. In case it is not defined, the + # remediation aborts and no changes regarding the mount point are done. + mount_point_match_regexp="$(printf "^[[:space:]]*[^#].*[[:space:]]%s[[:space:]]" "/var/log")" + + grep "$mount_point_match_regexp" -q /etc/fstab \ + || { echo "The mount point '/var/log' is not even in /etc/fstab, so we can't set up mount options" >&2; + echo "Not remediating, because there is no record of /var/log in /etc/fstab" >&2; return 1; } + + + + mount_point_match_regexp="$(printf "^[[:space:]]*[^#].*[[:space:]]%s[[:space:]]" /var/log)" + + # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab + if ! grep -q "$mount_point_match_regexp" /etc/fstab; then + # runtime opts without some automatic kernel/userspace-added defaults + previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 | awk '{print $4}' \ + | sed -E "s/(rw|defaults|seclabel|nosuid)(,|$)//g;s/,$//") + [ "$previous_mount_opts" ] && previous_mount_opts+="," + # In iso9660 filesystems mtab could describe a "blocksize" value, this should be reflected in + # fstab as "block". The next variable is to satisfy shellcheck SC2050. + fs_type="" + if [ "$fs_type" == "iso9660" ] ; then + previous_mount_opts=$(sed 's/blocksize=/block=/' <<< "$previous_mount_opts") + fi + echo " /var/log defaults,${previous_mount_opts}nosuid 0 0" >> /etc/fstab + # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it + elif ! grep "$mount_point_match_regexp" /etc/fstab | grep -q "nosuid"; then + previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}') + sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,nosuid|" /etc/fstab + fi + + + if mkdir -p "/var/log"; then + if mountpoint -q "/var/log"; then + mount -o remount --target "/var/log" + fi + fi +} + +perform_remediation + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002063 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_var_log_nosuid + - no_reboot_needed + +- name: 'Add nosuid Option to /var/log: Check information associated to mountpoint' + command: findmnt --fstab '/var/log' + register: device_name + failed_when: device_name.rc > 1 + changed_when: false + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/var/log" in ansible_mounts | map(attribute="mount") | list' + tags: + - DISA-STIG-OL09-00-002063 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_var_log_nosuid + - no_reboot_needed + +- name: 'Add nosuid Option to /var/log: Create mount_info dictionary variable' + set_fact: + mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' + with_together: + - '{{ device_name.stdout_lines[0].split() | list | lower }}' + - '{{ device_name.stdout_lines[1].split() | list }}' + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/var/log" in ansible_mounts | map(attribute="mount") | list' + - device_name.stdout is defined and device_name.stdout_lines is defined + - (device_name.stdout | length > 0) + tags: + - DISA-STIG-OL09-00-002063 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_var_log_nosuid + - no_reboot_needed + +- name: 'Add nosuid Option to /var/log: If /var/log not mounted, craft mount_info + manually' + set_fact: + mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' + with_together: + - - target + - source + - fstype + - options + - - /var/log + - '' + - '' + - defaults + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/var/log" in ansible_mounts | map(attribute="mount") | list' + - ("--fstab" | length == 0) + - device_name.stdout is defined and device_name.stdout_lines is defined + - (device_name.stdout | length == 0) + tags: + - DISA-STIG-OL09-00-002063 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_var_log_nosuid + - no_reboot_needed + +- name: 'Add nosuid Option to /var/log: Make sure nosuid option is part of the to + /var/log options' + set_fact: + mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',nosuid'' + }) }}' + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/var/log" in ansible_mounts | map(attribute="mount") | list' + - mount_info is defined and "nosuid" not in mount_info.options + tags: + - DISA-STIG-OL09-00-002063 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_var_log_nosuid + - no_reboot_needed + +- name: 'Add nosuid Option to /var/log: Ensure /var/log is mounted with nosuid option' + mount: + path: /var/log + src: '{{ mount_info.source }}' + opts: '{{ mount_info.options }}' + state: mounted + fstype: '{{ mount_info.fstype }}' + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/var/log" in ansible_mounts | map(attribute="mount") | list' + - mount_info is defined + - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" + | length == 0) + tags: + - DISA-STIG-OL09-00-002063 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_var_log_nosuid + - no_reboot_needed + + +part /var/log --mountoptions="nosuid" + + + + + + + + + + Add nodev Option to /var + The nodev mount option can be used to prevent device files from +being created in /var. +Legitimate character and block devices should exist only in +the /dev directory on the root partition or within chroot +jails built for system services. +Add the nodev option to the fourth column of +/etc/fstab for the line which controls mounting of +/var. + CCI-001764 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 + CM-7(a) + CM-7(b) + CM-6(a) + AC-6 + AC-6(1) + MP-7 + PR.IP-1 + PR.PT-2 + PR.PT-3 + SRG-OS-000368-GPOS-00154 + OL09-00-002060 + SV-271656r1091680_rule + The only legitimate location for device files is the /dev directory +located on the root partition. The only exception to this is chroot jails. + + # Remediation is applicable only in certain platforms +if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/var" > /dev/null || findmnt --fstab "/var" > /dev/null; }; then + +function perform_remediation { + + # the mount point /var has to be defined in /etc/fstab + # before this remediation can be executed. In case it is not defined, the + # remediation aborts and no changes regarding the mount point are done. + mount_point_match_regexp="$(printf "^[[:space:]]*[^#].*[[:space:]]%s[[:space:]]" "/var")" + + grep "$mount_point_match_regexp" -q /etc/fstab \ + || { echo "The mount point '/var' is not even in /etc/fstab, so we can't set up mount options" >&2; + echo "Not remediating, because there is no record of /var in /etc/fstab" >&2; return 1; } + + + + mount_point_match_regexp="$(printf "^[[:space:]]*[^#].*[[:space:]]%s[[:space:]]" /var)" + + # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab + if ! grep -q "$mount_point_match_regexp" /etc/fstab; then + # runtime opts without some automatic kernel/userspace-added defaults + previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 | awk '{print $4}' \ + | sed -E "s/(rw|defaults|seclabel|nodev)(,|$)//g;s/,$//") + [ "$previous_mount_opts" ] && previous_mount_opts+="," + # In iso9660 filesystems mtab could describe a "blocksize" value, this should be reflected in + # fstab as "block". The next variable is to satisfy shellcheck SC2050. + fs_type="" + if [ "$fs_type" == "iso9660" ] ; then + previous_mount_opts=$(sed 's/blocksize=/block=/' <<< "$previous_mount_opts") + fi + echo " /var defaults,${previous_mount_opts}nodev 0 0" >> /etc/fstab + # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it + elif ! grep "$mount_point_match_regexp" /etc/fstab | grep -q "nodev"; then + previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}') + sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,nodev|" /etc/fstab + fi + + + if mkdir -p "/var"; then + if mountpoint -q "/var"; then + mount -o remount --target "/var" + fi + fi +} + +perform_remediation + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002060 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_var_nodev + - no_reboot_needed + +- name: 'Add nodev Option to /var: Check information associated to mountpoint' + command: findmnt --fstab '/var' + register: device_name + failed_when: device_name.rc > 1 + changed_when: false + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/var" in ansible_mounts | map(attribute="mount") | list' + tags: + - DISA-STIG-OL09-00-002060 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_var_nodev + - no_reboot_needed + +- name: 'Add nodev Option to /var: Create mount_info dictionary variable' + set_fact: + mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' + with_together: + - '{{ device_name.stdout_lines[0].split() | list | lower }}' + - '{{ device_name.stdout_lines[1].split() | list }}' + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/var" in ansible_mounts | map(attribute="mount") | list' + - device_name.stdout is defined and device_name.stdout_lines is defined + - (device_name.stdout | length > 0) + tags: + - DISA-STIG-OL09-00-002060 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_var_nodev + - no_reboot_needed + +- name: 'Add nodev Option to /var: If /var not mounted, craft mount_info manually' + set_fact: + mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' + with_together: + - - target + - source + - fstype + - options + - - /var + - '' + - '' + - defaults + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/var" in ansible_mounts | map(attribute="mount") | list' + - ("--fstab" | length == 0) + - device_name.stdout is defined and device_name.stdout_lines is defined + - (device_name.stdout | length == 0) + tags: + - DISA-STIG-OL09-00-002060 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_var_nodev + - no_reboot_needed + +- name: 'Add nodev Option to /var: Make sure nodev option is part of the to /var options' + set_fact: + mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',nodev'' + }) }}' + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/var" in ansible_mounts | map(attribute="mount") | list' + - mount_info is defined and "nodev" not in mount_info.options + tags: + - DISA-STIG-OL09-00-002060 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_var_nodev + - no_reboot_needed + +- name: 'Add nodev Option to /var: Ensure /var is mounted with nodev option' + mount: + path: /var + src: '{{ mount_info.source }}' + opts: '{{ mount_info.options }}' + state: mounted + fstype: '{{ mount_info.fstype }}' + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/var" in ansible_mounts | map(attribute="mount") | list' + - mount_info is defined + - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" + | length == 0) + tags: + - DISA-STIG-OL09-00-002060 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_var_nodev + - no_reboot_needed + + +part /var --mountoptions="nodev" + + + + + + + + + + Add noexec Option to /var + The noexec mount option can be used to prevent binaries from being +executed out of /var. +Add the noexec option to the fourth column of +/etc/fstab for the line which controls mounting of +/var. + R28 + The /var directory contains variable system data such as logs, +mails and caches. No binaries should be executed from this directory. + + # Remediation is applicable only in certain platforms +if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/var" > /dev/null || findmnt --fstab "/var" > /dev/null; }; then + +function perform_remediation { + + # the mount point /var has to be defined in /etc/fstab + # before this remediation can be executed. In case it is not defined, the + # remediation aborts and no changes regarding the mount point are done. + mount_point_match_regexp="$(printf "^[[:space:]]*[^#].*[[:space:]]%s[[:space:]]" "/var")" + + grep "$mount_point_match_regexp" -q /etc/fstab \ + || { echo "The mount point '/var' is not even in /etc/fstab, so we can't set up mount options" >&2; + echo "Not remediating, because there is no record of /var in /etc/fstab" >&2; return 1; } + + + + mount_point_match_regexp="$(printf "^[[:space:]]*[^#].*[[:space:]]%s[[:space:]]" /var)" + + # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab + if ! grep -q "$mount_point_match_regexp" /etc/fstab; then + # runtime opts without some automatic kernel/userspace-added defaults + previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 | awk '{print $4}' \ + | sed -E "s/(rw|defaults|seclabel|noexec)(,|$)//g;s/,$//") + [ "$previous_mount_opts" ] && previous_mount_opts+="," + # In iso9660 filesystems mtab could describe a "blocksize" value, this should be reflected in + # fstab as "block". The next variable is to satisfy shellcheck SC2050. + fs_type="" + if [ "$fs_type" == "iso9660" ] ; then + previous_mount_opts=$(sed 's/blocksize=/block=/' <<< "$previous_mount_opts") + fi + echo " /var defaults,${previous_mount_opts}noexec 0 0" >> /etc/fstab + # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it + elif ! grep "$mount_point_match_regexp" /etc/fstab | grep -q "noexec"; then + previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}') + sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,noexec|" /etc/fstab + fi + + + if mkdir -p "/var"; then + if mountpoint -q "/var"; then + mount -o remount --target "/var" + fi + fi +} + +perform_remediation + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_var_noexec + - no_reboot_needed + +- name: 'Add noexec Option to /var: Check information associated to mountpoint' + command: findmnt --fstab '/var' + register: device_name + failed_when: device_name.rc > 1 + changed_when: false + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/var" in ansible_mounts | map(attribute="mount") | list' + tags: + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_var_noexec + - no_reboot_needed + +- name: 'Add noexec Option to /var: Create mount_info dictionary variable' + set_fact: + mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' + with_together: + - '{{ device_name.stdout_lines[0].split() | list | lower }}' + - '{{ device_name.stdout_lines[1].split() | list }}' + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/var" in ansible_mounts | map(attribute="mount") | list' + - device_name.stdout is defined and device_name.stdout_lines is defined + - (device_name.stdout | length > 0) + tags: + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_var_noexec + - no_reboot_needed + +- name: 'Add noexec Option to /var: If /var not mounted, craft mount_info manually' + set_fact: + mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' + with_together: + - - target + - source + - fstype + - options + - - /var + - '' + - '' + - defaults + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/var" in ansible_mounts | map(attribute="mount") | list' + - ("--fstab" | length == 0) + - device_name.stdout is defined and device_name.stdout_lines is defined + - (device_name.stdout | length == 0) + tags: + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_var_noexec + - no_reboot_needed + +- name: 'Add noexec Option to /var: Make sure noexec option is part of the to /var + options' + set_fact: + mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',noexec'' + }) }}' + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/var" in ansible_mounts | map(attribute="mount") | list' + - mount_info is defined and "noexec" not in mount_info.options + tags: + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_var_noexec + - no_reboot_needed + +- name: 'Add noexec Option to /var: Ensure /var is mounted with noexec option' + mount: + path: /var + src: '{{ mount_info.source }}' + opts: '{{ mount_info.options }}' + state: mounted + fstype: '{{ mount_info.fstype }}' + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/var" in ansible_mounts | map(attribute="mount") | list' + - mount_info is defined + - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" + | length == 0) + tags: + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_var_noexec + - no_reboot_needed + + +part /var --mountoptions="noexec" + + + + + + + + + + Add nosuid Option to /var + The nosuid mount option can be used to prevent +execution of setuid programs in /var. The SUID and SGID permissions +should not be required for this directory. +Add the nosuid option to the fourth column of +/etc/fstab for the line which controls mounting of +/var. + R28 + The presence of SUID and SGID executables should be tightly controlled. + + # Remediation is applicable only in certain platforms +if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/var" > /dev/null || findmnt --fstab "/var" > /dev/null; }; then + +function perform_remediation { + + # the mount point /var has to be defined in /etc/fstab + # before this remediation can be executed. In case it is not defined, the + # remediation aborts and no changes regarding the mount point are done. + mount_point_match_regexp="$(printf "^[[:space:]]*[^#].*[[:space:]]%s[[:space:]]" "/var")" + + grep "$mount_point_match_regexp" -q /etc/fstab \ + || { echo "The mount point '/var' is not even in /etc/fstab, so we can't set up mount options" >&2; + echo "Not remediating, because there is no record of /var in /etc/fstab" >&2; return 1; } + + + + mount_point_match_regexp="$(printf "^[[:space:]]*[^#].*[[:space:]]%s[[:space:]]" /var)" + + # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab + if ! grep -q "$mount_point_match_regexp" /etc/fstab; then + # runtime opts without some automatic kernel/userspace-added defaults + previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 | awk '{print $4}' \ + | sed -E "s/(rw|defaults|seclabel|nosuid)(,|$)//g;s/,$//") + [ "$previous_mount_opts" ] && previous_mount_opts+="," + # In iso9660 filesystems mtab could describe a "blocksize" value, this should be reflected in + # fstab as "block". The next variable is to satisfy shellcheck SC2050. + fs_type="" + if [ "$fs_type" == "iso9660" ] ; then + previous_mount_opts=$(sed 's/blocksize=/block=/' <<< "$previous_mount_opts") + fi + echo " /var defaults,${previous_mount_opts}nosuid 0 0" >> /etc/fstab + # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it + elif ! grep "$mount_point_match_regexp" /etc/fstab | grep -q "nosuid"; then + previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}') + sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,nosuid|" /etc/fstab + fi + + + if mkdir -p "/var"; then + if mountpoint -q "/var"; then + mount -o remount --target "/var" + fi + fi +} + +perform_remediation + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_var_nosuid + - no_reboot_needed + +- name: 'Add nosuid Option to /var: Check information associated to mountpoint' + command: findmnt --fstab '/var' + register: device_name + failed_when: device_name.rc > 1 + changed_when: false + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/var" in ansible_mounts | map(attribute="mount") | list' + tags: + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_var_nosuid + - no_reboot_needed + +- name: 'Add nosuid Option to /var: Create mount_info dictionary variable' + set_fact: + mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' + with_together: + - '{{ device_name.stdout_lines[0].split() | list | lower }}' + - '{{ device_name.stdout_lines[1].split() | list }}' + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/var" in ansible_mounts | map(attribute="mount") | list' + - device_name.stdout is defined and device_name.stdout_lines is defined + - (device_name.stdout | length > 0) + tags: + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_var_nosuid + - no_reboot_needed + +- name: 'Add nosuid Option to /var: If /var not mounted, craft mount_info manually' + set_fact: + mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' + with_together: + - - target + - source + - fstype + - options + - - /var + - '' + - '' + - defaults + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/var" in ansible_mounts | map(attribute="mount") | list' + - ("--fstab" | length == 0) + - device_name.stdout is defined and device_name.stdout_lines is defined + - (device_name.stdout | length == 0) + tags: + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_var_nosuid + - no_reboot_needed + +- name: 'Add nosuid Option to /var: Make sure nosuid option is part of the to /var + options' + set_fact: + mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',nosuid'' + }) }}' + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/var" in ansible_mounts | map(attribute="mount") | list' + - mount_info is defined and "nosuid" not in mount_info.options + tags: + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_var_nosuid + - no_reboot_needed + +- name: 'Add nosuid Option to /var: Ensure /var is mounted with nosuid option' + mount: + path: /var + src: '{{ mount_info.source }}' + opts: '{{ mount_info.options }}' + state: mounted + fstype: '{{ mount_info.fstype }}' + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/var" in ansible_mounts | map(attribute="mount") | list' + - mount_info is defined + - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" + | length == 0) + tags: + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_var_nosuid + - no_reboot_needed + + +part /var --mountoptions="nosuid" + + + + + + + + + + Add nodev Option to /var/tmp + The nodev mount option can be used to prevent device files from +being created in /var/tmp. Legitimate character and block devices +should not exist within temporary directories like /var/tmp. +Add the nodev option to the fourth column of +/etc/fstab for the line which controls mounting of +/var/tmp. + CCI-001764 + SRG-OS-000368-GPOS-00154 + OL09-00-002067 + SV-271663r1091701_rule + The only legitimate location for device files is the /dev directory +located on the root partition. The only exception to this is chroot jails. + + # Remediation is applicable only in certain platforms +if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/var/tmp" > /dev/null || findmnt --fstab "/var/tmp" > /dev/null; }; then + +function perform_remediation { + + # the mount point /var/tmp has to be defined in /etc/fstab + # before this remediation can be executed. In case it is not defined, the + # remediation aborts and no changes regarding the mount point are done. + mount_point_match_regexp="$(printf "^[[:space:]]*[^#].*[[:space:]]%s[[:space:]]" "/var/tmp")" + + grep "$mount_point_match_regexp" -q /etc/fstab \ + || { echo "The mount point '/var/tmp' is not even in /etc/fstab, so we can't set up mount options" >&2; + echo "Not remediating, because there is no record of /var/tmp in /etc/fstab" >&2; return 1; } + + + + mount_point_match_regexp="$(printf "^[[:space:]]*[^#].*[[:space:]]%s[[:space:]]" /var/tmp)" + + # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab + if ! grep -q "$mount_point_match_regexp" /etc/fstab; then + # runtime opts without some automatic kernel/userspace-added defaults + previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 | awk '{print $4}' \ + | sed -E "s/(rw|defaults|seclabel|nodev)(,|$)//g;s/,$//") + [ "$previous_mount_opts" ] && previous_mount_opts+="," + # In iso9660 filesystems mtab could describe a "blocksize" value, this should be reflected in + # fstab as "block". The next variable is to satisfy shellcheck SC2050. + fs_type="" + if [ "$fs_type" == "iso9660" ] ; then + previous_mount_opts=$(sed 's/blocksize=/block=/' <<< "$previous_mount_opts") + fi + echo " /var/tmp defaults,${previous_mount_opts}nodev 0 0" >> /etc/fstab + # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it + elif ! grep "$mount_point_match_regexp" /etc/fstab | grep -q "nodev"; then + previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}') + sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,nodev|" /etc/fstab + fi + + + if mkdir -p "/var/tmp"; then + if mountpoint -q "/var/tmp"; then + mount -o remount --target "/var/tmp" + fi + fi +} + +perform_remediation + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002067 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_var_tmp_nodev + - no_reboot_needed + +- name: 'Add nodev Option to /var/tmp: Check information associated to mountpoint' + command: findmnt --fstab '/var/tmp' + register: device_name + failed_when: device_name.rc > 1 + changed_when: false + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/var/tmp" in ansible_mounts | map(attribute="mount") | list' + tags: + - DISA-STIG-OL09-00-002067 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_var_tmp_nodev + - no_reboot_needed + +- name: 'Add nodev Option to /var/tmp: Create mount_info dictionary variable' + set_fact: + mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' + with_together: + - '{{ device_name.stdout_lines[0].split() | list | lower }}' + - '{{ device_name.stdout_lines[1].split() | list }}' + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/var/tmp" in ansible_mounts | map(attribute="mount") | list' + - device_name.stdout is defined and device_name.stdout_lines is defined + - (device_name.stdout | length > 0) + tags: + - DISA-STIG-OL09-00-002067 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_var_tmp_nodev + - no_reboot_needed + +- name: 'Add nodev Option to /var/tmp: If /var/tmp not mounted, craft mount_info manually' + set_fact: + mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' + with_together: + - - target + - source + - fstype + - options + - - /var/tmp + - '' + - '' + - defaults + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/var/tmp" in ansible_mounts | map(attribute="mount") | list' + - ("--fstab" | length == 0) + - device_name.stdout is defined and device_name.stdout_lines is defined + - (device_name.stdout | length == 0) + tags: + - DISA-STIG-OL09-00-002067 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_var_tmp_nodev + - no_reboot_needed + +- name: 'Add nodev Option to /var/tmp: Make sure nodev option is part of the to /var/tmp + options' + set_fact: + mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',nodev'' + }) }}' + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/var/tmp" in ansible_mounts | map(attribute="mount") | list' + - mount_info is defined and "nodev" not in mount_info.options + tags: + - DISA-STIG-OL09-00-002067 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_var_tmp_nodev + - no_reboot_needed + +- name: 'Add nodev Option to /var/tmp: Ensure /var/tmp is mounted with nodev option' + mount: + path: /var/tmp + src: '{{ mount_info.source }}' + opts: '{{ mount_info.options }}' + state: mounted + fstype: '{{ mount_info.fstype }}' + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/var/tmp" in ansible_mounts | map(attribute="mount") | list' + - mount_info is defined + - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" + | length == 0) + tags: + - DISA-STIG-OL09-00-002067 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_var_tmp_nodev + - no_reboot_needed + + +part /var/tmp --mountoptions="nodev" + + + + + + + + + + Add noexec Option to /var/tmp + The noexec mount option can be used to prevent binaries +from being executed out of /var/tmp. +Add the noexec option to the fourth column of +/etc/fstab for the line which controls mounting of +/var/tmp. + CCI-001764 + SRG-OS-000368-GPOS-00154 + R28 + OL09-00-002068 + SV-271664r1091704_rule + Allowing users to execute binaries from world-writable directories +such as /var/tmp should never be necessary in normal operation and +can expose the system to potential compromise. + + # Remediation is applicable only in certain platforms +if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/var/tmp" > /dev/null || findmnt --fstab "/var/tmp" > /dev/null; }; then + +function perform_remediation { + + # the mount point /var/tmp has to be defined in /etc/fstab + # before this remediation can be executed. In case it is not defined, the + # remediation aborts and no changes regarding the mount point are done. + mount_point_match_regexp="$(printf "^[[:space:]]*[^#].*[[:space:]]%s[[:space:]]" "/var/tmp")" + + grep "$mount_point_match_regexp" -q /etc/fstab \ + || { echo "The mount point '/var/tmp' is not even in /etc/fstab, so we can't set up mount options" >&2; + echo "Not remediating, because there is no record of /var/tmp in /etc/fstab" >&2; return 1; } + + + + mount_point_match_regexp="$(printf "^[[:space:]]*[^#].*[[:space:]]%s[[:space:]]" /var/tmp)" + + # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab + if ! grep -q "$mount_point_match_regexp" /etc/fstab; then + # runtime opts without some automatic kernel/userspace-added defaults + previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 | awk '{print $4}' \ + | sed -E "s/(rw|defaults|seclabel|noexec)(,|$)//g;s/,$//") + [ "$previous_mount_opts" ] && previous_mount_opts+="," + # In iso9660 filesystems mtab could describe a "blocksize" value, this should be reflected in + # fstab as "block". The next variable is to satisfy shellcheck SC2050. + fs_type="" + if [ "$fs_type" == "iso9660" ] ; then + previous_mount_opts=$(sed 's/blocksize=/block=/' <<< "$previous_mount_opts") + fi + echo " /var/tmp defaults,${previous_mount_opts}noexec 0 0" >> /etc/fstab + # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it + elif ! grep "$mount_point_match_regexp" /etc/fstab | grep -q "noexec"; then + previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}') + sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,noexec|" /etc/fstab + fi + + + if mkdir -p "/var/tmp"; then + if mountpoint -q "/var/tmp"; then + mount -o remount --target "/var/tmp" + fi + fi +} + +perform_remediation + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002068 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_var_tmp_noexec + - no_reboot_needed + +- name: 'Add noexec Option to /var/tmp: Check information associated to mountpoint' + command: findmnt --fstab '/var/tmp' + register: device_name + failed_when: device_name.rc > 1 + changed_when: false + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/var/tmp" in ansible_mounts | map(attribute="mount") | list' + tags: + - DISA-STIG-OL09-00-002068 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_var_tmp_noexec + - no_reboot_needed + +- name: 'Add noexec Option to /var/tmp: Create mount_info dictionary variable' + set_fact: + mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' + with_together: + - '{{ device_name.stdout_lines[0].split() | list | lower }}' + - '{{ device_name.stdout_lines[1].split() | list }}' + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/var/tmp" in ansible_mounts | map(attribute="mount") | list' + - device_name.stdout is defined and device_name.stdout_lines is defined + - (device_name.stdout | length > 0) + tags: + - DISA-STIG-OL09-00-002068 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_var_tmp_noexec + - no_reboot_needed + +- name: 'Add noexec Option to /var/tmp: If /var/tmp not mounted, craft mount_info + manually' + set_fact: + mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' + with_together: + - - target + - source + - fstype + - options + - - /var/tmp + - '' + - '' + - defaults + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/var/tmp" in ansible_mounts | map(attribute="mount") | list' + - ("--fstab" | length == 0) + - device_name.stdout is defined and device_name.stdout_lines is defined + - (device_name.stdout | length == 0) + tags: + - DISA-STIG-OL09-00-002068 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_var_tmp_noexec + - no_reboot_needed + +- name: 'Add noexec Option to /var/tmp: Make sure noexec option is part of the to + /var/tmp options' + set_fact: + mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',noexec'' + }) }}' + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/var/tmp" in ansible_mounts | map(attribute="mount") | list' + - mount_info is defined and "noexec" not in mount_info.options + tags: + - DISA-STIG-OL09-00-002068 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_var_tmp_noexec + - no_reboot_needed + +- name: 'Add noexec Option to /var/tmp: Ensure /var/tmp is mounted with noexec option' + mount: + path: /var/tmp + src: '{{ mount_info.source }}' + opts: '{{ mount_info.options }}' + state: mounted + fstype: '{{ mount_info.fstype }}' + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/var/tmp" in ansible_mounts | map(attribute="mount") | list' + - mount_info is defined + - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" + | length == 0) + tags: + - DISA-STIG-OL09-00-002068 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_var_tmp_noexec + - no_reboot_needed + + +part /var/tmp --mountoptions="noexec" + + + + + + + + + + Add nosuid Option to /var/tmp + The nosuid mount option can be used to prevent +execution of setuid programs in /var/tmp. The SUID and SGID permissions +should not be required in these world-writable directories. +Add the nosuid option to the fourth column of +/etc/fstab for the line which controls mounting of +/var/tmp. + CCI-001764 + SRG-OS-000368-GPOS-00154 + R28 + OL09-00-002069 + SV-271665r1091707_rule + The presence of SUID and SGID executables should be tightly controlled. Users +should not be able to execute SUID or SGID binaries from temporary storage partitions. + + # Remediation is applicable only in certain platforms +if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/var/tmp" > /dev/null || findmnt --fstab "/var/tmp" > /dev/null; }; then + +function perform_remediation { + + # the mount point /var/tmp has to be defined in /etc/fstab + # before this remediation can be executed. In case it is not defined, the + # remediation aborts and no changes regarding the mount point are done. + mount_point_match_regexp="$(printf "^[[:space:]]*[^#].*[[:space:]]%s[[:space:]]" "/var/tmp")" + + grep "$mount_point_match_regexp" -q /etc/fstab \ + || { echo "The mount point '/var/tmp' is not even in /etc/fstab, so we can't set up mount options" >&2; + echo "Not remediating, because there is no record of /var/tmp in /etc/fstab" >&2; return 1; } + + + + mount_point_match_regexp="$(printf "^[[:space:]]*[^#].*[[:space:]]%s[[:space:]]" /var/tmp)" + + # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab + if ! grep -q "$mount_point_match_regexp" /etc/fstab; then + # runtime opts without some automatic kernel/userspace-added defaults + previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 | awk '{print $4}' \ + | sed -E "s/(rw|defaults|seclabel|nosuid)(,|$)//g;s/,$//") + [ "$previous_mount_opts" ] && previous_mount_opts+="," + # In iso9660 filesystems mtab could describe a "blocksize" value, this should be reflected in + # fstab as "block". The next variable is to satisfy shellcheck SC2050. + fs_type="" + if [ "$fs_type" == "iso9660" ] ; then + previous_mount_opts=$(sed 's/blocksize=/block=/' <<< "$previous_mount_opts") + fi + echo " /var/tmp defaults,${previous_mount_opts}nosuid 0 0" >> /etc/fstab + # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it + elif ! grep "$mount_point_match_regexp" /etc/fstab | grep -q "nosuid"; then + previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}') + sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,nosuid|" /etc/fstab + fi + + + if mkdir -p "/var/tmp"; then + if mountpoint -q "/var/tmp"; then + mount -o remount --target "/var/tmp" + fi + fi +} + +perform_remediation + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002069 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_var_tmp_nosuid + - no_reboot_needed + +- name: 'Add nosuid Option to /var/tmp: Check information associated to mountpoint' + command: findmnt --fstab '/var/tmp' + register: device_name + failed_when: device_name.rc > 1 + changed_when: false + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/var/tmp" in ansible_mounts | map(attribute="mount") | list' + tags: + - DISA-STIG-OL09-00-002069 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_var_tmp_nosuid + - no_reboot_needed + +- name: 'Add nosuid Option to /var/tmp: Create mount_info dictionary variable' + set_fact: + mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' + with_together: + - '{{ device_name.stdout_lines[0].split() | list | lower }}' + - '{{ device_name.stdout_lines[1].split() | list }}' + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/var/tmp" in ansible_mounts | map(attribute="mount") | list' + - device_name.stdout is defined and device_name.stdout_lines is defined + - (device_name.stdout | length > 0) + tags: + - DISA-STIG-OL09-00-002069 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_var_tmp_nosuid + - no_reboot_needed + +- name: 'Add nosuid Option to /var/tmp: If /var/tmp not mounted, craft mount_info + manually' + set_fact: + mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' + with_together: + - - target + - source + - fstype + - options + - - /var/tmp + - '' + - '' + - defaults + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/var/tmp" in ansible_mounts | map(attribute="mount") | list' + - ("--fstab" | length == 0) + - device_name.stdout is defined and device_name.stdout_lines is defined + - (device_name.stdout | length == 0) + tags: + - DISA-STIG-OL09-00-002069 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_var_tmp_nosuid + - no_reboot_needed + +- name: 'Add nosuid Option to /var/tmp: Make sure nosuid option is part of the to + /var/tmp options' + set_fact: + mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',nosuid'' + }) }}' + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/var/tmp" in ansible_mounts | map(attribute="mount") | list' + - mount_info is defined and "nosuid" not in mount_info.options + tags: + - DISA-STIG-OL09-00-002069 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_var_tmp_nosuid + - no_reboot_needed + +- name: 'Add nosuid Option to /var/tmp: Ensure /var/tmp is mounted with nosuid option' + mount: + path: /var/tmp + src: '{{ mount_info.source }}' + opts: '{{ mount_info.options }}' + state: mounted + fstype: '{{ mount_info.fstype }}' + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) + - '"/var/tmp" in ansible_mounts | map(attribute="mount") | list' + - mount_info is defined + - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" + | length == 0) + tags: + - DISA-STIG-OL09-00-002069 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_var_tmp_nosuid + - no_reboot_needed + + +part /var/tmp --mountoptions="nosuid" + + + + + + + + + + + Restrict Programs from Dangerous Execution Patterns + The recommendations in this section are designed to +ensure that the system's features to protect against potentially +dangerous program execution are activated. +These protections are applied at the system initialization or +kernel level, and defend against certain types of badly-configured +or compromised programs. + + kernel.unprivileged_bpf_disabled + Prevent unprivileged processes from using the bpf() syscall. + 2 + 1 + 2 + + + Disable the uvcvideo module + If the device contains a camera it should be covered or disabled when not in use. + CCI-000381 + CM-7 (a) + CM-7 (5) (b) + SRG-OS-000095-GPOS-00049 + SRG-OS-000370-GPOS-00155 + Failing to disconnect from collaborative computing devices (i.e., cameras) can result in subsequent compromises of organizational information. +Providing easy methods to physically disconnect from such devices after a collaborative computing session helps to ensure participants actually carry out the disconnect activity without having to go through complex and tedious procedures. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +if LC_ALL=C grep -q -m 1 "^install uvcvideo" /etc/modprobe.d/uvcvideo.conf ; then + + sed -i 's#^install uvcvideo.*#install uvcvideo /bin/false#g' /etc/modprobe.d/uvcvideo.conf +else + echo -e "\n# Disable per security requirements" >> /etc/modprobe.d/uvcvideo.conf + echo "install uvcvideo /bin/false" >> /etc/modprobe.d/uvcvideo.conf +fi + +if ! LC_ALL=C grep -q -m 1 "^blacklist uvcvideo$" /etc/modprobe.d/uvcvideo.conf ; then + echo "blacklist uvcvideo" >> /etc/modprobe.d/uvcvideo.conf +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-53-CM-7 (5) (b) + - NIST-800-53-CM-7 (a) + - disable_strategy + - kernel_module_uvcvideo_disabled + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + +- name: Ensure kernel module 'uvcvideo' is disabled + lineinfile: + create: true + dest: /etc/modprobe.d/uvcvideo.conf + regexp: install\s+uvcvideo + line: install uvcvideo /bin/false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-CM-7 (5) (b) + - NIST-800-53-CM-7 (a) + - disable_strategy + - kernel_module_uvcvideo_disabled + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + +- name: Ensure kernel module 'uvcvideo' is blacklisted + lineinfile: + create: true + dest: /etc/modprobe.d/uvcvideo.conf + regexp: ^blacklist uvcvideo$ + line: blacklist uvcvideo + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-CM-7 (5) (b) + - NIST-800-53-CM-7 (a) + - disable_strategy + - kernel_module_uvcvideo_disabled + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + + + + + + + + + + Disable storing core dumps + To set the runtime status of the kernel.core_pattern kernel parameter, run the following command: $ sudo sysctl -w kernel.core_pattern=|/bin/false +To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: kernel.core_pattern = |/bin/false + + CCI-000366 + SC-7(10) + SRG-OS-000480-GPOS-00227 + 3.3.1.1 + 3.3.1 + 3.3 + OL09-00-002380 + SV-271728r1091896_rule + A core dump includes a memory image taken at the time the operating system +terminates an application. The memory image could contain sensitive data and is generally useful +only for developers trying to debug problems. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Comment out any occurrences of kernel.core_pattern from /etc/sysctl.d/*.conf files + +for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do + + + # skip systemd-sysctl symlink (/etc/sysctl.d/99-sysctl.conf -> /etc/sysctl.conf) + if [[ "$(readlink -f "$f")" == "/etc/sysctl.conf" ]]; then continue; fi + + matching_list=$(grep -P '^(?!#).*[\s]*kernel.core_pattern.*$' $f | uniq ) + if ! test -z "$matching_list"; then + while IFS= read -r entry; do + escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") + # comment out "kernel.core_pattern" matches to preserve user data + sed -i --follow-symlinks "s/^${escaped_entry}$/# &/g" $f + done <<< "$matching_list" + fi +done + +# +# Set sysctl config file which to save the desired value +# + +SYSCONFIG_FILE="/etc/sysctl.conf" + + +# +# Set runtime for kernel.core_pattern +# +if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then + /sbin/sysctl -q -n -w kernel.core_pattern="|/bin/false" +fi + +# +# If kernel.core_pattern present in /etc/sysctl.conf, change value to "|/bin/false" +# else, add "kernel.core_pattern = |/bin/false" to /etc/sysctl.conf +# + +# Strip any search characters in the key arg so that the key can be replaced without +# adding any search characters to the config file. +stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^kernel.core_pattern") + +# shellcheck disable=SC2059 +printf -v formatted_output "%s = %s" "$stripped_key" "|/bin/false" + +# If the key exists, change it. Otherwise, add it to the config_file. +# We search for the key string followed by a word boundary (matched by \>), +# so if we search for 'setting', 'setting2' won't match. +if LC_ALL=C grep -q -m 1 -i -e "^kernel.core_pattern\\>" "${SYSCONFIG_FILE}"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + LC_ALL=C sed -i --follow-symlinks "s/^kernel.core_pattern\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" +else + if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" + fi + printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002380 + - NIST-800-53-SC-7(10) + - PCI-DSSv4-3.3 + - PCI-DSSv4-3.3.1 + - PCI-DSSv4-3.3.1.1 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_core_pattern + +- name: List /etc/sysctl.d/*.conf files + find: + paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + contains: ^[\s]*kernel.core_pattern.*$ + patterns: '*.conf' + file_type: any + register: find_sysctl_d + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002380 + - NIST-800-53-SC-7(10) + - PCI-DSSv4-3.3 + - PCI-DSSv4-3.3.1 + - PCI-DSSv4-3.3.1.1 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_core_pattern + +- name: Comment out any occurrences of kernel.core_pattern from config files + replace: + path: '{{ item.path }}' + regexp: ^[\s]*kernel.core_pattern + replace: '#kernel.core_pattern' + loop: '{{ find_sysctl_d.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002380 + - NIST-800-53-SC-7(10) + - PCI-DSSv4-3.3 + - PCI-DSSv4-3.3.1 + - PCI-DSSv4-3.3.1.1 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_core_pattern + +- name: Ensure sysctl kernel.core_pattern is set to |/bin/false + sysctl: + name: kernel.core_pattern + value: '|/bin/false' + sysctl_file: /etc/sysctl.conf + state: present + reload: true + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002380 + - NIST-800-53-SC-7(10) + - PCI-DSSv4-3.3 + - PCI-DSSv4-3.3.1 + - PCI-DSSv4-3.3.1.1 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_core_pattern + + + + + + + + + + Disable storing core dumps + The kernel.core_pattern option specifies the core dumpfile pattern +name. It can be set to an empty string. In this case, the kernel +behaves differently based on another related option. If +kernel.core_uses_pid is set to 1, then a file named as +.PID (where PID is process ID of the crashed process) is +created in the working directory. If kernel.core_uses_pid is set to +0, no coredump is saved. +To set the runtime status of the kernel.core_pattern kernel parameter, +run the following command: +$ sudo sysctl -w kernel.core_pattern= + +To make sure that the setting is persistent, +add the following line to a file in the directory /etc/sysctl.d: +kernel.core_pattern = + + FMT_SMF_EXT.1 + A core dump includes a memory image taken at the time the operating system +terminates an application. The memory image could contain sensitive data and is generally useful +only for developers trying to debug problems. + + + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Comment out any occurrences of kernel.core_pattern from /etc/sysctl.d/*.conf files +for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf; do + + matching_list=$(grep -P '^(?!#).*[\s]*kernel.core_pattern.*$' $f | uniq ) + if ! test -z "$matching_list"; then + while IFS= read -r entry; do + escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") + # comment out "kernel.core_pattern" matches to preserve user data + sed -i "s/^${escaped_entry}$/# &/g" $f + done <<< "$matching_list" + fi +done + +# +# Set runtime for kernel.core_pattern +# +/sbin/sysctl -q -n -w kernel.core_pattern="" + +# +# If kernel.core_pattern present in /etc/sysctl.conf, change value to empty +# else, add "kernel.core_pattern =" to /etc/sysctl.conf +# +# Test if the config_file is a symbolic link. If so, use --follow-symlinks with sed. +# Otherwise, regular sed command will do. +sed_command=('sed' '-i') +if test -L "/etc/sysctl.conf"; then + sed_command+=('--follow-symlinks') +fi + +# Strip any search characters in the key arg so that the key can be replaced without +# adding any search characters to the config file. +stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^kernel.core_pattern") + +# shellcheck disable=SC2059 +printf -v formatted_output "%s=" "$stripped_key" + +# If the key exists, change it. Otherwise, add it to the config_file. +# We search for the key string followed by a word boundary (matched by \>), +# so if we search for 'setting', 'setting2' won't match. +if LC_ALL=C grep -q -m 1 -i -e "^kernel.core_pattern\\>" "/etc/sysctl.conf"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + "${sed_command[@]}" "s/^kernel.core_pattern\\>.*/$escaped_formatted_output/gi" "/etc/sysctl.conf" +else + # \n is precaution for case where file ends without trailing newline + + printf '%s\n' "$formatted_output" >> "/etc/sysctl.conf" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_core_pattern_empty_string + +- name: List /etc/sysctl.d/*.conf files + find: + paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + contains: ^[\s]*kernel.core_pattern.*$ + patterns: '*.conf' + file_type: any + register: find_sysctl_d + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_core_pattern_empty_string + +- name: Comment out any occurrences of kernel.core_pattern from /etc/sysctl.d/*.conf + files + replace: + path: '{{ item.path }}' + regexp: ^[\s]*kernel.core_pattern + replace: '#kernel.core_pattern' + loop: '{{ find_sysctl_d.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_core_pattern_empty_string + +- name: Comment out any occurrences of kernel.core_pattern with value from /etc/sysctl.conf + files + replace: + path: /etc/sysctl.conf + regexp: ^[\s]*kernel.core_pattern([ \t]*=[ \t]*\S+) + replace: '#kernel.core_pattern\1' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_core_pattern_empty_string + +- name: Ensure sysctl kernel.core_pattern is set to empty + sysctl: + name: kernel.core_pattern + value: ' ' + state: present + reload: true + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_core_pattern_empty_string + + + + + + + + + + Configure file name of core dumps + To set the runtime status of the kernel.core_uses_pid kernel parameter, run the following command: $ sudo sysctl -w kernel.core_uses_pid=0 +To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: kernel.core_uses_pid = 0 + + FMT_SMF_EXT.1 + The default coredump filename is core. By setting +core_uses_pid to 1, the coredump filename becomes +core.PID. If core_pattern does not include +%p (default does not) and core_uses_pid is set, then +.PID will be appended to the filename. +When combined with kernel.core_pattern = "" configuration, it +is ensured that no core dumps are generated and also no confusing error +messages are printed by a shell. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Comment out any occurrences of kernel.core_uses_pid from /etc/sysctl.d/*.conf files + +for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do + + + # skip systemd-sysctl symlink (/etc/sysctl.d/99-sysctl.conf -> /etc/sysctl.conf) + if [[ "$(readlink -f "$f")" == "/etc/sysctl.conf" ]]; then continue; fi + + matching_list=$(grep -P '^(?!#).*[\s]*kernel.core_uses_pid.*$' $f | uniq ) + if ! test -z "$matching_list"; then + while IFS= read -r entry; do + escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") + # comment out "kernel.core_uses_pid" matches to preserve user data + sed -i --follow-symlinks "s/^${escaped_entry}$/# &/g" $f + done <<< "$matching_list" + fi +done + +# +# Set sysctl config file which to save the desired value +# + +SYSCONFIG_FILE="/etc/sysctl.conf" + + +# +# Set runtime for kernel.core_uses_pid +# +if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then + /sbin/sysctl -q -n -w kernel.core_uses_pid="0" +fi + +# +# If kernel.core_uses_pid present in /etc/sysctl.conf, change value to "0" +# else, add "kernel.core_uses_pid = 0" to /etc/sysctl.conf +# + +# Strip any search characters in the key arg so that the key can be replaced without +# adding any search characters to the config file. +stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^kernel.core_uses_pid") + +# shellcheck disable=SC2059 +printf -v formatted_output "%s = %s" "$stripped_key" "0" + +# If the key exists, change it. Otherwise, add it to the config_file. +# We search for the key string followed by a word boundary (matched by \>), +# so if we search for 'setting', 'setting2' won't match. +if LC_ALL=C grep -q -m 1 -i -e "^kernel.core_uses_pid\\>" "${SYSCONFIG_FILE}"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + LC_ALL=C sed -i --follow-symlinks "s/^kernel.core_uses_pid\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" +else + if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" + fi + printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_core_uses_pid + +- name: List /etc/sysctl.d/*.conf files + find: + paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + contains: ^[\s]*kernel.core_uses_pid.*$ + patterns: '*.conf' + file_type: any + register: find_sysctl_d + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_core_uses_pid + +- name: Comment out any occurrences of kernel.core_uses_pid from config files + replace: + path: '{{ item.path }}' + regexp: ^[\s]*kernel.core_uses_pid + replace: '#kernel.core_uses_pid' + loop: '{{ find_sysctl_d.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_core_uses_pid + +- name: Ensure sysctl kernel.core_uses_pid is set to 0 + sysctl: + name: kernel.core_uses_pid + value: '0' + sysctl_file: /etc/sysctl.conf + state: present + reload: true + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_core_uses_pid + + + + + + + + + + Restrict Access to Kernel Message Buffer + To set the runtime status of the kernel.dmesg_restrict kernel parameter, run the following command: $ sudo sysctl -w kernel.dmesg_restrict=1 +To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: kernel.dmesg_restrict = 1 + + 3.1.5 + CCI-001082 + CCI-001090 + 164.308(a)(1)(ii)(D) + 164.308(a)(3) + 164.308(a)(4) + 164.310(b) + 164.310(c) + 164.312(a) + 164.312(e) + SI-11(a) + SI-11(b) + FMT_SMF_EXT.1 + SRG-OS-000132-GPOS-00067 + SRG-OS-000138-GPOS-00069 + SRG-APP-000243-CTR-000600 + R9 + OL09-00-002406 + SV-271745r1091947_rule + Unprivileged access to the kernel syslog can expose sensitive kernel +address information. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Comment out any occurrences of kernel.dmesg_restrict from /etc/sysctl.d/*.conf files + +for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do + + + # skip systemd-sysctl symlink (/etc/sysctl.d/99-sysctl.conf -> /etc/sysctl.conf) + if [[ "$(readlink -f "$f")" == "/etc/sysctl.conf" ]]; then continue; fi + + matching_list=$(grep -P '^(?!#).*[\s]*kernel.dmesg_restrict.*$' $f | uniq ) + if ! test -z "$matching_list"; then + while IFS= read -r entry; do + escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") + # comment out "kernel.dmesg_restrict" matches to preserve user data + sed -i --follow-symlinks "s/^${escaped_entry}$/# &/g" $f + done <<< "$matching_list" + fi +done + +# +# Set sysctl config file which to save the desired value +# + +SYSCONFIG_FILE="/etc/sysctl.conf" + + +# +# Set runtime for kernel.dmesg_restrict +# +if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then + /sbin/sysctl -q -n -w kernel.dmesg_restrict="1" +fi + +# +# If kernel.dmesg_restrict present in /etc/sysctl.conf, change value to "1" +# else, add "kernel.dmesg_restrict = 1" to /etc/sysctl.conf +# + +# Strip any search characters in the key arg so that the key can be replaced without +# adding any search characters to the config file. +stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^kernel.dmesg_restrict") + +# shellcheck disable=SC2059 +printf -v formatted_output "%s = %s" "$stripped_key" "1" + +# If the key exists, change it. Otherwise, add it to the config_file. +# We search for the key string followed by a word boundary (matched by \>), +# so if we search for 'setting', 'setting2' won't match. +if LC_ALL=C grep -q -m 1 -i -e "^kernel.dmesg_restrict\\>" "${SYSCONFIG_FILE}"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + LC_ALL=C sed -i --follow-symlinks "s/^kernel.dmesg_restrict\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" +else + if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" + fi + printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002406 + - NIST-800-171-3.1.5 + - NIST-800-53-SI-11(a) + - NIST-800-53-SI-11(b) + - disable_strategy + - low_complexity + - low_severity + - medium_disruption + - reboot_required + - sysctl_kernel_dmesg_restrict + +- name: List /etc/sysctl.d/*.conf files + find: + paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + contains: ^[\s]*kernel.dmesg_restrict.*$ + patterns: '*.conf' + file_type: any + register: find_sysctl_d + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002406 + - NIST-800-171-3.1.5 + - NIST-800-53-SI-11(a) + - NIST-800-53-SI-11(b) + - disable_strategy + - low_complexity + - low_severity + - medium_disruption + - reboot_required + - sysctl_kernel_dmesg_restrict + +- name: Comment out any occurrences of kernel.dmesg_restrict from config files + replace: + path: '{{ item.path }}' + regexp: ^[\s]*kernel.dmesg_restrict + replace: '#kernel.dmesg_restrict' + loop: '{{ find_sysctl_d.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002406 + - NIST-800-171-3.1.5 + - NIST-800-53-SI-11(a) + - NIST-800-53-SI-11(b) + - disable_strategy + - low_complexity + - low_severity + - medium_disruption + - reboot_required + - sysctl_kernel_dmesg_restrict + +- name: Ensure sysctl kernel.dmesg_restrict is set to 1 + sysctl: + name: kernel.dmesg_restrict + value: '1' + sysctl_file: /etc/sysctl.conf + state: present + reload: true + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002406 + - NIST-800-171-3.1.5 + - NIST-800-53-SI-11(a) + - NIST-800-53-SI-11(b) + - disable_strategy + - low_complexity + - low_severity + - medium_disruption + - reboot_required + - sysctl_kernel_dmesg_restrict + + + + + + + + + + Disable Kernel Image Loading + To set the runtime status of the kernel.kexec_load_disabled kernel parameter, run the following command: $ sudo sysctl -w kernel.kexec_load_disabled=1 +To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: kernel.kexec_load_disabled = 1 + + CCI-003992 + CCI-000366 + CM-6 + FMT_SMF_EXT.1 + SRG-OS-000480-GPOS-00227 + SRG-OS-000366-GPOS-00153 + OL09-00-002428 + SV-271766r1092010_rule + Disabling kexec_load allows greater control of the kernel memory. +It makes it impossible to load another kernel image after it has been disabled. + + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Comment out any occurrences of kernel.kexec_load_disabled from /etc/sysctl.d/*.conf files + +for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do + + + # skip systemd-sysctl symlink (/etc/sysctl.d/99-sysctl.conf -> /etc/sysctl.conf) + if [[ "$(readlink -f "$f")" == "/etc/sysctl.conf" ]]; then continue; fi + + matching_list=$(grep -P '^(?!#).*[\s]*kernel.kexec_load_disabled.*$' $f | uniq ) + if ! test -z "$matching_list"; then + while IFS= read -r entry; do + escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") + # comment out "kernel.kexec_load_disabled" matches to preserve user data + sed -i --follow-symlinks "s/^${escaped_entry}$/# &/g" $f + done <<< "$matching_list" + fi +done + +# +# Set sysctl config file which to save the desired value +# + +SYSCONFIG_FILE="/etc/sysctl.conf" + + +# +# Set runtime for kernel.kexec_load_disabled +# +if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then + /sbin/sysctl -q -n -w kernel.kexec_load_disabled="1" +fi + +# +# If kernel.kexec_load_disabled present in /etc/sysctl.conf, change value to "1" +# else, add "kernel.kexec_load_disabled = 1" to /etc/sysctl.conf +# + +# Strip any search characters in the key arg so that the key can be replaced without +# adding any search characters to the config file. +stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^kernel.kexec_load_disabled") + +# shellcheck disable=SC2059 +printf -v formatted_output "%s = %s" "$stripped_key" "1" + +# If the key exists, change it. Otherwise, add it to the config_file. +# We search for the key string followed by a word boundary (matched by \>), +# so if we search for 'setting', 'setting2' won't match. +if LC_ALL=C grep -q -m 1 -i -e "^kernel.kexec_load_disabled\\>" "${SYSCONFIG_FILE}"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + LC_ALL=C sed -i --follow-symlinks "s/^kernel.kexec_load_disabled\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" +else + if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" + fi + printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002428 + - NIST-800-53-CM-6 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_kexec_load_disabled + +- name: List /etc/sysctl.d/*.conf files + find: + paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + contains: ^[\s]*kernel.kexec_load_disabled.*$ + patterns: '*.conf' + file_type: any + register: find_sysctl_d + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002428 + - NIST-800-53-CM-6 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_kexec_load_disabled + +- name: Comment out any occurrences of kernel.kexec_load_disabled from config files + replace: + path: '{{ item.path }}' + regexp: ^[\s]*kernel.kexec_load_disabled + replace: '#kernel.kexec_load_disabled' + loop: '{{ find_sysctl_d.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002428 + - NIST-800-53-CM-6 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_kexec_load_disabled + +- name: Ensure sysctl kernel.kexec_load_disabled is set to 1 + sysctl: + name: kernel.kexec_load_disabled + value: '1' + sysctl_file: /etc/sysctl.conf + state: present + reload: true + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002428 + - NIST-800-53-CM-6 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_kexec_load_disabled + + + + + + + + + + Disable loading and unloading of kernel modules + To set the runtime status of the kernel.modules_disabled kernel parameter, run the following command: $ sudo sysctl -w kernel.modules_disabled=1 +To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: kernel.modules_disabled = 1 + + This rule doesn't come with remediation. Remediating this rule during the installation process disrupts the install and boot process. + R10 + Malicious kernel modules can have a significant impact on system security and +availability. Disabling loading of kernel modules prevents this threat. Note +that once this option has been set, it cannot be reverted without doing a +system reboot. Make sure that all needed kernel modules are loaded before +setting this option. + + + + + + + + + + Kernel panic on oops + To set the runtime status of the kernel.panic_on_oops kernel parameter, run the following command: $ sudo sysctl -w kernel.panic_on_oops=1 +To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: kernel.panic_on_oops = 1 + + The system may start to panic when it normally wouldn't. A non-catastrophic error that +would have allowed the system to continue operating will now result in a panic. + R9 + An attacker trying to exploit the kernel may trigger kernel OOPSes, +panicking the system will impede them from continuing. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Comment out any occurrences of kernel.panic_on_oops from /etc/sysctl.d/*.conf files + +for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do + + + # skip systemd-sysctl symlink (/etc/sysctl.d/99-sysctl.conf -> /etc/sysctl.conf) + if [[ "$(readlink -f "$f")" == "/etc/sysctl.conf" ]]; then continue; fi + + matching_list=$(grep -P '^(?!#).*[\s]*kernel.panic_on_oops.*$' $f | uniq ) + if ! test -z "$matching_list"; then + while IFS= read -r entry; do + escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") + # comment out "kernel.panic_on_oops" matches to preserve user data + sed -i --follow-symlinks "s/^${escaped_entry}$/# &/g" $f + done <<< "$matching_list" + fi +done + +# +# Set sysctl config file which to save the desired value +# + +SYSCONFIG_FILE="/etc/sysctl.conf" + + +# +# Set runtime for kernel.panic_on_oops +# +if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then + /sbin/sysctl -q -n -w kernel.panic_on_oops="1" +fi + +# +# If kernel.panic_on_oops present in /etc/sysctl.conf, change value to "1" +# else, add "kernel.panic_on_oops = 1" to /etc/sysctl.conf +# + +# Strip any search characters in the key arg so that the key can be replaced without +# adding any search characters to the config file. +stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^kernel.panic_on_oops") + +# shellcheck disable=SC2059 +printf -v formatted_output "%s = %s" "$stripped_key" "1" + +# If the key exists, change it. Otherwise, add it to the config_file. +# We search for the key string followed by a word boundary (matched by \>), +# so if we search for 'setting', 'setting2' won't match. +if LC_ALL=C grep -q -m 1 -i -e "^kernel.panic_on_oops\\>" "${SYSCONFIG_FILE}"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + LC_ALL=C sed -i --follow-symlinks "s/^kernel.panic_on_oops\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" +else + if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" + fi + printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_panic_on_oops + +- name: List /etc/sysctl.d/*.conf files + find: + paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + contains: ^[\s]*kernel.panic_on_oops.*$ + patterns: '*.conf' + file_type: any + register: find_sysctl_d + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_panic_on_oops + +- name: Comment out any occurrences of kernel.panic_on_oops from config files + replace: + path: '{{ item.path }}' + regexp: ^[\s]*kernel.panic_on_oops + replace: '#kernel.panic_on_oops' + loop: '{{ find_sysctl_d.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_panic_on_oops + +- name: Ensure sysctl kernel.panic_on_oops is set to 1 + sysctl: + name: kernel.panic_on_oops + value: '1' + sysctl_file: /etc/sysctl.conf + state: present + reload: true + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_panic_on_oops + + + + + + + + + + Limit CPU consumption of the Perf system + To set the runtime status of the kernel.perf_cpu_time_max_percent kernel parameter, run the following command: $ sudo sysctl -w kernel.perf_cpu_time_max_percent=1 +To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: kernel.perf_cpu_time_max_percent = 1 + + R9 + The kernel.perf_cpu_time_max_percent configures a treshold of +maximum percentile of CPU that can be used by Perf system. Restricting usage +of Perf system decreases risk of potential availability problems. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Comment out any occurrences of kernel.perf_cpu_time_max_percent from /etc/sysctl.d/*.conf files + +for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do + + + # skip systemd-sysctl symlink (/etc/sysctl.d/99-sysctl.conf -> /etc/sysctl.conf) + if [[ "$(readlink -f "$f")" == "/etc/sysctl.conf" ]]; then continue; fi + + matching_list=$(grep -P '^(?!#).*[\s]*kernel.perf_cpu_time_max_percent.*$' $f | uniq ) + if ! test -z "$matching_list"; then + while IFS= read -r entry; do + escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") + # comment out "kernel.perf_cpu_time_max_percent" matches to preserve user data + sed -i --follow-symlinks "s/^${escaped_entry}$/# &/g" $f + done <<< "$matching_list" + fi +done + +# +# Set sysctl config file which to save the desired value +# + +SYSCONFIG_FILE="/etc/sysctl.conf" + + +# +# Set runtime for kernel.perf_cpu_time_max_percent +# +if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then + /sbin/sysctl -q -n -w kernel.perf_cpu_time_max_percent="1" +fi + +# +# If kernel.perf_cpu_time_max_percent present in /etc/sysctl.conf, change value to "1" +# else, add "kernel.perf_cpu_time_max_percent = 1" to /etc/sysctl.conf +# + +# Strip any search characters in the key arg so that the key can be replaced without +# adding any search characters to the config file. +stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^kernel.perf_cpu_time_max_percent") + +# shellcheck disable=SC2059 +printf -v formatted_output "%s = %s" "$stripped_key" "1" + +# If the key exists, change it. Otherwise, add it to the config_file. +# We search for the key string followed by a word boundary (matched by \>), +# so if we search for 'setting', 'setting2' won't match. +if LC_ALL=C grep -q -m 1 -i -e "^kernel.perf_cpu_time_max_percent\\>" "${SYSCONFIG_FILE}"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + LC_ALL=C sed -i --follow-symlinks "s/^kernel.perf_cpu_time_max_percent\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" +else + if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" + fi + printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_perf_cpu_time_max_percent + +- name: List /etc/sysctl.d/*.conf files + find: + paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + contains: ^[\s]*kernel.perf_cpu_time_max_percent.*$ + patterns: '*.conf' + file_type: any + register: find_sysctl_d + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_perf_cpu_time_max_percent + +- name: Comment out any occurrences of kernel.perf_cpu_time_max_percent from config + files + replace: + path: '{{ item.path }}' + regexp: ^[\s]*kernel.perf_cpu_time_max_percent + replace: '#kernel.perf_cpu_time_max_percent' + loop: '{{ find_sysctl_d.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_perf_cpu_time_max_percent + +- name: Ensure sysctl kernel.perf_cpu_time_max_percent is set to 1 + sysctl: + name: kernel.perf_cpu_time_max_percent + value: '1' + sysctl_file: /etc/sysctl.conf + state: present + reload: true + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_perf_cpu_time_max_percent + + + + + + + + + + Limit sampling frequency of the Perf system + To set the runtime status of the kernel.perf_event_max_sample_rate kernel parameter, run the following command: $ sudo sysctl -w kernel.perf_event_max_sample_rate=1 +To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: kernel.perf_event_max_sample_rate = 1 + + R9 + The kernel.perf_event_max_sample_rate parameter configures maximum +frequency of collecting of samples for the Perf system. It is expressed in +samples per second. Restricting usage of Perf system decreases risk +of potential availability problems. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Comment out any occurrences of kernel.perf_event_max_sample_rate from /etc/sysctl.d/*.conf files + +for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do + + + # skip systemd-sysctl symlink (/etc/sysctl.d/99-sysctl.conf -> /etc/sysctl.conf) + if [[ "$(readlink -f "$f")" == "/etc/sysctl.conf" ]]; then continue; fi + + matching_list=$(grep -P '^(?!#).*[\s]*kernel.perf_event_max_sample_rate.*$' $f | uniq ) + if ! test -z "$matching_list"; then + while IFS= read -r entry; do + escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") + # comment out "kernel.perf_event_max_sample_rate" matches to preserve user data + sed -i --follow-symlinks "s/^${escaped_entry}$/# &/g" $f + done <<< "$matching_list" + fi +done + +# +# Set sysctl config file which to save the desired value +# + +SYSCONFIG_FILE="/etc/sysctl.conf" + + +# +# Set runtime for kernel.perf_event_max_sample_rate +# +if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then + /sbin/sysctl -q -n -w kernel.perf_event_max_sample_rate="1" +fi + +# +# If kernel.perf_event_max_sample_rate present in /etc/sysctl.conf, change value to "1" +# else, add "kernel.perf_event_max_sample_rate = 1" to /etc/sysctl.conf +# + +# Strip any search characters in the key arg so that the key can be replaced without +# adding any search characters to the config file. +stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^kernel.perf_event_max_sample_rate") + +# shellcheck disable=SC2059 +printf -v formatted_output "%s = %s" "$stripped_key" "1" + +# If the key exists, change it. Otherwise, add it to the config_file. +# We search for the key string followed by a word boundary (matched by \>), +# so if we search for 'setting', 'setting2' won't match. +if LC_ALL=C grep -q -m 1 -i -e "^kernel.perf_event_max_sample_rate\\>" "${SYSCONFIG_FILE}"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + LC_ALL=C sed -i --follow-symlinks "s/^kernel.perf_event_max_sample_rate\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" +else + if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" + fi + printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_perf_event_max_sample_rate + +- name: List /etc/sysctl.d/*.conf files + find: + paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + contains: ^[\s]*kernel.perf_event_max_sample_rate.*$ + patterns: '*.conf' + file_type: any + register: find_sysctl_d + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_perf_event_max_sample_rate + +- name: Comment out any occurrences of kernel.perf_event_max_sample_rate from config + files + replace: + path: '{{ item.path }}' + regexp: ^[\s]*kernel.perf_event_max_sample_rate + replace: '#kernel.perf_event_max_sample_rate' + loop: '{{ find_sysctl_d.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_perf_event_max_sample_rate + +- name: Ensure sysctl kernel.perf_event_max_sample_rate is set to 1 + sysctl: + name: kernel.perf_event_max_sample_rate + value: '1' + sysctl_file: /etc/sysctl.conf + state: present + reload: true + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_perf_event_max_sample_rate + + + + + + + + + + Disallow kernel profiling by unprivileged users + To set the runtime status of the kernel.perf_event_paranoid kernel parameter, run the following command: $ sudo sysctl -w kernel.perf_event_paranoid=2 +To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: kernel.perf_event_paranoid = 2 + + CCI-001082 + CCI-001090 + AC-6 + FMT_SMF_EXT.1 + SRG-OS-000132-GPOS-00067 + SRG-OS-000138-GPOS-00069 + SRG-APP-000243-CTR-000600 + R9 + OL09-00-002407 + SV-271746r1091950_rule + Kernel profiling can reveal sensitive information about kernel behaviour. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Comment out any occurrences of kernel.perf_event_paranoid from /etc/sysctl.d/*.conf files + +for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do + + + # skip systemd-sysctl symlink (/etc/sysctl.d/99-sysctl.conf -> /etc/sysctl.conf) + if [[ "$(readlink -f "$f")" == "/etc/sysctl.conf" ]]; then continue; fi + + matching_list=$(grep -P '^(?!#).*[\s]*kernel.perf_event_paranoid.*$' $f | uniq ) + if ! test -z "$matching_list"; then + while IFS= read -r entry; do + escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") + # comment out "kernel.perf_event_paranoid" matches to preserve user data + sed -i --follow-symlinks "s/^${escaped_entry}$/# &/g" $f + done <<< "$matching_list" + fi +done + +# +# Set sysctl config file which to save the desired value +# + +SYSCONFIG_FILE="/etc/sysctl.conf" + + +# +# Set runtime for kernel.perf_event_paranoid +# +if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then + /sbin/sysctl -q -n -w kernel.perf_event_paranoid="2" +fi + +# +# If kernel.perf_event_paranoid present in /etc/sysctl.conf, change value to "2" +# else, add "kernel.perf_event_paranoid = 2" to /etc/sysctl.conf +# + +# Strip any search characters in the key arg so that the key can be replaced without +# adding any search characters to the config file. +stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^kernel.perf_event_paranoid") + +# shellcheck disable=SC2059 +printf -v formatted_output "%s = %s" "$stripped_key" "2" + +# If the key exists, change it. Otherwise, add it to the config_file. +# We search for the key string followed by a word boundary (matched by \>), +# so if we search for 'setting', 'setting2' won't match. +if LC_ALL=C grep -q -m 1 -i -e "^kernel.perf_event_paranoid\\>" "${SYSCONFIG_FILE}"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + LC_ALL=C sed -i --follow-symlinks "s/^kernel.perf_event_paranoid\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" +else + if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" + fi + printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002407 + - NIST-800-53-AC-6 + - disable_strategy + - low_complexity + - low_severity + - medium_disruption + - reboot_required + - sysctl_kernel_perf_event_paranoid + +- name: List /etc/sysctl.d/*.conf files + find: + paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + contains: ^[\s]*kernel.perf_event_paranoid.*$ + patterns: '*.conf' + file_type: any + register: find_sysctl_d + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002407 + - NIST-800-53-AC-6 + - disable_strategy + - low_complexity + - low_severity + - medium_disruption + - reboot_required + - sysctl_kernel_perf_event_paranoid + +- name: Comment out any occurrences of kernel.perf_event_paranoid from config files + replace: + path: '{{ item.path }}' + regexp: ^[\s]*kernel.perf_event_paranoid + replace: '#kernel.perf_event_paranoid' + loop: '{{ find_sysctl_d.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002407 + - NIST-800-53-AC-6 + - disable_strategy + - low_complexity + - low_severity + - medium_disruption + - reboot_required + - sysctl_kernel_perf_event_paranoid + +- name: Ensure sysctl kernel.perf_event_paranoid is set to 2 + sysctl: + name: kernel.perf_event_paranoid + value: '2' + sysctl_file: /etc/sysctl.conf + state: present + reload: true + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002407 + - NIST-800-53-AC-6 + - disable_strategy + - low_complexity + - low_severity + - medium_disruption + - reboot_required + - sysctl_kernel_perf_event_paranoid + + + + + + + + + + Configure maximum number of process identifiers + To set the runtime status of the kernel.pid_max kernel parameter, run the following command: $ sudo sysctl -w kernel.pid_max=65536 +To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: kernel.pid_max = 65536 + + R9 + The kernel.pid_max parameter configures upper limit on process +identifiers (PID). If this number is not high enough, it might happen that +forking of new processes is not possible, because all available PIDs are +exhausted. Increasing this number enhances availability. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Comment out any occurrences of kernel.pid_max from /etc/sysctl.d/*.conf files + +for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do + + + # skip systemd-sysctl symlink (/etc/sysctl.d/99-sysctl.conf -> /etc/sysctl.conf) + if [[ "$(readlink -f "$f")" == "/etc/sysctl.conf" ]]; then continue; fi + + matching_list=$(grep -P '^(?!#).*[\s]*kernel.pid_max.*$' $f | uniq ) + if ! test -z "$matching_list"; then + while IFS= read -r entry; do + escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") + # comment out "kernel.pid_max" matches to preserve user data + sed -i --follow-symlinks "s/^${escaped_entry}$/# &/g" $f + done <<< "$matching_list" + fi +done + +# +# Set sysctl config file which to save the desired value +# + +SYSCONFIG_FILE="/etc/sysctl.conf" + + +# +# Set runtime for kernel.pid_max +# +if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then + /sbin/sysctl -q -n -w kernel.pid_max="65536" +fi + +# +# If kernel.pid_max present in /etc/sysctl.conf, change value to "65536" +# else, add "kernel.pid_max = 65536" to /etc/sysctl.conf +# + +# Strip any search characters in the key arg so that the key can be replaced without +# adding any search characters to the config file. +stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^kernel.pid_max") + +# shellcheck disable=SC2059 +printf -v formatted_output "%s = %s" "$stripped_key" "65536" + +# If the key exists, change it. Otherwise, add it to the config_file. +# We search for the key string followed by a word boundary (matched by \>), +# so if we search for 'setting', 'setting2' won't match. +if LC_ALL=C grep -q -m 1 -i -e "^kernel.pid_max\\>" "${SYSCONFIG_FILE}"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + LC_ALL=C sed -i --follow-symlinks "s/^kernel.pid_max\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" +else + if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" + fi + printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_pid_max + +- name: List /etc/sysctl.d/*.conf files + find: + paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + contains: ^[\s]*kernel.pid_max.*$ + patterns: '*.conf' + file_type: any + register: find_sysctl_d + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_pid_max + +- name: Comment out any occurrences of kernel.pid_max from config files + replace: + path: '{{ item.path }}' + regexp: ^[\s]*kernel.pid_max + replace: '#kernel.pid_max' + loop: '{{ find_sysctl_d.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_pid_max + +- name: Ensure sysctl kernel.pid_max is set to 65536 + sysctl: + name: kernel.pid_max + value: '65536' + sysctl_file: /etc/sysctl.conf + state: present + reload: true + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_pid_max + + + + + + + + + + Disallow magic SysRq key + To set the runtime status of the kernel.sysrq kernel parameter, run the following command: $ sudo sysctl -w kernel.sysrq=0 +To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: kernel.sysrq = 0 + + R9 + The Magic SysRq key allows sending certain commands directly to the running +kernel. It can dump various system and process information, potentially +revealing sensitive information. It can also reboot or shutdown the machine, +disturbing its availability. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Comment out any occurrences of kernel.sysrq from /etc/sysctl.d/*.conf files + +for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do + + + # skip systemd-sysctl symlink (/etc/sysctl.d/99-sysctl.conf -> /etc/sysctl.conf) + if [[ "$(readlink -f "$f")" == "/etc/sysctl.conf" ]]; then continue; fi + + matching_list=$(grep -P '^(?!#).*[\s]*kernel.sysrq.*$' $f | uniq ) + if ! test -z "$matching_list"; then + while IFS= read -r entry; do + escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") + # comment out "kernel.sysrq" matches to preserve user data + sed -i --follow-symlinks "s/^${escaped_entry}$/# &/g" $f + done <<< "$matching_list" + fi +done + +# +# Set sysctl config file which to save the desired value +# + +SYSCONFIG_FILE="/etc/sysctl.conf" + + +# +# Set runtime for kernel.sysrq +# +if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then + /sbin/sysctl -q -n -w kernel.sysrq="0" +fi + +# +# If kernel.sysrq present in /etc/sysctl.conf, change value to "0" +# else, add "kernel.sysrq = 0" to /etc/sysctl.conf +# + +# Strip any search characters in the key arg so that the key can be replaced without +# adding any search characters to the config file. +stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^kernel.sysrq") + +# shellcheck disable=SC2059 +printf -v formatted_output "%s = %s" "$stripped_key" "0" + +# If the key exists, change it. Otherwise, add it to the config_file. +# We search for the key string followed by a word boundary (matched by \>), +# so if we search for 'setting', 'setting2' won't match. +if LC_ALL=C grep -q -m 1 -i -e "^kernel.sysrq\\>" "${SYSCONFIG_FILE}"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + LC_ALL=C sed -i --follow-symlinks "s/^kernel.sysrq\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" +else + if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" + fi + printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_sysrq + +- name: List /etc/sysctl.d/*.conf files + find: + paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + contains: ^[\s]*kernel.sysrq.*$ + patterns: '*.conf' + file_type: any + register: find_sysctl_d + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_sysrq + +- name: Comment out any occurrences of kernel.sysrq from config files + replace: + path: '{{ item.path }}' + regexp: ^[\s]*kernel.sysrq + replace: '#kernel.sysrq' + loop: '{{ find_sysctl_d.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_sysrq + +- name: Ensure sysctl kernel.sysrq is set to 0 + sysctl: + name: kernel.sysrq + value: '0' + sysctl_file: /etc/sysctl.conf + state: present + reload: true + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_sysrq + + + + + + + + + + Disable Access to Network bpf() Syscall From Unprivileged Processes + To set the runtime status of the kernel.unprivileged_bpf_disabled kernel parameter, run the following command: $ sudo sysctl -w kernel.unprivileged_bpf_disabled=1 +To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: kernel.unprivileged_bpf_disabled = 1 + + CCI-000366 + CCI-001082 + AC-6 + SC-7(10) + SRG-OS-000132-GPOS-00067 + SRG-OS-000480-GPOS-00227 + R9 + OL09-00-002409 + SV-271748r1091956_rule + Loading and accessing the packet filters programs and maps using the bpf() +syscall has the potential of revealing sensitive information about the kernel state. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Comment out any occurrences of kernel.unprivileged_bpf_disabled from /etc/sysctl.d/*.conf files + +for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do + + + # skip systemd-sysctl symlink (/etc/sysctl.d/99-sysctl.conf -> /etc/sysctl.conf) + if [[ "$(readlink -f "$f")" == "/etc/sysctl.conf" ]]; then continue; fi + + matching_list=$(grep -P '^(?!#).*[\s]*kernel.unprivileged_bpf_disabled.*$' $f | uniq ) + if ! test -z "$matching_list"; then + while IFS= read -r entry; do + escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") + # comment out "kernel.unprivileged_bpf_disabled" matches to preserve user data + sed -i --follow-symlinks "s/^${escaped_entry}$/# &/g" $f + done <<< "$matching_list" + fi +done + +# +# Set sysctl config file which to save the desired value +# + +SYSCONFIG_FILE="/etc/sysctl.conf" + + +# +# Set runtime for kernel.unprivileged_bpf_disabled +# +if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then + /sbin/sysctl -q -n -w kernel.unprivileged_bpf_disabled="1" +fi + +# +# If kernel.unprivileged_bpf_disabled present in /etc/sysctl.conf, change value to "1" +# else, add "kernel.unprivileged_bpf_disabled = 1" to /etc/sysctl.conf +# + +# Strip any search characters in the key arg so that the key can be replaced without +# adding any search characters to the config file. +stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^kernel.unprivileged_bpf_disabled") + +# shellcheck disable=SC2059 +printf -v formatted_output "%s = %s" "$stripped_key" "1" + +# If the key exists, change it. Otherwise, add it to the config_file. +# We search for the key string followed by a word boundary (matched by \>), +# so if we search for 'setting', 'setting2' won't match. +if LC_ALL=C grep -q -m 1 -i -e "^kernel.unprivileged_bpf_disabled\\>" "${SYSCONFIG_FILE}"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + LC_ALL=C sed -i --follow-symlinks "s/^kernel.unprivileged_bpf_disabled\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" +else + if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" + fi + printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002409 + - NIST-800-53-AC-6 + - NIST-800-53-SC-7(10) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_unprivileged_bpf_disabled + +- name: List /etc/sysctl.d/*.conf files + find: + paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + contains: ^[\s]*kernel.unprivileged_bpf_disabled.*$ + patterns: '*.conf' + file_type: any + register: find_sysctl_d + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002409 + - NIST-800-53-AC-6 + - NIST-800-53-SC-7(10) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_unprivileged_bpf_disabled + +- name: Comment out any occurrences of kernel.unprivileged_bpf_disabled from config + files + replace: + path: '{{ item.path }}' + regexp: ^[\s]*kernel.unprivileged_bpf_disabled + replace: '#kernel.unprivileged_bpf_disabled' + loop: '{{ find_sysctl_d.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002409 + - NIST-800-53-AC-6 + - NIST-800-53-SC-7(10) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_unprivileged_bpf_disabled + +- name: Ensure sysctl kernel.unprivileged_bpf_disabled is set to 1 + sysctl: + name: kernel.unprivileged_bpf_disabled + value: '1' + sysctl_file: /etc/sysctl.conf + state: present + reload: true + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002409 + - NIST-800-53-AC-6 + - NIST-800-53-SC-7(10) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_unprivileged_bpf_disabled + + + + + + + + + + Disable Access to Network bpf() Syscall From Unprivileged Processes + To prevent unprivileged processes from using the bpf() syscall +the kernel.unprivileged_bpf_disabled kernel parameter must +be set to 1 or 2. + +Writing 1 to this entry will disable unprivileged calls to bpf(); once +disabled, calling bpf() without CAP_SYS_ADMIN or CAP_BPF will return -EPERM. +Once set to 1, this can't be cleared from the running kernel anymore. + +To set the runtime status of the kernel.unprivileged_bpf_disabled kernel parameter, +run the following command: +$ sudo sysctl -w kernel.unprivileged_bpf_disabled=1 + +To make sure that the setting is persistent, +add the following line to a file in the directory /etc/sysctl.d: +kernel.unprivileged_bpf_disabled = 1 + +Writing 2 to this entry will also disable unprivileged calls to bpf(), +however, an admin can still change this setting later on, if needed, by +writing 0 or 1 to this entry. + +To set the runtime status of the kernel.unprivileged_bpf_disabled kernel parameter, +run the following command: +$ sudo sysctl -w kernel.unprivileged_bpf_disabled=2 + +To make sure that the setting is persistent, +add the following line to a file in the directory /etc/sysctl.d: +kernel.unprivileged_bpf_disabled = 2 + + CCI-000366 + AC-6 + SC-7(10) + FMT_SMF_EXT.1 + SRG-OS-000132-GPOS-00067 + SRG-OS-000480-GPOS-00227 + Loading and accessing the packet filters programs and maps using the bpf() +syscall has the potential of revealing sensitive information about the kernel state. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Comment out any occurrences of kernel.unprivileged_bpf_disabled from /etc/sysctl.d/*.conf files + +for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do + + + # skip systemd-sysctl symlink (/etc/sysctl.d/99-sysctl.conf -> /etc/sysctl.conf) + if [[ "$(readlink -f "$f")" == "/etc/sysctl.conf" ]]; then continue; fi + + matching_list=$(grep -P '^(?!#).*[\s]*kernel.unprivileged_bpf_disabled.*$' $f | uniq ) + if ! test -z "$matching_list"; then + while IFS= read -r entry; do + escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") + # comment out "kernel.unprivileged_bpf_disabled" matches to preserve user data + sed -i --follow-symlinks "s/^${escaped_entry}$/# &/g" $f + done <<< "$matching_list" + fi +done + +# +# Set sysctl config file which to save the desired value +# + +SYSCONFIG_FILE="/etc/sysctl.conf" + +sysctl_kernel_unprivileged_bpf_disabled_value='' + + +# +# Set runtime for kernel.unprivileged_bpf_disabled +# +if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then + /sbin/sysctl -q -n -w kernel.unprivileged_bpf_disabled="$sysctl_kernel_unprivileged_bpf_disabled_value" +fi + +# +# If kernel.unprivileged_bpf_disabled present in /etc/sysctl.conf, change value to appropriate value +# else, add "kernel.unprivileged_bpf_disabled = value" to /etc/sysctl.conf +# + +# Strip any search characters in the key arg so that the key can be replaced without +# adding any search characters to the config file. +stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^kernel.unprivileged_bpf_disabled") + +# shellcheck disable=SC2059 +printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_kernel_unprivileged_bpf_disabled_value" + +# If the key exists, change it. Otherwise, add it to the config_file. +# We search for the key string followed by a word boundary (matched by \>), +# so if we search for 'setting', 'setting2' won't match. +if LC_ALL=C grep -q -m 1 -i -e "^kernel.unprivileged_bpf_disabled\\>" "${SYSCONFIG_FILE}"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + LC_ALL=C sed -i --follow-symlinks "s/^kernel.unprivileged_bpf_disabled\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" +else + if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" + fi + printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-53-AC-6 + - NIST-800-53-SC-7(10) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_unprivileged_bpf_disabled_accept_default + +- name: List /etc/sysctl.d/*.conf files + find: + paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + contains: ^[\s]*kernel.unprivileged_bpf_disabled.*$ + patterns: '*.conf' + file_type: any + register: find_sysctl_d + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-AC-6 + - NIST-800-53-SC-7(10) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_unprivileged_bpf_disabled_accept_default + +- name: Comment out any occurrences of kernel.unprivileged_bpf_disabled from config + files + replace: + path: '{{ item.path }}' + regexp: ^[\s]*kernel.unprivileged_bpf_disabled + replace: '#kernel.unprivileged_bpf_disabled' + loop: '{{ find_sysctl_d.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-AC-6 + - NIST-800-53-SC-7(10) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_unprivileged_bpf_disabled_accept_default +- name: XCCDF Value sysctl_kernel_unprivileged_bpf_disabled_value # promote to variable + set_fact: + sysctl_kernel_unprivileged_bpf_disabled_value: !!str + tags: + - always + +- name: Ensure sysctl kernel.unprivileged_bpf_disabled is set + sysctl: + name: kernel.unprivileged_bpf_disabled + value: '{{ sysctl_kernel_unprivileged_bpf_disabled_value }}' + sysctl_file: /etc/sysctl.conf + state: present + reload: true + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-AC-6 + - NIST-800-53-SC-7(10) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_unprivileged_bpf_disabled_accept_default + + + + + + + + + + Restrict usage of ptrace to descendant processes + To set the runtime status of the kernel.yama.ptrace_scope kernel parameter, run the following command: $ sudo sysctl -w kernel.yama.ptrace_scope=1 +To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: kernel.yama.ptrace_scope = 1 + + CCI-000366 + CCI-001082 + SC-7(10) + FMT_SMF_EXT.1 + SRG-OS-000132-GPOS-00067 + SRG-OS-000480-GPOS-00227 + R11 + OL09-00-002410 + SV-271749r1091959_rule + Unrestricted usage of ptrace allows compromised binaries to run ptrace +on another processes of the user. Like this, the attacker can steal +sensitive information from the target processes (e.g. SSH sessions, web browser, ...) +without any additional assistance from the user (i.e. without resorting to phishing). + + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Comment out any occurrences of kernel.yama.ptrace_scope from /etc/sysctl.d/*.conf files + +for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do + + + # skip systemd-sysctl symlink (/etc/sysctl.d/99-sysctl.conf -> /etc/sysctl.conf) + if [[ "$(readlink -f "$f")" == "/etc/sysctl.conf" ]]; then continue; fi + + matching_list=$(grep -P '^(?!#).*[\s]*kernel.yama.ptrace_scope.*$' $f | uniq ) + if ! test -z "$matching_list"; then + while IFS= read -r entry; do + escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") + # comment out "kernel.yama.ptrace_scope" matches to preserve user data + sed -i --follow-symlinks "s/^${escaped_entry}$/# &/g" $f + done <<< "$matching_list" + fi +done + +# +# Set sysctl config file which to save the desired value +# + +SYSCONFIG_FILE="/etc/sysctl.conf" + + +# +# Set runtime for kernel.yama.ptrace_scope +# +if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then + /sbin/sysctl -q -n -w kernel.yama.ptrace_scope="1" +fi + +# +# If kernel.yama.ptrace_scope present in /etc/sysctl.conf, change value to "1" +# else, add "kernel.yama.ptrace_scope = 1" to /etc/sysctl.conf +# + +# Strip any search characters in the key arg so that the key can be replaced without +# adding any search characters to the config file. +stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^kernel.yama.ptrace_scope") + +# shellcheck disable=SC2059 +printf -v formatted_output "%s = %s" "$stripped_key" "1" + +# If the key exists, change it. Otherwise, add it to the config_file. +# We search for the key string followed by a word boundary (matched by \>), +# so if we search for 'setting', 'setting2' won't match. +if LC_ALL=C grep -q -m 1 -i -e "^kernel.yama.ptrace_scope\\>" "${SYSCONFIG_FILE}"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + LC_ALL=C sed -i --follow-symlinks "s/^kernel.yama.ptrace_scope\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" +else + if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" + fi + printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002410 + - NIST-800-53-SC-7(10) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_yama_ptrace_scope + +- name: List /etc/sysctl.d/*.conf files + find: + paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + contains: ^[\s]*kernel.yama.ptrace_scope.*$ + patterns: '*.conf' + file_type: any + register: find_sysctl_d + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002410 + - NIST-800-53-SC-7(10) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_yama_ptrace_scope + +- name: Comment out any occurrences of kernel.yama.ptrace_scope from config files + replace: + path: '{{ item.path }}' + regexp: ^[\s]*kernel.yama.ptrace_scope + replace: '#kernel.yama.ptrace_scope' + loop: '{{ find_sysctl_d.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002410 + - NIST-800-53-SC-7(10) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_yama_ptrace_scope + +- name: Ensure sysctl kernel.yama.ptrace_scope is set to 1 + sysctl: + name: kernel.yama.ptrace_scope + value: '1' + sysctl_file: /etc/sysctl.conf + state: present + reload: true + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002410 + - NIST-800-53-SC-7(10) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_yama_ptrace_scope + + + + + + + + + + Harden the operation of the BPF just-in-time compiler + To set the runtime status of the net.core.bpf_jit_harden kernel parameter, run the following command: $ sudo sysctl -w net.core.bpf_jit_harden=2 +To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.core.bpf_jit_harden = 2 + + CCI-000366 + CM-6 + SC-7(10) + SRG-OS-000480-GPOS-00227 + R12 + OL09-00-002430 + SV-271768r1092016_rule + When hardened, the extended Berkeley Packet Filter just-in-time compiler +will randomize any kernel addresses in the BPF programs and maps, +and will not expose the JIT addresses in /proc/kallsyms. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Comment out any occurrences of net.core.bpf_jit_harden from /etc/sysctl.d/*.conf files + +for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do + + + # skip systemd-sysctl symlink (/etc/sysctl.d/99-sysctl.conf -> /etc/sysctl.conf) + if [[ "$(readlink -f "$f")" == "/etc/sysctl.conf" ]]; then continue; fi + + matching_list=$(grep -P '^(?!#).*[\s]*net.core.bpf_jit_harden.*$' $f | uniq ) + if ! test -z "$matching_list"; then + while IFS= read -r entry; do + escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") + # comment out "net.core.bpf_jit_harden" matches to preserve user data + sed -i --follow-symlinks "s/^${escaped_entry}$/# &/g" $f + done <<< "$matching_list" + fi +done + +# +# Set sysctl config file which to save the desired value +# + +SYSCONFIG_FILE="/etc/sysctl.conf" + + +# +# Set runtime for net.core.bpf_jit_harden +# +if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then + /sbin/sysctl -q -n -w net.core.bpf_jit_harden="2" +fi + +# +# If net.core.bpf_jit_harden present in /etc/sysctl.conf, change value to "2" +# else, add "net.core.bpf_jit_harden = 2" to /etc/sysctl.conf +# + +# Strip any search characters in the key arg so that the key can be replaced without +# adding any search characters to the config file. +stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.core.bpf_jit_harden") + +# shellcheck disable=SC2059 +printf -v formatted_output "%s = %s" "$stripped_key" "2" + +# If the key exists, change it. Otherwise, add it to the config_file. +# We search for the key string followed by a word boundary (matched by \>), +# so if we search for 'setting', 'setting2' won't match. +if LC_ALL=C grep -q -m 1 -i -e "^net.core.bpf_jit_harden\\>" "${SYSCONFIG_FILE}"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + LC_ALL=C sed -i --follow-symlinks "s/^net.core.bpf_jit_harden\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" +else + if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" + fi + printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002430 + - NIST-800-53-CM-6 + - NIST-800-53-SC-7(10) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_core_bpf_jit_harden + +- name: List /etc/sysctl.d/*.conf files + find: + paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + contains: ^[\s]*net.core.bpf_jit_harden.*$ + patterns: '*.conf' + file_type: any + register: find_sysctl_d + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002430 + - NIST-800-53-CM-6 + - NIST-800-53-SC-7(10) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_core_bpf_jit_harden + +- name: Comment out any occurrences of net.core.bpf_jit_harden from config files + replace: + path: '{{ item.path }}' + regexp: ^[\s]*net.core.bpf_jit_harden + replace: '#net.core.bpf_jit_harden' + loop: '{{ find_sysctl_d.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002430 + - NIST-800-53-CM-6 + - NIST-800-53-SC-7(10) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_core_bpf_jit_harden + +- name: Ensure sysctl net.core.bpf_jit_harden is set to 2 + sysctl: + name: net.core.bpf_jit_harden + value: '2' + sysctl_file: /etc/sysctl.conf + state: present + reload: true + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002430 + - NIST-800-53-CM-6 + - NIST-800-53-SC-7(10) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_core_bpf_jit_harden + + + + + + + + + + Disable the use of user namespaces + To set the runtime status of the user.max_user_namespaces kernel parameter, +run the following command: +$ sudo sysctl -w user.max_user_namespaces=0 + +To make sure that the setting is persistent, +add the following line to a file in the directory /etc/sysctl.d: +user.max_user_namespaces = 0 +When containers are deployed on the machine, the value should be set +to large non-zero value. + This configuration baseline was created to deploy the base operating system for general purpose +workloads. When the operating system is configured for certain purposes, such as to host Linux Containers, +it is expected that user.max_user_namespaces will be enabled. + CCI-000366 + SC-39 + CM-6(a) + FMT_SMF_EXT.1 + SRG-OS-000480-GPOS-00227 + OL09-00-002370 + SV-271727r1091893_rule + It is detrimental for operating systems to provide, or install by default, functionality exceeding requirements or system objectives. +These unnecessary capabilities or services are often overlooked and therefore may remain unsecured. +They increase the risk to the platform by providing additional attack vectors. +User namespaces are used primarily for Linux containers. The value 0 +disallows the use of user namespaces. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Comment out any occurrences of user.max_user_namespaces from /etc/sysctl.d/*.conf files + +for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do + + + # skip systemd-sysctl symlink (/etc/sysctl.d/99-sysctl.conf -> /etc/sysctl.conf) + if [[ "$(readlink -f "$f")" == "/etc/sysctl.conf" ]]; then continue; fi + + matching_list=$(grep -P '^(?!#).*[\s]*user.max_user_namespaces.*$' $f | uniq ) + if ! test -z "$matching_list"; then + while IFS= read -r entry; do + escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") + # comment out "user.max_user_namespaces" matches to preserve user data + sed -i --follow-symlinks "s/^${escaped_entry}$/# &/g" $f + done <<< "$matching_list" + fi +done + +# +# Set sysctl config file which to save the desired value +# + +SYSCONFIG_FILE="/etc/sysctl.conf" + + +# +# Set runtime for user.max_user_namespaces +# +if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then + /sbin/sysctl -q -n -w user.max_user_namespaces="0" +fi + +# +# If user.max_user_namespaces present in /etc/sysctl.conf, change value to "0" +# else, add "user.max_user_namespaces = 0" to /etc/sysctl.conf +# + +# Strip any search characters in the key arg so that the key can be replaced without +# adding any search characters to the config file. +stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^user.max_user_namespaces") + +# shellcheck disable=SC2059 +printf -v formatted_output "%s = %s" "$stripped_key" "0" + +# If the key exists, change it. Otherwise, add it to the config_file. +# We search for the key string followed by a word boundary (matched by \>), +# so if we search for 'setting', 'setting2' won't match. +if LC_ALL=C grep -q -m 1 -i -e "^user.max_user_namespaces\\>" "${SYSCONFIG_FILE}"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + LC_ALL=C sed -i --follow-symlinks "s/^user.max_user_namespaces\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" +else + if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" + fi + printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002370 + - NIST-800-53-CM-6(a) + - NIST-800-53-SC-39 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_user_max_user_namespaces + +- name: List /etc/sysctl.d/*.conf files + find: + paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + contains: ^[\s]*user.max_user_namespaces.*$ + patterns: '*.conf' + file_type: any + register: find_sysctl_d + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002370 + - NIST-800-53-CM-6(a) + - NIST-800-53-SC-39 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_user_max_user_namespaces + +- name: Comment out any occurrences of user.max_user_namespaces from config files + replace: + path: '{{ item.path }}' + regexp: ^[\s]*user.max_user_namespaces + replace: '#user.max_user_namespaces' + loop: '{{ find_sysctl_d.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002370 + - NIST-800-53-CM-6(a) + - NIST-800-53-SC-39 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_user_max_user_namespaces + +- name: Ensure sysctl user.max_user_namespaces is set to 0 + sysctl: + name: user.max_user_namespaces + value: '0' + sysctl_file: /etc/sysctl.conf + state: present + reload: true + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002370 + - NIST-800-53-CM-6(a) + - NIST-800-53-SC-39 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_user_max_user_namespaces + + + + + + + + + + Prevent applications from mapping low portion of virtual memory + To set the runtime status of the vm.mmap_min_addr kernel parameter, run the following command: $ sudo sysctl -w vm.mmap_min_addr=65536 +To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: vm.mmap_min_addr = 65536 + + R8 + The vm.mmap_min_addr parameter specifies the minimum virtual +address that a process is allowed to mmap. Allowing a process to mmap low +portion of virtual memory can have security implications such as such as +heightened risk of kernel null pointer dereference defects. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Comment out any occurrences of vm.mmap_min_addr from /etc/sysctl.d/*.conf files + +for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do + + + # skip systemd-sysctl symlink (/etc/sysctl.d/99-sysctl.conf -> /etc/sysctl.conf) + if [[ "$(readlink -f "$f")" == "/etc/sysctl.conf" ]]; then continue; fi + + matching_list=$(grep -P '^(?!#).*[\s]*vm.mmap_min_addr.*$' $f | uniq ) + if ! test -z "$matching_list"; then + while IFS= read -r entry; do + escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") + # comment out "vm.mmap_min_addr" matches to preserve user data + sed -i --follow-symlinks "s/^${escaped_entry}$/# &/g" $f + done <<< "$matching_list" + fi +done + +# +# Set sysctl config file which to save the desired value +# + +SYSCONFIG_FILE="/etc/sysctl.conf" + + +# +# Set runtime for vm.mmap_min_addr +# +if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then + /sbin/sysctl -q -n -w vm.mmap_min_addr="65536" +fi + +# +# If vm.mmap_min_addr present in /etc/sysctl.conf, change value to "65536" +# else, add "vm.mmap_min_addr = 65536" to /etc/sysctl.conf +# + +# Strip any search characters in the key arg so that the key can be replaced without +# adding any search characters to the config file. +stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^vm.mmap_min_addr") + +# shellcheck disable=SC2059 +printf -v formatted_output "%s = %s" "$stripped_key" "65536" + +# If the key exists, change it. Otherwise, add it to the config_file. +# We search for the key string followed by a word boundary (matched by \>), +# so if we search for 'setting', 'setting2' won't match. +if LC_ALL=C grep -q -m 1 -i -e "^vm.mmap_min_addr\\>" "${SYSCONFIG_FILE}"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + LC_ALL=C sed -i --follow-symlinks "s/^vm.mmap_min_addr\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" +else + if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" + fi + printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_vm_mmap_min_addr + +- name: List /etc/sysctl.d/*.conf files + find: + paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + contains: ^[\s]*vm.mmap_min_addr.*$ + patterns: '*.conf' + file_type: any + register: find_sysctl_d + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_vm_mmap_min_addr + +- name: Comment out any occurrences of vm.mmap_min_addr from config files + replace: + path: '{{ item.path }}' + regexp: ^[\s]*vm.mmap_min_addr + replace: '#vm.mmap_min_addr' + loop: '{{ find_sysctl_d.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_vm_mmap_min_addr + +- name: Ensure sysctl vm.mmap_min_addr is set to 65536 + sysctl: + name: vm.mmap_min_addr + value: '65536' + sysctl_file: /etc/sysctl.conf + state: present + reload: true + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_vm_mmap_min_addr + + + + + + + + + + Disable Core Dumps + A core dump file is the memory image of an executable +program when it was terminated by the operating system due to +errant behavior. In most cases, only software developers +legitimately need to access these files. The core dump files may +also contain sensitive information, or unnecessarily occupy large +amounts of disk space. + + +Once a hard limit is set in /etc/security/limits.conf, or +to a file within the /etc/security/limits.d/ directory, a +user cannot increase that limit within his or her own session. If access +to core dumps is required, consider restricting them to only +certain users or groups. See the limits.conf man page for more +information. + + +The core dumps of setuid programs are further protected. The +sysctl variable fs.suid_dumpable controls whether +the kernel allows core dumps from these programs at all. The default +value of 0 is recommended. + + Disable acquiring, saving, and processing core dumps + The systemd-coredump.socket unit is a socket activation of +the systemd-coredump@.service which processes core dumps. +By masking the unit, core dump processing is disabled. + CCI-000366 + SC-7(10) + FMT_SMF_EXT.1 + SRG-OS-000480-GPOS-00227 + OL09-00-002384 + SV-271732r1091908_rule + A core dump includes a memory image taken at the time the operating system +terminates an application. The memory image could contain sensitive data +and is generally useful only for developers trying to debug problems. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +SOCKET_NAME="systemd-coredump.socket" +SYSTEMCTL_EXEC='/usr/bin/systemctl' + +if "$SYSTEMCTL_EXEC" -q list-unit-files --type socket | grep -q "$SOCKET_NAME"; then + if [[ $("$SYSTEMCTL_EXEC" is-system-running) != "offline" ]]; then + "$SYSTEMCTL_EXEC" stop "$SOCKET_NAME" + fi + "$SYSTEMCTL_EXEC" mask "$SOCKET_NAME" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002384 + - NIST-800-53-SC-7(10) + - disable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_systemd-coredump_disabled + +- name: Disable acquiring, saving, and processing core dumps - Collect systemd Socket + Units Present in the System + ansible.builtin.command: + cmd: systemctl -q list-unit-files --type socket + register: result_systemd_unit_files + changed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002384 + - NIST-800-53-SC-7(10) + - disable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_systemd-coredump_disabled + +- name: Disable acquiring, saving, and processing core dumps - Ensure systemd-coredump.socket + is Masked + ansible.builtin.systemd: + name: systemd-coredump.socket + state: stopped + enabled: false + masked: true + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - result_systemd_unit_files.stdout_lines is search("systemd-coredump.socket") + tags: + - DISA-STIG-OL09-00-002384 + - NIST-800-53-SC-7(10) + - disable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_systemd-coredump_disabled + + + + + + + + + + Disable core dump backtraces + The ProcessSizeMax option in [Coredump] section +of /etc/systemd/coredump.conf +specifies the maximum size in bytes of a core which will be processed. +Core dumps exceeding this size may be stored, but the backtrace will not +be generated. + If the /etc/systemd/coredump.conf file +does not already contain the [Coredump] section, +the value will not be configured correctly. + CCI-000366 + CM-6 + Req-3.2 + SRG-OS-000480-GPOS-00227 + 3.3.1.1 + 3.3.1 + 3.3 + OL09-00-002381 + SV-271729r1091899_rule + A core dump includes a memory image taken at the time the operating system +terminates an application. The memory image could contain sensitive data +and is generally useful only for developers or system operators trying to +debug problems. + +Enabling core dumps on production systems is not recommended, +however there may be overriding operational requirements to enable advanced +debuging. Permitting temporary enablement of core dumps during such situations +should be reviewed through local needs and policy. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q systemd; then + +found=false + +# set value in all files if they contain section or key +for f in $(echo -n "/etc/systemd/coredump.conf"); do + if [ ! -e "$f" ]; then + continue + fi + + # find key in section and change value + if grep -qzosP "[[:space:]]*\[Coredump\]([^\n\[]*\n+)+?[[:space:]]*ProcessSizeMax" "$f"; then + + sed -i "s/ProcessSizeMax[^(\n)]*/ProcessSizeMax=0/" "$f" + + found=true + + # find section and add key = value to it + elif grep -qs "[[:space:]]*\[Coredump\]" "$f"; then + + sed -i "/[[:space:]]*\[Coredump\]/a ProcessSizeMax=0" "$f" + + found=true + fi +done + +# if section not in any file, append section with key = value to FIRST file in files parameter +if ! $found ; then + file=$(echo "/etc/systemd/coredump.conf" | cut -f1 -d ' ') + mkdir -p "$(dirname "$file")" + + echo -e "[Coredump]\nProcessSizeMax=0" >> "$file" + +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002381 + - NIST-800-53-CM-6 + - PCI-DSS-Req-3.2 + - PCI-DSSv4-3.3 + - PCI-DSSv4-3.3.1 + - PCI-DSSv4-3.3.1.1 + - coredump_disable_backtraces + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Set 'ProcessSizeMax' to '0' in the [Coredump] section of '/etc/systemd/coredump.conf' + ini_file: + path: /etc/systemd/coredump.conf + section: Coredump + option: ProcessSizeMax + value: '0' + create: true + mode: 420 + when: '"systemd" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-002381 + - NIST-800-53-CM-6 + - PCI-DSS-Req-3.2 + - PCI-DSSv4-3.3 + - PCI-DSSv4-3.3.1 + - PCI-DSSv4-3.3.1.1 + - coredump_disable_backtraces + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + + + + + + + + + + Disable storing core dump + The Storage option in [Coredump] sectionof /etc/systemd/coredump.conf +can be set to none to disable storing core dumps permanently. + If the /etc/systemd/coredump.conf file +does not already contain the [Coredump] section, +the value will not be configured correctly. + CCI-000366 + CM-6 + Req-3.2 + SRG-OS-000480-GPOS-00227 + 3.3.1.1 + 3.3.1 + 3.3 + OL09-00-002382 + SV-271730r1091902_rule + A core dump includes a memory image taken at the time the operating system +terminates an application. The memory image could contain sensitive data +and is generally useful only for developers or system operators trying to +debug problems. Enabling core dumps on production systems is not recommended, +however there may be overriding operational requirements to enable advanced +debuging. Permitting temporary enablement of core dumps during such situations +should be reviewed through local needs and policy. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q systemd; then + +found=false + +# set value in all files if they contain section or key +for f in $(echo -n "/etc/systemd/coredump.conf"); do + if [ ! -e "$f" ]; then + continue + fi + + # find key in section and change value + if grep -qzosP "[[:space:]]*\[Coredump\]([^\n\[]*\n+)+?[[:space:]]*Storage" "$f"; then + + sed -i "s/Storage[^(\n)]*/Storage=none/" "$f" + + found=true + + # find section and add key = value to it + elif grep -qs "[[:space:]]*\[Coredump\]" "$f"; then + + sed -i "/[[:space:]]*\[Coredump\]/a Storage=none" "$f" + + found=true + fi +done + +# if section not in any file, append section with key = value to FIRST file in files parameter +if ! $found ; then + file=$(echo "/etc/systemd/coredump.conf" | cut -f1 -d ' ') + mkdir -p "$(dirname "$file")" + + echo -e "[Coredump]\nStorage=none" >> "$file" + +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002382 + - NIST-800-53-CM-6 + - PCI-DSS-Req-3.2 + - PCI-DSSv4-3.3 + - PCI-DSSv4-3.3.1 + - PCI-DSSv4-3.3.1.1 + - coredump_disable_storage + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Set 'Storage' to 'none' in the [Coredump] section of '/etc/systemd/coredump.conf' + ini_file: + path: /etc/systemd/coredump.conf + section: Coredump + option: Storage + value: none + create: true + mode: 420 + when: '"systemd" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-002382 + - NIST-800-53-CM-6 + - PCI-DSS-Req-3.2 + - PCI-DSSv4-3.3 + - PCI-DSSv4-3.3.1 + - PCI-DSSv4-3.3.1.1 + - coredump_disable_storage + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + + + + + + + + + + Disable Core Dumps for All Users + To disable core dumps for all users, add the following line to +/etc/security/limits.conf, or to a file within the +/etc/security/limits.d/ directory: +* hard core 0 + + 1 + 12 + 13 + 15 + 16 + 2 + 7 + 8 + APO13.01 + BAI04.04 + DSS01.03 + DSS03.05 + DSS05.07 + CCI-000366 + SR 6.2 + SR 7.1 + SR 7.2 + A.12.1.3 + A.17.2.1 + CM-6 + SC-7(10) + DE.CM-1 + PR.DS-4 + SRG-OS-000480-GPOS-00227 + 3.3.1.1 + 3.3.1 + 3.3 + OL09-00-002383 + SV-271731r1091905_rule + A core dump includes a memory image taken at the time the operating system +terminates an application. The memory image could contain sensitive data and is generally useful +only for developers trying to debug problems. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q pam; then + +SECURITY_LIMITS_FILE="/etc/security/limits.conf" + +if grep -qE '^\s*\*\s+hard\s+core' $SECURITY_LIMITS_FILE; then + sed -ri 's/(hard\s+core\s+)[[:digit:]]+/\1 0/' $SECURITY_LIMITS_FILE +else + echo "* hard core 0" >> $SECURITY_LIMITS_FILE +fi + +if ls /etc/security/limits.d/*.conf > /dev/null; then + sed -ri '/^\s*\*\s+hard\s+core/d' /etc/security/limits.d/*.conf +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002383 + - NIST-800-53-CM-6 + - NIST-800-53-SC-7(10) + - PCI-DSSv4-3.3 + - PCI-DSSv4-3.3.1 + - PCI-DSSv4-3.3.1.1 + - disable_users_coredumps + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Disable core dumps with limits + lineinfile: + dest: /etc/security/limits.conf + regexp: ^[^#].*core + line: '* hard core 0' + create: true + when: '"pam" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-002383 + - NIST-800-53-CM-6 + - NIST-800-53-SC-7(10) + - PCI-DSSv4-3.3 + - PCI-DSSv4-3.3.1 + - PCI-DSSv4-3.3.1.1 + - disable_users_coredumps + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + + + + + + + + + + Disable Core Dumps for SUID programs + To set the runtime status of the fs.suid_dumpable kernel parameter, run the following command: $ sudo sysctl -w fs.suid_dumpable=0 +To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: fs.suid_dumpable = 0 + + 164.308(a)(1)(ii)(D) + 164.308(a)(3) + 164.308(a)(4) + 164.310(b) + 164.310(c) + 164.312(a) + 164.312(e) + SI-11(a) + SI-11(b) + R14 + A.8.SEC-OL6 + 3.3.1.1 + 3.3.1 + 3.3 + The core dump of a setuid program is more likely to contain +sensitive data, as the program itself runs with greater privileges than the +user who initiated execution of the program. Disabling the ability for any +setuid program to write a core file decreases the risk of unauthorized access +of such data. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Comment out any occurrences of fs.suid_dumpable from /etc/sysctl.d/*.conf files + +for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do + + + # skip systemd-sysctl symlink (/etc/sysctl.d/99-sysctl.conf -> /etc/sysctl.conf) + if [[ "$(readlink -f "$f")" == "/etc/sysctl.conf" ]]; then continue; fi + + matching_list=$(grep -P '^(?!#).*[\s]*fs.suid_dumpable.*$' $f | uniq ) + if ! test -z "$matching_list"; then + while IFS= read -r entry; do + escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") + # comment out "fs.suid_dumpable" matches to preserve user data + sed -i --follow-symlinks "s/^${escaped_entry}$/# &/g" $f + done <<< "$matching_list" + fi +done + +# +# Set sysctl config file which to save the desired value +# + +SYSCONFIG_FILE="/etc/sysctl.conf" + + +# +# Set runtime for fs.suid_dumpable +# +if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then + /sbin/sysctl -q -n -w fs.suid_dumpable="0" +fi + +# +# If fs.suid_dumpable present in /etc/sysctl.conf, change value to "0" +# else, add "fs.suid_dumpable = 0" to /etc/sysctl.conf +# + +# Strip any search characters in the key arg so that the key can be replaced without +# adding any search characters to the config file. +stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^fs.suid_dumpable") + +# shellcheck disable=SC2059 +printf -v formatted_output "%s = %s" "$stripped_key" "0" + +# If the key exists, change it. Otherwise, add it to the config_file. +# We search for the key string followed by a word boundary (matched by \>), +# so if we search for 'setting', 'setting2' won't match. +if LC_ALL=C grep -q -m 1 -i -e "^fs.suid_dumpable\\>" "${SYSCONFIG_FILE}"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + LC_ALL=C sed -i --follow-symlinks "s/^fs.suid_dumpable\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" +else + if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" + fi + printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-53-SI-11(a) + - NIST-800-53-SI-11(b) + - PCI-DSSv4-3.3 + - PCI-DSSv4-3.3.1 + - PCI-DSSv4-3.3.1.1 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_fs_suid_dumpable + +- name: List /etc/sysctl.d/*.conf files + find: + paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + contains: ^[\s]*fs.suid_dumpable.*$ + patterns: '*.conf' + file_type: any + register: find_sysctl_d + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-SI-11(a) + - NIST-800-53-SI-11(b) + - PCI-DSSv4-3.3 + - PCI-DSSv4-3.3.1 + - PCI-DSSv4-3.3.1.1 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_fs_suid_dumpable + +- name: Comment out any occurrences of fs.suid_dumpable from config files + replace: + path: '{{ item.path }}' + regexp: ^[\s]*fs.suid_dumpable + replace: '#fs.suid_dumpable' + loop: '{{ find_sysctl_d.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-SI-11(a) + - NIST-800-53-SI-11(b) + - PCI-DSSv4-3.3 + - PCI-DSSv4-3.3.1 + - PCI-DSSv4-3.3.1.1 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_fs_suid_dumpable + +- name: Ensure sysctl fs.suid_dumpable is set to 0 + sysctl: + name: fs.suid_dumpable + value: '0' + sysctl_file: /etc/sysctl.conf + state: present + reload: true + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-SI-11(a) + - NIST-800-53-SI-11(b) + - PCI-DSSv4-3.3 + - PCI-DSSv4-3.3.1 + - PCI-DSSv4-3.3.1.1 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_fs_suid_dumpable + + + + + + + + + + + Enable ExecShield + ExecShield describes kernel features that provide +protection against exploitation of memory corruption errors such as buffer +overflows. These features include random placement of the stack and other +memory regions, prevention of execution in memory that should only hold data, +and special handling of text buffers. These protections are enabled by default +on 32-bit systems and controlled through sysctl variables +kernel.exec-shield and kernel.randomize_va_space. On the latest +64-bit systems, kernel.exec-shield cannot be enabled or disabled with +sysctl. + + kernel.kptr_restrict + Configure exposition of kernel pointer addresses + 1 + 1 + 2 + + + Enable ExecShield via sysctl + By default on Oracle Linux 9 64-bit systems, ExecShield is +enabled and can only be disabled if the hardware does not support +ExecShield or is disabled in /etc/default/grub. + 12 + 15 + 8 + APO13.01 + DSS05.02 + 3.1.7 + CCI-002824 + 164.308(a)(1)(ii)(D) + 164.308(a)(3) + 164.308(a)(4) + 164.310(b) + 164.310(c) + 164.312(a) + 164.312(e) + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 7.1 + SR 7.6 + A.13.1.1 + A.13.2.1 + A.14.1.3 + SC-39 + CM-6(a) + PR.PT-4 + SRG-OS-000433-GPOS-00192 + OL09-00-002422 + SV-271760r1091992_rule + ExecShield uses the segmentation feature on all x86 systems to prevent +execution in memory higher than a certain address. It writes an address as +a limit in the code segment descriptor, to control where code can be +executed, on a per-process basis. When the kernel places a process's memory +regions such as the stack and heap higher than this address, the hardware +prevents execution in that address range. This is enabled by default on the +latest Red Hat and Fedora systems if supported by the hardware. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +grubby --update-kernel=ALL --remove-args=noexec + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002422 + - NIST-800-171-3.1.7 + - NIST-800-53-CM-6(a) + - NIST-800-53-SC-39 + - low_complexity + - low_disruption + - medium_severity + - reboot_required + - restrict_strategy + - sysctl_kernel_exec_shield + +- name: Update grub defaults and the bootloader menu + command: /sbin/grubby --update-kernel=ALL --remove-args="noexec" + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002422 + - NIST-800-171-3.1.7 + - NIST-800-53-CM-6(a) + - NIST-800-53-SC-39 + - low_complexity + - low_disruption + - medium_severity + - reboot_required + - restrict_strategy + - sysctl_kernel_exec_shield + + + + + + + + + + Restrict Exposed Kernel Pointer Addresses Access + To set the runtime status of the kernel.kptr_restrict kernel parameter, run the following command: $ sudo sysctl -w kernel.kptr_restrict= + +To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: kernel.kptr_restrict = + + + CCI-000366 + CCI-002824 + CCI-001082 + CIP-002-5 R1.1 + CIP-002-5 R1.2 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 4.1 + CIP-004-6 4.2 + CIP-004-6 R2.2.3 + CIP-004-6 R2.2.4 + CIP-004-6 R2.3 + CIP-004-6 R4 + CIP-005-6 R1 + CIP-005-6 R1.1 + CIP-005-6 R1.2 + CIP-007-3 R3 + CIP-007-3 R3.1 + CIP-007-3 R5.1 + CIP-007-3 R5.1.2 + CIP-007-3 R5.1.3 + CIP-007-3 R5.2.1 + CIP-007-3 R5.2.3 + CIP-007-3 R8.4 + CIP-009-6 R.1.1 + CIP-009-6 R4 + SC-30 + SC-30(2) + SC-30(5) + CM-6(a) + FMT_SMF_EXT.1 + SRG-OS-000132-GPOS-00067 + SRG-OS-000433-GPOS-00192 + SRG-OS-000480-GPOS-00227 + R9 + OL09-00-002408 + SV-271747r1091953_rule + Exposing kernel pointers (through procfs or seq_printf()) exposes kernel +writeable structures which may contain functions pointers. If a write vulnerability +occurs in the kernel, allowing write access to any of this structure, the kernel can +be compromised. This option disallow any program without the CAP_SYSLOG capability +to get the addresses of kernel pointers by replacing them with 0. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Comment out any occurrences of kernel.kptr_restrict from /etc/sysctl.d/*.conf files + +for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do + + + # skip systemd-sysctl symlink (/etc/sysctl.d/99-sysctl.conf -> /etc/sysctl.conf) + if [[ "$(readlink -f "$f")" == "/etc/sysctl.conf" ]]; then continue; fi + + matching_list=$(grep -P '^(?!#).*[\s]*kernel.kptr_restrict.*$' $f | uniq ) + if ! test -z "$matching_list"; then + while IFS= read -r entry; do + escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") + # comment out "kernel.kptr_restrict" matches to preserve user data + sed -i --follow-symlinks "s/^${escaped_entry}$/# &/g" $f + done <<< "$matching_list" + fi +done + +# +# Set sysctl config file which to save the desired value +# + +SYSCONFIG_FILE="/etc/sysctl.conf" + +sysctl_kernel_kptr_restrict_value='' + + +# +# Set runtime for kernel.kptr_restrict +# +if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then + /sbin/sysctl -q -n -w kernel.kptr_restrict="$sysctl_kernel_kptr_restrict_value" +fi + +# +# If kernel.kptr_restrict present in /etc/sysctl.conf, change value to appropriate value +# else, add "kernel.kptr_restrict = value" to /etc/sysctl.conf +# + +# Strip any search characters in the key arg so that the key can be replaced without +# adding any search characters to the config file. +stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^kernel.kptr_restrict") + +# shellcheck disable=SC2059 +printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_kernel_kptr_restrict_value" + +# If the key exists, change it. Otherwise, add it to the config_file. +# We search for the key string followed by a word boundary (matched by \>), +# so if we search for 'setting', 'setting2' won't match. +if LC_ALL=C grep -q -m 1 -i -e "^kernel.kptr_restrict\\>" "${SYSCONFIG_FILE}"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + LC_ALL=C sed -i --follow-symlinks "s/^kernel.kptr_restrict\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" +else + if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" + fi + printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002408 + - NIST-800-53-CM-6(a) + - NIST-800-53-SC-30 + - NIST-800-53-SC-30(2) + - NIST-800-53-SC-30(5) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_kptr_restrict + +- name: List /etc/sysctl.d/*.conf files + find: + paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + contains: ^[\s]*kernel.kptr_restrict.*$ + patterns: '*.conf' + file_type: any + register: find_sysctl_d + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002408 + - NIST-800-53-CM-6(a) + - NIST-800-53-SC-30 + - NIST-800-53-SC-30(2) + - NIST-800-53-SC-30(5) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_kptr_restrict + +- name: Comment out any occurrences of kernel.kptr_restrict from config files + replace: + path: '{{ item.path }}' + regexp: ^[\s]*kernel.kptr_restrict + replace: '#kernel.kptr_restrict' + loop: '{{ find_sysctl_d.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002408 + - NIST-800-53-CM-6(a) + - NIST-800-53-SC-30 + - NIST-800-53-SC-30(2) + - NIST-800-53-SC-30(5) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_kptr_restrict +- name: XCCDF Value sysctl_kernel_kptr_restrict_value # promote to variable + set_fact: + sysctl_kernel_kptr_restrict_value: !!str + tags: + - always + +- name: Ensure sysctl kernel.kptr_restrict is set + sysctl: + name: kernel.kptr_restrict + value: '{{ sysctl_kernel_kptr_restrict_value }}' + sysctl_file: /etc/sysctl.conf + state: present + reload: true + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002408 + - NIST-800-53-CM-6(a) + - NIST-800-53-SC-30 + - NIST-800-53-SC-30(2) + - NIST-800-53-SC-30(5) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_kptr_restrict + + + + + + + + + + Enable Randomized Layout of Virtual Address Space + To set the runtime status of the kernel.randomize_va_space kernel parameter, run the following command: $ sudo sysctl -w kernel.randomize_va_space=2 +To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: kernel.randomize_va_space = 2 + + 3.1.7 + CCI-000366 + CCI-002824 + 164.308(a)(1)(ii)(D) + 164.308(a)(3) + 164.308(a)(4) + 164.310(b) + 164.310(c) + 164.312(a) + 164.312(e) + CIP-002-5 R1.1 + CIP-002-5 R1.2 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 4.1 + CIP-004-6 4.2 + CIP-004-6 R2.2.3 + CIP-004-6 R2.2.4 + CIP-004-6 R2.3 + CIP-004-6 R4 + CIP-005-6 R1 + CIP-005-6 R1.1 + CIP-005-6 R1.2 + CIP-007-3 R3 + CIP-007-3 R3.1 + CIP-007-3 R5.1 + CIP-007-3 R5.1.2 + CIP-007-3 R5.1.3 + CIP-007-3 R5.2.1 + CIP-007-3 R5.2.3 + CIP-007-3 R8.4 + CIP-009-6 R.1.1 + CIP-009-6 R4 + SC-30 + SC-30(2) + CM-6(a) + Req-2.2.1 + SRG-OS-000433-GPOS-00193 + SRG-OS-000480-GPOS-00227 + SRG-APP-000450-CTR-001105 + R9 + 3.3.1.1 + 3.3.1 + 3.3 + OL09-00-002423 + SV-271761r1091995_rule + Address space layout randomization (ASLR) makes it more difficult for an +attacker to predict the location of attack code they have introduced into a +process's address space during an attempt at exploitation. Additionally, +ASLR makes it more difficult for an attacker to know the location of +existing code in order to re-purpose it using return oriented programming +(ROP) techniques. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Comment out any occurrences of kernel.randomize_va_space from /etc/sysctl.d/*.conf files + +for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do + + + # skip systemd-sysctl symlink (/etc/sysctl.d/99-sysctl.conf -> /etc/sysctl.conf) + if [[ "$(readlink -f "$f")" == "/etc/sysctl.conf" ]]; then continue; fi + + matching_list=$(grep -P '^(?!#).*[\s]*kernel.randomize_va_space.*$' $f | uniq ) + if ! test -z "$matching_list"; then + while IFS= read -r entry; do + escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") + # comment out "kernel.randomize_va_space" matches to preserve user data + sed -i --follow-symlinks "s/^${escaped_entry}$/# &/g" $f + done <<< "$matching_list" + fi +done + +# +# Set sysctl config file which to save the desired value +# + +SYSCONFIG_FILE="/etc/sysctl.conf" + + +# +# Set runtime for kernel.randomize_va_space +# +if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then + /sbin/sysctl -q -n -w kernel.randomize_va_space="2" +fi + +# +# If kernel.randomize_va_space present in /etc/sysctl.conf, change value to "2" +# else, add "kernel.randomize_va_space = 2" to /etc/sysctl.conf +# + +# Strip any search characters in the key arg so that the key can be replaced without +# adding any search characters to the config file. +stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^kernel.randomize_va_space") + +# shellcheck disable=SC2059 +printf -v formatted_output "%s = %s" "$stripped_key" "2" + +# If the key exists, change it. Otherwise, add it to the config_file. +# We search for the key string followed by a word boundary (matched by \>), +# so if we search for 'setting', 'setting2' won't match. +if LC_ALL=C grep -q -m 1 -i -e "^kernel.randomize_va_space\\>" "${SYSCONFIG_FILE}"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + LC_ALL=C sed -i --follow-symlinks "s/^kernel.randomize_va_space\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" +else + if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" + fi + printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002423 + - NIST-800-171-3.1.7 + - NIST-800-53-CM-6(a) + - NIST-800-53-SC-30 + - NIST-800-53-SC-30(2) + - PCI-DSS-Req-2.2.1 + - PCI-DSSv4-3.3 + - PCI-DSSv4-3.3.1 + - PCI-DSSv4-3.3.1.1 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_randomize_va_space + +- name: List /etc/sysctl.d/*.conf files + find: + paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + contains: ^[\s]*kernel.randomize_va_space.*$ + patterns: '*.conf' + file_type: any + register: find_sysctl_d + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002423 + - NIST-800-171-3.1.7 + - NIST-800-53-CM-6(a) + - NIST-800-53-SC-30 + - NIST-800-53-SC-30(2) + - PCI-DSS-Req-2.2.1 + - PCI-DSSv4-3.3 + - PCI-DSSv4-3.3.1 + - PCI-DSSv4-3.3.1.1 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_randomize_va_space + +- name: Comment out any occurrences of kernel.randomize_va_space from config files + replace: + path: '{{ item.path }}' + regexp: ^[\s]*kernel.randomize_va_space + replace: '#kernel.randomize_va_space' + loop: '{{ find_sysctl_d.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002423 + - NIST-800-171-3.1.7 + - NIST-800-53-CM-6(a) + - NIST-800-53-SC-30 + - NIST-800-53-SC-30(2) + - PCI-DSS-Req-2.2.1 + - PCI-DSSv4-3.3 + - PCI-DSSv4-3.3.1 + - PCI-DSSv4-3.3.1.1 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_randomize_va_space + +- name: Ensure sysctl kernel.randomize_va_space is set to 2 + sysctl: + name: kernel.randomize_va_space + value: '2' + sysctl_file: /etc/sysctl.conf + state: present + reload: true + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002423 + - NIST-800-171-3.1.7 + - NIST-800-53-CM-6(a) + - NIST-800-53-SC-30 + - NIST-800-53-SC-30(2) + - PCI-DSS-Req-2.2.1 + - PCI-DSSv4-3.3 + - PCI-DSSv4-3.3.1 + - PCI-DSSv4-3.3.1.1 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_randomize_va_space + + + + + + + + + + + Enable Execute Disable (XD) or No Execute (NX) Support on +x86 Systems + Recent processors in the x86 family support the +ability to prevent code execution on a per memory page basis. +Generically and on AMD processors, this ability is called No +Execute (NX), while on Intel processors it is called Execute +Disable (XD). This ability can help prevent exploitation of buffer +overflow vulnerabilities and should be activated whenever possible. +Extra steps must be taken to ensure that this protection is +enabled, particularly on 32-bit x86 systems. Other processors, such +as Itanium and POWER, have included such support since inception +and the standard kernel for those platforms supports the +feature. This is enabled by default on the latest Oracle Linux, Red Hat and +Fedora systems if supported by the hardware. + + Enable NX or XD Support in the BIOS + Reboot the system and enter the BIOS or Setup configuration menu. +Navigate the BIOS configuration menu and make sure that the option is enabled. The setting may be located +under a Security section. Look for Execute Disable (XD) on Intel-based systems and No Execute (NX) +on AMD-based systems. + 11 + 3 + 9 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + 3.1.7 + CCI-002824 + 4.3.4.3.2 + 4.3.4.3.3 + SR 7.6 + A.12.1.2 + A.12.5.1 + A.12.6.2 + A.14.2.2 + A.14.2.3 + A.14.2.4 + SC-39 + CM-6(a) + PR.IP-1 + SRG-OS-000433-GPOS-00192 + SRG-APP-000450-CTR-001105 + 2.2.1 + 2.2 + Computers with the ability to prevent this type of code execution frequently put an option in the BIOS that will +allow users to turn the feature on or off at will. + + + + + + + + + + + Memory Poisoning + Memory Poisoning consists of writing a special value to uninitialized or freed memory. +Poisoning can be used as a mechanism to prevent leak of information and detection of +corrupted memory. + + + slub_debug - debug options + Defines the debug options to use in slub_debug kernel command line argument. + P + F + Z + P + FZ + FZP + + + Enable page allocator poisoning + To enable poisoning of free pages, +add the argument page_poison=1 to the default +GRUB 2 command line for the Linux operating system. +To ensure that page_poison=1 is added as a kernel command line +argument to newly installed kernels, add page_poison=1 to the +default Grub2 command line for Linux operating systems. Modify the line within +/etc/default/grub as shown below: +GRUB_CMDLINE_LINUX="... page_poison=1 ..." +Run the following command to update command line for already installed kernels:# grubby --update-kernel=ALL --args="page_poison=1" + + CCI-000366 + CCI-001084 + CM-6(a) + SRG-OS-000480-GPOS-00227 + SRG-OS-000134-GPOS-00068 + R8 + OL09-00-002394 + SV-271738r1092600_rule + Poisoning writes an arbitrary value to freed pages, so any modification or +reference to that page after being freed or before being initialized will be +detected and prevented. +This prevents many types of use-after-free vulnerabilities at little performance cost. +Also prevents leak of data and detection of corrupted memory. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q grub2-common; }; then + +expected_value="1" + + +if [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; then + KARGS_DIR="/usr/lib/bootc/kargs.d/" + if grep -q -E "page_poison" "$KARGS_DIR/*.toml" ; then + sed -i -E "s/^(\s*kargs\s*=\s*\[.*)\"page_poison=[^\"]*\"(.*]\s*)/\1\"page_poison=$expected_value\"\2/" "$KARGS_DIR/*.toml" + else + echo "kargs = [\"page_poison=$expected_value\"]" >> "$KARGS_DIR/10-page_poison.toml" + fi +else + + grubby --update-kernel=ALL --args=page_poison=1 + +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002394 + - NIST-800-53-CM-6(a) + - grub2_page_poison_argument + - low_disruption + - medium_complexity + - medium_severity + - reboot_required + - restrict_strategy + +- name: Update grub defaults and the bootloader menu + command: /sbin/grubby --update-kernel=ALL --args="page_poison=1" + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"grub2-common" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-002394 + - NIST-800-53-CM-6(a) + - grub2_page_poison_argument + - low_disruption + - medium_complexity + - medium_severity + - reboot_required + - restrict_strategy + + [customizations.kernel] +append = "page_poison=1" + + + + + + + + + + Enable SLUB/SLAB allocator poisoning + To enable poisoning of SLUB/SLAB objects, +add the argument slub_debug= + to the default +GRUB 2 command line for the Linux operating system. +To ensure that slub_debug= + is added as a kernel command line +argument to newly installed kernels, add slub_debug= + to the +default Grub2 command line for Linux operating systems. Modify the line within +/etc/default/grub as shown below: +GRUB_CMDLINE_LINUX="... slub_debug= ..." +Run the following command to update command line for already installed kernels:# grubby --update-kernel=ALL --args="slub_debug=" + + CCI-002824 + CCI-001084 + CM-6(a) + SRG-OS-000433-GPOS-00192 + SRG-OS-000134-GPOS-00068 + R8 + OL09-00-002390 + SV-271734r1091914_rule + Poisoning writes an arbitrary value to freed objects, so any modification or +reference to that object after being freed or before being initialized will be +detected and prevented. +This prevents many types of use-after-free vulnerabilities at little performance cost. +Also prevents leak of data and detection of corrupted memory. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q grub2-common; }; then + +var_slub_debug_options='' + +expected_value="$var_slub_debug_options" + + +if [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; then + KARGS_DIR="/usr/lib/bootc/kargs.d/" + if grep -q -E "slub_debug" "$KARGS_DIR/*.toml" ; then + sed -i -E "s/^(\s*kargs\s*=\s*\[.*)\"slub_debug=[^\"]*\"(.*]\s*)/\1\"slub_debug=$expected_value\"\2/" "$KARGS_DIR/*.toml" + else + echo "kargs = [\"slub_debug=$expected_value\"]" >> "$KARGS_DIR/10-slub_debug.toml" + fi +else + + grubby --update-kernel=ALL --args=slub_debug=$var_slub_debug_options + +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002390 + - NIST-800-53-CM-6(a) + - grub2_slub_debug_argument + - low_disruption + - medium_complexity + - medium_severity + - reboot_required + - restrict_strategy +- name: XCCDF Value var_slub_debug_options # promote to variable + set_fact: + var_slub_debug_options: !!str + tags: + - always + +- name: Update grub defaults and the bootloader menu + command: /sbin/grubby --update-kernel=ALL --args="slub_debug={{ var_slub_debug_options + }}" + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"grub2-common" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-002390 + - NIST-800-53-CM-6(a) + - grub2_slub_debug_argument + - low_disruption + - medium_complexity + - medium_severity + - reboot_required + - restrict_strategy + + [customizations.kernel] +append = "slub_debug=" + + + + + + + + + + + + + + SELinux + SELinux is a feature of the Linux kernel which can be +used to guard against misconfigured or compromised programs. +SELinux enforces the idea that programs should be limited in what +files they can access and what actions they can take. + + +The default SELinux policy, as configured on Oracle Linux 9, has been +sufficiently developed and debugged that it should be usable on +almost any system with minimal configuration and a small +amount of system administrator training. This policy prevents +system services - including most of the common network-visible +services such as mail servers, FTP servers, and DNS servers - from +accessing files which those services have no valid reason to +access. This action alone prevents a huge amount of possible damage +from network attacks against services, from trojaned software, and +so forth. + + +This guide recommends that SELinux be enabled using the +default (targeted) policy on every Oracle Linux 9 system, unless that +system has unusual requirements which make a stronger policy +appropriate. + +For more information on SELinux, see https://docs.oracle.com/en/operating-systems/oracle-linux/selinux/. + + + SELinux policy + Type of policy in use. Possible values are: +targeted - Only targeted network daemons are protected. +strict - Full SELinux protection. +mls - Multiple levels of security + targeted + mls + targeted + + + SELinux state + enforcing - SELinux security policy is enforced. +permissive - SELinux prints warnings instead of enforcing. +disabled - SELinux is fully disabled. + enforcing + disabled + enforcing + permissive + + + Install libselinux Package + The libselinux package can be installed with the following command: + +$ sudo yum install libselinux + + A.6.SEC-OL1 + 1.2.6 + 1.2 + Security-enhanced Linux is a feature of the Linux kernel and a number of utilities +with enhanced security functionality designed to add mandatory access controls to Linux. + +The libselinux package contains the core library of the Security-enhanced Linux system. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +if ! rpm -q --quiet "libselinux" ; then + yum install -y "libselinux" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - PCI-DSSv4-1.2 + - PCI-DSSv4-1.2.6 + - enable_strategy + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - package_libselinux_installed + +- name: Ensure libselinux is installed + package: + name: libselinux + state: present + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - PCI-DSSv4-1.2 + - PCI-DSSv4-1.2.6 + - enable_strategy + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - package_libselinux_installed + + include install_libselinux + +class install_libselinux { + package { 'libselinux': + ensure => 'installed', + } +} + + +package --add=libselinux + + +[[packages]] +name = "libselinux" +version = "*" + + + + + + + + + + Install policycoreutils-python-utils package + The policycoreutils-python-utils package can be installed with the following command: + +$ sudo yum install policycoreutils-python-utils + + CCI-000366 + SRG-OS-000480-GPOS-00227 + OL09-00-000210 + SV-271468r1091116_rule + This package is required to operate and manage an SELinux environment and its policies. +It provides utilities such as semanage, audit2allow, audit2why, chcat and sandbox. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +if ! rpm -q --quiet "policycoreutils-python-utils" ; then + yum install -y "policycoreutils-python-utils" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-000210 + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - package_policycoreutils-python-utils_installed + +- name: Ensure policycoreutils-python-utils is installed + package: + name: policycoreutils-python-utils + state: present + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-000210 + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - package_policycoreutils-python-utils_installed + + include install_policycoreutils-python-utils + +class install_policycoreutils-python-utils { + package { 'policycoreutils-python-utils': + ensure => 'installed', + } +} + + +package --add=policycoreutils-python-utils + + +[[packages]] +name = "policycoreutils-python-utils" +version = "*" + + + + + + + + + + Install policycoreutils Package + The policycoreutils package can be installed with the following command: + +$ sudo yum install policycoreutils + + CCI-000366 + CCI-001084 + SRG-OS-000480-GPOS-00227 + SRG-OS-000134-GPOS-00068 + OL09-00-000200 + SV-271467r1091113_rule + Security-enhanced Linux is a feature of the Linux kernel and a number of utilities +with enhanced security functionality designed to add mandatory access controls to Linux. +The Security-enhanced Linux kernel contains new architectural components originally +developed to improve security of the Flask operating system. These architectural components +provide general support for the enforcement of many kinds of mandatory access control +policies, including those based on the concepts of Type Enforcement, Role-based Access +Control, and Multi-level Security. + +policycoreutils contains the policy core utilities that are required for +basic operation of an SELinux-enabled system. These utilities include load_policy +to load SELinux policies, setfiles to label filesystems, newrole to +switch roles, and so on. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +if ! rpm -q --quiet "policycoreutils" ; then + yum install -y "policycoreutils" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-000200 + - enable_strategy + - low_complexity + - low_disruption + - low_severity + - no_reboot_needed + - package_policycoreutils_installed + +- name: Ensure policycoreutils is installed + package: + name: policycoreutils + state: present + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-000200 + - enable_strategy + - low_complexity + - low_disruption + - low_severity + - no_reboot_needed + - package_policycoreutils_installed + + include install_policycoreutils + +class install_policycoreutils { + package { 'policycoreutils': + ensure => 'installed', + } +} + + +package --add=policycoreutils + + +[[packages]] +name = "policycoreutils" +version = "*" + + + + + + + + + + Uninstall setroubleshoot-plugins Package + The SETroubleshoot plugins are used to analyze SELinux AVC data. The service provides information around configuration errors, +unauthorized intrusions, and other potential errors. +The setroubleshoot-plugins package can be removed with the following command: + +$ sudo yum erase setroubleshoot-plugins + + R49 + The SETroubleshoot service is an unnecessary daemon to +have running on a server. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# CAUTION: This remediation script will remove setroubleshoot-plugins +# from the system, and may remove any packages +# that depend on setroubleshoot-plugins. Execute this +# remediation AFTER testing on a non-production +# system! + +if rpm -q --quiet "setroubleshoot-plugins" ; then +yum remove -y "setroubleshoot-plugins" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - disable_strategy + - low_complexity + - low_disruption + - low_severity + - no_reboot_needed + - package_setroubleshoot-plugins_removed + +- name: Ensure setroubleshoot-plugins is removed + package: + name: setroubleshoot-plugins + state: absent + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - low_disruption + - low_severity + - no_reboot_needed + - package_setroubleshoot-plugins_removed + + include remove_setroubleshoot-plugins + +class remove_setroubleshoot-plugins { + package { 'setroubleshoot-plugins': + ensure => 'purged', + } +} + + +package --remove=setroubleshoot-plugins + + + + + + + + + + Uninstall setroubleshoot-server Package + The SETroubleshoot service notifies desktop users of SELinux +denials. The service provides information around configuration errors, +unauthorized intrusions, and other potential errors. +The setroubleshoot-server package can be removed with the following command: + +$ sudo yum erase setroubleshoot-server + + R49 + The SETroubleshoot service is an unnecessary daemon to have +running on a server. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# CAUTION: This remediation script will remove setroubleshoot-server +# from the system, and may remove any packages +# that depend on setroubleshoot-server. Execute this +# remediation AFTER testing on a non-production +# system! + +if rpm -q --quiet "setroubleshoot-server" ; then +yum remove -y "setroubleshoot-server" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - disable_strategy + - low_complexity + - low_disruption + - low_severity + - no_reboot_needed + - package_setroubleshoot-server_removed + +- name: Ensure setroubleshoot-server is removed + package: + name: setroubleshoot-server + state: absent + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - low_disruption + - low_severity + - no_reboot_needed + - package_setroubleshoot-server_removed + + include remove_setroubleshoot-server + +class remove_setroubleshoot-server { + package { 'setroubleshoot-server': + ensure => 'purged', + } +} + + +package --remove=setroubleshoot-server + + + + + + + + + + Uninstall setroubleshoot Package + The SETroubleshoot service notifies desktop users of SELinux +denials. The service provides information around configuration errors, +unauthorized intrusions, and other potential errors. +The setroubleshoot package can be removed with the following command: + +$ sudo yum erase setroubleshoot + + R49 + The SETroubleshoot service is an unnecessary daemon to +have running on a server, especially if +X Windows is removed or disabled. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# CAUTION: This remediation script will remove setroubleshoot +# from the system, and may remove any packages +# that depend on setroubleshoot. Execute this +# remediation AFTER testing on a non-production +# system! + +if rpm -q --quiet "setroubleshoot" ; then +yum remove -y "setroubleshoot" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - disable_strategy + - low_complexity + - low_disruption + - low_severity + - no_reboot_needed + - package_setroubleshoot_removed + +- name: Ensure setroubleshoot is removed + package: + name: setroubleshoot + state: absent + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - low_disruption + - low_severity + - no_reboot_needed + - package_setroubleshoot_removed + + include remove_setroubleshoot + +class remove_setroubleshoot { + package { 'setroubleshoot': + ensure => 'purged', + } +} + + +package --remove=setroubleshoot + + + + + + + Verify Group Who Owns /etc/selinux Directory + To properly set the group owner of /etc/selinux, run the command: $ sudo chgrp root /etc/selinux + + R50 + The ownership of the /etc/selinux directory by the root group is important +because this directory hosts SELinux configuration. Protection of this +directory is critical for system security. Assigning the ownership to root +ensures exclusive control of the SELinux configuration. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +find -H /etc/selinux/ -maxdepth 1 -type d -exec chgrp -L root {} \; + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - configure_strategy + - directory_groupowner_etc_selinux + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure group owner on /etc/selinux/ + file: + path: /etc/selinux/ + state: directory + group: root + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - configure_strategy + - directory_groupowner_etc_selinux + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify User Who Owns /etc/selinux Directory + To properly set the owner of /etc/selinux, run the command: $ sudo chown root /etc/selinux + + R50 + The ownership of the /etc/selinux directory by the root user is important +because this directory hosts SELinux configuration. Protection of this +directory is critical for system security. Assigning the ownership to root +ensures exclusive control of the SELinux configuration. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +find -H /etc/selinux/ -maxdepth 1 -type d -exec chown -L 0 {} \; + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - configure_strategy + - directory_owner_etc_selinux + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure owner on directory /etc/selinux/ + file: + path: /etc/selinux/ + state: directory + owner: '0' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - configure_strategy + - directory_owner_etc_selinux + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify Permissions On /etc/selinux Directory + To properly set the permissions of /etc/selinux, run the command: $ sudo chmod 0755 /etc/selinux + + R50 + Setting correct permissions on the /etc/selinux directory is important +because this directory hosts SELinux configuration. Protection of this +directory is critical for system security. Restricting the permissions +ensures exclusive control of the SELinux configuration. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +find -H /etc/selinux/ -maxdepth 1 -perm /u+s,g+ws,o+wt -type d -exec chmod u-s,g-ws,o-wt {} \; + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - configure_strategy + - directory_permissions_etc_selinux + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Find /etc/selinux/ file(s) + command: 'find -H /etc/selinux/ -maxdepth 1 -perm /u+s,g+ws,o+wt -type d ' + register: files_found + changed_when: false + failed_when: false + check_mode: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - configure_strategy + - directory_permissions_etc_selinux + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Set permissions for /etc/selinux/ file(s) + file: + path: '{{ item }}' + mode: u-s,g-ws,o-wt + state: directory + with_items: + - '{{ files_found.stdout_lines }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - configure_strategy + - directory_permissions_etc_selinux + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify Group Who Owns /etc/sestatus.conf File + To properly set the group owner of /etc/sestatus.conf, run the command: $ sudo chgrp root /etc/sestatus.conf + + R50 + The ownership of the /etc/sestatus.conf file by the root group is important +because this file hosts SELinux configuration. Protection of this +file is critical for system security. Assigning the ownership to root +ensures exclusive control of the SELinux configuration. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +chgrp root /etc/sestatus.conf + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - configure_strategy + - file_groupowner_etc_sestatus_conf + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /etc/sestatus.conf + stat: + path: /etc/sestatus.conf + register: file_exists + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - configure_strategy + - file_groupowner_etc_sestatus_conf + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure group owner root on /etc/sestatus.conf + file: + path: /etc/sestatus.conf + group: root + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - file_exists.stat is defined and file_exists.stat.exists + tags: + - configure_strategy + - file_groupowner_etc_sestatus_conf + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify User Who Owns /etc/sestatus.conf File + To properly set the owner of /etc/sestatus.conf, run the command: $ sudo chown root /etc/sestatus.conf + + R50 + The ownership of the /etc/sestatus.conf file by the root user is important +because this file hosts SELinux configuration. Protection of this +file is critical for system security. Assigning the ownership to root +ensures exclusive control of the SELinux configuration. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +chown 0 /etc/sestatus.conf + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - configure_strategy + - file_owner_etc_sestatus_conf + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /etc/sestatus.conf + stat: + path: /etc/sestatus.conf + register: file_exists + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - configure_strategy + - file_owner_etc_sestatus_conf + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure owner 0 on /etc/sestatus.conf + file: + path: /etc/sestatus.conf + owner: '0' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - file_exists.stat is defined and file_exists.stat.exists + tags: + - configure_strategy + - file_owner_etc_sestatus_conf + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify Permissions On /etc/sestatus.conf File + To properly set the permissions of /etc/sestatus.conf, run the command: $ sudo chmod 0644 /etc/sestatus.conf + + R50 + Setting correct permissions on the /etc/sestatus.conf file is important +because this file hosts SELinux configuration. Protection of this +file is critical for system security. Restricting the permissions +ensures exclusive control of the SELinux configuration. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +chmod u-xs,g-xws,o-xwt /etc/sestatus.conf + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - configure_strategy + - file_permissions_etc_sestatus_conf + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /etc/sestatus.conf + stat: + path: /etc/sestatus.conf + register: file_exists + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - configure_strategy + - file_permissions_etc_sestatus_conf + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure permission u-xs,g-xws,o-xwt on /etc/sestatus.conf + file: + path: /etc/sestatus.conf + mode: u-xs,g-xws,o-xwt + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - file_exists.stat is defined and file_exists.stat.exists + tags: + - configure_strategy + - file_permissions_etc_sestatus_conf + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Ensure SELinux Not Disabled in /etc/default/grub + SELinux can be disabled at boot time by an argument in +/etc/default/grub. +Remove any instances of selinux=0 from the kernel arguments in that +file to prevent SELinux from being disabled at boot. + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 4 + 5 + 6 + 8 + 9 + APO01.06 + APO11.04 + APO13.01 + BAI03.05 + DSS01.05 + DSS03.01 + DSS05.02 + DSS05.04 + DSS05.05 + DSS05.07 + DSS06.02 + DSS06.03 + DSS06.06 + MEA02.01 + 3.1.2 + 3.7.2 + CCI-000022 + CCI-000032 + 164.308(a)(1)(ii)(D) + 164.308(a)(3) + 164.308(a)(4) + 164.310(b) + 164.310(c) + 164.312(a) + 164.312(e) + 4.2.3.4 + 4.3.3.2.2 + 4.3.3.3.9 + 4.3.3.4 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.4.7 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + 4.4.3.3 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 2.8 + SR 2.9 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 7.1 + SR 7.6 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.12.1.1 + A.12.1.2 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.13.1.1 + A.13.1.2 + A.13.1.3 + A.13.2.1 + A.13.2.2 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.1 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.2.3 + CIP-004-6 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.2 + CIP-007-3 R5.2 + CIP-007-3 R5.3.1 + CIP-007-3 R5.3.2 + CIP-007-3 R5.3.3 + AC-3 + AC-3(3)(a) + DE.AE-1 + ID.AM-3 + PR.AC-4 + PR.AC-5 + PR.AC-6 + PR.DS-5 + PR.PT-1 + PR.PT-3 + PR.PT-4 + A.6.SEC-OL1 + 1.2.6 + 1.2 + Disabling a major host protection feature, such as SELinux, at boot time prevents +it from confining system services at boot time. Further, it increases +the chances that it will remain off during system operation. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q grub2-common; }; then + +sed -i --follow-symlinks "s/selinux=0//gI" /etc/default/grub /etc/grub2.cfg /etc/grub.d/* +sed -i --follow-symlinks "s/enforcing=0//gI" /etc/default/grub /etc/grub2.cfg /etc/grub.d/* + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-171-3.1.2 + - NIST-800-171-3.7.2 + - NIST-800-53-AC-3 + - NIST-800-53-AC-3(3)(a) + - PCI-DSSv4-1.2 + - PCI-DSSv4-1.2.6 + - grub2_enable_selinux + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure SELinux Not Disabled in /etc/default/grub - Find /etc/grub.d/ files + ansible.builtin.find: + paths: + - /etc/grub.d/ + follow: true + register: result_grub_d + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"grub2-common" in ansible_facts.packages' + tags: + - NIST-800-171-3.1.2 + - NIST-800-171-3.7.2 + - NIST-800-53-AC-3 + - NIST-800-53-AC-3(3)(a) + - PCI-DSSv4-1.2 + - PCI-DSSv4-1.2.6 + - grub2_enable_selinux + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure SELinux Not Disabled in /etc/default/grub - Ensure SELinux Not Disabled + in /etc/grub.d/ files + ansible.builtin.replace: + dest: '{{ item.path }}' + regexp: (selinux|enforcing)=0 + with_items: + - '{{ result_grub_d.files }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"grub2-common" in ansible_facts.packages' + tags: + - NIST-800-171-3.1.2 + - NIST-800-171-3.7.2 + - NIST-800-53-AC-3 + - NIST-800-53-AC-3(3)(a) + - PCI-DSSv4-1.2 + - PCI-DSSv4-1.2.6 + - grub2_enable_selinux + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure SELinux Not Disabled in /etc/default/grub - Check if /etc/grub2.cfg + exists + ansible.builtin.stat: + path: /etc/grub2.cfg + register: result_grub2_cfg_present + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"grub2-common" in ansible_facts.packages' + tags: + - NIST-800-171-3.1.2 + - NIST-800-171-3.7.2 + - NIST-800-53-AC-3 + - NIST-800-53-AC-3(3)(a) + - PCI-DSSv4-1.2 + - PCI-DSSv4-1.2.6 + - grub2_enable_selinux + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure SELinux Not Disabled in /etc/default/grub - Check if /etc/default/grub + exists + ansible.builtin.stat: + path: /etc/default/grub + register: result_default_grub_present + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"grub2-common" in ansible_facts.packages' + tags: + - NIST-800-171-3.1.2 + - NIST-800-171-3.7.2 + - NIST-800-53-AC-3 + - NIST-800-53-AC-3(3)(a) + - PCI-DSSv4-1.2 + - PCI-DSSv4-1.2.6 + - grub2_enable_selinux + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure SELinux Not Disabled in /etc/default/grub - Ensure SELinux Not Disabled + in /etc/grub2.cfg + ansible.builtin.replace: + dest: /etc/grub2.cfg + regexp: (selinux|enforcing)=0 + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"grub2-common" in ansible_facts.packages' + - result_grub2_cfg_present.stat.exists + tags: + - NIST-800-171-3.1.2 + - NIST-800-171-3.7.2 + - NIST-800-53-AC-3 + - NIST-800-53-AC-3(3)(a) + - PCI-DSSv4-1.2 + - PCI-DSSv4-1.2.6 + - grub2_enable_selinux + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure SELinux Not Disabled in /etc/default/grub - Ensure SELinux Not Disabled + in /etc/default/grub + ansible.builtin.replace: + dest: /etc/default/grub + regexp: (selinux|enforcing)=0 + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"grub2-common" in ansible_facts.packages' + - result_default_grub_present.stat.exists + tags: + - NIST-800-171-3.1.2 + - NIST-800-171-3.7.2 + - NIST-800-53-AC-3 + - NIST-800-53-AC-3(3)(a) + - PCI-DSSv4-1.2 + - PCI-DSSv4-1.2.6 + - grub2_enable_selinux + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + + + + + + + + + + Ensure No Device Files are Unlabeled by SELinux + Device files, which are used for communication with important system +resources, should be labeled with proper SELinux types. If any device files +carry the SELinux type device_t or unlabeled_t, report the +bug so that policy can be corrected. Supply information about what the +device is and what programs use it. + + +To check for incorrectly labeled device files, run following commands: +$ sudo find /dev -context *:device_t:* \( -type c -o -type b \) -printf "%p %Z\n" + $ sudo find /dev -context *:unlabeled_t:* \( -type c -o -type b \) -printf "%p %Z\n" +It should produce no output in a well-configured system. + Automatic remediation of this control is not available. The remediation +can be achieved by amending SELinux policy. + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 18 + 2 + 3 + 5 + 6 + 7 + 8 + 9 + APO01.06 + APO11.04 + BAI01.06 + BAI03.05 + BAI06.01 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS01.03 + DSS03.05 + DSS05.02 + DSS05.04 + DSS05.05 + DSS05.07 + DSS06.02 + DSS06.06 + MEA02.01 + 3.1.2 + 3.1.5 + 3.7.2 + CCI-000366 + 4.3.3.3.9 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.2 + 4.3.4.3.3 + 4.3.4.4.7 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 2.8 + SR 2.9 + SR 5.2 + SR 6.2 + SR 7.6 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.12.1.2 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.5.1 + A.12.6.2 + A.12.7.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.14.2.7 + A.15.2.1 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CM-7(a) + CM-7(b) + CM-6(a) + AC-3(3)(a) + AC-6 + DE.CM-1 + DE.CM-7 + PR.AC-4 + PR.DS-5 + PR.IP-1 + PR.IP-3 + PR.PT-1 + PR.PT-3 + SRG-OS-000480-GPOS-00227 + OL09-00-002500 + SV-271769r1092019_rule + If a device file carries the SELinux type device_t or +unlabeled_t, then SELinux cannot properly restrict access to the +device file. + + + + + + + + + Ensure No Daemons are Unconfined by SELinux + Daemons for which the SELinux policy does not contain rules will inherit the +context of the parent process. Because daemons are launched during +startup and descend from the init process, they inherit the unconfined_service_t context. + + +To check for unconfined daemons, run the following command: +$ sudo ps -eZ | grep "unconfined_service_t" +It should produce no output in a well-configured system. + Automatic remediation of this control is not available. Remediation +can be achieved by amending SELinux policy or stopping the unconfined +daemons as outlined above. + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + 6 + 9 + APO01.06 + APO11.04 + BAI03.05 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS05.02 + DSS05.04 + DSS05.05 + DSS05.07 + DSS06.02 + DSS06.06 + MEA02.01 + 3.1.2 + 3.1.5 + 3.7.2 + 164.308(a)(1)(ii)(D) + 164.308(a)(3) + 164.308(a)(4) + 164.310(b) + 164.310(c) + 164.312(a) + 164.312(e) + 4.3.3.3.9 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.2 + 4.3.4.3.3 + 4.3.4.4.7 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 2.8 + SR 2.9 + SR 5.2 + SR 7.6 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.12.1.2 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.5.1 + A.12.6.2 + A.12.7.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 + CM-7(a) + CM-7(b) + CM-6(a) + AC-3(3)(a) + AC-6 + PR.AC-4 + PR.DS-5 + PR.IP-1 + PR.PT-1 + PR.PT-3 + 1.2.6 + 1.2 + Daemons which run with the unconfined_service_t context may cause AVC denials, +or allow privileges that the daemon does not require. + + + + + + + + + Ensure SELinux is Not Disabled + The SELinux state should be set to enforcing or permissive at system boot +time. In the file /etc/selinux/config, add or correct the following line to configure +the system to boot into enforcing or permissive mode: +SELINUX=enforcing +OR +SELINUX=permissive + + In case the SELinux is "disabled", the automated remediation will adopt a more +conservative approach and set it to "permissive" in order to avoid any system disruption +and give the administrator the opportunity to assess the impact and necessary efforts +before setting it to "enforcing", which is strongly recommended. + Running SELinux in disabled mode is strongly discouraged. It prevents enforcing the SELinux +controls without a system reboot. It also avoids labeling any persistent objects such as +files, making it difficult to enable SELinux in the future. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +if [ -e "/etc/selinux/config" ] ; then + + LC_ALL=C sed -i "/^SELINUX=/Id" "/etc/selinux/config" +else + touch "/etc/selinux/config" +fi +# make sure file has newline at the end +sed -i -e '$a\' "/etc/selinux/config" + +cp "/etc/selinux/config" "/etc/selinux/config.bak" +# Insert at the end of the file +printf '%s\n' "SELINUX=permissive" >> "/etc/selinux/config" +# Clean up after ourselves. +rm "/etc/selinux/config.bak" + +fixfiles onboot +fixfiles -f relabel + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - high_severity + - low_complexity + - low_disruption + - reboot_required + - restrict_strategy + - selinux_not_disabled + +- name: Ensure SELinux is Not Disabled + block: + + - name: Check for duplicate values + lineinfile: + path: /etc/selinux/config + create: true + regexp: (?i)^SELINUX= + state: absent + check_mode: true + changed_when: false + register: dupes + + - name: Deduplicate values from /etc/selinux/config + lineinfile: + path: /etc/selinux/config + create: true + regexp: (?i)^SELINUX= + state: absent + when: dupes.found is defined and dupes.found > 1 + + - name: Insert correct line to /etc/selinux/config + lineinfile: + path: /etc/selinux/config + create: true + regexp: (?i)^SELINUX= + line: SELINUX=permissive + state: present + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - high_severity + - low_complexity + - low_disruption + - reboot_required + - restrict_strategy + - selinux_not_disabled + + + + + + + + + + Configure SELinux Policy + The SELinux targeted policy is appropriate for +general-purpose desktops and servers, as well as systems in many other roles. +To configure the system to use this policy, add or correct the following line +in /etc/selinux/config: +SELINUXTYPE= + +Other policies, such as mls, provide additional security labeling +and greater confinement but are not compatible with many general-purpose +use cases. + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 4 + 5 + 6 + 8 + 9 + APO01.06 + APO11.04 + APO13.01 + BAI03.05 + DSS01.05 + DSS03.01 + DSS05.02 + DSS05.04 + DSS05.05 + DSS05.07 + DSS06.02 + DSS06.03 + DSS06.06 + MEA02.01 + 3.1.2 + 3.7.2 + CCI-002696 + 164.308(a)(1)(ii)(D) + 164.308(a)(3) + 164.308(a)(4) + 164.310(b) + 164.310(c) + 164.312(a) + 164.312(e) + 4.2.3.4 + 4.3.3.2.2 + 4.3.3.3.9 + 4.3.3.4 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.4.7 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + 4.4.3.3 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 2.8 + SR 2.9 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 7.1 + SR 7.6 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.12.1.1 + A.12.1.2 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.13.1.1 + A.13.1.2 + A.13.1.3 + A.13.2.1 + A.13.2.2 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.1 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CIP-003-8 R5.1.1 + CIP-003-8 R5.2 + CIP-003-8 R5.3 + CIP-004-6 R2.2.3 + CIP-004-6 R2.3 + CIP-004-6 R3.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.2 + CIP-007-3 R5.2 + CIP-007-3 R5.3.1 + CIP-007-3 R5.3.2 + CIP-007-3 R5.3.3 + CIP-007-3 R6.5 + AC-3 + AC-3(3)(a) + AU-9 + SC-7(21) + DE.AE-1 + ID.AM-3 + PR.AC-4 + PR.AC-5 + PR.AC-6 + PR.DS-5 + PR.PT-1 + PR.PT-3 + PR.PT-4 + FMT_MOF_EXT.1 + SRG-OS-000445-GPOS-00199 + SRG-APP-000233-CTR-000585 + R46 + R64 + APP.4.4.A4 + SYS.1.6.A3 + SYS.1.6.A18 + SYS.1.6.A21 + A.6.SEC-OL1 + 1.2.6 + 1.2 + OL09-00-000065 + SV-271453r1091071_rule + Setting the SELinux policy to targeted or a more specialized policy +ensures the system will confine processes that are likely to be +targeted for exploitation, such as network or system services. + + +Note: During the development or debugging of SELinux modules, it is common to +temporarily place non-production systems in permissive mode. In such +temporary cases, SELinux policies should be developed, and once work +is completed, the system should be reconfigured to +. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +var_selinux_policy_name='' + + +if [ -e "/etc/selinux/config" ] ; then + + LC_ALL=C sed -i "/^SELINUXTYPE=/Id" "/etc/selinux/config" +else + touch "/etc/selinux/config" +fi +# make sure file has newline at the end +sed -i -e '$a\' "/etc/selinux/config" + +cp "/etc/selinux/config" "/etc/selinux/config.bak" +# Insert at the end of the file +printf '%s\n' "SELINUXTYPE=$var_selinux_policy_name" >> "/etc/selinux/config" +# Clean up after ourselves. +rm "/etc/selinux/config.bak" + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-000065 + - NIST-800-171-3.1.2 + - NIST-800-171-3.7.2 + - NIST-800-53-AC-3 + - NIST-800-53-AC-3(3)(a) + - NIST-800-53-AU-9 + - NIST-800-53-SC-7(21) + - PCI-DSSv4-1.2 + - PCI-DSSv4-1.2.6 + - low_complexity + - low_disruption + - medium_severity + - reboot_required + - restrict_strategy + - selinux_policytype +- name: XCCDF Value var_selinux_policy_name # promote to variable + set_fact: + var_selinux_policy_name: !!str + tags: + - always + +- name: Configure SELinux Policy + block: + + - name: Check for duplicate values + lineinfile: + path: /etc/selinux/config + create: true + regexp: (?i)^SELINUXTYPE= + state: absent + check_mode: true + changed_when: false + register: dupes + + - name: Deduplicate values from /etc/selinux/config + lineinfile: + path: /etc/selinux/config + create: true + regexp: (?i)^SELINUXTYPE= + state: absent + when: dupes.found is defined and dupes.found > 1 + + - name: Insert correct line to /etc/selinux/config + lineinfile: + path: /etc/selinux/config + create: true + regexp: (?i)^SELINUXTYPE= + line: SELINUXTYPE={{ var_selinux_policy_name }} + state: present + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-000065 + - NIST-800-171-3.1.2 + - NIST-800-171-3.7.2 + - NIST-800-53-AC-3 + - NIST-800-53-AC-3(3)(a) + - NIST-800-53-AU-9 + - NIST-800-53-SC-7(21) + - PCI-DSSv4-1.2 + - PCI-DSSv4-1.2.6 + - low_complexity + - low_disruption + - medium_severity + - reboot_required + - restrict_strategy + - selinux_policytype + + + + + + + + + + + Ensure SELinux State is Enforcing + The SELinux state should be set to at +system boot time. In the file /etc/selinux/config, add or correct the +following line to configure the system to boot into enforcing mode: +SELINUX= + + + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 4 + 5 + 6 + 8 + 9 + APO01.06 + APO11.04 + APO13.01 + BAI03.05 + DSS01.05 + DSS03.01 + DSS05.02 + DSS05.04 + DSS05.05 + DSS05.07 + DSS06.02 + DSS06.03 + DSS06.06 + MEA02.01 + 3.1.2 + 3.7.2 + CCI-002696 + CCI-001084 + 164.308(a)(1)(ii)(D) + 164.308(a)(3) + 164.308(a)(4) + 164.310(b) + 164.310(c) + 164.312(a) + 164.312(e) + 4.2.3.4 + 4.3.3.2.2 + 4.3.3.3.9 + 4.3.3.4 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.4.7 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + 4.4.3.3 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 2.8 + SR 2.9 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 7.1 + SR 7.6 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.12.1.1 + A.12.1.2 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.13.1.1 + A.13.1.2 + A.13.1.3 + A.13.2.1 + A.13.2.2 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.1 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CIP-003-8 R5.1.1 + CIP-003-8 R5.2 + CIP-003-8 R5.3 + CIP-004-6 R2.2.3 + CIP-004-6 R2.3 + CIP-004-6 R3.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.2 + CIP-007-3 R5.2 + CIP-007-3 R5.3.1 + CIP-007-3 R5.3.2 + CIP-007-3 R5.3.3 + CIP-007-3 R6.5 + AC-3 + AC-3(3)(a) + AU-9 + SC-7(21) + DE.AE-1 + ID.AM-3 + PR.AC-4 + PR.AC-5 + PR.AC-6 + PR.DS-5 + PR.PT-1 + PR.PT-3 + PR.PT-4 + FMT_MOF_EXT.1 + SRG-OS-000445-GPOS-00199 + SRG-OS-000134-GPOS-00068 + R37 + R79 + APP.4.4.A4 + SYS.1.6.A3 + SYS.1.6.A18 + SYS.1.6.A21 + A.6.SEC-OL1 + 1.2.6 + 1.2 + OL09-00-000060 + SV-271452r1091068_rule + Setting the SELinux state to enforcing ensures SELinux is able to confine +potentially compromised processes to the security policy, which is designed to +prevent them from causing damage to the system or further elevating their +privileges. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +var_selinux_state='' + + +if [ -e "/etc/selinux/config" ] ; then + + LC_ALL=C sed -i "/^SELINUX=/Id" "/etc/selinux/config" +else + touch "/etc/selinux/config" +fi +# make sure file has newline at the end +sed -i -e '$a\' "/etc/selinux/config" + +cp "/etc/selinux/config" "/etc/selinux/config.bak" +# Insert at the end of the file +printf '%s\n' "SELINUX=$var_selinux_state" >> "/etc/selinux/config" +# Clean up after ourselves. +rm "/etc/selinux/config.bak" + +fixfiles onboot +fixfiles -f relabel + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-000060 + - NIST-800-171-3.1.2 + - NIST-800-171-3.7.2 + - NIST-800-53-AC-3 + - NIST-800-53-AC-3(3)(a) + - NIST-800-53-AU-9 + - NIST-800-53-SC-7(21) + - PCI-DSSv4-1.2 + - PCI-DSSv4-1.2.6 + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - restrict_strategy + - selinux_state +- name: XCCDF Value var_selinux_state # promote to variable + set_fact: + var_selinux_state: !!str + tags: + - always + +- name: Ensure SELinux State is Enforcing + block: + + - name: Check for duplicate values + lineinfile: + path: /etc/selinux/config + create: true + regexp: (?i)^SELINUX= + state: absent + check_mode: true + changed_when: false + register: dupes + + - name: Deduplicate values from /etc/selinux/config + lineinfile: + path: /etc/selinux/config + create: true + regexp: (?i)^SELINUX= + state: absent + when: dupes.found is defined and dupes.found > 1 + + - name: Insert correct line to /etc/selinux/config + lineinfile: + path: /etc/selinux/config + create: true + regexp: (?i)^SELINUX= + line: SELINUX={{ var_selinux_state }} + state: present + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-000060 + - NIST-800-171-3.1.2 + - NIST-800-171-3.7.2 + - NIST-800-53-AC-3 + - NIST-800-53-AC-3(3)(a) + - NIST-800-53-AU-9 + - NIST-800-53-SC-7(21) + - PCI-DSSv4-1.2 + - PCI-DSSv4-1.2.6 + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - restrict_strategy + - selinux_state + + + + + + + + + + + SELinux - Booleans + Enable or Disable runtime customization of SELinux system policies +without having to reload or recompile the SELinux policy. + + + auditadm_exec_content SELinux Boolean + default - Default SELinux boolean setting. +on - SELinux boolean is enabled. +off - SELinux boolean is disabled. + true + false + true + + + authlogin_nsswitch_use_ldap SELinux Boolean + default - Default SELinux boolean setting. +on - SELinux boolean is enabled. +off - SELinux boolean is disabled. + false + false + true + + + authlogin_radius SELinux Boolean + default - Default SELinux boolean setting. +on - SELinux boolean is enabled. +off - SELinux boolean is disabled. + false + false + true + + + deny_execmem SELinux Boolean + default - Default SELinux boolean setting. +on - SELinux boolean is enabled. +off - SELinux boolean is disabled. + false + false + true + + + kerberos_enabled SELinux Boolean + default - Default SELinux boolean setting. +on - SELinux boolean is enabled. +off - SELinux boolean is disabled. + true + false + true + + + polyinstantiation_enabled SELinux Boolean + default - Default SELinux boolean setting. +on - SELinux boolean is enabled. +off - SELinux boolean is disabled. + false + false + true + + + secure_mode_insmod SELinux Boolean + default - Default SELinux boolean setting. +on - SELinux boolean is enabled. +off - SELinux boolean is disabled. + false + false + true + + + selinuxuser_execheap SELinux Boolean + default - Default SELinux boolean setting. +on - SELinux boolean is enabled. +off - SELinux boolean is disabled. + false + false + true + + + selinuxuser_execmod SELinux Boolean + default - Default SELinux boolean setting. +on - SELinux boolean is enabled. +off - SELinux boolean is disabled. + true + false + true + + + selinuxuser_execstack SELinux Boolean + default - Default SELinux boolean setting. +on - SELinux boolean is enabled. +off - SELinux boolean is disabled. + false + false + true + + + ssh_sysadm_login SELinux Boolean + default - Default SELinux boolean setting. +on - SELinux boolean is enabled. +off - SELinux boolean is disabled. + false + false + true + + + Enable the auditadm_exec_content SELinux Boolean + By default, the SELinux boolean auditadm_exec_content is enabled. +If this setting is disabled, it should be enabled. + +To enable the auditadm_exec_content SELinux boolean, run the following command: +$ sudo setsebool -P auditadm_exec_content on + + 80424-5 + 0582 + 0584 + 05885 + 0586 + 0846 + 0957 + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +if ! rpm -q --quiet "python3-libsemanage" ; then + yum install -y "python3-libsemanage" +fi + + +if selinuxenabled || [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; then + + var_auditadm_exec_content='' + + setsebool -P auditadm_exec_content $var_auditadm_exec_content + +else + echo "Skipping remediation, SELinux is disabled"; + false +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-171-80424-5 + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - sebool_auditadm_exec_content + +- name: Enable the auditadm_exec_content SELinux Boolean - Ensure python3-libsemanage + Installed + package: + name: python3-libsemanage + state: present + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-171-80424-5 + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - sebool_auditadm_exec_content +- name: XCCDF Value var_auditadm_exec_content # promote to variable + set_fact: + var_auditadm_exec_content: !!str + tags: + - always + +- name: Enable the auditadm_exec_content SELinux Boolean - Set SELinux Boolean auditadm_exec_content + Accordingly + seboolean: + name: auditadm_exec_content + state: '{{ var_auditadm_exec_content }}' + persistent: true + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - ansible_facts.selinux.status == 'enabled' + tags: + - NIST-800-171-80424-5 + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - sebool_auditadm_exec_content + + + + + + + + + + + Disable the authlogin_nsswitch_use_ldap SELinux Boolean + By default, the SELinux boolean authlogin_nsswitch_use_ldap is disabled. +If this setting is enabled, it should be disabled. + +To disable the authlogin_nsswitch_use_ldap SELinux boolean, run the following command: +$ sudo setsebool -P authlogin_nsswitch_use_ldap off + + 3.7.2 + 0421 + 0422 + 0431 + 0974 + 1173 + 1401 + 1504 + 1505 + 1546 + 1557 + 1558 + 1559 + 1560 + 1561 + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +if ! rpm -q --quiet "python3-libsemanage" ; then + yum install -y "python3-libsemanage" +fi + + +if selinuxenabled || [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; then + + var_authlogin_nsswitch_use_ldap='' + + setsebool -P authlogin_nsswitch_use_ldap $var_authlogin_nsswitch_use_ldap + +else + echo "Skipping remediation, SELinux is disabled"; + false +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-171-3.7.2 + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - sebool_authlogin_nsswitch_use_ldap + +- name: Disable the authlogin_nsswitch_use_ldap SELinux Boolean - Ensure python3-libsemanage + Installed + package: + name: python3-libsemanage + state: present + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-171-3.7.2 + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - sebool_authlogin_nsswitch_use_ldap +- name: XCCDF Value var_authlogin_nsswitch_use_ldap # promote to variable + set_fact: + var_authlogin_nsswitch_use_ldap: !!str + tags: + - always + +- name: Disable the authlogin_nsswitch_use_ldap SELinux Boolean - Set SELinux Boolean + authlogin_nsswitch_use_ldap Accordingly + seboolean: + name: authlogin_nsswitch_use_ldap + state: '{{ var_authlogin_nsswitch_use_ldap }}' + persistent: true + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - ansible_facts.selinux.status == 'enabled' + tags: + - NIST-800-171-3.7.2 + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - sebool_authlogin_nsswitch_use_ldap + + + + + + + + + + + Disable the authlogin_radius SELinux Boolean + By default, the SELinux boolean authlogin_radius is disabled. +If this setting is enabled, it should be disabled. + +To disable the authlogin_radius SELinux boolean, run the following command: +$ sudo setsebool -P authlogin_radius off + + 3.7.2 + 0421 + 0422 + 0431 + 0974 + 1173 + 1401 + 1504 + 1505 + 1546 + 1557 + 1558 + 1559 + 1560 + 1561 + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +if ! rpm -q --quiet "python3-libsemanage" ; then + yum install -y "python3-libsemanage" +fi + + +if selinuxenabled || [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; then + + var_authlogin_radius='' + + setsebool -P authlogin_radius $var_authlogin_radius + +else + echo "Skipping remediation, SELinux is disabled"; + false +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-171-3.7.2 + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - sebool_authlogin_radius + +- name: Disable the authlogin_radius SELinux Boolean - Ensure python3-libsemanage + Installed + package: + name: python3-libsemanage + state: present + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-171-3.7.2 + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - sebool_authlogin_radius +- name: XCCDF Value var_authlogin_radius # promote to variable + set_fact: + var_authlogin_radius: !!str + tags: + - always + +- name: Disable the authlogin_radius SELinux Boolean - Set SELinux Boolean authlogin_radius + Accordingly + seboolean: + name: authlogin_radius + state: '{{ var_authlogin_radius }}' + persistent: true + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - ansible_facts.selinux.status == 'enabled' + tags: + - NIST-800-171-3.7.2 + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - sebool_authlogin_radius + + + + + + + + + + + Configure the deny_execmem SELinux Boolean + By default, the SELinux boolean deny_execmem is disabled. +This setting should be configured to . + +To set the deny_execmem SELinux boolean, run the following command: +$ sudo setsebool -P deny_execmem + + + This rule doesn't come with a remediation, as enabling this SELinux boolean can cause +applications to malfunction, for example Graphical login managers and Firefox. + Proper function and stability should be assessed before applying enabling the SELinux +boolean in production systems. + R48 + Allowing user domain applications to map a memory region as both writable and +executable makes them more susceptible to data execution attacks. + + + + + + + + + + Enable the kerberos_enabled SELinux Boolean + By default, the SELinux boolean kerberos_enabled is enabled. +If this setting is disabled, it should be enabled to allow confined +applications to run with Kerberos. + +To enable the kerberos_enabled SELinux boolean, run the following command: +$ sudo setsebool -P kerberos_enabled on + + 0418 + 1055 + 1402 + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +if ! rpm -q --quiet "python3-libsemanage" ; then + yum install -y "python3-libsemanage" +fi + + +if selinuxenabled || [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; then + + var_kerberos_enabled='' + + setsebool -P kerberos_enabled $var_kerberos_enabled + +else + echo "Skipping remediation, SELinux is disabled"; + false +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - sebool_kerberos_enabled + +- name: Enable the kerberos_enabled SELinux Boolean - Ensure python3-libsemanage Installed + package: + name: python3-libsemanage + state: present + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - sebool_kerberos_enabled +- name: XCCDF Value var_kerberos_enabled # promote to variable + set_fact: + var_kerberos_enabled: !!str + tags: + - always + +- name: Enable the kerberos_enabled SELinux Boolean - Set SELinux Boolean kerberos_enabled + Accordingly + seboolean: + name: kerberos_enabled + state: '{{ var_kerberos_enabled }}' + persistent: true + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - ansible_facts.selinux.status == 'enabled' + tags: + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - sebool_kerberos_enabled + + + + + + + + + + + Configure the polyinstantiation_enabled SELinux Boolean + By default, the SELinux boolean polyinstantiation_enabled is disabled. +This setting should be configured to . + +To set the polyinstantiation_enabled SELinux boolean, run the following command: +$ sudo setsebool -P polyinstantiation_enabled + + + R55 + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +if ! rpm -q --quiet "python3-libsemanage" ; then + yum install -y "python3-libsemanage" +fi + + +if selinuxenabled || [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; then + + var_polyinstantiation_enabled='' + + setsebool -P polyinstantiation_enabled $var_polyinstantiation_enabled + +else + echo "Skipping remediation, SELinux is disabled"; + false +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - sebool_polyinstantiation_enabled + +- name: Configure the polyinstantiation_enabled SELinux Boolean - Ensure python3-libsemanage + Installed + package: + name: python3-libsemanage + state: present + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - sebool_polyinstantiation_enabled +- name: XCCDF Value var_polyinstantiation_enabled # promote to variable + set_fact: + var_polyinstantiation_enabled: !!str + tags: + - always + +- name: Configure the polyinstantiation_enabled SELinux Boolean - Set SELinux Boolean + polyinstantiation_enabled Accordingly + seboolean: + name: polyinstantiation_enabled + state: '{{ var_polyinstantiation_enabled }}' + persistent: true + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - ansible_facts.selinux.status == 'enabled' + tags: + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - sebool_polyinstantiation_enabled + + + + + + + + + + + Configure the secure_mode_insmod SELinux Boolean + By default, the SELinux boolean secure_mode_insmod is disabled. +This setting should be configured to . + +To set the secure_mode_insmod SELinux boolean, run the following command: +$ sudo setsebool -P secure_mode_insmod + + + R48 + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +var_secure_mode_insmod='' + +setsebool -P secure_mode_insmod $var_secure_mode_insmod + +# Preload vfat in initramfs, otherwise the system fails to reboot +echo "vfat" >> /etc/modules-load.d/vfat.conf +dracut -f --regenerate-all + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - sebool_secure_mode_insmod +- name: XCCDF Value var_secure_mode_insmod # promote to variable + set_fact: + var_secure_mode_insmod: !!str + tags: + - always + +- name: Configure the secure_mode_insmod SELinux Boolean - Ensure libsemanage-python + installed + ansible.builtin.package: + name: libsemanage-python + state: present + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - sebool_secure_mode_insmod + +- name: Configure the secure_mode_insmod SELinux Boolean - Set SELinux boolean secure_mode_insmod + accordingly + ansible.posix.seboolean: + name: secure_mode_insmod + state: '{{ var_secure_mode_insmod }}' + persistent: true + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - sebool_secure_mode_insmod + +- name: Configure the secure_mode_insmod SELinux Boolean - Add vfat to static kernel + module list + ansible.builtin.lineinfile: + create: true + dest: /etc/modules-load.d/vfat.conf + regexp: ^\s*\bvfat\b + line: vfat + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - sebool_secure_mode_insmod + +- name: Configure the secure_mode_insmod SELinux Boolean - Regenerate initramfs + ansible.builtin.command: + cmd: dracut -f --regenerate-all + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - sebool_secure_mode_insmod + + + + + + + + + + + Disable the selinuxuser_execheap SELinux Boolean + By default, the SELinux boolean selinuxuser_execheap is disabled. +When enabled this boolean is enabled it allows selinuxusers to execute code from the heap. +If this setting is enabled, it should be disabled. + +To disable the selinuxuser_execheap SELinux boolean, run the following command: +$ sudo setsebool -P selinuxuser_execheap off + + 164.308(a)(1)(ii)(D) + 164.308(a)(3) + 164.308(a)(4) + 164.310(b) + 164.310(c) + 164.312(a) + 164.312(e) + R48 + Disabling code execution from the heap blocks buffer overflow attacks. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +if ! rpm -q --quiet "python3-libsemanage" ; then + yum install -y "python3-libsemanage" +fi + + +if selinuxenabled || [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; then + + var_selinuxuser_execheap='' + + setsebool -P selinuxuser_execheap $var_selinuxuser_execheap + +else + echo "Skipping remediation, SELinux is disabled"; + false +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - sebool_selinuxuser_execheap + +- name: Disable the selinuxuser_execheap SELinux Boolean - Ensure python3-libsemanage + Installed + package: + name: python3-libsemanage + state: present + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - sebool_selinuxuser_execheap +- name: XCCDF Value var_selinuxuser_execheap # promote to variable + set_fact: + var_selinuxuser_execheap: !!str + tags: + - always + +- name: Disable the selinuxuser_execheap SELinux Boolean - Set SELinux Boolean selinuxuser_execheap + Accordingly + seboolean: + name: selinuxuser_execheap + state: '{{ var_selinuxuser_execheap }}' + persistent: true + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - ansible_facts.selinux.status == 'enabled' + tags: + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - sebool_selinuxuser_execheap + + + + + + + + + + + Enable the selinuxuser_execmod SELinux Boolean + By default, the SELinux boolean selinuxuser_execmod is enabled. +If this setting is disabled, it should be enabled. + +To enable the selinuxuser_execmod SELinux boolean, run the following command: +$ sudo setsebool -P selinuxuser_execmod on + + 164.308(a)(1)(ii)(D) + 164.308(a)(3) + 164.308(a)(4) + 164.310(b) + 164.310(c) + 164.312(a) + 164.312(e) + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +if ! rpm -q --quiet "python3-libsemanage" ; then + yum install -y "python3-libsemanage" +fi + + +if selinuxenabled || [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; then + + var_selinuxuser_execmod='' + + setsebool -P selinuxuser_execmod $var_selinuxuser_execmod + +else + echo "Skipping remediation, SELinux is disabled"; + false +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - sebool_selinuxuser_execmod + +- name: Enable the selinuxuser_execmod SELinux Boolean - Ensure python3-libsemanage + Installed + package: + name: python3-libsemanage + state: present + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - sebool_selinuxuser_execmod +- name: XCCDF Value var_selinuxuser_execmod # promote to variable + set_fact: + var_selinuxuser_execmod: !!str + tags: + - always + +- name: Enable the selinuxuser_execmod SELinux Boolean - Set SELinux Boolean selinuxuser_execmod + Accordingly + seboolean: + name: selinuxuser_execmod + state: '{{ var_selinuxuser_execmod }}' + persistent: true + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - ansible_facts.selinux.status == 'enabled' + tags: + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - sebool_selinuxuser_execmod + + + + + + + + + + + Disable the selinuxuser_execstack SELinux Boolean + By default, the SELinux boolean selinuxuser_execstack is enabled. +This setting should be disabled as unconfined executables should not be able +to make their stack executable. + +To disable the selinuxuser_execstack SELinux boolean, run the following command: +$ sudo setsebool -P selinuxuser_execstack off + + 164.308(a)(1)(ii)(D) + 164.308(a)(3) + 164.308(a)(4) + 164.310(b) + 164.310(c) + 164.312(a) + 164.312(e) + R48 + Disabling code execution from the stack blocks buffer overflow attacks. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +if ! rpm -q --quiet "python3-libsemanage" ; then + yum install -y "python3-libsemanage" +fi + + +if selinuxenabled || [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; then + + var_selinuxuser_execstack='' + + setsebool -P selinuxuser_execstack $var_selinuxuser_execstack + +else + echo "Skipping remediation, SELinux is disabled"; + false +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - sebool_selinuxuser_execstack + +- name: Disable the selinuxuser_execstack SELinux Boolean - Ensure python3-libsemanage + Installed + package: + name: python3-libsemanage + state: present + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - sebool_selinuxuser_execstack +- name: XCCDF Value var_selinuxuser_execstack # promote to variable + set_fact: + var_selinuxuser_execstack: !!str + tags: + - always + +- name: Disable the selinuxuser_execstack SELinux Boolean - Set SELinux Boolean selinuxuser_execstack + Accordingly + seboolean: + name: selinuxuser_execstack + state: '{{ var_selinuxuser_execstack }}' + persistent: true + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - ansible_facts.selinux.status == 'enabled' + tags: + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - sebool_selinuxuser_execstack + + + + + + + + + + + Disable the ssh_sysadm_login SELinux Boolean + By default, the SELinux boolean ssh_sysadm_login is disabled. +If this setting is enabled, it should be disabled. + +To disable the ssh_sysadm_login SELinux boolean, run the following command: +$ sudo setsebool -P ssh_sysadm_login off + + CCI-002165 + CCI-002235 + SRG-OS-000324-GPOS-00125 + R48 + Preventing non-privileged users from executing privileged functions mitigates +the risk that unauthorized individuals or processes may gain unnecessary access +to information or privileges. + +Privileged functions include, for example, establishing accounts, performing +system integrity checks, or administering cryptographic key management +activities. Non-privileged users are individuals who do not possess appropriate +authorizations. Circumventing intrusion detection and prevention mechanisms or +malicious code protection mechanisms are examples of privileged functions that +require protection from non-privileged users. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +if ! rpm -q --quiet "python3-libsemanage" ; then + yum install -y "python3-libsemanage" +fi + + +if selinuxenabled || [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; then + + var_ssh_sysadm_login='' + + setsebool -P ssh_sysadm_login $var_ssh_sysadm_login + +else + echo "Skipping remediation, SELinux is disabled"; + false +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - sebool_ssh_sysadm_login + +- name: Disable the ssh_sysadm_login SELinux Boolean - Ensure python3-libsemanage + Installed + package: + name: python3-libsemanage + state: present + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - sebool_ssh_sysadm_login +- name: XCCDF Value var_ssh_sysadm_login # promote to variable + set_fact: + var_ssh_sysadm_login: !!str + tags: + - always + +- name: Disable the ssh_sysadm_login SELinux Boolean - Set SELinux Boolean ssh_sysadm_login + Accordingly + seboolean: + name: ssh_sysadm_login + state: '{{ var_ssh_sysadm_login }}' + persistent: true + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - ansible_facts.selinux.status == 'enabled' + tags: + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - sebool_ssh_sysadm_login + + + + + + + + + + + + + + Services + The best protection against vulnerable software is running less software. This section describes how to review +the software which Oracle Linux 9 installs on a system and disable software which is not needed. It +then enumerates the software packages installed on a default Oracle Linux 9 system and provides guidance about which +ones can be safely disabled. + + +Oracle Linux 9 provides a convenient minimal install option that essentially installs the bare necessities for a functional +system. When building Oracle Linux 9 systems, it is highly recommended to select the minimal packages and then build up +the system from there. + + Avahi Server + The Avahi daemon implements the DNS Service Discovery +and Multicast DNS protocols, which provide service and host +discovery on a network. It allows a system to automatically +identify resources on the network, such as printers or web servers. +This capability is also known as mDNSresponder and is a major part +of Zeroconf networking. + + Configure Avahi if Necessary + If your system requires the Avahi daemon, its configuration can be restricted +to improve security. The Avahi daemon configuration file is +/etc/avahi/avahi-daemon.conf. The following security recommendations +should be applied to this file: +See the avahi-daemon.conf(5) man page, or documentation at + + http://www.avahi.org, for more detailed information +about the configuration options. + + Disable Avahi Publishing + To prevent Avahi from publishing its records, edit /etc/avahi/avahi-daemon.conf +and ensure the following line appears in the [publish] section: +disable-publishing=yes + + 11 + 14 + 3 + 9 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS05.02 + DSS05.05 + DSS06.06 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.2 + 4.3.4.3.3 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 7.6 + A.12.1.2 + A.12.5.1 + A.12.6.2 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.9.1.2 + CM-7(a) + CM-7(b) + CM-6(a) + PR.IP-1 + PR.PT-3 + This helps ensure that no record will be published by Avahi. + + + + Disable Avahi Server if Possible + Because the Avahi daemon service keeps an open network +port, it is subject to network attacks. +Disabling it can reduce the system's vulnerability to such attacks. + + Disable Avahi Server Software + +The avahi-daemon service can be disabled with the following command: +$ sudo systemctl mask --now avahi-daemon.service + + 11 + 14 + 3 + 9 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS05.02 + DSS05.05 + DSS06.06 + CCI-000366 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.2 + 4.3.4.3.3 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 7.6 + A.12.1.2 + A.12.5.1 + A.12.6.2 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.9.1.2 + CM-7(a) + CM-7(b) + CM-6(a) + PR.IP-1 + PR.PT-3 + 2.2.4 + 2.2 + Because the Avahi daemon service keeps an open network +port, it is subject to network attacks. Its functionality +is convenient but is only appropriate if the local network +can be trusted. + + # Remediation is applicable only in certain platforms +if ( rpm --quiet -q avahi && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ); then + +SYSTEMCTL_EXEC='/usr/bin/systemctl' +if [[ $("$SYSTEMCTL_EXEC" is-system-running) != "offline" ]]; then + "$SYSTEMCTL_EXEC" stop 'avahi-daemon.service' +fi +"$SYSTEMCTL_EXEC" disable 'avahi-daemon.service' +"$SYSTEMCTL_EXEC" mask 'avahi-daemon.service' +# Disable socket activation if we have a unit file for it +if "$SYSTEMCTL_EXEC" -q list-unit-files avahi-daemon.socket; then + if [[ $("$SYSTEMCTL_EXEC" is-system-running) != "offline" ]]; then + "$SYSTEMCTL_EXEC" stop 'avahi-daemon.socket' + fi + "$SYSTEMCTL_EXEC" mask 'avahi-daemon.socket' +fi +# The service may not be running because it has been started and failed, +# so let's reset the state so OVAL checks pass. +# Service should be 'inactive', not 'failed' after reboot though. +"$SYSTEMCTL_EXEC" reset-failed 'avahi-daemon.service' || true + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.4 + - disable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_avahi-daemon_disabled + +- name: Disable Avahi Server Software - Collect systemd Services Present in the System + ansible.builtin.command: systemctl -q list-unit-files --type service + register: service_exists + changed_when: false + failed_when: service_exists.rc not in [0, 1] + check_mode: false + when: ( "avahi" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + tags: + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.4 + - disable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_avahi-daemon_disabled + +- name: Disable Avahi Server Software - Ensure avahi-daemon.service is Masked + ansible.builtin.systemd: + name: avahi-daemon.service + state: stopped + enabled: false + masked: true + when: + - ( "avahi" in ansible_facts.packages and ("kernel" in ansible_facts.packages or + "kernel-uek" in ansible_facts.packages) ) + - service_exists.stdout_lines is search("avahi-daemon.service", multiline=True) + tags: + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.4 + - disable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_avahi-daemon_disabled + +- name: Unit Socket Exists - avahi-daemon.socket + ansible.builtin.command: systemctl -q list-unit-files avahi-daemon.socket + register: socket_file_exists + changed_when: false + failed_when: socket_file_exists.rc not in [0, 1] + check_mode: false + when: ( "avahi" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + tags: + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.4 + - disable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_avahi-daemon_disabled + +- name: Disable Avahi Server Software - Disable Socket avahi-daemon + ansible.builtin.systemd: + name: avahi-daemon.socket + enabled: false + state: stopped + masked: true + when: + - ( "avahi" in ansible_facts.packages and ("kernel" in ansible_facts.packages or + "kernel-uek" in ansible_facts.packages) ) + - socket_file_exists.stdout_lines is search("avahi-daemon.socket", multiline=True) + tags: + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.4 + - disable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_avahi-daemon_disabled + + include disable_avahi-daemon + +class disable_avahi-daemon { + service {'avahi-daemon': + enable => false, + ensure => 'stopped', + } +} + + +[customizations.services] +masked = ["avahi-daemon"] + + + + + + + + + + + + Base Services + This section addresses the base services that are installed on a +Oracle Linux 9 default installation which are not covered in other +sections. Some of these services listen on the network and +should be treated with particular discretion. Other services are local +system utilities that may or may not be extraneous. In general, system services +should be disabled if not required. + + Disable KDump Kernel Crash Analyzer (kdump) + The kdump service provides a kernel crash dump analyzer. It uses the kexec +system call to boot a secondary kernel ("capture" kernel) following a system +crash, which can load information from the crashed kernel for analysis. + +The kdump service can be disabled with the following command: +$ sudo systemctl mask --now kdump.service + + 11 + 12 + 14 + 15 + 3 + 8 + 9 + APO13.01 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS01.04 + DSS05.02 + DSS05.03 + DSS05.05 + DSS06.06 + CCI-000366 + 164.308(a)(1)(ii)(D) + 164.308(a)(3) + 164.308(a)(4) + 164.310(b) + 164.310(c) + 164.312(a) + 164.312(e) + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.2 + 4.3.4.3.3 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 7.1 + SR 7.6 + A.11.2.6 + A.12.1.2 + A.12.5.1 + A.12.6.2 + A.13.1.1 + A.13.2.1 + A.14.1.3 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.6.2.1 + A.6.2.2 + A.9.1.2 + CM-7(a) + CM-7(b) + CM-6(a) + PR.AC-3 + PR.IP-1 + PR.PT-3 + PR.PT-4 + FMT_SMF_EXT.1.1 + SRG-OS-000269-GPOS-00103 + SRG-OS-000480-GPOS-00227 + OL09-00-002385 + SV-271733r1092598_rule + Kernel core dumps may contain the full contents of system memory at the +time of the crash. Kernel core dumps consume a considerable amount of disk +space and may result in denial of service by exhausting the available space +on the target file system partition. Unless the system is used for kernel +development or testing, there is little need to run the kdump service. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +SYSTEMCTL_EXEC='/usr/bin/systemctl' +if [[ $("$SYSTEMCTL_EXEC" is-system-running) != "offline" ]]; then + "$SYSTEMCTL_EXEC" stop 'kdump.service' +fi +"$SYSTEMCTL_EXEC" disable 'kdump.service' +"$SYSTEMCTL_EXEC" mask 'kdump.service' +# Disable socket activation if we have a unit file for it +if "$SYSTEMCTL_EXEC" -q list-unit-files kdump.socket; then + if [[ $("$SYSTEMCTL_EXEC" is-system-running) != "offline" ]]; then + "$SYSTEMCTL_EXEC" stop 'kdump.socket' + fi + "$SYSTEMCTL_EXEC" mask 'kdump.socket' +fi +# The service may not be running because it has been started and failed, +# so let's reset the state so OVAL checks pass. +# Service should be 'inactive', not 'failed' after reboot though. +"$SYSTEMCTL_EXEC" reset-failed 'kdump.service' || true + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002385 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_kdump_disabled + +- name: Disable KDump Kernel Crash Analyzer (kdump) - Collect systemd Services Present + in the System + ansible.builtin.command: systemctl -q list-unit-files --type service + register: service_exists + changed_when: false + failed_when: service_exists.rc not in [0, 1] + check_mode: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002385 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_kdump_disabled + +- name: Disable KDump Kernel Crash Analyzer (kdump) - Ensure kdump.service is Masked + ansible.builtin.systemd: + name: kdump.service + state: stopped + enabled: false + masked: true + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - service_exists.stdout_lines is search("kdump.service", multiline=True) + tags: + - DISA-STIG-OL09-00-002385 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_kdump_disabled + +- name: Unit Socket Exists - kdump.socket + ansible.builtin.command: systemctl -q list-unit-files kdump.socket + register: socket_file_exists + changed_when: false + failed_when: socket_file_exists.rc not in [0, 1] + check_mode: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002385 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_kdump_disabled + +- name: Disable KDump Kernel Crash Analyzer (kdump) - Disable Socket kdump + ansible.builtin.systemd: + name: kdump.socket + enabled: false + state: stopped + masked: true + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - socket_file_exists.stdout_lines is search("kdump.socket", multiline=True) + tags: + - DISA-STIG-OL09-00-002385 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_kdump_disabled + + include disable_kdump + +class disable_kdump { + service {'kdump': + enable => false, + ensure => 'stopped', + } +} + + +kdump --disable + + +[customizations.services] +masked = ["kdump"] + + + + + + + + + + Disable Odd Job Daemon (oddjobd) + The oddjobd service exists to provide an interface and +access control mechanism through which +specified privileged tasks can run tasks for unprivileged client +applications. Communication with oddjobd through the system message bus. + +The oddjobd service can be disabled with the following command: +$ sudo systemctl mask --now oddjobd.service + + 11 + 14 + 3 + 9 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS05.02 + DSS05.05 + DSS06.06 + CCI-000381 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.2 + 4.3.4.3.3 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 7.6 + A.12.1.2 + A.12.5.1 + A.12.6.2 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.9.1.2 + CM-7(a) + CM-7(b) + CM-6(a) + PR.IP-1 + PR.PT-3 + The oddjobd service may provide necessary functionality in +some environments, and can be disabled if it is not needed. Execution of +tasks by privileged programs, on behalf of unprivileged ones, has traditionally +been a source of privilege escalation security issues. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +SYSTEMCTL_EXEC='/usr/bin/systemctl' +if [[ $("$SYSTEMCTL_EXEC" is-system-running) != "offline" ]]; then + "$SYSTEMCTL_EXEC" stop 'oddjobd.service' +fi +"$SYSTEMCTL_EXEC" disable 'oddjobd.service' +"$SYSTEMCTL_EXEC" mask 'oddjobd.service' +# Disable socket activation if we have a unit file for it +if "$SYSTEMCTL_EXEC" -q list-unit-files oddjobd.socket; then + if [[ $("$SYSTEMCTL_EXEC" is-system-running) != "offline" ]]; then + "$SYSTEMCTL_EXEC" stop 'oddjobd.socket' + fi + "$SYSTEMCTL_EXEC" mask 'oddjobd.socket' +fi +# The service may not be running because it has been started and failed, +# so let's reset the state so OVAL checks pass. +# Service should be 'inactive', not 'failed' after reboot though. +"$SYSTEMCTL_EXEC" reset-failed 'oddjobd.service' || true + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_oddjobd_disabled + +- name: Disable Odd Job Daemon (oddjobd) - Collect systemd Services Present in the + System + ansible.builtin.command: systemctl -q list-unit-files --type service + register: service_exists + changed_when: false + failed_when: service_exists.rc not in [0, 1] + check_mode: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_oddjobd_disabled + +- name: Disable Odd Job Daemon (oddjobd) - Ensure oddjobd.service is Masked + ansible.builtin.systemd: + name: oddjobd.service + state: stopped + enabled: false + masked: true + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - service_exists.stdout_lines is search("oddjobd.service", multiline=True) + tags: + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_oddjobd_disabled + +- name: Unit Socket Exists - oddjobd.socket + ansible.builtin.command: systemctl -q list-unit-files oddjobd.socket + register: socket_file_exists + changed_when: false + failed_when: socket_file_exists.rc not in [0, 1] + check_mode: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_oddjobd_disabled + +- name: Disable Odd Job Daemon (oddjobd) - Disable Socket oddjobd + ansible.builtin.systemd: + name: oddjobd.socket + enabled: false + state: stopped + masked: true + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - socket_file_exists.stdout_lines is search("oddjobd.socket", multiline=True) + tags: + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_oddjobd_disabled + + include disable_oddjobd + +class disable_oddjobd { + service {'oddjobd': + enable => false, + ensure => 'stopped', + } +} + + +[customizations.services] +masked = ["oddjobd"] + + + + + + + + + + Disable Network Router Discovery Daemon (rdisc) + The rdisc service implements the client side of the ICMP +Internet Router Discovery Protocol (IRDP), which allows discovery of routers on +the local subnet. If a router is discovered then the local routing table is +updated with a corresponding default route. By default this daemon is disabled. + +The rdisc service can be disabled with the following command: +$ sudo systemctl mask --now rdisc.service + + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 4 + 6 + 8 + 9 + APO01.06 + APO13.01 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS01.04 + DSS01.05 + DSS03.01 + DSS05.02 + DSS05.03 + DSS05.04 + DSS05.05 + DSS05.07 + DSS06.02 + DSS06.06 + CCI-000382 + 4.2.3.4 + 4.3.3.4 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.2 + 4.3.4.3.3 + 4.4.3.3 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 7.1 + SR 7.6 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.11.2.6 + A.12.1.1 + A.12.1.2 + A.12.5.1 + A.12.6.2 + A.13.1.1 + A.13.1.2 + A.13.1.3 + A.13.2.1 + A.13.2.2 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.6.1.2 + A.6.2.1 + A.6.2.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + AC-4 + CM-7(a) + CM-7(b) + CM-6(a) + DE.AE-1 + ID.AM-3 + PR.AC-3 + PR.AC-5 + PR.DS-5 + PR.IP-1 + PR.PT-3 + PR.PT-4 + General-purpose systems typically have their network and routing +information configured statically by a system administrator. Workstations or +some special-purpose systems often use DHCP (instead of IRDP) to retrieve +dynamic network configuration information. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +SYSTEMCTL_EXEC='/usr/bin/systemctl' +if [[ $("$SYSTEMCTL_EXEC" is-system-running) != "offline" ]]; then + "$SYSTEMCTL_EXEC" stop 'rdisc.service' +fi +"$SYSTEMCTL_EXEC" disable 'rdisc.service' +"$SYSTEMCTL_EXEC" mask 'rdisc.service' +# Disable socket activation if we have a unit file for it +if "$SYSTEMCTL_EXEC" -q list-unit-files rdisc.socket; then + if [[ $("$SYSTEMCTL_EXEC" is-system-running) != "offline" ]]; then + "$SYSTEMCTL_EXEC" stop 'rdisc.socket' + fi + "$SYSTEMCTL_EXEC" mask 'rdisc.socket' +fi +# The service may not be running because it has been started and failed, +# so let's reset the state so OVAL checks pass. +# Service should be 'inactive', not 'failed' after reboot though. +"$SYSTEMCTL_EXEC" reset-failed 'rdisc.service' || true + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-53-AC-4 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_rdisc_disabled + +- name: Disable Network Router Discovery Daemon (rdisc) - Collect systemd Services + Present in the System + ansible.builtin.command: systemctl -q list-unit-files --type service + register: service_exists + changed_when: false + failed_when: service_exists.rc not in [0, 1] + check_mode: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-AC-4 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_rdisc_disabled + +- name: Disable Network Router Discovery Daemon (rdisc) - Ensure rdisc.service is + Masked + ansible.builtin.systemd: + name: rdisc.service + state: stopped + enabled: false + masked: true + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - service_exists.stdout_lines is search("rdisc.service", multiline=True) + tags: + - NIST-800-53-AC-4 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_rdisc_disabled + +- name: Unit Socket Exists - rdisc.socket + ansible.builtin.command: systemctl -q list-unit-files rdisc.socket + register: socket_file_exists + changed_when: false + failed_when: socket_file_exists.rc not in [0, 1] + check_mode: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-AC-4 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_rdisc_disabled + +- name: Disable Network Router Discovery Daemon (rdisc) - Disable Socket rdisc + ansible.builtin.systemd: + name: rdisc.socket + enabled: false + state: stopped + masked: true + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - socket_file_exists.stdout_lines is search("rdisc.socket", multiline=True) + tags: + - NIST-800-53-AC-4 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_rdisc_disabled + + include disable_rdisc + +class disable_rdisc { + service {'rdisc': + enable => false, + ensure => 'stopped', + } +} + + +[customizations.services] +masked = ["rdisc"] + + + + + + + + + + + Cron and At Daemons + The cron and at services are used to allow commands to +be executed at a later time. The cron service is required by almost +all systems to perform necessary maintenance tasks, while at may or +may not be required on a given system. Both daemons should be +configured defensively. + + + Install the cron service + The Cron service should be installed. + 11 + 14 + 3 + 9 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS05.02 + DSS05.05 + DSS06.06 + CCI-000366 + 164.308(a)(4)(i) + 164.308(b)(1) + 164.308(b)(3) + 164.310(b) + 164.312(e)(1) + 164.312(e)(2)(ii) + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.2 + 4.3.4.3.3 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 7.6 + A.12.1.2 + A.12.5.1 + A.12.6.2 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.9.1.2 + CM-6(a) + PR.IP-1 + PR.PT-3 + SRG-OS-000480-GPOS-00227 + 2.2.6 + 2.2 + The cron service allow periodic job execution, needed for almost all administrative tasks and services (software update, log rotating, etc.). Access to cron service should be restricted to administrative accounts only. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +if ! rpm -q --quiet "cronie" ; then + yum install -y "cronie" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - package_cron_installed + +- name: Ensure cronie is installed + package: + name: cronie + state: present + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - package_cron_installed + + include install_cronie + +class install_cronie { + package { 'cronie': + ensure => 'installed', + } +} + + +package --add=cronie + + +[[packages]] +name = "cronie" +version = "*" + + + + + + + + + + Enable cron Service + The crond service is used to execute commands at +preconfigured times. It is required by almost all systems to perform necessary +maintenance tasks, such as notifying root of system activity. + +The crond service can be enabled with the following command: +$ sudo systemctl enable crond.service + + 11 + 14 + 3 + 9 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS05.02 + DSS05.05 + DSS06.06 + 164.308(a)(4)(i) + 164.308(b)(1) + 164.308(b)(3) + 164.310(b) + 164.312(e)(1) + 164.312(e)(2)(ii) + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.2 + 4.3.4.3.3 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 7.6 + A.12.1.2 + A.12.5.1 + A.12.6.2 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.9.1.2 + CM-6(a) + PR.IP-1 + PR.PT-3 + Due to its usage for maintenance and security-supporting tasks, +enabling the cron daemon is essential. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +SYSTEMCTL_EXEC='/usr/bin/systemctl' +"$SYSTEMCTL_EXEC" unmask 'crond.service' +if [[ $("$SYSTEMCTL_EXEC" is-system-running) != "offline" ]]; then + "$SYSTEMCTL_EXEC" start 'crond.service' +fi +"$SYSTEMCTL_EXEC" enable 'crond.service' + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-53-CM-6(a) + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_crond_enabled + +- name: Enable cron Service - Enable service crond + block: + + - name: Gather the package facts + package_facts: + manager: auto + + - name: Enable cron Service - Enable Service crond + ansible.builtin.systemd: + name: crond + enabled: true + state: started + masked: false + when: + - '"cronie" in ansible_facts.packages' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-CM-6(a) + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_crond_enabled + + include enable_crond + +class enable_crond { + service {'crond': + enable => true, + ensure => 'running', + } +} + + +[customizations.services] +enabled = ["crond"] + + + + + + + + + + Disable At Service (atd) + The at and batch commands can be used to +schedule tasks that are meant to be executed only once. This allows delayed +execution in a manner similar to cron, except that it is not +recurring. The daemon atd keeps track of tasks scheduled via +at and batch, and executes them at the specified time. + +The atd service can be disabled with the following command: +$ sudo systemctl mask --now atd.service + + 11 + 14 + 3 + 9 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS05.02 + DSS05.05 + DSS06.06 + CCI-000381 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.2 + 4.3.4.3.3 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 7.6 + A.12.1.2 + A.12.5.1 + A.12.6.2 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.9.1.2 + CM-7(a) + CM-7(b) + CM-6(a) + PR.IP-1 + PR.PT-3 + The atd service could be used by an unsophisticated insider to carry +out activities outside of a normal login session, which could complicate +accountability. Furthermore, the need to schedule tasks with at or +batch is not common. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +SYSTEMCTL_EXEC='/usr/bin/systemctl' +if [[ $("$SYSTEMCTL_EXEC" is-system-running) != "offline" ]]; then + "$SYSTEMCTL_EXEC" stop 'atd.service' +fi +"$SYSTEMCTL_EXEC" disable 'atd.service' +"$SYSTEMCTL_EXEC" mask 'atd.service' +# Disable socket activation if we have a unit file for it +if "$SYSTEMCTL_EXEC" -q list-unit-files atd.socket; then + if [[ $("$SYSTEMCTL_EXEC" is-system-running) != "offline" ]]; then + "$SYSTEMCTL_EXEC" stop 'atd.socket' + fi + "$SYSTEMCTL_EXEC" mask 'atd.socket' +fi +# The service may not be running because it has been started and failed, +# so let's reset the state so OVAL checks pass. +# Service should be 'inactive', not 'failed' after reboot though. +"$SYSTEMCTL_EXEC" reset-failed 'atd.service' || true + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_atd_disabled + +- name: Disable At Service (atd) - Collect systemd Services Present in the System + ansible.builtin.command: systemctl -q list-unit-files --type service + register: service_exists + changed_when: false + failed_when: service_exists.rc not in [0, 1] + check_mode: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_atd_disabled + +- name: Disable At Service (atd) - Ensure atd.service is Masked + ansible.builtin.systemd: + name: atd.service + state: stopped + enabled: false + masked: true + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - service_exists.stdout_lines is search("atd.service", multiline=True) + tags: + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_atd_disabled + +- name: Unit Socket Exists - atd.socket + ansible.builtin.command: systemctl -q list-unit-files atd.socket + register: socket_file_exists + changed_when: false + failed_when: socket_file_exists.rc not in [0, 1] + check_mode: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_atd_disabled + +- name: Disable At Service (atd) - Disable Socket atd + ansible.builtin.systemd: + name: atd.socket + enabled: false + state: stopped + masked: true + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - socket_file_exists.stdout_lines is search("atd.socket", multiline=True) + tags: + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_atd_disabled + + include disable_atd + +class disable_atd { + service {'atd': + enable => false, + ensure => 'stopped', + } +} + + +[customizations.services] +masked = ["atd"] + + + + + + + + + + Verify Group Who Owns cron.d + +To properly set the group owner of /etc/cron.d, run the command: +$ sudo chgrp root /etc/cron.d + + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + APO01.06 + DSS05.04 + DSS05.07 + DSS06.02 + CCI-000366 + 4.3.3.7.3 + SR 2.1 + SR 5.2 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CM-6(a) + AC-6(1) + PR.AC-4 + PR.DS-5 + SRG-OS-000480-GPOS-00227 + 2.2.6 + 2.2 + OL09-00-002581 + SV-271828r1092196_rule + Service configuration files enable or disable features of their respective services that if configured incorrectly +can lead to insecure and vulnerable configurations. Therefore, service configuration files should be owned by the +correct group to prevent unauthorized changes. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +find -H /etc/cron.d/ -maxdepth 1 -type d -exec chgrp -L 0 {} \; + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002581 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_groupowner_cron_d + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure group owner on /etc/cron.d/ + file: + path: /etc/cron.d/ + state: directory + group: '0' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002581 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_groupowner_cron_d + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify Group Who Owns cron.daily + +To properly set the group owner of /etc/cron.daily, run the command: +$ sudo chgrp root /etc/cron.daily + + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + APO01.06 + DSS05.04 + DSS05.07 + DSS06.02 + CCI-000366 + 4.3.3.7.3 + SR 2.1 + SR 5.2 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CM-6(a) + AC-6(1) + PR.AC-4 + PR.DS-5 + SRG-OS-000480-GPOS-00227 + 2.2.6 + 2.2 + OL09-00-002581 + SV-271828r1092196_rule + Service configuration files enable or disable features of their respective services that if configured incorrectly +can lead to insecure and vulnerable configurations. Therefore, service configuration files should be owned by the +correct group to prevent unauthorized changes. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +find -H /etc/cron.daily/ -maxdepth 1 -type d -exec chgrp -L 0 {} \; + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002581 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_groupowner_cron_daily + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure group owner on /etc/cron.daily/ + file: + path: /etc/cron.daily/ + state: directory + group: '0' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002581 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_groupowner_cron_daily + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify Group Who Owns cron.deny + +To properly set the group owner of /etc/cron.deny, run the command: +$ sudo chgrp root /etc/cron.deny + + CCI-000366 + CM-6 b + SRG-OS-000480-GPOS-00227 + OL09-00-002581 + SV-271828r1092196_rule + Service configuration files enable or disable features of their respective services that if configured incorrectly +can lead to insecure and vulnerable configurations. Therefore, service configuration files should be owned by the +correct group to prevent unauthorized changes. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +chgrp 0 /etc/cron.deny + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002581 + - NIST-800-53-CM-6 b + - configure_strategy + - file_groupowner_cron_deny + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /etc/cron.deny + stat: + path: /etc/cron.deny + register: file_exists + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002581 + - NIST-800-53-CM-6 b + - configure_strategy + - file_groupowner_cron_deny + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure group owner 0 on /etc/cron.deny + file: + path: /etc/cron.deny + group: '0' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - file_exists.stat is defined and file_exists.stat.exists + tags: + - DISA-STIG-OL09-00-002581 + - NIST-800-53-CM-6 b + - configure_strategy + - file_groupowner_cron_deny + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify Group Who Owns cron.hourly + +To properly set the group owner of /etc/cron.hourly, run the command: +$ sudo chgrp root /etc/cron.hourly + + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + APO01.06 + DSS05.04 + DSS05.07 + DSS06.02 + CCI-000366 + 4.3.3.7.3 + SR 2.1 + SR 5.2 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CM-6(a) + AC-6(1) + PR.AC-4 + PR.DS-5 + SRG-OS-000480-GPOS-00227 + 2.2.6 + 2.2 + OL09-00-002581 + SV-271828r1092196_rule + Service configuration files enable or disable features of their respective services that if configured incorrectly +can lead to insecure and vulnerable configurations. Therefore, service configuration files should be owned by the +correct group to prevent unauthorized changes. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +find -H /etc/cron.hourly/ -maxdepth 1 -type d -exec chgrp -L 0 {} \; + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002581 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_groupowner_cron_hourly + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure group owner on /etc/cron.hourly/ + file: + path: /etc/cron.hourly/ + state: directory + group: '0' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002581 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_groupowner_cron_hourly + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify Group Who Owns cron.monthly + +To properly set the group owner of /etc/cron.monthly, run the command: +$ sudo chgrp root /etc/cron.monthly + + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + APO01.06 + DSS05.04 + DSS05.07 + DSS06.02 + CCI-000366 + 4.3.3.7.3 + SR 2.1 + SR 5.2 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CM-6(a) + AC-6(1) + PR.AC-4 + PR.DS-5 + SRG-OS-000480-GPOS-00227 + 2.2.6 + 2.2 + OL09-00-002581 + SV-271828r1092196_rule + Service configuration files enable or disable features of their respective services that if configured incorrectly +can lead to insecure and vulnerable configurations. Therefore, service configuration files should be owned by the +correct group to prevent unauthorized changes. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +find -H /etc/cron.monthly/ -maxdepth 1 -type d -exec chgrp -L 0 {} \; + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002581 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_groupowner_cron_monthly + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure group owner on /etc/cron.monthly/ + file: + path: /etc/cron.monthly/ + state: directory + group: '0' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002581 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_groupowner_cron_monthly + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify Group Who Owns cron.weekly + +To properly set the group owner of /etc/cron.weekly, run the command: +$ sudo chgrp root /etc/cron.weekly + + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + APO01.06 + DSS05.04 + DSS05.07 + DSS06.02 + CCI-000366 + 4.3.3.7.3 + SR 2.1 + SR 5.2 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CM-6(a) + AC-6(1) + PR.AC-4 + PR.DS-5 + SRG-OS-000480-GPOS-00227 + 2.2.6 + 2.2 + OL09-00-002581 + SV-271828r1092196_rule + Service configuration files enable or disable features of their respective services that if configured incorrectly +can lead to insecure and vulnerable configurations. Therefore, service configuration files should be owned by the +correct group to prevent unauthorized changes. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +find -H /etc/cron.weekly/ -maxdepth 1 -type d -exec chgrp -L 0 {} \; + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002581 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_groupowner_cron_weekly + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure group owner on /etc/cron.weekly/ + file: + path: /etc/cron.weekly/ + state: directory + group: '0' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002581 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_groupowner_cron_weekly + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify Group Who Owns Crontab + +To properly set the group owner of /etc/crontab, run the command: +$ sudo chgrp root /etc/crontab + + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + APO01.06 + DSS05.04 + DSS05.07 + DSS06.02 + CCI-000366 + 4.3.3.7.3 + SR 2.1 + SR 5.2 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CM-6(a) + AC-6(1) + PR.AC-4 + PR.DS-5 + SRG-OS-000480-GPOS-00227 + 2.2.6 + 2.2 + OL09-00-002581 + SV-271828r1092196_rule + Service configuration files enable or disable features of their respective services that if configured incorrectly +can lead to insecure and vulnerable configurations. Therefore, service configuration files should be owned by the +correct group to prevent unauthorized changes. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +chgrp 0 /etc/crontab + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002581 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_groupowner_crontab + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /etc/crontab + stat: + path: /etc/crontab + register: file_exists + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002581 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_groupowner_crontab + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure group owner 0 on /etc/crontab + file: + path: /etc/crontab + group: '0' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - file_exists.stat is defined and file_exists.stat.exists + tags: + - DISA-STIG-OL09-00-002581 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_groupowner_crontab + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify Owner on cron.d + +To properly set the owner of /etc/cron.d, run the command: +$ sudo chown root /etc/cron.d + + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + APO01.06 + DSS05.04 + DSS05.07 + DSS06.02 + CCI-000366 + 4.3.3.7.3 + SR 2.1 + SR 5.2 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CM-6(a) + AC-6(1) + PR.AC-4 + PR.DS-5 + SRG-OS-000480-GPOS-00227 + 2.2.6 + 2.2 + OL09-00-002582 + SV-271829r1092199_rule + Service configuration files enable or disable features of their respective services that if configured incorrectly +can lead to insecure and vulnerable configurations. Therefore, service configuration files should be owned by the +correct user to prevent unauthorized changes. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +find -H /etc/cron.d/ -maxdepth 1 -type d -exec chown -L 0 {} \; + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002582 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_owner_cron_d + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure owner on directory /etc/cron.d/ + file: + path: /etc/cron.d/ + state: directory + owner: '0' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002582 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_owner_cron_d + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify Owner on cron.daily + +To properly set the owner of /etc/cron.daily, run the command: +$ sudo chown root /etc/cron.daily + + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + APO01.06 + DSS05.04 + DSS05.07 + DSS06.02 + CCI-000366 + 4.3.3.7.3 + SR 2.1 + SR 5.2 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CM-6(a) + AC-6(1) + PR.AC-4 + PR.DS-5 + SRG-OS-000480-GPOS-00227 + 2.2.6 + 2.2 + OL09-00-002582 + SV-271829r1092199_rule + Service configuration files enable or disable features of their respective services that if configured incorrectly +can lead to insecure and vulnerable configurations. Therefore, service configuration files should be owned by the +correct user to prevent unauthorized changes. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +find -H /etc/cron.daily/ -maxdepth 1 -type d -exec chown -L 0 {} \; + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002582 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_owner_cron_daily + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure owner on directory /etc/cron.daily/ + file: + path: /etc/cron.daily/ + state: directory + owner: '0' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002582 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_owner_cron_daily + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify Owner on cron.deny + +To properly set the owner of /etc/cron.deny, run the command: +$ sudo chown root /etc/cron.deny + + CCI-000366 + CM-6 b + SRG-OS-000480-GPOS-00227 + OL09-00-002582 + SV-271829r1092199_rule + Service configuration files enable or disable features of their respective services that if configured incorrectly +can lead to insecure and vulnerable configurations. Therefore, service configuration files should be owned by the +correct user to prevent unauthorized changes. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +chown 0 /etc/cron.deny + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002582 + - NIST-800-53-CM-6 b + - configure_strategy + - file_owner_cron_deny + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /etc/cron.deny + stat: + path: /etc/cron.deny + register: file_exists + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002582 + - NIST-800-53-CM-6 b + - configure_strategy + - file_owner_cron_deny + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure owner 0 on /etc/cron.deny + file: + path: /etc/cron.deny + owner: '0' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - file_exists.stat is defined and file_exists.stat.exists + tags: + - DISA-STIG-OL09-00-002582 + - NIST-800-53-CM-6 b + - configure_strategy + - file_owner_cron_deny + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify Owner on cron.hourly + +To properly set the owner of /etc/cron.hourly, run the command: +$ sudo chown root /etc/cron.hourly + + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + APO01.06 + DSS05.04 + DSS05.07 + DSS06.02 + CCI-000366 + 4.3.3.7.3 + SR 2.1 + SR 5.2 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CM-6(a) + AC-6(1) + PR.AC-4 + PR.DS-5 + SRG-OS-000480-GPOS-00227 + 2.2.6 + 2.2 + OL09-00-002582 + SV-271829r1092199_rule + Service configuration files enable or disable features of their respective services that if configured incorrectly +can lead to insecure and vulnerable configurations. Therefore, service configuration files should be owned by the +correct user to prevent unauthorized changes. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +find -H /etc/cron.hourly/ -maxdepth 1 -type d -exec chown -L 0 {} \; + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002582 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_owner_cron_hourly + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure owner on directory /etc/cron.hourly/ + file: + path: /etc/cron.hourly/ + state: directory + owner: '0' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002582 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_owner_cron_hourly + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify Owner on cron.monthly + +To properly set the owner of /etc/cron.monthly, run the command: +$ sudo chown root /etc/cron.monthly + + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + APO01.06 + DSS05.04 + DSS05.07 + DSS06.02 + CCI-000366 + 4.3.3.7.3 + SR 2.1 + SR 5.2 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CM-6(a) + AC-6(1) + PR.AC-4 + PR.DS-5 + SRG-OS-000480-GPOS-00227 + 2.2.6 + 2.2 + OL09-00-002582 + SV-271829r1092199_rule + Service configuration files enable or disable features of their respective services that if configured incorrectly +can lead to insecure and vulnerable configurations. Therefore, service configuration files should be owned by the +correct user to prevent unauthorized changes. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +find -H /etc/cron.monthly/ -maxdepth 1 -type d -exec chown -L 0 {} \; + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002582 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_owner_cron_monthly + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure owner on directory /etc/cron.monthly/ + file: + path: /etc/cron.monthly/ + state: directory + owner: '0' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002582 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_owner_cron_monthly + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify Owner on cron.weekly + +To properly set the owner of /etc/cron.weekly, run the command: +$ sudo chown root /etc/cron.weekly + + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + APO01.06 + DSS05.04 + DSS05.07 + DSS06.02 + CCI-000366 + 4.3.3.7.3 + SR 2.1 + SR 5.2 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CM-6(a) + AC-6(1) + PR.AC-4 + PR.DS-5 + SRG-OS-000480-GPOS-00227 + 2.2.6 + 2.2 + OL09-00-002582 + SV-271829r1092199_rule + Service configuration files enable or disable features of their respective services that if configured incorrectly +can lead to insecure and vulnerable configurations. Therefore, service configuration files should be owned by the +correct user to prevent unauthorized changes. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +find -H /etc/cron.weekly/ -maxdepth 1 -type d -exec chown -L 0 {} \; + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002582 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_owner_cron_weekly + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure owner on directory /etc/cron.weekly/ + file: + path: /etc/cron.weekly/ + state: directory + owner: '0' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002582 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_owner_cron_weekly + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify Owner on crontab + +To properly set the owner of /etc/crontab, run the command: +$ sudo chown root /etc/crontab + + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + APO01.06 + DSS05.04 + DSS05.07 + DSS06.02 + CCI-000366 + 4.3.3.7.3 + SR 2.1 + SR 5.2 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CM-6(a) + AC-6(1) + PR.AC-4 + PR.DS-5 + SRG-OS-000480-GPOS-00227 + 2.2.6 + 2.2 + OL09-00-002582 + SV-271829r1092199_rule + Service configuration files enable or disable features of their respective services that if configured incorrectly +can lead to insecure and vulnerable configurations. Therefore, service configuration files should be owned by the +correct user to prevent unauthorized changes. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +chown 0 /etc/crontab + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002582 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_owner_crontab + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /etc/crontab + stat: + path: /etc/crontab + register: file_exists + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002582 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_owner_crontab + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure owner 0 on /etc/crontab + file: + path: /etc/crontab + owner: '0' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - file_exists.stat is defined and file_exists.stat.exists + tags: + - DISA-STIG-OL09-00-002582 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_owner_crontab + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify Permissions on cron.d + +To properly set the permissions of /etc/cron.d, run the command: +$ sudo chmod 0700 /etc/cron.d + + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + APO01.06 + DSS05.04 + DSS05.07 + DSS06.02 + CCI-000366 + 4.3.3.7.3 + SR 2.1 + SR 5.2 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CM-6(a) + AC-6(1) + PR.AC-4 + PR.DS-5 + SRG-OS-000480-GPOS-00227 + 2.2.6 + 2.2 + OL09-00-002580 + SV-271827r1092193_rule + Service configuration files enable or disable features of their respective services that if configured incorrectly +can lead to insecure and vulnerable configurations. Therefore, service configuration files should have the +correct access rights to prevent unauthorized changes. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +find -H /etc/cron.d/ -maxdepth 1 -perm /u+s,g+xwrs,o+xwrt -type d -exec chmod u-s,g-xwrs,o-xwrt {} \; + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002580 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_permissions_cron_d + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Find /etc/cron.d/ file(s) + command: 'find -H /etc/cron.d/ -maxdepth 1 -perm /u+s,g+xwrs,o+xwrt -type d ' + register: files_found + changed_when: false + failed_when: false + check_mode: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002580 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_permissions_cron_d + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Set permissions for /etc/cron.d/ file(s) + file: + path: '{{ item }}' + mode: u-s,g-xwrs,o-xwrt + state: directory + with_items: + - '{{ files_found.stdout_lines }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002580 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_permissions_cron_d + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify Permissions on cron.daily + +To properly set the permissions of /etc/cron.daily, run the command: +$ sudo chmod 0700 /etc/cron.daily + + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + APO01.06 + DSS05.04 + DSS05.07 + DSS06.02 + CCI-000366 + 4.3.3.7.3 + SR 2.1 + SR 5.2 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CM-6(a) + AC-6(1) + PR.AC-4 + PR.DS-5 + SRG-OS-000480-GPOS-00227 + 2.2.6 + 2.2 + OL09-00-002580 + SV-271827r1092193_rule + Service configuration files enable or disable features of their respective services that if configured incorrectly +can lead to insecure and vulnerable configurations. Therefore, service configuration files should have the +correct access rights to prevent unauthorized changes. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +find -H /etc/cron.daily/ -maxdepth 1 -perm /u+s,g+xwrs,o+xwrt -type d -exec chmod u-s,g-xwrs,o-xwrt {} \; + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002580 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_permissions_cron_daily + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Find /etc/cron.daily/ file(s) + command: 'find -H /etc/cron.daily/ -maxdepth 1 -perm /u+s,g+xwrs,o+xwrt -type d ' + register: files_found + changed_when: false + failed_when: false + check_mode: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002580 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_permissions_cron_daily + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Set permissions for /etc/cron.daily/ file(s) + file: + path: '{{ item }}' + mode: u-s,g-xwrs,o-xwrt + state: directory + with_items: + - '{{ files_found.stdout_lines }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002580 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_permissions_cron_daily + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify Permissions on cron.hourly + +To properly set the permissions of /etc/cron.hourly, run the command: +$ sudo chmod 0700 /etc/cron.hourly + + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + APO01.06 + DSS05.04 + DSS05.07 + DSS06.02 + CCI-000366 + 4.3.3.7.3 + SR 2.1 + SR 5.2 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CM-6(a) + AC-6(1) + PR.AC-4 + PR.DS-5 + SRG-OS-000480-GPOS-00227 + 2.2.6 + 2.2 + OL09-00-002580 + SV-271827r1092193_rule + Service configuration files enable or disable features of their respective services that if configured incorrectly +can lead to insecure and vulnerable configurations. Therefore, service configuration files should have the +correct access rights to prevent unauthorized changes. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +find -H /etc/cron.hourly/ -maxdepth 1 -perm /u+s,g+xwrs,o+xwrt -type d -exec chmod u-s,g-xwrs,o-xwrt {} \; + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002580 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_permissions_cron_hourly + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Find /etc/cron.hourly/ file(s) + command: 'find -H /etc/cron.hourly/ -maxdepth 1 -perm /u+s,g+xwrs,o+xwrt -type + d ' + register: files_found + changed_when: false + failed_when: false + check_mode: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002580 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_permissions_cron_hourly + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Set permissions for /etc/cron.hourly/ file(s) + file: + path: '{{ item }}' + mode: u-s,g-xwrs,o-xwrt + state: directory + with_items: + - '{{ files_found.stdout_lines }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002580 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_permissions_cron_hourly + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify Permissions on cron.monthly + +To properly set the permissions of /etc/cron.monthly, run the command: +$ sudo chmod 0700 /etc/cron.monthly + + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + APO01.06 + DSS05.04 + DSS05.07 + DSS06.02 + CCI-000366 + 4.3.3.7.3 + SR 2.1 + SR 5.2 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CM-6(a) + AC-6(1) + PR.AC-4 + PR.DS-5 + SRG-OS-000480-GPOS-00227 + 2.2.6 + 2.2 + OL09-00-002580 + SV-271827r1092193_rule + Service configuration files enable or disable features of their respective services that if configured incorrectly +can lead to insecure and vulnerable configurations. Therefore, service configuration files should have the +correct access rights to prevent unauthorized changes. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +find -H /etc/cron.monthly/ -maxdepth 1 -perm /u+s,g+xwrs,o+xwrt -type d -exec chmod u-s,g-xwrs,o-xwrt {} \; + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002580 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_permissions_cron_monthly + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Find /etc/cron.monthly/ file(s) + command: 'find -H /etc/cron.monthly/ -maxdepth 1 -perm /u+s,g+xwrs,o+xwrt -type + d ' + register: files_found + changed_when: false + failed_when: false + check_mode: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002580 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_permissions_cron_monthly + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Set permissions for /etc/cron.monthly/ file(s) + file: + path: '{{ item }}' + mode: u-s,g-xwrs,o-xwrt + state: directory + with_items: + - '{{ files_found.stdout_lines }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002580 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_permissions_cron_monthly + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify Permissions on cron.weekly + +To properly set the permissions of /etc/cron.weekly, run the command: +$ sudo chmod 0700 /etc/cron.weekly + + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + APO01.06 + DSS05.04 + DSS05.07 + DSS06.02 + CCI-000366 + 4.3.3.7.3 + SR 2.1 + SR 5.2 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CM-6(a) + AC-6(1) + PR.AC-4 + PR.DS-5 + SRG-OS-000480-GPOS-00227 + 2.2.6 + 2.2 + OL09-00-002580 + SV-271827r1092193_rule + Service configuration files enable or disable features of their respective services that if configured incorrectly +can lead to insecure and vulnerable configurations. Therefore, service configuration files should have the +correct access rights to prevent unauthorized changes. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +find -H /etc/cron.weekly/ -maxdepth 1 -perm /u+s,g+xwrs,o+xwrt -type d -exec chmod u-s,g-xwrs,o-xwrt {} \; + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002580 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_permissions_cron_weekly + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Find /etc/cron.weekly/ file(s) + command: 'find -H /etc/cron.weekly/ -maxdepth 1 -perm /u+s,g+xwrs,o+xwrt -type + d ' + register: files_found + changed_when: false + failed_when: false + check_mode: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002580 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_permissions_cron_weekly + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Set permissions for /etc/cron.weekly/ file(s) + file: + path: '{{ item }}' + mode: u-s,g-xwrs,o-xwrt + state: directory + with_items: + - '{{ files_found.stdout_lines }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002580 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_permissions_cron_weekly + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify Permissions on crontab + +To properly set the permissions of /etc/crontab, run the command: +$ sudo chmod 0600 /etc/crontab + + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + APO01.06 + DSS05.04 + DSS05.07 + DSS06.02 + CCI-000366 + 4.3.3.7.3 + SR 2.1 + SR 5.2 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CM-6(a) + AC-6(1) + PR.AC-4 + PR.DS-5 + SRG-OS-000480-GPOS-00227 + 2.2.6 + 2.2 + OL09-00-002583 + SV-271830r1092202_rule + Service configuration files enable or disable features of their respective services that if configured incorrectly +can lead to insecure and vulnerable configurations. Therefore, service configuration files should have the +correct access rights to prevent unauthorized changes. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +chmod u-xs,g-xwrs,o-xwrt /etc/crontab + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002583 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_permissions_crontab + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /etc/crontab + stat: + path: /etc/crontab + register: file_exists + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002583 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_permissions_crontab + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure permission u-xs,g-xwrs,o-xwrt on /etc/crontab + file: + path: /etc/crontab + mode: u-xs,g-xwrs,o-xwrt + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - file_exists.stat is defined and file_exists.stat.exists + tags: + - DISA-STIG-OL09-00-002583 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_permissions_crontab + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Restrict at and cron to Authorized Users if Necessary + The /etc/cron.allow and /etc/at.allow files contain lists of +users who are allowed to use cron and at to delay execution of +processes. If these files exist and if the corresponding files +/etc/cron.deny and /etc/at.deny do not exist, then only users +listed in the relevant allow files can run the crontab and at commands +to submit jobs to be run at scheduled intervals. On many systems, only the +system administrator needs the ability to schedule jobs. Note that even if a +given user is not listed in cron.allow, cron jobs can still be run as +that user. The cron.allow file controls only administrative access +to the crontab command for scheduling and modifying cron jobs. + + +To restrict at and cron to only authorized users: +Remove the cron.deny file:$ sudo rm /etc/cron.deny + Edit /etc/cron.allow, adding one line for each user allowed to use +the crontab command to create cron jobs.Remove the at.deny file:$ sudo rm /etc/at.deny + Edit /etc/at.allow, adding one line for each user allowed to use +the at command to create at jobs. + + + Ensure that /etc/at.deny does not exist + The file /etc/at.deny should not exist. +Use /etc/at.allow instead. + 2.2.6 + 2.2 + Access to at should be restricted. +It is easier to manage an allow list than a deny list. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +if [[ -f /etc/at.deny ]]; then + rm /etc/at.deny + fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - disable_strategy + - file_at_deny_not_exist + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Remove /etc/at.deny + file: + path: /etc/at.deny + state: absent + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - disable_strategy + - file_at_deny_not_exist + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Ensure that /etc/cron.deny does not exist + The file /etc/cron.deny should not exist. +Use /etc/cron.allow instead. + 2.2.6 + 2.2 + Access to cron should be restricted. +It is easier to manage an allow list than a deny list. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +if [[ -f /etc/cron.deny ]]; then + rm /etc/cron.deny + fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - disable_strategy + - file_cron_deny_not_exist + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Remove /etc/cron.deny + file: + path: /etc/cron.deny + state: absent + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - disable_strategy + - file_cron_deny_not_exist + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify Group Who Owns /etc/at.allow file + If /etc/at.allow exists, it must be group-owned by root. + +To properly set the group owner of /etc/at.allow, run the command: +$ sudo chgrp root /etc/at.allow + + 2.2.6 + 2.2 + If the owner of the at.allow file is not set to root, the possibility exists for an +unauthorized user to view or edit sensitive information. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +chgrp 0 /etc/at.allow + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_groupowner_at_allow + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /etc/at.allow + stat: + path: /etc/at.allow + register: file_exists + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_groupowner_at_allow + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure group owner 0 on /etc/at.allow + file: + path: /etc/at.allow + group: '0' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - file_exists.stat is defined and file_exists.stat.exists + tags: + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_groupowner_at_allow + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify Group Who Owns /etc/cron.allow file + If /etc/cron.allow exists, it must be group-owned by root. + +To properly set the group owner of /etc/cron.allow, run the command: +$ sudo chgrp root /etc/cron.allow + + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + APO01.06 + DSS05.04 + DSS05.07 + DSS06.02 + CCI-000366 + 4.3.3.7.3 + SR 2.1 + SR 5.2 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CM-6(a) + AC-6(1) + PR.AC-4 + PR.DS-5 + SRG-OS-000480-GPOS-00227 + 2.2.6 + 2.2 + If the owner of the cron.allow file is not set to root, the possibility exists for an +unauthorized user to view or edit sensitive information. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +chgrp 0 /etc/cron.allow + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_groupowner_cron_allow + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /etc/cron.allow + stat: + path: /etc/cron.allow + register: file_exists + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_groupowner_cron_allow + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure group owner 0 on /etc/cron.allow + file: + path: /etc/cron.allow + group: '0' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - file_exists.stat is defined and file_exists.stat.exists + tags: + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_groupowner_cron_allow + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify User Who Owns /etc/cron.allow file + If /etc/cron.allow exists, it must be owned by root. + +To properly set the owner of /etc/cron.allow, run the command: +$ sudo chown root /etc/cron.allow + + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + APO01.06 + DSS05.04 + DSS05.07 + DSS06.02 + CCI-000366 + 4.3.3.7.3 + SR 2.1 + SR 5.2 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CM-6(a) + AC-6(1) + PR.AC-4 + PR.DS-5 + SRG-OS-000480-GPOS-00227 + 2.2.6 + 2.2 + If the owner of the cron.allow file is not set to root, the possibility exists for an +unauthorized user to view or edit sensitive information. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +chown 0 /etc/cron.allow + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_owner_cron_allow + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /etc/cron.allow + stat: + path: /etc/cron.allow + register: file_exists + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_owner_cron_allow + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure owner 0 on /etc/cron.allow + file: + path: /etc/cron.allow + owner: '0' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - file_exists.stat is defined and file_exists.stat.exists + tags: + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_owner_cron_allow + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify Permissions on /etc/at.allow file + If /etc/at.allow exists, it must have permissions 0640 +or more restrictive. + + +To properly set the permissions of /etc/at.allow, run the command: +$ sudo chmod 0640 /etc/at.allow + + 2.2.6 + 2.2 + If the permissions of the at.allow file are not set to 0640 or more restrictive, +the possibility exists for an unauthorized user to view or edit sensitive information. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +chmod u-xs,g-xws,o-xwrt /etc/at.allow + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_permissions_at_allow + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /etc/at.allow + stat: + path: /etc/at.allow + register: file_exists + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_permissions_at_allow + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure permission u-xs,g-xws,o-xwrt on /etc/at.allow + file: + path: /etc/at.allow + mode: u-xs,g-xws,o-xwrt + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - file_exists.stat is defined and file_exists.stat.exists + tags: + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_permissions_at_allow + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify Permissions on /etc/cron.allow file + If /etc/cron.allow exists, it must have permissions 0640 +or more restrictive. + + +To properly set the permissions of /etc/cron.allow, run the command: +$ sudo chmod 0640 /etc/cron.allow + + CCI-000366 + SRG-OS-000480-GPOS-00227 + 2.2.6 + 2.2 + If the permissions of the cron.allow file are not set to 0640 or more restrictive, +the possibility exists for an unauthorized user to view or edit sensitive information. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +chmod u-xs,g-xws,o-xwrt /etc/cron.allow + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_permissions_cron_allow + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /etc/cron.allow + stat: + path: /etc/cron.allow + register: file_exists + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_permissions_cron_allow + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure permission u-xs,g-xws,o-xwrt on /etc/cron.allow + file: + path: /etc/cron.allow + mode: u-xs,g-xws,o-xwrt + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - file_exists.stat is defined and file_exists.stat.exists + tags: + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_permissions_cron_allow + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + + + Deprecated services + Some deprecated software services impact the overall system security due to their behavior (leak of +confidentiality in network exchange, usage as uncontrolled communication channel, risk associated with the service due to its old age, etc. + + Uninstall the inet-based telnet server + The inet-based telnet daemon should be uninstalled. + 11 + 12 + 14 + 15 + 3 + 8 + 9 + APO13.01 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS01.04 + DSS05.02 + DSS05.03 + DSS05.05 + DSS06.06 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.2 + 4.3.4.3.3 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 7.1 + SR 7.6 + A.11.2.6 + A.12.1.2 + A.12.5.1 + A.12.6.2 + A.13.1.1 + A.13.2.1 + A.14.1.3 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.6.2.1 + A.6.2.2 + A.9.1.2 + CM-7(a) + CM-7(b) + CM-6(a) + PR.AC-3 + PR.IP-1 + PR.PT-3 + PR.PT-4 + telnet allows clear text communications, and does not protect any +data transmission between client and server. Any confidential data can be +listened and no integrity checking is made. + +# CAUTION: This remediation script will remove inetutils-telnetd +# from the system, and may remove any packages +# that depend on inetutils-telnetd. Execute this +# remediation AFTER testing on a non-production +# system! + +if rpm -q --quiet "inetutils-telnetd" ; then +yum remove -y "inetutils-telnetd" +fi + + - name: Ensure inetutils-telnetd is removed + package: + name: inetutils-telnetd + state: absent + tags: + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - package_inetutils-telnetd_removed + + include remove_inetutils-telnetd + +class remove_inetutils-telnetd { + package { 'inetutils-telnetd': + ensure => 'purged', + } +} + + +package --remove=inetutils-telnetd + + + + + + + Uninstall the nis package + The support for Yellowpages should not be installed unless it is required. + NIS is the historical SUN service for central account management, more and more replaced by LDAP. +NIS does not support efficiently security constraints, ACL, etc. and should not be used. + +# CAUTION: This remediation script will remove nis +# from the system, and may remove any packages +# that depend on nis. Execute this +# remediation AFTER testing on a non-production +# system! + +if rpm -q --quiet "nis" ; then +yum remove -y "nis" +fi + + - name: Ensure nis is removed + package: + name: nis + state: absent + tags: + - disable_strategy + - low_complexity + - low_disruption + - low_severity + - no_reboot_needed + - package_nis_removed + + include remove_nis + +class remove_nis { + package { 'nis': + ensure => 'purged', + } +} + + +package --remove=nis + + + + + + + Uninstall the ssl compliant telnet server + The telnet daemon, even with ssl support, should be uninstalled. + 11 + 12 + 14 + 15 + 3 + 8 + 9 + APO13.01 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS01.04 + DSS05.02 + DSS05.03 + DSS05.05 + DSS06.06 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.2 + 4.3.4.3.3 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 7.1 + SR 7.6 + A.11.2.6 + A.12.1.2 + A.12.5.1 + A.12.6.2 + A.13.1.1 + A.13.2.1 + A.14.1.3 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.6.2.1 + A.6.2.2 + A.9.1.2 + CM-7(a) + CM-7(b) + CM-6(a) + PR.AC-3 + PR.IP-1 + PR.PT-3 + PR.PT-4 + telnet, even with ssl support, should not be installed. +When remote shell is required, up-to-date ssh daemon can be used. + +# CAUTION: This remediation script will remove telnetd-ssl +# from the system, and may remove any packages +# that depend on telnetd-ssl. Execute this +# remediation AFTER testing on a non-production +# system! + +if rpm -q --quiet "telnetd-ssl" ; then +yum remove -y "telnetd-ssl" +fi + + - name: Ensure telnetd-ssl is removed + package: + name: telnetd-ssl + state: absent + tags: + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - package_telnetd-ssl_removed + + include remove_telnetd-ssl + +class remove_telnetd-ssl { + package { 'telnetd-ssl': + ensure => 'purged', + } +} + + +package --remove=telnetd-ssl + + + + + + + Uninstall the telnet server + The telnet daemon should be uninstalled. + 11 + 12 + 14 + 15 + 3 + 8 + 9 + APO13.01 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS01.04 + DSS05.02 + DSS05.03 + DSS05.05 + DSS06.06 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.2 + 4.3.4.3.3 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 7.1 + SR 7.6 + A.11.2.6 + A.12.1.2 + A.12.5.1 + A.12.6.2 + A.13.1.1 + A.13.2.1 + A.14.1.3 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.6.2.1 + A.6.2.2 + A.9.1.2 + CM-7(a) + CM-7(b) + CM-6(a) + PR.AC-3 + PR.IP-1 + PR.PT-3 + PR.PT-4 + telnet allows clear text communications, and does not protect +any data transmission between client and server. Any confidential data +can be listened and no integrity checking is made.' + +# CAUTION: This remediation script will remove telnetd +# from the system, and may remove any packages +# that depend on telnetd. Execute this +# remediation AFTER testing on a non-production +# system! + +if rpm -q --quiet "telnetd" ; then +yum remove -y "telnetd" +fi + + - name: Ensure telnetd is removed + package: + name: telnetd + state: absent + tags: + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - package_telnetd_removed + + include remove_telnetd + +class remove_telnetd { + package { 'telnetd': + ensure => 'purged', + } +} + + +package --remove=telnetd + + + + + + + + DHCP + The Dynamic Host Configuration Protocol (DHCP) allows +systems to request and obtain an IP address and other configuration +parameters from a server. + + +This guide recommends configuring networking on clients by manually editing +the appropriate files under /etc/sysconfig. Use of DHCP can make client +systems vulnerable to compromise by rogue DHCP servers, and should be avoided +unless necessary. If using DHCP is necessary, however, there are best practices +that should be followed to minimize security risk. + + Configure DHCP Client if Necessary + If DHCP must be used, then certain configuration changes can +minimize the amount of information it receives and applies from the network, +and thus the amount of incorrect information a rogue DHCP server could +successfully distribute. For more information on configuring dhclient, see the +dhclient(8) and dhclient.conf(5) man pages. + + Minimize the DHCP-Configured Options + Create the file /etc/dhcp/dhclient.conf, and add an +appropriate setting for each of the ten configuration settings which can be +obtained via DHCP. For each setting, do one of the following: + +If the setting should not be configured remotely by the DHCP server, +select an appropriate static value, and add the line: +supersede setting value; +If the setting should be configured remotely by the DHCP server, add the lines: +request setting; +require setting; +For example, suppose the DHCP server should provide only the IP address itself +and the subnet mask. Then the entire file should look like: +supersede domain-name "example.com"; +supersede domain-name-servers 192.168.1.2; +supersede nis-domain ""; +supersede nis-servers ""; +supersede ntp-servers "ntp.example.com "; +supersede routers 192.168.1.1; +supersede time-offset -18000; +request subnet-mask; +require subnet-mask; + + In this example, the options nis-servers and +nis-domain are set to empty strings, on the assumption that the deprecated NIS +protocol is not in use. It is necessary to supersede settings for unused +services so that they cannot be set by a hostile DHCP server. If an option is +set to an empty string, dhclient will typically not attempt to configure the +service. + By default, the DHCP client program, dhclient, requests and applies +ten configuration options (in addition to the IP address) from the DHCP server. +subnet-mask, broadcast-address, time-offset, routers, domain-name, +domain-name-servers, host-name, nis-domain, nis-servers, and ntp-servers. Many +of the options requested and applied by dhclient may be the same for every +system on a network. It is recommended that almost all configuration options be +assigned statically, and only options which must vary on a host-by-host basis +be assigned via DHCP. This limits the damage which can be done by a rogue DHCP +server. If appropriate for your site, it is also possible to supersede the +host-name directive in /etc/dhcp/dhclient.conf, establishing a static +hostname for the system. However, dhclient does not use the host name option +provided by the DHCP server (instead using the value provided by a reverse DNS +lookup). + + + + Configure DHCP Server + If the system must act as a DHCP server, the configuration +information it serves should be minimized. Also, support for other protocols +and DNS-updating schemes should be explicitly disabled unless needed. The +configuration file for dhcpd is called /etc/dhcp/dhcpd.conf. The file +begins with a number of global configuration options. The remainder of the file +is divided into sections, one for each block of addresses offered by dhcpd, +each of which contains configuration options specific to that address +block. + + Minimize Served Information + Edit /etc/dhcp/dhcpd.conf. Examine each address range section within +the file, and ensure that the following options are not defined unless there is +an operational need to provide this information via DHCP: +option domain-name +option domain-name-servers +option nis-domain +option nis-servers +option ntp-servers +option routers +option time-offset + + By default, the Red Hat Enterprise Linux client installation uses DHCP +to request much of the above information from the DHCP server. In particular, +domain-name, domain-name-servers, and routers are configured via DHCP. These +settings are typically necessary for proper network functionality, but are also +usually static across systems at a given site. + 11 + 14 + 3 + 9 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS05.02 + DSS05.05 + DSS06.06 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.2 + 4.3.4.3.3 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 7.6 + A.12.1.2 + A.12.5.1 + A.12.6.2 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.9.1.2 + CM-7(a) + CM-7(b) + CM-6(a) + PR.IP-1 + PR.PT-3 + Because the configuration information provided by the DHCP server +could be maliciously provided to clients by a rogue DHCP server, the amount of +information provided via DHCP should be minimized. Remove these definitions +from the DHCP server configuration to ensure that legitimate clients do not +unnecessarily rely on DHCP for this information. + + + + Disable DHCP Server + The DHCP server dhcpd is not installed or activated by +default. If the software was installed and activated, but the +system does not need to act as a DHCP server, it should be disabled +and removed. + + Uninstall DHCP Server Package + If the system does not need to act as a DHCP server, +the dhcp package can be uninstalled. + +The dhcp-server package can be removed with the following command: + +$ sudo yum erase dhcp-server + + 11 + 14 + 3 + 9 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS05.02 + DSS05.05 + DSS06.06 + CCI-000366 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.2 + 4.3.4.3.3 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 7.6 + A.12.1.2 + A.12.5.1 + A.12.6.2 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.9.1.2 + CM-7(a) + CM-7(b) + CM-6(a) + PR.IP-1 + PR.PT-3 + R62 + 2.2.4 + 2.2 + Removing the DHCP server ensures that it cannot be easily or +accidentally reactivated and disrupt network operation. + +# CAUTION: This remediation script will remove dhcp +# from the system, and may remove any packages +# that depend on dhcp. Execute this +# remediation AFTER testing on a non-production +# system! + +if rpm -q --quiet "dhcp" ; then +yum remove -y "dhcp" +fi + + - name: Ensure dhcp is removed + package: + name: dhcp + state: absent + tags: + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.4 + - disable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - package_dhcp_removed + + include remove_dhcp + +class remove_dhcp { + package { 'dhcp': + ensure => 'purged', + } +} + + +package --remove=dhcp + + + + + + + + + + + + DNS Server + Most organizations have an operational need to run at +least one nameserver. However, there are many common attacks +involving DNS server software, and this server software should +be disabled on any system +on which it is not needed. + + Disable DNS Server + DNS software should be disabled on any systems which does not +need to be a nameserver. Note that the BIND DNS server software is +not installed on Oracle Linux 9 by default. The remainder of this section +discusses secure configuration of systems which must be +nameservers. + + Uninstall bind Package + The named service is provided by the bind package. +The bind package can be removed with the following command: + +$ sudo yum erase bind + + 11 + 14 + 3 + 9 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS05.02 + DSS05.05 + DSS06.06 + CCI-000366 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.2 + 4.3.4.3.3 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 7.6 + A.12.1.2 + A.12.5.1 + A.12.6.2 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.9.1.2 + CM-7(a) + CM-7(b) + CM-6(a) + PR.IP-1 + PR.PT-3 + A.8.SEC-OL4 + If there is no need to make DNS server software available, +removing it provides a safeguard against its activation. + +# CAUTION: This remediation script will remove bind +# from the system, and may remove any packages +# that depend on bind. Execute this +# remediation AFTER testing on a non-production +# system! + +if rpm -q --quiet "bind" ; then +yum remove -y "bind" +fi + + - name: Ensure bind is removed + package: + name: bind + state: absent + tags: + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - low_disruption + - low_severity + - no_reboot_needed + - package_bind_removed + + include remove_bind + +class remove_bind { + package { 'bind': + ensure => 'purged', + } +} + + +package --remove=bind + + + + + + + + + + + + Application Whitelisting Daemon + Fapolicyd (File Access Policy Daemon) implements application whitelisting +to decide file access rights. Applications that are known via a reputation +source are allowed access while unknown applications are not. The daemon +makes use of the kernel's fanotify interface to determine file access rights. + + + Install fapolicyd Package + The fapolicyd package can be installed with the following command: + +$ sudo yum install fapolicyd + + CCI-001774 + CCI-001764 + CM-6(a) + SI-4(22) + FMT_SMF_EXT.1 + SRG-OS-000370-GPOS-00155 + SRG-OS-000368-GPOS-00154 + SRG-OS-000480-GPOS-00230 + OL09-00-000340 + SV-271506r1091230_rule + fapolicyd (File Access Policy Daemon) +implements application whitelisting to decide file access rights. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +if ! rpm -q --quiet "fapolicyd" ; then + yum install -y "fapolicyd" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-000340 + - NIST-800-53-CM-6(a) + - NIST-800-53-SI-4(22) + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - package_fapolicyd_installed + +- name: Ensure fapolicyd is installed + package: + name: fapolicyd + state: present + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-000340 + - NIST-800-53-CM-6(a) + - NIST-800-53-SI-4(22) + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - package_fapolicyd_installed + + include install_fapolicyd + +class install_fapolicyd { + package { 'fapolicyd': + ensure => 'installed', + } +} + + +package --add=fapolicyd + + +[[packages]] +name = "fapolicyd" +version = "*" + + + + + + + + + + Enable the File Access Policy Service + The File Access Policy service should be enabled. + +The fapolicyd service can be enabled with the following command: +$ sudo systemctl enable fapolicyd.service + + CCI-001774 + CCI-001764 + CM-6(a) + SI-4(22) + FMT_SMF_EXT.1 + SRG-OS-000370-GPOS-00155 + SRG-OS-000368-GPOS-00154 + SRG-OS-000480-GPOS-00230 + OL09-00-000341 + SV-271507r1091233_rule + The fapolicyd service (File Access Policy Daemon) +implements application whitelisting to decide file access rights. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +SYSTEMCTL_EXEC='/usr/bin/systemctl' +"$SYSTEMCTL_EXEC" unmask 'fapolicyd.service' +if [[ $("$SYSTEMCTL_EXEC" is-system-running) != "offline" ]]; then + "$SYSTEMCTL_EXEC" start 'fapolicyd.service' +fi +"$SYSTEMCTL_EXEC" enable 'fapolicyd.service' + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-000341 + - NIST-800-53-CM-6(a) + - NIST-800-53-SI-4(22) + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_fapolicyd_enabled + +- name: Enable the File Access Policy Service - Enable service fapolicyd + block: + + - name: Gather the package facts + package_facts: + manager: auto + + - name: Enable the File Access Policy Service - Enable Service fapolicyd + ansible.builtin.systemd: + name: fapolicyd + enabled: true + state: started + masked: false + when: + - '"fapolicyd" in ansible_facts.packages' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-000341 + - NIST-800-53-CM-6(a) + - NIST-800-53-SI-4(22) + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_fapolicyd_enabled + + include enable_fapolicyd + +class enable_fapolicyd { + service {'fapolicyd': + enable => true, + ensure => 'running', + } +} + + +[customizations.services] +enabled = ["fapolicyd"] + + + + + + + + + + Configure Fapolicy Module to Employ a Deny-all, Permit-by-exception Policy to Allow the Execution of Authorized Software Programs. + The Fapolicy module must be configured to employ a deny-all, permit-by-exception policy to allow the execution of authorized software programs and to prevent unauthorized software from running. + CCI-001764 + CM-7 (2) + CM-7 (5) (b) + CM-6 b + SRG-OS-000368-GPOS-00154 + SRG-OS-000370-GPOS-00155 + SRG-OS-000480-GPOS-00232 + Utilizing a whitelist provides a configuration management method for allowing the execution of only authorized software. +Using only authorized software decreases risk by limiting the number of potential vulnerabilities. Verification of whitelisted software occurs prior to execution or at system startup. + +Proceed with caution with enforcing the use of this daemon. +Improper configuration may render the system non-functional. +The "fapolicyd" API is not namespace aware and can cause issues when launching or running containers. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +cat > /etc/fapolicyd/rules.d/99-deny-everything.rules << EOF +deny perm=any all : all +EOF + +chmod 644 /etc/fapolicyd/rules.d/99-deny-everything.rules +chgrp fapolicyd /etc/fapolicyd/rules.d/99-deny-everything.rules + +if [ -e "/etc/fapolicyd/fapolicyd.conf" ] ; then + + LC_ALL=C sed -i "/^\s*permissive\s*=\s*/Id" "/etc/fapolicyd/fapolicyd.conf" +else + touch "/etc/fapolicyd/fapolicyd.conf" +fi +# make sure file has newline at the end +sed -i -e '$a\' "/etc/fapolicyd/fapolicyd.conf" + +cp "/etc/fapolicyd/fapolicyd.conf" "/etc/fapolicyd/fapolicyd.conf.bak" +# Insert at the end of the file +printf '%s\n' "permissive = 0" >> "/etc/fapolicyd/fapolicyd.conf" +# Clean up after ourselves. +rm "/etc/fapolicyd/fapolicyd.conf.bak" + +systemctl restart fapolicyd + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-53-CM-6 b + - NIST-800-53-CM-7 (2) + - NIST-800-53-CM-7 (5) (b) + - fapolicy_default_deny + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Configure Fapolicy Module to Employ a Deny-all, Permit-by-exception Policy + to Allow the Execution of Authorized Software Programs. - Ensure a Final Rule + Denying Everything + ansible.builtin.copy: + content: | + deny perm=any all : all + dest: /etc/fapolicyd/rules.d/99-deny-everything.rules + owner: root + group: fapolicyd + mode: '0644' + register: result_fapolicyd_final_rule + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-CM-6 b + - NIST-800-53-CM-7 (2) + - NIST-800-53-CM-7 (5) (b) + - fapolicy_default_deny + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Configure Fapolicy Module to Employ a Deny-all, Permit-by-exception Policy + to Allow the Execution of Authorized Software Programs. - Ensure fapolicyd is + Not Permissive + ansible.builtin.lineinfile: + path: /etc/fapolicyd/fapolicyd.conf + regexp: ^(permissive\s*=).*$ + line: \1 0 + backrefs: true + register: result_fapolicyd_enforced + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-CM-6 b + - NIST-800-53-CM-7 (2) + - NIST-800-53-CM-7 (5) (b) + - fapolicy_default_deny + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Configure Fapolicy Module to Employ a Deny-all, Permit-by-exception Policy + to Allow the Execution of Authorized Software Programs. - Restart fapolicyd If + Permissive Mode or Final Rule is Changed + ansible.builtin.service: + name: fapolicyd + state: restarted + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - result_fapolicyd_final_rule is changed or result_fapolicyd_enforced is changed + tags: + - NIST-800-53-CM-6 b + - NIST-800-53-CM-7 (2) + - NIST-800-53-CM-7 (5) (b) + - fapolicy_default_deny + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + + + + + + + + + + fapolicyd Must be Configured to Limit Access to Users Home Folders + fapolicyd needs be configured so that users cannot give access to their home folders to other users. + This rule is deprecated and there is no replacement at this time. +Previous versions of this rule provided fixtext that would cause fapolicyd not to start. + CCI-000366 + CM-6 b + SRG-OS-000480-GPOS-00230 + Users' home directories/folders may contain information of a sensitive nature. +Non-privileged users should coordinate any sharing of information with a System Administrator (SA) through shared resources. +fapolicyd can confine users to their home directory, not allowing them to make any changes outside of their own home directories. +Confining users to their home directory will minimize the risk of sharing information. + + + + FTP Server + FTP is a common method for allowing remote access to +files. Like telnet, the FTP protocol is unencrypted, which means +that passwords and other data transmitted during the session can be +captured and that the session is vulnerable to hijacking. +Therefore, running the FTP server software is not recommended. + + +However, there are some FTP server configurations which may +be appropriate for some environments, particularly those which +allow only read-only anonymous access as a means of downloading +data available to the public. + + Remove ftp Package + FTP (File Transfer Protocol) is a traditional and widely used standard tool for +transferring files between a server and clients over a network, especially where no +authentication is necessary (permits anonymous users to connect to a server). + +The ftp package can be removed with the following command: + +$ sudo yum erase ftp + + 2.2.4 + 2.2 + FTP does not protect the confidentiality of data or authentication credentials. It +is recommended SFTP be used if file transfer is required. Unless there is a need +to run the system as a FTP server (for example, to allow anonymous downloads), it is +recommended that the package be removed to reduce the potential attack surface. + +# CAUTION: This remediation script will remove ftp +# from the system, and may remove any packages +# that depend on ftp. Execute this +# remediation AFTER testing on a non-production +# system! + +if rpm -q --quiet "ftp" ; then +yum remove -y "ftp" +fi + + - name: Ensure ftp is removed + package: + name: ftp + state: absent + tags: + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.4 + - disable_strategy + - low_complexity + - low_disruption + - low_severity + - no_reboot_needed + - package_ftp_removed + + include remove_ftp + +class remove_ftp { + package { 'ftp': + ensure => 'purged', + } +} + + +package --remove=ftp + + + + + + + + + + Disable vsftpd if Possible + To minimize attack surface, disable vsftpd if at all +possible. + + Uninstall vsftpd Package + The vsftpd package can be removed with the following command: $ sudo yum erase vsftpd + + 11 + 14 + 3 + 9 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS05.02 + DSS05.05 + DSS06.06 + CCI-000366 + CCI-000197 + CCI-000381 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.2 + 4.3.4.3.3 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 7.6 + A.12.1.2 + A.12.5.1 + A.12.6.2 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.9.1.2 + CM-7(a) + CM-7(b) + CM-6(a) + IA-5(1)(c) + IA-5(1).1(v) + CM-7 + CM-7.1(ii) + PR.IP-1 + PR.PT-3 + SRG-OS-000074-GPOS-00042 + SRG-OS-000095-GPOS-00049 + SRG-OS-000480-GPOS-00227 + A.8.SEC-OL4 + OL09-00-000130 + SV-271462r1091098_rule + Removing the vsftpd package decreases the risk of its +accidental activation. + +# CAUTION: This remediation script will remove vsftpd +# from the system, and may remove any packages +# that depend on vsftpd. Execute this +# remediation AFTER testing on a non-production +# system! + +if rpm -q --quiet "vsftpd" ; then +yum remove -y "vsftpd" +fi + + - name: Ensure vsftpd is removed + package: + name: vsftpd + state: absent + tags: + - DISA-STIG-OL09-00-000130 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7 + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-CM-7.1(ii) + - NIST-800-53-IA-5(1)(c) + - NIST-800-53-IA-5(1).1(v) + - disable_strategy + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - package_vsftpd_removed + + include remove_vsftpd + +class remove_vsftpd { + package { 'vsftpd': + ensure => 'purged', + } +} + + +package --remove=vsftpd + + + + + + + + + + + Configure vsftpd to Provide FTP Service if Necessary + The primary vsftpd configuration file is +/etc/vsftpd.conf, if that file exists, or +/etc/vsftpd/vsftpd.conf if it does not. + + Configure Firewalls to Protect the FTP Server + By default, iptables +blocks access to the ports used by the web server. + +To configure iptables to allow port 21 traffic, one must edit +/etc/sysconfig/iptables and +/etc/sysconfig/ip6tables (if IPv6 is in use). +Add the following line, ensuring that it appears before the final LOG and DROP lines for the INPUT chain: +-A INPUT -m state --state NEW -p tcp --dport 21 -j ACCEPT +Edit the file /etc/sysconfig/iptables-config. Ensure that the space-separated list of modules contains +the FTP connection tracking module: +IPTABLES_MODULES="ip_conntrack_ftp" + + These settings configure the firewall to allow connections to an FTP server. + + + Restrict the Set of Users Allowed to Access FTP + This section describes how to disable non-anonymous (password-based) FTP logins, or, if it is not possible to +do this entirely due to legacy applications, how to restrict insecure FTP login to only those users who have an +identified need for this access. + + Limit Users Allowed FTP Access if Necessary + If there is a mission-critical reason for users to access their accounts via the insecure FTP protocol, limit the set of users who are allowed this access. Edit the vsftpd configuration file. Add or correct the following configuration options: +userlist_enable=YES +userlist_file=/etc/vsftp.ftpusers +userlist_deny=NO +Edit the file /etc/vsftp.ftpusers. For each user USERNAME who should be allowed to access the system via FTP, add a line containing that user's name: +USERNAME +If anonymous access is also required, add the anonymous usernames to /etc/vsftp.ftpusers as well. +anonymous +ftp + + Historically, the file /etc/ftpusers contained a list of users who were not allowed to access the system via FTP. It was used to prevent system users such as the root user from logging in via the insecure FTP protocol. However, when the configuration option userlist deny=NO is set, vsftpd interprets ftpusers as the set of users who are allowed to login via FTP. Since it should be possible for most users to access their accounts via secure protocols, it is recommended that this setting be used, so that non-anonymous FTP access can be limited to legacy users who have been explicitly identified. + + + + + + IMAP and POP3 Server + Dovecot provides IMAP and POP3 services. It is not +installed by default. The project page at + http://www.dovecot.org +contains more detailed information about Dovecot +configuration. + + Disable Cyrus IMAP + If the system does not need to operate as an IMAP or +POP3 server, the Cyrus IMAP software should be removed. + + Uninstall cyrus-imapd Package + The cyrus-imapd package can be removed with the following command: + +$ sudo yum erase cyrus-imapd + + A.8.SEC-OL4 + If there is no need to make the cyrus-imapd software available, +removing it provides a safeguard against its activation. + +# CAUTION: This remediation script will remove cyrus-imapd +# from the system, and may remove any packages +# that depend on cyrus-imapd. Execute this +# remediation AFTER testing on a non-production +# system! + +if rpm -q --quiet "cyrus-imapd" ; then +yum remove -y "cyrus-imapd" +fi + + - name: Ensure cyrus-imapd is removed + package: + name: cyrus-imapd + state: absent + tags: + - disable_strategy + - low_complexity + - low_disruption + - no_reboot_needed + - package_cyrus-imapd_removed + - unknown_severity + + include remove_cyrus-imapd + +class remove_cyrus-imapd { + package { 'cyrus-imapd': + ensure => 'purged', + } +} + + +package --remove=cyrus-imapd + + + + + + + + + + + Disable Dovecot + If the system does not need to operate as an IMAP or +POP3 server, the dovecot software should be disabled and removed. + + Uninstall dovecot Package + +The dovecot package can be removed with the following command: + +$ sudo yum erase dovecot + + A.8.SEC-OL4 + If there is no need to make the Dovecot software available, +removing it provides a safeguard against its activation. + +# CAUTION: This remediation script will remove dovecot +# from the system, and may remove any packages +# that depend on dovecot. Execute this +# remediation AFTER testing on a non-production +# system! + +if rpm -q --quiet "dovecot" ; then +yum remove -y "dovecot" +fi + + - name: Ensure dovecot is removed + package: + name: dovecot + state: absent + tags: + - disable_strategy + - low_complexity + - low_disruption + - no_reboot_needed + - package_dovecot_removed + - unknown_severity + + include remove_dovecot + +class remove_dovecot { + package { 'dovecot': + ensure => 'purged', + } +} + + +package --remove=dovecot + + + + + + + + + + + + Mail Server Software + Mail servers are used to send and receive email over the network. +Mail is a very common service, and Mail Transfer Agents (MTAs) are obvious +targets of network attack. +Ensure that systems are not running MTAs unnecessarily, +and configure needed MTAs as defensively as possible. + + +Very few systems at any site should be configured to directly receive email over the +network. Users should instead use mail client programs to retrieve email +from a central server that supports protocols such as IMAP or POP3. +However, it is normal for most systems to be independently capable of sending email, +for instance so that cron jobs can report output to an administrator. +Most MTAs, including Postfix, support a submission-only mode in which mail can be sent from +the local system to a central site MTA (or directly delivered to a local account), +but the system still cannot receive mail directly over a network. + + +The alternatives program in Oracle Linux 9 permits selection of other mail server software +(such as Sendmail), but Postfix is the default and is preferred. +Postfix was coded with security in mind and can also be more effectively contained by +SELinux as its modular design has resulted in separate processes performing specific actions. +More information is available on its website, + http://www.postfix.org. + + + The Postfix package is installed + A mail server is required for sending emails. +The postfix package can be installed with the following command: + +$ sudo yum install postfix + + CCI-000139 + SRG-OS-000046-GPOS-00022 + Emails can be used to notify designated personnel about important +system events such as failures or warnings. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +if ! rpm -q --quiet "postfix" ; then + yum install -y "postfix" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - package_postfix_installed + +- name: Ensure postfix is installed + package: + name: postfix + state: present + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - package_postfix_installed + + include install_postfix + +class install_postfix { + package { 'postfix': + ensure => 'installed', + } +} + + +package --add=postfix + + +[[packages]] +name = "postfix" +version = "*" + + + + + + + + + + The s-nail Package Is Installed + A mail server is required for sending emails. +The s-nail package can be installed with the following command: + +$ sudo yum install s-nail + + CCI-001744 + CM-3(5) + SRG-OS-000363-GPOS-00150 + OL09-00-000290 + SV-271495r1091197_rule + Emails can be used to notify designated personnel about important +system events such as failures or warnings. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +if ! rpm -q --quiet "s-nail" ; then + yum install -y "s-nail" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-000290 + - NIST-800-53-CM-3(5) + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - package_s-nail_installed + +- name: Ensure s-nail is installed + package: + name: s-nail + state: present + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-000290 + - NIST-800-53-CM-3(5) + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - package_s-nail_installed + + include install_s-nail + +class install_s-nail { + package { 's-nail': + ensure => 'installed', + } +} + + +package --add=s-nail + + +[[packages]] +name = "s-nail" +version = "*" + + + + + + + + + + Uninstall Sendmail Package + Sendmail is not the default mail transfer agent and is +not installed by default. +The sendmail package can be removed with the following command: + +$ sudo yum erase sendmail + + 11 + 14 + 3 + 9 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS05.02 + DSS05.05 + DSS06.06 + CCI-000366 + CCI-000381 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.2 + 4.3.4.3.3 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 7.6 + A.12.1.2 + A.12.5.1 + A.12.6.2 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.9.1.2 + CM-7(a) + CM-7(b) + CM-6(a) + PR.IP-1 + PR.PT-3 + SRG-OS-000480-GPOS-00227 + SRG-OS-000095-GPOS-00049 + R62 + OL09-00-000150 + SV-271466r1091110_rule + The sendmail software was not developed with security in mind and +its design prevents it from being effectively contained by SELinux. Postfix +should be used instead. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# CAUTION: This remediation script will remove sendmail +# from the system, and may remove any packages +# that depend on sendmail. Execute this +# remediation AFTER testing on a non-production +# system! + +if rpm -q --quiet "sendmail" ; then +yum remove -y "sendmail" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-000150 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - package_sendmail_removed + +- name: Ensure sendmail is removed + package: + name: sendmail + state: absent + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-000150 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - package_sendmail_removed + + include remove_sendmail + +class remove_sendmail { + package { 'sendmail': + ensure => 'purged', + } +} + + +package --remove=sendmail + + + + + + + + + + Enable Postfix Service + The Postfix mail transfer agent is used for local mail delivery +within the system. The default configuration only listens for connections to +the default SMTP port (port 25) on the loopback interface (127.0.0.1). It is +recommended to leave this service enabled for local mail delivery. + +The postfix service can be enabled with the following command: +$ sudo systemctl enable postfix.service + + Local mail delivery is essential to some system maintenance and +notification tasks. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +SYSTEMCTL_EXEC='/usr/bin/systemctl' +"$SYSTEMCTL_EXEC" unmask 'postfix.service' +if [[ $("$SYSTEMCTL_EXEC" is-system-running) != "offline" ]]; then + "$SYSTEMCTL_EXEC" start 'postfix.service' +fi +"$SYSTEMCTL_EXEC" enable 'postfix.service' + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - enable_strategy + - low_complexity + - low_disruption + - no_reboot_needed + - service_postfix_enabled + - unknown_severity + +- name: Enable Postfix Service - Enable service postfix + block: + + - name: Gather the package facts + package_facts: + manager: auto + + - name: Enable Postfix Service - Enable Service postfix + ansible.builtin.systemd: + name: postfix + enabled: true + state: started + masked: false + when: + - '"postfix" in ansible_facts.packages' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - enable_strategy + - low_complexity + - low_disruption + - no_reboot_needed + - service_postfix_enabled + - unknown_severity + + include enable_postfix + +class enable_postfix { + service {'postfix': + enable => true, + ensure => 'running', + } +} + + +[customizations.services] +enabled = ["postfix"] + + + + + + + + + + Configure SMTP For Mail Clients + This section discusses settings for Postfix in a submission-only +e-mail configuration. + + Postfix Network Interfaces + The setting for inet_interfaces in /etc/postfix/main.cf + loopback-only + loopback-only + localhost + + + Postfix relayhost + Specify the host all outbound email should be routed into. + smtp.$mydomain + + + Postfix Root Mail Alias + Specify an email address (string) for a root mail alias. + change_me@localhost + system.administrator@mail.mil + + + Configure System to Forward All Mail For The Root Account + Make sure that mails delivered to root user are forwarded to a monitored +email address. Make sure that the address + is a valid email address +reachable from the system in question. Use the following command to +configure the alias: +$ sudo echo "root: " >> /etc/aliases +$ sudo newaliases + + CCI-000139 + CM-6(a) + SRG-OS-000046-GPOS-00022 + R75 + OL09-00-002405 + SV-271744r1091944_rule + A number of system services utilize email messages sent to the root user to +notify system administrators of active or impending issues. These messages must +be forwarded to at least one monitored email address. + + + + + + + + + + Configure System to Forward All Mail From Postmaster to The Root Account + Verify the administrators are notified in the event of an audit processing failure. +Check that the "/etc/aliases" file has a defined value for "root". +$ sudo grep "postmaster:\s*root$" /etc/aliases + +postmaster: root + + CCI-000139 + AU-5(a) + AU-5.1(ii) + SRG-OS-000046-GPOS-00022 + OL09-00-000815 + SV-271589r1091479_rule + It is critical for the appropriate personnel to be aware if a system is at risk of failing to +process audit logs as required. Without this notification, the security personnel may be +unaware of an impending failure of the audit capability, and system operation may be adversely +affected. + +Audit processing failures include software/hardware errors, failures in the audit capturing +mechanisms, and audit storage capacity being reached or exceeded. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +if [ -e "/etc/aliases" ] ; then + + LC_ALL=C sed -i "/^\s*postmaster\s*:\s*/Id" "/etc/aliases" +else + touch "/etc/aliases" +fi +# make sure file has newline at the end +sed -i -e '$a\' "/etc/aliases" + +cp "/etc/aliases" "/etc/aliases.bak" +# Insert at the end of the file +printf '%s\n' "postmaster: root" >> "/etc/aliases" +# Clean up after ourselves. +rm "/etc/aliases.bak" + +if [ -f /usr/bin/newaliases ]; then + newaliases +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-000815 + - NIST-800-53-AU-5(a) + - NIST-800-53-AU-5.1(ii) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - postfix_client_configure_mail_alias_postmaster + +- name: Configure System to Forward All Mail From Postmaster to The Root Account + block: + + - name: Check for duplicate values + lineinfile: + path: /etc/aliases + create: true + regexp: (?i)^\s*postmaster\s*:\s* + state: absent + check_mode: true + changed_when: false + register: dupes + + - name: Deduplicate values from /etc/aliases + lineinfile: + path: /etc/aliases + create: true + regexp: (?i)^\s*postmaster\s*:\s* + state: absent + when: dupes.found is defined and dupes.found > 1 + + - name: Insert correct line to /etc/aliases + lineinfile: + path: /etc/aliases + create: true + regexp: (?i)^\s*postmaster\s*:\s* + line: 'postmaster: root' + state: present + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-000815 + - NIST-800-53-AU-5(a) + - NIST-800-53-AU-5.1(ii) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - postfix_client_configure_mail_alias_postmaster + +- name: Check if newaliases command is available + ansible.builtin.stat: + path: /usr/bin/newaliases + register: result_newaliases_present + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-000815 + - NIST-800-53-AU-5(a) + - NIST-800-53-AU-5.1(ii) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - postfix_client_configure_mail_alias_postmaster + +- name: Update postfix aliases + ansible.builtin.command: + cmd: newaliases + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - result_newaliases_present.stat.exists + tags: + - DISA-STIG-OL09-00-000815 + - NIST-800-53-AU-5(a) + - NIST-800-53-AU-5.1(ii) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - postfix_client_configure_mail_alias_postmaster + + + + + + + + + + Configure System to Forward All Mail through a specific host + Set up a relay host that will act as a gateway for all outbound email. +Edit the file /etc/postfix/main.cf to ensure that only the following +relayhost line appears: +relayhost = + + + A central outbound email location ensures messages sent from any network host +can be audited for potential unexpected content. Tooling on the central server +may help prevent spam or viruses from being delivered. + + + + + + + Disable Postfix Network Listening + Edit the file /etc/postfix/main.cf to ensure that only the following +inet_interfaces line appears: +inet_interfaces = + + + 11 + 14 + 3 + 9 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS05.02 + DSS05.05 + DSS06.06 + CCI-000382 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.2 + 4.3.4.3.3 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 7.6 + A.12.1.2 + A.12.5.1 + A.12.6.2 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.9.1.2 + CM-7(a) + CM-7(b) + CM-6(a) + PR.IP-1 + PR.PT-3 + R74 + 1.4.2 + 1.4 + This ensures postfix accepts mail messages +(such as cron job reports) from the local system only, +and not from the network, which protects it from network attack. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q postfix; }; then + +var_postfix_inet_interfaces='' + + +if [ -e "/etc/postfix/main.cf" ] ; then + + LC_ALL=C sed -i "/^\s*inet_interfaces\s\+=\s\+/Id" "/etc/postfix/main.cf" +else + touch "/etc/postfix/main.cf" +fi +# make sure file has newline at the end +sed -i -e '$a\' "/etc/postfix/main.cf" + +cp "/etc/postfix/main.cf" "/etc/postfix/main.cf.bak" +# Insert at the end of the file +printf '%s\n' "inet_interfaces=$var_postfix_inet_interfaces" >> "/etc/postfix/main.cf" +# Clean up after ourselves. +rm "/etc/postfix/main.cf.bak" + +systemctl restart postfix + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: XCCDF Value var_postfix_inet_interfaces # promote to variable + set_fact: + var_postfix_inet_interfaces: !!str + tags: + - always + +- name: Gather list of packages + package_facts: + manager: auto + tags: + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.2 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - postfix_network_listening_disabled + - restrict_strategy + +- name: Make changes to Postfix configuration file + lineinfile: + path: /etc/postfix/main.cf + create: false + regexp: (?i)^inet_interfaces\s*=\s.* + line: inet_interfaces = {{ var_postfix_inet_interfaces }} + state: present + insertafter: ^inet_interfaces\s*=\s.* + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"postfix" in ansible_facts.packages' + - '"postfix" in ansible_facts.packages' + tags: + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.2 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - postfix_network_listening_disabled + - restrict_strategy + + + + + + + + + + + + Configure Operating System to Protect Mail Server + The guidance in this section is appropriate for any host which is +operating as a site MTA, whether the mail server runs using Sendmail, Postfix, +or some other software. + + + Configure Postfix if Necessary + Postfix stores its configuration files in the directory +/etc/postfix by default. The primary configuration file is +/etc/postfix/main.cf. + + Control Mail Relaying + Postfix's mail relay controls are implemented with the help of the +smtpd recipient restrictions option, which controls the restrictions placed on +the SMTP dialogue once the sender and recipient envelope addresses are known. +The guidance in the following sections should be applied to all systems. If +there are systems which must be allowed to relay mail, but which cannot be +trusted to relay unconditionally, configure SMTP AUTH with SSL support. + + Prevent Unrestricted Mail Relaying + Modify the /etc/postfix/main.cf file to restrict client connections +to the local network with the following command: +$ sudo postconf -e 'smtpd_client_restrictions = permit_mynetworks,reject' + + CCI-000366 + SRG-OS-000480-GPOS-00227 + OL09-00-002425 + SV-271763r1092001_rule + If unrestricted mail relaying is permitted, unauthorized senders could use this +host as a mail relay for the purpose of sending spam or other unauthorized +activity. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && rpm --quiet -q postfix; then + +if ! grep -q ^smtpd_client_restrictions /etc/postfix/main.cf; then + echo "smtpd_client_restrictions = permit_mynetworks,reject" >> /etc/postfix/main.cf +else + sed -i "s/^smtpd_client_restrictions.*/smtpd_client_restrictions = permit_mynetworks,reject/g" /etc/postfix/main.cf +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002425 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - postfix_prevent_unrestricted_relay + - restrict_strategy + +- name: Prevent Unrestricted Mail Relaying + block: + + - name: Check for duplicate values + lineinfile: + path: /etc/postfix/main.cf + create: true + regexp: (?i)^[ \t]*smtpd_client_restrictions\s*=\s* + state: absent + check_mode: true + changed_when: false + register: dupes + + - name: Deduplicate values from /etc/postfix/main.cf + lineinfile: + path: /etc/postfix/main.cf + create: true + regexp: (?i)^[ \t]*smtpd_client_restrictions\s*=\s* + state: absent + when: dupes.found is defined and dupes.found > 1 + + - name: Insert correct line to /etc/postfix/main.cf + lineinfile: + path: /etc/postfix/main.cf + create: true + regexp: (?i)^[ \t]*smtpd_client_restrictions\s*=\s* + line: smtpd_client_restrictions = permit_mynetworks,reject + state: present + when: + - '"postfix" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002425 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - postfix_prevent_unrestricted_relay + - restrict_strategy + + + + + + + + + + + + + + NFS and RPC + The Network File System is a popular distributed filesystem for +the Unix environment, and is very widely deployed. This section discusses the +circumstances under which it is possible to disable NFS and its dependencies, +and then details steps which should be taken to secure +NFS's configuration. This section is relevant to systems operating as NFS +clients, as well as to those operating as NFS servers. + + Uninstall nfs-utils Package + The nfs-utils package can be removed with the following command: + +$ sudo yum erase nfs-utils + + CCI-000381 + SRG-OS-000095-GPOS-00049 + OL09-00-000100 + SV-271456r1091080_rule + nfs-utils provides a daemon for the kernel NFS server and related tools. This +package also contains the showmount program. showmount queries the mount +daemon on a remote host for information about the Network File System (NFS) server on the +remote host. For example, showmount can display the clients which are mounted on +that host. + +# CAUTION: This remediation script will remove nfs-utils +# from the system, and may remove any packages +# that depend on nfs-utils. Execute this +# remediation AFTER testing on a non-production +# system! + +if rpm -q --quiet "nfs-utils" ; then +yum remove -y "nfs-utils" +fi + + - name: Ensure nfs-utils is removed + package: + name: nfs-utils + state: absent + tags: + - DISA-STIG-OL09-00-000100 + - disable_strategy + - low_complexity + - low_disruption + - low_severity + - no_reboot_needed + - package_nfs-utils_removed + + include remove_nfs-utils + +class remove_nfs-utils { + package { 'nfs-utils': + ensure => 'purged', + } +} + + +package --remove=nfs-utils + + + + + + + + + + Configure NFS Clients + The steps in this section are appropriate for systems which operate as NFS clients. + + Mount Remote Filesystems with Restrictive Options + Edit the file /etc/fstab. For each filesystem whose type +(column 3) is nfs or nfs4, add the text +,nodev,nosuid to the list of mount options in column 4. If +appropriate, also add ,noexec. + + +See the section titled "Restrict Partition Mount Options" for a description of +the effects of these options. In general, execution of files mounted via NFS +should be considered risky because of the possibility that an adversary could +intercept the request and substitute a malicious file. Allowing setuid files to +be executed from remote servers is particularly risky, both for this reason and +because it requires the clients to extend root-level trust to the NFS +server. + + + Mount Remote Filesystems with Kerberos Security + Add the sec=krb5:krb5i:krb5p option to the fourth column of /etc/fstab for the line which controls mounting of +any NFS mounts. + 1 + 12 + 14 + 15 + 16 + 18 + 3 + 5 + DSS05.04 + DSS05.10 + DSS06.10 + CCI-000366 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.3 + SR 1.1 + SR 1.10 + SR 1.2 + SR 1.5 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + A.18.1.4 + A.6.1.2 + A.9.1.2 + A.9.2.1 + A.9.2.3 + A.9.2.4 + A.9.3.1 + A.9.4.1 + A.9.4.2 + A.9.4.3 + A.9.4.4 + A.9.4.5 + CM-7(a) + CM-7(b) + CM-6(a) + IA-2 + IA-2(8) + IA-2(9) + AC-17(a) + PR.AC-4 + PR.AC-7 + SRG-OS-000480-GPOS-00227 + OL09-00-002010 + SV-271640r1091632_rule + When an NFS server is configured to use AUTH_SYS a selected userid and groupid are used to handle +requests from the remote user. The userid and groupid could mistakenly or maliciously be set +incorrectly. The AUTH_GSS method of authentication uses certificates on the server and client +systems to more securely authenticate the remote mount request. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +vfstype_points=() +readarray -t vfstype_points < <(grep -E "[[:space:]]nfs[4]?[[:space:]]" /etc/fstab | awk '{print $2}') + +for vfstype_point in "${vfstype_points[@]}" +do + mount_point_match_regexp="$(printf "^[[:space:]]*[^#].*[[:space:]]%s[[:space:]]" ${vfstype_point//\\/\\\\})" + + # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab + if ! grep -q "$mount_point_match_regexp" /etc/fstab; then + # runtime opts without some automatic kernel/userspace-added defaults + previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 | awk '{print $4}' \ + | sed -E "s/(rw|defaults|seclabel|sec=krb5:krb5i:krb5p)(,|$)//g;s/,$//") + [ "$previous_mount_opts" ] && previous_mount_opts+="," + # In iso9660 filesystems mtab could describe a "blocksize" value, this should be reflected in + # fstab as "block". The next variable is to satisfy shellcheck SC2050. + fs_type="nfs4" + if [ "$fs_type" == "iso9660" ] ; then + previous_mount_opts=$(sed 's/blocksize=/block=/' <<< "$previous_mount_opts") + fi + echo " ${vfstype_point//\\/\\\\} nfs4 defaults,${previous_mount_opts}sec=krb5:krb5i:krb5p 0 0" >> /etc/fstab + # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it + elif ! grep "$mount_point_match_regexp" /etc/fstab | grep -q "sec=krb5:krb5i:krb5p"; then + previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}') + sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,sec=krb5:krb5i:krb5p|" /etc/fstab + fi +done + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002010 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-IA-2 + - NIST-800-53-IA-2(8) + - NIST-800-53-IA-2(9) + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - mount_option_krb_sec_remote_filesystems + - no_reboot_needed + +- name: Get nfs and nfs4 mount points, that don't have sec=krb5:krb5i:krb5p + command: findmnt --fstab --types nfs,nfs4 -O nosec=krb5:krb5i:krb5p -n -P + register: points_register + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002010 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-IA-2 + - NIST-800-53-IA-2(8) + - NIST-800-53-IA-2(9) + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - mount_option_krb_sec_remote_filesystems + - no_reboot_needed + +- name: Add sec=krb5:krb5i:krb5p to nfs and nfs4 mount points + mount: + path: '{{ item | regex_search(''TARGET="([^"]+)"'',''\1'') | first }}' + src: '{{ item | regex_search(''SOURCE="([^"]+)"'',''\1'') | first }}' + fstype: '{{ item | regex_search(''FSTYPE="([^"]+)"'',''\1'') | first }}' + state: present + opts: '{{ item | regex_search(''OPTIONS="([^"]+)"'',''\1'') | first }},sec=krb5:krb5i:krb5p' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - (points_register.stdout | length > 0) and '\\x09' not in item + with_items: '{{ points_register.stdout_lines }}' + tags: + - DISA-STIG-OL09-00-002010 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-IA-2 + - NIST-800-53-IA-2(8) + - NIST-800-53-IA-2(9) + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - mount_option_krb_sec_remote_filesystems + - no_reboot_needed + + + + + + + + + + Mount Remote Filesystems with nodev + Add the nodev option to the fourth column of /etc/fstab for the line which controls mounting of +any NFS mounts. + 11 + 13 + 14 + 3 + 8 + 9 + APO13.01 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS05.02 + DSS05.05 + DSS05.06 + DSS06.06 + CCI-000366 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.2 + 4.3.4.3.3 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 7.6 + A.11.2.9 + A.12.1.2 + A.12.5.1 + A.12.6.2 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.8.2.1 + A.8.2.2 + A.8.2.3 + A.8.3.1 + A.8.3.3 + A.9.1.2 + CM-6(a) + MP-2 + PR.IP-1 + PR.PT-2 + PR.PT-3 + SRG-OS-000480-GPOS-00227 + OL09-00-002011 + SV-271641r1091635_rule + Legitimate device files should only exist in the /dev directory. NFS mounts +should not present device files to users. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +vfstype_points=() +readarray -t vfstype_points < <(grep -E "[[:space:]]nfs[4]?[[:space:]]" /etc/fstab | awk '{print $2}') + +for vfstype_point in "${vfstype_points[@]}" +do + mount_point_match_regexp="$(printf "^[[:space:]]*[^#].*[[:space:]]%s[[:space:]]" ${vfstype_point//\\/\\\\})" + + # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab + if ! grep -q "$mount_point_match_regexp" /etc/fstab; then + # runtime opts without some automatic kernel/userspace-added defaults + previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 | awk '{print $4}' \ + | sed -E "s/(rw|defaults|seclabel|nodev)(,|$)//g;s/,$//") + [ "$previous_mount_opts" ] && previous_mount_opts+="," + # In iso9660 filesystems mtab could describe a "blocksize" value, this should be reflected in + # fstab as "block". The next variable is to satisfy shellcheck SC2050. + fs_type="nfs4" + if [ "$fs_type" == "iso9660" ] ; then + previous_mount_opts=$(sed 's/blocksize=/block=/' <<< "$previous_mount_opts") + fi + echo " ${vfstype_point//\\/\\\\} nfs4 defaults,${previous_mount_opts}nodev 0 0" >> /etc/fstab + # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it + elif ! grep "$mount_point_match_regexp" /etc/fstab | grep -q "nodev"; then + previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}') + sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,nodev|" /etc/fstab + fi +done + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002011 + - NIST-800-53-CM-6(a) + - NIST-800-53-MP-2 + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - mount_option_nodev_remote_filesystems + - no_reboot_needed + +- name: Get nfs and nfs4 mount points, that don't have nodev + command: findmnt --fstab --types nfs,nfs4 -O nonodev -n -P + register: points_register + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002011 + - NIST-800-53-CM-6(a) + - NIST-800-53-MP-2 + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - mount_option_nodev_remote_filesystems + - no_reboot_needed + +- name: Add nodev to nfs and nfs4 mount points + mount: + path: '{{ item | regex_search(''TARGET="([^"]+)"'',''\1'') | first }}' + src: '{{ item | regex_search(''SOURCE="([^"]+)"'',''\1'') | first }}' + fstype: '{{ item | regex_search(''FSTYPE="([^"]+)"'',''\1'') | first }}' + state: present + opts: '{{ item | regex_search(''OPTIONS="([^"]+)"'',''\1'') | first }},nodev' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - (points_register.stdout | length > 0) and '\\x09' not in item + with_items: '{{ points_register.stdout_lines }}' + tags: + - DISA-STIG-OL09-00-002011 + - NIST-800-53-CM-6(a) + - NIST-800-53-MP-2 + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - mount_option_nodev_remote_filesystems + - no_reboot_needed + + + + + + + + + + Mount Remote Filesystems with noexec + Add the noexec option to the fourth column of /etc/fstab for the line which controls mounting of +any NFS mounts. + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + APO01.06 + DSS05.04 + DSS05.07 + DSS06.02 + CCI-000366 + 4.3.3.7.3 + SR 2.1 + SR 5.2 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + AC-6 + AC-6(8) + AC-6(10) + CM-6(a) + PR.AC-4 + PR.DS-5 + SRG-OS-000480-GPOS-00227 + OL09-00-002012 + SV-271642r1092593_rule + The noexec mount option causes the system not to execute binary files. This option must be used +for mounting any file system not containing approved binary files as they may be incompatible. Executing +files from untrusted file systems increases the opportunity for unprivileged users to attain unauthorized +administrative access. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +vfstype_points=() +readarray -t vfstype_points < <(grep -E "[[:space:]]nfs[4]?[[:space:]]" /etc/fstab | awk '{print $2}') + +for vfstype_point in "${vfstype_points[@]}" +do + mount_point_match_regexp="$(printf "^[[:space:]]*[^#].*[[:space:]]%s[[:space:]]" ${vfstype_point//\\/\\\\})" + + # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab + if ! grep -q "$mount_point_match_regexp" /etc/fstab; then + # runtime opts without some automatic kernel/userspace-added defaults + previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 | awk '{print $4}' \ + | sed -E "s/(rw|defaults|seclabel|noexec)(,|$)//g;s/,$//") + [ "$previous_mount_opts" ] && previous_mount_opts+="," + # In iso9660 filesystems mtab could describe a "blocksize" value, this should be reflected in + # fstab as "block". The next variable is to satisfy shellcheck SC2050. + fs_type="nfs4" + if [ "$fs_type" == "iso9660" ] ; then + previous_mount_opts=$(sed 's/blocksize=/block=/' <<< "$previous_mount_opts") + fi + echo " ${vfstype_point//\\/\\\\} nfs4 defaults,${previous_mount_opts}noexec 0 0" >> /etc/fstab + # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it + elif ! grep "$mount_point_match_regexp" /etc/fstab | grep -q "noexec"; then + previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}') + sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,noexec|" /etc/fstab + fi +done + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002012 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(10) + - NIST-800-53-AC-6(8) + - NIST-800-53-CM-6(a) + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - mount_option_noexec_remote_filesystems + - no_reboot_needed + +- name: Get nfs and nfs4 mount points, that don't have noexec + command: findmnt --fstab --types nfs,nfs4 -O nonoexec -n -P + register: points_register + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002012 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(10) + - NIST-800-53-AC-6(8) + - NIST-800-53-CM-6(a) + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - mount_option_noexec_remote_filesystems + - no_reboot_needed + +- name: Add noexec to nfs and nfs4 mount points + mount: + path: '{{ item | regex_search(''TARGET="([^"]+)"'',''\1'') | first }}' + src: '{{ item | regex_search(''SOURCE="([^"]+)"'',''\1'') | first }}' + fstype: '{{ item | regex_search(''FSTYPE="([^"]+)"'',''\1'') | first }}' + state: present + opts: '{{ item | regex_search(''OPTIONS="([^"]+)"'',''\1'') | first }},noexec' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - (points_register.stdout | length > 0) and '\\x09' not in item + with_items: '{{ points_register.stdout_lines }}' + tags: + - DISA-STIG-OL09-00-002012 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(10) + - NIST-800-53-AC-6(8) + - NIST-800-53-CM-6(a) + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - mount_option_noexec_remote_filesystems + - no_reboot_needed + + + + + + + + + + Mount Remote Filesystems with nosuid + Add the nosuid option to the fourth column of /etc/fstab for the line which controls mounting of +any NFS mounts. + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + APO01.06 + DSS05.04 + DSS05.07 + DSS06.02 + CCI-000366 + 4.3.3.7.3 + SR 2.1 + SR 5.2 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + AC-6 + AC-6(1) + CM6(a) + PR.AC-4 + PR.DS-5 + SRG-OS-000480-GPOS-00227 + OL09-00-002013 + SV-271643r1091641_rule + NFS mounts should not present suid binaries to users. Only vendor-supplied suid executables +should be installed to their default location on the local filesystem. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +vfstype_points=() +readarray -t vfstype_points < <(grep -E "[[:space:]]nfs[4]?[[:space:]]" /etc/fstab | awk '{print $2}') + +for vfstype_point in "${vfstype_points[@]}" +do + mount_point_match_regexp="$(printf "^[[:space:]]*[^#].*[[:space:]]%s[[:space:]]" ${vfstype_point//\\/\\\\})" + + # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab + if ! grep -q "$mount_point_match_regexp" /etc/fstab; then + # runtime opts without some automatic kernel/userspace-added defaults + previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 | awk '{print $4}' \ + | sed -E "s/(rw|defaults|seclabel|nosuid)(,|$)//g;s/,$//") + [ "$previous_mount_opts" ] && previous_mount_opts+="," + # In iso9660 filesystems mtab could describe a "blocksize" value, this should be reflected in + # fstab as "block". The next variable is to satisfy shellcheck SC2050. + fs_type="nfs4" + if [ "$fs_type" == "iso9660" ] ; then + previous_mount_opts=$(sed 's/blocksize=/block=/' <<< "$previous_mount_opts") + fi + echo " ${vfstype_point//\\/\\\\} nfs4 defaults,${previous_mount_opts}nosuid 0 0" >> /etc/fstab + # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it + elif ! grep "$mount_point_match_regexp" /etc/fstab | grep -q "nosuid"; then + previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}') + sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,nosuid|" /etc/fstab + fi +done + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002013 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM6(a) + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - mount_option_nosuid_remote_filesystems + - no_reboot_needed + +- name: Get nfs and nfs4 mount points, that don't have nosuid + command: findmnt --fstab --types nfs,nfs4 -O nonosuid -n -P + register: points_register + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002013 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM6(a) + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - mount_option_nosuid_remote_filesystems + - no_reboot_needed + +- name: Add nosuid to nfs and nfs4 mount points + mount: + path: '{{ item | regex_search(''TARGET="([^"]+)"'',''\1'') | first }}' + src: '{{ item | regex_search(''SOURCE="([^"]+)"'',''\1'') | first }}' + fstype: '{{ item | regex_search(''FSTYPE="([^"]+)"'',''\1'') | first }}' + state: present + opts: '{{ item | regex_search(''OPTIONS="([^"]+)"'',''\1'') | first }},nosuid' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - (points_register.stdout | length > 0) and '\\x09' not in item + with_items: '{{ points_register.stdout_lines }}' + tags: + - DISA-STIG-OL09-00-002013 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM6(a) + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - mount_option_nosuid_remote_filesystems + - no_reboot_needed + + + + + + + + + + + + Configure NFS Servers + The steps in this section are appropriate for systems which operate as NFS servers. + + Ensure All-Squashing Disabled On All Exports + The all_squash maps all uids and gids to an anonymous user. +This should be disabled by removing any instances of the +all_squash option from the file /etc/exports. + The all_squash option maps all client requests to a single anonymous +uid/gid on the NFS server, negating the ability to track file access +by user ID. + + + + + + Use Kerberos Security on All Exports + Using Kerberos on all exported mounts prevents a malicious client or user from +impersonating a system user. To cryptography authenticate users to the NFS server, +add sec=krb5:krb5i:krb5p to each export in /etc/exports. + 1 + 12 + 14 + 15 + 16 + 18 + 3 + 5 + DSS05.04 + DSS05.10 + DSS06.10 + CCI-000366 + 164.308(a)(4)(i) + 164.308(b)(1) + 164.308(b)(3) + 164.310(b) + 164.312(e)(1) + 164.312(e)(2)(ii) + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.3 + SR 1.1 + SR 1.10 + SR 1.2 + SR 1.5 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + A.18.1.4 + A.6.1.2 + A.9.1.2 + A.9.2.1 + A.9.2.3 + A.9.2.4 + A.9.3.1 + A.9.4.1 + A.9.4.2 + A.9.4.3 + A.9.4.4 + A.9.4.5 + CM-7(a) + CM-7(b) + CM-6(a) + IA-2 + IA-2(8) + IA-2(9) + AC-17(a) + PR.AC-4 + PR.AC-7 + SRG-OS-000480-GPOS-00227 + When an NFS server is configured to use AUTH_SYS a selected userid and groupid are used to handle +requests from the remote user. The userid and groupid could mistakenly or maliciously be set +incorrectly. The AUTH_GSS method of authentication uses certificates on the server and client +systems to more securely authenticate the remote mount request. + +nfs_exports=() +readarray -t nfs_exports < <(grep -E "^/.*[[:space:]]+ .*\(.*\)[[:space:]]*$" /etc/exports | awk '{print $2}') + +for nfs_export in "${nfs_exports[@]}" +do + correct_export="" + if [ "$(grep -c "sec=" <<<"$nfs_export")" -eq 0 ]; then + correct_export="$(echo $nfs_export|sed -e 's/).*$/,sec=krb5\:krb5i\:krb5p)/')" + else + correct_export="$(echo $nfs_export|sed -e 's/sec=[^\,\)]*/sec=krb5\:krb5i\:krb5p/')" + fi + sed -i "s|$nfs_export|$correct_export|g" /etc/exports +done + + - name: Drop any security clause for every export + replace: + path: /etc/exports + regexp: ^(/.*\w+.*\(.*),sec=[^,]*(.*\)\w*$) + replace: \1\2 + tags: + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-IA-2 + - NIST-800-53-IA-2(8) + - NIST-800-53-IA-2(9) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - use_kerberos_security_all_exports + +- name: Add kerberos security when no security is defined for an export + replace: + path: /etc/exports + regexp: ^(/.*\w+.*\(.*)(\)\w*$) + replace: \1,sec=krb5:krb5i:krb5p\2 + tags: + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-IA-2 + - NIST-800-53-IA-2(8) + - NIST-800-53-IA-2(9) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - use_kerberos_security_all_exports + + + + + + + + + + + + Network Time Protocol + The Network Time Protocol is used to manage the system +clock over a network. Computer clocks are not very accurate, so +time will drift unpredictably on unmanaged systems. Central time +protocols can be used both to ensure that time is consistent among +a network of systems, and that their time is consistent with the +outside world. + + +If every system on a network reliably reports the same time, then it is much +easier to correlate log messages in case of an attack. In addition, a number of +cryptographic protocols (such as Kerberos) use timestamps to prevent certain +types of attacks. If your network does not have synchronized time, these +protocols may be unreliable or even unusable. + + +Depending on the specifics of the network, global time accuracy may be just as +important as local synchronization, or not very important at all. If your +network is connected to the Internet, using a public timeserver (or one +provided by your enterprise) provides globally accurate timestamps which may be +essential in investigating or responding to an attack which originated outside +of your network. + + +A typical network setup involves a small number of internal systems operating +as NTP servers, and the remainder obtaining time information from those +internal servers. + + +There is a choice between the daemons ntpd and chronyd, which +are available from the repositories in the ntp and chrony +packages respectively. + + +The default chronyd daemon can work well when external time references +are only intermittently accesible, can perform well even when the network is +congested for longer periods of time, can usually synchronize the clock faster +and with better time accuracy, and quickly adapts to sudden changes in the rate +of the clock, for example, due to changes in the temperature of the crystal +oscillator. Chronyd should be considered for all systems which are +frequently suspended or otherwise intermittently disconnected and reconnected +to a network. Mobile and virtual systems for example. + + +The ntpd NTP daemon fully supports NTP protocol version 4 (RFC 5905), +including broadcast, multicast, manycast clients and servers, and the orphan +mode. It also supports extra authentication schemes based on public-key +cryptography (RFC 5906). The NTP daemon (ntpd) should be considered +for systems which are normally kept permanently on. Systems which are required +to use broadcast or multicast IP, or to perform authentication of packets with +the Autokey protocol, should consider using ntpd. + + +Refer to + + + https://docs.oracle.com/en/operating-systems/oracle-linux/9/network/network-ConfiguringNetworkTime.html#ol-nettime + +for more detailed comparison of features of chronyd +and ntpd daemon features respectively, and for further guidance how to +choose between the two NTP daemons. + + +The upstream manual pages at + https://chrony-project.org/documentation.html for +chronyd and + http://www.ntp.org for ntpd provide additional +information on the capabilities and configuration of each of the NTP daemons. + + + Vendor Approved Time pools + The list of vendor-approved pool servers + 0.pool.ntp.org,1.pool.ntp.org,2.pool.ntp.org,3.pool.ntp.org + 0.fedora.pool.ntp.org,1.fedora.pool.ntp.org,2.fedora.pool.ntp.org,3.fedora.pool.ntp.org + 0.rhel.pool.ntp.org,1.rhel.pool.ntp.org,2.rhel.pool.ntp.org,3.rhel.pool.ntp.org + 0.pool.ntp.org,1.pool.ntp.org,2.pool.ntp.org,3.pool.ntp.org + 0.suse.pool.ntp.org,1.suse.pool.ntp.org,2.suse.pool.ntp.org,3.suse.pool.ntp.org + 0.ntp.cloud.aliyuncs.com,1.ntp.aliyun.com,2.ntp1.aliyun.com,3.ntp1.cloud.aliyuncs.com + 0.rhel.pool.ntp.org,1.rhel.pool.ntp.org,2.rhel.pool.ntp.org,3.rhel.pool.ntp.org + 0.ubuntu.pool.ntp.org,1.ubuntu.pool.ntp.org,2.ubuntu.pool.ntp.org,3.ubuntu.pool.ntp.org + + + Vendor Approved Time Servers + The list of vendor-approved time servers + 0.pool.ntp.org,1.pool.ntp.org,2.pool.ntp.org,3.pool.ntp.org + 0.pool.ntp.org,1.pool.ntp.org,2.pool.ntp.org,3.pool.ntp.org + 0.us.pool.ntp.mil + 0.fedora.pool.ntp.org,1.fedora.pool.ntp.org,2.fedora.pool.ntp.org,3.fedora.pool.ntp.org + 0.rhel.pool.ntp.org,1.rhel.pool.ntp.org,2.rhel.pool.ntp.org,3.rhel.pool.ntp.org + 0.pool.ntp.org,1.pool.ntp.org,2.pool.ntp.org,3.pool.ntp.org + 0.suse.pool.ntp.org,1.suse.pool.ntp.org,2.suse.pool.ntp.org,3.suse.pool.ntp.org + 0.ntp.cloud.aliyuncs.com,1.ntp.aliyun.com,2.ntp1.aliyun.com,3.ntp1.cloud.aliyuncs.com + 0.rhel.pool.ntp.org,1.rhel.pool.ntp.org,2.rhel.pool.ntp.org,3.rhel.pool.ntp.org + 0.ubuntu.pool.ntp.org,1.ubuntu.pool.ntp.org,2.ubuntu.pool.ntp.org,3.ubuntu.pool.ntp.org + 0.almalinux.pool.ntp.org,1.almalinux.pool.ntp.org,2.almalinux.pool.ntp.org,3.almalinux.pool.ntp.org + + + Maximum NTP or Chrony Poll + The maximum NTP or Chrony poll interval number in seconds specified as a power of two. + 17 + 16 + 10 + 10 + + + The Chrony package is installed + System time should be synchronized between all systems in an environment. This is +typically done by establishing an authoritative time server or set of servers and having all +systems synchronize their clocks to them. +The chrony package can be installed with the following command: + +$ sudo yum install chrony + + CCI-004923 + 0988 + 1405 + FMT_SMF_EXT.1 + Req-10.4 + SRG-OS-000355-GPOS-00143 + R71 + A.3.SEC-OL3 + 10.6.1 + 10.6 + OL09-00-000310 + SV-271501r1091215_rule + Time synchronization is important to support time sensitive security mechanisms like +Kerberos and also ensures log files have consistent time records across the enterprise, +which aids in forensic investigations. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +if ! rpm -q --quiet "chrony" ; then + yum install -y "chrony" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-000310 + - PCI-DSS-Req-10.4 + - PCI-DSSv4-10.6 + - PCI-DSSv4-10.6.1 + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - package_chrony_installed + +- name: Ensure chrony is installed + package: + name: chrony + state: present + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-000310 + - PCI-DSS-Req-10.4 + - PCI-DSSv4-10.6 + - PCI-DSSv4-10.6.1 + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - package_chrony_installed + + include install_chrony + +class install_chrony { + package { 'chrony': + ensure => 'installed', + } +} + + +package --add=chrony + + +[[packages]] +name = "chrony" +version = "*" + + + + + + + + + + The Chronyd service is enabled + chrony is a daemon which implements the Network Time Protocol (NTP) is designed to +synchronize system clocks across a variety of systems and use a source that is highly +accurate. More information on chrony can be found at + + https://chrony-project.org/. +Chrony can be configured to be a client and/or a server. +To enable Chronyd service, you can run: +# systemctl enable chronyd.service +This recommendation only applies if chrony is in use on the system. + CCI-004923 + 0988 + 1405 + SRG-OS-000355-GPOS-00143 + OL09-00-000311 + SV-271502r1091218_rule + If chrony is in use on the system proper configuration is vital to ensuring time +synchronization is working properly. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q chrony; }; then + +SYSTEMCTL_EXEC='/usr/bin/systemctl' +"$SYSTEMCTL_EXEC" unmask 'chronyd.service' +if [[ $("$SYSTEMCTL_EXEC" is-system-running) != "offline" ]]; then + "$SYSTEMCTL_EXEC" start 'chronyd.service' +fi +"$SYSTEMCTL_EXEC" enable 'chronyd.service' + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-000311 + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_chronyd_enabled + +- name: The Chronyd service is enabled - Enable service chronyd + block: + + - name: Gather the package facts + package_facts: + manager: auto + + - name: The Chronyd service is enabled - Enable Service chronyd + ansible.builtin.systemd: + name: chronyd + enabled: true + state: started + masked: false + when: + - '"chrony" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"chrony" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-000311 + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_chronyd_enabled + + include enable_chronyd + +class enable_chronyd { + service {'chronyd': + enable => true, + ensure => 'running', + } +} + + +[customizations.services] +enabled = ["chronyd"] + + + + + + + + + + A remote time server for Chrony is configured + Chrony is a daemon which implements the Network Time Protocol (NTP). It is designed +to synchronize system clocks across a variety of systems and use a source that is highly +accurate. More information on chrony can be found at + + https://chrony-project.org/. +Chrony can be configured to be a client and/or a server. +Add or edit server or pool lines to /etc/chrony.conf as appropriate: +server <remote-server> +Multiple servers may be configured. + CCI-001890 + CCI-004926 + CCI-004923 + 0988 + 1405 + CM-6(a) + AU-8(1)(a) + Req-10.4.3 + SRG-OS-000355-GPOS-00143 + R71 + A.3.SEC-OL3 + 10.6.2 + 10.6 + If chrony is in use on the system proper configuration is vital to ensuring time +synchronization is working properly. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q chrony; }; then + +var_multiple_time_servers='' + + +config_file="/etc/chrony.conf" + +if ! grep -q '^[[:space:]]*\(server\|pool\)[[:space:]]\+[[:graph:]]\+' "$config_file" ; then + if ! grep -q '#[[:space:]]*server' "$config_file" ; then + for server in $(echo "$var_multiple_time_servers" | tr ',' '\n') ; do + printf '\nserver %s' "$server" >> "$config_file" + done + else + sed -i 's/#[ \t]*server/server/g' "$config_file" + fi +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-53-AU-8(1)(a) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-10.4.3 + - PCI-DSSv4-10.6 + - PCI-DSSv4-10.6.2 + - chronyd_specify_remote_server + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed +- name: XCCDF Value var_multiple_time_servers # promote to variable + set_fact: + var_multiple_time_servers: !!str + tags: + - always + +- name: Detect if chrony is already configured with pools or servers + find: + path: /etc + patterns: chrony.conf + contains: ^[\s]*(?:server|pool)[\s]+[\w]+ + register: chrony_servers + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"chrony" in ansible_facts.packages' + tags: + - NIST-800-53-AU-8(1)(a) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-10.4.3 + - PCI-DSSv4-10.6 + - PCI-DSSv4-10.6.2 + - chronyd_specify_remote_server + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Configure remote time servers + lineinfile: + path: /etc/chrony.conf + line: server {{ item }} + state: present + create: true + loop: '{{ var_multiple_time_servers.split(",") }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"chrony" in ansible_facts.packages' + - chrony_servers.matched == 0 + tags: + - NIST-800-53-AU-8(1)(a) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-10.4.3 + - PCI-DSSv4-10.6 + - PCI-DSSv4-10.6.2 + - chronyd_specify_remote_server + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Disable chrony daemon from acting as server + The port option in /etc/chrony.conf can be set to +0 to make chrony daemon to never open any listening port +for server operation and to operate strictly in a client-only mode. + CCI-000382 + CCI-000381 + AU-8(1) + AU-12(1) + FMT_SMF_EXT.1 + SRG-OS-000096-GPOS-00050 + SRG-OS-000095-GPOS-00049 + OL09-00-002320 + SV-271697r1091803_rule + In order to prevent unauthorized connection of devices, unauthorized transfer of information, or unauthorized tunneling (i.e., embedding of data types within data types), organizations must disable or restrict unused or unnecessary physical and logical ports/protocols on information systems. +Operating systems are capable of providing a wide variety of functions and services. Some of the functions and services provided by default may not be necessary to support essential organizational operations. Additionally, it is sometimes convenient to provide multiple services from a single component (e.g., VPN and IPS); however, doing so increases risk over limiting the services provided by any one component. +To support the requirements and principles of least functionality, the operating system must support the organizational requirements, providing only essential capabilities and limiting the use of ports, protocols, and/or services to only those required, authorized, and approved to conduct official business or to address authorized quality of life issues. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q chrony; }; then + +# Strip any search characters in the key arg so that the key can be replaced without +# adding any search characters to the config file. +stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^port") + +# shellcheck disable=SC2059 +printf -v formatted_output "%s %s" "$stripped_key" "0" + +# If the key exists, change it. Otherwise, add it to the config_file. +# We search for the key string followed by a word boundary (matched by \>), +# so if we search for 'setting', 'setting2' won't match. +if LC_ALL=C grep -q -m 1 -i -e "^port\\>" "/etc/chrony.conf"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + LC_ALL=C sed -i --follow-symlinks "s/^port\\>.*/$escaped_formatted_output/gi" "/etc/chrony.conf" +else + if [[ -s "/etc/chrony.conf" ]] && [[ -n "$(tail -c 1 -- "/etc/chrony.conf" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "/etc/chrony.conf" + fi + printf '%s\n' "$formatted_output" >> "/etc/chrony.conf" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002320 + - NIST-800-53-AU-12(1) + - NIST-800-53-AU-8(1) + - chronyd_client_only + - low_complexity + - low_disruption + - low_severity + - no_reboot_needed + - restrict_strategy + +- name: Disable chrony daemon from acting as server + block: + + - name: Check for duplicate values + lineinfile: + path: /etc/chrony.conf + create: true + regexp: (?i)^\s*port\s+ + state: absent + check_mode: true + changed_when: false + register: dupes + + - name: Deduplicate values from /etc/chrony.conf + lineinfile: + path: /etc/chrony.conf + create: true + regexp: (?i)^\s*port\s+ + state: absent + when: dupes.found is defined and dupes.found > 1 + + - name: Insert correct line to /etc/chrony.conf + lineinfile: + path: /etc/chrony.conf + create: true + regexp: (?i)^\s*port\s+ + line: port 0 + state: present + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"chrony" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-002320 + - NIST-800-53-AU-12(1) + - NIST-800-53-AU-8(1) + - chronyd_client_only + - low_complexity + - low_disruption + - low_severity + - no_reboot_needed + - restrict_strategy + + + + + + + + + + Chrony Configure Pool and Server + Chrony is a daemon which implements the Network Time Protocol (NTP). It is designed to +synchronize system clocks across a variety of systems and use a source that is highly +accurate. More information on chrony can be found at + + https://chrony-project.org/. +Chrony can be configured to be a client and/or a server. +Add or edit server or pool lines to /etc/chrony.conf as appropriate: +server <remote-server> +Multiple servers may be configured. + CCI-000160 + CCI-001891 + 0988 + 1405 + CM-6(a) + AU-8(1)(a) + Req-10.4.3 + R71 + If chrony is in use on the system proper configuration is vital to ensuring time +synchronization is working properly. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q chrony; }; then + +var_multiple_time_servers='' + +var_multiple_time_pools='' + + +config_file="/etc/chrony.conf" + +# Check and configigure servers in /etc/chrony.conf +IFS="," read -a SERVERS <<< $var_multiple_time_servers +for srv in "${SERVERS[@]}" +do + NTP_SRV=$(grep -w $srv $config_file) + if [[ ! "$NTP_SRV" == "server "* ]] + then + time_server="server $srv" + echo $time_server >> "$config_file" + fi +done + +# Check and configure pools in /etc/chrony.conf +IFS="," read -a POOLS <<< $var_multiple_time_pools +for srv in "${POOLS[@]}" +do + NTP_POOL=$(grep -w $srv $config_file) + if [[ ! "$NTP_POOL" == "pool "* ]] + then + time_server="pool $srv" + echo $time_server >> "$config_file" + fi +done + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-53-AU-8(1)(a) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-10.4.3 + - chronyd_configure_pool_and_server + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed +- name: XCCDF Value var_multiple_time_servers # promote to variable + set_fact: + var_multiple_time_servers: !!str + tags: + - always +- name: XCCDF Value var_multiple_time_pools # promote to variable + set_fact: + var_multiple_time_pools: !!str + tags: + - always + +- name: Chrony Configure Pool and Server - Add missing / update wrong records for + remote time servers + ansible.builtin.lineinfile: + path: /etc/chrony.conf + regexp: ^\s*\bserver\b\s*\b{{ item }}\b$ + state: present + line: server {{ item }} + create: true + with_items: + - '{{ var_multiple_time_servers.split(",") }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"chrony" in ansible_facts.packages' + tags: + - NIST-800-53-AU-8(1)(a) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-10.4.3 + - chronyd_configure_pool_and_server + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Chrony Configure Pool and Server - Add missing / update wrong records for + remote time pools + ansible.builtin.lineinfile: + path: /etc/chrony.conf + regexp: ^\s*\bpool\b\s*\b{{ item }}\b$ + state: present + line: pool {{ item }} + create: true + with_items: + - '{{ var_multiple_time_pools.split(",") }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"chrony" in ansible_facts.packages' + tags: + - NIST-800-53-AU-8(1)(a) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-10.4.3 + - chronyd_configure_pool_and_server + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + + + Disable network management of chrony daemon + The cmdport option in /etc/chrony.conf can be set to +0 to stop chrony daemon from listening on the UDP port 323 +for management connections made by chronyc. + CCI-000382 + CCI-000381 + CM-7(1) + SRG-OS-000096-GPOS-00050 + SRG-OS-000095-GPOS-00049 + OL09-00-002321 + SV-271698r1091806_rule + Minimizing the exposure of the server functionality of the chrony +daemon diminishes the attack surface. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q chrony; }; then + +# Strip any search characters in the key arg so that the key can be replaced without +# adding any search characters to the config file. +stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^cmdport") + +# shellcheck disable=SC2059 +printf -v formatted_output "%s %s" "$stripped_key" "0" + +# If the key exists, change it. Otherwise, add it to the config_file. +# We search for the key string followed by a word boundary (matched by \>), +# so if we search for 'setting', 'setting2' won't match. +if LC_ALL=C grep -q -m 1 -i -e "^cmdport\\>" "/etc/chrony.conf"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + LC_ALL=C sed -i --follow-symlinks "s/^cmdport\\>.*/$escaped_formatted_output/gi" "/etc/chrony.conf" +else + if [[ -s "/etc/chrony.conf" ]] && [[ -n "$(tail -c 1 -- "/etc/chrony.conf" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "/etc/chrony.conf" + fi + printf '%s\n' "$formatted_output" >> "/etc/chrony.conf" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002321 + - NIST-800-53-CM-7(1) + - chronyd_no_chronyc_network + - low_complexity + - low_disruption + - low_severity + - no_reboot_needed + - restrict_strategy + +- name: Disable network management of chrony daemon + block: + + - name: Check for duplicate values + lineinfile: + path: /etc/chrony.conf + create: true + regexp: (?i)^\s*cmdport\s+ + state: absent + check_mode: true + changed_when: false + register: dupes + + - name: Deduplicate values from /etc/chrony.conf + lineinfile: + path: /etc/chrony.conf + create: true + regexp: (?i)^\s*cmdport\s+ + state: absent + when: dupes.found is defined and dupes.found > 1 + + - name: Insert correct line to /etc/chrony.conf + lineinfile: + path: /etc/chrony.conf + create: true + regexp: (?i)^\s*cmdport\s+ + line: cmdport 0 + state: present + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"chrony" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-002321 + - NIST-800-53-CM-7(1) + - chronyd_no_chronyc_network + - low_complexity + - low_disruption + - low_severity + - no_reboot_needed + - restrict_strategy + + + + + + + + + + Configure Time Service Maxpoll Interval + The maxpoll should be configured to + in /etc/ntp.conf or +/etc/chrony.conf (or /etc/chrony.d/) to continuously poll time servers. To configure +maxpoll in /etc/ntp.conf or /etc/chrony.conf (or /etc/chrony.d/) +add the following after each server, pool or peer entry: +maxpoll + +to server directives. If using chrony, any pool directives +should be configured too. + 1 + 14 + 15 + 16 + 3 + 5 + 6 + APO11.04 + BAI03.05 + DSS05.04 + DSS05.07 + MEA02.01 + CCI-001890 + CCI-004926 + CCI-004923 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.4.4.7 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.8 + SR 2.9 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + CM-6(a) + AU-8(1)(b) + AU-12(1) + PR.PT-1 + SRG-OS-000355-GPOS-00143 + SRG-OS-000356-GPOS-00144 + SRG-OS-000359-GPOS-00146 + OL09-00-002323 + SV-271699r1091809_rule + Inaccurate time stamps make it more difficult to correlate events and can lead to an inaccurate analysis. Determining the correct time a particular event occurred on a system is critical when conducting forensic analysis and investigating system events. Sources outside the configured acceptable allowance (drift) may be inaccurate. +Synchronizing internal information system clocks provides uniformity of time stamps for information systems with multiple system clocks and systems connected over a network. +Organizations should consider endpoints that may not have regular access to the authoritative time server (e.g., mobile, teleworking, and tactical endpoints). + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { ( rpm --quiet -q chrony || rpm --quiet -q ntp ); }; then + +var_time_service_set_maxpoll='' + + + + +pof="/usr/sbin/pidof" + + +CONFIG_FILES="/etc/ntp.conf" +$pof ntpd || { + CHRONY_D_PATH=/etc/chrony.d/ + mapfile -t CONFIG_FILES < <(find ${CHRONY_D_PATH}.* -type f -name '*.conf') + CONFIG_FILES+=(/etc/chrony.conf) +} + +# get list of ntp files + +for config_file in "${CONFIG_FILES[@]}" ; do + # Set maxpoll values to var_time_service_set_maxpoll + sed -i "s/^\(\(server\|pool\|peer\).*maxpoll\) [0-9,-][0-9]*\(.*\)$/\1 $var_time_service_set_maxpoll \3/" "$config_file" +done + +for config_file in "${CONFIG_FILES[@]}" ; do + # Add maxpoll to server, pool or peer entries without maxpoll + grep "^\(server\|pool\|peer\)" "$config_file" | grep -v maxpoll | while read -r line ; do + sed -i "s/$line/& maxpoll $var_time_service_set_maxpoll/" "$config_file" + done +done + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002323 + - NIST-800-53-AU-12(1) + - NIST-800-53-AU-8(1)(b) + - NIST-800-53-CM-6(a) + - chronyd_or_ntpd_set_maxpoll + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy +- name: XCCDF Value var_time_service_set_maxpoll # promote to variable + set_fact: + var_time_service_set_maxpoll: !!str + tags: + - always + +- name: Configure Time Service Maxpoll Interval - Check That /etc/ntp.conf Exist + ansible.builtin.stat: + path: /etc/ntp.conf + register: ntp_conf_exist_result + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - ( "chrony" in ansible_facts.packages or "ntp" in ansible_facts.packages ) + tags: + - DISA-STIG-OL09-00-002323 + - NIST-800-53-AU-12(1) + - NIST-800-53-AU-8(1)(b) + - NIST-800-53-CM-6(a) + - chronyd_or_ntpd_set_maxpoll + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Configure Time Service Maxpoll Interval - Update the maxpoll Values in /etc/ntp.conf + ansible.builtin.replace: + path: /etc/ntp.conf + regexp: ^(server.*maxpoll)[ ]+[0-9]+(.*)$ + replace: \1 {{ var_time_service_set_maxpoll }}\2 + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - ( "chrony" in ansible_facts.packages or "ntp" in ansible_facts.packages ) + - ntp_conf_exist_result.stat.exists + tags: + - DISA-STIG-OL09-00-002323 + - NIST-800-53-AU-12(1) + - NIST-800-53-AU-8(1)(b) + - NIST-800-53-CM-6(a) + - chronyd_or_ntpd_set_maxpoll + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Configure Time Service Maxpoll Interval - Set the maxpoll Values in /etc/ntp.conf + ansible.builtin.replace: + path: /etc/ntp.conf + regexp: (^server\s+((?!maxpoll).)*)$ + replace: \1 maxpoll {{ var_time_service_set_maxpoll }}\n + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - ( "chrony" in ansible_facts.packages or "ntp" in ansible_facts.packages ) + - ntp_conf_exist_result.stat.exists + tags: + - DISA-STIG-OL09-00-002323 + - NIST-800-53-AU-12(1) + - NIST-800-53-AU-8(1)(b) + - NIST-800-53-CM-6(a) + - chronyd_or_ntpd_set_maxpoll + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Configure Time Service Maxpoll Interval - Check That /etc/chrony.conf Exist + ansible.builtin.stat: + path: /etc/chrony.conf + register: chrony_conf_exist_result + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - ( "chrony" in ansible_facts.packages or "ntp" in ansible_facts.packages ) + tags: + - DISA-STIG-OL09-00-002323 + - NIST-800-53-AU-12(1) + - NIST-800-53-AU-8(1)(b) + - NIST-800-53-CM-6(a) + - chronyd_or_ntpd_set_maxpoll + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Configure Time Service Maxpoll Interval - Update the maxpoll Values in /etc/chrony.conf + ansible.builtin.replace: + path: /etc/chrony.conf + regexp: ^((?:server|pool|peer).*maxpoll)[ ]+[0-9]+(.*)$ + replace: \1 {{ var_time_service_set_maxpoll }}\2 + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - ( "chrony" in ansible_facts.packages or "ntp" in ansible_facts.packages ) + - chrony_conf_exist_result.stat.exists + tags: + - DISA-STIG-OL09-00-002323 + - NIST-800-53-AU-12(1) + - NIST-800-53-AU-8(1)(b) + - NIST-800-53-CM-6(a) + - chronyd_or_ntpd_set_maxpoll + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Configure Time Service Maxpoll Interval - Set the maxpoll Values in /etc/chrony.conf + ansible.builtin.replace: + path: /etc/chrony.conf + regexp: (^(?:server|pool|peer)\s+((?!maxpoll).)*)$ + replace: \1 maxpoll {{ var_time_service_set_maxpoll }}\n + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - ( "chrony" in ansible_facts.packages or "ntp" in ansible_facts.packages ) + - chrony_conf_exist_result.stat.exists + tags: + - DISA-STIG-OL09-00-002323 + - NIST-800-53-AU-12(1) + - NIST-800-53-AU-8(1)(b) + - NIST-800-53-CM-6(a) + - chronyd_or_ntpd_set_maxpoll + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Configure Time Service Maxpoll Interval - Get Conf Files from /etc/chrony.d/ + ansible.builtin.find: + path: /etc/chrony.d/ + patterns: '*.conf' + file_type: file + register: chrony_d_conf_files + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - ( "chrony" in ansible_facts.packages or "ntp" in ansible_facts.packages ) + tags: + - DISA-STIG-OL09-00-002323 + - NIST-800-53-AU-12(1) + - NIST-800-53-AU-8(1)(b) + - NIST-800-53-CM-6(a) + - chronyd_or_ntpd_set_maxpoll + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Configure Time Service Maxpoll Interval - Update the maxpoll Values in /etc/chrony.d/ + ansible.builtin.replace: + path: '{{ item.path }}' + regexp: ^((?:server|pool|peer).*maxpoll)[ ]+[0-9,-]+(.*)$ + replace: \1 {{ var_time_service_set_maxpoll }}\2 + loop: '{{ chrony_d_conf_files.files }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - ( "chrony" in ansible_facts.packages or "ntp" in ansible_facts.packages ) + - chrony_d_conf_files.matched + tags: + - DISA-STIG-OL09-00-002323 + - NIST-800-53-AU-12(1) + - NIST-800-53-AU-8(1)(b) + - NIST-800-53-CM-6(a) + - chronyd_or_ntpd_set_maxpoll + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Configure Time Service Maxpoll Interval - Set the maxpoll Values in /etc/chrony.d/ + ansible.builtin.replace: + path: '{{ item.path }}' + regexp: (^(?:server|pool|peer)\s+((?!maxpoll).)*)$ + replace: \1 maxpoll {{ var_time_service_set_maxpoll }}\n + loop: '{{ chrony_d_conf_files.files }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - ( "chrony" in ansible_facts.packages or "ntp" in ansible_facts.packages ) + - chrony_d_conf_files.matched + tags: + - DISA-STIG-OL09-00-002323 + - NIST-800-53-AU-12(1) + - NIST-800-53-AU-8(1)(b) + - NIST-800-53-CM-6(a) + - chronyd_or_ntpd_set_maxpoll + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + + + + + + + + + + + Specify Additional Remote NTP Servers + Depending on specific functional requirements of a concrete +production environment, the Oracle Linux 9 system can be +configured to utilize the services of the chronyd NTP daemon (the +default), or services of the ntpd NTP daemon. Refer to + + + https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/system_administrators_guide/ch-configuring_ntp_using_the_chrony_suite + +for more detailed comparison of the features of both of the choices, and for +further guidance how to choose between the two NTP daemons. + +Additional NTP servers can be specified for time synchronization. To do so, +perform the following: + if the system is configured to use the chronyd as the NTP daemon +(the default), edit the file /etc/chrony.conf as follows, if the system is configured to use the ntpd as the NTP daemon, +edit the file /etc/ntp.conf as documented below. +Add additional lines of the following form, substituting the IP address or +hostname of a remote NTP server for ntpserver: +server ntpserver + + + 1 + 14 + 15 + 16 + 3 + 5 + 6 + APO11.04 + BAI03.05 + DSS05.04 + DSS05.07 + MEA02.01 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.4.4.7 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.8 + SR 2.9 + 0988 + 1405 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + CM-6(a) + AU-8(1)(a) + AU-8(2) + AU-12(1) + PR.PT-1 + Req-10.4.3 + Specifying additional NTP servers increases the availability of +accurate time data, in the event that one of the specified servers becomes +unavailable. This is typical for a system acting as an NTP server for +other systems. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { ( rpm --quiet -q chrony || rpm --quiet -q ntp ); }; then + +var_multiple_time_servers='' + + +config_file="/etc/ntp.conf" +/usr/sbin/pidof ntpd || config_file="/etc/chrony.conf" + +if ! [ "$(grep -c '^server' "$config_file")" -gt 1 ] ; then + if ! grep -q '#[[:space:]]*server' "$config_file" ; then + for server in $(echo "$var_multiple_time_servers" | tr ',' '\n') ; do + printf '\nserver %s' "$server" >> "$config_file" + done + else + sed -i 's/#[ \t]*server/server/g' "$config_file" + fi +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-53-AU-12(1) + - NIST-800-53-AU-8(1)(a) + - NIST-800-53-AU-8(2) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-10.4.3 + - chronyd_or_ntpd_specify_multiple_servers + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed +- name: XCCDF Value var_multiple_time_servers # promote to variable + set_fact: + var_multiple_time_servers: !!str + tags: + - always + +- name: Detect if chrony configuration file is present + find: + path: /etc + patterns: chrony.conf + register: chrony_server_config + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - ( "chrony" in ansible_facts.packages or "ntp" in ansible_facts.packages ) + tags: + - NIST-800-53-AU-12(1) + - NIST-800-53-AU-8(1)(a) + - NIST-800-53-AU-8(2) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-10.4.3 + - chronyd_or_ntpd_specify_multiple_servers + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Configure multiple time servers in chrony config + lineinfile: + path: /etc/chrony.conf + line: server {{ item }} + state: present + create: true + loop: '{{ var_multiple_time_servers.split(",") }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - ( "chrony" in ansible_facts.packages or "ntp" in ansible_facts.packages ) + - chrony_server_config.matched == 1 + tags: + - NIST-800-53-AU-12(1) + - NIST-800-53-AU-8(1)(a) + - NIST-800-53-AU-8(2) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-10.4.3 + - chronyd_or_ntpd_specify_multiple_servers + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Detect if NTP configuration file is present + find: + path: /etc + patterns: ntp.conf + register: ntp_server_config + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - ( "chrony" in ansible_facts.packages or "ntp" in ansible_facts.packages ) + tags: + - NIST-800-53-AU-12(1) + - NIST-800-53-AU-8(1)(a) + - NIST-800-53-AU-8(2) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-10.4.3 + - chronyd_or_ntpd_specify_multiple_servers + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Configure multiple time servers in NTP config + lineinfile: + path: /etc/chrony.conf + line: pool {{ item }} + state: present + create: true + loop: '{{ var_multiple_time_servers.split(",") }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - ( "chrony" in ansible_facts.packages or "ntp" in ansible_facts.packages ) + - ntp_server_config.matched == 1 + tags: + - NIST-800-53-AU-12(1) + - NIST-800-53-AU-8(1)(a) + - NIST-800-53-AU-8(2) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-10.4.3 + - chronyd_or_ntpd_specify_multiple_servers + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + Ensure that chronyd is running under chrony user account + chrony is a daemon which implements the Network Time Protocol (NTP). It is designed to +synchronize system clocks across a variety of systems and use a source that is highly +accurate. More information on chrony can be found at + + https://chrony-project.org/. +Chrony can be configured to be a client and/or a server. +To ensure that chronyd is running under chrony user account, +remove any -u ... option from OPTIONS other than -u chrony, +as chrony is run under its own user by default. +This recommendation only applies if chrony is in use on the system. + A.3.SEC-OL3 + 10.6.3 + 10.6 + If chrony is in use on the system proper configuration is vital to ensuring time synchronization +is working properly. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q chrony; }; then + +if grep -q 'OPTIONS=.*' /etc/sysconfig/chronyd; then + # trying to solve cases where the parameter after OPTIONS + #may or may not be enclosed in quotes + sed -i -E -e 's/\s*-u\s*\w+\s*/ /' -e 's/^([\s]*OPTIONS=["]?[^"]*)("?)/\1\2/' /etc/sysconfig/chronyd +fi + +if grep -q 'OPTIONS=.*' /etc/sysconfig/chronyd; then + # trying to solve cases where the parameter after OPTIONS + #may or may not be enclosed in quotes + sed -i -E -e 's/\s*-u\s*\w+\s*/ /' -e 's/^([\s]*OPTIONS=["]?[^"]*)("?)/\1 -u chrony\2/' /etc/sysconfig/chronyd +else + echo 'OPTIONS="-u chrony"' >> /etc/sysconfig/chronyd +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - PCI-DSSv4-10.6 + - PCI-DSSv4-10.6.3 + - chronyd_run_as_chrony_user + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Detect if file /etc/sysconfig/chronyd is not empty or missing + find: + path: /etc/sysconfig/ + patterns: chronyd + contains: ^([\s]*OPTIONS=["]?[^"]*)("?) + register: chronyd_file + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"chrony" in ansible_facts.packages' + tags: + - PCI-DSSv4-10.6 + - PCI-DSSv4-10.6.3 + - chronyd_run_as_chrony_user + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Remove any previous configuration of user used to run chronyd process + replace: + path: /etc/sysconfig/chronyd + regexp: \s*-u\s*\w+\s* + replace: ' ' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"chrony" in ansible_facts.packages' + - chronyd_file is defined and chronyd_file.matched > 0 + tags: + - PCI-DSSv4-10.6 + - PCI-DSSv4-10.6.3 + - chronyd_run_as_chrony_user + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Ensure Chrony is only configured with the server directive + Check that Chrony only has time sources configured with the server directive. + This rule doesn't come with a remediation, the time source needs to be added by the administrator. + CCI-001890 + CCI-004926 + CCI-004923 + SRG-OS-000355-GPOS-00143 + SRG-OS-000356-GPOS-00144 + SRG-OS-000359-GPOS-00146 + OL09-00-002323 + SV-271699r1091809_rule + Depending on the infrastructure being used the pool directive may not be supported. +Using the server directive allows for better control of where the system gets time data from. + + + + + + + + + + Verify Group Who Owns /etc/chrony.keys File + To properly set the group owner of /etc/chrony.keys, run the command: $ sudo chgrp chrony /etc/chrony.keys + + R50 + The ownership of the /etc/chrony.keys file by the chrony group is important +because this file hosts chrony cryptographic keys. Protection +of this file is critical for system security. Assigning the ownership to +chrony ensures exclusive control of the chrony cryptography keys. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +chgrp chrony /etc/chrony.keys + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - configure_strategy + - file_groupowner_etc_chrony_keys + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /etc/chrony.keys + stat: + path: /etc/chrony.keys + register: file_exists + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - configure_strategy + - file_groupowner_etc_chrony_keys + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure group owner chrony on /etc/chrony.keys + file: + path: /etc/chrony.keys + group: chrony + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - file_exists.stat is defined and file_exists.stat.exists + tags: + - configure_strategy + - file_groupowner_etc_chrony_keys + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify User Who Owns /etc/chrony.keys File + To properly set the owner of /etc/chrony.keys, run the command: $ sudo chown root /etc/chrony.keys + + R50 + The ownership of the /etc/chrony.keys file by the chrony user is important +because this file hosts chrony cryptographic keys. Protection +of this file is critical for system security. Assigning the ownership to +chrony ensures exclusive control of the chrony cryptographic keys. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +chown 0 /etc/chrony.keys + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - configure_strategy + - file_owner_etc_chrony_keys + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /etc/chrony.keys + stat: + path: /etc/chrony.keys + register: file_exists + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - configure_strategy + - file_owner_etc_chrony_keys + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure owner 0 on /etc/chrony.keys + file: + path: /etc/chrony.keys + owner: '0' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - file_exists.stat is defined and file_exists.stat.exists + tags: + - configure_strategy + - file_owner_etc_chrony_keys + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify Permissions On /etc/chrony.keys File + To properly set the permissions of /etc/chrony.keys, run the command: $ sudo chmod 0640 /etc/chrony.keys + + R50 + Setting correct permissions on the /etc/chrony.keys file is important +because this file hosts chrony cryptographic keys. Protection +of this file is critical for system security. Assigning the correct mode +ensures exclusive control of the chrony cryptographic keys. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +chmod u-xs,g-xws,o-xwrt /etc/chrony.keys + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - configure_strategy + - file_permissions_etc_chrony_keys + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /etc/chrony.keys + stat: + path: /etc/chrony.keys + register: file_exists + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - configure_strategy + - file_permissions_etc_chrony_keys + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure permission u-xs,g-xws,o-xwrt on /etc/chrony.keys + file: + path: /etc/chrony.keys + mode: u-xs,g-xws,o-xwrt + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - file_exists.stat is defined and file_exists.stat.exists + tags: + - configure_strategy + - file_permissions_etc_chrony_keys + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + + Obsolete Services + This section discusses a number of network-visible +services which have historically caused problems for system +security, and for which disabling or severely limiting the service +has been the best available guidance for some time. As a result of +this, many of these services are not installed as part of Oracle Linux 9 +by default. + + +Organizations which are running these services should +switch to more secure equivalents as soon as possible. +If it remains absolutely necessary to run one of +these services for legacy reasons, care should be taken to restrict +the service as much as possible, for instance by configuring host + +firewall software such as iptables to restrict access to the + +vulnerable service to only those remote hosts which have a known +need to use it. + + Ensure rsyncd service is disabled + +The rsyncd service can be disabled with the following command: +$ sudo systemctl mask --now rsyncd.service + + 2.2.4 + 2.2 + The rsyncd service presents a security risk as it uses unencrypted protocols for +communication. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +SYSTEMCTL_EXEC='/usr/bin/systemctl' +if [[ $("$SYSTEMCTL_EXEC" is-system-running) != "offline" ]]; then + "$SYSTEMCTL_EXEC" stop 'rsyncd.service' +fi +"$SYSTEMCTL_EXEC" disable 'rsyncd.service' +"$SYSTEMCTL_EXEC" mask 'rsyncd.service' +# Disable socket activation if we have a unit file for it +if "$SYSTEMCTL_EXEC" -q list-unit-files rsyncd.socket; then + if [[ $("$SYSTEMCTL_EXEC" is-system-running) != "offline" ]]; then + "$SYSTEMCTL_EXEC" stop 'rsyncd.socket' + fi + "$SYSTEMCTL_EXEC" mask 'rsyncd.socket' +fi +# The service may not be running because it has been started and failed, +# so let's reset the state so OVAL checks pass. +# Service should be 'inactive', not 'failed' after reboot though. +"$SYSTEMCTL_EXEC" reset-failed 'rsyncd.service' || true + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.4 + - disable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_rsyncd_disabled + +- name: Ensure rsyncd service is disabled - Collect systemd Services Present in the + System + ansible.builtin.command: systemctl -q list-unit-files --type service + register: service_exists + changed_when: false + failed_when: service_exists.rc not in [0, 1] + check_mode: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.4 + - disable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_rsyncd_disabled + +- name: Ensure rsyncd service is disabled - Ensure rsyncd.service is Masked + ansible.builtin.systemd: + name: rsyncd.service + state: stopped + enabled: false + masked: true + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - service_exists.stdout_lines is search("rsyncd.service", multiline=True) + tags: + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.4 + - disable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_rsyncd_disabled + +- name: Unit Socket Exists - rsyncd.socket + ansible.builtin.command: systemctl -q list-unit-files rsyncd.socket + register: socket_file_exists + changed_when: false + failed_when: socket_file_exists.rc not in [0, 1] + check_mode: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.4 + - disable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_rsyncd_disabled + +- name: Ensure rsyncd service is disabled - Disable Socket rsyncd + ansible.builtin.systemd: + name: rsyncd.socket + enabled: false + state: stopped + masked: true + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - socket_file_exists.stdout_lines is search("rsyncd.socket", multiline=True) + tags: + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.4 + - disable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_rsyncd_disabled + + include disable_rsyncd + +class disable_rsyncd { + service {'rsyncd': + enable => false, + ensure => 'stopped', + } +} + + +[customizations.services] +masked = ["rsyncd"] + + + + + + + + + + Rlogin, Rsh, and Rexec + The Berkeley r-commands are legacy services which +allow cleartext remote access and have an insecure trust +model. + + Uninstall rsh-server Package + The rsh-server package can be removed with the following command: + +$ sudo yum erase rsh-server + + 11 + 12 + 14 + 15 + 3 + 8 + 9 + APO13.01 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS01.04 + DSS05.02 + DSS05.03 + DSS05.05 + DSS06.06 + CCI-000381 + 164.308(a)(4)(i) + 164.308(b)(1) + 164.308(b)(3) + 164.310(b) + 164.312(e)(1) + 164.312(e)(2)(ii) + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.2 + 4.3.4.3.3 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 7.1 + SR 7.6 + A.11.2.6 + A.12.1.2 + A.12.5.1 + A.12.6.2 + A.13.1.1 + A.13.2.1 + A.14.1.3 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.6.2.1 + A.6.2.2 + A.9.1.2 + CM-7(a) + CM-7(b) + CM-6(a) + IA-5(1)(c) + PR.AC-3 + PR.IP-1 + PR.PT-3 + PR.PT-4 + SRG-OS-000095-GPOS-00049 + R62 + 2.2.4 + 2.2 + OL09-00-000105 + SV-271457r1091083_rule + The rsh-server service provides unencrypted remote access service which does not +provide for the confidentiality and integrity of user passwords or the remote session and has very weak +authentication. If a privileged user were to login using this service, the privileged user password +could be compromised. The rsh-server package provides several obsolete and insecure +network services. Removing it decreases the risk of those services' accidental (or intentional) +activation. + +# CAUTION: This remediation script will remove rsh-server +# from the system, and may remove any packages +# that depend on rsh-server. Execute this +# remediation AFTER testing on a non-production +# system! + +if rpm -q --quiet "rsh-server" ; then +yum remove -y "rsh-server" +fi + + - name: Ensure rsh-server is removed + package: + name: rsh-server + state: absent + tags: + - DISA-STIG-OL09-00-000105 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-IA-5(1)(c) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.4 + - disable_strategy + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - package_rsh-server_removed + + include remove_rsh-server + +class remove_rsh-server { + package { 'rsh-server': + ensure => 'purged', + } +} + + +package --remove=rsh-server + + + + + + + + + + Uninstall rsh Package + +The rsh package contains the client commands + +for the rsh services + 3.1.13 + 164.308(a)(4)(i) + 164.308(b)(1) + 164.308(b)(3) + 164.310(b) + 164.312(e)(1) + 164.312(e)(2)(ii) + A.8.2.3 + A.13.1.1 + A.13.2.1 + A.13.2.3 + A.14.1.2 + A.14.1.3 + R62 + 2.2.4 + 2.2 + These legacy clients contain numerous security exposures and have +been replaced with the more secure SSH package. Even if the server is removed, +it is best to ensure the clients are also removed to prevent users from +inadvertently attempting to use these commands and therefore exposing + +their credentials. Note that removing the rsh package removes + +the clients for rsh,rcp, and rlogin. + +# CAUTION: This remediation script will remove rsh +# from the system, and may remove any packages +# that depend on rsh. Execute this +# remediation AFTER testing on a non-production +# system! + +if rpm -q --quiet "rsh" ; then +yum remove -y "rsh" +fi + + - name: Ensure rsh is removed + package: + name: rsh + state: absent + tags: + - NIST-800-171-3.1.13 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.4 + - disable_strategy + - low_complexity + - low_disruption + - no_reboot_needed + - package_rsh_removed + - unknown_severity + + include remove_rsh + +class remove_rsh { + package { 'rsh': + ensure => 'purged', + } +} + + +package --remove=rsh + + + + + + + + + + Disable rlogin Service + The rlogin service, which is available with +the rsh-server package and runs as a service through xinetd or separately +as a systemd socket, should be disabled. +If using xinetd, set disable to yes in /etc/xinetd.d/rlogin. + +The rlogin socket can be disabled with the following command: +$ sudo systemctl mask --now rlogin.socket + + 1 + 11 + 12 + 14 + 15 + 16 + 3 + 5 + 8 + 9 + APO13.01 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS01.04 + DSS05.02 + DSS05.03 + DSS05.04 + DSS05.05 + DSS05.07 + DSS05.10 + DSS06.03 + DSS06.06 + DSS06.10 + 3.1.13 + 3.4.7 + CCI-001436 + 164.308(a)(4)(i) + 164.308(b)(1) + 164.308(b)(3) + 164.310(b) + 164.312(e)(1) + 164.312(e)(2)(ii) + 4.3.3.2.2 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.2 + 4.3.4.3.3 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 7.1 + SR 7.6 + A.11.2.6 + A.12.1.2 + A.12.5.1 + A.12.6.2 + A.13.1.1 + A.13.2.1 + A.14.1.3 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.18.1.4 + A.6.2.1 + A.6.2.2 + A.7.1.1 + A.9.1.2 + A.9.2.1 + A.9.2.2 + A.9.2.3 + A.9.2.4 + A.9.2.6 + A.9.3.1 + A.9.4.2 + A.9.4.3 + CM-7(a) + CM-7(b) + CM-6(a) + IA-5(1)(c) + PR.AC-1 + PR.AC-3 + PR.AC-6 + PR.AC-7 + PR.IP-1 + PR.PT-3 + PR.PT-4 + The rlogin service uses unencrypted network communications, which +means that data from the login session, including passwords and +all other information transmitted during the session, can be +stolen by eavesdroppers on the network. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +SYSTEMCTL_EXEC='/usr/bin/systemctl' +if [[ $("$SYSTEMCTL_EXEC" is-system-running) != "offline" ]]; then + "$SYSTEMCTL_EXEC" stop 'rlogin.service' +fi +"$SYSTEMCTL_EXEC" disable 'rlogin.service' +"$SYSTEMCTL_EXEC" mask 'rlogin.service' +# Disable socket activation if we have a unit file for it +if "$SYSTEMCTL_EXEC" -q list-unit-files rlogin.socket; then + if [[ $("$SYSTEMCTL_EXEC" is-system-running) != "offline" ]]; then + "$SYSTEMCTL_EXEC" stop 'rlogin.socket' + fi + "$SYSTEMCTL_EXEC" mask 'rlogin.socket' +fi +# The service may not be running because it has been started and failed, +# so let's reset the state so OVAL checks pass. +# Service should be 'inactive', not 'failed' after reboot though. +"$SYSTEMCTL_EXEC" reset-failed 'rlogin.service' || true + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-171-3.1.13 + - NIST-800-171-3.4.7 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-IA-5(1)(c) + - disable_strategy + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - service_rlogin_disabled + +- name: Disable rlogin Service - Collect systemd Services Present in the System + ansible.builtin.command: systemctl -q list-unit-files --type service + register: service_exists + changed_when: false + failed_when: service_exists.rc not in [0, 1] + check_mode: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-171-3.1.13 + - NIST-800-171-3.4.7 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-IA-5(1)(c) + - disable_strategy + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - service_rlogin_disabled + +- name: Disable rlogin Service - Ensure rlogin.service is Masked + ansible.builtin.systemd: + name: rlogin.service + state: stopped + enabled: false + masked: true + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - service_exists.stdout_lines is search("rlogin.service", multiline=True) + tags: + - NIST-800-171-3.1.13 + - NIST-800-171-3.4.7 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-IA-5(1)(c) + - disable_strategy + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - service_rlogin_disabled + +- name: Unit Socket Exists - rlogin.socket + ansible.builtin.command: systemctl -q list-unit-files rlogin.socket + register: socket_file_exists + changed_when: false + failed_when: socket_file_exists.rc not in [0, 1] + check_mode: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-171-3.1.13 + - NIST-800-171-3.4.7 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-IA-5(1)(c) + - disable_strategy + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - service_rlogin_disabled + +- name: Disable rlogin Service - Disable Socket rlogin + ansible.builtin.systemd: + name: rlogin.socket + enabled: false + state: stopped + masked: true + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - socket_file_exists.stdout_lines is search("rlogin.socket", multiline=True) + tags: + - NIST-800-171-3.1.13 + - NIST-800-171-3.4.7 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-IA-5(1)(c) + - disable_strategy + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - service_rlogin_disabled + + include disable_rlogin + +class disable_rlogin { + service {'rlogin': + enable => false, + ensure => 'stopped', + } +} + + +[customizations.services] +masked = ["rlogin"] + + + + + + + + + + Remove Host-Based Authentication Files + The shosts.equiv file lists remote hosts and users that are trusted by the local +system. To remove these files, run the following command to delete them from any location: +$ sudo rm /[path]/[to]/[file]/shosts.equiv + + CCI-000366 + SRG-OS-000480-GPOS-00227 + OL09-00-002419 + SV-271757r1092604_rule + The shosts.equiv files are used to configure host-based authentication for the system via SSH. +Host-based authentication is not sufficient for preventing unauthorized access to the system, +as it does not require interactive identification and authentication of a connection request, +or for the use of two-factor authentication. + +# Identify local mounts +MOUNT_LIST=$(df --local | awk '{ print $6 }') + +# Find file on each listed mount point +for cur_mount in ${MOUNT_LIST} +do + find ${cur_mount} -xdev -type f -name "shosts.equiv" -exec rm -f {} \; +done + + - name: Remove Host-Based Authentication Files - Define Excluded (Non-Local) File + Systems and Paths + ansible.builtin.set_fact: + excluded_fstypes: + - afs + - ceph + - cifs + - smb3 + - smbfs + - sshfs + - ncpfs + - ncp + - nfs + - nfs4 + - gfs + - gfs2 + - glusterfs + - gpfs + - pvfs2 + - ocfs2 + - lustre + - davfs + - fuse.sshfs + excluded_paths: + - dev + - proc + - run + - sys + search_paths: [] + tags: + - DISA-STIG-OL09-00-002419 + - high_severity + - low_complexity + - low_disruption + - no_host_based_files + - no_reboot_needed + - restrict_strategy + +- name: Remove Host-Based Authentication Files - Find Relevant Root Directories Ignoring + Pre-Defined Excluded Paths + ansible.builtin.find: + paths: / + file_type: directory + excludes: '{{ excluded_paths }}' + hidden: true + recurse: false + register: result_relevant_root_dirs + tags: + - DISA-STIG-OL09-00-002419 + - high_severity + - low_complexity + - low_disruption + - no_host_based_files + - no_reboot_needed + - restrict_strategy + +- name: Remove Host-Based Authentication Files - Include Relevant Root Directories + in a List of Paths to be Searched + ansible.builtin.set_fact: + search_paths: '{{ search_paths | union([item.path]) }}' + loop: '{{ result_relevant_root_dirs.files }}' + tags: + - DISA-STIG-OL09-00-002419 + - high_severity + - low_complexity + - low_disruption + - no_host_based_files + - no_reboot_needed + - restrict_strategy + +- name: Remove Host-Based Authentication Files - Increment Search Paths List with + Local Partitions Mount Points + ansible.builtin.set_fact: + search_paths: '{{ search_paths | union([item.mount]) }}' + loop: '{{ ansible_mounts }}' + when: + - item.fstype not in excluded_fstypes + - item.mount != '/' + tags: + - DISA-STIG-OL09-00-002419 + - high_severity + - low_complexity + - low_disruption + - no_host_based_files + - no_reboot_needed + - restrict_strategy + +- name: Remove Host-Based Authentication Files - Increment Search Paths List with + Local NFS File System Targets + ansible.builtin.set_fact: + search_paths: '{{ search_paths | union([item.device.split('':'')[1]]) }}' + loop: '{{ ansible_mounts }}' + when: item.device is search("localhost:") + tags: + - DISA-STIG-OL09-00-002419 + - high_severity + - low_complexity + - low_disruption + - no_host_based_files + - no_reboot_needed + - restrict_strategy + +- name: Remove Host-Based Authentication Files - Define Rule Specific Facts + ansible.builtin.set_fact: + shosts_equiv_files: + - /shosts.equiv + tags: + - DISA-STIG-OL09-00-002419 + - high_severity + - low_complexity + - low_disruption + - no_host_based_files + - no_reboot_needed + - restrict_strategy + +- name: Remove Host-Based Authentication Files - Find All shosts.equiv Files in Local + File Systems + ansible.builtin.command: + cmd: find {{ item }} -xdev -type f -name "shosts.equiv" + loop: '{{ search_paths }}' + changed_when: false + register: result_found_shosts_equiv_files + tags: + - DISA-STIG-OL09-00-002419 + - high_severity + - low_complexity + - low_disruption + - no_host_based_files + - no_reboot_needed + - restrict_strategy + +- name: Remove Host-Based Authentication Files - Create List of shosts.equiv Files + Present in Local File Systems + ansible.builtin.set_fact: + shosts_equiv_files: '{{ shosts_equiv_files | union(item.stdout_lines) | list }}' + loop: '{{ result_found_shosts_equiv_files.results }}' + tags: + - DISA-STIG-OL09-00-002419 + - high_severity + - low_complexity + - low_disruption + - no_host_based_files + - no_reboot_needed + - restrict_strategy + +- name: Remove Host-Based Authentication Files - Ensure No shosts.equiv Files Are + Present in the System + ansible.builtin.file: + path: '{{ item }}' + state: absent + loop: '{{ shosts_equiv_files }}' + tags: + - DISA-STIG-OL09-00-002419 + - high_severity + - low_complexity + - low_disruption + - no_host_based_files + - no_reboot_needed + - restrict_strategy + + + + + + + + + + Remove Rsh Trust Files + The files /etc/hosts.equiv and ~/.rhosts (in +each user's home directory) list remote hosts and users that are trusted by the +local system when using the rshd daemon. +To remove these files, run the following command to delete them from any +location: +$ sudo rm /etc/hosts.equiv + $ rm ~/.rhosts + + 11 + 12 + 14 + 15 + 3 + 8 + 9 + APO13.01 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS01.04 + DSS05.02 + DSS05.03 + DSS05.05 + DSS06.06 + CCI-001436 + 164.308(a)(4)(i) + 164.308(b)(1) + 164.308(b)(3) + 164.310(b) + 164.312(e)(1) + 164.312(e)(2)(ii) + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.2 + 4.3.4.3.3 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 7.1 + SR 7.6 + A.11.2.6 + A.12.1.2 + A.12.5.1 + A.12.6.2 + A.13.1.1 + A.13.2.1 + A.14.1.3 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.6.2.1 + A.6.2.2 + A.9.1.2 + CM-7(a) + CM-7(b) + CM-6(a) + PR.AC-3 + PR.IP-1 + PR.PT-3 + PR.PT-4 + This action is only meaningful if .rhosts support is permitted +through PAM. Trust files are convenient, but when used in conjunction with +the R-services, they can allow unauthenticated access to a system. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q rsh-server; then + +find /root -xdev -type f -name ".rhosts" -exec rm -f {} \; +find /home -maxdepth 2 -xdev -type f -name ".rhosts" -exec rm -f {} \; +rm -f /etc/hosts.equiv + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - no_rsh_trust_files + - restrict_strategy + +- name: Detect .rhosts files in users home directories + find: + paths: + - /root + - /home + recurse: true + patterns: .rhosts + hidden: true + file_type: file + check_mode: false + register: rhosts_locations + when: '"rsh-server" in ansible_facts.packages' + tags: + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - no_rsh_trust_files + - restrict_strategy + +- name: Remove .rhosts files + file: + path: '{{ item }}' + state: absent + with_items: '{{ rhosts_locations.files | map(attribute=''path'') | list }}' + when: + - '"rsh-server" in ansible_facts.packages' + - rhosts_locations is success + tags: + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - no_rsh_trust_files + - restrict_strategy + +- name: Remove /etc/hosts.equiv file + file: + path: /etc/hosts.equiv + state: absent + when: '"rsh-server" in ansible_facts.packages' + tags: + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - no_rsh_trust_files + - restrict_strategy + + + + + + + + + + Remove User Host-Based Authentication Files + The ~/.shosts (in each user's home directory) files +list remote hosts and users that are trusted by the +local system. To remove these files, run the following command +to delete them from any location: +$ sudo find / -name '.shosts' -type f -delete + + CCI-000366 + SRG-OS-000480-GPOS-00227 + OL09-00-002420 + SV-271758r1091986_rule + The .shosts files are used to configure host-based authentication for +individual users or the system via SSH. Host-based authentication is not +sufficient for preventing unauthorized access to the system, as it does not +require interactive identification and authentication of a connection request, +or for the use of two-factor authentication. + +# Identify local mounts +MOUNT_LIST=$(df --local | awk '{ print $6 }') + +# Find file on each listed mount point +for cur_mount in ${MOUNT_LIST} +do + find ${cur_mount} -xdev -type f -name ".shosts" -exec rm -f {} \; +done + + - name: Remove User Host-Based Authentication Files - Define Excluded (Non-Local) + File Systems and Paths + ansible.builtin.set_fact: + excluded_fstypes: + - afs + - ceph + - cifs + - smb3 + - smbfs + - sshfs + - ncpfs + - ncp + - nfs + - nfs4 + - gfs + - gfs2 + - glusterfs + - gpfs + - pvfs2 + - ocfs2 + - lustre + - davfs + - fuse.sshfs + excluded_paths: + - dev + - proc + - run + - sys + search_paths: [] + tags: + - DISA-STIG-OL09-00-002420 + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - no_user_host_based_files + - restrict_strategy + +- name: Remove User Host-Based Authentication Files - Find Relevant Root Directories + Ignoring Pre-Defined Excluded Paths + ansible.builtin.find: + paths: / + file_type: directory + excludes: '{{ excluded_paths }}' + hidden: true + recurse: false + register: result_relevant_root_dirs + tags: + - DISA-STIG-OL09-00-002420 + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - no_user_host_based_files + - restrict_strategy + +- name: Remove User Host-Based Authentication Files - Include Relevant Root Directories + in a List of Paths to be Searched + ansible.builtin.set_fact: + search_paths: '{{ search_paths | union([item.path]) }}' + loop: '{{ result_relevant_root_dirs.files }}' + tags: + - DISA-STIG-OL09-00-002420 + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - no_user_host_based_files + - restrict_strategy + +- name: Remove User Host-Based Authentication Files - Increment Search Paths List + with Local Partitions Mount Points + ansible.builtin.set_fact: + search_paths: '{{ search_paths | union([item.mount]) }}' + loop: '{{ ansible_mounts }}' + when: + - item.fstype not in excluded_fstypes + - item.mount != '/' + tags: + - DISA-STIG-OL09-00-002420 + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - no_user_host_based_files + - restrict_strategy + +- name: Remove User Host-Based Authentication Files - Increment Search Paths List + with Local NFS File System Targets + ansible.builtin.set_fact: + search_paths: '{{ search_paths | union([item.device.split('':'')[1]]) }}' + loop: '{{ ansible_mounts }}' + when: item.device is search("localhost:") + tags: + - DISA-STIG-OL09-00-002420 + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - no_user_host_based_files + - restrict_strategy + +- name: Remove User Host-Based Authentication Files - Define Rule Specific Facts + ansible.builtin.set_fact: + user_shosts_files: + - /.shosts + tags: + - DISA-STIG-OL09-00-002420 + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - no_user_host_based_files + - restrict_strategy + +- name: Remove User Host-Based Authentication Files - Find All .shosts Files in Local + File Systems + ansible.builtin.command: + cmd: find {{ item }} -xdev -type f -name ".shosts" + loop: '{{ search_paths }}' + changed_when: false + register: result_found_shosts_files + tags: + - DISA-STIG-OL09-00-002420 + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - no_user_host_based_files + - restrict_strategy + +- name: Remove User Host-Based Authentication Files - Create List of .shosts Files + Present in Local File Systems + ansible.builtin.set_fact: + user_shosts_files: '{{ user_shosts_files | union(item.stdout_lines) | list }}' + loop: '{{ result_found_shosts_files.results }}' + tags: + - DISA-STIG-OL09-00-002420 + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - no_user_host_based_files + - restrict_strategy + +- name: Remove User Host-Based Authentication Files - Ensure No .shosts Files Are + Present in the System + ansible.builtin.file: + path: '{{ item }}' + state: absent + loop: '{{ user_shosts_files }}' + tags: + - DISA-STIG-OL09-00-002420 + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - no_user_host_based_files + - restrict_strategy + + + + + + + + + + + Chat/Messaging Services + The talk software makes it possible for users to send and receive messages +across systems through a terminal session. + + Uninstall talk-server Package + The talk-server package can be removed with the following command: $ sudo yum erase talk-server + + 164.308(a)(4)(i) + 164.308(b)(1) + 164.308(b)(3) + 164.310(b) + 164.312(e)(1) + 164.312(e)(2)(ii) + R62 + 2.2.4 + 2.2 + The talk software presents a security risk as it uses unencrypted protocols +for communications. Removing the talk-server package decreases the +risk of the accidental (or intentional) activation of talk services. + +# CAUTION: This remediation script will remove talk-server +# from the system, and may remove any packages +# that depend on talk-server. Execute this +# remediation AFTER testing on a non-production +# system! + +if rpm -q --quiet "talk-server" ; then +yum remove -y "talk-server" +fi + + - name: Ensure talk-server is removed + package: + name: talk-server + state: absent + tags: + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.4 + - disable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - package_talk-server_removed + + include remove_talk-server + +class remove_talk-server { + package { 'talk-server': + ensure => 'purged', + } +} + + +package --remove=talk-server + + + + + + + + + + Uninstall talk Package + The talk package contains the client program for the +Internet talk protocol, which allows the user to chat with other users on +different systems. Talk is a communication program which copies lines from one +terminal to the terminal of another user. +The talk package can be removed with the following command: + +$ sudo yum erase talk + + 164.308(a)(4)(i) + 164.308(b)(1) + 164.308(b)(3) + 164.310(b) + 164.312(e)(1) + 164.312(e)(2)(ii) + R62 + 2.2.4 + 2.2 + The talk software presents a security risk as it uses unencrypted protocols +for communications. Removing the talk package decreases the +risk of the accidental (or intentional) activation of talk client program. + +# CAUTION: This remediation script will remove talk +# from the system, and may remove any packages +# that depend on talk. Execute this +# remediation AFTER testing on a non-production +# system! + +if rpm -q --quiet "talk" ; then +yum remove -y "talk" +fi + + - name: Ensure talk is removed + package: + name: talk + state: absent + tags: + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.4 + - disable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - package_talk_removed + + include remove_talk + +class remove_talk { + package { 'talk': + ensure => 'purged', + } +} + + +package --remove=talk + + + + + + + + + + + Telnet + The telnet protocol does not provide confidentiality or integrity +for information transmitted on the network. This includes authentication +information such as passwords. Organizations which use telnet should be +actively working to migrate to a more secure protocol. + + Uninstall telnet-server Package + The telnet-server package can be removed with the following command: + +$ sudo yum erase telnet-server + + 11 + 12 + 14 + 15 + 3 + 8 + 9 + APO13.01 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS01.04 + DSS05.02 + DSS05.03 + DSS05.05 + DSS06.06 + CCI-000381 + 164.308(a)(4)(i) + 164.308(b)(1) + 164.308(b)(3) + 164.310(b) + 164.312(e)(1) + 164.312(e)(2)(ii) + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.2 + 4.3.4.3.3 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 7.1 + SR 7.6 + A.11.2.6 + A.12.1.2 + A.12.5.1 + A.12.6.2 + A.13.1.1 + A.13.2.1 + A.14.1.3 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.6.2.1 + A.6.2.2 + A.9.1.2 + CM-7(a) + CM-7(b) + CM-6(a) + PR.AC-3 + PR.IP-1 + PR.PT-3 + PR.PT-4 + Req-2.2.2 + SRG-OS-000095-GPOS-00049 + R62 + A.8.SEC-OL4 + 2.2.4 + 2.2 + OL09-00-000110 + SV-271458r1091086_rule + It is detrimental for operating systems to provide, or install by default, +functionality exceeding requirements or mission objectives. These +unnecessary capabilities are often overlooked and therefore may remain +unsecure. They increase the risk to the platform by providing additional +attack vectors. + +The telnet service provides an unencrypted remote access service which does +not provide for the confidentiality and integrity of user passwords or the +remote session. If a privileged user were to login using this service, the +privileged user password could be compromised. + +Removing the telnet-server package decreases the risk of the +telnet service's accidental (or intentional) activation. + +# CAUTION: This remediation script will remove telnet-server +# from the system, and may remove any packages +# that depend on telnet-server. Execute this +# remediation AFTER testing on a non-production +# system! + +if rpm -q --quiet "telnet-server" ; then +yum remove -y "telnet-server" +fi + + - name: Ensure telnet-server is removed + package: + name: telnet-server + state: absent + tags: + - DISA-STIG-OL09-00-000110 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - PCI-DSS-Req-2.2.2 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.4 + - disable_strategy + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - package_telnet-server_removed + + include remove_telnet-server + +class remove_telnet-server { + package { 'telnet-server': + ensure => 'purged', + } +} + + +package --remove=telnet-server + + + + + + + + + + Remove telnet Clients + The telnet client allows users to start connections to other systems via +the telnet protocol. + 3.1.13 + 164.308(a)(4)(i) + 164.308(b)(1) + 164.308(b)(3) + 164.310(b) + 164.312(e)(1) + 164.312(e)(2)(ii) + A.8.2.3 + A.13.1.1 + A.13.2.1 + A.13.2.3 + A.14.1.2 + A.14.1.3 + R62 + 2.2.4 + 2.2 + The telnet protocol is insecure and unencrypted. The use +of an unencrypted transmission medium could allow an unauthorized user +to steal credentials. The ssh package provides an +encrypted session and stronger security and is included in Oracle Linux 9. + +# CAUTION: This remediation script will remove telnet +# from the system, and may remove any packages +# that depend on telnet. Execute this +# remediation AFTER testing on a non-production +# system! + +if rpm -q --quiet "telnet" ; then +yum remove -y "telnet" +fi + + - name: Ensure telnet is removed + package: + name: telnet + state: absent + tags: + - NIST-800-171-3.1.13 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.4 + - disable_strategy + - low_complexity + - low_disruption + - low_severity + - no_reboot_needed + - package_telnet_removed + + include remove_telnet + +class remove_telnet { + package { 'telnet': + ensure => 'purged', + } +} + + +package --remove=telnet + + + + + + + + + + Disable telnet Service + Make sure that the activation of the telnet service on system boot is disabled. + +The telnet socket can be disabled with the following command: +$ sudo systemctl mask --now telnet.socket + + If the system relies on xinetd to manage telnet sessions, ensure the telnet service +is disabled by the following line: disable = yes. Note that the xinetd file for +telnet is not created automatically, therefore it might have different names. + 1 + 11 + 12 + 14 + 15 + 16 + 3 + 5 + 8 + 9 + APO13.01 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS01.04 + DSS05.02 + DSS05.03 + DSS05.04 + DSS05.05 + DSS05.07 + DSS05.10 + DSS06.03 + DSS06.06 + DSS06.10 + 3.1.13 + 3.4.7 + 164.308(a)(4)(i) + 164.308(b)(1) + 164.308(b)(3) + 164.310(b) + 164.312(e)(1) + 164.312(e)(2)(ii) + 4.3.3.2.2 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.2 + 4.3.4.3.3 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 7.1 + SR 7.6 + A.11.2.6 + A.12.1.2 + A.12.5.1 + A.12.6.2 + A.13.1.1 + A.13.2.1 + A.14.1.3 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.18.1.4 + A.6.2.1 + A.6.2.2 + A.7.1.1 + A.9.1.2 + A.9.2.1 + A.9.2.2 + A.9.2.3 + A.9.2.4 + A.9.2.6 + A.9.3.1 + A.9.4.2 + A.9.4.3 + CM-7(a) + CM-7(b) + CM-6(a) + IA-5(1)(c) + PR.AC-1 + PR.AC-3 + PR.AC-6 + PR.AC-7 + PR.IP-1 + PR.PT-3 + PR.PT-4 + The telnet protocol uses unencrypted network communication, which means that data from the +login session, including passwords and all other information transmitted during the session, +can be stolen by eavesdroppers on the network. The telnet protocol is also subject to +man-in-the-middle attacks. + + # Remediation is applicable only in certain platforms +if ( rpm --quiet -q telnet-server && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ); then + +SYSTEMCTL_EXEC='/usr/bin/systemctl' +if [[ $("$SYSTEMCTL_EXEC" is-system-running) != "offline" ]]; then + "$SYSTEMCTL_EXEC" stop 'telnet.service' +fi +"$SYSTEMCTL_EXEC" disable 'telnet.service' +"$SYSTEMCTL_EXEC" mask 'telnet.service' +# Disable socket activation if we have a unit file for it +if "$SYSTEMCTL_EXEC" -q list-unit-files telnet.socket; then + if [[ $("$SYSTEMCTL_EXEC" is-system-running) != "offline" ]]; then + "$SYSTEMCTL_EXEC" stop 'telnet.socket' + fi + "$SYSTEMCTL_EXEC" mask 'telnet.socket' +fi +# The service may not be running because it has been started and failed, +# so let's reset the state so OVAL checks pass. +# Service should be 'inactive', not 'failed' after reboot though. +"$SYSTEMCTL_EXEC" reset-failed 'telnet.service' || true + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-171-3.1.13 + - NIST-800-171-3.4.7 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-IA-5(1)(c) + - disable_strategy + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - service_telnet_disabled + +- name: Disable telnet Service - Collect systemd Services Present in the System + ansible.builtin.command: systemctl -q list-unit-files --type service + register: service_exists + changed_when: false + failed_when: service_exists.rc not in [0, 1] + check_mode: false + when: ( "telnet-server" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + tags: + - NIST-800-171-3.1.13 + - NIST-800-171-3.4.7 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-IA-5(1)(c) + - disable_strategy + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - service_telnet_disabled + +- name: Disable telnet Service - Ensure telnet.service is Masked + ansible.builtin.systemd: + name: telnet.service + state: stopped + enabled: false + masked: true + when: + - ( "telnet-server" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + - service_exists.stdout_lines is search("telnet.service", multiline=True) + tags: + - NIST-800-171-3.1.13 + - NIST-800-171-3.4.7 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-IA-5(1)(c) + - disable_strategy + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - service_telnet_disabled + +- name: Unit Socket Exists - telnet.socket + ansible.builtin.command: systemctl -q list-unit-files telnet.socket + register: socket_file_exists + changed_when: false + failed_when: socket_file_exists.rc not in [0, 1] + check_mode: false + when: ( "telnet-server" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + tags: + - NIST-800-171-3.1.13 + - NIST-800-171-3.4.7 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-IA-5(1)(c) + - disable_strategy + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - service_telnet_disabled + +- name: Disable telnet Service - Disable Socket telnet + ansible.builtin.systemd: + name: telnet.socket + enabled: false + state: stopped + masked: true + when: + - ( "telnet-server" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + - socket_file_exists.stdout_lines is search("telnet.socket", multiline=True) + tags: + - NIST-800-171-3.1.13 + - NIST-800-171-3.4.7 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-IA-5(1)(c) + - disable_strategy + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - service_telnet_disabled + + include disable_telnet + +class disable_telnet { + service {'telnet': + enable => false, + ensure => 'stopped', + } +} + + +[customizations.services] +masked = ["telnet"] + + + + + + + + + + + TFTP Server + TFTP is a lightweight version of the FTP protocol which has +traditionally been used to configure networking equipment. However, +TFTP provides little security, and modern versions of networking +operating systems frequently support configuration via SSH or other +more secure protocols. A TFTP server should be run only if no more +secure method of supporting existing equipment can be +found. + + TFTP server secure directory + Specify the directory which is used by TFTP server as a root directory when running in secure mode. + /var/lib/tftpboot + + + Uninstall tftp-server Package + The tftp-server package can be removed with the following command: $ sudo yum erase tftp-server + + 11 + 12 + 14 + 15 + 3 + 8 + 9 + APO13.01 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS01.04 + DSS05.02 + DSS05.03 + DSS05.05 + DSS06.06 + CCI-000366 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.2 + 4.3.4.3.3 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 7.1 + SR 7.6 + A.11.2.6 + A.12.1.2 + A.12.5.1 + A.12.6.2 + A.13.1.1 + A.13.2.1 + A.14.1.3 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.6.2.1 + A.6.2.2 + A.9.1.2 + CM-7(a) + CM-7(b) + CM-6(a) + PR.AC-3 + PR.IP-1 + PR.PT-3 + PR.PT-4 + SRG-OS-000480-GPOS-00227 + R62 + A.8.SEC-OL4 + 2.2.4 + 2.2 + OL09-00-000135 + SV-271463r1091101_rule + Removing the tftp-server package decreases the risk of the accidental +(or intentional) activation of tftp services. + + +If TFTP is required for operational support (such as transmission of router +configurations), its use must be documented with the Information Systems +Securty Manager (ISSM), restricted to only authorized personnel, and have +access control rules established. + +# CAUTION: This remediation script will remove tftp-server +# from the system, and may remove any packages +# that depend on tftp-server. Execute this +# remediation AFTER testing on a non-production +# system! + +if rpm -q --quiet "tftp-server" ; then +yum remove -y "tftp-server" +fi + + - name: Ensure tftp-server is removed + package: + name: tftp-server + state: absent + tags: + - DISA-STIG-OL09-00-000135 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.4 + - disable_strategy + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - package_tftp-server_removed + + include remove_tftp-server + +class remove_tftp-server { + package { 'tftp-server': + ensure => 'purged', + } +} + + +package --remove=tftp-server + + + + + + + + + + Remove tftp Daemon + Trivial File Transfer Protocol (TFTP) is a simple file transfer protocol, +typically used to automatically transfer configuration or boot files between systems. +TFTP does not support authentication and can be easily hacked. The package +tftp is a client program that allows for connections to a tftp server. + CCI-000197 + SRG-OS-000074-GPOS-00042 + R62 + 2.2.4 + 2.2 + It is recommended that TFTP be removed, unless there is a specific need +for TFTP (such as a boot server). In that case, use extreme caution when configuring +the services. + +# CAUTION: This remediation script will remove tftp +# from the system, and may remove any packages +# that depend on tftp. Execute this +# remediation AFTER testing on a non-production +# system! + +if rpm -q --quiet "tftp" ; then +yum remove -y "tftp" +fi + + - name: Ensure tftp is removed + package: + name: tftp + state: absent + tags: + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.4 + - disable_strategy + - low_complexity + - low_disruption + - low_severity + - no_reboot_needed + - package_tftp_removed + + include remove_tftp + +class remove_tftp { + package { 'tftp': + ensure => 'purged', + } +} + + +package --remove=tftp + + + + + + + + + + Ensure tftp Daemon Uses Secure Mode + If running the Trivial File Transfer Protocol (TFTP) service is necessary, +it should be configured to change its root directory at startup. To do so, +find the path for the tftp systemd service: +$ sudo systemctl show tftp | grep FragmentPath= +FragmentPath=/etc/systemd/system/tftp.service + +and ensure the ExecStart line on that file includes the -s option with a subdirectory: +ExecStart=/usr/sbin/in.tftpd -s + + + 11 + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + 8 + 9 + APO01.06 + APO13.01 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS01.04 + DSS05.02 + DSS05.03 + DSS05.04 + DSS05.05 + DSS05.07 + DSS06.02 + DSS06.06 + CCI-000366 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.2 + 4.3.4.3.3 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 7.1 + SR 7.6 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.11.2.6 + A.12.1.2 + A.12.5.1 + A.12.6.2 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.6.1.2 + A.6.2.1 + A.6.2.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CM-6(b) + AC-6 + CM-7(a) + PR.AC-3 + PR.AC-4 + PR.DS-5 + PR.IP-1 + PR.PT-3 + PR.PT-4 + SRG-OS-000480-GPOS-00227 + OL09-00-002426 + SV-271764r1092004_rule + Using the -s option causes the TFTP service to only serve files from the +given directory. Serving files from an intentionally-specified directory +reduces the risk of sharing files which should remain private. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q tftp-server; then + +var_tftpd_secure_directory='' + + +if grep -q 'server_args' /etc/xinetd.d/tftp; then + sed -i -E "s;^([[:blank:]]*server_args[[:blank:]]+=[[:blank:]]+.*?)(-s[[:blank:]]+[[:graph:]]+)*(.*)$;\1 -s $var_tftpd_secure_directory \3;" /etc/xinetd.d/tftp +else + echo "server_args = -s $var_tftpd_secure_directory" >> /etc/xinetd.d/tftp +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002426 + - NIST-800-53-AC-6 + - NIST-800-53-CM-6(b) + - NIST-800-53-CM-7(a) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - tftpd_uses_secure_mode +- name: XCCDF Value var_tftpd_secure_directory # promote to variable + set_fact: + var_tftpd_secure_directory: !!str + tags: + - always + +- name: Find out if the file exists and contains the line configuring server arguments + find: + path: /etc/xinetd.d + patterns: tftp + contains: ^[\s]+server_args.*$ + register: tftpd_secure_config_line + when: '"tftp-server" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-002426 + - NIST-800-53-AC-6 + - NIST-800-53-CM-6(b) + - NIST-800-53-CM-7(a) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - tftpd_uses_secure_mode + +- name: Ensure that TFTP server is configured to start with secure directory + lineinfile: + path: /etc/xinetd.d/tftp + regexp: ^[\s]*(server_args[\s]+=[\s]+.*?)(-s[\s]+[/\.\w]+)*(.*)$ + line: \1 -s {{ var_tftpd_secure_directory }} \3 + state: present + backrefs: true + when: + - '"tftp-server" in ansible_facts.packages' + - tftpd_secure_config_line is defined and tftpd_secure_config_line.matched > 0 + tags: + - DISA-STIG-OL09-00-002426 + - NIST-800-53-AC-6 + - NIST-800-53-CM-6(b) + - NIST-800-53-CM-7(a) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - tftpd_uses_secure_mode + +- name: Insert correct config line to start TFTP server with secure directory + lineinfile: + path: /etc/xinetd.d/tftp + line: server_args = -s {{ var_tftpd_secure_directory }} + state: present + create: true + when: + - '"tftp-server" in ansible_facts.packages' + - tftpd_secure_config_line is defined and tftpd_secure_config_line.matched == 0 + tags: + - DISA-STIG-OL09-00-002426 + - NIST-800-53-AC-6 + - NIST-800-53-CM-6(b) + - NIST-800-53-CM-7(a) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - tftpd_uses_secure_mode + + + + + + + + + + + + + Proxy Server + A proxy server is a very desirable target for a +potential adversary because much (or all) sensitive data for a +given infrastructure may flow through it. Therefore, if one is +required, the system acting as a proxy server should be dedicated +to that purpose alone and be stored in a physically secure +location. The system's default proxy server software is Squid, and +provided in an RPM package of the same name. + + Disable Squid if Possible + If Squid was installed and activated, but the system +does not need to act as a proxy server, then it should be disabled +and removed. + + Uninstall squid Package + The squid package can be removed with the following command: $ sudo yum erase squid + + A.8.SEC-OL4 + If there is no need to make the proxy server software available, +removing it provides a safeguard against its activation. + +# CAUTION: This remediation script will remove squid +# from the system, and may remove any packages +# that depend on squid. Execute this +# remediation AFTER testing on a non-production +# system! + +if rpm -q --quiet "squid" ; then +yum remove -y "squid" +fi + + - name: Ensure squid is removed + package: + name: squid + state: absent + tags: + - disable_strategy + - low_complexity + - low_disruption + - no_reboot_needed + - package_squid_removed + - unknown_severity + + include remove_squid + +class remove_squid { + package { 'squid': + ensure => 'purged', + } +} + + +package --remove=squid + + + + + + + + + + Disable Squid + +The squid service can be disabled with the following command: +$ sudo systemctl mask --now squid.service + + Running proxy server software provides a network-based avenue +of attack, and should be removed if not needed. + + # Remediation is applicable only in certain platforms +if ( rpm --quiet -q squid && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ); then + +SYSTEMCTL_EXEC='/usr/bin/systemctl' +if [[ $("$SYSTEMCTL_EXEC" is-system-running) != "offline" ]]; then + "$SYSTEMCTL_EXEC" stop 'squid.service' +fi +"$SYSTEMCTL_EXEC" disable 'squid.service' +"$SYSTEMCTL_EXEC" mask 'squid.service' +# Disable socket activation if we have a unit file for it +if "$SYSTEMCTL_EXEC" -q list-unit-files squid.socket; then + if [[ $("$SYSTEMCTL_EXEC" is-system-running) != "offline" ]]; then + "$SYSTEMCTL_EXEC" stop 'squid.socket' + fi + "$SYSTEMCTL_EXEC" mask 'squid.socket' +fi +# The service may not be running because it has been started and failed, +# so let's reset the state so OVAL checks pass. +# Service should be 'inactive', not 'failed' after reboot though. +"$SYSTEMCTL_EXEC" reset-failed 'squid.service' || true + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - disable_strategy + - low_complexity + - low_disruption + - no_reboot_needed + - service_squid_disabled + - unknown_severity + +- name: Disable Squid - Collect systemd Services Present in the System + ansible.builtin.command: systemctl -q list-unit-files --type service + register: service_exists + changed_when: false + failed_when: service_exists.rc not in [0, 1] + check_mode: false + when: ( "squid" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + tags: + - disable_strategy + - low_complexity + - low_disruption + - no_reboot_needed + - service_squid_disabled + - unknown_severity + +- name: Disable Squid - Ensure squid.service is Masked + ansible.builtin.systemd: + name: squid.service + state: stopped + enabled: false + masked: true + when: + - ( "squid" in ansible_facts.packages and ("kernel" in ansible_facts.packages or + "kernel-uek" in ansible_facts.packages) ) + - service_exists.stdout_lines is search("squid.service", multiline=True) + tags: + - disable_strategy + - low_complexity + - low_disruption + - no_reboot_needed + - service_squid_disabled + - unknown_severity + +- name: Unit Socket Exists - squid.socket + ansible.builtin.command: systemctl -q list-unit-files squid.socket + register: socket_file_exists + changed_when: false + failed_when: socket_file_exists.rc not in [0, 1] + check_mode: false + when: ( "squid" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + tags: + - disable_strategy + - low_complexity + - low_disruption + - no_reboot_needed + - service_squid_disabled + - unknown_severity + +- name: Disable Squid - Disable Socket squid + ansible.builtin.systemd: + name: squid.socket + enabled: false + state: stopped + masked: true + when: + - ( "squid" in ansible_facts.packages and ("kernel" in ansible_facts.packages or + "kernel-uek" in ansible_facts.packages) ) + - socket_file_exists.stdout_lines is search("squid.socket", multiline=True) + tags: + - disable_strategy + - low_complexity + - low_disruption + - no_reboot_needed + - service_squid_disabled + - unknown_severity + + include disable_squid + +class disable_squid { + service {'squid': + enable => false, + ensure => 'stopped', + } +} + + +[customizations.services] +masked = ["squid"] + + + + + + + + + + + + Hardware RNG Entropy Gatherer Daemon + The rngd feeds random data from hardware device to kernel random device. + + + Enable the Hardware RNG Entropy Gatherer Service + The Hardware RNG Entropy Gatherer service should be enabled. + +The rngd service can be enabled with the following command: +$ sudo systemctl enable rngd.service + + For Oracle Linux 9 running with kernel FIPS mode enabled this rule is not applicable. +The in-kernel deterministic random bit generator (DRBG) is used in FIPS mode instead. +Consequently, the rngd service can't be started in FIPS mode. + CCI-000366 + SRG-OS-000480-GPOS-00227 + The rngd service +feeds random data from hardware device to kernel random device. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { ! ( [ "$(sysctl -a | grep -c 'fips_enabled.*1')" -eq 1 ] ); }; then + +SYSTEMCTL_EXEC='/usr/bin/systemctl' +"$SYSTEMCTL_EXEC" unmask 'rngd.service' +if [[ $("$SYSTEMCTL_EXEC" is-system-running) != "offline" ]]; then + "$SYSTEMCTL_EXEC" start 'rngd.service' +fi +"$SYSTEMCTL_EXEC" enable 'rngd.service' + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - enable_strategy + - low_complexity + - low_disruption + - low_severity + - no_reboot_needed + - service_rngd_enabled + +- name: Enable the Hardware RNG Entropy Gatherer Service - Enable service rngd + block: + + - name: Gather the package facts + package_facts: + manager: auto + + - name: Enable the Hardware RNG Entropy Gatherer Service - Enable Service rngd + ansible.builtin.systemd: + name: rngd + enabled: true + state: started + masked: false + when: + - '"rng-tools" in ansible_facts.packages' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - enable_strategy + - low_complexity + - low_disruption + - low_severity + - no_reboot_needed + - service_rngd_enabled + + include enable_rngd + +class enable_rngd { + service {'rngd': + enable => true, + ensure => 'running', + } +} + + +[customizations.services] +enabled = ["rngd"] + + + + + + + + + + + Network Routing + A router is a very desirable target for a +potential adversary because they fulfill a variety of +infrastructure networking roles such as access to network segments, +gateways to other networks, filtering, etc. Therefore, if one is +required, the system acting as a router should be dedicated +to that purpose alone and be stored in a physically secure +location. The system's default routing software is Quagga, and +provided in an RPM package of the same name. + + Disable Quagga if Possible + If Quagga was installed and activated, but the system +does not need to act as a router, then it should be disabled +and removed. + + Uninstall quagga Package + The quagga package can be removed with the following command: $ sudo yum erase quagga + + 12 + 15 + 8 + APO13.01 + DSS05.02 + CCI-000366 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 7.1 + SR 7.6 + A.13.1.1 + A.13.2.1 + A.14.1.3 + CM-7(a) + CM-7(b) + CM-6(a) + PR.PT-4 + SRG-OS-000480-GPOS-00227 + OL09-00-000140 + SV-271464r1092459_rule + Routing software is typically used on routers to exchange network topology information +with other routers. If routing software is used when not required, system network +information may be unnecessarily transmitted across the network. + +If there is no need to make the router software available, +removing it provides a safeguard against its activation. + +# CAUTION: This remediation script will remove quagga +# from the system, and may remove any packages +# that depend on quagga. Execute this +# remediation AFTER testing on a non-production +# system! + +if rpm -q --quiet "quagga" ; then +yum remove -y "quagga" +fi + + - name: Ensure quagga is removed + package: + name: quagga + state: absent + tags: + - DISA-STIG-OL09-00-000140 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - low_disruption + - low_severity + - no_reboot_needed + - package_quagga_removed + + include remove_quagga + +class remove_quagga { + package { 'quagga': + ensure => 'purged', + } +} + + +package --remove=quagga + + + + + + + + + + + + SNMP Server + The Simple Network Management Protocol allows +administrators to monitor the state of network devices, including +computers. Older versions of SNMP were well-known for weak +security, such as plaintext transmission of the community string +(used for authentication) and usage of easily-guessable +choices for the community string. + + Disable SNMP Server if Possible + The system includes an SNMP daemon that allows for its remote +monitoring, though it not installed by default. If it was installed and +activated but is not needed, the software should be disabled and removed. + + Uninstall net-snmp Package + +The net-snmp package provides the snmpd service. +The net-snmp package can be removed with the following command: + +$ sudo yum erase net-snmp + + A.8.SEC-OL4 + 2.2.4 + 2.2 + If there is no need to run SNMP server software, +removing the package provides a safeguard against its +activation. + +# CAUTION: This remediation script will remove net-snmp +# from the system, and may remove any packages +# that depend on net-snmp. Execute this +# remediation AFTER testing on a non-production +# system! + +if rpm -q --quiet "net-snmp" ; then +yum remove -y "net-snmp" +fi + + - name: Ensure net-snmp is removed + package: + name: net-snmp + state: absent + tags: + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.4 + - disable_strategy + - low_complexity + - low_disruption + - no_reboot_needed + - package_net-snmp_removed + - unknown_severity + + include remove_net-snmp + +class remove_net-snmp { + package { 'net-snmp': + ensure => 'purged', + } +} + + +package --remove=net-snmp + + + + + + + + + + Disable snmpd Service + +The snmpd service can be disabled with the following command: +$ sudo systemctl mask --now snmpd.service + + 1311 + Running SNMP software provides a network-based avenue of attack, and +should be disabled if not needed. + + # Remediation is applicable only in certain platforms +if ( rpm --quiet -q net-snmp && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ); then + +SYSTEMCTL_EXEC='/usr/bin/systemctl' +if [[ $("$SYSTEMCTL_EXEC" is-system-running) != "offline" ]]; then + "$SYSTEMCTL_EXEC" stop 'snmpd.service' +fi +"$SYSTEMCTL_EXEC" disable 'snmpd.service' +"$SYSTEMCTL_EXEC" mask 'snmpd.service' +# Disable socket activation if we have a unit file for it +if "$SYSTEMCTL_EXEC" -q list-unit-files snmpd.socket; then + if [[ $("$SYSTEMCTL_EXEC" is-system-running) != "offline" ]]; then + "$SYSTEMCTL_EXEC" stop 'snmpd.socket' + fi + "$SYSTEMCTL_EXEC" mask 'snmpd.socket' +fi +# The service may not be running because it has been started and failed, +# so let's reset the state so OVAL checks pass. +# Service should be 'inactive', not 'failed' after reboot though. +"$SYSTEMCTL_EXEC" reset-failed 'snmpd.service' || true + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - disable_strategy + - low_complexity + - low_disruption + - low_severity + - no_reboot_needed + - service_snmpd_disabled + +- name: Disable snmpd Service - Collect systemd Services Present in the System + ansible.builtin.command: systemctl -q list-unit-files --type service + register: service_exists + changed_when: false + failed_when: service_exists.rc not in [0, 1] + check_mode: false + when: ( "net-snmp" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + tags: + - disable_strategy + - low_complexity + - low_disruption + - low_severity + - no_reboot_needed + - service_snmpd_disabled + +- name: Disable snmpd Service - Ensure snmpd.service is Masked + ansible.builtin.systemd: + name: snmpd.service + state: stopped + enabled: false + masked: true + when: + - ( "net-snmp" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + - service_exists.stdout_lines is search("snmpd.service", multiline=True) + tags: + - disable_strategy + - low_complexity + - low_disruption + - low_severity + - no_reboot_needed + - service_snmpd_disabled + +- name: Unit Socket Exists - snmpd.socket + ansible.builtin.command: systemctl -q list-unit-files snmpd.socket + register: socket_file_exists + changed_when: false + failed_when: socket_file_exists.rc not in [0, 1] + check_mode: false + when: ( "net-snmp" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + tags: + - disable_strategy + - low_complexity + - low_disruption + - low_severity + - no_reboot_needed + - service_snmpd_disabled + +- name: Disable snmpd Service - Disable Socket snmpd + ansible.builtin.systemd: + name: snmpd.socket + enabled: false + state: stopped + masked: true + when: + - ( "net-snmp" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + - socket_file_exists.stdout_lines is search("snmpd.socket", multiline=True) + tags: + - disable_strategy + - low_complexity + - low_disruption + - low_severity + - no_reboot_needed + - service_snmpd_disabled + + include disable_snmpd + +class disable_snmpd { + service {'snmpd': + enable => false, + ensure => 'stopped', + } +} + + +[customizations.services] +masked = ["snmpd"] + + + + + + + + + + + Configure SNMP Server if Necessary + If it is necessary to run the snmpd agent on the system, some best +practices should be followed to minimize the security risk from the +installation. The multiple security models implemented by SNMP cannot be fully +covered here so only the following general configuration advice can be offered: +use only SNMP version 3 security models and enable the use of authentication and encryptionwrite access to the MIB (Management Information Base) should be allowed only if necessaryall access to the MIB should be restricted following a principle of least privilegenetwork access should be limited to the maximum extent possible including restricting to expected network +addresses both in the configuration files and in the system firewall rulesensure SNMP agents send traps only to, and accept SNMP queries only from, authorized management +stationsensure that permissions on the snmpd.conf configuration file (by default, in /etc/snmp) are 640 or more restrictiveensure that any MIB files' permissions are also 640 or more restrictive + + + Configure SNMP Service to Use Only SNMPv3 or Newer + Edit /etc/snmp/snmpd.conf, removing any references to rocommunity, rwcommunity, or com2sec. +Upon doing that, restart the SNMP service: +$ sudo systemctl restart snmpd + + 1311 + Earlier versions of SNMP are considered insecure, as they potentially allow +unauthorized access to detailed system management information. + + + + + + + + + + + + SSH Server + The SSH protocol is recommended for remote login and +remote file transfer. SSH provides confidentiality and integrity +for data exchanged between two systems, as well as server +authentication, through the use of public key cryptography. The +implementation included with the system is called OpenSSH, and more +detailed documentation is available from its website, + + https://www.openssh.com. +Its server program is called sshd and provided by the RPM package +openssh-server. + + + SSH enabled firewalld zone + Specify firewalld zone to enable SSH service. This value is used only for remediation purposes. + block + public + dmz + drop + external + home + internal + public + trusted + work + + + SSH Approved ciphers by FIPS + Specify the FIPS approved ciphers that are used for data integrity protection by the SSH server. + aes256-ctr,aes192-ctr,aes128-ctr + aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes128-ctr + aes256-gcm@openssh.com,aes256-ctr,aes128-gcm@openssh.com,aes128-ctr + aes128-ctr,aes192-ctr,aes256-ctr,aes128-cbc,3des-cbc,aes192-cbc,aes256-cbc,rijndael-cbc@lysator.liu.se + -3des-cbc,aes128-cbc,aes192-cbc,aes256-cbc,rijndael-cbc@lysator.liu.se + -3des-cbc,aes128-cbc,aes192-cbc,aes256-cbc,rijndael-cbc@lysator.liu.se + chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr + chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr + chacha20-poly1305@openssh.com,aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm@openssh.com,aes256-gcm@openssh.com + aes256-ctr,aes256-gcm@openssh.com,aes192-ctr,aes128-ctr,aes128-gcm@openssh.com + aes256-gcm@openssh.com,aes256-ctr,aes128-gcm@openssh.com,aes128-ctr + + + SSH Approved MACs by FIPS + Specify the FIPS approved MACs (message authentication code) algorithms + that are used for data integrity protection by the SSH server. + hmac-sha2-512,hmac-sha2-256 + hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512,hmac-sha2-256 + hmac-sha2-512,hmac-sha2-256,hmac-sha1,hmac-sha1-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com + hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512,hmac-sha2-256 + hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512,hmac-sha2-256 + hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512,hmac-sha2-256 + hmac-sha2-512,hmac-sha2-512-etm@openssh.com,hmac-sha2-256,hmac-sha2-256-etm@openssh.com + + + SSH session Idle time + Specify duration of allowed idle time. + 600 + 7200 + 840 + 900 + 1800 + 300 + 3600 + 300 + + + SSH Server Listening Port + Specify port the SSH server is listening. + 22 + + + SSH Max authentication attempts + Specify the maximum number of authentication attempts per connection. + 10 + 3 + 4 + 5 + 4 + + + SSH is required to be installed + Specify if the Policy requires SSH to be installed. Used by SSH Rules +to determine if SSH should be uninstalled or configured. +A value of 0 means that the policy doesn't care if OpenSSH server is installed or not. If it is installed, scanner will check for it's configuration, if it's not installed, the check will pass. +A value of 1 indicates that OpenSSH server package is not required by the policy; +A value of 2 indicates that OpenSSH server package is required by the policy. + + 0 + 1 + 2 + + + SSH Strong MACs by FIPS + Specify the FIPS approved MACs (Message Authentication Code) algorithms + that are used for data integrity protection by the SSH server. + hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-512,hmac-sha2-256,hmac-ripemd160 + -hmac-md5,hmac-md5-96,hmac-ripemd160,hmac-sha1-96,umac-64@openssh.com,hmac-md5-etm@openssh.com,hmac-md5-96-etm@openssh.com,hmac-ripemd160-etm@openssh.com,hmac-sha1-96-etm@openssh.com,umac-64-etm@openssh.com + -hmac-md5,hmac-md5-96,hmac-ripemd160,hmac-sha1-96,umac-64@openssh.com,hmac-md5-etm@openssh.com,hmac-md5-96-etm@openssh.com,hmac-ripemd160-etm@openssh.com,hmac-sha1-96-etm@openssh.com,umac-64-etm@openssh.com + hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-512,hmac-sha2-256,hmac-ripemd160 + hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-512,hmac-sha2-256 + hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512,hmac-sha2-256 + hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512,hmac-sha2-256 + hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-sha2-256,hmac-sha2-512 + hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-sha2-256,hmac-sha2-512 + + + SSH Max Sessions Count + Specify the maximum number of open sessions permitted. + 10 + 4 + 3 + 2 + 1 + 0 + 10 + + + SSH Max Keep Alive Count + Specify the maximum number of idle message counts before session is terminated. + 10 + 3 + 5 + 0 + 1 + 0 + + + Install OpenSSH client software + The openssh-clients package can be installed with the following command: + +$ sudo yum install openssh-clients + + CCI-000366 + FIA_UAU.5 + FTP_ITC_EXT.1 + FCS_SSH_EXT.1 + FCS_SSHC_EXT.1 + SRG-OS-000480-GPOS-00227 + OL09-00-000260 + SV-271488r1091176_rule + This package includes utilities to make encrypted connections and transfer +files securely to SSH servers. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +if ! rpm -q --quiet "openssh-clients" ; then + yum install -y "openssh-clients" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-000260 + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - package_openssh-clients_installed + +- name: Ensure openssh-clients is installed + package: + name: openssh-clients + state: present + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-000260 + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - package_openssh-clients_installed + + include install_openssh-clients + +class install_openssh-clients { + package { 'openssh-clients': + ensure => 'installed', + } +} + + +package --add=openssh-clients + + +[[packages]] +name = "openssh-clients" +version = "*" + + + + + + + + + + Install the OpenSSH Server Package + The openssh-server package should be installed. +The openssh-server package can be installed with the following command: + +$ sudo yum install openssh-server + + 13 + 14 + APO01.06 + DSS05.02 + DSS05.04 + DSS05.07 + DSS06.02 + DSS06.06 + CCI-002420 + CCI-002421 + CCI-002418 + CCI-002422 + SR 3.1 + SR 3.8 + SR 4.1 + SR 4.2 + SR 5.2 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CM-6(a) + PR.DS-2 + PR.DS-5 + FIA_UAU.5 + FTP_ITC_EXT.1 + FCS_SSH_EXT.1 + FCS_SSHS_EXT.1 + SRG-OS-000423-GPOS-00187 + SRG-OS-000424-GPOS-00188 + SRG-OS-000425-GPOS-00189 + SRG-OS-000426-GPOS-00190 + OL09-00-000250 + SV-271482r1091158_rule + Without protection of the transmitted information, confidentiality, and +integrity may be compromised because unprotected communications can be +intercepted and either read or altered. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +if ! rpm -q --quiet "openssh-server" ; then + yum install -y "openssh-server" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-000250 + - NIST-800-53-CM-6(a) + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - package_openssh-server_installed + +- name: Ensure openssh-server is installed + package: + name: openssh-server + state: present + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-000250 + - NIST-800-53-CM-6(a) + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - package_openssh-server_installed + + include install_openssh-server + +class install_openssh-server { + package { 'openssh-server': + ensure => 'installed', + } +} + + +package --add=openssh-server + + +[[packages]] +name = "openssh-server" +version = "*" + + + + + + + + + + Remove the OpenSSH Server Package + The openssh-server package should be removed. +The openssh-server package can be removed with the following command: + +$ sudo yum erase openssh-server + + Without protection of the transmitted information, confidentiality, and +integrity may be compromised because unprotected communications can be +intercepted and either read or altered. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# CAUTION: This remediation script will remove openssh-server +# from the system, and may remove any packages +# that depend on openssh-server. Execute this +# remediation AFTER testing on a non-production +# system! + +if rpm -q --quiet "openssh-server" ; then +yum remove -y "openssh-server" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - disable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - package_openssh-server_removed + +- name: Ensure openssh-server is removed + package: + name: openssh-server + state: absent + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - package_openssh-server_removed + + include remove_openssh-server + +class remove_openssh-server { + package { 'openssh-server': + ensure => 'purged', + } +} + + +package --remove=openssh-server + + + + + + + + + + Enable the OpenSSH Service + The SSH server service, sshd, is commonly needed. + +The sshd service can be enabled with the following command: +$ sudo systemctl enable sshd.service + + 13 + 14 + APO01.06 + DSS05.02 + DSS05.04 + DSS05.07 + DSS06.02 + DSS06.06 + 3.1.13 + 3.5.4 + 3.13.8 + CCI-002420 + CCI-002421 + CCI-002418 + CCI-002422 + SR 3.1 + SR 3.8 + SR 4.1 + SR 4.2 + SR 5.2 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CM-6(a) + SC-8 + SC-8(1) + SC-8(2) + SC-8(3) + SC-8(4) + PR.DS-2 + PR.DS-5 + SRG-OS-000423-GPOS-00187 + SRG-OS-000424-GPOS-00188 + SRG-OS-000425-GPOS-00189 + SRG-OS-000426-GPOS-00190 + OL09-00-000251 + SV-271483r1091161_rule + Without protection of the transmitted information, confidentiality, and +integrity may be compromised because unprotected communications can be +intercepted and either read or altered. + + +This checklist item applies to both internal and external networks and all types +of information system components from which information can be transmitted (e.g., servers, +mobile devices, notebook computers, printers, copiers, scanners, etc). Communication paths +outside the physical protection of a controlled boundary are exposed to the possibility +of interception and modification. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +SYSTEMCTL_EXEC='/usr/bin/systemctl' +"$SYSTEMCTL_EXEC" unmask 'sshd.service' +if [[ $("$SYSTEMCTL_EXEC" is-system-running) != "offline" ]]; then + "$SYSTEMCTL_EXEC" start 'sshd.service' +fi +"$SYSTEMCTL_EXEC" enable 'sshd.service' + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-000251 + - NIST-800-171-3.1.13 + - NIST-800-171-3.13.8 + - NIST-800-171-3.5.4 + - NIST-800-53-CM-6(a) + - NIST-800-53-SC-8 + - NIST-800-53-SC-8(1) + - NIST-800-53-SC-8(2) + - NIST-800-53-SC-8(3) + - NIST-800-53-SC-8(4) + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_sshd_enabled + +- name: Enable the OpenSSH Service - Enable service sshd + block: + + - name: Gather the package facts + package_facts: + manager: auto + + - name: Enable the OpenSSH Service - Enable Service sshd + ansible.builtin.systemd: + name: sshd + enabled: true + state: started + masked: false + when: + - '"openssh-server" in ansible_facts.packages' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-000251 + - NIST-800-171-3.1.13 + - NIST-800-171-3.13.8 + - NIST-800-171-3.5.4 + - NIST-800-53-CM-6(a) + - NIST-800-53-SC-8 + - NIST-800-53-SC-8(1) + - NIST-800-53-SC-8(2) + - NIST-800-53-SC-8(3) + - NIST-800-53-SC-8(4) + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_sshd_enabled + + include enable_sshd + +class enable_sshd { + service {'sshd': + enable => true, + ensure => 'running', + } +} + + +[customizations.services] +enabled = ["sshd"] + + + + + + + + + + Disable SSH Server If Possible + +The SSH server service, sshd, is commonly needed. +However, if it can be disabled, do so. +This is unusual, as SSH is a common method for encrypted and authenticated +remote access. + CM-3(6) + IA-2(4) + SRG-APP-000185-CTR-000490 + SRG-APP-000141-CTR-000315 + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +SYSTEMCTL_EXEC='/usr/bin/systemctl' +if [[ $("$SYSTEMCTL_EXEC" is-system-running) != "offline" ]]; then + "$SYSTEMCTL_EXEC" stop 'sshd.service' +fi +"$SYSTEMCTL_EXEC" disable 'sshd.service' +"$SYSTEMCTL_EXEC" mask 'sshd.service' +# Disable socket activation if we have a unit file for it +if "$SYSTEMCTL_EXEC" -q list-unit-files sshd.socket; then + if [[ $("$SYSTEMCTL_EXEC" is-system-running) != "offline" ]]; then + "$SYSTEMCTL_EXEC" stop 'sshd.socket' + fi + "$SYSTEMCTL_EXEC" mask 'sshd.socket' +fi +# The service may not be running because it has been started and failed, +# so let's reset the state so OVAL checks pass. +# Service should be 'inactive', not 'failed' after reboot though. +"$SYSTEMCTL_EXEC" reset-failed 'sshd.service' || true + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-53-CM-3(6) + - NIST-800-53-IA-2(4) + - disable_strategy + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - service_sshd_disabled + +- name: Disable SSH Server If Possible - Collect systemd Services Present in the System + ansible.builtin.command: systemctl -q list-unit-files --type service + register: service_exists + changed_when: false + failed_when: service_exists.rc not in [0, 1] + check_mode: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-CM-3(6) + - NIST-800-53-IA-2(4) + - disable_strategy + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - service_sshd_disabled + +- name: Disable SSH Server If Possible - Ensure sshd.service is Masked + ansible.builtin.systemd: + name: sshd.service + state: stopped + enabled: false + masked: true + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - service_exists.stdout_lines is search("sshd.service", multiline=True) + tags: + - NIST-800-53-CM-3(6) + - NIST-800-53-IA-2(4) + - disable_strategy + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - service_sshd_disabled + +- name: Unit Socket Exists - sshd.socket + ansible.builtin.command: systemctl -q list-unit-files sshd.socket + register: socket_file_exists + changed_when: false + failed_when: socket_file_exists.rc not in [0, 1] + check_mode: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-CM-3(6) + - NIST-800-53-IA-2(4) + - disable_strategy + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - service_sshd_disabled + +- name: Disable SSH Server If Possible - Disable Socket sshd + ansible.builtin.systemd: + name: sshd.socket + enabled: false + state: stopped + masked: true + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - socket_file_exists.stdout_lines is search("sshd.socket", multiline=True) + tags: + - NIST-800-53-CM-3(6) + - NIST-800-53-IA-2(4) + - disable_strategy + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - service_sshd_disabled + + include disable_sshd + +class disable_sshd { + service {'sshd': + enable => false, + ensure => 'stopped', + } +} + + +[customizations.services] +masked = ["sshd"] + + + + + + + + + + Verify Group Who Owns SSH Server config file + +To properly set the group owner of /etc/ssh/sshd_config, run the command: +$ sudo chgrp root /etc/ssh/sshd_config + + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + APO01.06 + DSS05.04 + DSS05.07 + DSS06.02 + CCI-000366 + 4.3.3.7.3 + SR 2.1 + SR 5.2 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 + AC-17(a) + CM-6(a) + AC-6(1) + PR.AC-4 + PR.DS-5 + SRG-OS-000480-GPOS-00227 + R50 + OL09-00-002507 + SV-271776r1092040_rule + Service configuration files enable or disable features of their respective +services that if configured incorrectly can lead to insecure and vulnerable +configurations. Therefore, service configuration files should be owned by the +correct group to prevent unauthorized changes. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +chgrp 0 /etc/ssh/sshd_config + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002507 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - configure_strategy + - file_groupowner_sshd_config + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /etc/ssh/sshd_config + stat: + path: /etc/ssh/sshd_config + register: file_exists + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002507 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - configure_strategy + - file_groupowner_sshd_config + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure group owner 0 on /etc/ssh/sshd_config + file: + path: /etc/ssh/sshd_config + group: '0' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - file_exists.stat is defined and file_exists.stat.exists + tags: + - DISA-STIG-OL09-00-002507 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - configure_strategy + - file_groupowner_sshd_config + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify Group Ownership on SSH Server Private *_key Key Files + SSH server private keys, files that match the /etc/ssh/*_key glob, must be +group-owned by ssh_keys group. + Remediation is not possible at bootable container build time because SSH host +keys are generated post-deployment. + R50 + If an unauthorized user obtains the private SSH host key file, the host could be impersonated. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +find -L /etc/ssh/ -maxdepth 1 -type f ! -group ssh_keys -regextype posix-extended -regex '^.*_key$' -exec chgrp -L ssh_keys {} \; + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - configure_strategy + - file_groupownership_sshd_private_key + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Find /etc/ssh/ file(s) matching ^.*_key$ + command: find -H /etc/ssh/ -maxdepth 1 -type f ! -group ssh_keys -regextype posix-extended + -regex "^.*_key$" + register: files_found + changed_when: false + failed_when: false + check_mode: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - configure_strategy + - file_groupownership_sshd_private_key + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure group owner on /etc/ssh/ file(s) matching ^.*_key$ + file: + path: '{{ item }}' + group: ssh_keys + state: file + with_items: + - '{{ files_found.stdout_lines }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - configure_strategy + - file_groupownership_sshd_private_key + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify Group Ownership on SSH Server Public *.pub Key Files + SSH server public keys, files that match the /etc/ssh/*.pub glob, must be +group-owned by root group. + Remediation is not possible at bootable container build time because SSH host +keys are generated post-deployment. + R50 + If a public host key file is modified by an unauthorized user, the SSH service +may be compromised. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +find -L /etc/ssh/ -maxdepth 1 -type f ! -group 0 -regextype posix-extended -regex '^.*\.pub$' -exec chgrp -L 0 {} \; + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - configure_strategy + - file_groupownership_sshd_pub_key + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Find /etc/ssh/ file(s) matching ^.*\.pub$ + command: find -H /etc/ssh/ -maxdepth 1 -type f ! -group 0 -regextype posix-extended + -regex "^.*\.pub$" + register: files_found + changed_when: false + failed_when: false + check_mode: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - configure_strategy + - file_groupownership_sshd_pub_key + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure group owner on /etc/ssh/ file(s) matching ^.*\.pub$ + file: + path: '{{ item }}' + group: '0' + state: file + with_items: + - '{{ files_found.stdout_lines }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - configure_strategy + - file_groupownership_sshd_pub_key + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify Owner on SSH Server config file + +To properly set the owner of /etc/ssh/sshd_config, run the command: +$ sudo chown root /etc/ssh/sshd_config + + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + APO01.06 + DSS05.04 + DSS05.07 + DSS06.02 + CCI-000366 + 4.3.3.7.3 + SR 2.1 + SR 5.2 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 + AC-17(a) + CM-6(a) + AC-6(1) + PR.AC-4 + PR.DS-5 + SRG-OS-000480-GPOS-00227 + R50 + OL09-00-002508 + SV-271777r1092043_rule + Service configuration files enable or disable features of their respective +services that if configured incorrectly can lead to insecure and vulnerable +configurations. Therefore, service configuration files should be owned by the +correct group to prevent unauthorized changes. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +chown 0 /etc/ssh/sshd_config + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002508 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - configure_strategy + - file_owner_sshd_config + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /etc/ssh/sshd_config + stat: + path: /etc/ssh/sshd_config + register: file_exists + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002508 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - configure_strategy + - file_owner_sshd_config + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure owner 0 on /etc/ssh/sshd_config + file: + path: /etc/ssh/sshd_config + owner: '0' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - file_exists.stat is defined and file_exists.stat.exists + tags: + - DISA-STIG-OL09-00-002508 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - configure_strategy + - file_owner_sshd_config + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify Ownership on SSH Server Private *_key Key Files + SSH server private keys, files that match the /etc/ssh/*_key glob, must be owned +by root user. + Remediation is not possible at bootable container build time because SSH host +keys are generated post-deployment. + R50 + If an unauthorized user obtains the private SSH host key file, the host could be impersonated. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +find -L /etc/ssh/ -maxdepth 1 -type f ! -uid 0 -regextype posix-extended -regex '^.*_key$' -exec chown -L 0 {} \; + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - configure_strategy + - file_ownership_sshd_private_key + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Find /etc/ssh/ file(s) matching ^.*_key$ + command: find -H /etc/ssh/ -maxdepth 1 -type f ! -uid 0 -regextype posix-extended + -regex "^.*_key$" + register: files_found + changed_when: false + failed_when: false + check_mode: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - configure_strategy + - file_ownership_sshd_private_key + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure owner on /etc/ssh/ file(s) matching ^.*_key$ + file: + path: '{{ item }}' + owner: '0' + state: file + with_items: + - '{{ files_found.stdout_lines }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - configure_strategy + - file_ownership_sshd_private_key + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify Ownership on SSH Server Public *.pub Key Files + SSH server public keys, files that match the /etc/ssh/*.pub glob, must be owned +by root user. + Remediation is not possible at bootable container build time because SSH host +keys are generated post-deployment. + R50 + If a public host key file is modified by an unauthorized user, the SSH service +may be compromised. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +find -L /etc/ssh/ -maxdepth 1 -type f ! -uid 0 -regextype posix-extended -regex '^.*\.pub$' -exec chown -L 0 {} \; + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - configure_strategy + - file_ownership_sshd_pub_key + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Find /etc/ssh/ file(s) matching ^.*\.pub$ + command: find -H /etc/ssh/ -maxdepth 1 -type f ! -uid 0 -regextype posix-extended + -regex "^.*\.pub$" + register: files_found + changed_when: false + failed_when: false + check_mode: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - configure_strategy + - file_ownership_sshd_pub_key + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure owner on /etc/ssh/ file(s) matching ^.*\.pub$ + file: + path: '{{ item }}' + owner: '0' + state: file + with_items: + - '{{ files_found.stdout_lines }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - configure_strategy + - file_ownership_sshd_pub_key + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify Permissions on SSH Server config file + +To properly set the permissions of /etc/ssh/sshd_config, run the command: +$ sudo chmod 0600 /etc/ssh/sshd_config + + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + APO01.06 + DSS05.04 + DSS05.07 + DSS06.02 + CCI-000366 + 4.3.3.7.3 + SR 2.1 + SR 5.2 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 + AC-17(a) + CM-6(a) + AC-6(1) + PR.AC-4 + PR.DS-5 + SRG-OS-000480-GPOS-00227 + R50 + 2.2.6 + 2.2 + OL09-00-002509 + SV-271778r1092046_rule + Service configuration files enable or disable features of their respective +services that if configured incorrectly can lead to insecure and vulnerable +configurations. Therefore, service configuration files should be owned by the +correct group to prevent unauthorized changes. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +chmod u-xs,g-xwrs,o-xwrt /etc/ssh/sshd_config + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002509 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_permissions_sshd_config + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /etc/ssh/sshd_config + stat: + path: /etc/ssh/sshd_config + register: file_exists + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002509 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_permissions_sshd_config + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure permission u-xs,g-xwrs,o-xwrt on /etc/ssh/sshd_config + file: + path: /etc/ssh/sshd_config + mode: u-xs,g-xwrs,o-xwrt + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - file_exists.stat is defined and file_exists.stat.exists + tags: + - DISA-STIG-OL09-00-002509 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_permissions_sshd_config + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify Permissions on SSH Server Private *_key Key Files + SSH server private keys - files that match the /etc/ssh/*_key glob, have to have restricted permissions. +If those files are owned by the root user and the root group, they have to have the 0600 permission or stricter. +If they are owned by the root user, but by a dedicated group ssh_keys, they can have the 0640 permission or stricter. + Remediation is not possible at bootable container build time because SSH host +keys are generated post-deployment. + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + APO01.06 + DSS05.04 + DSS05.07 + DSS06.02 + 3.1.13 + 3.13.10 + CCI-000366 + 4.3.3.7.3 + SR 2.1 + SR 5.2 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 + AC-17(a) + CM-6(a) + AC-6(1) + PR.AC-4 + PR.DS-5 + Req-2.2.4 + SRG-OS-000480-GPOS-00227 + R50 + 2.2.6 + 2.2 + OL09-00-002502 + SV-271771r1092025_rule + If an unauthorized user obtains the private SSH host key file, the host could be +impersonated. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +for keyfile in /etc/ssh/*_key; do + test -f "$keyfile" || continue + if test root:root = "$(stat -c "%U:%G" "$keyfile")"; then + + chmod u-xs,g-xwrs,o-xwrt "$keyfile" + + elif test root:ssh_keys = "$(stat -c "%U:%G" "$keyfile")"; then + chmod u-xs,g-xws,o-xwrt "$keyfile" + else + echo "Key-like file '$keyfile' is owned by an unexpected user:group combination" + fi +done + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002502 + - NIST-800-171-3.1.13 + - NIST-800-171-3.13.10 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-2.2.4 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_permissions_sshd_private_key + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Find root:root-owned keys + ansible.builtin.command: find -H /etc/ssh/ -maxdepth 1 -user root -regex ".*_key$" + -type f -group root -perm /u+xs,g+xwrs,o+xwrt + register: root_owned_keys + changed_when: false + failed_when: false + check_mode: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002502 + - NIST-800-171-3.1.13 + - NIST-800-171-3.13.10 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-2.2.4 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_permissions_sshd_private_key + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Set permissions for root:root-owned keys + ansible.builtin.file: + path: '{{ item }}' + mode: u-xs,g-xwrs,o-xwrt + state: file + with_items: + - '{{ root_owned_keys.stdout_lines }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002502 + - NIST-800-171-3.1.13 + - NIST-800-171-3.13.10 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-2.2.4 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_permissions_sshd_private_key + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Find root:ssh_keys-owned keys + ansible.builtin.command: find -H /etc/ssh/ -maxdepth 1 -user root -regex ".*_key$" + -type f -group ssh_keys -perm /u+xs,g+xws,o+xwrt + register: dedicated_group_owned_keys + changed_when: false + failed_when: false + check_mode: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002502 + - NIST-800-171-3.1.13 + - NIST-800-171-3.13.10 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-2.2.4 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_permissions_sshd_private_key + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Set permissions for root:ssh_keys-owned keys + ansible.builtin.file: + path: '{{ item }}' + mode: u-xs,g-xws,o-xwrt + state: file + with_items: + - '{{ dedicated_group_owned_keys.stdout_lines }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002502 + - NIST-800-171-3.1.13 + - NIST-800-171-3.13.10 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-2.2.4 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_permissions_sshd_private_key + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + include ssh_private_key_perms + +class ssh_private_key_perms { + exec { 'sshd_priv_key': + command => "chmod 0640 /etc/ssh/*_key", + path => '/bin:/usr/bin' + } +} + + + + + + + + + + Verify Permissions on SSH Server Public *.pub Key Files + To properly set the permissions of /etc/ssh/*.pub, run the command: $ sudo chmod 0644 /etc/ssh/*.pub + + Remediation is not possible at bootable container build time because SSH host +keys are generated post-deployment. + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + APO01.06 + DSS05.04 + DSS05.07 + DSS06.02 + 3.1.13 + 3.13.10 + CCI-000366 + 4.3.3.7.3 + SR 2.1 + SR 5.2 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 + AC-17(a) + CM-6(a) + AC-6(1) + PR.AC-4 + PR.DS-5 + Req-2.2.4 + SRG-OS-000480-GPOS-00227 + R50 + 2.2.6 + 2.2 + OL09-00-002503 + SV-271772r1092028_rule + If a public host key file is modified by an unauthorized user, the SSH service +may be compromised. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +find -L /etc/ssh/ -maxdepth 1 -perm /u+xs,g+xws,o+xwt -type f -regextype posix-extended -regex '^.*\.pub$' -exec chmod u-xs,g-xws,o-xwt {} \; + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002503 + - NIST-800-171-3.1.13 + - NIST-800-171-3.13.10 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-2.2.4 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_permissions_sshd_pub_key + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Find /etc/ssh/ file(s) + command: find -H /etc/ssh/ -maxdepth 1 -perm /u+xs,g+xws,o+xwt -type f -regextype + posix-extended -regex "^.*\.pub$" + register: files_found + changed_when: false + failed_when: false + check_mode: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002503 + - NIST-800-171-3.1.13 + - NIST-800-171-3.13.10 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-2.2.4 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_permissions_sshd_pub_key + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Set permissions for /etc/ssh/ file(s) + file: + path: '{{ item }}' + mode: u-xs,g-xws,o-xwt + state: file + with_items: + - '{{ files_found.stdout_lines }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002503 + - NIST-800-171-3.1.13 + - NIST-800-171-3.13.10 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-2.2.4 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_permissions_sshd_pub_key + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + include ssh_public_key_perms + +class ssh_public_key_perms { + exec { 'sshd_pub_key': + command => "chmod 0644 /etc/ssh/*.pub", + path => '/bin:/usr/bin' + } +} + + + + + + + + + + The File /etc/ssh/sshd_config.d/50-redhat.conf Must Exist + The /etc/ssh/sshd_config.d/50-redhat.conf file must exist as it contains important +settings to secure SSH. + There is no remediation available for this rule since this file needs to have the correct content for the given system. + CCI-001453 + AC-17 (2) + SRG-OS-000250-GPOS-00093 + OL09-00-000252 + SV-271484r1092624_rule + The file must exist to configure SSH correctly. + + + + + + Remove SSH Server iptables Firewall exception (Unusual) + By default, inbound connections to SSH's port are allowed. If the SSH +server is not being used, this exception should be removed from the +firewall configuration. + + +Edit the files /etc/sysconfig/iptables and +/etc/sysconfig/ip6tables (if IPv6 is in use). In each file, locate +and delete the line: +-A INPUT -m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT +This is unusual, as SSH is a common method for encrypted and authenticated +remote access. + If inbound SSH connections are not expected, disallowing access to the SSH +port will avoid possible exploitation of the port by an attacker. + + + Configure OpenSSH Client if Necessary + The following configuration changes apply to the SSH client. They can +improve security parameters relwevant to the client user, e.g. increasing +entropy while generating initialization vectors. Note that these changes +influence only the default SSH client configuration. Changes in this group +can be overridden by the client user by modifying files within the +~/.ssh directory or by supplying parameters on the command line. + + Configure session renegotiation for SSH client + The RekeyLimit parameter specifies how often +the session key is renegotiated, both in terms of +amount of data that may be transmitted and the time +elapsed. To decrease the default limits, put line +RekeyLimit + + to file /etc/ssh/ssh_config.d/02-rekey-limit.conf. +Make sure that there is no other RekeyLimit configuration preceding +the include directive in the main config file +/etc/ssh/ssh_config. Check also other files in +/etc/ssh/ssh_config.d directory. Files are processed according to +lexicographical order of file names. Make sure that there is no file +processed before 02-rekey-limit.conf containing definition of +RekeyLimit. + CCI-000068 + FCS_SSH_EXT.1.8 + SRG-OS-000423-GPOS-00187 + SRG-OS-000033-GPOS-00014 + SRG-OS-000424-GPOS-00188 + By decreasing the limit based on the amount of data and enabling +time-based limit, effects of potential attacks against +encryption keys are limited. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +var_ssh_client_rekey_limit_size='' +var_ssh_client_rekey_limit_time='' + + +main_config="/etc/ssh/ssh_config" +include_directory="/etc/ssh/ssh_config.d" + +if grep -q '^[\s]*RekeyLimit.*$' "$main_config"; then + sed -i '/^[\s]*RekeyLimit.*/d' "$main_config" +fi + +for file in "$include_directory"/*.conf; do + if grep -q '^[\s]*RekeyLimit.*$' "$file"; then + sed -i '/^[\s]*RekeyLimit.*/d' "$file" + fi +done + +if [ -e "/etc/ssh/ssh_config.d/02-rekey-limit.conf" ] ; then + + LC_ALL=C sed -i "/^\s*RekeyLimit\s\+/d" "/etc/ssh/ssh_config.d/02-rekey-limit.conf" +else + touch "/etc/ssh/ssh_config.d/02-rekey-limit.conf" +fi +# make sure file has newline at the end +sed -i -e '$a\' "/etc/ssh/ssh_config.d/02-rekey-limit.conf" + +cp "/etc/ssh/ssh_config.d/02-rekey-limit.conf" "/etc/ssh/ssh_config.d/02-rekey-limit.conf.bak" +# Insert at the end of the file +printf '%s\n' "RekeyLimit $var_ssh_client_rekey_limit_size $var_ssh_client_rekey_limit_time" >> "/etc/ssh/ssh_config.d/02-rekey-limit.conf" +# Clean up after ourselves. +rm "/etc/ssh/ssh_config.d/02-rekey-limit.conf.bak" + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - ssh_client_rekey_limit +- name: XCCDF Value var_ssh_client_rekey_limit_size # promote to variable + set_fact: + var_ssh_client_rekey_limit_size: !!str + tags: + - always +- name: XCCDF Value var_ssh_client_rekey_limit_time # promote to variable + set_fact: + var_ssh_client_rekey_limit_time: !!str + tags: + - always + +- name: Ensure RekeyLimit is not configured in /etc/ssh/ssh_config + lineinfile: + path: /etc/ssh/ssh_config + create: false + regexp: ^\s*RekeyLimit.*$ + state: absent + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - ssh_client_rekey_limit + +- name: Collect all include config files for ssh client which configure RekeyLimit + find: + paths: /etc/ssh/ssh_config.d/ + contains: ^[\s]*RekeyLimit.*$ + patterns: '*.config' + register: ssh_config_include_files + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - ssh_client_rekey_limit + +- name: Remove all occurences of RekeyLimit configuration from include config files + of ssh client + lineinfile: + path: '{{ item }}' + regexp: ^[\s]*RekeyLimit.*$ + state: absent + loop: '{{ ssh_config_include_files.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - ssh_client_rekey_limit + +- name: Ensure that rekey limit is set to {{ var_ssh_client_rekey_limit_size }} {{ + var_ssh_client_rekey_limit_time }} in /etc/ssh/ssh_config.d/02-rekey-limit.conf + lineinfile: + path: /etc/ssh/ssh_config.d/02-rekey-limit.conf + create: true + regexp: ^\s*RekeyLimit.*$ + line: RekeyLimit {{ var_ssh_client_rekey_limit_size }} {{ var_ssh_client_rekey_limit_time + }} + state: present + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - ssh_client_rekey_limit + + + + + + + + + + + + Verify the SSH Private Key Files Have a Passcode + When creating SSH key pairs, always use a passcode. + +You can create such keys with the following command: +$ sudo ssh-keygen -n [passphrase] +Oracle Linux 9, for certificate-based authentication, must enforce authorized access to the corresponding private key. + CCI-000186 + SRG-OS-000067-GPOS-00035 + OL09-00-000905 + SV-271605r1091527_rule + If an unauthorized user obtains access to a private key without a passcode, +that user would have unauthorized access to any system where the associated +public key has been installed. + + + + + + + Configure OpenSSH Server if Necessary + If the system needs to act as an SSH server, then +certain changes should be made to the OpenSSH daemon configuration +file /etc/ssh/sshd_config. The following recommendations can be +applied to this file. See the sshd_config(5) man page for more +detailed information. + + SSH RekeyLimit - size + Specify the size component of the rekey limit. + default + 512M + 512M + 1G + + + SSH RekeyLimit - size + Specify the size component of the rekey limit. + none + 1h + 1h + + + SSH Compression Setting + Specify the compression setting for SSH connections. + no + delayed + no + + + SSH Privilege Separation Setting + Specify whether and how sshd separates privileges when handling incoming network connections. + no + yes + sandbox + sandbox + + + SSH LoginGraceTime setting + Configure parameters for how long the servers stays connected before the user has successfully logged in + 60 + 60 + + + SSH MaxStartups setting + Configure parameters for maximum concurrent unauthenticated connections to the SSH daemon. + 10:30:100 + 10:30:60 + + + SSHD Must Include System Crypto Policy Config File + SSHD should follow the system cryptographic policy. +In order to accomplish this the SSHD configuration should include the configuration file provided by the system crypto policy. +The following line should be present in /etc/ssh/sshd_config or in a file included by this file (a file within the /etc/ssh/sshd_config.d directory): +Include /etc/crypto-policies/back-ends/opensshserver.config + + There is no automated remediation because recommended action could severely disrupt the system and might not be efficient in fixing the problem. + CCI-001453 + AC-17 (2) + SRG-OS-000250-GPOS-00093 + OL09-00-000252 + SV-271484r1092624_rule + Without cryptographic integrity protections, information can be altered by unauthorized users without detection. + + + + + + Set SSH Client Alive Count Max to zero + The SSH server sends at most ClientAliveCountMax messages +during a SSH session and waits for a response from the SSH client. +The option ClientAliveInterval configures timeout after +each ClientAliveCountMax message. If the SSH server does not +receive a response from the client, then the connection is considered unresponsive +and terminated. + +To ensure the SSH timeout occurs precisely when the +ClientAliveInterval is set, set the ClientAliveCountMax to +value of 0 in + + +/etc/ssh/sshd_config: + 1 + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + 7 + 8 + 5.5.6 + APO13.01 + BAI03.01 + BAI03.02 + BAI03.03 + DSS01.03 + DSS03.05 + DSS05.04 + DSS05.05 + DSS05.07 + DSS05.10 + DSS06.03 + DSS06.10 + 3.1.11 + CCI-000879 + CCI-001133 + CCI-002361 + 164.308(a)(4)(i) + 164.308(b)(1) + 164.308(b)(3) + 164.310(b) + 164.312(e)(1) + 164.312(e)(2)(ii) + 4.3.3.2.2 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.3 + SR 1.1 + SR 1.10 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 6.2 + A.12.4.1 + A.12.4.3 + A.14.1.1 + A.14.2.1 + A.14.2.5 + A.18.1.4 + A.6.1.2 + A.6.1.5 + A.7.1.1 + A.9.1.2 + A.9.2.1 + A.9.2.2 + A.9.2.3 + A.9.2.4 + A.9.2.6 + A.9.3.1 + A.9.4.1 + A.9.4.2 + A.9.4.3 + A.9.4.4 + A.9.4.5 + CIP-004-6 R2.2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.2 + CIP-007-3 R5.3.1 + CIP-007-3 R5.3.2 + CIP-007-3 R5.3.3 + AC-2(5) + AC-12 + AC-17(a) + SC-10 + CM-6(a) + DE.CM-1 + DE.CM-3 + PR.AC-1 + PR.AC-4 + PR.AC-6 + PR.AC-7 + PR.IP-2 + Req-8.1.8 + SRG-OS-000126-GPOS-00066 + SRG-OS-000163-GPOS-00072 + SRG-OS-000279-GPOS-00109 + This ensures a user login will be terminated as soon as the ClientAliveInterval +is reached. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Find the include keyword, extract from the line the glob expression representing included files. +# And if it is a relative path prepend '/etc/ssh/' +included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*include\s*//I' | sed -e 's|^[^/]|/etc/ssh/&|') +for included_file in ${included_files} ; do + + LC_ALL=C sed -i "/^\s*ClientAliveCountMax/Id" "$included_file" +done + +if [ -e "/etc/ssh/sshd_config" ] ; then + + LC_ALL=C sed -i "/^\s*ClientAliveCountMax\s\+/Id" "/etc/ssh/sshd_config" +else + touch "/etc/ssh/sshd_config" +fi +# make sure file has newline at the end +sed -i -e '$a\' "/etc/ssh/sshd_config" + +cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +# Insert at the beginning of the file +printf '%s\n' "ClientAliveCountMax 0" > "/etc/ssh/sshd_config" +cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +# Clean up after ourselves. +rm "/etc/ssh/sshd_config.bak" + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - CJIS-5.5.6 + - NIST-800-171-3.1.11 + - NIST-800-53-AC-12 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-2(5) + - NIST-800-53-CM-6(a) + - NIST-800-53-SC-10 + - PCI-DSS-Req-8.1.8 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_keepalive_0 + +- name: Find sshd_config included files + shell: |- + included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') + [[ -n $included_files ]] && ls $included_files || true + register: sshd_config_included_files + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.5.6 + - NIST-800-171-3.1.11 + - NIST-800-53-AC-12 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-2(5) + - NIST-800-53-CM-6(a) + - NIST-800-53-SC-10 + - PCI-DSS-Req-8.1.8 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_keepalive_0 + +- name: Comment conf from included files + replace: + path: '{{ item }}' + regexp: ^(\s*ClientAliveCountMax.*)$ + replace: '# \1' + loop: '{{ sshd_config_included_files.stdout_lines }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.5.6 + - NIST-800-171-3.1.11 + - NIST-800-53-AC-12 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-2(5) + - NIST-800-53-CM-6(a) + - NIST-800-53-SC-10 + - PCI-DSS-Req-8.1.8 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_keepalive_0 + +- name: Set SSH Client Alive Count Max to zero + block: + + - name: Check for duplicate values + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*ClientAliveCountMax\s+ + state: absent + check_mode: true + changed_when: false + register: dupes + + - name: Deduplicate values from /etc/ssh/sshd_config + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*ClientAliveCountMax\s+ + state: absent + when: dupes.found is defined and dupes.found > 1 + + - name: Insert correct line to /etc/ssh/sshd_config + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*ClientAliveCountMax\s+ + line: ClientAliveCountMax 0 + state: present + insertbefore: BOF + validate: /usr/sbin/sshd -t -f %s + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.5.6 + - NIST-800-171-3.1.11 + - NIST-800-53-AC-12 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-2(5) + - NIST-800-53-CM-6(a) + - NIST-800-53-SC-10 + - PCI-DSS-Req-8.1.8 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_keepalive_0 + + + + + + + + + + + Set SSH Client Alive Count Max + The SSH server sends at most ClientAliveCountMax messages +during a SSH session and waits for a response from the SSH client. +The option ClientAliveInterval configures timeout after +each ClientAliveCountMax message. If the SSH server does not +receive a response from the client, then the connection is considered unresponsive +and terminated. +For SSH earlier than v8.2, a ClientAliveCountMax value of 0 +causes a timeout precisely when the ClientAliveInterval is set. +Starting with v8.2, a value of 0 disables the timeout functionality +completely. If the option is set to a number greater than 0, then +the session will be disconnected after +ClientAliveInterval * ClientAliveCountMax seconds without receiving +a keep alive message. + 1 + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + 7 + 8 + 5.5.6 + APO13.01 + BAI03.01 + BAI03.02 + BAI03.03 + DSS01.03 + DSS03.05 + DSS05.04 + DSS05.05 + DSS05.07 + DSS05.10 + DSS06.03 + DSS06.10 + 3.1.11 + CCI-001133 + CCI-002361 + 164.308(a)(4)(i) + 164.308(b)(1) + 164.308(b)(3) + 164.310(b) + 164.312(e)(1) + 164.312(e)(2)(ii) + 4.3.3.2.2 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.3 + SR 1.1 + SR 1.10 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 6.2 + A.12.4.1 + A.12.4.3 + A.14.1.1 + A.14.2.1 + A.14.2.5 + A.18.1.4 + A.6.1.2 + A.6.1.5 + A.7.1.1 + A.9.1.2 + A.9.2.1 + A.9.2.2 + A.9.2.3 + A.9.2.4 + A.9.2.6 + A.9.3.1 + A.9.4.1 + A.9.4.2 + A.9.4.3 + A.9.4.4 + A.9.4.5 + CIP-004-6 R2.2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.2 + CIP-007-3 R5.3.1 + CIP-007-3 R5.3.2 + CIP-007-3 R5.3.3 + AC-2(5) + AC-12 + AC-17(a) + SC-10 + CM-6(a) + DE.CM-1 + DE.CM-3 + PR.AC-1 + PR.AC-4 + PR.AC-6 + PR.AC-7 + PR.IP-2 + Req-8.1.8 + SRG-OS-000163-GPOS-00072 + SRG-OS-000279-GPOS-00109 + A.5.SEC-OL7 + 8.2.8 + 8.2 + OL09-00-002346 + SV-271709r1091839_rule + This ensures a user login will be terminated as soon as the ClientAliveInterval +is reached. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +var_sshd_set_keepalive='' + + + +# Find the include keyword, extract from the line the glob expression representing included files. +# And if it is a relative path prepend '/etc/ssh/' +included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*include\s*//I' | sed -e 's|^[^/]|/etc/ssh/&|') +for included_file in ${included_files} ; do + + LC_ALL=C sed -i "/^\s*ClientAliveCountMax/Id" "$included_file" +done + +if [ -e "/etc/ssh/sshd_config" ] ; then + + LC_ALL=C sed -i "/^\s*ClientAliveCountMax\s\+/Id" "/etc/ssh/sshd_config" +else + touch "/etc/ssh/sshd_config" +fi +# make sure file has newline at the end +sed -i -e '$a\' "/etc/ssh/sshd_config" + +cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +# Insert at the beginning of the file +printf '%s\n' "ClientAliveCountMax $var_sshd_set_keepalive" > "/etc/ssh/sshd_config" +cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +# Clean up after ourselves. +rm "/etc/ssh/sshd_config.bak" + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - CJIS-5.5.6 + - DISA-STIG-OL09-00-002346 + - NIST-800-171-3.1.11 + - NIST-800-53-AC-12 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-2(5) + - NIST-800-53-CM-6(a) + - NIST-800-53-SC-10 + - PCI-DSS-Req-8.1.8 + - PCI-DSSv4-8.2 + - PCI-DSSv4-8.2.8 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_keepalive +- name: XCCDF Value var_sshd_set_keepalive # promote to variable + set_fact: + var_sshd_set_keepalive: !!str + tags: + - always + +- name: Find sshd_config included files + shell: |- + included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') + [[ -n $included_files ]] && ls $included_files || true + register: sshd_config_included_files + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.5.6 + - DISA-STIG-OL09-00-002346 + - NIST-800-171-3.1.11 + - NIST-800-53-AC-12 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-2(5) + - NIST-800-53-CM-6(a) + - NIST-800-53-SC-10 + - PCI-DSS-Req-8.1.8 + - PCI-DSSv4-8.2 + - PCI-DSSv4-8.2.8 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_keepalive + +- name: Comment conf from included files + replace: + path: '{{ item }}' + regexp: ^(\s*ClientAliveCountMax.*)$ + replace: '# \1' + loop: '{{ sshd_config_included_files.stdout_lines }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.5.6 + - DISA-STIG-OL09-00-002346 + - NIST-800-171-3.1.11 + - NIST-800-53-AC-12 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-2(5) + - NIST-800-53-CM-6(a) + - NIST-800-53-SC-10 + - PCI-DSS-Req-8.1.8 + - PCI-DSSv4-8.2 + - PCI-DSSv4-8.2.8 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_keepalive + +- name: Set SSH Client Alive Count Max + block: + + - name: Check for duplicate values + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*ClientAliveCountMax\s+ + state: absent + check_mode: true + changed_when: false + register: dupes + + - name: Deduplicate values from /etc/ssh/sshd_config + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*ClientAliveCountMax\s+ + state: absent + when: dupes.found is defined and dupes.found > 1 + + - name: Insert correct line to /etc/ssh/sshd_config + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*ClientAliveCountMax\s+ + line: ClientAliveCountMax {{ var_sshd_set_keepalive }} + state: present + insertbefore: BOF + validate: /usr/sbin/sshd -t -f %s + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.5.6 + - DISA-STIG-OL09-00-002346 + - NIST-800-171-3.1.11 + - NIST-800-53-AC-12 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-2(5) + - NIST-800-53-CM-6(a) + - NIST-800-53-SC-10 + - PCI-DSS-Req-8.1.8 + - PCI-DSSv4-8.2 + - PCI-DSSv4-8.2.8 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_keepalive + + + + + + + + + + + + Set SSH Client Alive Interval + SSH allows administrators to set a network responsiveness timeout interval. +After this interval has passed, the unresponsive client will be automatically logged out. + + +To set this timeout interval, edit the following line in /etc/ssh/sshd_config as +follows: +ClientAliveInterval + + + +The timeout interval is given in seconds. For example, have a timeout +of 10 minutes, set interval to 600. + + +If a shorter timeout has already been set for the login shell, that value will +preempt any SSH setting made in /etc/ssh/sshd_config. Keep in mind that +some processes may stop SSH from correctly detecting that the user is idle. + SSH disconnecting unresponsive clients will not have desired effect without also +configuring ClientAliveCountMax in the SSH service configuration. + Following conditions may prevent the SSH session to time out: +Remote processes on the remote machine generates output. As the output has to be transferred over the network to the client, the timeout is reset every time such transfer happens.Any scp or sftp activity by the same user to the host resets the timeout. + + 1 + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + 7 + 8 + 5.5.6 + APO13.01 + BAI03.01 + BAI03.02 + BAI03.03 + DSS01.03 + DSS03.05 + DSS05.04 + DSS05.05 + DSS05.07 + DSS05.10 + DSS06.03 + DSS06.10 + 3.1.11 + CCI-001133 + CCI-002361 + CCI-002891 + 4.3.3.2.2 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.3 + SR 1.1 + SR 1.10 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 6.2 + A.12.4.1 + A.12.4.3 + A.14.1.1 + A.14.2.1 + A.14.2.5 + A.18.1.4 + A.6.1.2 + A.6.1.5 + A.7.1.1 + A.9.1.2 + A.9.2.1 + A.9.2.2 + A.9.2.3 + A.9.2.4 + A.9.2.6 + A.9.3.1 + A.9.4.1 + A.9.4.2 + A.9.4.3 + A.9.4.4 + A.9.4.5 + CIP-004-6 R2.2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.2 + CIP-007-3 R5.3.1 + CIP-007-3 R5.3.2 + CIP-007-3 R5.3.3 + CM-6(a) + AC-17(a) + AC-2(5) + AC-12 + AC-17(a) + SC-10 + CM-6(a) + DE.CM-1 + DE.CM-3 + PR.AC-1 + PR.AC-4 + PR.AC-6 + PR.AC-7 + PR.IP-2 + Req-8.1.8 + SRG-OS-000126-GPOS-00066 + SRG-OS-000163-GPOS-00072 + SRG-OS-000279-GPOS-00109 + SRG-OS-000395-GPOS-00175 + A.5.SEC-OL7 + 8.2.8 + 8.2 + OL09-00-002347 + SV-271710r1092596_rule + Terminating an idle ssh session within a short time period reduces the window of +opportunity for unauthorized personnel to take control of a management session +enabled on the console or console port that has been let unattended. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +sshd_idle_timeout_value='' + + + +# Find the include keyword, extract from the line the glob expression representing included files. +# And if it is a relative path prepend '/etc/ssh/' +included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*include\s*//I' | sed -e 's|^[^/]|/etc/ssh/&|') +for included_file in ${included_files} ; do + + LC_ALL=C sed -i "/^\s*ClientAliveInterval/Id" "$included_file" +done + +if [ -e "/etc/ssh/sshd_config" ] ; then + + LC_ALL=C sed -i "/^\s*ClientAliveInterval\s\+/Id" "/etc/ssh/sshd_config" +else + touch "/etc/ssh/sshd_config" +fi +# make sure file has newline at the end +sed -i -e '$a\' "/etc/ssh/sshd_config" + +cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +# Insert at the beginning of the file +printf '%s\n' "ClientAliveInterval $sshd_idle_timeout_value" > "/etc/ssh/sshd_config" +cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +# Clean up after ourselves. +rm "/etc/ssh/sshd_config.bak" + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - CJIS-5.5.6 + - DISA-STIG-OL09-00-002347 + - NIST-800-171-3.1.11 + - NIST-800-53-AC-12 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-2(5) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-SC-10 + - PCI-DSS-Req-8.1.8 + - PCI-DSSv4-8.2 + - PCI-DSSv4-8.2.8 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_idle_timeout +- name: XCCDF Value sshd_idle_timeout_value # promote to variable + set_fact: + sshd_idle_timeout_value: !!str + tags: + - always + +- name: Find sshd_config included files + shell: |- + included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') + [[ -n $included_files ]] && ls $included_files || true + register: sshd_config_included_files + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.5.6 + - DISA-STIG-OL09-00-002347 + - NIST-800-171-3.1.11 + - NIST-800-53-AC-12 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-2(5) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-SC-10 + - PCI-DSS-Req-8.1.8 + - PCI-DSSv4-8.2 + - PCI-DSSv4-8.2.8 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_idle_timeout + +- name: Comment conf from included files + replace: + path: '{{ item }}' + regexp: ^(\s*ClientAliveInterval.*)$ + replace: '# \1' + loop: '{{ sshd_config_included_files.stdout_lines }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.5.6 + - DISA-STIG-OL09-00-002347 + - NIST-800-171-3.1.11 + - NIST-800-53-AC-12 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-2(5) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-SC-10 + - PCI-DSS-Req-8.1.8 + - PCI-DSSv4-8.2 + - PCI-DSSv4-8.2.8 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_idle_timeout + +- name: Set SSH Client Alive Interval + block: + + - name: Check for duplicate values + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*ClientAliveInterval\s+ + state: absent + check_mode: true + changed_when: false + register: dupes + + - name: Deduplicate values from /etc/ssh/sshd_config + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*ClientAliveInterval\s+ + state: absent + when: dupes.found is defined and dupes.found > 1 + + - name: Insert correct line to /etc/ssh/sshd_config + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*ClientAliveInterval\s+ + line: ClientAliveInterval {{ sshd_idle_timeout_value }} + state: present + insertbefore: BOF + validate: /usr/sbin/sshd -t -f %s + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.5.6 + - DISA-STIG-OL09-00-002347 + - NIST-800-171-3.1.11 + - NIST-800-53-AC-12 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-2(5) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-SC-10 + - PCI-DSS-Req-8.1.8 + - PCI-DSSv4-8.2 + - PCI-DSSv4-8.2.8 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_idle_timeout + + + + + + + + + + + + Disable Host-Based Authentication + SSH's cryptographic host-based authentication is +more secure than .rhosts authentication. However, it is +not recommended that hosts unilaterally trust one another, even +within an organization. + +The default SSH configuration disables host-based authentication. The appropriate +configuration is used if no value is set for HostbasedAuthentication. + +To explicitly disable host-based authentication, add or correct the +following line in + + +/etc/ssh/sshd_config: + +HostbasedAuthentication no + + 11 + 12 + 14 + 15 + 16 + 18 + 3 + 5 + 9 + 5.5.6 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS05.02 + DSS05.04 + DSS05.05 + DSS05.07 + DSS06.03 + DSS06.06 + 3.1.12 + CCI-000366 + 164.308(a)(4)(i) + 164.308(b)(1) + 164.308(b)(3) + 164.310(b) + 164.312(e)(1) + 164.312(e)(2)(ii) + 4.3.3.2.2 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.2 + 4.3.4.3.3 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 7.6 + 0421 + 0422 + 0431 + 0974 + 1173 + 1401 + 1504 + 1505 + 1546 + 1557 + 1558 + 1559 + 1560 + 1561 + A.12.1.2 + A.12.5.1 + A.12.6.2 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.6.1.2 + A.7.1.1 + A.9.1.2 + A.9.2.1 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.2.3 + CIP-004-6 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.2 + CIP-007-3 R5.2 + CIP-007-3 R5.3.1 + CIP-007-3 R5.3.2 + CIP-007-3 R5.3.3 + AC-3 + AC-17(a) + CM-7(a) + CM-7(b) + CM-6(a) + PR.AC-4 + PR.AC-6 + PR.IP-1 + PR.PT-3 + FIA_UAU.1 + SRG-OS-000480-GPOS-00229 + 8.3.1 + 8.3 + OL09-00-002357 + SV-271719r1091869_rule + SSH trust relationships mean a compromise on one host +can allow an attacker to move trivially to other hosts. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Find the include keyword, extract from the line the glob expression representing included files. +# And if it is a relative path prepend '/etc/ssh/' +included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*include\s*//I' | sed -e 's|^[^/]|/etc/ssh/&|') +for included_file in ${included_files} ; do + + LC_ALL=C sed -i "/^\s*HostbasedAuthentication/Id" "$included_file" +done + +if [ -e "/etc/ssh/sshd_config" ] ; then + + LC_ALL=C sed -i "/^\s*HostbasedAuthentication\s\+/Id" "/etc/ssh/sshd_config" +else + touch "/etc/ssh/sshd_config" +fi +# make sure file has newline at the end +sed -i -e '$a\' "/etc/ssh/sshd_config" + +cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +# Insert at the beginning of the file +printf '%s\n' "HostbasedAuthentication no" > "/etc/ssh/sshd_config" +cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +# Clean up after ourselves. +rm "/etc/ssh/sshd_config.bak" + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - CJIS-5.5.6 + - DISA-STIG-OL09-00-002357 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-3 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - PCI-DSSv4-8.3 + - PCI-DSSv4-8.3.1 + - disable_host_auth + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Find sshd_config included files + shell: |- + included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') + [[ -n $included_files ]] && ls $included_files || true + register: sshd_config_included_files + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.5.6 + - DISA-STIG-OL09-00-002357 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-3 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - PCI-DSSv4-8.3 + - PCI-DSSv4-8.3.1 + - disable_host_auth + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Comment conf from included files + replace: + path: '{{ item }}' + regexp: ^(\s*HostbasedAuthentication.*)$ + replace: '# \1' + loop: '{{ sshd_config_included_files.stdout_lines }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.5.6 + - DISA-STIG-OL09-00-002357 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-3 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - PCI-DSSv4-8.3 + - PCI-DSSv4-8.3.1 + - disable_host_auth + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Disable Host-Based Authentication + block: + + - name: Check for duplicate values + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*HostbasedAuthentication\s+ + state: absent + check_mode: true + changed_when: false + register: dupes + + - name: Deduplicate values from /etc/ssh/sshd_config + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*HostbasedAuthentication\s+ + state: absent + when: dupes.found is defined and dupes.found > 1 + + - name: Insert correct line to /etc/ssh/sshd_config + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*HostbasedAuthentication\s+ + line: HostbasedAuthentication no + state: present + insertbefore: BOF + validate: /usr/sbin/sshd -t -f %s + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.5.6 + - DISA-STIG-OL09-00-002357 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-3 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - PCI-DSSv4-8.3 + - PCI-DSSv4-8.3.1 + - disable_host_auth + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + + + + + + + + + + + Enable SSH Server firewalld Firewall Exception + If the SSH server is in use, inbound connections to SSH's port should be allowed to permit +remote access through SSH. In more restrictive firewalld settings, the SSH port should be +added to the proper firewalld zone in order to allow SSH remote access. + + + +To configure firewalld to allow ssh access, run the following command(s): +firewall-cmd --permanent --add-service=ssh +Then run the following command to load the newly created rule(s): +firewall-cmd --reload + + The remediation for this rule uses firewall-cmd and nmcli tools. +Therefore, it will only be executed if firewalld and NetworkManager +services are running. Otherwise, the remediation will be aborted and a informative message +will be shown in the remediation report. +These respective services will not be started in order to preserve any intentional change +in network components related to firewall and network interfaces. + This rule also checks if the SSH port was modified by the administrator in the firewalld +services definitions and is reflecting the expected port number. Although this is checked, +fixing the custom ssh.xml file placed by the administrator at /etc/firewalld/services it +is not in the scope of the remediation since there is no reliable way to manually change +the respective file. If the default SSH port is modified, it is on the administrator +responsibility to ensure the firewalld customizations in the service port level are +properly configured. + Oracle Linux 9 prefers and recommends to use NetworkManager keyfiles instead of the +ifcfg files stored in /etc/sysconfig/network-scripts. Therefore, if the +system was upgraded from a previous release, make sure the NIC configuration files are +properly migrated from ifcfg format to NetworkManager keyfiles. Otherwise, this +rule won't be able to check the configuration. The migration can be accomplished by +nmcli connection migrate command. + 3.1.12 + CCI-000382 + 1416 + AC-17(a) + CM-6(b) + CM-7(a) + CM-7(b) + SRG-OS-000096-GPOS-00050 + OL09-00-000222 + SV-271471r1091125_rule + If inbound SSH connections are expected, adding the SSH port to the proper firewalld zone +will allow remote access through the SSH port. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +if ! rpm -q --quiet "firewalld" ; then + yum install -y "firewalld" +fi +if ! rpm -q --quiet "NetworkManager" ; then + yum install -y "NetworkManager" +fi +firewalld_sshd_zone='' + + +if [[ "$OSCAP_BOOTC_BUILD" == "YES" ]]; then + # By default, NetworkManager interfaces are created only once + # container image is booted so we do not have information about + # what interfaces will be created during container build time. + # Therefore, we will rely on NetworkManager to automatically assign + # interfaces to the default firewalld zone. For more details see: + # https://firewalld.org/documentation/man-pages/firewalld.zone.html + # https://firewalld.org/documentation/zone/connections-interfaces-and-sources.html + # That also means this remediation only works if zone defined in + # the firewalld_sshd_zone variable equals to the default zone of firewalld. + default_zone=$(firewall-offline-cmd --get-default-zone) + if [ "$firewalld_sshd_zone" != "$default_zone" ]; then + echo "Firewalld default zone ($default_zone) and pre-set zone for sshd ($firewalld_sshd_zone) differ. Remediation aborted!" >&2 + exit 1 + fi + + # Make sure default zone is set in all existing NetworkManager keyfiles. + while IFS= read -r -d '' file; do + sed "s|^\s*zone=.*$|zone=$firewalld_sshd_zone|g" "$file" + done < <(find /etc/NetworkManager/system-connections -maxdepth 1 -name "*.nmconnection" -print0) + + firewall-offline-cmd --zone="$firewalld_sshd_zone" --add-service=ssh +else + if test "$(stat -c %d:%i /)" != "$(stat -c %d:%i /proc/1/root/.)"; then + # TODO: NM (nmcli) now has --offline mode support, and it could operate without NM service. + # See: https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/1183 + # The feature is not quite straighforward (and probably incomplete), though. + echo "Not applicable in offline mode. Remediation aborted!" + else + if systemctl is-active NetworkManager && systemctl is-active firewalld; then + # First make sure the SSH service is enabled in run-time for the proper zone. + # This is to avoid connection issues when new interfaces are addeded to this zone. + firewall-cmd --zone="$firewalld_sshd_zone" --add-service=ssh + + # This will collect all NetworkManager connections names + readarray -t nm_connections < <(nmcli -g UUID,TYPE con | grep -v loopback | awk -F ':' '{ print $1 }') + # If the connection is not yet assigned to a firewalld zone, assign it to the proper zone. + # This will not change connections which are already assigned to any firewalld zone. + for connection in "${nm_connections[@]}"; do + current_zone=$(nmcli -f connection.zone connection show "$connection" | awk '{ print $2}') + if [ $current_zone = "--" ]; then + nmcli connection modify "$connection" connection.zone $firewalld_sshd_zone + fi + done + systemctl restart NetworkManager + + # Active zones are zones with at least one interface assigned to it. + # It is possible that traffic is coming by any active interface and consequently any + # active zone. So, this make sure all active zones are permanently allowing SSH service. + readarray -t firewalld_active_zones < <(firewall-cmd --get-active-zones | grep -v "^ " | cut -d " " -f 1) + for zone in "${firewalld_active_zones[@]}"; do + firewall-cmd --permanent --zone="$zone" --add-service=ssh + done + firewall-cmd --reload + else + echo "The firewalld or NetworkManager service is not active. Remediation aborted!" + fi + fi +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-000222 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(b) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - configure_strategy + - firewalld_sshd_port_enabled + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed +- name: XCCDF Value firewalld_sshd_zone # promote to variable + set_fact: + firewalld_sshd_zone: !!str + tags: + - always + +- name: Enable SSH Server firewalld Firewall Exception - Ensure firewalld and NetworkManager + packages are installed + ansible.builtin.package: + name: '{{ item }}' + state: present + with_items: + - firewalld + - NetworkManager + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-000222 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(b) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - configure_strategy + - firewalld_sshd_port_enabled + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Enable SSH Server firewalld Firewall Exception - Collect facts about system + services + ansible.builtin.service_facts: null + register: result_services_states + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-000222 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(b) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - configure_strategy + - firewalld_sshd_port_enabled + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Enable SSH Server firewalld Firewall Exception - Remediation is applicable + if firewalld and NetworkManager services are running + block: + + - name: Enable SSH Server firewalld Firewall Exception - Collect NetworkManager + connections names + ansible.builtin.shell: + cmd: nmcli -g UUID,TYPE con | grep -v loopback | awk -F ':' '{ print $1 }' + register: result_nmcli_cmd_connections_names + changed_when: false + + - name: Enable SSH Server firewalld Firewall Exception - Collect NetworkManager + connections zones + ansible.builtin.shell: + cmd: nmcli -f connection.zone connection show {{ item | trim }} | awk '{ print + $2}' + register: result_nmcli_cmd_connections_zones + changed_when: false + with_items: + - '{{ result_nmcli_cmd_connections_names.stdout_lines }}' + + - name: Enable SSH Server firewalld Firewall Exception - Ensure NetworkManager connections + are assigned to a firewalld zone + ansible.builtin.command: + cmd: nmcli connection modify {{ item.0 }} connection.zone {{ firewalld_sshd_zone + }} + register: result_nmcli_cmd_connections_assignment + with_together: + - '{{ result_nmcli_cmd_connections_names.stdout_lines }}' + - '{{ result_nmcli_cmd_connections_zones.results }}' + when: + - item.1.stdout == '--' + + - name: Enable SSH Server firewalld Firewall Exception - Ensure NetworkManager connections + changes are applied + ansible.builtin.service: + name: NetworkManager + state: restarted + when: + - result_nmcli_cmd_connections_assignment is changed + + - name: Enable SSH Server firewalld Firewall Exception - Collect firewalld active + zones + ansible.builtin.shell: + cmd: firewall-cmd --get-active-zones | grep -v "^ " | cut -d " " -f 1 + register: result_firewall_cmd_zones_names + changed_when: false + + - name: Enable SSH Server firewalld Firewall Exception - Ensure firewalld zones + allow SSH + ansible.builtin.command: + cmd: firewall-cmd --permanent --zone={{ item }} --add-service=ssh + register: result_nmcli_cmd_connections_assignment + changed_when: + - '''ALREADY_ENABLED'' not in result_nmcli_cmd_connections_assignment.stderr' + with_items: + - '{{ result_firewall_cmd_zones_names.stdout_lines }}' + + - name: Enable SSH Server firewalld Firewall Exception - Ensure firewalld changes + are applied + ansible.builtin.service: + name: firewalld + state: reloaded + when: + - result_nmcli_cmd_connections_assignment is changed + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - ansible_facts.services['firewalld.service'].state == 'running' + - ansible_facts.services['NetworkManager.service'].state == 'running' + tags: + - DISA-STIG-OL09-00-000222 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(b) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - configure_strategy + - firewalld_sshd_port_enabled + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Enable SSH Server firewalld Firewall Exception - Informative message based + on services states + ansible.builtin.assert: + that: + - ansible_facts.services['firewalld.service'].state == 'running' + - ansible_facts.services['NetworkManager.service'].state == 'running' + fail_msg: + - firewalld and NetworkManager services are not active. Remediation aborted! + - This remediation could not be applied because it depends on firewalld and NetworkManager + services running. + - The service is not started by this remediation in order to prevent connection + issues. + success_msg: + - Enable SSH Server firewalld Firewall Exception remediation successfully executed + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-000222 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(b) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - configure_strategy + - firewalld_sshd_port_enabled + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + + Allow Only SSH Protocol 2 + Only SSH protocol version 2 connections should be +permitted. The default setting in +/etc/ssh/sshd_config is correct, and can be +verified by ensuring that the following +line appears: +Protocol 2 + + As of openssh-server version 7.4 and above, the only protocol +supported is version 2, and line Protocol 2 in +/etc/ssh/sshd_config is not necessary. + 1 + 12 + 15 + 16 + 5 + 8 + 5.5.6 + APO13.01 + DSS01.04 + DSS05.02 + DSS05.03 + DSS05.04 + DSS05.05 + DSS05.07 + DSS05.10 + DSS06.03 + DSS06.10 + 3.1.13 + 3.5.4 + CCI-000197 + CCI-000366 + 164.308(a)(4)(i) + 164.308(b)(1) + 164.308(b)(3) + 164.310(b) + 164.312(e)(1) + 164.312(e)(2)(ii) + 4.3.3.2.2 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.2 + 4.3.3.7.4 + SR 1.1 + SR 1.10 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.6 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 7.1 + SR 7.6 + 0487 + 1449 + 1506 + A.11.2.6 + A.13.1.1 + A.13.2.1 + A.14.1.3 + A.18.1.4 + A.6.2.1 + A.6.2.2 + A.7.1.1 + A.9.2.1 + A.9.2.2 + A.9.2.3 + A.9.2.4 + A.9.2.6 + A.9.3.1 + A.9.4.2 + A.9.4.3 + CIP-003-8 R4.2 + CIP-007-3 R5.1 + CIP-007-3 R7.1 + CM-6(a) + AC-17(a) + AC-17(2) + IA-5(1)(c) + SC-13 + MA-4(6) + PR.AC-1 + PR.AC-3 + PR.AC-6 + PR.AC-7 + PR.PT-4 + SRG-OS-000074-GPOS-00042 + SRG-OS-000480-GPOS-00227 + SSH protocol version 1 is an insecure implementation of the SSH protocol and +has many well-known vulnerability exploits. Exploits of the SSH daemon could provide +immediate root access to the system. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Find the include keyword, extract from the line the glob expression representing included files. +# And if it is a relative path prepend '/etc/ssh/' +included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*include\s*//I' | sed -e 's|^[^/]|/etc/ssh/&|') +for included_file in ${included_files} ; do + + LC_ALL=C sed -i "/^\s*Protocol/Id" "$included_file" +done + +if [ -e "/etc/ssh/sshd_config" ] ; then + + LC_ALL=C sed -i "/^\s*Protocol\s\+/Id" "/etc/ssh/sshd_config" +else + touch "/etc/ssh/sshd_config" +fi +# make sure file has newline at the end +sed -i -e '$a\' "/etc/ssh/sshd_config" + +cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +# Insert at the beginning of the file +printf '%s\n' "Protocol 2" > "/etc/ssh/sshd_config" +cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +# Clean up after ourselves. +rm "/etc/ssh/sshd_config.bak" + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - CJIS-5.5.6 + - NIST-800-171-3.1.13 + - NIST-800-171-3.5.4 + - NIST-800-53-AC-17(2) + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(c) + - NIST-800-53-MA-4(6) + - NIST-800-53-SC-13 + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - restrict_strategy + - sshd_allow_only_protocol2 + +- name: Find sshd_config included files + shell: |- + included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') + [[ -n $included_files ]] && ls $included_files || true + register: sshd_config_included_files + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.5.6 + - NIST-800-171-3.1.13 + - NIST-800-171-3.5.4 + - NIST-800-53-AC-17(2) + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(c) + - NIST-800-53-MA-4(6) + - NIST-800-53-SC-13 + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - restrict_strategy + - sshd_allow_only_protocol2 + +- name: Comment conf from included files + replace: + path: '{{ item }}' + regexp: ^(\s*Protocol.*)$ + replace: '# \1' + loop: '{{ sshd_config_included_files.stdout_lines }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.5.6 + - NIST-800-171-3.1.13 + - NIST-800-171-3.5.4 + - NIST-800-53-AC-17(2) + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(c) + - NIST-800-53-MA-4(6) + - NIST-800-53-SC-13 + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - restrict_strategy + - sshd_allow_only_protocol2 + +- name: Allow Only SSH Protocol 2 + block: + + - name: Check for duplicate values + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*Protocol\s+ + state: absent + check_mode: true + changed_when: false + register: dupes + + - name: Deduplicate values from /etc/ssh/sshd_config + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*Protocol\s+ + state: absent + when: dupes.found is defined and dupes.found > 1 + + - name: Insert correct line to /etc/ssh/sshd_config + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*Protocol\s+ + line: Protocol 2 + state: present + insertbefore: BOF + validate: /usr/sbin/sshd -t -f %s + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.5.6 + - NIST-800-171-3.1.13 + - NIST-800-171-3.5.4 + - NIST-800-53-AC-17(2) + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(c) + - NIST-800-53-MA-4(6) + - NIST-800-53-SC-13 + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - restrict_strategy + - sshd_allow_only_protocol2 + + + + + + + + + + + Disable Compression Or Set Compression to delayed + Compression is useful for slow network connections over long +distances but can cause performance issues on local LANs. If use of compression +is required, it should be enabled only after a user has authenticated; otherwise, +it should be disabled. To disable compression or delay compression until after +a user has successfully authenticated, add or correct the following line in the +/etc/ssh/sshd_config file: +Compression + + + 11 + 3 + 9 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + 3.1.12 + CCI-000366 + 164.308(a)(4)(i) + 164.308(b)(1) + 164.308(b)(3) + 164.310(b) + 164.312(e)(1) + 164.312(e)(2)(ii) + 4.3.4.3.2 + 4.3.4.3.3 + SR 7.6 + A.12.1.2 + A.12.5.1 + A.12.6.2 + A.14.2.2 + A.14.2.3 + A.14.2.4 + AC-17(a) + CM-7(a) + CM-7(b) + CM-6(a) + PR.IP-1 + SRG-OS-000480-GPOS-00227 + OL09-00-002355 + SV-271717r1091863_rule + If compression is allowed in an SSH connection prior to authentication, +vulnerabilities in the compression software could result in compromise of the +system from an unauthenticated connection, potentially with root privileges. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +var_sshd_disable_compression='' + + + +# Find the include keyword, extract from the line the glob expression representing included files. +# And if it is a relative path prepend '/etc/ssh/' +included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*include\s*//I' | sed -e 's|^[^/]|/etc/ssh/&|') +for included_file in ${included_files} ; do + + LC_ALL=C sed -i "/^\s*Compression/Id" "$included_file" +done + +if [ -e "/etc/ssh/sshd_config" ] ; then + + LC_ALL=C sed -i "/^\s*Compression\s\+/Id" "/etc/ssh/sshd_config" +else + touch "/etc/ssh/sshd_config" +fi +# make sure file has newline at the end +sed -i -e '$a\' "/etc/ssh/sshd_config" + +cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +# Insert at the beginning of the file +printf '%s\n' "Compression $var_sshd_disable_compression" > "/etc/ssh/sshd_config" +cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +# Clean up after ourselves. +rm "/etc/ssh/sshd_config.bak" + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002355 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_compression +- name: XCCDF Value var_sshd_disable_compression # promote to variable + set_fact: + var_sshd_disable_compression: !!str + tags: + - always + +- name: Find sshd_config included files + shell: |- + included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') + [[ -n $included_files ]] && ls $included_files || true + register: sshd_config_included_files + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002355 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_compression + +- name: Comment conf from included files + replace: + path: '{{ item }}' + regexp: ^(\s*Compression.*)$ + replace: '# \1' + loop: '{{ sshd_config_included_files.stdout_lines }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002355 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_compression + +- name: Disable Compression Or Set Compression to delayed + block: + + - name: Check for duplicate values + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*Compression\s+ + state: absent + check_mode: true + changed_when: false + register: dupes + + - name: Deduplicate values from /etc/ssh/sshd_config + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*Compression\s+ + state: absent + when: dupes.found is defined and dupes.found > 1 + + - name: Insert correct line to /etc/ssh/sshd_config + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*Compression\s+ + line: Compression {{ var_sshd_disable_compression }} + state: present + insertbefore: BOF + validate: /usr/sbin/sshd -t -f %s + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002355 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_compression + + + + + + + + + + + + Disable SSH Access via Empty Passwords + Disallow SSH login with empty passwords. +The default SSH configuration disables logins with empty passwords. The appropriate +configuration is used if no value is set for PermitEmptyPasswords. + +To explicitly disallow SSH login from accounts with empty passwords, +add or correct the following line in + + +/etc/ssh/sshd_config: + + + PermitEmptyPasswords no +Any accounts with empty passwords should be disabled immediately, and PAM configuration +should prevent users from being able to assign themselves empty passwords. + 11 + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + 9 + 5.5.6 + APO01.06 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS05.02 + DSS05.04 + DSS05.05 + DSS05.07 + DSS06.02 + DSS06.03 + DSS06.06 + 3.1.1 + 3.1.5 + CCI-000766 + CCI-000366 + 164.308(a)(4)(i) + 164.308(b)(1) + 164.308(b)(3) + 164.310(b) + 164.312(e)(1) + 164.312(e)(2)(ii) + 4.3.3.2.2 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.2 + 4.3.4.3.3 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 5.2 + SR 7.6 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.12.1.2 + A.12.5.1 + A.12.6.2 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.1 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + AC-17(a) + CM-7(a) + CM-7(b) + CM-6(a) + PR.AC-4 + PR.AC-6 + PR.DS-5 + PR.IP-1 + PR.PT-3 + FIA_UAU.1 + Req-2.2.4 + SRG-OS-000106-GPOS-00053 + SRG-OS-000480-GPOS-00229 + SRG-OS-000480-GPOS-00227 + 2.2.6 + 2.2 + OL09-00-002343 + SV-271706r1091830_rule + Configuring this setting for the SSH daemon provides additional assurance +that remote login via SSH will require a password, even in the event of +misconfiguration elsewhere. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Find the include keyword, extract from the line the glob expression representing included files. +# And if it is a relative path prepend '/etc/ssh/' +included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*include\s*//I' | sed -e 's|^[^/]|/etc/ssh/&|') +for included_file in ${included_files} ; do + + LC_ALL=C sed -i "/^\s*PermitEmptyPasswords/Id" "$included_file" +done + +if [ -e "/etc/ssh/sshd_config" ] ; then + + LC_ALL=C sed -i "/^\s*PermitEmptyPasswords\s\+/Id" "/etc/ssh/sshd_config" +else + touch "/etc/ssh/sshd_config" +fi +# make sure file has newline at the end +sed -i -e '$a\' "/etc/ssh/sshd_config" + +cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +# Insert at the beginning of the file +printf '%s\n' "PermitEmptyPasswords no" > "/etc/ssh/sshd_config" +cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +# Clean up after ourselves. +rm "/etc/ssh/sshd_config.bak" + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - CJIS-5.5.6 + - DISA-STIG-OL09-00-002343 + - NIST-800-171-3.1.1 + - NIST-800-171-3.1.5 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - PCI-DSS-Req-2.2.4 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - restrict_strategy + - sshd_disable_empty_passwords + +- name: Find sshd_config included files + shell: |- + included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') + [[ -n $included_files ]] && ls $included_files || true + register: sshd_config_included_files + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.5.6 + - DISA-STIG-OL09-00-002343 + - NIST-800-171-3.1.1 + - NIST-800-171-3.1.5 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - PCI-DSS-Req-2.2.4 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - restrict_strategy + - sshd_disable_empty_passwords + +- name: Comment conf from included files + replace: + path: '{{ item }}' + regexp: ^(\s*PermitEmptyPasswords.*)$ + replace: '# \1' + loop: '{{ sshd_config_included_files.stdout_lines }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.5.6 + - DISA-STIG-OL09-00-002343 + - NIST-800-171-3.1.1 + - NIST-800-171-3.1.5 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - PCI-DSS-Req-2.2.4 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - restrict_strategy + - sshd_disable_empty_passwords + +- name: Disable SSH Access via Empty Passwords + block: + + - name: Check for duplicate values + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*PermitEmptyPasswords\s+ + state: absent + check_mode: true + changed_when: false + register: dupes + + - name: Deduplicate values from /etc/ssh/sshd_config + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*PermitEmptyPasswords\s+ + state: absent + when: dupes.found is defined and dupes.found > 1 + + - name: Insert correct line to /etc/ssh/sshd_config + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*PermitEmptyPasswords\s+ + line: PermitEmptyPasswords no + state: present + insertbefore: BOF + validate: /usr/sbin/sshd -t -f %s + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.5.6 + - DISA-STIG-OL09-00-002343 + - NIST-800-171-3.1.1 + - NIST-800-171-3.1.5 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - PCI-DSS-Req-2.2.4 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - restrict_strategy + - sshd_disable_empty_passwords + + + + + + + + + + + Disable GSSAPI Authentication + Unless needed, SSH should not permit extraneous or unnecessary +authentication mechanisms like GSSAPI. + +The default SSH configuration disallows authentications based on GSSAPI. The appropriate +configuration is used if no value is set for GSSAPIAuthentication. + +To explicitly disable GSSAPI authentication, add or correct the following line in + + +/etc/ssh/sshd_config: + +GSSAPIAuthentication no + + 11 + 3 + 9 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + 3.1.12 + CCI-000366 + CCI-001813 + 164.308(a)(4)(i) + 164.308(b)(1) + 164.308(b)(3) + 164.310(b) + 164.312(e)(1) + 164.312(e)(2)(ii) + 4.3.4.3.2 + 4.3.4.3.3 + SR 7.6 + 0418 + 1055 + 1402 + A.12.1.2 + A.12.5.1 + A.12.6.2 + A.14.2.2 + A.14.2.3 + A.14.2.4 + CM-7(a) + CM-7(b) + CM-6(a) + AC-17(a) + PR.IP-1 + FTP_ITC_EXT.1 + FCS_SSH_EXT.1.2 + SRG-OS-000364-GPOS-00151 + SRG-OS-000480-GPOS-00227 + OL09-00-002341 + SV-271704r1091824_rule + GSSAPI authentication is used to provide additional authentication mechanisms to +applications. Allowing GSSAPI authentication through SSH exposes the system's +GSSAPI to remote hosts, increasing the attack surface of the system. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Find the include keyword, extract from the line the glob expression representing included files. +# And if it is a relative path prepend '/etc/ssh/' +included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*include\s*//I' | sed -e 's|^[^/]|/etc/ssh/&|') +for included_file in ${included_files} ; do + + LC_ALL=C sed -i "/^\s*GSSAPIAuthentication/Id" "$included_file" +done + +if [ -e "/etc/ssh/sshd_config" ] ; then + + LC_ALL=C sed -i "/^\s*GSSAPIAuthentication\s\+/Id" "/etc/ssh/sshd_config" +else + touch "/etc/ssh/sshd_config" +fi +# make sure file has newline at the end +sed -i -e '$a\' "/etc/ssh/sshd_config" + +cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +# Insert at the beginning of the file +printf '%s\n' "GSSAPIAuthentication no" > "/etc/ssh/sshd_config" +cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +# Clean up after ourselves. +rm "/etc/ssh/sshd_config.bak" + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002341 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_gssapi_auth + +- name: Find sshd_config included files + shell: |- + included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') + [[ -n $included_files ]] && ls $included_files || true + register: sshd_config_included_files + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002341 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_gssapi_auth + +- name: Comment conf from included files + replace: + path: '{{ item }}' + regexp: ^(\s*GSSAPIAuthentication.*)$ + replace: '# \1' + loop: '{{ sshd_config_included_files.stdout_lines }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002341 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_gssapi_auth + +- name: Disable GSSAPI Authentication + block: + + - name: Check for duplicate values + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*GSSAPIAuthentication\s+ + state: absent + check_mode: true + changed_when: false + register: dupes + + - name: Deduplicate values from /etc/ssh/sshd_config + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*GSSAPIAuthentication\s+ + state: absent + when: dupes.found is defined and dupes.found > 1 + + - name: Insert correct line to /etc/ssh/sshd_config + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*GSSAPIAuthentication\s+ + line: GSSAPIAuthentication no + state: present + insertbefore: BOF + validate: /usr/sbin/sshd -t -f %s + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002341 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_gssapi_auth + + + + + + + + + + + Disable Kerberos Authentication + Unless needed, SSH should not permit extraneous or unnecessary +authentication mechanisms like Kerberos. + +The default SSH configuration disallows authentication validation through Kerberos. +The appropriate configuration is used if no value is set for KerberosAuthentication. + +To explicitly disable Kerberos authentication, add or correct the following line in + + +/etc/ssh/sshd_config: + +KerberosAuthentication no + + 11 + 3 + 9 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + 3.1.12 + CCI-000366 + CCI-001813 + 164.308(a)(4)(i) + 164.308(b)(1) + 164.308(b)(3) + 164.310(b) + 164.312(e)(1) + 164.312(e)(2)(ii) + 4.3.4.3.2 + 4.3.4.3.3 + SR 7.6 + 0421 + 0422 + 0431 + 0974 + 1173 + 1401 + 1504 + 1505 + 1546 + 1557 + 1558 + 1559 + 1560 + 1561 + A.12.1.2 + A.12.5.1 + A.12.6.2 + A.14.2.2 + A.14.2.3 + A.14.2.4 + AC-17(a) + CM-7(a) + CM-7(b) + CM-6(a) + PR.IP-1 + FTP_ITC_EXT.1 + FCS_SSH_EXT.1.2 + SRG-OS-000364-GPOS-00151 + SRG-OS-000480-GPOS-00227 + OL09-00-002356 + SV-271718r1091866_rule + Kerberos authentication for SSH is often implemented using GSSAPI. If Kerberos +is enabled through SSH, the SSH daemon provides a means of access to the +system's Kerberos implementation. +Configuring these settings for the SSH daemon provides additional assurance that remote logon via SSH will not use unused methods of authentication, even in the event of misconfiguration elsewhere. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Find the include keyword, extract from the line the glob expression representing included files. +# And if it is a relative path prepend '/etc/ssh/' +included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*include\s*//I' | sed -e 's|^[^/]|/etc/ssh/&|') +for included_file in ${included_files} ; do + + LC_ALL=C sed -i "/^\s*KerberosAuthentication/Id" "$included_file" +done + +if [ -e "/etc/ssh/sshd_config" ] ; then + + LC_ALL=C sed -i "/^\s*KerberosAuthentication\s\+/Id" "/etc/ssh/sshd_config" +else + touch "/etc/ssh/sshd_config" +fi +# make sure file has newline at the end +sed -i -e '$a\' "/etc/ssh/sshd_config" + +cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +# Insert at the beginning of the file +printf '%s\n' "KerberosAuthentication no" > "/etc/ssh/sshd_config" +cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +# Clean up after ourselves. +rm "/etc/ssh/sshd_config.bak" + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002356 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_kerb_auth + +- name: Find sshd_config included files + shell: |- + included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') + [[ -n $included_files ]] && ls $included_files || true + register: sshd_config_included_files + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002356 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_kerb_auth + +- name: Comment conf from included files + replace: + path: '{{ item }}' + regexp: ^(\s*KerberosAuthentication.*)$ + replace: '# \1' + loop: '{{ sshd_config_included_files.stdout_lines }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002356 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_kerb_auth + +- name: Disable Kerberos Authentication + block: + + - name: Check for duplicate values + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*KerberosAuthentication\s+ + state: absent + check_mode: true + changed_when: false + register: dupes + + - name: Deduplicate values from /etc/ssh/sshd_config + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*KerberosAuthentication\s+ + state: absent + when: dupes.found is defined and dupes.found > 1 + + - name: Insert correct line to /etc/ssh/sshd_config + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*KerberosAuthentication\s+ + line: KerberosAuthentication no + state: present + insertbefore: BOF + validate: /usr/sbin/sshd -t -f %s + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002356 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_kerb_auth + + + + + + + + + + + Disable PubkeyAuthentication Authentication + Unless needed, SSH should not permit extraneous or unnecessary +authentication mechanisms. To disable PubkeyAuthentication authentication, add or +correct the following line in + + +/etc/ssh/sshd_config: + +PubkeyAuthentication no + + PubkeyAuthentication authentication is used to provide additional authentication mechanisms to +applications. Allowing PubkeyAuthentication authentication through SSH allows users to +generate their own authentication tokens, increasing the attack surface of the system. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Find the include keyword, extract from the line the glob expression representing included files. +# And if it is a relative path prepend '/etc/ssh/' +included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*include\s*//I' | sed -e 's|^[^/]|/etc/ssh/&|') +for included_file in ${included_files} ; do + + LC_ALL=C sed -i "/^\s*PubkeyAuthentication/Id" "$included_file" +done + +if [ -e "/etc/ssh/sshd_config" ] ; then + + LC_ALL=C sed -i "/^\s*PubkeyAuthentication\s\+/Id" "/etc/ssh/sshd_config" +else + touch "/etc/ssh/sshd_config" +fi +# make sure file has newline at the end +sed -i -e '$a\' "/etc/ssh/sshd_config" + +cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +# Insert at the beginning of the file +printf '%s\n' "PubkeyAuthentication no" > "/etc/ssh/sshd_config" +cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +# Clean up after ourselves. +rm "/etc/ssh/sshd_config.bak" + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_pubkey_auth + +- name: Find sshd_config included files + shell: |- + included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') + [[ -n $included_files ]] && ls $included_files || true + register: sshd_config_included_files + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_pubkey_auth + +- name: Comment conf from included files + replace: + path: '{{ item }}' + regexp: ^(\s*PubkeyAuthentication.*)$ + replace: '# \1' + loop: '{{ sshd_config_included_files.stdout_lines }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_pubkey_auth + +- name: Disable PubkeyAuthentication Authentication + block: + + - name: Check for duplicate values + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*PubkeyAuthentication\s+ + state: absent + check_mode: true + changed_when: false + register: dupes + + - name: Deduplicate values from /etc/ssh/sshd_config + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*PubkeyAuthentication\s+ + state: absent + when: dupes.found is defined and dupes.found > 1 + + - name: Insert correct line to /etc/ssh/sshd_config + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*PubkeyAuthentication\s+ + line: PubkeyAuthentication no + state: present + insertbefore: BOF + validate: /usr/sbin/sshd -t -f %s + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_pubkey_auth + + + + + + + + + + + Disable SSH Support for .rhosts Files + SSH can emulate the behavior of the obsolete rsh +command in allowing users to enable insecure access to their +accounts via .rhosts files. + +The default SSH configuration disables support for .rhosts. The appropriate +configuration is used if no value is set for IgnoreRhosts. + +To explicitly disable support for .rhosts files, add or correct the following line in + + +/etc/ssh/sshd_config: + +IgnoreRhosts yes + + 11 + 12 + 14 + 15 + 16 + 18 + 3 + 5 + 9 + 5.5.6 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS05.02 + DSS05.04 + DSS05.05 + DSS05.07 + DSS06.03 + DSS06.06 + 3.1.12 + CCI-000366 + 4.3.3.2.2 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.2 + 4.3.4.3.3 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 7.6 + A.12.1.2 + A.12.5.1 + A.12.6.2 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.6.1.2 + A.7.1.1 + A.9.1.2 + A.9.2.1 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + AC-17(a) + CM-7(a) + CM-7(b) + CM-6(a) + PR.AC-4 + PR.AC-6 + PR.IP-1 + PR.PT-3 + SRG-OS-000480-GPOS-00227 + 2.2.6 + 2.2 + OL09-00-002348 + SV-271711r1091845_rule + SSH trust relationships mean a compromise on one host +can allow an attacker to move trivially to other hosts. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Find the include keyword, extract from the line the glob expression representing included files. +# And if it is a relative path prepend '/etc/ssh/' +included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*include\s*//I' | sed -e 's|^[^/]|/etc/ssh/&|') +for included_file in ${included_files} ; do + + LC_ALL=C sed -i "/^\s*IgnoreRhosts/Id" "$included_file" +done + +if [ -e "/etc/ssh/sshd_config" ] ; then + + LC_ALL=C sed -i "/^\s*IgnoreRhosts\s\+/Id" "/etc/ssh/sshd_config" +else + touch "/etc/ssh/sshd_config" +fi +# make sure file has newline at the end +sed -i -e '$a\' "/etc/ssh/sshd_config" + +cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +# Insert at the beginning of the file +printf '%s\n' "IgnoreRhosts yes" > "/etc/ssh/sshd_config" +cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +# Clean up after ourselves. +rm "/etc/ssh/sshd_config.bak" + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - CJIS-5.5.6 + - DISA-STIG-OL09-00-002348 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_rhosts + +- name: Find sshd_config included files + shell: |- + included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') + [[ -n $included_files ]] && ls $included_files || true + register: sshd_config_included_files + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.5.6 + - DISA-STIG-OL09-00-002348 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_rhosts + +- name: Comment conf from included files + replace: + path: '{{ item }}' + regexp: ^(\s*IgnoreRhosts.*)$ + replace: '# \1' + loop: '{{ sshd_config_included_files.stdout_lines }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.5.6 + - DISA-STIG-OL09-00-002348 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_rhosts + +- name: Disable SSH Support for .rhosts Files + block: + + - name: Check for duplicate values + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*IgnoreRhosts\s+ + state: absent + check_mode: true + changed_when: false + register: dupes + + - name: Deduplicate values from /etc/ssh/sshd_config + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*IgnoreRhosts\s+ + state: absent + when: dupes.found is defined and dupes.found > 1 + + - name: Insert correct line to /etc/ssh/sshd_config + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*IgnoreRhosts\s+ + line: IgnoreRhosts yes + state: present + insertbefore: BOF + validate: /usr/sbin/sshd -t -f %s + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.5.6 + - DISA-STIG-OL09-00-002348 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_rhosts + + + + + + + + + + + Disable SSH Support for Rhosts RSA Authentication + SSH can allow authentication through the obsolete rsh +command through the use of the authenticating user's SSH keys. This should be disabled. + + +To ensure this behavior is disabled, add or correct the +following line in /etc/ssh/sshd_config: +RhostsRSAAuthentication no + + As of openssh-server version 7.4 and above, +the RhostsRSAAuthentication option has been deprecated, and the line +RhostsRSAAuthentication no in /etc/ssh/sshd_config is not +necessary. + 11 + 3 + 9 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + 3.1.12 + CCI-000366 + 164.308(a)(4)(i) + 164.308(b)(1) + 164.308(b)(3) + 164.310(b) + 164.312(e)(1) + 164.312(e)(2)(ii) + 4.3.4.3.2 + 4.3.4.3.3 + SR 7.6 + A.12.1.2 + A.12.5.1 + A.12.6.2 + A.14.2.2 + A.14.2.3 + A.14.2.4 + AC-17(a) + CM-7(a) + CM-7(b) + CM-6(a) + PR.IP-1 + SRG-OS-000480-GPOS-00227 + Configuring this setting for the SSH daemon provides additional +assurance that remote login via SSH will require a password, even +in the event of misconfiguration elsewhere. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Find the include keyword, extract from the line the glob expression representing included files. +# And if it is a relative path prepend '/etc/ssh/' +included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*include\s*//I' | sed -e 's|^[^/]|/etc/ssh/&|') +for included_file in ${included_files} ; do + + LC_ALL=C sed -i "/^\s*RhostsRSAAuthentication/Id" "$included_file" +done + +if [ -e "/etc/ssh/sshd_config" ] ; then + + LC_ALL=C sed -i "/^\s*RhostsRSAAuthentication\s\+/Id" "/etc/ssh/sshd_config" +else + touch "/etc/ssh/sshd_config" +fi +# make sure file has newline at the end +sed -i -e '$a\' "/etc/ssh/sshd_config" + +cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +# Insert at the beginning of the file +printf '%s\n' "RhostsRSAAuthentication no" > "/etc/ssh/sshd_config" +cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +# Clean up after ourselves. +rm "/etc/ssh/sshd_config.bak" + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_rhosts_rsa + +- name: Find sshd_config included files + shell: |- + included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') + [[ -n $included_files ]] && ls $included_files || true + register: sshd_config_included_files + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_rhosts_rsa + +- name: Comment conf from included files + replace: + path: '{{ item }}' + regexp: ^(\s*RhostsRSAAuthentication.*)$ + replace: '# \1' + loop: '{{ sshd_config_included_files.stdout_lines }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_rhosts_rsa + +- name: Disable SSH Support for Rhosts RSA Authentication + block: + + - name: Check for duplicate values + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*RhostsRSAAuthentication\s+ + state: absent + check_mode: true + changed_when: false + register: dupes + + - name: Deduplicate values from /etc/ssh/sshd_config + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*RhostsRSAAuthentication\s+ + state: absent + when: dupes.found is defined and dupes.found > 1 + + - name: Insert correct line to /etc/ssh/sshd_config + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*RhostsRSAAuthentication\s+ + line: RhostsRSAAuthentication no + state: present + insertbefore: BOF + validate: /usr/sbin/sshd -t -f %s + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_rhosts_rsa + + + + + + + + + + + Disable SSH Root Login + The root user should never be allowed to login to a +system directly over a network. +To disable root login via SSH, add or correct the following line in + + +/etc/ssh/sshd_config: + +PermitRootLogin no + + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + 5.5.6 + APO01.06 + DSS05.02 + DSS05.04 + DSS05.05 + DSS05.07 + DSS05.10 + DSS06.02 + DSS06.03 + DSS06.06 + DSS06.10 + 3.1.1 + 3.1.5 + CCI-000366 + CCI-004045 + 164.308(a)(4)(i) + 164.308(b)(1) + 164.308(b)(3) + 164.310(b) + 164.312(e)(1) + 164.312(e)(2)(ii) + 4.3.3.2.2 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 5.2 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.18.1.4 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.1 + A.9.2.2 + A.9.2.3 + A.9.2.4 + A.9.2.6 + A.9.3.1 + A.9.4.1 + A.9.4.2 + A.9.4.3 + A.9.4.4 + A.9.4.5 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.2.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 + CIP-007-3 R5.2 + CIP-007-3 R5.3.1 + CIP-007-3 R5.3.2 + CIP-007-3 R5.3.3 + AC-6(2) + AC-17(a) + IA-2 + IA-2(5) + CM-7(a) + CM-7(b) + CM-6(a) + PR.AC-1 + PR.AC-4 + PR.AC-6 + PR.AC-7 + PR.DS-5 + PR.PT-3 + FAU_GEN.1 + Req-2.2.4 + SRG-OS-000109-GPOS-00056 + SRG-OS-000480-GPOS-00227 + SRG-APP-000148-CTR-000335 + SRG-APP-000190-CTR-000500 + R33 + 2.2.6 + 2.2 + OL09-00-002345 + SV-271708r1092594_rule + Even though the communications channel may be encrypted, an additional layer of +security is gained by extending the policy of not logging directly on as root. +In addition, logging in with a user-specific account provides individual +accountability of actions performed on the system and also helps to minimize +direct attack attempts on root's password. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Find the include keyword, extract from the line the glob expression representing included files. +# And if it is a relative path prepend '/etc/ssh/' +included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*include\s*//I' | sed -e 's|^[^/]|/etc/ssh/&|') +for included_file in ${included_files} ; do + + LC_ALL=C sed -i "/^\s*PermitRootLogin/Id" "$included_file" +done + +if [ -e "/etc/ssh/sshd_config" ] ; then + + LC_ALL=C sed -i "/^\s*PermitRootLogin\s\+/Id" "/etc/ssh/sshd_config" +else + touch "/etc/ssh/sshd_config" +fi +# make sure file has newline at the end +sed -i -e '$a\' "/etc/ssh/sshd_config" + +cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +# Insert at the beginning of the file +printf '%s\n' "PermitRootLogin no" > "/etc/ssh/sshd_config" +cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +# Clean up after ourselves. +rm "/etc/ssh/sshd_config.bak" + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - CJIS-5.5.6 + - DISA-STIG-OL09-00-002345 + - NIST-800-171-3.1.1 + - NIST-800-171-3.1.5 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-6(2) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-IA-2 + - NIST-800-53-IA-2(5) + - PCI-DSS-Req-2.2.4 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_root_login + +- name: Find sshd_config included files + shell: |- + included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') + [[ -n $included_files ]] && ls $included_files || true + register: sshd_config_included_files + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.5.6 + - DISA-STIG-OL09-00-002345 + - NIST-800-171-3.1.1 + - NIST-800-171-3.1.5 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-6(2) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-IA-2 + - NIST-800-53-IA-2(5) + - PCI-DSS-Req-2.2.4 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_root_login + +- name: Comment conf from included files + replace: + path: '{{ item }}' + regexp: ^(\s*PermitRootLogin.*)$ + replace: '# \1' + loop: '{{ sshd_config_included_files.stdout_lines }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.5.6 + - DISA-STIG-OL09-00-002345 + - NIST-800-171-3.1.1 + - NIST-800-171-3.1.5 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-6(2) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-IA-2 + - NIST-800-53-IA-2(5) + - PCI-DSS-Req-2.2.4 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_root_login + +- name: Disable SSH Root Login + block: + + - name: Check for duplicate values + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*PermitRootLogin\s+ + state: absent + check_mode: true + changed_when: false + register: dupes + + - name: Deduplicate values from /etc/ssh/sshd_config + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*PermitRootLogin\s+ + state: absent + when: dupes.found is defined and dupes.found > 1 + + - name: Insert correct line to /etc/ssh/sshd_config + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*PermitRootLogin\s+ + line: PermitRootLogin no + state: present + insertbefore: BOF + validate: /usr/sbin/sshd -t -f %s + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.5.6 + - DISA-STIG-OL09-00-002345 + - NIST-800-171-3.1.1 + - NIST-800-171-3.1.5 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-6(2) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-IA-2 + - NIST-800-53-IA-2(5) + - PCI-DSS-Req-2.2.4 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_root_login + + + + + + + + + + + Disable SSH root Login with a Password (Insecure) + To disable password-based root logins over SSH, add or correct the following line in + + +/etc/ssh/sshd_config: + +PermitRootLogin prohibit-password + + While this disables password-based root logins, direct root logins +through other means such as through SSH keys or GSSAPI will still be +permitted. Permitting any sort of root login remotely opens up the +root account to attack. +To fully disable direct root logins over SSH (which is considered a +best practice) and prevent remote attacks against the root account, +see CCE-27100-7, CCE-27445-6, CCE-80901-2, and similar. + Even though the communications channel may be encrypted, an additional +layer of security is gained by preventing use of a password. +This also helps to minimize direct attack attempts on root's password. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Find the include keyword, extract from the line the glob expression representing included files. +# And if it is a relative path prepend '/etc/ssh/' +included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*include\s*//I' | sed -e 's|^[^/]|/etc/ssh/&|') +for included_file in ${included_files} ; do + + LC_ALL=C sed -i "/^\s*PermitRootLogin/Id" "$included_file" +done + +if [ -e "/etc/ssh/sshd_config" ] ; then + + LC_ALL=C sed -i "/^\s*PermitRootLogin\s\+/Id" "/etc/ssh/sshd_config" +else + touch "/etc/ssh/sshd_config" +fi +# make sure file has newline at the end +sed -i -e '$a\' "/etc/ssh/sshd_config" + +cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +# Insert at the beginning of the file +printf '%s\n' "PermitRootLogin prohibit-password" > "/etc/ssh/sshd_config" +cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +# Clean up after ourselves. +rm "/etc/ssh/sshd_config.bak" + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_root_password_login + +- name: Find sshd_config included files + shell: |- + included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') + [[ -n $included_files ]] && ls $included_files || true + register: sshd_config_included_files + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_root_password_login + +- name: Comment conf from included files + replace: + path: '{{ item }}' + regexp: ^(\s*PermitRootLogin.*)$ + replace: '# \1' + loop: '{{ sshd_config_included_files.stdout_lines }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_root_password_login + +- name: Disable SSH root Login with a Password (Insecure) + block: + + - name: Check for duplicate values + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*PermitRootLogin\s+ + state: absent + check_mode: true + changed_when: false + register: dupes + + - name: Deduplicate values from /etc/ssh/sshd_config + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*PermitRootLogin\s+ + state: absent + when: dupes.found is defined and dupes.found > 1 + + - name: Insert correct line to /etc/ssh/sshd_config + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*PermitRootLogin\s+ + line: PermitRootLogin prohibit-password + state: present + insertbefore: BOF + validate: /usr/sbin/sshd -t -f %s + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_root_password_login + + + + + + + + + + + Disable SSH TCP Forwarding + The AllowTcpForwarding parameter specifies whether TCP forwarding is permitted. +To disable TCP forwarding, add or correct the following line in + + +/etc/ssh/sshd_config: + +AllowTcpForwarding no + + 2.2.6 + 2.2 + Leaving port forwarding enabled can expose the organization to security risks and back-doors. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Find the include keyword, extract from the line the glob expression representing included files. +# And if it is a relative path prepend '/etc/ssh/' +included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*include\s*//I' | sed -e 's|^[^/]|/etc/ssh/&|') +for included_file in ${included_files} ; do + + LC_ALL=C sed -i "/^\s*AllowTcpForwarding/Id" "$included_file" +done + +if [ -e "/etc/ssh/sshd_config" ] ; then + + LC_ALL=C sed -i "/^\s*AllowTcpForwarding\s\+/Id" "/etc/ssh/sshd_config" +else + touch "/etc/ssh/sshd_config" +fi +# make sure file has newline at the end +sed -i -e '$a\' "/etc/ssh/sshd_config" + +cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +# Insert at the beginning of the file +printf '%s\n' "AllowTcpForwarding no" > "/etc/ssh/sshd_config" +cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +# Clean up after ourselves. +rm "/etc/ssh/sshd_config.bak" + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_tcp_forwarding + +- name: Find sshd_config included files + shell: |- + included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') + [[ -n $included_files ]] && ls $included_files || true + register: sshd_config_included_files + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_tcp_forwarding + +- name: Comment conf from included files + replace: + path: '{{ item }}' + regexp: ^(\s*AllowTcpForwarding.*)$ + replace: '# \1' + loop: '{{ sshd_config_included_files.stdout_lines }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_tcp_forwarding + +- name: Disable SSH TCP Forwarding + block: + + - name: Check for duplicate values + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*AllowTcpForwarding\s+ + state: absent + check_mode: true + changed_when: false + register: dupes + + - name: Deduplicate values from /etc/ssh/sshd_config + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*AllowTcpForwarding\s+ + state: absent + when: dupes.found is defined and dupes.found > 1 + + - name: Insert correct line to /etc/ssh/sshd_config + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*AllowTcpForwarding\s+ + line: AllowTcpForwarding no + state: present + insertbefore: BOF + validate: /usr/sbin/sshd -t -f %s + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_tcp_forwarding + + + + + + + + + + + Disable SSH Support for User Known Hosts + SSH can allow system users to connect to systems if a cache of the remote +systems public keys is available. This should be disabled. + + +To ensure this behavior is disabled, add or correct the following line in + + +/etc/ssh/sshd_config: + +IgnoreUserKnownHosts yes + + 11 + 3 + 9 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + 3.1.12 + CCI-000366 + 164.308(a)(4)(i) + 164.308(b)(1) + 164.308(b)(3) + 164.310(b) + 164.312(e)(1) + 164.312(e)(2)(ii) + 4.3.4.3.2 + 4.3.4.3.3 + SR 7.6 + A.12.1.2 + A.12.5.1 + A.12.6.2 + A.14.2.2 + A.14.2.3 + A.14.2.4 + AC-17(a) + CM-7(a) + CM-7(b) + CM-6(a) + PR.IP-1 + SRG-OS-000480-GPOS-00227 + OL09-00-002349 + SV-271712r1091848_rule + Configuring this setting for the SSH daemon provides additional +assurance that remote login via SSH will require a password, even +in the event of misconfiguration elsewhere. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Find the include keyword, extract from the line the glob expression representing included files. +# And if it is a relative path prepend '/etc/ssh/' +included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*include\s*//I' | sed -e 's|^[^/]|/etc/ssh/&|') +for included_file in ${included_files} ; do + + LC_ALL=C sed -i "/^\s*IgnoreUserKnownHosts/Id" "$included_file" +done + +if [ -e "/etc/ssh/sshd_config" ] ; then + + LC_ALL=C sed -i "/^\s*IgnoreUserKnownHosts\s\+/Id" "/etc/ssh/sshd_config" +else + touch "/etc/ssh/sshd_config" +fi +# make sure file has newline at the end +sed -i -e '$a\' "/etc/ssh/sshd_config" + +cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +# Insert at the beginning of the file +printf '%s\n' "IgnoreUserKnownHosts yes" > "/etc/ssh/sshd_config" +cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +# Clean up after ourselves. +rm "/etc/ssh/sshd_config.bak" + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002349 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_user_known_hosts + +- name: Find sshd_config included files + shell: |- + included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') + [[ -n $included_files ]] && ls $included_files || true + register: sshd_config_included_files + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002349 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_user_known_hosts + +- name: Comment conf from included files + replace: + path: '{{ item }}' + regexp: ^(\s*IgnoreUserKnownHosts.*)$ + replace: '# \1' + loop: '{{ sshd_config_included_files.stdout_lines }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002349 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_user_known_hosts + +- name: Disable SSH Support for User Known Hosts + block: + + - name: Check for duplicate values + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*IgnoreUserKnownHosts\s+ + state: absent + check_mode: true + changed_when: false + register: dupes + + - name: Deduplicate values from /etc/ssh/sshd_config + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*IgnoreUserKnownHosts\s+ + state: absent + when: dupes.found is defined and dupes.found > 1 + + - name: Insert correct line to /etc/ssh/sshd_config + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*IgnoreUserKnownHosts\s+ + line: IgnoreUserKnownHosts yes + state: present + insertbefore: BOF + validate: /usr/sbin/sshd -t -f %s + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002349 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_user_known_hosts + + + + + + + + + + + Disable X11 Forwarding + The X11Forwarding parameter provides the ability to tunnel X11 traffic +through the connection to enable remote graphic connections. +SSH has the capability to encrypt remote X11 connections when SSH's +X11Forwarding option is enabled. + +The default SSH configuration disables X11Forwarding. The appropriate +configuration is used if no value is set for X11Forwarding. + +To explicitly disable X11 Forwarding, add or correct the following line in + + +/etc/ssh/sshd_config: + +X11Forwarding no + + CCI-000366 + CM-6(b) + SRG-OS-000480-GPOS-00227 + 2.2.6 + 2.2 + OL09-00-002350 + SV-271713r1091851_rule + Disable X11 forwarding unless there is an operational requirement to use X11 +applications directly. There is a small risk that the remote X11 servers of +users who are logged in via SSH with X11 forwarding could be compromised by +other users on the X11 server. Note that even if X11 forwarding is disabled, +users can always install their own forwarders. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Find the include keyword, extract from the line the glob expression representing included files. +# And if it is a relative path prepend '/etc/ssh/' +included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*include\s*//I' | sed -e 's|^[^/]|/etc/ssh/&|') +for included_file in ${included_files} ; do + + LC_ALL=C sed -i "/^\s*X11Forwarding/Id" "$included_file" +done + +if [ -e "/etc/ssh/sshd_config" ] ; then + + LC_ALL=C sed -i "/^\s*X11Forwarding\s\+/Id" "/etc/ssh/sshd_config" +else + touch "/etc/ssh/sshd_config" +fi +# make sure file has newline at the end +sed -i -e '$a\' "/etc/ssh/sshd_config" + +cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +# Insert at the beginning of the file +printf '%s\n' "X11Forwarding no" > "/etc/ssh/sshd_config" +cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +# Clean up after ourselves. +rm "/etc/ssh/sshd_config.bak" + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002350 + - NIST-800-53-CM-6(b) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_x11_forwarding + +- name: Find sshd_config included files + shell: |- + included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') + [[ -n $included_files ]] && ls $included_files || true + register: sshd_config_included_files + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002350 + - NIST-800-53-CM-6(b) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_x11_forwarding + +- name: Comment conf from included files + replace: + path: '{{ item }}' + regexp: ^(\s*X11Forwarding.*)$ + replace: '# \1' + loop: '{{ sshd_config_included_files.stdout_lines }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002350 + - NIST-800-53-CM-6(b) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_x11_forwarding + +- name: Disable X11 Forwarding + block: + + - name: Check for duplicate values + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*X11Forwarding\s+ + state: absent + check_mode: true + changed_when: false + register: dupes + + - name: Deduplicate values from /etc/ssh/sshd_config + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*X11Forwarding\s+ + state: absent + when: dupes.found is defined and dupes.found > 1 + + - name: Insert correct line to /etc/ssh/sshd_config + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*X11Forwarding\s+ + line: X11Forwarding no + state: present + insertbefore: BOF + validate: /usr/sbin/sshd -t -f %s + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002350 + - NIST-800-53-CM-6(b) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_x11_forwarding + + + + + + + + + + + Do Not Allow SSH Environment Options + Ensure that users are not able to override environment variables of the SSH daemon. + +The default SSH configuration disables environment processing. The appropriate +configuration is used if no value is set for PermitUserEnvironment. + +To explicitly disable Environment options, add or correct the following + + +/etc/ssh/sshd_config: + +PermitUserEnvironment no + + 11 + 3 + 9 + 5.5.6 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + 3.1.12 + CCI-000366 + 164.308(a)(4)(i) + 164.308(b)(1) + 164.308(b)(3) + 164.310(b) + 164.312(e)(1) + 164.312(e)(2)(ii) + 4.3.4.3.2 + 4.3.4.3.3 + SR 7.6 + A.12.1.2 + A.12.5.1 + A.12.6.2 + A.14.2.2 + A.14.2.3 + A.14.2.4 + AC-17(a) + CM-7(a) + CM-7(b) + CM-6(a) + PR.IP-1 + Req-2.2.4 + SRG-OS-000480-GPOS-00229 + 2.2.6 + 2.2 + OL09-00-002358 + SV-271720r1091872_rule + SSH environment options potentially allow users to bypass +access restriction in some configurations. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Find the include keyword, extract from the line the glob expression representing included files. +# And if it is a relative path prepend '/etc/ssh/' +included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*include\s*//I' | sed -e 's|^[^/]|/etc/ssh/&|') +for included_file in ${included_files} ; do + + LC_ALL=C sed -i "/^\s*PermitUserEnvironment/Id" "$included_file" +done + +if [ -e "/etc/ssh/sshd_config" ] ; then + + LC_ALL=C sed -i "/^\s*PermitUserEnvironment\s\+/Id" "/etc/ssh/sshd_config" +else + touch "/etc/ssh/sshd_config" +fi +# make sure file has newline at the end +sed -i -e '$a\' "/etc/ssh/sshd_config" + +cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +# Insert at the beginning of the file +printf '%s\n' "PermitUserEnvironment no" > "/etc/ssh/sshd_config" +cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +# Clean up after ourselves. +rm "/etc/ssh/sshd_config.bak" + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - CJIS-5.5.6 + - DISA-STIG-OL09-00-002358 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - PCI-DSS-Req-2.2.4 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_do_not_permit_user_env + +- name: Find sshd_config included files + shell: |- + included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') + [[ -n $included_files ]] && ls $included_files || true + register: sshd_config_included_files + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.5.6 + - DISA-STIG-OL09-00-002358 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - PCI-DSS-Req-2.2.4 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_do_not_permit_user_env + +- name: Comment conf from included files + replace: + path: '{{ item }}' + regexp: ^(\s*PermitUserEnvironment.*)$ + replace: '# \1' + loop: '{{ sshd_config_included_files.stdout_lines }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.5.6 + - DISA-STIG-OL09-00-002358 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - PCI-DSS-Req-2.2.4 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_do_not_permit_user_env + +- name: Do Not Allow SSH Environment Options + block: + + - name: Check for duplicate values + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*PermitUserEnvironment\s+ + state: absent + check_mode: true + changed_when: false + register: dupes + + - name: Deduplicate values from /etc/ssh/sshd_config + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*PermitUserEnvironment\s+ + state: absent + when: dupes.found is defined and dupes.found > 1 + + - name: Insert correct line to /etc/ssh/sshd_config + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*PermitUserEnvironment\s+ + line: PermitUserEnvironment no + state: present + insertbefore: BOF + validate: /usr/sbin/sshd -t -f %s + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.5.6 + - DISA-STIG-OL09-00-002358 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - PCI-DSS-Req-2.2.4 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_do_not_permit_user_env + + + + + + + + + + + Enable GSSAPI Authentication + Sites setup to use Kerberos or other GSSAPI Authenticaion require setting +sshd to accept this authentication. +To enable GSSAPI authentication, add or correct the following line in + + +/etc/ssh/sshd_config: + +GSSAPIAuthentication yes + + Kerberos authentication for SSH is often implemented using GSSAPI. If +Kerberos is enabled through SSH, the SSH daemon provides a means of access +to the system's Kerberos implementation. Vulnerabilities in the system's +Kerberos implementations may be subject to exploitation. + +For enterprises, Kerberos is often enabled and used with GSSAPI for +centralized user account management which may necessitate enabling of +GSSAPI functionality in SSH. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Find the include keyword, extract from the line the glob expression representing included files. +# And if it is a relative path prepend '/etc/ssh/' +included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*include\s*//I' | sed -e 's|^[^/]|/etc/ssh/&|') +for included_file in ${included_files} ; do + + LC_ALL=C sed -i "/^\s*GSSAPIAuthentication/Id" "$included_file" +done + +if [ -e "/etc/ssh/sshd_config" ] ; then + + LC_ALL=C sed -i "/^\s*GSSAPIAuthentication\s\+/Id" "/etc/ssh/sshd_config" +else + touch "/etc/ssh/sshd_config" +fi +# make sure file has newline at the end +sed -i -e '$a\' "/etc/ssh/sshd_config" + +cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +# Insert at the beginning of the file +printf '%s\n' "GSSAPIAuthentication yes" > "/etc/ssh/sshd_config" +cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +# Clean up after ourselves. +rm "/etc/ssh/sshd_config.bak" + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_enable_gssapi_auth + +- name: Find sshd_config included files + shell: |- + included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') + [[ -n $included_files ]] && ls $included_files || true + register: sshd_config_included_files + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_enable_gssapi_auth + +- name: Comment conf from included files + replace: + path: '{{ item }}' + regexp: ^(\s*GSSAPIAuthentication.*)$ + replace: '# \1' + loop: '{{ sshd_config_included_files.stdout_lines }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_enable_gssapi_auth + +- name: Enable GSSAPI Authentication + block: + + - name: Check for duplicate values + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*GSSAPIAuthentication\s+ + state: absent + check_mode: true + changed_when: false + register: dupes + + - name: Deduplicate values from /etc/ssh/sshd_config + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*GSSAPIAuthentication\s+ + state: absent + when: dupes.found is defined and dupes.found > 1 + + - name: Insert correct line to /etc/ssh/sshd_config + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*GSSAPIAuthentication\s+ + line: GSSAPIAuthentication yes + state: present + insertbefore: BOF + validate: /usr/sbin/sshd -t -f %s + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_enable_gssapi_auth + + + + + + + + + + + Enable PAM + UsePAM Enables the Pluggable Authentication Module interface. If set to “yes” this will +enable PAM authentication using ChallengeResponseAuthentication and +PasswordAuthentication in addition to PAM account and session module processing for all +authentication types. + +To enable PAM authentication, add or correct the following line in + + +/etc/ssh/sshd_config: + +UsePAM yes + + CCI-000877 + SRG-OS-000125-GPOS-00065 + 2.2.6 + 2.2 + OL09-00-002344 + SV-271707r1091833_rule + When UsePAM is set to yes, PAM runs through account and session types properly. This is +important if you want to restrict access to services based off of IP, time or other factors of +the account. Additionally, you can make sure users inherit certain environment variables +on login or disallow access to the server. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Find the include keyword, extract from the line the glob expression representing included files. +# And if it is a relative path prepend '/etc/ssh/' +included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*include\s*//I' | sed -e 's|^[^/]|/etc/ssh/&|') +for included_file in ${included_files} ; do + + LC_ALL=C sed -i "/^\s*UsePAM/Id" "$included_file" +done + +if [ -e "/etc/ssh/sshd_config" ] ; then + + LC_ALL=C sed -i "/^\s*UsePAM\s\+/Id" "/etc/ssh/sshd_config" +else + touch "/etc/ssh/sshd_config" +fi +# make sure file has newline at the end +sed -i -e '$a\' "/etc/ssh/sshd_config" + +cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +# Insert at the beginning of the file +printf '%s\n' "UsePAM yes" > "/etc/ssh/sshd_config" +cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +# Clean up after ourselves. +rm "/etc/ssh/sshd_config.bak" + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002344 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_enable_pam + +- name: Find sshd_config included files + shell: |- + included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') + [[ -n $included_files ]] && ls $included_files || true + register: sshd_config_included_files + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002344 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_enable_pam + +- name: Comment conf from included files + replace: + path: '{{ item }}' + regexp: ^(\s*UsePAM.*)$ + replace: '# \1' + loop: '{{ sshd_config_included_files.stdout_lines }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002344 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_enable_pam + +- name: Enable PAM + block: + + - name: Check for duplicate values + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*UsePAM\s+ + state: absent + check_mode: true + changed_when: false + register: dupes + + - name: Deduplicate values from /etc/ssh/sshd_config + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*UsePAM\s+ + state: absent + when: dupes.found is defined and dupes.found > 1 + + - name: Insert correct line to /etc/ssh/sshd_config + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*UsePAM\s+ + line: UsePAM yes + state: present + insertbefore: BOF + validate: /usr/sbin/sshd -t -f %s + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002344 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_enable_pam + + + + + + + + + + + Enable Public Key Authentication + Enable SSH login with public keys. + +The default SSH configuration enables authentication based on public keys. The appropriate +configuration is used if no value is set for PubkeyAuthentication. + +To explicitly enable Public Key Authentication, add or correct the following + + +/etc/ssh/sshd_config: + +PubkeyAuthentication yes + + CCI-000765 + CCI-000766 + SRG-OS-000105-GPOS-00052 + SRG-OS-000106-GPOS-00053 + SRG-OS-000107-GPOS-00054 + SRG-OS-000108-GPOS-00055 + OL09-00-002359 + SV-271721r1091875_rule + Without the use of multifactor authentication, the ease of access to +privileged functions is greatly increased. Multifactor authentication +requires using two or more factors to achieve authentication. +A privileged account is defined as an information system account with +authorizations of a privileged user. +The DoD CAC with DoD-approved PKI is an example of multifactor +authentication. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Find the include keyword, extract from the line the glob expression representing included files. +# And if it is a relative path prepend '/etc/ssh/' +included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*include\s*//I' | sed -e 's|^[^/]|/etc/ssh/&|') +for included_file in ${included_files} ; do + + LC_ALL=C sed -i "/^\s*PubkeyAuthentication/Id" "$included_file" +done + +if [ -e "/etc/ssh/sshd_config" ] ; then + + LC_ALL=C sed -i "/^\s*PubkeyAuthentication\s\+/Id" "/etc/ssh/sshd_config" +else + touch "/etc/ssh/sshd_config" +fi +# make sure file has newline at the end +sed -i -e '$a\' "/etc/ssh/sshd_config" + +cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +# Insert at the beginning of the file +printf '%s\n' "PubkeyAuthentication yes" > "/etc/ssh/sshd_config" +cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +# Clean up after ourselves. +rm "/etc/ssh/sshd_config.bak" + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002359 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_enable_pubkey_auth + +- name: Find sshd_config included files + shell: |- + included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') + [[ -n $included_files ]] && ls $included_files || true + register: sshd_config_included_files + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002359 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_enable_pubkey_auth + +- name: Comment conf from included files + replace: + path: '{{ item }}' + regexp: ^(\s*PubkeyAuthentication.*)$ + replace: '# \1' + loop: '{{ sshd_config_included_files.stdout_lines }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002359 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_enable_pubkey_auth + +- name: Enable Public Key Authentication + block: + + - name: Check for duplicate values + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*PubkeyAuthentication\s+ + state: absent + check_mode: true + changed_when: false + register: dupes + + - name: Deduplicate values from /etc/ssh/sshd_config + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*PubkeyAuthentication\s+ + state: absent + when: dupes.found is defined and dupes.found > 1 + + - name: Insert correct line to /etc/ssh/sshd_config + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*PubkeyAuthentication\s+ + line: PubkeyAuthentication yes + state: present + insertbefore: BOF + validate: /usr/sbin/sshd -t -f %s + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002359 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_enable_pubkey_auth + + + + + + + + + + + Enable Use of Strict Mode Checking + SSHs StrictModes option checks file and ownership permissions in +the user's home directory .ssh folder before accepting login. If world- +writable permissions are found, logon is rejected. + +The default SSH configuration has StrictModes enabled. The appropriate +configuration is used if no value is set for StrictModes. + +To explicitly enable StrictModes in SSH, add or correct the following line in + + +/etc/ssh/sshd_config: + +StrictModes yes + + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + APO01.06 + DSS05.04 + DSS05.07 + DSS06.02 + 3.1.12 + CCI-000366 + 164.308(a)(4)(i) + 164.308(b)(1) + 164.308(b)(3) + 164.310(b) + 164.312(e)(1) + 164.312(e)(2)(ii) + 4.3.3.7.3 + SR 2.1 + SR 5.2 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 + AC-6 + AC-17(a) + CM-6(a) + PR.AC-4 + PR.DS-5 + SRG-OS-000480-GPOS-00227 + OL09-00-002351 + SV-271714r1091854_rule + If other users have access to modify user-specific SSH configuration files, they +may be able to log into the system as another user. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Find the include keyword, extract from the line the glob expression representing included files. +# And if it is a relative path prepend '/etc/ssh/' +included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*include\s*//I' | sed -e 's|^[^/]|/etc/ssh/&|') +for included_file in ${included_files} ; do + + LC_ALL=C sed -i "/^\s*StrictModes/Id" "$included_file" +done + +if [ -e "/etc/ssh/sshd_config" ] ; then + + LC_ALL=C sed -i "/^\s*StrictModes\s\+/Id" "/etc/ssh/sshd_config" +else + touch "/etc/ssh/sshd_config" +fi +# make sure file has newline at the end +sed -i -e '$a\' "/etc/ssh/sshd_config" + +cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +# Insert at the beginning of the file +printf '%s\n' "StrictModes yes" > "/etc/ssh/sshd_config" +cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +# Clean up after ourselves. +rm "/etc/ssh/sshd_config.bak" + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002351 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-6 + - NIST-800-53-CM-6(a) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_enable_strictmodes + +- name: Find sshd_config included files + shell: |- + included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') + [[ -n $included_files ]] && ls $included_files || true + register: sshd_config_included_files + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002351 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-6 + - NIST-800-53-CM-6(a) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_enable_strictmodes + +- name: Comment conf from included files + replace: + path: '{{ item }}' + regexp: ^(\s*StrictModes.*)$ + replace: '# \1' + loop: '{{ sshd_config_included_files.stdout_lines }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002351 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-6 + - NIST-800-53-CM-6(a) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_enable_strictmodes + +- name: Enable Use of Strict Mode Checking + block: + + - name: Check for duplicate values + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*StrictModes\s+ + state: absent + check_mode: true + changed_when: false + register: dupes + + - name: Deduplicate values from /etc/ssh/sshd_config + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*StrictModes\s+ + state: absent + when: dupes.found is defined and dupes.found > 1 + + - name: Insert correct line to /etc/ssh/sshd_config + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*StrictModes\s+ + line: StrictModes yes + state: present + insertbefore: BOF + validate: /usr/sbin/sshd -t -f %s + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002351 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-6 + - NIST-800-53-CM-6(a) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_enable_strictmodes + + + + + + + + + + + Enable SSH Warning Banner + To enable the warning banner and ensure it is consistent +across the system, add or correct the following line in + + +/etc/ssh/sshd_config: + +Banner /etc/issue +Another section contains information on how to create an +appropriate system-wide warning banner. + 1 + 12 + 15 + 16 + 5.5.6 + DSS05.04 + DSS05.10 + DSS06.10 + 3.1.9 + CCI-001387 + CCI-001384 + CCI-000048 + CCI-001386 + CCI-001388 + CCI-001385 + 164.308(a)(4)(i) + 164.308(b)(1) + 164.308(b)(3) + 164.310(b) + 164.312(e)(1) + 164.312(e)(2)(ii) + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + SR 1.1 + SR 1.10 + SR 1.2 + SR 1.5 + SR 1.7 + SR 1.8 + SR 1.9 + A.18.1.4 + A.9.2.1 + A.9.2.4 + A.9.3.1 + A.9.4.2 + A.9.4.3 + AC-8(a) + AC-8(c) + AC-17(a) + CM-6(a) + PR.AC-7 + FTA_TAB.1 + Req-2.2.4 + SRG-OS-000023-GPOS-00006 + SRG-OS-000228-GPOS-00088 + OL09-00-000256 + SV-271487r1091173_rule + The warning message reinforces policy awareness during the logon process and +facilitates possible legal action against attackers. Alternatively, systems +whose ownership should not be obvious should ensure usage of a banner that does +not provide easy attribution. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Find the include keyword, extract from the line the glob expression representing included files. +# And if it is a relative path prepend '/etc/ssh/' +included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*include\s*//I' | sed -e 's|^[^/]|/etc/ssh/&|') +for included_file in ${included_files} ; do + + LC_ALL=C sed -i "/^\s*Banner/Id" "$included_file" +done + +if [ -e "/etc/ssh/sshd_config" ] ; then + + LC_ALL=C sed -i "/^\s*Banner\s\+/Id" "/etc/ssh/sshd_config" +else + touch "/etc/ssh/sshd_config" +fi +# make sure file has newline at the end +sed -i -e '$a\' "/etc/ssh/sshd_config" + +cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +# Insert at the beginning of the file +printf '%s\n' "Banner /etc/issue" > "/etc/ssh/sshd_config" +cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +# Clean up after ourselves. +rm "/etc/ssh/sshd_config.bak" + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - CJIS-5.5.6 + - DISA-STIG-OL09-00-000256 + - NIST-800-171-3.1.9 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-8(a) + - NIST-800-53-AC-8(c) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-2.2.4 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_enable_warning_banner + +- name: Find sshd_config included files + shell: |- + included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') + [[ -n $included_files ]] && ls $included_files || true + register: sshd_config_included_files + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.5.6 + - DISA-STIG-OL09-00-000256 + - NIST-800-171-3.1.9 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-8(a) + - NIST-800-53-AC-8(c) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-2.2.4 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_enable_warning_banner + +- name: Comment conf from included files + replace: + path: '{{ item }}' + regexp: ^(\s*Banner.*)$ + replace: '# \1' + loop: '{{ sshd_config_included_files.stdout_lines }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.5.6 + - DISA-STIG-OL09-00-000256 + - NIST-800-171-3.1.9 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-8(a) + - NIST-800-53-AC-8(c) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-2.2.4 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_enable_warning_banner + +- name: Enable SSH Warning Banner + block: + + - name: Check for duplicate values + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*Banner\s+ + state: absent + check_mode: true + changed_when: false + register: dupes + + - name: Deduplicate values from /etc/ssh/sshd_config + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*Banner\s+ + state: absent + when: dupes.found is defined and dupes.found > 1 + + - name: Insert correct line to /etc/ssh/sshd_config + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*Banner\s+ + line: Banner /etc/issue + state: present + insertbefore: BOF + validate: /usr/sbin/sshd -t -f %s + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.5.6 + - DISA-STIG-OL09-00-000256 + - NIST-800-171-3.1.9 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-8(a) + - NIST-800-53-AC-8(c) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-2.2.4 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_enable_warning_banner + + + + + + + + + + + Enable SSH Warning Banner + To enable the warning banner and ensure it is consistent +across the system, add or correct the following line in + +/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf: + +Banner /etc/issue.net +Another section contains information on how to create an +appropriate system-wide warning banner. + 5.5.6 + DSS05.04 + DSS05.10 + DSS06.10 + 3.1.9 + CCI-000048 + CCI-000050 + CCI-001384 + CCI-001385 + CCI-001386 + CCI-001387 + CCI-001388 + 164.308(a)(4)(i) + 164.308(b)(1) + 164.308(b)(3) + 164.310(b) + 164.312(e)(1) + 164.312(e)(2)(ii) + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + SR 1.1 + SR 1.10 + SR 1.2 + SR 1.5 + SR 1.7 + SR 1.8 + SR 1.9 + A.18.1.4 + A.9.2.1 + A.9.2.4 + A.9.3.1 + A.9.4.2 + A.9.4.3 + AC-8(a) + AC-8(c) + AC-17(a) + CM-6(a) + PR.AC-7 + SRG-OS-000023-GPOS-00006 + SRG-OS-000228-GPOS-00088 + A.11.SEC-OL4 + The warning message reinforces policy awareness during the logon process and +facilitates possible legal action against attackers. Alternatively, systems +whose ownership should not be obvious should ensure usage of a banner that does +not provide easy attribution. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Find the include keyword, extract from the line the glob expression representing included files. +# And if it is a relative path prepend '/etc/ssh/' +included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*include\s*//I' | sed -e 's|^[^/]|/etc/ssh/&|') +for included_file in ${included_files} ; do + + LC_ALL=C sed -i "/^\s*Banner/Id" "$included_file" +done + +if [ -e "/etc/ssh/sshd_config" ] ; then + + LC_ALL=C sed -i "/^\s*Banner\s\+/Id" "/etc/ssh/sshd_config" +else + touch "/etc/ssh/sshd_config" +fi +# make sure file has newline at the end +sed -i -e '$a\' "/etc/ssh/sshd_config" + +cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +# Insert at the beginning of the file +printf '%s\n' "Banner /etc/issue.net" > "/etc/ssh/sshd_config" +cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +# Clean up after ourselves. +rm "/etc/ssh/sshd_config.bak" + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - CJIS-5.5.6 + - NIST-800-171-3.1.9 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-8(a) + - NIST-800-53-AC-8(c) + - NIST-800-53-CM-6(a) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_enable_warning_banner_net + +- name: Find sshd_config included files + shell: |- + included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') + [[ -n $included_files ]] && ls $included_files || true + register: sshd_config_included_files + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.5.6 + - NIST-800-171-3.1.9 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-8(a) + - NIST-800-53-AC-8(c) + - NIST-800-53-CM-6(a) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_enable_warning_banner_net + +- name: Comment conf from included files + replace: + path: '{{ item }}' + regexp: ^(\s*Banner.*)$ + replace: '# \1' + loop: '{{ sshd_config_included_files.stdout_lines }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.5.6 + - NIST-800-171-3.1.9 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-8(a) + - NIST-800-53-AC-8(c) + - NIST-800-53-CM-6(a) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_enable_warning_banner_net + +- name: Enable SSH Warning Banner + block: + + - name: Check for duplicate values + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*Banner\s+ + state: absent + check_mode: true + changed_when: false + register: dupes + + - name: Deduplicate values from /etc/ssh/sshd_config + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*Banner\s+ + state: absent + when: dupes.found is defined and dupes.found > 1 + + - name: Insert correct line to /etc/ssh/sshd_config + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*Banner\s+ + line: Banner /etc/issue.net + state: present + insertbefore: BOF + validate: /usr/sbin/sshd -t -f %s + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.5.6 + - NIST-800-171-3.1.9 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-8(a) + - NIST-800-53-AC-8(c) + - NIST-800-53-CM-6(a) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_enable_warning_banner_net + + + + + + + + + + + Enable Encrypted X11 Forwarding + By default, remote X11 connections are not encrypted when initiated +by users. SSH has the capability to encrypt remote X11 connections when SSH's +X11Forwarding option is enabled. + + +To enable X11 Forwarding, add or correct the following line in + + +/etc/ssh/sshd_config: + +X11Forwarding yes + + 1 + 11 + 12 + 13 + 15 + 16 + 18 + 20 + 3 + 4 + 6 + 9 + BAI03.08 + BAI07.04 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS03.01 + 3.1.13 + CCI-000366 + 4.3.4.3.2 + 4.3.4.3.3 + 4.4.3.3 + SR 7.6 + A.12.1.1 + A.12.1.2 + A.12.1.4 + A.12.5.1 + A.12.6.2 + A.13.1.1 + A.13.1.2 + A.14.2.2 + A.14.2.3 + A.14.2.4 + CIP-007-3 R7.1 + CM-6(a) + AC-17(a) + AC-17(2) + DE.AE-1 + PR.DS-7 + PR.IP-1 + SRG-OS-000480-GPOS-00227 + Non-encrypted X displays allow an attacker to capture keystrokes and to execute commands +remotely. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Find the include keyword, extract from the line the glob expression representing included files. +# And if it is a relative path prepend '/etc/ssh/' +included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*include\s*//I' | sed -e 's|^[^/]|/etc/ssh/&|') +for included_file in ${included_files} ; do + + LC_ALL=C sed -i "/^\s*X11Forwarding/Id" "$included_file" +done + +if [ -e "/etc/ssh/sshd_config" ] ; then + + LC_ALL=C sed -i "/^\s*X11Forwarding\s\+/Id" "/etc/ssh/sshd_config" +else + touch "/etc/ssh/sshd_config" +fi +# make sure file has newline at the end +sed -i -e '$a\' "/etc/ssh/sshd_config" + +cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +# Insert at the beginning of the file +printf '%s\n' "X11Forwarding yes" > "/etc/ssh/sshd_config" +cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +# Clean up after ourselves. +rm "/etc/ssh/sshd_config.bak" + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-171-3.1.13 + - NIST-800-53-AC-17(2) + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - restrict_strategy + - sshd_enable_x11_forwarding + +- name: Find sshd_config included files + shell: |- + included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') + [[ -n $included_files ]] && ls $included_files || true + register: sshd_config_included_files + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-171-3.1.13 + - NIST-800-53-AC-17(2) + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - restrict_strategy + - sshd_enable_x11_forwarding + +- name: Comment conf from included files + replace: + path: '{{ item }}' + regexp: ^(\s*X11Forwarding.*)$ + replace: '# \1' + loop: '{{ sshd_config_included_files.stdout_lines }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-171-3.1.13 + - NIST-800-53-AC-17(2) + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - restrict_strategy + - sshd_enable_x11_forwarding + +- name: Enable Encrypted X11 Forwarding + block: + + - name: Check for duplicate values + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*X11Forwarding\s+ + state: absent + check_mode: true + changed_when: false + register: dupes + + - name: Deduplicate values from /etc/ssh/sshd_config + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*X11Forwarding\s+ + state: absent + when: dupes.found is defined and dupes.found > 1 + + - name: Insert correct line to /etc/ssh/sshd_config + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*X11Forwarding\s+ + line: X11Forwarding yes + state: present + insertbefore: BOF + validate: /usr/sbin/sshd -t -f %s + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-171-3.1.13 + - NIST-800-53-AC-17(2) + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - restrict_strategy + - sshd_enable_x11_forwarding + + + + + + + + + + + Limit Users' SSH Access + By default, the SSH configuration allows any user with an account +to access the system. There are several options available to limit +which users and group can access the system via SSH. It is +recommended that at least one of the following options be leveraged: +- AllowUsers variable gives the system administrator the option of + allowing specific users to ssh into the system. The list consists of + space separated user names. Numeric user IDs are not recognized with + this variable. If a system administrator wants to restrict user + access further by specifically allowing a user's access only from a + particular host, the entry can be specified in the form of user@host. +- AllowGroups variable gives the system administrator the option of + allowing specific groups of users to ssh into the system. The list + consists of space separated group names. Numeric group IDs are not + recognized with this variable. +- DenyUsers variable gives the system administrator the option of + denying specific users to ssh into the system. The list consists of + space separated user names. Numeric user IDs are not recognized with + this variable. If a system administrator wants to restrict user + access further by specifically denying a user's access from a + particular host, the entry can be specified in the form of user@host. +- DenyGroups variable gives the system administrator the option of + denying specific groups of users to ssh into the system. The list + consists of space separated group names. Numeric group IDs are not + recognized with this variable. + Automated remediation is not available for this configuration check +because each system has unique user names and group names. + 11 + 12 + 14 + 15 + 16 + 18 + 3 + 5 + DSS05.02 + DSS05.04 + DSS05.05 + DSS05.07 + DSS06.03 + DSS06.06 + 3.1.12 + 4.3.3.2.2 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + A.6.1.2 + A.7.1.1 + A.9.1.2 + A.9.2.1 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.2.3 + CIP-004-6 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.2 + CIP-007-3 R5.2 + CIP-007-3 R5.3.1 + CIP-007-3 R5.3.2 + CIP-007-3 R5.3.3 + AC-3 + CM-6(a) + PR.AC-4 + PR.AC-6 + PR.PT-3 + Req-2.2.4 + A.11.SEC-OL2 + 2.2.6 + 2.2 + Specifying which accounts are allowed SSH access into the system reduces the +possibility of unauthorized access to the system. + + + + + + + + + Enable SSH Print Last Log + Ensure that SSH will display the date and time of the last successful account logon. + +The default SSH configuration enables print of the date and time of the last login. +The appropriate configuration is used if no value is set for PrintLastLog. + +To explicitly enable LastLog in SSH, add or correct the following line in + + +/etc/ssh/sshd_config: + +PrintLastLog yes + + 1 + 12 + 15 + 16 + DSS05.04 + DSS05.10 + DSS06.10 + CCI-000366 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + SR 1.1 + SR 1.10 + SR 1.2 + SR 1.5 + SR 1.7 + SR 1.8 + SR 1.9 + A.18.1.4 + A.9.2.1 + A.9.2.4 + A.9.3.1 + A.9.4.2 + A.9.4.3 + AC-9 + AC-9(1) + PR.AC-7 + SRG-OS-000480-GPOS-00227 + OL09-00-002352 + SV-271715r1091857_rule + Providing users feedback on when account accesses last occurred facilitates user +recognition and reporting of unauthorized account use. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Find the include keyword, extract from the line the glob expression representing included files. +# And if it is a relative path prepend '/etc/ssh/' +included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*include\s*//I' | sed -e 's|^[^/]|/etc/ssh/&|') +for included_file in ${included_files} ; do + + LC_ALL=C sed -i "/^\s*PrintLastLog/Id" "$included_file" +done + +if [ -e "/etc/ssh/sshd_config" ] ; then + + LC_ALL=C sed -i "/^\s*PrintLastLog\s\+/Id" "/etc/ssh/sshd_config" +else + touch "/etc/ssh/sshd_config" +fi +# make sure file has newline at the end +sed -i -e '$a\' "/etc/ssh/sshd_config" + +cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +# Insert at the beginning of the file +printf '%s\n' "PrintLastLog yes" > "/etc/ssh/sshd_config" +cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +# Clean up after ourselves. +rm "/etc/ssh/sshd_config.bak" + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002352 + - NIST-800-53-AC-9 + - NIST-800-53-AC-9(1) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_print_last_log + +- name: Find sshd_config included files + shell: |- + included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') + [[ -n $included_files ]] && ls $included_files || true + register: sshd_config_included_files + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002352 + - NIST-800-53-AC-9 + - NIST-800-53-AC-9(1) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_print_last_log + +- name: Comment conf from included files + replace: + path: '{{ item }}' + regexp: ^(\s*PrintLastLog.*)$ + replace: '# \1' + loop: '{{ sshd_config_included_files.stdout_lines }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002352 + - NIST-800-53-AC-9 + - NIST-800-53-AC-9(1) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_print_last_log + +- name: Enable SSH Print Last Log + block: + + - name: Check for duplicate values + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*PrintLastLog\s+ + state: absent + check_mode: true + changed_when: false + register: dupes + + - name: Deduplicate values from /etc/ssh/sshd_config + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*PrintLastLog\s+ + state: absent + when: dupes.found is defined and dupes.found > 1 + + - name: Insert correct line to /etc/ssh/sshd_config + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*PrintLastLog\s+ + line: PrintLastLog yes + state: present + insertbefore: BOF + validate: /usr/sbin/sshd -t -f %s + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002352 + - NIST-800-53-AC-9 + - NIST-800-53-AC-9(1) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_print_last_log + + + + + + + + + + + Force frequent session key renegotiation + The RekeyLimit parameter specifies how often +the session key of the is renegotiated, both in terms of +amount of data that may be transmitted and the time +elapsed. +To decrease the default limits, add or correct the following line in + + +/etc/ssh/sshd_config: + +RekeyLimit + + + + CCI-002421 + CCI-000068 + CCI-002418 + FCS_SSH_EXT.1.8 + SRG-OS-000480-GPOS-00227 + SRG-OS-000033-GPOS-00014 + OL09-00-002342 + SV-271705r1091827_rule + By decreasing the limit based on the amount of data and enabling +time-based limit, effects of potential attacks against +encryption keys are limited. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +var_rekey_limit_size='' +var_rekey_limit_time='' + + + + +# Find the include keyword, extract from the line the glob expression representing included files. +# And if it is a relative path prepend '/etc/ssh/' +included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*include\s*//I' | sed -e 's|^[^/]|/etc/ssh/&|') +for included_file in ${included_files} ; do + + LC_ALL=C sed -i "/^\s*RekeyLimit/Id" "$included_file" +done + +if [ -e "/etc/ssh/sshd_config" ] ; then + + LC_ALL=C sed -i "/^\s*RekeyLimit\s\+/Id" "/etc/ssh/sshd_config" +else + touch "/etc/ssh/sshd_config" +fi +# make sure file has newline at the end +sed -i -e '$a\' "/etc/ssh/sshd_config" + +cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +# Insert at the beginning of the file +printf '%s\n' "RekeyLimit $var_rekey_limit_size $var_rekey_limit_time" > "/etc/ssh/sshd_config" +cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +# Clean up after ourselves. +rm "/etc/ssh/sshd_config.bak" + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002342 + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - sshd_rekey_limit +- name: XCCDF Value var_rekey_limit_size # promote to variable + set_fact: + var_rekey_limit_size: !!str + tags: + - always +- name: XCCDF Value var_rekey_limit_time # promote to variable + set_fact: + var_rekey_limit_time: !!str + tags: + - always + +- name: Find sshd_config included files + shell: |- + included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') + [[ -n $included_files ]] && ls $included_files || true + register: sshd_config_included_files + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002342 + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - sshd_rekey_limit + +- name: Comment conf from included files + replace: + path: '{{ item }}' + regexp: ^(\s*RekeyLimit.*)$ + replace: '# \1' + loop: '{{ sshd_config_included_files.stdout_lines }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002342 + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - sshd_rekey_limit + +- name: Force frequent session key renegotiation + block: + + - name: Check for duplicate values + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*RekeyLimit\s+ + state: absent + check_mode: true + changed_when: false + register: dupes + + - name: Deduplicate values from /etc/ssh/sshd_config + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*RekeyLimit\s+ + state: absent + when: dupes.found is defined and dupes.found > 1 + + - name: Insert correct line to /etc/ssh/sshd_config + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*RekeyLimit\s+ + line: RekeyLimit {{ var_rekey_limit_size }} {{ var_rekey_limit_time }} + state: present + insertbefore: BOF + validate: /usr/sbin/sshd -t -f %s + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002342 + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - sshd_rekey_limit + + + + + + + + + + + + + Ensure SSH LoginGraceTime is configured + The LoginGraceTime parameter to the SSH server specifies the time allowed for successful authentication to +the SSH server. The longer the Grace period is the more open unauthenticated connections +can exist. Like other session controls in this session the Grace Period should be limited to +appropriate limits to ensure the service is available for needed access. + 2.2.6 + 2.2 + Setting the LoginGraceTime parameter to a low number will minimize the risk of successful +brute force attacks to the SSH server. It will also limit the number of concurrent +unauthenticated connections. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +var_sshd_set_login_grace_time='' + + + +# Find the include keyword, extract from the line the glob expression representing included files. +# And if it is a relative path prepend '/etc/ssh/' +included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*include\s*//I' | sed -e 's|^[^/]|/etc/ssh/&|') +for included_file in ${included_files} ; do + + LC_ALL=C sed -i "/^\s*LoginGraceTime/Id" "$included_file" +done + +if [ -e "/etc/ssh/sshd_config" ] ; then + + LC_ALL=C sed -i "/^\s*LoginGraceTime\s\+/Id" "/etc/ssh/sshd_config" +else + touch "/etc/ssh/sshd_config" +fi +# make sure file has newline at the end +sed -i -e '$a\' "/etc/ssh/sshd_config" + +cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +# Insert at the beginning of the file +printf '%s\n' "LoginGraceTime $var_sshd_set_login_grace_time" > "/etc/ssh/sshd_config" +cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +# Clean up after ourselves. +rm "/etc/ssh/sshd_config.bak" + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_login_grace_time +- name: XCCDF Value var_sshd_set_login_grace_time # promote to variable + set_fact: + var_sshd_set_login_grace_time: !!str + tags: + - always + +- name: Find sshd_config included files + shell: |- + included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') + [[ -n $included_files ]] && ls $included_files || true + register: sshd_config_included_files + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_login_grace_time + +- name: Comment conf from included files + replace: + path: '{{ item }}' + regexp: ^(\s*LoginGraceTime.*)$ + replace: '# \1' + loop: '{{ sshd_config_included_files.stdout_lines }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_login_grace_time + +- name: Ensure SSH LoginGraceTime is configured + block: + + - name: Check for duplicate values + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*LoginGraceTime\s+ + state: absent + check_mode: true + changed_when: false + register: dupes + + - name: Deduplicate values from /etc/ssh/sshd_config + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*LoginGraceTime\s+ + state: absent + when: dupes.found is defined and dupes.found > 1 + + - name: Insert correct line to /etc/ssh/sshd_config + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*LoginGraceTime\s+ + line: LoginGraceTime {{ var_sshd_set_login_grace_time }} + state: present + insertbefore: BOF + validate: /usr/sbin/sshd -t -f %s + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_login_grace_time + + + + + + + + + + + + Set LogLevel to INFO + The INFO parameter specifices that record login and logout activity will be logged. + +The default SSH configuration sets the log level to INFO. The appropriate +configuration is used if no value is set for LogLevel. + +To explicitly specify the log level in SSH, add or correct the following line in + + +/etc/ssh/sshd_config: + +LogLevel INFO + + AC-17(a) + CM-6(a) + SSH provides several logging levels with varying amounts of verbosity. DEBUG is specifically +not recommended other than strictly for debugging SSH communications since it provides +so much data that it is difficult to identify important security information. INFO level is the +basic level that only records login activity of SSH users. In many situations, such as Incident +Response, it is important to determine when a particular user was active on a system. The +logout record can eliminate those users who disconnected, which helps narrow the field. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Find the include keyword, extract from the line the glob expression representing included files. +# And if it is a relative path prepend '/etc/ssh/' +included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*include\s*//I' | sed -e 's|^[^/]|/etc/ssh/&|') +for included_file in ${included_files} ; do + + LC_ALL=C sed -i "/^\s*LogLevel/Id" "$included_file" +done + +if [ -e "/etc/ssh/sshd_config" ] ; then + + LC_ALL=C sed -i "/^\s*LogLevel\s\+/Id" "/etc/ssh/sshd_config" +else + touch "/etc/ssh/sshd_config" +fi +# make sure file has newline at the end +sed -i -e '$a\' "/etc/ssh/sshd_config" + +cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +# Insert at the beginning of the file +printf '%s\n' "LogLevel INFO" > "/etc/ssh/sshd_config" +cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +# Clean up after ourselves. +rm "/etc/ssh/sshd_config.bak" + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - low_complexity + - low_disruption + - low_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_loglevel_info + +- name: Find sshd_config included files + shell: |- + included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') + [[ -n $included_files ]] && ls $included_files || true + register: sshd_config_included_files + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - low_complexity + - low_disruption + - low_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_loglevel_info + +- name: Comment conf from included files + replace: + path: '{{ item }}' + regexp: ^(\s*LogLevel.*)$ + replace: '# \1' + loop: '{{ sshd_config_included_files.stdout_lines }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - low_complexity + - low_disruption + - low_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_loglevel_info + +- name: Set LogLevel to INFO + block: + + - name: Check for duplicate values + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*LogLevel\s+ + state: absent + check_mode: true + changed_when: false + register: dupes + + - name: Deduplicate values from /etc/ssh/sshd_config + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*LogLevel\s+ + state: absent + when: dupes.found is defined and dupes.found > 1 + + - name: Insert correct line to /etc/ssh/sshd_config + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*LogLevel\s+ + line: LogLevel INFO + state: present + insertbefore: BOF + validate: /usr/sbin/sshd -t -f %s + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - low_complexity + - low_disruption + - low_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_loglevel_info + + + + + + + + + + + Set SSH Daemon LogLevel to VERBOSE + The VERBOSE parameter configures the SSH daemon to record login and logout activity. +To specify the log level in +SSH, add or correct the following line in + + +/etc/ssh/sshd_config: + +LogLevel VERBOSE + + CCI-000067 + CIP-007-3 R7.1 + AC-17(a) + AC-17(1) + CM-6(a) + Req-2.2.4 + SRG-OS-000032-GPOS-00013 + 2.2.6 + 2.2 + OL09-00-002340 + SV-271703r1091821_rule + SSH provides several logging levels with varying amounts of verbosity. DEBUG is specifically +not recommended other than strictly for debugging SSH communications since it provides +so much data that it is difficult to identify important security information. INFO or +VERBOSE level is the basic level that only records login activity of SSH users. In many +situations, such as Incident Response, it is important to determine when a particular user was active +on a system. The logout record can eliminate those users who disconnected, which helps narrow the +field. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Find the include keyword, extract from the line the glob expression representing included files. +# And if it is a relative path prepend '/etc/ssh/' +included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*include\s*//I' | sed -e 's|^[^/]|/etc/ssh/&|') +for included_file in ${included_files} ; do + + LC_ALL=C sed -i "/^\s*LogLevel/Id" "$included_file" +done + +if [ -e "/etc/ssh/sshd_config" ] ; then + + LC_ALL=C sed -i "/^\s*LogLevel\s\+/Id" "/etc/ssh/sshd_config" +else + touch "/etc/ssh/sshd_config" +fi +# make sure file has newline at the end +sed -i -e '$a\' "/etc/ssh/sshd_config" + +cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +# Insert at the beginning of the file +printf '%s\n' "LogLevel VERBOSE" > "/etc/ssh/sshd_config" +cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +# Clean up after ourselves. +rm "/etc/ssh/sshd_config.bak" + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002340 + - NIST-800-53-AC-17(1) + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-2.2.4 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_loglevel_verbose + +- name: Find sshd_config included files + shell: |- + included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') + [[ -n $included_files ]] && ls $included_files || true + register: sshd_config_included_files + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002340 + - NIST-800-53-AC-17(1) + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-2.2.4 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_loglevel_verbose + +- name: Comment conf from included files + replace: + path: '{{ item }}' + regexp: ^(\s*LogLevel.*)$ + replace: '# \1' + loop: '{{ sshd_config_included_files.stdout_lines }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002340 + - NIST-800-53-AC-17(1) + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-2.2.4 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_loglevel_verbose + +- name: Set SSH Daemon LogLevel to VERBOSE + block: + + - name: Check for duplicate values + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*LogLevel\s+ + state: absent + check_mode: true + changed_when: false + register: dupes + + - name: Deduplicate values from /etc/ssh/sshd_config + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*LogLevel\s+ + state: absent + when: dupes.found is defined and dupes.found > 1 + + - name: Insert correct line to /etc/ssh/sshd_config + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*LogLevel\s+ + line: LogLevel VERBOSE + state: present + insertbefore: BOF + validate: /usr/sbin/sshd -t -f %s + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002340 + - NIST-800-53-AC-17(1) + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-2.2.4 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_loglevel_verbose + + + + + + + + + + + Set SSH authentication attempt limit + The MaxAuthTries parameter specifies the maximum number of authentication attempts +permitted per connection. Once the number of failures reaches half this value, additional failures are logged. +to set MaxAUthTries edit /etc/ssh/sshd_config as follows: +MaxAuthTries + + + 0421 + 0422 + 0431 + 0974 + 1173 + 1401 + 1504 + 1505 + 1546 + 1557 + 1558 + 1559 + 1560 + 1561 + 2.2.6 + 2.2 + Setting the MaxAuthTries parameter to a low number will minimize the risk of successful +brute force attacks to the SSH server. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +sshd_max_auth_tries_value='' + + + +# Find the include keyword, extract from the line the glob expression representing included files. +# And if it is a relative path prepend '/etc/ssh/' +included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*include\s*//I' | sed -e 's|^[^/]|/etc/ssh/&|') +for included_file in ${included_files} ; do + + LC_ALL=C sed -i "/^\s*MaxAuthTries/Id" "$included_file" +done + +if [ -e "/etc/ssh/sshd_config" ] ; then + + LC_ALL=C sed -i "/^\s*MaxAuthTries\s\+/Id" "/etc/ssh/sshd_config" +else + touch "/etc/ssh/sshd_config" +fi +# make sure file has newline at the end +sed -i -e '$a\' "/etc/ssh/sshd_config" + +cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +# Insert at the beginning of the file +printf '%s\n' "MaxAuthTries $sshd_max_auth_tries_value" > "/etc/ssh/sshd_config" +cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +# Clean up after ourselves. +rm "/etc/ssh/sshd_config.bak" + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_max_auth_tries +- name: XCCDF Value sshd_max_auth_tries_value # promote to variable + set_fact: + sshd_max_auth_tries_value: !!str + tags: + - always + +- name: Find sshd_config included files + shell: |- + included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') + [[ -n $included_files ]] && ls $included_files || true + register: sshd_config_included_files + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_max_auth_tries + +- name: Comment conf from included files + replace: + path: '{{ item }}' + regexp: ^(\s*MaxAuthTries.*)$ + replace: '# \1' + loop: '{{ sshd_config_included_files.stdout_lines }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_max_auth_tries + +- name: Set SSH authentication attempt limit + block: + + - name: Check for duplicate values + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*MaxAuthTries\s+ + state: absent + check_mode: true + changed_when: false + register: dupes + + - name: Deduplicate values from /etc/ssh/sshd_config + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*MaxAuthTries\s+ + state: absent + when: dupes.found is defined and dupes.found > 1 + + - name: Insert correct line to /etc/ssh/sshd_config + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*MaxAuthTries\s+ + line: MaxAuthTries {{ sshd_max_auth_tries_value }} + state: present + insertbefore: BOF + validate: /usr/sbin/sshd -t -f %s + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_max_auth_tries + + + + + + + + + + + + Set SSH MaxSessions limit + The MaxSessions parameter specifies the maximum number of open sessions permitted +from a given connection. To set MaxSessions edit +/etc/ssh/sshd_config as follows: MaxSessions + + + 2.2.6 + 2.2 + To protect a system from denial of service due to a large number of concurrent +sessions, use the rate limiting function of MaxSessions to protect availability +of sshd logins and prevent overwhelming the daemon. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +var_sshd_max_sessions='' + + + +# Find the include keyword, extract from the line the glob expression representing included files. +# And if it is a relative path prepend '/etc/ssh/' +included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*include\s*//I' | sed -e 's|^[^/]|/etc/ssh/&|') +for included_file in ${included_files} ; do + + LC_ALL=C sed -i "/^\s*MaxSessions/Id" "$included_file" +done + +if [ -e "/etc/ssh/sshd_config" ] ; then + + LC_ALL=C sed -i "/^\s*MaxSessions\s\+/Id" "/etc/ssh/sshd_config" +else + touch "/etc/ssh/sshd_config" +fi +# make sure file has newline at the end +sed -i -e '$a\' "/etc/ssh/sshd_config" + +cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +# Insert at the beginning of the file +printf '%s\n' "MaxSessions $var_sshd_max_sessions" > "/etc/ssh/sshd_config" +cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +# Clean up after ourselves. +rm "/etc/ssh/sshd_config.bak" + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_max_sessions +- name: XCCDF Value var_sshd_max_sessions # promote to variable + set_fact: + var_sshd_max_sessions: !!str + tags: + - always + +- name: Find sshd_config included files + shell: |- + included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') + [[ -n $included_files ]] && ls $included_files || true + register: sshd_config_included_files + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_max_sessions + +- name: Comment conf from included files + replace: + path: '{{ item }}' + regexp: ^(\s*MaxSessions.*)$ + replace: '# \1' + loop: '{{ sshd_config_included_files.stdout_lines }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_max_sessions + +- name: Set SSH MaxSessions limit + block: + + - name: Check for duplicate values + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*MaxSessions\s+ + state: absent + check_mode: true + changed_when: false + register: dupes + + - name: Deduplicate values from /etc/ssh/sshd_config + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*MaxSessions\s+ + state: absent + when: dupes.found is defined and dupes.found > 1 + + - name: Insert correct line to /etc/ssh/sshd_config + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*MaxSessions\s+ + line: MaxSessions {{ var_sshd_max_sessions }} + state: present + insertbefore: BOF + validate: /usr/sbin/sshd -t -f %s + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_max_sessions + + + + + + + + + + + + Ensure SSH MaxStartups is configured + The MaxStartups parameter specifies the maximum number of concurrent unauthenticated +connections to the SSH daemon. Additional connections will be dropped until authentication +succeeds or the LoginGraceTime expires for a connection. To configure MaxStartups, you should +add or edit the following line in the /etc/ssh/sshd_config file: +MaxStartups + + + 2.2.6 + 2.2 + To protect a system from denial of service due to a large number of pending authentication +connection attempts, use the rate limiting function of MaxStartups to protect availability of +sshd logins and prevent overwhelming the daemon. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +var_sshd_set_maxstartups='' + + + +# Find the include keyword, extract from the line the glob expression representing included files. +# And if it is a relative path prepend '/etc/ssh/' +included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*include\s*//I' | sed -e 's|^[^/]|/etc/ssh/&|') +for included_file in ${included_files} ; do + + LC_ALL=C sed -i "/^\s*MaxStartups/Id" "$included_file" +done + +if [ -e "/etc/ssh/sshd_config" ] ; then + + LC_ALL=C sed -i "/^\s*MaxStartups\s\+/Id" "/etc/ssh/sshd_config" +else + touch "/etc/ssh/sshd_config" +fi +# make sure file has newline at the end +sed -i -e '$a\' "/etc/ssh/sshd_config" + +cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +# Insert at the beginning of the file +printf '%s\n' "MaxStartups $var_sshd_set_maxstartups" > "/etc/ssh/sshd_config" +cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +# Clean up after ourselves. +rm "/etc/ssh/sshd_config.bak" + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_maxstartups +- name: XCCDF Value var_sshd_set_maxstartups # promote to variable + set_fact: + var_sshd_set_maxstartups: !!str + tags: + - always + +- name: Find sshd_config included files + shell: |- + included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') + [[ -n $included_files ]] && ls $included_files || true + register: sshd_config_included_files + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_maxstartups + +- name: Comment conf from included files + replace: + path: '{{ item }}' + regexp: ^(\s*MaxStartups.*)$ + replace: '# \1' + loop: '{{ sshd_config_included_files.stdout_lines }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_maxstartups + +- name: Ensure SSH MaxStartups is configured + block: + + - name: Check for duplicate values + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*MaxStartups\s+ + state: absent + check_mode: true + changed_when: false + register: dupes + + - name: Deduplicate values from /etc/ssh/sshd_config + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*MaxStartups\s+ + state: absent + when: dupes.found is defined and dupes.found > 1 + + - name: Insert correct line to /etc/ssh/sshd_config + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*MaxStartups\s+ + line: MaxStartups {{ var_sshd_set_maxstartups }} + state: present + insertbefore: BOF + validate: /usr/sbin/sshd -t -f %s + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_maxstartups + + + + + + + + + + + + Distribute the SSH Server configuration to multiple files in a config directory. + Make sure to have the Include /etc/ssh/sshd_config.d/*.conf line in the /etc/ssh/sshd_config file. +Ideally, don't have any active configuration directives in that file, and distribute the service configuration +to several files in the /etc/ssh/sshd_config.d directory. + 164.312(a) + FCS_SSH_EXT.1 + This form of distributed configuration is considered as a good practice, and as other sshd rules assume that directives in files in the /etc/ssh/sshd_config.d config directory are effective, there has to be a rule that ensures this. +Aside from that, having multiple configuration files makes the SSH Server configuration changes easier to partition according to the reason that they were introduced, and therefore it should help to perform merges of hardening updates. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +if test -f /etc/ssh/sshd_config.d/sshd_config_original.conf; then + printf '%s\n' "Remediation probably already happened, '/etc/ssh/sshd_config.d/sshd_config_original.conf' already exists, not doing anything." >&2 +false 1 +elif grep -Eq '^\s*Include\s+/etc/ssh/sshd_config\.d/\*\.conf' /etc/ssh/sshd_config && ! grep -Eq '^\s*Match\s' /etc/ssh/sshd_config; then + printf '%s\n' "Remediation probably already happened, '/etc/ssh/sshd_config' already contains the include directive." >&2 +false 1 +else + mkdir -p /etc/ssh/sshd_config.d + mv /etc/ssh/sshd_config /etc/ssh/sshd_config.d/sshd_config_original.conf +cat > /etc/ssh/sshd_config << EOF +# To modify the system-wide sshd configuration, create a *.conf file under +# /etc/ssh/sshd_config.d/ which will be automatically included below + +Include /etc/ssh/sshd_config.d/*.conf +EOF +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + + + + + + + + + + Enable Use of Privilege Separation + When enabled, SSH will create an unprivileged child process that +has the privilege of the authenticated user. To enable privilege separation in +SSH, add or correct the following line in the /etc/ssh/sshd_config file: +UsePrivilegeSeparation + + + 12 + 13 + 14 + 15 + 16 + 18 + 3 + 5 + APO01.06 + DSS05.04 + DSS05.07 + DSS06.02 + 3.1.12 + CCI-000366 + 164.308(a)(4)(i) + 164.308(b)(1) + 164.308(b)(3) + 164.310(b) + 164.312(e)(1) + 164.312(e)(2)(ii) + 4.3.3.7.3 + SR 2.1 + SR 5.2 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 + CM-6(a) + AC-17(a) + AC-6 + PR.AC-4 + PR.DS-5 + SRG-OS-000480-GPOS-00227 + SSH daemon privilege separation causes the SSH process to drop root privileges +when not needed which would decrease the impact of software vulnerabilities in +the unprivileged section. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +var_sshd_priv_separation='' + + + +# Find the include keyword, extract from the line the glob expression representing included files. +# And if it is a relative path prepend '/etc/ssh/' +included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*include\s*//I' | sed -e 's|^[^/]|/etc/ssh/&|') +for included_file in ${included_files} ; do + + LC_ALL=C sed -i "/^\s*UsePrivilegeSeparation/Id" "$included_file" +done + +if [ -e "/etc/ssh/sshd_config" ] ; then + + LC_ALL=C sed -i "/^\s*UsePrivilegeSeparation\s\+/Id" "/etc/ssh/sshd_config" +else + touch "/etc/ssh/sshd_config" +fi +# make sure file has newline at the end +sed -i -e '$a\' "/etc/ssh/sshd_config" + +cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +# Insert at the beginning of the file +printf '%s\n' "UsePrivilegeSeparation $var_sshd_priv_separation" > "/etc/ssh/sshd_config" +cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +# Clean up after ourselves. +rm "/etc/ssh/sshd_config.bak" + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-6 + - NIST-800-53-CM-6(a) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_use_priv_separation +- name: XCCDF Value var_sshd_priv_separation # promote to variable + set_fact: + var_sshd_priv_separation: !!str + tags: + - always + +- name: Find sshd_config included files + shell: |- + included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') + [[ -n $included_files ]] && ls $included_files || true + register: sshd_config_included_files + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-6 + - NIST-800-53-CM-6(a) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_use_priv_separation + +- name: Comment conf from included files + replace: + path: '{{ item }}' + regexp: ^(\s*UsePrivilegeSeparation.*)$ + replace: '# \1' + loop: '{{ sshd_config_included_files.stdout_lines }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-6 + - NIST-800-53-CM-6(a) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_use_priv_separation + +- name: Enable Use of Privilege Separation + block: + + - name: Check for duplicate values + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*UsePrivilegeSeparation\s+ + state: absent + check_mode: true + changed_when: false + register: dupes + + - name: Deduplicate values from /etc/ssh/sshd_config + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*UsePrivilegeSeparation\s+ + state: absent + when: dupes.found is defined and dupes.found > 1 + + - name: Insert correct line to /etc/ssh/sshd_config + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*UsePrivilegeSeparation\s+ + line: UsePrivilegeSeparation {{ var_sshd_priv_separation }} + state: present + insertbefore: BOF + validate: /usr/sbin/sshd -t -f %s + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-6 + - NIST-800-53-CM-6(a) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_use_priv_separation + + + + + + + + + + + + Use Only Strong MACs + Limit the MACs to strong hash algorithms. +The following line in /etc/ssh/sshd_config demonstrates use +of those MACs: +MACs + + + CCI-001453 + AC-17 (2) + SRG-OS-000250-GPOS-00093 + OL09-00-000262 + SV-271490r1092628_rule + MD5 and 96-bit MAC algorithms are considered weak and have been shown to increase +exploitability in SSH downgrade attacks. Weak algorithms continue to have a great deal of +attention as a weak spot that can be exploited with expanded computing power. An +attacker that breaks the algorithm could take advantage of a MiTM position to decrypt the +SSH tunnel and capture credentials and information + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +sshd_strong_macs='' + + +# Strip any search characters in the key arg so that the key can be replaced without +# adding any search characters to the config file. +stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^MACs") + +# shellcheck disable=SC2059 +printf -v formatted_output "%s %s" "$stripped_key" "$sshd_strong_macs" + +# If the key exists, change it. Otherwise, add it to the config_file. +# We search for the key string followed by a word boundary (matched by \>), +# so if we search for 'setting', 'setting2' won't match. +if LC_ALL=C grep -q -m 1 -i -e "^MACs\\>" "/etc/ssh/sshd_config"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + LC_ALL=C sed -i --follow-symlinks "s/^MACs\\>.*/$escaped_formatted_output/gi" "/etc/ssh/sshd_config" +else + if [[ -s "/etc/ssh/sshd_config" ]] && [[ -n "$(tail -c 1 -- "/etc/ssh/sshd_config" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "/etc/ssh/sshd_config" + fi + printf '%s\n' "$formatted_output" >> "/etc/ssh/sshd_config" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-000262 + - NIST-800-53-AC-17 (2) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_use_strong_macs +- name: XCCDF Value sshd_strong_macs # promote to variable + set_fact: + sshd_strong_macs: !!str + tags: + - always + +- name: Find sshd_config included files + shell: |- + included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') + [[ -n $included_files ]] && ls $included_files || true + register: sshd_config_included_files + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-000262 + - NIST-800-53-AC-17 (2) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_use_strong_macs + +- name: Comment conf from included files + replace: + path: '{{ item }}' + regexp: ^(\s*MACs.*)$ + replace: '# \1' + loop: '{{ sshd_config_included_files.stdout_lines }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-000262 + - NIST-800-53-AC-17 (2) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_use_strong_macs + +- name: Use Only Strong MACs + block: + + - name: Check for duplicate values + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*MACs\s+ + state: absent + check_mode: true + changed_when: false + register: dupes + + - name: Deduplicate values from /etc/ssh/sshd_config + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*MACs\s+ + state: absent + when: dupes.found is defined and dupes.found > 1 + + - name: Insert correct line to /etc/ssh/sshd_config + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*MACs\s+ + line: MACs {{ sshd_strong_macs }} + state: present + insertbefore: BOF + validate: /usr/sbin/sshd -t -f %s + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-000262 + - NIST-800-53-AC-17 (2) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_use_strong_macs + + + + + + + + + + + + Prevent remote hosts from connecting to the proxy display + The SSH daemon should prevent remote hosts from connecting to the proxy +display. + +The default SSH configuration for X11UseLocalhost is yes, +which prevents remote hosts from connecting to the proxy display. + +To explicitly prevent remote connections to the proxy display, add or correct +the following line in + + +/etc/ssh/sshd_config: + +X11UseLocalhost yes + + CCI-000366 + CM-6(b) + SRG-OS-000480-GPOS-00227 + OL09-00-002354 + SV-271716r1091860_rule + When X11 forwarding is enabled, there may be additional exposure to the +server and client displays if the sshd proxy display is configured to listen +on the wildcard address. By default, sshd binds the forwarding server to the +loopback address and sets the hostname part of the DISPLAY +environment variable to localhost. This prevents remote hosts from +connecting to the proxy display. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Find the include keyword, extract from the line the glob expression representing included files. +# And if it is a relative path prepend '/etc/ssh/' +included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*include\s*//I' | sed -e 's|^[^/]|/etc/ssh/&|') +for included_file in ${included_files} ; do + + LC_ALL=C sed -i "/^\s*X11UseLocalhost/Id" "$included_file" +done + +if [ -e "/etc/ssh/sshd_config" ] ; then + + LC_ALL=C sed -i "/^\s*X11UseLocalhost\s\+/Id" "/etc/ssh/sshd_config" +else + touch "/etc/ssh/sshd_config" +fi +# make sure file has newline at the end +sed -i -e '$a\' "/etc/ssh/sshd_config" + +cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +# Insert at the beginning of the file +printf '%s\n' "X11UseLocalhost yes" > "/etc/ssh/sshd_config" +cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +# Clean up after ourselves. +rm "/etc/ssh/sshd_config.bak" + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002354 + - NIST-800-53-CM-6(b) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_x11_use_localhost + +- name: Find sshd_config included files + shell: |- + included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') + [[ -n $included_files ]] && ls $included_files || true + register: sshd_config_included_files + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002354 + - NIST-800-53-CM-6(b) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_x11_use_localhost + +- name: Comment conf from included files + replace: + path: '{{ item }}' + regexp: ^(\s*X11UseLocalhost.*)$ + replace: '# \1' + loop: '{{ sshd_config_included_files.stdout_lines }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002354 + - NIST-800-53-CM-6(b) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_x11_use_localhost + +- name: Prevent remote hosts from connecting to the proxy display + block: + + - name: Check for duplicate values + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*X11UseLocalhost\s+ + state: absent + check_mode: true + changed_when: false + register: dupes + + - name: Deduplicate values from /etc/ssh/sshd_config + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*X11UseLocalhost\s+ + state: absent + when: dupes.found is defined and dupes.found > 1 + + - name: Insert correct line to /etc/ssh/sshd_config + lineinfile: + path: /etc/ssh/sshd_config + create: true + regexp: (?i)(?i)^\s*X11UseLocalhost\s+ + line: X11UseLocalhost yes + state: present + insertbefore: BOF + validate: /usr/sbin/sshd -t -f %s + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002354 + - NIST-800-53-CM-6(b) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_x11_use_localhost + + + + + + + + + + + + + System Security Services Daemon + The System Security Services Daemon (SSSD) is a system daemon that provides access +to different identity and authentication providers such as Red Hat's IdM, Microsoft's AD, +openLDAP, MIT Kerberos, etc. It uses a common framework that can provide caching and offline +support to systems utilizing SSSD. SSSD using caching to reduce load on authentication +servers permit offline authentication as well as store extended user data. + + +For more information, see + https://docs.oracle.com/en/operating-systems/oracle-linux/9/userauth/userauth-UsingtheSystemSecurityServicesDaemon.html + + + + SSSD certificate_verification option + Value of the certificate_verification option in +the SSSD config. + sha1 + sha256 + sha384 + sha512 + sha1 + + + Install the SSSD Package + The sssd package should be installed. +The sssd package can be installed with the following command: + +$ sudo yum install sssd + + 1 + 12 + 15 + 16 + 5 + DSS05.04 + DSS05.05 + DSS05.07 + DSS05.10 + DSS06.03 + DSS06.10 + 4.3.3.2.2 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.2 + 4.3.3.7.4 + SR 1.1 + SR 1.10 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + A.18.1.4 + A.7.1.1 + A.9.2.1 + A.9.2.2 + A.9.2.3 + A.9.2.4 + A.9.2.6 + A.9.3.1 + A.9.4.2 + A.9.4.3 + CM-6(a) + PR.AC-1 + PR.AC-6 + PR.AC-7 + R67 + + # Remediation is applicable only in certain platforms +if rpm --quiet -q sssd-common; then + +if ! rpm -q --quiet "sssd" ; then + yum install -y "sssd" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-53-CM-6(a) + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - package_sssd_installed + +- name: Ensure sssd is installed + package: + name: sssd + state: present + when: '"sssd-common" in ansible_facts.packages' + tags: + - NIST-800-53-CM-6(a) + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - package_sssd_installed + + include install_sssd + +class install_sssd { + package { 'sssd': + ensure => 'installed', + } +} + + +package --add=sssd + + +[[packages]] +name = "sssd" +version = "*" + + + + + + + + + + Enable the SSSD Service + The SSSD service should be enabled. + +The sssd service can be enabled with the following command: +$ sudo systemctl enable sssd.service + + The service requires a valid sssd configuration. If the configuration is not present, the service will fail to start and consequently this rule will be reported as failing. The configuration shipped in your distribution package might not be sufficient. Manual modification of configuration files might be required. + 1 + 12 + 15 + 16 + 5 + DSS05.04 + DSS05.05 + DSS05.07 + DSS05.10 + DSS06.03 + DSS06.10 + 4.3.3.2.2 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.2 + 4.3.3.7.4 + SR 1.1 + SR 1.10 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + A.18.1.4 + A.7.1.1 + A.9.2.1 + A.9.2.2 + A.9.2.3 + A.9.2.4 + A.9.2.6 + A.9.3.1 + A.9.4.2 + A.9.4.3 + CM-6(a) + IA-5(10) + PR.AC-1 + PR.AC-6 + PR.AC-7 + R67 + + + # Remediation is applicable only in certain platforms +if rpm --quiet -q sssd-common && { rpm --quiet -q kernel || rpm --quiet -q kernel-uek; }; then + +SYSTEMCTL_EXEC='/usr/bin/systemctl' +"$SYSTEMCTL_EXEC" unmask 'sssd.service' +if [[ $("$SYSTEMCTL_EXEC" is-system-running) != "offline" ]]; then + "$SYSTEMCTL_EXEC" start 'sssd.service' +fi +"$SYSTEMCTL_EXEC" enable 'sssd.service' + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(10) + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_sssd_enabled + +- name: Enable the SSSD Service - Enable service sssd + block: + + - name: Gather the package facts + package_facts: + manager: auto + + - name: Enable the SSSD Service - Enable Service sssd + ansible.builtin.systemd: + name: sssd + enabled: true + state: started + masked: false + when: + - '"sssd-common" in ansible_facts.packages' + when: + - '"sssd-common" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(10) + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_sssd_enabled + + include enable_sssd + +class enable_sssd { + service {'sssd': + enable => true, + ensure => 'running', + } +} + + +[customizations.services] +enabled = ["sssd"] + + + + + + + + + + Certificate status checking in SSSD + Multifactor solutions that require devices separate from information systems gaining access include, +for example, hardware tokens providing time-based or challenge-response authenticators and smart cards. +Configuring certificate_verification to ocsp_dgst= + ensures that certificates for +multifactor solutions are checked via Online Certificate Status Protocol (OCSP). + CCI-001954 + CCI-004046 + IA-2(11) + SRG-OS-000375-GPOS-00160 + SRG-OS-000377-GPOS-00162 + OL09-00-000930 + SV-271608r1091536_rule + Ensuring that multifactor solutions certificates are checked via Online Certificate Status Protocol (OCSP) +ensures the security of the system. + # Remediation is applicable only in certain platforms +if rpm --quiet -q sssd-common; then + +var_sssd_certificate_verification_digest_function='' + + +# sssd configuration files must be created with 600 permissions if they don't exist +# otherwise the sssd module fails to start +OLD_UMASK=$(umask) +umask u=rw,go= + +MAIN_CONF="/etc/sssd/conf.d/certificate_verification.conf" + +found=false + +# set value in all files if they contain section or key +for f in $(echo -n "$MAIN_CONF /etc/sssd/sssd.conf /etc/sssd/conf.d/*.conf"); do + if [ ! -e "$f" ]; then + continue + fi + + # find key in section and change value + if grep -qzosP "[[:space:]]*\[sssd\]([^\n\[]*\n+)+?[[:space:]]*certificate_verification" "$f"; then + + sed -i "s/certificate_verification[^(\n)]*/certificate_verification=ocsp_dgst=$var_sssd_certificate_verification_digest_function/" "$f" + + found=true + + # find section and add key = value to it + elif grep -qs "[[:space:]]*\[sssd\]" "$f"; then + + sed -i "/[[:space:]]*\[sssd\]/a certificate_verification=ocsp_dgst=$var_sssd_certificate_verification_digest_function" "$f" + + found=true + fi +done + +# if section not in any file, append section with key = value to FIRST file in files parameter +if ! $found ; then + file=$(echo "$MAIN_CONF /etc/sssd/sssd.conf /etc/sssd/conf.d/*.conf" | cut -f1 -d ' ') + mkdir -p "$(dirname "$file")" + + echo -e "[sssd]\ncertificate_verification=ocsp_dgst=$var_sssd_certificate_verification_digest_function" >> "$file" + +fi + +umask $OLD_UMASK + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-000930 + - NIST-800-53-IA-2(11) + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - sssd_certificate_verification +- name: XCCDF Value var_sssd_certificate_verification_digest_function # promote to variable + set_fact: + var_sssd_certificate_verification_digest_function: !!str + tags: + - always + +- name: Ensure that "certificate_verification" is not set in /etc/sssd/sssd.conf + ini_file: + path: /etc/sssd/sssd.conf + section: sssd + option: certificate_verification + state: absent + mode: 384 + when: '"sssd-common" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-000930 + - NIST-800-53-IA-2(11) + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - sssd_certificate_verification + +- name: Ensure that "certificate_verification" is not set in /etc/sssd/conf.d/*.conf + ini_file: + path: /etc/sssd/conf.d/*.conf + section: sssd + option: certificate_verification + state: absent + mode: 384 + when: '"sssd-common" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-000930 + - NIST-800-53-IA-2(11) + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - sssd_certificate_verification + +- name: Ensure that "certificate_verification" is set + ini_file: + path: /etc/sssd/conf.d/certificate_verification.conf + section: sssd + option: certificate_verification + value: ocsp_dgst={{ var_sssd_certificate_verification_digest_function }} + state: present + mode: 384 + when: '"sssd-common" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-000930 + - NIST-800-53-IA-2(11) + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - sssd_certificate_verification + + + + + + + + + + + Enable Certmap in SSSD + SSSD should be configured to verify the certificate of the user or group. To set this up + ensure that section like certmap/testing.test/rule_name is setup in +/etc/sssd/sssd.conf. For example + +[certmap/testing.test/rule_name] +matchrule =<SAN>.*EDIPI@mil +maprule = (userCertificate;binary={cert!bin}) +domains = testing.test + + + Automatic remediation of this control is not available, since all of the settings in +in the certmap need to be customized. + CCI-000187 + IA-5 (2) (c) + SRG-OS-000068-GPOS-00036 + OL09-00-000910 + SV-271606r1091530_rule + Without mapping the certificate used to authenticate to the user account, the ability to +determine the identity of the individual user or group will not be available for forensic +analysis. + + + + + + + + + Configure PAM in SSSD Services + SSSD should be configured to run SSSD pam services. +To configure SSSD to known SSH hosts, add pam +to services under the [sssd] section in +/etc/sssd/sssd.conf. For example: +[sssd] +services = sudo, autofs, pam + + + 1 + 12 + 15 + 16 + 5 + DSS05.04 + DSS05.05 + DSS05.07 + DSS05.10 + DSS06.03 + DSS06.10 + CCI-004046 + CCI-001953 + CCI-001954 + 4.3.3.2.2 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.2 + 4.3.3.7.4 + SR 1.1 + SR 1.10 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + A.18.1.4 + A.7.1.1 + A.9.2.1 + A.9.2.2 + A.9.2.3 + A.9.2.4 + A.9.2.6 + A.9.3.1 + A.9.4.2 + A.9.4.3 + IA-2(1) + CM-6(a) + PR.AC-1 + PR.AC-6 + PR.AC-7 + SRG-OS-000375-GPOS-00160 + SRG-OS-000376-GPOS-00161 + SRG-OS-000377-GPOS-00162 + R67 + Using an authentication device, such as a CAC or token that is separate from +the information system, ensures that even if the information system is +compromised, that compromise will not affect credentials stored on the +authentication device. + # Remediation is applicable only in certain platforms +if rpm --quiet -q sssd-common; then + +# sssd configuration files must be created with 600 permissions if they don't exist +# otherwise the sssd module fails to start +OLD_UMASK=$(umask) +umask u=rw,go= + +SSSD_CONF="/etc/sssd/sssd.conf" +SSSD_CONF_DIR="/etc/sssd/conf.d/*.conf" + +if [ ! -f "$SSSD_CONF" ] && [ ! -f "$SSSD_CONF_DIR" ]; then + mkdir -p /etc/sssd + touch "$SSSD_CONF" +fi + +# Flag to check if there is already services with pam +service_already_exist=false +for f in $SSSD_CONF $SSSD_CONF_DIR; do + if [ ! -e "$f" ]; then + continue + fi + # finds all services entries under [sssd] configuration category, get a unique list so it doesn't add redundant fix + services_list=$( awk '/^\s*\[/{f=0} /^\s*\[sssd\]/{f=1}f' $f | grep -P '^services[ \t]*=' | uniq ) + if [ -z "$services_list" ]; then + continue + fi + + while IFS= read -r services; do + if [[ ! $services =~ "pam" ]]; then + sed -i "s/$services$/&, pam/" $f + fi + # Either pam service was already there or got added now + service_already_exist=true + done <<< "$services_list" + +done + +# If there was no service in [sssd], add it to first config +if [ "$service_already_exist" = false ]; then + for f in $SSSD_CONF $SSSD_CONF_DIR; do + cat << EOF >> "$f" +[sssd] +services = pam +EOF + break + done +fi + +umask $OLD_UMASK + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-2(1) + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - sssd_enable_pam_services + +- name: Configure PAM in SSSD Services - Find all the conf files inside the /etc/sssd/conf.d/ + directory + ansible.builtin.find: + paths: + - /etc/sssd/conf.d/ + patterns: '*.conf' + register: sssd_conf_d_files + when: '"sssd-common" in ansible_facts.packages' + tags: + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-2(1) + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - sssd_enable_pam_services + +- name: Configure PAM in SSSD Services - Modify lines in files in the /etc/sssd/conf.d/ + directory + ansible.builtin.replace: + path: '{{ item }}' + regexp: ^(\s*\[sssd\].*(?:\n\s*[^[\s].*)*\n\s*services\s*=(?!.*\bpam\b).*)$ + replace: \1,pam + with_items: '{{ sssd_conf_d_files.files | map(attribute=''path'') }}' + register: modify_lines_sssd_conf_d_files + when: + - '"sssd-common" in ansible_facts.packages' + - sssd_conf_d_files.matched is defined and sssd_conf_d_files.matched >= 1 + tags: + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-2(1) + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - sssd_enable_pam_services + +- name: Configure PAM in SSSD Services - Find /etc/sssd/sssd.conf + ansible.builtin.stat: + path: /etc/sssd/sssd.conf + register: sssd_conf_file + when: '"sssd-common" in ansible_facts.packages' + tags: + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-2(1) + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - sssd_enable_pam_services + +- name: Configure PAM in SSSD Services - Modify lines in /etc/sssd/sssd.conf + ansible.builtin.replace: + path: /etc/sssd/sssd.conf + regexp: ^(\s*\[sssd\].*(?:\n\s*[^[\s].*)*\n\s*services\s*=(?!.*\bpam\b).*)$ + replace: \1,pam + register: modify_lines_sssd_conf_file + when: + - '"sssd-common" in ansible_facts.packages' + - sssd_conf_file.stat.exists + tags: + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-2(1) + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - sssd_enable_pam_services + +- name: Configure PAM in SSSD Services - Find services key in /etc/sssd/sssd.conf + ansible.builtin.replace: + path: /etc/sssd/sssd.conf + regexp: ^\s*\[sssd\][^\[\]]*?(?:\n(?!\[)[^\n]*?services\s*=)+ + replace: '' + changed_when: false + check_mode: true + register: sssd_conf_file_services + when: + - '"sssd-common" in ansible_facts.packages' + - sssd_conf_file.stat.exists + tags: + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-2(1) + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - sssd_enable_pam_services + +- name: Configure PAM in SSSD Services - Insert entry to /etc/sssd/sssd.conf + ini_file: + path: /etc/sssd/sssd.conf + section: sssd + option: services + value: pam + when: + - '"sssd-common" in ansible_facts.packages' + - not modify_lines_sssd_conf_d_files.changed + - not modify_lines_sssd_conf_file.changed + - (sssd_conf_file_services.msg is defined and "replacements" not in sssd_conf_file_services.msg) + or not sssd_conf_file.stat.exists + tags: + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-2(1) + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - sssd_enable_pam_services + + + + + + + + + + Enable Smartcards in SSSD + SSSD should be configured to authenticate access to the system using smart cards. +To enable smart cards in SSSD, set pam_cert_auth to True under the +[pam] section in /etc/sssd/sssd.conf. For example: +[pam] +pam_cert_auth = True + + +Add or update "pam_sss.so" line in auth section of "/etc/pam.d/system-auth" file to include +"try_cert_auth" or "require_cert_auth" option, like in the following example: + +/etc/pam.d/system-auth:auth [success=done authinfo_unavail=ignore ignore=ignore default=die] pam_sss.so try_cert_auth + +Also add or update "pam_sss.so" line in auth section of "/etc/pam.d/smartcard-auth" file to +include the "allow_missing_name" option, like in the following example: +/etc/pam.d/smartcard-auth:auth sufficient pam_sss.so allow_missing_name + + CCI-000765 + CCI-004047 + CCI-004046 + 0421 + 0422 + 0431 + 0974 + 1173 + 1401 + 1504 + 1505 + 1546 + 1557 + 1558 + 1559 + 1560 + 1561 + Req-8.3 + SRG-OS-000375-GPOS-00160 + SRG-OS-000105-GPOS-00052 + SRG-OS-000106-GPOS-00053 + SRG-OS-000107-GPOS-00054 + SRG-OS-000108-GPOS-00055 + OL09-00-000925 + SV-271607r1091533_rule + Using an authentication device, such as a CAC or token that is separate from +the information system, ensures that even if the information system is +compromised, that compromise will not affect credentials stored on the +authentication device. + + +Multi-Factor Authentication (MFA) solutions that require devices separate from +information systems gaining access include, for example, hardware tokens +providing time-based or challenge-response authenticators and smart cards such +as the U.S. Government Personal Identity Verification card and the DoD Common +Access Card. + # Remediation is applicable only in certain platforms +if rpm --quiet -q sssd-common; then + +# sssd configuration files must be created with 600 permissions if they don't exist +# otherwise the sssd module fails to start +OLD_UMASK=$(umask) +umask u=rw,go= + +found=false + +# set value in all files if they contain section or key +for f in $(echo -n "/etc/sssd/sssd.conf /etc/sssd/conf.d/*.conf"); do + if [ ! -e "$f" ]; then + continue + fi + + # find key in section and change value + if grep -qzosP "[[:space:]]*\[pam\]([^\n\[]*\n+)+?[[:space:]]*pam_cert_auth" "$f"; then + + sed -i "s/pam_cert_auth[^(\n)]*/pam_cert_auth=True/" "$f" + + found=true + + # find section and add key = value to it + elif grep -qs "[[:space:]]*\[pam\]" "$f"; then + + sed -i "/[[:space:]]*\[pam\]/a pam_cert_auth=True" "$f" + + found=true + fi +done + +# if section not in any file, append section with key = value to FIRST file in files parameter +if ! $found ; then + file=$(echo "/etc/sssd/sssd.conf /etc/sssd/conf.d/*.conf" | cut -f1 -d ' ') + mkdir -p "$(dirname "$file")" + + echo -e "[pam]\npam_cert_auth=True" >> "$file" + +fi + +umask $OLD_UMASK + + +if [ -f /usr/bin/authselect ]; then + if ! authselect check; then + echo " + authselect integrity check failed. Remediation aborted! + This remediation could not be applied because an authselect profile was not selected or the selected profile is not intact. + It is not recommended to manually edit the PAM files when authselect tool is available. + In cases where the default authselect profile does not cover a specific demand, a custom authselect profile is recommended." + exit 1 + fi + authselect enable-feature with-smartcard + + authselect apply-changes -b +else + + + if ! grep -qP "^\s*auth\s+sufficient\s+pam_sss.so\s*.*" "/etc/pam.d/smartcard-auth"; then + # Line matching group + control + module was not found. Check group + module. + if [ "$(grep -cP '^\s*auth\s+.*\s+pam_sss.so\s*' "/etc/pam.d/smartcard-auth")" -eq 1 ]; then + # The control is updated only if one single line matches. + sed -i -E --follow-symlinks "s/^(\s*auth\s+).*(\bpam_sss.so.*)/\1sufficient \2/" "/etc/pam.d/smartcard-auth" + else + echo "auth sufficient pam_sss.so" >> "/etc/pam.d/smartcard-auth" + fi + fi + # Check the option + if ! grep -qP "^\s*auth\s+sufficient\s+pam_sss.so\s*.*\sallow_missing_name\b" "/etc/pam.d/smartcard-auth"; then + sed -i -E --follow-symlinks "/\s*auth\s+sufficient\s+pam_sss.so.*/ s/$/ allow_missing_name/" "/etc/pam.d/smartcard-auth" + fi + + + if ! grep -qP "^\s*auth\s+\[success=done authinfo_unavail=ignore ignore=ignore default=die\]\s+pam_sss.so\s*.*" "/etc/pam.d/system-auth"; then + # Line matching group + control + module was not found. Check group + module. + if [ "$(grep -cP '^\s*auth\s+.*\s+pam_sss.so\s*' "/etc/pam.d/system-auth")" -eq 1 ]; then + # The control is updated only if one single line matches. + sed -i -E --follow-symlinks "s/^(\s*auth\s+).*(\bpam_sss.so.*)/\1[success=done authinfo_unavail=ignore ignore=ignore default=die] \2/" "/etc/pam.d/system-auth" + else + echo "auth [success=done authinfo_unavail=ignore ignore=ignore default=die] pam_sss.so" >> "/etc/pam.d/system-auth" + fi + fi + # Check the option + if ! grep -qP "^\s*auth\s+\[success=done authinfo_unavail=ignore ignore=ignore default=die\]\s+pam_sss.so\s*.*\stry_cert_auth\b" "/etc/pam.d/system-auth"; then + sed -i -E --follow-symlinks "/\s*auth\s+\[success=done authinfo_unavail=ignore ignore=ignore default=die\]\s+pam_sss.so.*/ s/$/ try_cert_auth/" "/etc/pam.d/system-auth" + fi +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-000925 + - PCI-DSS-Req-8.3 + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - sssd_enable_smartcards + +- name: Test for domain group + command: grep '^\s*\[domain\/[^]]*]' /etc/sssd/sssd.conf + register: test_grep_domain + failed_when: false + changed_when: false + check_mode: false + when: '"sssd-common" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-000925 + - PCI-DSS-Req-8.3 + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - sssd_enable_smartcards + +- name: Add default domain group (if no domain there) + ini_file: + path: /etc/sssd/sssd.conf + section: '{{ item.section }}' + option: '{{ item.option }}' + value: '{{ item.value }}' + create: true + mode: 384 + with_items: + - section: sssd + option: domains + value: default + - section: domain/default + option: id_provider + value: files + when: + - '"sssd-common" in ansible_facts.packages' + - test_grep_domain.stdout is defined + - test_grep_domain.stdout | length < 1 + tags: + - DISA-STIG-OL09-00-000925 + - PCI-DSS-Req-8.3 + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - sssd_enable_smartcards + +- name: Enable Smartcards in SSSD + ini_file: + dest: /etc/sssd/sssd.conf + section: pam + option: pam_cert_auth + value: 'True' + create: true + mode: 384 + when: '"sssd-common" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-000925 + - PCI-DSS-Req-8.3 + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - sssd_enable_smartcards + +- name: Find all the conf files inside /etc/sssd/conf.d/ + find: + paths: /etc/sssd/conf.d/ + patterns: '*.conf' + register: sssd_conf_d_files + when: '"sssd-common" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-000925 + - PCI-DSS-Req-8.3 + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - sssd_enable_smartcards + +- name: Fix pam_cert_auth configuration in /etc/sssd/conf.d/ + ansible.builtin.replace: + path: '{{ item.path }}' + regexp: '[^#]*pam_cert_auth.*' + replace: pam_cert_auth = True + with_items: '{{ sssd_conf_d_files.files }}' + when: '"sssd-common" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-000925 + - PCI-DSS-Req-8.3 + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - sssd_enable_smartcards + +- name: Enable Smartcards in SSSD - Check if system relies on authselect + ansible.builtin.stat: + path: /usr/bin/authselect + register: result_authselect_present + when: '"sssd-common" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-000925 + - PCI-DSS-Req-8.3 + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - sssd_enable_smartcards + +- name: Enable Smartcards in SSSD - Remediate using authselect + block: + + - name: Enable Smartcards in SSSD - Check integrity of authselect current profile + ansible.builtin.command: + cmd: authselect check + register: result_authselect_check_cmd + changed_when: false + failed_when: false + + - name: Enable Smartcards in SSSD - Informative message based on the authselect + integrity check result + ansible.builtin.assert: + that: + - result_authselect_check_cmd.rc == 0 + fail_msg: + - authselect integrity check failed. Remediation aborted! + - This remediation could not be applied because an authselect profile was not + selected or the selected profile is not intact. + - It is not recommended to manually edit the PAM files when authselect tool + is available. + - In cases where the default authselect profile does not cover a specific demand, + a custom authselect profile is recommended. + success_msg: + - authselect integrity check passed + + - name: Enable Smartcards in SSSD - Get authselect current features + ansible.builtin.shell: + cmd: authselect current | tail -n+3 | awk '{ print $2 }' + register: result_authselect_features + changed_when: false + when: + - result_authselect_check_cmd is success + + - name: Enable Smartcards in SSSD - Ensure "with-smartcard" feature is enabled using + authselect tool + ansible.builtin.command: + cmd: authselect enable-feature with-smartcard + register: result_authselect_enable_feature_cmd + when: + - result_authselect_check_cmd is success + - result_authselect_features.stdout is not search("with-smartcard") + + - name: Enable Smartcards in SSSD - Ensure authselect changes are applied + ansible.builtin.command: + cmd: authselect apply-changes -b + when: + - result_authselect_enable_feature_cmd is not skipped + - result_authselect_enable_feature_cmd is success + when: + - '"sssd-common" in ansible_facts.packages' + - result_authselect_present.stat.exists + tags: + - DISA-STIG-OL09-00-000925 + - PCI-DSS-Req-8.3 + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - sssd_enable_smartcards + +- name: Enable Smartcards in SSSD - Remediate by directly editing PAM files + block: + + - name: Enable Smartcards in SSSD - Define a fact for control already filtered in + case filters are used + ansible.builtin.set_fact: + pam_module_control: sufficient + + - name: Enable Smartcards in SSSD - Check if expected PAM module line is present + in /etc/pam.d/smartcard-auth + ansible.builtin.lineinfile: + path: /etc/pam.d/smartcard-auth + regexp: ^\s*auth\s+{{ pam_module_control | regex_escape() }}\s+pam_sss.so\s*.* + state: absent + check_mode: true + changed_when: false + register: result_pam_line_present + + - name: Enable Smartcards in SSSD - Include or update the PAM module line in /etc/pam.d/smartcard-auth + block: + + - name: Enable Smartcards in SSSD - Check if required PAM module line is present + in /etc/pam.d/smartcard-auth with different control + ansible.builtin.lineinfile: + path: /etc/pam.d/smartcard-auth + regexp: ^\s*auth\s+.*\s+pam_sss.so\s* + state: absent + check_mode: true + changed_when: false + register: result_pam_line_other_control_present + + - name: Enable Smartcards in SSSD - Ensure the correct control for the required + PAM module line in /etc/pam.d/smartcard-auth + ansible.builtin.replace: + dest: /etc/pam.d/smartcard-auth + regexp: ^(\s*auth\s+).*(\bpam_sss.so.*) + replace: \1{{ pam_module_control }} \2 + register: result_pam_module_edit + when: + - result_pam_line_other_control_present.found == 1 + + - name: Enable Smartcards in SSSD - Ensure the required PAM module line is included + in /etc/pam.d/smartcard-auth + ansible.builtin.lineinfile: + dest: /etc/pam.d/smartcard-auth + line: auth {{ pam_module_control }} pam_sss.so + register: result_pam_module_add + when: + - result_pam_line_other_control_present.found == 0 or result_pam_line_other_control_present.found + > 1 + + - name: Enable Smartcards in SSSD - Ensure authselect changes are applied + ansible.builtin.command: + cmd: authselect apply-changes -b + when: + - result_authselect_present is defined + - result_authselect_present.stat.exists + - |- + (result_pam_module_add is defined and result_pam_module_add.changed) + or (result_pam_module_edit is defined and result_pam_module_edit.changed) + when: + - result_pam_line_present.found is defined + - result_pam_line_present.found == 0 + + - name: Enable Smartcards in SSSD - Define a fact for control already filtered in + case filters are used + ansible.builtin.set_fact: + pam_module_control: sufficient + + - name: Enable Smartcards in SSSD - Check if the required PAM module option is present + in /etc/pam.d/smartcard-auth + ansible.builtin.lineinfile: + path: /etc/pam.d/smartcard-auth + regexp: ^\s*auth\s+{{ pam_module_control | regex_escape() }}\s+pam_sss.so\s*.*\sallow_missing_name\b + state: absent + check_mode: true + changed_when: false + register: result_pam_module_sssd_enable_smartcards_option_present + + - name: Enable Smartcards in SSSD - Ensure the "allow_missing_name" PAM option for + "pam_sss.so" is included in /etc/pam.d/smartcard-auth + ansible.builtin.lineinfile: + path: /etc/pam.d/smartcard-auth + backrefs: true + regexp: ^(\s*auth\s+{{ pam_module_control | regex_escape() }}\s+pam_sss.so.*) + line: \1 allow_missing_name + state: present + register: result_pam_sssd_enable_smartcards_add + when: + - result_pam_module_sssd_enable_smartcards_option_present.found == 0 + + - name: Enable Smartcards in SSSD - Define a fact for control already filtered in + case filters are used + ansible.builtin.set_fact: + pam_module_control: '[success=done authinfo_unavail=ignore ignore=ignore default=die]' + + - name: Enable Smartcards in SSSD - Check if expected PAM module line is present + in /etc/pam.d/system-auth + ansible.builtin.lineinfile: + path: /etc/pam.d/system-auth + regexp: ^\s*auth\s+{{ pam_module_control | regex_escape() }}\s+pam_sss.so\s*.* + state: absent + check_mode: true + changed_when: false + register: result_pam_line_present + + - name: Enable Smartcards in SSSD - Include or update the PAM module line in /etc/pam.d/system-auth + block: + + - name: Enable Smartcards in SSSD - Check if required PAM module line is present + in /etc/pam.d/system-auth with different control + ansible.builtin.lineinfile: + path: /etc/pam.d/system-auth + regexp: ^\s*auth\s+.*\s+pam_sss.so\s* + state: absent + check_mode: true + changed_when: false + register: result_pam_line_other_control_present + + - name: Enable Smartcards in SSSD - Ensure the correct control for the required + PAM module line in /etc/pam.d/system-auth + ansible.builtin.replace: + dest: /etc/pam.d/system-auth + regexp: ^(\s*auth\s+).*(\bpam_sss.so.*) + replace: \1{{ pam_module_control }} \2 + register: result_pam_module_edit + when: + - result_pam_line_other_control_present.found == 1 + + - name: Enable Smartcards in SSSD - Ensure the required PAM module line is included + in /etc/pam.d/system-auth + ansible.builtin.lineinfile: + dest: /etc/pam.d/system-auth + line: auth {{ pam_module_control }} pam_sss.so + register: result_pam_module_add + when: + - result_pam_line_other_control_present.found == 0 or result_pam_line_other_control_present.found + > 1 + + - name: Enable Smartcards in SSSD - Ensure authselect changes are applied + ansible.builtin.command: + cmd: authselect apply-changes -b + when: + - result_authselect_present is defined + - result_authselect_present.stat.exists + - |- + (result_pam_module_add is defined and result_pam_module_add.changed) + or (result_pam_module_edit is defined and result_pam_module_edit.changed) + when: + - result_pam_line_present.found is defined + - result_pam_line_present.found == 0 + + - name: Enable Smartcards in SSSD - Define a fact for control already filtered in + case filters are used + ansible.builtin.set_fact: + pam_module_control: '[success=done authinfo_unavail=ignore ignore=ignore default=die]' + + - name: Enable Smartcards in SSSD - Check if the required PAM module option is present + in /etc/pam.d/system-auth + ansible.builtin.lineinfile: + path: /etc/pam.d/system-auth + regexp: ^\s*auth\s+{{ pam_module_control | regex_escape() }}\s+pam_sss.so\s*.*\stry_cert_auth\b + state: absent + check_mode: true + changed_when: false + register: result_pam_module_sssd_enable_smartcards_option_present + + - name: Enable Smartcards in SSSD - Ensure the "try_cert_auth" PAM option for "pam_sss.so" + is included in /etc/pam.d/system-auth + ansible.builtin.lineinfile: + path: /etc/pam.d/system-auth + backrefs: true + regexp: ^(\s*auth\s+{{ pam_module_control | regex_escape() }}\s+pam_sss.so.*) + line: \1 try_cert_auth + state: present + register: result_pam_sssd_enable_smartcards_add + when: + - result_pam_module_sssd_enable_smartcards_option_present.found == 0 + when: + - '"sssd-common" in ansible_facts.packages' + - not result_authselect_present.stat.exists + tags: + - DISA-STIG-OL09-00-000925 + - PCI-DSS-Req-8.3 + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - sssd_enable_smartcards + + + + + + + + + + SSSD Has a Correct Trust Anchor + SSSD must have acceptable trust anchor present. + Automatic remediation of this control is not available. + CCI-004068 + CCI-000185 + IA-5 (2) (a) + SRG-OS-000066-GPOS-00034 + SRG-OS-000384-GPOS-00167 + OL09-00-000900 + SV-271604r1091524_rule + Without path validation, an informed trust decision by the relying party cannot be made when +presented with any certificate not already explicitly trusted. + +A trust anchor is an authoritative entity represented via a public key and associated data. It +is used in the context of public key infrastructures, X.509 digital certificates, and DNSSEC. + +When there is a chain of trust, usually the top entity to be trusted becomes the trust anchor; +it can be, for example, a Certification Authority (CA). A certification path starts with the +subject certificate and proceeds through a number of intermediate certificates up to a trusted +root certificate, typically issued by a trusted CA. + +This requirement verifies that a certification path to an accepted trust anchor is used for +certificate validation and that the path includes status information. Path validation is +necessary for a relying party to make an informed trust decision when presented with any +certificate not already explicitly trusted. Status information for certification paths includes +certificate revocation lists or online certificate status protocol responses. +Validation of the certificate status information is out of scope for this requirement. + + + + + + Configure SSSD to Expire Offline Credentials + SSSD should be configured to expire offline credentials after 1 day. + +Check if SSSD allows cached authentications with the following command: + +$ sudo grep cache_credentials /etc/sssd/sssd.conf +cache_credentials = true + +If "cache_credentials" is set to "false" or is missing no further checks are required. + +To configure SSSD to expire offline credentials, set +offline_credentials_expiration to 1 under the [pam] +section in /etc/sssd/sssd.conf. For example: +[pam] +offline_credentials_expiration = 1 + + + 1 + 12 + 15 + 16 + 5 + DSS05.04 + DSS05.05 + DSS05.07 + DSS05.10 + DSS06.03 + DSS06.10 + CCI-002007 + 4.3.3.2.2 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.2 + 4.3.3.7.4 + SR 1.1 + SR 1.10 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + A.18.1.4 + A.7.1.1 + A.9.2.1 + A.9.2.2 + A.9.2.3 + A.9.2.4 + A.9.2.6 + A.9.3.1 + A.9.4.2 + A.9.4.3 + CM-6(a) + IA-5(13) + PR.AC-1 + PR.AC-6 + PR.AC-7 + SRG-OS-000383-GPOS-00166 + OL09-00-000935 + SV-271609r1091539_rule + If cached authentication information is out-of-date, the validity of the +authentication information may be questionable. + # Remediation is applicable only in certain platforms +if rpm --quiet -q sssd-common; then + +# sssd configuration files must be created with 600 permissions if they don't exist +# otherwise the sssd module fails to start +OLD_UMASK=$(umask) +umask u=rw,go= + +found=false + +# set value in all files if they contain section or key +for f in $(echo -n "/etc/sssd/sssd.conf /etc/sssd/conf.d/*.conf"); do + if [ ! -e "$f" ]; then + continue + fi + + # find key in section and change value + if grep -qzosP "[[:space:]]*\[pam\]([^\n\[]*\n+)+?[[:space:]]*offline_credentials_expiration" "$f"; then + + sed -i "s/offline_credentials_expiration[^(\n)]*/offline_credentials_expiration=1/" "$f" + + found=true + + # find section and add key = value to it + elif grep -qs "[[:space:]]*\[pam\]" "$f"; then + + sed -i "/[[:space:]]*\[pam\]/a offline_credentials_expiration=1" "$f" + + found=true + fi +done + +# if section not in any file, append section with key = value to FIRST file in files parameter +if ! $found ; then + file=$(echo "/etc/sssd/sssd.conf /etc/sssd/conf.d/*.conf" | cut -f1 -d ' ') + mkdir -p "$(dirname "$file")" + + echo -e "[pam]\noffline_credentials_expiration=1" >> "$file" + +fi + +umask $OLD_UMASK + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-000935 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(13) + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - sssd_offline_cred_expiration + +- name: Test for domain group + command: grep '\s*\[domain\/[^]]*]' /etc/sssd/sssd.conf + register: test_grep_domain + failed_when: false + changed_when: false + check_mode: false + when: '"sssd-common" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-000935 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(13) + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - sssd_offline_cred_expiration + +- name: Add default domain group (if no domain there) + ini_file: + path: /etc/sssd/sssd.conf + section: '{{ item.section }}' + option: '{{ item.option }}' + value: '{{ item.value }}' + create: true + mode: 384 + with_items: + - section: sssd + option: domains + value: default + - section: domain/default + option: id_provider + value: files + when: + - '"sssd-common" in ansible_facts.packages' + - test_grep_domain.stdout is defined + - test_grep_domain.stdout | length < 1 + tags: + - DISA-STIG-OL09-00-000935 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(13) + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - sssd_offline_cred_expiration + +- name: Configure SSD to Expire Offline Credentials + ini_file: + dest: /etc/sssd/sssd.conf + section: pam + option: offline_credentials_expiration + value: 1 + create: true + mode: 384 + when: '"sssd-common" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-000935 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(13) + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - sssd_offline_cred_expiration + +- name: Find all the conf files inside /etc/sssd/conf.d/ + find: + paths: /etc/sssd/conf.d/ + patterns: '*.conf' + register: sssd_conf_d_files + when: '"sssd-common" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-000935 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(13) + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - sssd_offline_cred_expiration + +- name: Fix offline_credentials_expiration configuration in /etc/sssd/conf.d/ + ansible.builtin.replace: + path: '{{ item.path }}' + regexp: '[^#]*offline_credentials_expiration.*' + replace: offline_credentials_expiration = 1 + with_items: '{{ sssd_conf_d_files.files }}' + when: '"sssd-common" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-000935 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(13) + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - sssd_offline_cred_expiration + + + + + + + + + + System Security Services Daemon (SSSD) - LDAP + The System Security Services Daemon (SSSD) is a system daemon that provides access +to different identity and authentication providers such as Red Hat's IdM, Microsoft's AD, +openLDAP, MIT Kerberos, etc. It uses a common framework that can provide caching and offline +support to systems utilizing SSSD. SSSD using caching to reduce load on authentication +servers permit offline authentication as well as store extended user data. + + +SSSD can support many backends including LDAP. The sssd-ldap backend +allows SSSD to fetch identity information from an LDAP server. + + + Configure SSSD LDAP Backend Client to Demand a Valid Certificate from the Server + Configure SSSD to demand a valid certificate from the server to +protect the integrity of LDAP remote access sessions by setting +the ldap_tls_reqcert option in /etc/sssd/sssd.conf +to demand. + CCI-001453 + SC-12(3) + CM-6(a) + SRG-OS-000250-GPOS-00093 + R67 + Without a valid certificate presented to the LDAP client backend, the identity of a +server can be forged compromising LDAP remote access sessions. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && rpm --quiet -q sssd-common; then + +SSSD_CONF="/etc/sssd/sssd.conf" +LDAP_REGEX='[[:space:]]*\[domain\/[^]]*]([^(\n)]*(\n)+)+?[[:space:]]*ldap_tls_reqcert' +AD_REGEX='[[:space:]]*\[domain\/[^]]*]([^(\n)]*(\n)+)+?[[:space:]]*id_provider[[:space:]]*=[[:space:]]*((?i)ad)[[:space:]]*$' +DOMAIN_REGEX="[[:space:]]*\[domain\/[^]]*]" + +# Check if id_provider is not set to ad (Active Directory) which makes start_tls not applicable, note the -v option to invert the grep. +# Try to find [domain/..] and ldap_tls_reqcert in sssd.conf, if it exists, set to 'demand' +# if ldap_tls_reqcert isn't here, add it +# if [domain/..] doesn't exist, add it here for default domain +if grep -qvzosP $AD_REGEX $SSSD_CONF; then + if grep -qzosP $LDAP_REGEX $SSSD_CONF; then + + sed -i "s#ldap_tls_reqcert[^(\n)]*#ldap_tls_reqcert = demand#" $SSSD_CONF + elif grep -qs $DOMAIN_REGEX $SSSD_CONF; then + sed -i "/$DOMAIN_REGEX/a ldap_tls_reqcert = demand" $SSSD_CONF + else + if test -f "$SSSD_CONF"; then + echo -e "[domain/default]\nldap_tls_reqcert = demand" >> $SSSD_CONF + else + echo "Config file '$SSSD_CONF' doesnt exist, not remediating, assuming non-applicability." >&2 + fi + fi +fi + +readarray -t SSSD_CONF_D_FILES < <(find /etc/sssd/conf.d/ -name "*.conf") +for SSSD_CONF_D_FILE in "${SSSD_CONF_D_FILES[@]}"; do + sed -i "s#ldap_tls_reqcert[^(\n)]*#ldap_tls_reqcert = demand#" "$SSSD_CONF_D_FILE" +done + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-53-CM-6(a) + - NIST-800-53-SC-12(3) + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - sssd_ldap_configure_tls_reqcert + - unknown_strategy + +- name: Test for id_provider different than Active Directory (ad) + command: grep -qzosP '[[:space:]]*\[domain\/[^]]*]([^(\n)]*(\n)+)+?[[:space:]]*id_provider[[:space:]]*=[[:space:]]*((?i)ad)[[:space:]]*$' + /etc/sssd/sssd.conf + register: test_id_provider + failed_when: false + changed_when: false + check_mode: false + when: + - '"sssd-common" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-CM-6(a) + - NIST-800-53-SC-12(3) + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - sssd_ldap_configure_tls_reqcert + - unknown_strategy + +- name: Test for domain group + command: grep '\s*\[domain\/[^]]*]' /etc/sssd/sssd.conf + register: test_grep_domain + failed_when: false + changed_when: false + check_mode: false + when: + - '"sssd-common" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-CM-6(a) + - NIST-800-53-SC-12(3) + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - sssd_ldap_configure_tls_reqcert + - unknown_strategy + +- name: Add default domain group and set ldap_tls_reqcert in sssd configuration (if + no domain there) + ini_file: + path: /etc/sssd/sssd.conf + section: '{{ item.section }}' + option: '{{ item.option }}' + value: '{{ item.value }}' + mode: 384 + with_items: + - section: sssd + option: domains + value: default + - section: domain/default + option: ldap_tls_reqcert + value: demand + when: + - '"sssd-common" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - test_grep_domain.stdout is defined + - test_grep_domain.stdout | length < 1 + - test_id_provider.stdout is defined + - test_id_provider.stdout | length < 1 + tags: + - NIST-800-53-CM-6(a) + - NIST-800-53-SC-12(3) + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - sssd_ldap_configure_tls_reqcert + - unknown_strategy + +- name: Set ldap_tls_reqcert in sssd configuration + ini_file: + path: /etc/sssd/sssd.conf + section: '{{ test_grep_domain.stdout | regex_replace(''\[(.*)\]'',''\1'') }}' + option: ldap_tls_reqcert + value: demand + mode: 384 + when: + - '"sssd-common" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - test_grep_domain.stdout is defined + - test_grep_domain.stdout | length > 0 + - test_id_provider.stdout is defined + - test_id_provider.stdout | length < 1 + tags: + - NIST-800-53-CM-6(a) + - NIST-800-53-SC-12(3) + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - sssd_ldap_configure_tls_reqcert + - unknown_strategy + +- name: Find all the conf files inside /etc/sssd/conf.d/ + find: + paths: /etc/sssd/conf.d/ + patterns: '*.conf' + register: sssd_conf_d_files + when: + - '"sssd-common" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-CM-6(a) + - NIST-800-53-SC-12(3) + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - sssd_ldap_configure_tls_reqcert + - unknown_strategy + +- name: Set ldap_tls_reqcert to demand in /etc/sssd/conf.d/ if exists + ansible.builtin.replace: + path: '{{ item.path }}' + regexp: '[^#]*ldap_tls_reqcert.*' + replace: ldap_tls_reqcert = demand + with_items: '{{ sssd_conf_d_files.files }}' + when: + - '"sssd-common" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-CM-6(a) + - NIST-800-53-SC-12(3) + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - sssd_ldap_configure_tls_reqcert + - unknown_strategy + + + + + + + + + + Configure SSSD LDAP Backend to Use TLS For All Transactions + The LDAP client should be configured to implement TLS for the integrity +of all remote LDAP authentication sessions. If the id_provider is +set to ldap or ipa in /etc/sssd/sssd.conf or any of the +/etc/sssd/sssd.conf.d configuration files, ldap_id_use_start_tls +must be set to true. + + +To check if LDAP is configured to use TLS when id_provider is +set to ldap or ipa, use the following command: +$ sudo grep -i ldap_id_use_start_tls /etc/sssd/sssd.conf /etc/sssd/conf.d/*.conf + + 11 + 12 + 14 + 15 + 3 + 8 + 9 + APO13.01 + BAI10.01 + BAI10.02 + BAI10.03 + BAI10.05 + DSS01.04 + DSS05.02 + DSS05.03 + DSS05.05 + DSS06.06 + CCI-001453 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.3 + 4.3.3.5.4 + 4.3.3.5.5 + 4.3.3.5.6 + 4.3.3.5.7 + 4.3.3.5.8 + 4.3.3.6.1 + 4.3.3.6.2 + 4.3.3.6.3 + 4.3.3.6.4 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.3.6.9 + 4.3.3.7.1 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.3.2 + 4.3.4.3.3 + SR 1.1 + SR 1.10 + SR 1.11 + SR 1.12 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.6 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.2 + SR 2.3 + SR 2.4 + SR 2.5 + SR 2.6 + SR 2.7 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 7.1 + SR 7.6 + A.11.2.6 + A.12.1.2 + A.12.5.1 + A.12.6.2 + A.13.1.1 + A.13.2.1 + A.14.1.3 + A.14.2.2 + A.14.2.3 + A.14.2.4 + A.6.2.1 + A.6.2.2 + A.9.1.2 + CM-7(a) + CM-7(b) + CM-6(a) + PR.AC-3 + PR.IP-1 + PR.PT-3 + PR.PT-4 + SRG-OS-000250-GPOS-00093 + R67 + Without cryptographic integrity protections, information can be +altered by unauthorized users without detection. The ssl directive specifies +whether to use TLS or not. If not specified it will default to no. +It should be set to start_tls rather than doing LDAP over SSL. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && rpm --quiet -q sssd-common; then + +SSSD_CONF="/etc/sssd/sssd.conf" +LDAP_REGEX='[[:space:]]*\[domain\/[^]]*]([^(\n)]*(\n)+)+?[[:space:]]*ldap_id_use_start_tls' +AD_REGEX='[[:space:]]*\[domain\/[^]]*]([^(\n)]*(\n)+)+?[[:space:]]*id_provider[[:space:]]*=[[:space:]]*((?i)ad)[[:space:]]*$' +DOMAIN_REGEX="[[:space:]]*\[domain\/[^]]*]" + +# Check if id_provider is not set to ad (Active Directory) which makes start_tls not applicable, note the -v option to invert the grep. +# Try to find [domain/..] and ldap_id_use_start_tls in sssd.conf, if it exists, set to 'true' +# if ldap_id_use_start_tls isn't here, add it +# if [domain/..] doesn't exist, add it here for default domain +if grep -qvzosP $AD_REGEX $SSSD_CONF; then + if grep -qzosP $LDAP_REGEX $SSSD_CONF; then + + sed -i "s#ldap_id_use_start_tls[^(\n)]*#ldap_id_use_start_tls = true#" $SSSD_CONF + elif grep -qs $DOMAIN_REGEX $SSSD_CONF; then + sed -i "/$DOMAIN_REGEX/a ldap_id_use_start_tls = true" $SSSD_CONF + else + if test -f "$SSSD_CONF"; then + echo -e "[domain/default]\nldap_id_use_start_tls = true" >> $SSSD_CONF + else + echo "Config file '$SSSD_CONF' doesnt exist, not remediating, assuming non-applicability." >&2 + fi + fi +fi + +readarray -t SSSD_CONF_D_FILES < <(find /etc/sssd/conf.d/ -name "*.conf") +for SSSD_CONF_D_FILE in "${SSSD_CONF_D_FILES[@]}"; do + sed -i "s#ldap_id_use_start_tls[^(\n)]*#ldap_id_use_start_tls = true#" "$SSSD_CONF_D_FILE" +done + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - high_severity + - low_complexity + - medium_disruption + - no_reboot_needed + - sssd_ldap_start_tls + - unknown_strategy + +- name: Test for id_provider different than Active Directory (ad) + command: grep -qzosP '[[:space:]]*\[domain\/[^]]*]([^(\n)]*(\n)+)+?[[:space:]]*id_provider[[:space:]]*=[[:space:]]*((?i)ad)[[:space:]]*$' + /etc/sssd/sssd.conf + register: test_id_provider + failed_when: false + changed_when: false + check_mode: false + when: + - '"sssd-common" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - high_severity + - low_complexity + - medium_disruption + - no_reboot_needed + - sssd_ldap_start_tls + - unknown_strategy + +- name: Test for domain group + command: grep '\s*\[domain\/[^]]*]' /etc/sssd/sssd.conf + register: test_grep_domain + failed_when: false + changed_when: false + check_mode: false + when: + - '"sssd-common" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - high_severity + - low_complexity + - medium_disruption + - no_reboot_needed + - sssd_ldap_start_tls + - unknown_strategy + +- name: Add default domain group and set ldap_id_use_start_tls in sssd configuration + (if no domain there) + ini_file: + path: /etc/sssd/sssd.conf + section: '{{ item.section }}' + option: '{{ item.option }}' + value: '{{ item.value }}' + mode: 384 + with_items: + - section: sssd + option: domains + value: default + - section: domain/default + option: ldap_id_use_start_tls + value: 'true' + when: + - '"sssd-common" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - test_grep_domain.stdout is defined + - test_grep_domain.stdout | length < 1 + - test_id_provider.stdout is defined + - test_id_provider.stdout | length < 1 + tags: + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - high_severity + - low_complexity + - medium_disruption + - no_reboot_needed + - sssd_ldap_start_tls + - unknown_strategy + +- name: Set ldap_id_use_start_tls in sssd configuration + ini_file: + path: /etc/sssd/sssd.conf + section: '{{ test_grep_domain.stdout | regex_replace(''\[(.*)\]'',''\1'') }}' + option: ldap_id_use_start_tls + value: 'true' + mode: 384 + when: + - '"sssd-common" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - test_grep_domain.stdout is defined + - test_grep_domain.stdout | length > 0 + - test_id_provider.stdout is defined + - test_id_provider.stdout | length < 1 + tags: + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - high_severity + - low_complexity + - medium_disruption + - no_reboot_needed + - sssd_ldap_start_tls + - unknown_strategy + +- name: Find all the conf files inside /etc/sssd/conf.d/ + find: + paths: /etc/sssd/conf.d/ + patterns: '*.conf' + register: sssd_conf_d_files + when: + - '"sssd-common" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - high_severity + - low_complexity + - medium_disruption + - no_reboot_needed + - sssd_ldap_start_tls + - unknown_strategy + +- name: Set ldap_id_use_start_tls to true in /etc/sssd/conf.d/ if exists + ansible.builtin.replace: + path: '{{ item.path }}' + regexp: '[^#]*ldap_id_use_start_tls.*' + replace: ldap_id_use_start_tls = true + with_items: '{{ sssd_conf_d_files.files }}' + when: + - '"sssd-common" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - high_severity + - low_complexity + - medium_disruption + - no_reboot_needed + - sssd_ldap_start_tls + - unknown_strategy + + + + + + + + + + + + USBGuard daemon + The USBGuard daemon enforces the USB device authorization policy for all USB devices. + + + Install usbguard Package + +The usbguard package can be installed with the following command: + +$ sudo yum install usbguard + + CCI-001958 + CCI-003959 + 1418 + CM-8(3) + IA-3 + FMT_SMF_EXT.1 + SRG-OS-000378-GPOS-00163 + SRG-APP-000141-CTR-000315 + A.23.SEC-OL1 + OL09-00-000320 + SV-271503r1091221_rule + usbguard is a software framework that helps to protect +against rogue USB devices by implementing basic whitelisting/blacklisting +capabilities based on USB device attributes. + # Remediation is applicable only in certain platforms +if ( ! ( grep -sqE "^.*\.s390x$" /proc/sys/kernel/osrelease || grep -sqE "^s390x$" /proc/sys/kernel/arch; ) && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ); then + +if ! rpm -q --quiet "usbguard" ; then + yum install -y "usbguard" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-000320 + - NIST-800-53-CM-8(3) + - NIST-800-53-IA-3 + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - package_usbguard_installed + +- name: Ensure usbguard is installed + package: + name: usbguard + state: present + when: ( ansible_architecture != "s390x" and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + tags: + - DISA-STIG-OL09-00-000320 + - NIST-800-53-CM-8(3) + - NIST-800-53-IA-3 + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - package_usbguard_installed + + include install_usbguard + +class install_usbguard { + package { 'usbguard': + ensure => 'installed', + } +} + + +package --add=usbguard + + --- +apiVersion: machineconfiguration.openshift.io/v1 +kind: MachineConfig +spec: + config: + ignition: + version: 3.1.0 + extensions: + - usbguard + + +[[packages]] +name = "usbguard" +version = "*" + + + + + + + + + + Enable the USBGuard Service + The USBGuard service should be enabled. + +The usbguard service can be enabled with the following command: +$ sudo systemctl enable usbguard.service + + CCI-001958 + CCI-003959 + 1418 + CM-8(3)(a) + IA-3 + FMT_SMF_EXT.1 + SRG-OS-000378-GPOS-00163 + SRG-APP-000141-CTR-000315 + A.23.SEC-OL1 + OL09-00-000321 + SV-271504r1091224_rule + The usbguard service must be running in order to +enforce the USB device authorization policy for all USB devices. + # Remediation is applicable only in certain platforms +if ( ! ( grep -sqE "^.*\.s390x$" /proc/sys/kernel/osrelease || grep -sqE "^s390x$" /proc/sys/kernel/arch; ) && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ); then + +SYSTEMCTL_EXEC='/usr/bin/systemctl' +"$SYSTEMCTL_EXEC" unmask 'usbguard.service' +if [[ $("$SYSTEMCTL_EXEC" is-system-running) != "offline" ]]; then + "$SYSTEMCTL_EXEC" start 'usbguard.service' +fi +"$SYSTEMCTL_EXEC" enable 'usbguard.service' + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-000321 + - NIST-800-53-CM-8(3)(a) + - NIST-800-53-IA-3 + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_usbguard_enabled + +- name: Enable the USBGuard Service - Enable service usbguard + block: + + - name: Gather the package facts + package_facts: + manager: auto + + - name: Enable the USBGuard Service - Enable Service usbguard + ansible.builtin.systemd: + name: usbguard + enabled: true + state: started + masked: false + when: + - '"usbguard" in ansible_facts.packages' + when: ( ansible_architecture != "s390x" and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + tags: + - DISA-STIG-OL09-00-000321 + - NIST-800-53-CM-8(3)(a) + - NIST-800-53-IA-3 + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_usbguard_enabled + + include enable_usbguard + +class enable_usbguard { + service {'usbguard': + enable => true, + ensure => 'running', + } +} + + --- +apiVersion: machineconfiguration.openshift.io/v1 +kind: MachineConfig +metadata: + annotations: + complianceascode.io/depends-on: xccdf_org.ssgproject.content_rule_package_usbguard_installed +spec: + config: + ignition: + version: 3.1.0 + systemd: + units: + - name: usbguard.service + enabled: true + + +[customizations.services] +enabled = ["usbguard"] + + + + + + + + + + Log USBGuard daemon audit events using Linux Audit + To configure USBGuard daemon to log via Linux Audit +(as opposed directly to a file), +AuditBackend option in /etc/usbguard/usbguard-daemon.conf +needs to be set to LinuxAudit. + CCI-000169 + AU-2 + CM-8(3) + IA-3 + FMT_SMF_EXT.1 + SRG-OS-000062-GPOS-00031 + SRG-OS-000471-GPOS-00215 + SRG-APP-000141-CTR-000315 + OL09-00-002330 + SV-271700r1091812_rule + Using the Linux Audit logging allows for centralized trace +of events. + + # Remediation is applicable only in certain platforms +if ( ! ( grep -sqE "^.*\.s390x$" /proc/sys/kernel/osrelease || grep -sqE "^s390x$" /proc/sys/kernel/arch; ) && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ) && { rpm --quiet -q usbguard; }; then + +if [ -e "/etc/usbguard/usbguard-daemon.conf" ] ; then + + LC_ALL=C sed -i "/^\s*AuditBackend=/d" "/etc/usbguard/usbguard-daemon.conf" +else + touch "/etc/usbguard/usbguard-daemon.conf" +fi +# make sure file has newline at the end +sed -i -e '$a\' "/etc/usbguard/usbguard-daemon.conf" + +cp "/etc/usbguard/usbguard-daemon.conf" "/etc/usbguard/usbguard-daemon.conf.bak" +# Insert at the end of the file +printf '%s\n' "AuditBackend=LinuxAudit" >> "/etc/usbguard/usbguard-daemon.conf" +# Clean up after ourselves. +rm "/etc/usbguard/usbguard-daemon.conf.bak" + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002330 + - NIST-800-53-AU-2 + - NIST-800-53-CM-8(3) + - NIST-800-53-IA-3 + - configure_usbguard_auditbackend + - low_complexity + - low_disruption + - low_severity + - no_reboot_needed + - restrict_strategy + +- name: Log USBGuard daemon audit events using Linux Audit + block: + + - name: Check for duplicate values + lineinfile: + path: /etc/usbguard/usbguard-daemon.conf + create: true + regexp: (?i)^\s*AuditBackend= + state: absent + check_mode: true + changed_when: false + register: dupes + + - name: Deduplicate values from /etc/usbguard/usbguard-daemon.conf + lineinfile: + path: /etc/usbguard/usbguard-daemon.conf + create: true + regexp: (?i)^\s*AuditBackend= + state: absent + when: dupes.found is defined and dupes.found > 1 + + - name: Insert correct line to /etc/usbguard/usbguard-daemon.conf + lineinfile: + path: /etc/usbguard/usbguard-daemon.conf + create: true + regexp: (?i)^\s*AuditBackend= + line: AuditBackend=LinuxAudit + state: present + when: + - ( ansible_architecture != "s390x" and ("kernel" in ansible_facts.packages or "kernel-uek" + in ansible_facts.packages) ) + - '"usbguard" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-002330 + - NIST-800-53-AU-2 + - NIST-800-53-CM-8(3) + - NIST-800-53-IA-3 + - configure_usbguard_auditbackend + - low_complexity + - low_disruption + - low_severity + - no_reboot_needed + - restrict_strategy + + --- +apiVersion: machineconfiguration.openshift.io/v1 +kind: MachineConfig +metadata: + annotations: + complianceascode.io/depends-on: xccdf_org.ssgproject.content_rule_package_usbguard_installed + complianceascode.io/ocp-version: '>=4.7.0' +spec: + config: + ignition: + version: 3.1.0 + storage: + files: + - contents: + source: data:,{{ %0A%23%0A%23%20Rule%20set%20file%20path.%0A%23%0A%23%20The%20USBGuard%20daemon%20will%20use%20this%20file%20to%20load%20the%20policy%0A%23%20rule%20set%20from%20it%20and%20to%20write%20new%20rules%20received%20via%20the%0A%23%20IPC%20interface.%0A%23%0A%23%20RuleFile%3D/path/to/rules.conf%0A%23%0ARuleFile%3D/etc/usbguard/rules.conf%0A%0A%23%0A%23%20Rule%20set%20folder%20path.%0A%23%0A%23%20The%20USBGuard%20daemon%20will%20use%20this%20folder%20to%20load%20the%20policy%0A%23%20rule%20set%20from%20it%20and%20to%20write%20new%20rules%20received%20via%20the%0A%23%20IPC%20interface.%20Usually%2C%20we%20set%20the%20option%20to%0A%23%20/etc/usbguard/rules.d/.%20The%20USBGuard%20daemon%20is%20supposed%20to%0A%23%20behave%20like%20any%20other%20standard%20Linux%20daemon%20therefore%20it%0A%23%20loads%20rule%20files%20in%20alpha-numeric%20order.%20File%20names%20inside%0A%23%20RuleFolder%20directory%20should%20start%20with%20a%20two-digit%20number%0A%23%20prefix%20indicating%20the%20position%2C%20in%20which%20the%20rules%20are%0A%23%20scanned%20by%20the%20daemon.%0A%23%0A%23%20RuleFolder%3D/path/to/rulesfolder/%0A%23%0ARuleFolder%3D/etc/usbguard/rules.d/%0A%0A%23%0A%23%20Implicit%20policy%20target.%0A%23%0A%23%20How%20to%20treat%20devices%20that%20don%27t%20match%20any%20rule%20in%20the%0A%23%20policy.%20One%20of%3A%0A%23%0A%23%20%2A%20allow%20%20-%20authorize%20the%20device%0A%23%20%2A%20block%20%20-%20block%20the%20device%0A%23%20%2A%20reject%20-%20remove%20the%20device%0A%23%0AImplicitPolicyTarget%3Dblock%0A%0A%23%0A%23%20Present%20device%20policy.%0A%23%0A%23%20How%20to%20treat%20devices%20that%20are%20already%20connected%20when%20the%0A%23%20daemon%20starts.%20One%20of%3A%0A%23%0A%23%20%2A%20allow%20%20%20%20%20%20%20%20-%20authorize%20every%20present%20device%0A%23%20%2A%20block%20%20%20%20%20%20%20%20-%20deauthorize%20every%20present%20device%0A%23%20%2A%20reject%20%20%20%20%20%20%20-%20remove%20every%20present%20device%0A%23%20%2A%20keep%20%20%20%20%20%20%20%20%20-%20just%20sync%20the%20internal%20state%20and%20leave%20it%0A%23%20%2A%20apply-policy%20-%20evaluate%20the%20ruleset%20for%20every%20present%0A%23%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20device%0A%23%0APresentDevicePolicy%3Dapply-policy%0A%0A%23%0A%23%20Present%20controller%20policy.%0A%23%0A%23%20How%20to%20treat%20USB%20controllers%20that%20are%20already%20connected%0A%23%20when%20the%20daemon%20starts.%20One%20of%3A%0A%23%0A%23%20%2A%20allow%20%20%20%20%20%20%20%20-%20authorize%20every%20present%20device%0A%23%20%2A%20block%20%20%20%20%20%20%20%20-%20deauthorize%20every%20present%20device%0A%23%20%2A%20reject%20%20%20%20%20%20%20-%20remove%20every%20present%20device%0A%23%20%2A%20keep%20%20%20%20%20%20%20%20%20-%20just%20sync%20the%20internal%20state%20and%20leave%20it%0A%23%20%2A%20apply-policy%20-%20evaluate%20the%20ruleset%20for%20every%20present%0A%23%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20device%0A%23%0APresentControllerPolicy%3Dkeep%0A%0A%23%0A%23%20Inserted%20device%20policy.%0A%23%0A%23%20How%20to%20treat%20USB%20devices%20that%20are%20already%20connected%0A%23%20%2Aafter%2A%20the%20daemon%20starts.%20One%20of%3A%0A%23%0A%23%20%2A%20block%20%20%20%20%20%20%20%20-%20deauthorize%20every%20present%20device%0A%23%20%2A%20reject%20%20%20%20%20%20%20-%20remove%20every%20present%20device%0A%23%20%2A%20apply-policy%20-%20evaluate%20the%20ruleset%20for%20every%20present%0A%23%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20device%0A%23%0AInsertedDevicePolicy%3Dapply-policy%0A%0A%23%0A%23%20Control%20which%20devices%20are%20authorized%20by%20default.%0A%23%0A%23%20The%20USBGuard%20daemon%20modifies%20some%20the%20default%20authorization%20state%20attributes%0A%23%20of%20controller%20devices.%20This%20setting%2C%20enables%20you%20to%20define%20what%20value%20the%0A%23%20default%20authorization%20is%20set%20to.%0A%23%0A%23%20%2A%20keep%20%20%20%20%20%20%20%20%20-%20do%20not%20change%20the%20authorization%20state%0A%23%20%2A%20none%20%20%20%20%20%20%20%20%20-%20every%20new%20device%20starts%20out%20deauthorized%0A%23%20%2A%20all%20%20%20%20%20%20%20%20%20%20-%20every%20new%20device%20starts%20out%20authorized%0A%23%20%2A%20internal%20%20%20%20%20-%20internal%20devices%20start%20out%20authorized%2C%20external%20devices%20start%0A%23%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20out%20deauthorized%20%28this%20requires%20the%20ACPI%20tables%20to%20properly%0A%23%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20label%20internal%20devices%2C%20and%20kernel%20support%29%0A%23%0A%23AuthorizedDefault%3Dnone%0A%0A%23%0A%23%20Restore%20controller%20device%20state.%0A%23%0A%23%20The%20USBGuard%20daemon%20modifies%20some%20attributes%20of%20controller%0A%23%20devices%20like%20the%20default%20authorization%20state%20of%20new%20child%20device%0A%23%20instances.%20Using%20this%20setting%2C%20you%20can%20control%20whether%20the%0A%23%20daemon%20will%20try%20to%20restore%20the%20attribute%20values%20to%20the%20state%0A%23%20before%20modification%20on%20shutdown.%0A%23%0A%23%20SECURITY%20CONSIDERATIONS%3A%20If%20set%20to%20true%2C%20the%20USB%20authorization%0A%23%20policy%20could%20be%20bypassed%20by%20performing%20some%20sort%20of%20attack%20on%20the%0A%23%20daemon%20%28via%20a%20local%20exploit%20or%20via%20a%20USB%20device%29%20to%20make%20it%20shutdown%0A%23%20and%20restore%20to%20the%20operating-system%20default%20state%20%28known%20to%20be%20permissive%29.%0A%23%0ARestoreControllerDeviceState%3Dfalse%0A%0A%23%0A%23%20Device%20manager%20backend%0A%23%0A%23%20Which%20device%20manager%20backend%20implementation%20to%20use.%20One%20of%3A%0A%23%0A%23%20%2A%20uevent%20%20%20-%20Netlink%20based%20implementation%20which%20uses%20sysfs%20to%20scan%20for%20present%0A%23%20%20%20%20%20%20%20%20%20%20%20%20%20%20devices%20and%20an%20uevent%20netlink%20socket%20for%20receiving%20USB%20device%0A%23%20%20%20%20%20%20%20%20%20%20%20%20%20%20related%20events.%0A%23%20%2A%20umockdev%20-%20umockdev%20based%20device%20manager%20capable%20of%20simulating%20devices%20based%0A%23%20%20%20%20%20%20%20%20%20%20%20%20%20%20on%20umockdev-record%20files.%20Useful%20for%20testing.%0A%23%0ADeviceManagerBackend%3Duevent%0A%0A%23%21%21%21%20WARNING%3A%20It%27s%20good%20practice%20to%20set%20at%20least%20one%20of%20the%20%21%21%21%0A%23%21%21%21%20%20%20%20%20%20%20%20%20%20two%20options%20bellow.%20If%20none%20of%20them%20are%20set%2C%20%20%21%21%21%0A%23%21%21%21%20%20%20%20%20%20%20%20%20%20the%20daemon%20will%20accept%20IPC%20connections%20from%20%20%20%21%21%21%0A%23%21%21%21%20%20%20%20%20%20%20%20%20%20anyone%2C%20thus%20allowing%20anyone%20to%20modify%20the%20%20%20%20%21%21%21%0A%23%21%21%21%20%20%20%20%20%20%20%20%20%20rule%20set%20and%20%28de%29authorize%20USB%20devices.%20%20%20%20%20%20%20%21%21%21%0A%0A%23%0A%23%20Users%20allowed%20to%20use%20the%20IPC%20interface.%0A%23%0A%23%20A%20space%20delimited%20list%20of%20usernames%20that%20the%20daemon%20will%0A%23%20accept%20IPC%20connections%20from.%0A%23%0A%23%20IPCAllowedUsers%3Dusername1%20username2%20...%0A%23%0AIPCAllowedUsers%3Droot%0A%0A%23%0A%23%20Groups%20allowed%20to%20use%20the%20IPC%20interface.%0A%23%0A%23%20A%20space%20delimited%20list%20of%20groupnames%20that%20the%20daemon%20will%0A%23%20accept%20IPC%20connections%20from.%0A%23%0A%23%20IPCAllowedGroups%3Dgroupname1%20groupname2%20...%0A%23%0AIPCAllowedGroups%3Dwheel%0A%0A%23%0A%23%20IPC%20access%20control%20definition%20files%20path.%0A%23%0A%23%20The%20files%20at%20this%20location%20will%20be%20interpreted%20by%20the%20daemon%0A%23%20as%20access%20control%20definition%20files.%20The%20%28base%29name%20of%20a%20file%0A%23%20should%20be%20in%20the%20form%3A%0A%23%0A%23%20%20%20%5Buser%5D%5B%3A%3Cgroup%3E%5D%0A%23%0A%23%20and%20should%20contain%20lines%20in%20the%20form%3A%0A%23%0A%23%20%20%20%3Csection%3E%3D%5Bprivilege%5D%20...%0A%23%0A%23%20This%20way%20each%20file%20defines%20who%20is%20able%20to%20connect%20to%20the%20IPC%0A%23%20bus%20and%20what%20privileges%20he%20has.%0A%23%0AIPCAccessControlFiles%3D/etc/usbguard/IPCAccessControl.d/%0A%0A%23%0A%23%20Generate%20device%20specific%20rules%20including%20the%20%22via-port%22%0A%23%20attribute.%0A%23%0A%23%20This%20option%20modifies%20the%20behavior%20of%20the%20allowDevice%0A%23%20action.%20When%20instructed%20to%20generate%20a%20permanent%20rule%2C%0A%23%20the%20action%20can%20generate%20a%20port%20specific%20rule.%20Because%0A%23%20some%20systems%20have%20unstable%20port%20numbering%2C%20the%20generated%0A%23%20rule%20might%20not%20match%20the%20device%20after%20rebooting%20the%20system.%0A%23%0A%23%20If%20set%20to%20false%2C%20the%20generated%20rule%20will%20still%20contain%0A%23%20the%20%22parent-hash%22%20attribute%20which%20also%20defines%20an%20association%0A%23%20to%20the%20parent%20device.%20See%20usbguard-rules.conf%285%29%20for%20more%0A%23%20details.%0A%23%0ADeviceRulesWithPort%3Dfalse%0A%0A%23%0A%23%20USBGuard%20Audit%20events%20log%20backend%0A%23%0A%23%20One%20of%3A%0A%23%0A%23%20%2A%20FileAudit%20-%20Log%20audit%20events%20into%20a%20file%20specified%20by%0A%23%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20AuditFilePath%20setting%20%28see%20below%29%0A%23%20%2A%20LinuxAudit%20-%20Log%20audit%20events%20using%20the%20Linux%20Audit%0A%23%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20subsystem%20%28using%20audit_log_user_message%29%0A%23%0AAuditBackend%3DLinuxAudit%0A%0A%23%0A%23%20USBGuard%20audit%20events%20log%20file%20path.%0A%23%0A%23AuditFilePath%3D/var/log/usbguard/usbguard-audit.log%0A%0A%23%0A%23%20Hides%20personally%20identifiable%20information%20such%20as%20device%20serial%20numbers%20and%0A%23%20hashes%20of%20descriptors%20%28which%20include%20the%20serial%20number%29%20from%20audit%20entries.%0A%23%0A%23HidePII%3Dfalse }} + mode: 0600 + path: /etc/usbguard/usbguard-daemon.conf + overwrite: true + + + + + + + + + + Authorize Human Interface Devices and USB hubs in USBGuard daemon + To allow authorization of USB devices combining human interface device and hub capabilities +by USBGuard daemon, +add the line +allow with-interface match-all { 03:*:* 09:00:* } +to /etc/usbguard/rules.conf. + This rule should be understood primarily as a convenience administration feature. This rule ensures that if the USBGuard default rules.conf file is present, it will alter it so that USB human interface devices and hubs are allowed. However, if the rules.conf file is altered by system administrator, the rule does not check if USB human interface devices and hubs are allowed. This assumes that an administrator modified the file with some purpose in mind. + CM-8(3) + IA-3 + FMT_SMF_EXT.1 + SRG-OS-000114-GPOS-00059 + SRG-APP-000092-CTR-000165 + Without allowing Human Interface Devices, it might not be possible +to interact with the system. Without allowing hubs, it might not be possible to use any +USB devices on the system. + # Remediation is applicable only in certain platforms +if ( ! ( grep -sqE "^.*\.s390x$" /proc/sys/kernel/osrelease || grep -sqE "^s390x$" /proc/sys/kernel/arch; ) && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ); then + +echo "allow with-interface match-all { 03:*:* 09:00:* }" >> /etc/usbguard/rules.conf + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-53-CM-8(3) + - NIST-800-53-IA-3 + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - usbguard_allow_hid_and_hub + +- name: Allow HID devices and hubs + lineinfile: + path: /etc/usbguard/rules.conf + create: true + regexp: '' + line: allow with-interface match-all { 03:*:* 09:00:* } + state: present + when: ( ansible_architecture != "s390x" and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + tags: + - NIST-800-53-CM-8(3) + - NIST-800-53-IA-3 + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - usbguard_allow_hid_and_hub + + --- +apiVersion: machineconfiguration.openshift.io/v1 +kind: MachineConfig +metadata: + annotations: + complianceascode.io/depends-on: xccdf_org.ssgproject.content_rule_package_usbguard_installed +spec: + config: + ignition: + version: 3.1.0 + storage: + files: + - contents: + source: data:,{{ %0Aallow%20with-interface%20match-all%20%7B%2003%3A%2A%3A%2A%2009%3A00%3A%2A%20%7D }} + mode: 0600 + path: /etc/usbguard/rules.d/75-hid-and-hub.conf + overwrite: true + + + + + + + + + + Generate USBGuard Policy + By default USBGuard when enabled prevents access to all USB devices and this lead +to inaccessible system if they use USB mouse/keyboard. To prevent this scenario, +the initial policy configuration must be generated based on current connected USB +devices. + CCI-001958 + CM-8(3)(a) + IA-3 + SRG-OS-000378-GPOS-00163 + A.23.SEC-OL1 + OL09-00-002331 + SV-271701r1091815_rule + The usbguard must be configured to allow connected USB devices to work +properly, avoiding the system to become inaccessible. + # Remediation is applicable only in certain platforms +if ( ! ( grep -sqE "^.*\.s390x$" /proc/sys/kernel/osrelease || grep -sqE "^s390x$" /proc/sys/kernel/arch; ) && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ); then + +if rpm --quiet -q usbguard +then + USBGUARD_CONF=/etc/usbguard/rules.conf + if [ ! -f "$USBGUARD_CONF" ] || [ ! -s "$USBGUARD_CONF" ]; then + usbguard generate-policy > $USBGUARD_CONF + if [ ! -s "$USBGUARD_CONF" ]; then + # make sure OVAL check doesn't fail on systems where + # generate-policy doesn't find any USB devices (for + # example a system might not have a USB bus) + echo "# No USB devices found" > $USBGUARD_CONF + fi + # make sure it has correct permissions + chmod 600 $USBGUARD_CONF + + SYSTEMCTL_EXEC='/usr/bin/systemctl' + "$SYSTEMCTL_EXEC" unmask 'usbguard.service' + "$SYSTEMCTL_EXEC" restart 'usbguard.service' + "$SYSTEMCTL_EXEC" enable 'usbguard.service' + fi +else + echo "USBGuard is not installed. No remediation was applied!" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002331 + - NIST-800-53-CM-8(3)(a) + - NIST-800-53-IA-3 + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - usbguard_generate_policy + +- name: Generate USBGuard Policy + block: + + - name: Gather the package facts + package_facts: + manager: auto + + - name: Check that the /etc/usbguard/rules.conf exists + stat: + path: /etc/usbguard/rules.conf + register: policy_file + + - name: Create USBGuard Policy configuration + command: usbguard generate-policy + register: policy + when: not policy_file.stat.exists or policy_file.stat.size == 0 + + - name: Copy the Generated Policy configuration to a persistent file + copy: + content: '{{ policy.stdout }}' + dest: /etc/usbguard/rules.conf + mode: 384 + when: not policy_file.stat.exists or policy_file.stat.size == 0 + + - name: Add comment into /etc/usbguard/rules.conf when system has no USB devices + lineinfile: + path: /etc/usbguard/rules.conf + line: '# No USB devices found' + state: present + when: not policy_file.stat.exists or policy_file.stat.size == 0 + + - name: Enable service usbguard + systemd: + name: usbguard + enabled: 'yes' + state: started + masked: 'no' + when: + - ( ansible_architecture != "s390x" and ("kernel" in ansible_facts.packages or "kernel-uek" + in ansible_facts.packages) ) + - '"usbguard" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-002331 + - NIST-800-53-CM-8(3)(a) + - NIST-800-53-IA-3 + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - usbguard_generate_policy + + + + + + + + + + + X Window System + The X Window System implementation included with the +system is called X.org. + + Disable X Windows + Unless there is a mission-critical reason for the +system to run a graphical user interface, ensure X is not set to start +automatically at boot and remove the X Windows software packages. +There is usually no reason to run X Windows +on a dedicated server system, as it increases the system's attack surface and consumes +system resources. Administrators of server systems should instead login via +SSH or on the text console. + + Remove the X Windows Package Group + By removing the xorg-x11-server-common package, the system no longer has X Windows +installed. If X Windows is not installed then the system cannot boot into graphical user mode. +This prevents the system from being accidentally or maliciously booted into a graphical.target +mode. To do so, run the following command:$ sudo yum groupremove base-x + $ sudo yum remove xorg-x11-server-common + + The installation and use of a Graphical User Interface (GUI) increases your attack vector and decreases your +overall security posture. Removing the package xorg-x11-server-common package will remove the graphical target +which might bring your system to an inconsistent state requiring additional configuration to access the system +again. If a GUI is an operational requirement, a tailored profile that removes this rule should used before +continuing installation. + 12 + 15 + 8 + APO13.01 + DSS01.04 + DSS05.02 + DSS05.03 + CCI-000366 + 4.3.3.6.6 + SR 1.13 + SR 2.6 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 7.1 + SR 7.6 + A.11.2.6 + A.13.1.1 + A.13.2.1 + A.14.1.3 + A.6.2.1 + A.6.2.2 + CM-7(a) + CM-7(b) + CM-6(a) + PR.AC-3 + PR.PT-4 + SRG-OS-000480-GPOS-00227 + Unnecessary service packages must not be installed to decrease the attack surface of the system. X windows has a long history of security +vulnerabilities and should not be installed unless approved and documented. + +# CAUTION: This remediation script will remove xorg-x11-server-common +# from the system, and may remove any packages +# that depend on xorg-x11-server-common. Execute this +# remediation AFTER testing on a non-production +# system! + +if rpm -q --quiet "xorg-x11-server-common" ; then +yum remove -y "xorg-x11-server-common" +fi + + - name: Ensure xorg-x11-server-common is removed + package: + name: xorg-x11-server-common + state: absent + tags: + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - package_xorg-x11-server-common_removed + + include remove_xorg-x11-server-common + +class remove_xorg-x11-server-common { + package { 'xorg-x11-server-common': + ensure => 'purged', + } +} + + +package --remove=xorg-x11-server-common + + + + + + + + + + Disable graphical user interface + By removing the following packages, the system no longer has X Windows installed. + +xorg-x11-server-Xorg xorg-x11-server-common xorg-x11-server-utils xorg-x11-server-Xwayland + +If X Windows is not installed then the system cannot boot into graphical user mode. +This prevents the system from being accidentally or maliciously booted into a graphical.target +mode. To do so, run the following command: + +sudo yum remove xorg-x11-server-Xorg xorg-x11-server-common xorg-x11-server-utils xorg-x11-server-Xwayland + + The installation and use of a Graphical User Interface (GUI) increases your attack vector and decreases your +overall security posture. Removing the package xorg-x11-server-common package will remove the graphical target +which might bring your system to an inconsistent state requiring additional configuration to access the system +again. +The rule xwindows_runlevel_target can be used to configure the system to boot into the multi-user.target. +If a GUI is an operational requirement, a tailored profile that removes this rule should be used before +continuing installation. + CCI-000366 + CM-6(b) + SRG-OS-000480-GPOS-00227 + OL09-00-000145 + SV-271465r1091107_rule + Unnecessary service packages must not be installed to decrease the attack surface of the system. X windows has a long history of security +vulnerabilities and should not be installed unless approved and documented. + + +# remove packages +if rpm -q --quiet "xorg-x11-server-Xorg" ; then +yum remove -y "xorg-x11-server-Xorg" +fi +if rpm -q --quiet "xorg-x11-server-utils" ; then +yum remove -y "xorg-x11-server-utils" +fi +if rpm -q --quiet "xorg-x11-server-common" ; then +yum remove -y "xorg-x11-server-common" +fi + +if rpm -q --quiet "xorg-x11-server-Xwayland" ; then +yum remove -y "xorg-x11-server-Xwayland" +fi + + - name: Ensure xorg packages are removed + package: + name: + - xorg-x11-server-Xorg + - xorg-x11-server-common + - xorg-x11-server-utils + - xorg-x11-server-Xwayland + state: absent + tags: + - DISA-STIG-OL09-00-000145 + - NIST-800-53-CM-6(b) + - low_complexity + - low_disruption + - medium_severity + - reboot_required + - restrict_strategy + - xwindows_remove_packages + + +package --remove=xorg-x11-server-Xorg --remove=xorg-x11-server-common --remove=xorg-x11-server-utils --remove=xorg-x11-server-Xwayland + + + + + + + + + + Disable Graphical Environment Startup By Setting Default Target + Systems that do not require a graphical user interface should only boot by +default into multi-user.target mode. This prevents accidental booting of the system +into a graphical.target mode. Setting the system's default target to +multi-user.target will prevent automatic startup of the graphical environment. +To do so, run: +$ systemctl set-default multi-user.target +You should see the following output: +Removed symlink /etc/systemd/system/default.target. +Created symlink from /etc/systemd/system/default.target to /usr/lib/systemd/system/multi-user.target. + + 12 + 15 + 8 + APO13.01 + DSS01.04 + DSS05.02 + DSS05.03 + CCI-000366 + 4.3.3.6.6 + SR 1.13 + SR 2.6 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 7.1 + SR 7.6 + A.11.2.6 + A.13.1.1 + A.13.2.1 + A.14.1.3 + A.6.2.1 + A.6.2.2 + CM-7(a) + CM-7(b) + CM-6(a) + PR.AC-3 + PR.PT-4 + SRG-OS-000480-GPOS-00227 + OL09-00-000020 + SV-271440r1092462_rule + Services that are not required for system and application processes +must not be active to decrease the attack surface of the system. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +systemctl set-default multi-user.target + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-000020 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - low_complexity + - low_disruption + - medium_severity + - reboot_required + - restrict_strategy + - xwindows_runlevel_target + +- name: Switch to multi-user runlevel + file: + src: /usr/lib/systemd/system/multi-user.target + dest: /etc/systemd/system/default.target + state: link + force: true + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-000020 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - low_complexity + - low_disruption + - medium_severity + - reboot_required + - restrict_strategy + - xwindows_runlevel_target + + + + + + + + + + + + + System Accounting with auditd + The audit service provides substantial capabilities for recording system activities. By default, the service audits about SELinux AVC denials and certain types of security-relevant events such as system logins, account modifications, and authentication events performed by programs such as sudo. Under its default configuration, auditd has modest disk space requirements, and should not noticeably impact system performance. - + + NOTE: The Linux Audit daemon auditd can be configured to use the augenrules program to read audit rules files (*.rules) located in /etc/audit/rules.d location and compile them to create @@ -38287,15 +117988,18 @@ appropriate ExecStartPost directive setting in the /usr/lib/systemd/system/auditd.service configuration file. To instruct the auditd daemon to use the augenrules program to read audit rules (default configuration), use the following setting: - ExecStartPost=-/sbin/augenrules --load + + ExecStartPost=-/sbin/augenrules --load in the /usr/lib/systemd/system/auditd.service configuration file. In order to instruct the auditd daemon to use the auditctl utility to read audit rules, use the following setting: - ExecStartPost=-/sbin/auditctl -R /etc/audit/audit.rules + + ExecStartPost=-/sbin/auditctl -R /etc/audit/audit.rules in the /usr/lib/systemd/system/auditd.service configuration file. Refer to [Service] section of the /usr/lib/systemd/system/auditd.service configuration file for further details. - + + Government networks often have substantial auditing requirements and auditd can be configured to meet these requirements. @@ -38318,7 +118022,7 @@ a0=b98df198 a1=bfec85dc a2=54dff4 a3=2008171 items=0 ppid=2463 pid=2465 auid=502 gid=48 euid=48 suid=48 fsuid=48 egid=48 sgid=48 fsgid=48 tty=(none) ses=6 comm="httpd" exe="/usr/sbin/httpd" subj=unconfined_u:system_r:httpd_t:s0 key=(null) -msg=audit(1226874073.147:96)The number in parentheses is the unformatted time stamp (Epoch time) + msg=audit(1226874073.147:96)The number in parentheses is the unformatted time stamp (Epoch time) for the event, which can be converted to standard time by using the date command. { getattr }The item in braces indicates the permission that was denied. getattr @@ -38343,20 +118047,26 @@ and kernel_t. exe="/usr/sbin/httpd": the full path to the executable that launched the process, which in this case, is exe="/usr/sbin/httpd". - - - - Install audispd-plugins Package - The audispd-plugins package can be installed with the following command: + + + + + Install audispd-plugins Package + The audispd-plugins package can be installed with the following command: -$ sudo yum install audispd-plugins - FMT_SMF_EXT.1 - SRG-OS-000342-GPOS-00133 - audispd-plugins provides plugins for the real-time interface to the +$ sudo yum install audispd-plugins + + CCI-001851 + SRG-OS-000342-GPOS-00133 + 10.3.3 + 10.3 + OL09-00-000450 + SV-271521r1091275_rule + audispd-plugins provides plugins for the real-time interface to the audit subsystem, audispd. These plugins can do things like relay events -to remote machines or analyze events for suspicious behavior. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then +to remote machines or analyze events for suspicious behavior. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then if ! rpm -q --quiet "audispd-plugins" ; then yum install -y "audispd-plugins" @@ -38365,167 +118075,137 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Ensure audispd-plugins is installed - package: - name: audispd-plugins - state: present - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + + - name: Gather the package facts + package_facts: + manager: auto tags: - - enable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - package_audispd-plugins_installed - - include install_audispd-plugins - -class install_audispd-plugins { - package { 'audispd-plugins': - ensure => 'installed', - } -} - - -package --add=audispd-plugins - - -[[packages]] -name = "audispd-plugins" -version = "*" - - - - - - - - - - Ensure the default plugins for the audit dispatcher are Installed - The audit-audispd-plugins package should be installed. - CCI-001851 - Req-10.5.3 - 10.3.3 - SRG-OS-000342-GPOS-00133 - Information stored in one location is vulnerable to accidental or incidental deletion or alteration. Off-loading is a common process in information systems with limited audit storage capacity. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -if ! rpm -q --quiet "audit-audispd-plugins" ; then - yum install -y "audit-audispd-plugins" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Ensure audit-audispd-plugins is installed - package: - name: audit-audispd-plugins - state: present - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - PCI-DSS-Req-10.5.3 + - DISA-STIG-OL09-00-000450 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.3 - enable_strategy - low_complexity - low_disruption - medium_severity - no_reboot_needed - - package_audit-audispd-plugins_installed - - include install_audit-audispd-plugins + - package_audispd-plugins_installed -class install_audit-audispd-plugins { - package { 'audit-audispd-plugins': +- name: Ensure audispd-plugins is installed + package: + name: audispd-plugins + state: present + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-000450 + - PCI-DSSv4-10.3 + - PCI-DSSv4-10.3.3 + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - package_audispd-plugins_installed + + include install_audispd-plugins + +class install_audispd-plugins { + package { 'audispd-plugins': ensure => 'installed', } } - - -package --add=audit-audispd-plugins - - + + +package --add=audispd-plugins + + [[packages]] -name = "audit-audispd-plugins" +name = "audispd-plugins" version = "*" - - - - - - - - - - Ensure the audit Subsystem is Installed - The audit package should be installed. - BP28(R50) - CCI-000130 - CCI-000131 - CCI-000132 - CCI-000133 - CCI-000134 - CCI-000135 - CCI-000154 - CCI-000158 - CCI-000172 - CCI-001464 - CCI-001487 - CCI-001814 - CCI-001875 - CCI-001876 - CCI-001877 - CCI-001878 - CCI-001879 - CCI-001880 - CCI-001881 - CCI-001882 - CCI-001889 - CCI-001914 - CCI-002884 - CCI-000169 - CIP-004-6 R3.3 - CIP-007-3 R6.5 - AC-7(a) - AU-7(1) - AU-7(2) - AU-14 - AU-12(2) - AU-2(a) - CM-6(a) - FAU_GEN.1 - Req-10.1 - 10.2.1 - SRG-OS-000062-GPOS-00031 - SRG-OS-000037-GPOS-00015 - SRG-OS-000038-GPOS-00016 - SRG-OS-000039-GPOS-00017 - SRG-OS-000040-GPOS-00018 - SRG-OS-000041-GPOS-00019 - SRG-OS-000042-GPOS-00021 - SRG-OS-000051-GPOS-00024 - SRG-OS-000054-GPOS-00025 - SRG-OS-000122-GPOS-00063 - SRG-OS-000254-GPOS-00095 - SRG-OS-000255-GPOS-00096 - SRG-OS-000337-GPOS-00129 - SRG-OS-000348-GPOS-00136 - SRG-OS-000349-GPOS-00137 - SRG-OS-000350-GPOS-00138 - SRG-OS-000351-GPOS-00139 - SRG-OS-000352-GPOS-00140 - SRG-OS-000353-GPOS-00141 - SRG-OS-000354-GPOS-00142 - SRG-OS-000358-GPOS-00145 - SRG-OS-000365-GPOS-00152 - SRG-OS-000392-GPOS-00172 - SRG-OS-000475-GPOS-00220 - The auditd service is an access monitoring and accounting daemon, watching system calls to audit any access, in comparison with potential local access control policy such as SELinux policy. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then + + + + + + + + + + Ensure the audit Subsystem is Installed + The audit package should be installed. + CCI-000133 + CCI-001881 + CCI-001875 + CCI-000154 + CCI-001882 + CCI-000158 + CCI-001914 + CCI-000169 + CCI-001464 + CCI-001878 + CCI-001877 + CCI-001889 + CCI-000135 + CCI-002884 + CCI-001487 + CCI-003938 + CCI-000132 + CCI-000134 + CCI-000172 + CCI-000130 + CCI-000131 + CCI-001879 + CCI-001880 + CCI-001876 + CCI-000159 + 164.308(a)(1)(ii)(D) + 164.308(a)(5)(ii)(C) + 164.310(a)(2)(iv) + 164.310(d)(2)(iii) + 164.312(b) + CIP-004-6 R3.3 + CIP-007-3 R6.5 + AC-7(a) + AU-7(1) + AU-7(2) + AU-14 + AU-12(2) + AU-2(a) + CM-6(a) + FAU_GEN.1 + Req-10.1 + SRG-OS-000062-GPOS-00031 + SRG-OS-000037-GPOS-00015 + SRG-OS-000038-GPOS-00016 + SRG-OS-000039-GPOS-00017 + SRG-OS-000040-GPOS-00018 + SRG-OS-000041-GPOS-00019 + SRG-OS-000042-GPOS-00021 + SRG-OS-000051-GPOS-00024 + SRG-OS-000054-GPOS-00025 + SRG-OS-000122-GPOS-00063 + SRG-OS-000254-GPOS-00095 + SRG-OS-000255-GPOS-00096 + SRG-OS-000337-GPOS-00129 + SRG-OS-000348-GPOS-00136 + SRG-OS-000349-GPOS-00137 + SRG-OS-000350-GPOS-00138 + SRG-OS-000351-GPOS-00139 + SRG-OS-000352-GPOS-00140 + SRG-OS-000353-GPOS-00141 + SRG-OS-000354-GPOS-00142 + SRG-OS-000358-GPOS-00145 + SRG-OS-000365-GPOS-00152 + SRG-OS-000392-GPOS-00172 + SRG-OS-000475-GPOS-00220 + R33 + R73 + 10.2.1 + 10.2 + OL09-00-000440 + SV-271519r1091269_rule + The auditd service is an access monitoring and accounting daemon, watching system calls to audit any access, in comparison with potential local access control policy such as SELinux policy. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then if ! rpm -q --quiet "audit" ; then yum install -y "audit" @@ -38534,13 +118214,12 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Ensure audit is installed - package: - name: audit - state: present - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + + - name: Gather the package facts + package_facts: + manager: auto tags: + - DISA-STIG-OL09-00-000440 - NIST-800-53-AC-7(a) - NIST-800-53-AU-12(2) - NIST-800-53-AU-14 @@ -38549,6 +118228,7 @@ fi - NIST-800-53-AU-7(2) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.1 + - PCI-DSSv4-10.2 - PCI-DSSv4-10.2.1 - enable_strategy - low_complexity @@ -38556,240 +118236,277 @@ fi - medium_severity - no_reboot_needed - package_audit_installed - - include install_audit + +- name: Ensure audit is installed + package: + name: audit + state: present + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-000440 + - NIST-800-53-AC-7(a) + - NIST-800-53-AU-12(2) + - NIST-800-53-AU-14 + - NIST-800-53-AU-2(a) + - NIST-800-53-AU-7(1) + - NIST-800-53-AU-7(2) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-10.1 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - package_audit_installed + + include install_audit class install_audit { package { 'audit': ensure => 'installed', } } - - + + package --add=audit - - + + [[packages]] name = "audit" version = "*" - - - - - - - - - - Enable auditd Service - The auditd service is an essential userspace component of + + + + + + + + + + Enable auditd Service + The auditd service is an essential userspace component of the Linux Auditing System, as it is responsible for writing audit records to disk. The auditd service can be enabled with the following command: -$ sudo systemctl enable auditd.service - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 19 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 5.4.1.1 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - APO12.06 - APO13.01 - BAI03.05 - BAI08.02 - DSS01.03 - DSS01.04 - DSS02.02 - DSS02.04 - DSS02.07 - DSS03.01 - DSS03.05 - DSS05.02 - DSS05.03 - DSS05.04 - DSS05.05 - DSS05.07 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.3.1 - 3.3.2 - 3.3.6 - CCI-000126 - CCI-000130 - CCI-000131 - CCI-000132 - CCI-000133 - CCI-000134 - CCI-000135 - CCI-000154 - CCI-000158 - CCI-000172 - CCI-000366 - CCI-001464 - CCI-001487 - CCI-001814 - CCI-001875 - CCI-001876 - CCI-001877 - CCI-002884 - CCI-001878 - CCI-001879 - CCI-001880 - CCI-001881 - CCI-001882 - CCI-001889 - CCI-001914 - CCI-000169 - 164.308(a)(1)(ii)(D) - 164.308(a)(5)(ii)(C) - 164.310(a)(2)(iv) - 164.310(d)(2)(iii) - 164.312(b) - 4.2.3.10 - 4.3.2.6.7 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.3.6.6 - 4.3.4.4.7 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 1.13 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.6 - SR 2.8 - SR 2.9 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 6.1 - SR 6.2 - SR 7.1 - SR 7.6 - A.11.2.6 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.14.2.7 - A.15.2.1 - A.15.2.2 - A.16.1.4 - A.16.1.5 - A.16.1.7 - A.6.2.1 - A.6.2.2 - CIP-004-6 R3.3 - CIP-007-3 R6.5 - AC-2(g) - AU-3 - AU-10 - AU-2(d) - AU-12(c) - AU-14(1) - AC-6(9) - CM-6(a) - SI-4(23) - DE.AE-3 - DE.AE-5 - DE.CM-1 - DE.CM-3 - DE.CM-7 - ID.SC-4 - PR.AC-3 - PR.PT-1 - PR.PT-4 - RS.AN-1 - RS.AN-4 - FAU_GEN.1 - Req-10.1 - 10.2.1 - SRG-OS-000062-GPOS-00031 - SRG-OS-000037-GPOS-00015 - SRG-OS-000038-GPOS-00016 - SRG-OS-000039-GPOS-00017 - SRG-OS-000040-GPOS-00018 - SRG-OS-000041-GPOS-00019 - SRG-OS-000042-GPOS-00021 - SRG-OS-000051-GPOS-00024 - SRG-OS-000054-GPOS-00025 - SRG-OS-000122-GPOS-00063 - SRG-OS-000254-GPOS-00095 - SRG-OS-000255-GPOS-00096 - SRG-OS-000337-GPOS-00129 - SRG-OS-000348-GPOS-00136 - SRG-OS-000349-GPOS-00137 - SRG-OS-000350-GPOS-00138 - SRG-OS-000351-GPOS-00139 - SRG-OS-000352-GPOS-00140 - SRG-OS-000353-GPOS-00141 - SRG-OS-000354-GPOS-00142 - SRG-OS-000358-GPOS-00145 - SRG-OS-000365-GPOS-00152 - SRG-OS-000392-GPOS-00172 - SRG-OS-000475-GPOS-00220 - Without establishing what type of events occurred, it would be difficult +$ sudo systemctl enable auditd.service + + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 19 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 5.4.1.1 + APO10.01 + APO10.03 + APO10.04 + APO10.05 + APO11.04 + APO12.06 + APO13.01 + BAI03.05 + BAI08.02 + DSS01.03 + DSS01.04 + DSS02.02 + DSS02.04 + DSS02.07 + DSS03.01 + DSS03.05 + DSS05.02 + DSS05.03 + DSS05.04 + DSS05.05 + DSS05.07 + MEA01.01 + MEA01.02 + MEA01.03 + MEA01.04 + MEA01.05 + MEA02.01 + 3.3.1 + 3.3.2 + 3.3.6 + CCI-000133 + CCI-001881 + CCI-001875 + CCI-000154 + CCI-001882 + CCI-000158 + CCI-001914 + CCI-000169 + CCI-001464 + CCI-001878 + CCI-001877 + CCI-001889 + CCI-000135 + CCI-002884 + CCI-001487 + CCI-003938 + CCI-000132 + CCI-004188 + CCI-000134 + CCI-000172 + CCI-000130 + CCI-000131 + CCI-001879 + CCI-001880 + CCI-001876 + 164.308(a)(1)(ii)(D) + 164.308(a)(5)(ii)(C) + 164.310(a)(2)(iv) + 164.310(d)(2)(iii) + 164.312(b) + 4.2.3.10 + 4.3.2.6.7 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.3.6.6 + 4.3.4.4.7 + 4.3.4.5.6 + 4.3.4.5.7 + 4.3.4.5.8 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 1.13 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.6 + SR 2.8 + SR 2.9 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 6.1 + SR 6.2 + SR 7.1 + SR 7.6 + A.11.2.6 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.13.1.1 + A.13.2.1 + A.14.1.3 + A.14.2.7 + A.15.2.1 + A.15.2.2 + A.16.1.4 + A.16.1.5 + A.16.1.7 + A.6.2.1 + A.6.2.2 + CIP-004-6 R3.3 + CIP-007-3 R6.5 + AC-2(g) + AU-3 + AU-10 + AU-2(d) + AU-12(c) + AU-14(1) + AC-6(9) + CM-6(a) + SI-4(23) + DE.AE-3 + DE.AE-5 + DE.CM-1 + DE.CM-3 + DE.CM-7 + ID.SC-4 + PR.AC-3 + PR.PT-1 + PR.PT-4 + RS.AN-1 + RS.AN-4 + FAU_GEN.1 + Req-10.1 + SRG-OS-000062-GPOS-00031 + SRG-OS-000037-GPOS-00015 + SRG-OS-000038-GPOS-00016 + SRG-OS-000039-GPOS-00017 + SRG-OS-000040-GPOS-00018 + SRG-OS-000041-GPOS-00019 + SRG-OS-000042-GPOS-00021 + SRG-OS-000051-GPOS-00024 + SRG-OS-000054-GPOS-00025 + SRG-OS-000122-GPOS-00063 + SRG-OS-000254-GPOS-00095 + SRG-OS-000255-GPOS-00096 + SRG-OS-000337-GPOS-00129 + SRG-OS-000348-GPOS-00136 + SRG-OS-000349-GPOS-00137 + SRG-OS-000350-GPOS-00138 + SRG-OS-000351-GPOS-00139 + SRG-OS-000352-GPOS-00140 + SRG-OS-000353-GPOS-00141 + SRG-OS-000354-GPOS-00142 + SRG-OS-000358-GPOS-00145 + SRG-OS-000365-GPOS-00152 + SRG-OS-000392-GPOS-00172 + SRG-OS-000475-GPOS-00220 + SRG-APP-000095-CTR-000170 + SRG-APP-000409-CTR-000990 + SRG-APP-000508-CTR-001300 + SRG-APP-000510-CTR-001310 + R33 + R73 + 10.2.1 + 10.2 + OL09-00-000441 + SV-271520r1091272_rule + Without establishing what type of events occurred, it would be difficult to establish, correlate, and investigate the events leading up to an outage or attack. Ensuring the auditd service is active ensures audit records generated by the kernel are appropriately recorded. - + + Additionally, a properly configured audit subsystem ensures that actions of individual system users can be uniquely traced to those users so they -can be held accountable for their actions. - - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && { rpm --quiet -q audit; }; then +can be held accountable for their actions. + + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q audit; }; then SYSTEMCTL_EXEC='/usr/bin/systemctl' "$SYSTEMCTL_EXEC" unmask 'auditd.service' -"$SYSTEMCTL_EXEC" start 'auditd.service' +if [[ $("$SYSTEMCTL_EXEC" is-system-running) != "offline" ]]; then + "$SYSTEMCTL_EXEC" start 'auditd.service' +fi "$SYSTEMCTL_EXEC" enable 'auditd.service' else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000441 - NIST-800-171-3.3.1 - NIST-800-171-3.3.2 - NIST-800-171-3.3.6 @@ -38803,6 +118520,7 @@ fi - NIST-800-53-CM-6(a) - NIST-800-53-SI-4(23) - PCI-DSS-Req-10.1 + - PCI-DSSv4-10.2 - PCI-DSSv4-10.2.1 - enable_strategy - low_complexity @@ -38811,26 +118529,27 @@ fi - no_reboot_needed - service_auditd_enabled -- name: Enable service auditd +- name: Enable auditd Service - Enable service auditd block: - name: Gather the package facts package_facts: manager: auto - - name: Enable service auditd - systemd: + - name: Enable auditd Service - Enable Service auditd + ansible.builtin.systemd: name: auditd - enabled: 'yes' + enabled: true state: started - masked: 'no' + masked: false when: - '"audit" in ansible_facts.packages' when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"audit" in ansible_facts.packages' tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000441 - NIST-800-171-3.3.1 - NIST-800-171-3.3.2 - NIST-800-171-3.3.6 @@ -38844,6 +118563,7 @@ fi - NIST-800-53-CM-6(a) - NIST-800-53-SI-4(23) - PCI-DSS-Req-10.1 + - PCI-DSSv4-10.2 - PCI-DSSv4-10.2.1 - enable_strategy - low_complexity @@ -38851,8 +118571,8 @@ fi - medium_severity - no_reboot_needed - service_auditd_enabled - - include enable_auditd + + include enable_auditd class enable_auditd { service {'auditd': @@ -38860,8 +118580,8 @@ class enable_auditd { ensure => 'running', } } - - --- + + --- apiVersion: machineconfiguration.openshift.io/v1 kind: MachineConfig spec: @@ -38872,21 +118592,21 @@ spec: units: - name: auditd.service enabled: true - - + + [customizations.services] enabled = ["auditd"] - - - - - - - - - - Enable Auditing for Processes Which Start Prior to the Audit Daemon - To ensure all processes can be audited, even those which start + + + + + + + + + + Enable Auditing for Processes Which Start Prior to the Audit Daemon + To ensure all processes can be audited, even those which start prior to the audit daemon, add the argument audit=1 to the default GRUB 2 command line for the Linux operating system. To ensure that audit=1 is added as a kernel command line @@ -38894,147 +118614,166 @@ argument to newly installed kernels, add audit=1 to the default Grub2 command line for Linux operating systems. Modify the line within /etc/default/grub as shown below: GRUB_CMDLINE_LINUX="... audit=1 ..." -Run the following command to update command line for already installed kernels:# grubby --update-kernel=ALL --args="audit=1" - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 19 - 3 - 4 - 5 - 6 - 7 - 8 - 5.4.1.1 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - APO12.06 - APO13.01 - BAI03.05 - BAI08.02 - DSS01.04 - DSS02.02 - DSS02.04 - DSS02.07 - DSS03.01 - DSS05.02 - DSS05.03 - DSS05.04 - DSS05.07 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.3.1 - CCI-001464 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-000172 - CCI-002884 - 164.308(a)(1)(ii)(D) - 164.308(a)(5)(ii)(C) - 164.310(a)(2)(iv) - 164.310(d)(2)(iii) - 164.312(b) - 4.2.3.10 - 4.3.2.6.7 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.3.6.6 - 4.3.4.4.7 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 1.13 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.6 - SR 2.8 - SR 2.9 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 6.1 - SR 7.1 - SR 7.6 - A.11.2.6 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.15.2.1 - A.15.2.2 - A.16.1.4 - A.16.1.5 - A.16.1.7 - A.6.2.1 - A.6.2.2 - AC-17(1) - AU-14(1) - AU-10 - CM-6(a) - IR-5(1) - DE.AE-3 - DE.AE-5 - ID.SC-4 - PR.AC-3 - PR.PT-1 - PR.PT-4 - RS.AN-1 - RS.AN-4 - FAU_GEN.1 - Req-10.3 - 10.7 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-OS-000473-GPOS-00218 - SRG-OS-000254-GPOS-00095 - Each process on the system carries an "auditable" flag which indicates whether +Run the following command to update command line for already installed kernels:# grubby --update-kernel=ALL --args="audit=1" + + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 19 + 3 + 4 + 5 + 6 + 7 + 8 + 5.4.1.1 + APO10.01 + APO10.03 + APO10.04 + APO10.05 + APO11.04 + APO12.06 + APO13.01 + BAI03.05 + BAI08.02 + DSS01.04 + DSS02.02 + DSS02.04 + DSS02.07 + DSS03.01 + DSS05.02 + DSS05.03 + DSS05.04 + DSS05.07 + MEA01.01 + MEA01.02 + MEA01.03 + MEA01.04 + MEA01.05 + MEA02.01 + 3.3.1 + CCI-000172 + CCI-000130 + CCI-000135 + CCI-000169 + CCI-002884 + CCI-001464 + 164.308(a)(1)(ii)(D) + 164.308(a)(5)(ii)(C) + 164.310(a)(2)(iv) + 164.310(d)(2)(iii) + 164.312(b) + 4.2.3.10 + 4.3.2.6.7 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.3.6.6 + 4.3.4.4.7 + 4.3.4.5.6 + 4.3.4.5.7 + 4.3.4.5.8 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 1.13 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.6 + SR 2.8 + SR 2.9 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 6.1 + SR 7.1 + SR 7.6 + A.11.2.6 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.13.1.1 + A.13.2.1 + A.14.1.3 + A.15.2.1 + A.15.2.2 + A.16.1.4 + A.16.1.5 + A.16.1.7 + A.6.2.1 + A.6.2.2 + AC-17(1) + AU-14(1) + AU-10 + CM-6(a) + IR-5(1) + DE.AE-3 + DE.AE-5 + ID.SC-4 + PR.AC-3 + PR.PT-1 + PR.PT-4 + RS.AN-1 + RS.AN-4 + FAU_GEN.1 + Req-10.3 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-OS-000473-GPOS-00218 + SRG-OS-000254-GPOS-00095 + 10.7.2 + 10.7 + OL09-00-000750 + SV-271577r1091443_rule + Each process on the system carries an "auditable" flag which indicates whether its activities can be audited. Although auditd takes care of enabling this for all processes which launch after it does, adding the kernel argument -ensures it is set for every process during boot. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && { rpm --quiet -q grub2-common; }; then +ensures it is set for every process during boot. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q grub2-common; }; then -grubby --update-kernel=ALL --args=audit=1 +expected_value="1" + + +if [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; then + KARGS_DIR="/usr/lib/bootc/kargs.d/" + if grep -q -E "audit" "$KARGS_DIR/*.toml" ; then + sed -i -E "s/^(\s*kargs\s*=\s*\[.*)\"audit=[^\"]*\"(.*]\s*)/\1\"audit=$expected_value\"\2/" "$KARGS_DIR/*.toml" + else + echo "kargs = [\"audit=$expected_value\"]" >> "$KARGS_DIR/10-audit.toml" + fi +else + + grubby --update-kernel=ALL --args=audit=1 + +fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000750 - NIST-800-171-3.3.1 - NIST-800-53-AC-17(1) - NIST-800-53-AU-10 @@ -39043,6 +118782,7 @@ fi - NIST-800-53-IR-5(1) - PCI-DSS-Req-10.3 - PCI-DSSv4-10.7 + - PCI-DSSv4-10.7.2 - grub2_audit_argument - low_disruption - low_severity @@ -39053,10 +118793,11 @@ fi - name: Update grub defaults and the bootloader menu command: /sbin/grubby --update-kernel=ALL --args="audit=1" when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"grub2-common" in ansible_facts.packages' tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000750 - NIST-800-171-3.3.1 - NIST-800-53-AC-17(1) - NIST-800-53-AU-10 @@ -39065,26 +118806,27 @@ fi - NIST-800-53-IR-5(1) - PCI-DSS-Req-10.3 - PCI-DSSv4-10.7 + - PCI-DSSv4-10.7.2 - grub2_audit_argument - low_disruption - low_severity - medium_complexity - reboot_required - restrict_strategy - - [customizations.kernel] + + [customizations.kernel] append = "audit=1" - - - - - - - - - - Extend Audit Backlog Limit for the Audit Daemon - To improve the kernel capacity to queue all log events, even those which occurred + + + + + + + + + + Extend Audit Backlog Limit for the Audit Daemon + To improve the kernel capacity to queue all log events, even those which occurred prior to the audit daemon, add the argument audit_backlog_limit=8192 to the default GRUB 2 command line for the Linux operating system. To ensure that audit_backlog_limit=8192 is added as a kernel command line @@ -39092,43 +118834,61 @@ argument to newly installed kernels, add audit_backlog_limit=8192/etc/default/grub as shown below: GRUB_CMDLINE_LINUX="... audit_backlog_limit=8192 ..." -Run the following command to update command line for already installed kernels:# grubby --update-kernel=ALL --args="audit_backlog_limit=8192" - CCI-000130 - CCI-000135 - CCI-000169 - CCI-000172 - CCI-001849 - CCI-002884 - CM-6(a) - FAU_STG.1 - FAU_STG.3 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000254-GPOS-00095 - SRG-OS-000341-GPOS-00132 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - audit_backlog_limit sets the queue length for audit events awaiting transfer +Run the following command to update command line for already installed kernels:# grubby --update-kernel=ALL --args="audit_backlog_limit=8192" + + CCI-001849 + CCI-001464 + CM-6(a) + FAU_STG.1 + FAU_STG.3 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000254-GPOS-00095 + SRG-OS-000341-GPOS-00132 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + 10.7.2 + 10.7 + OL09-00-000830 + SV-271592r1091488_rule + audit_backlog_limit sets the queue length for audit events awaiting transfer to the audit daemon. Until the audit daemon is up and running, all log messages are stored in this queue. If the queue is overrun during boot process, the action -defined by audit failure flag is taken. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && { rpm --quiet -q grub2-common; }; then +defined by audit failure flag is taken. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q grub2-common; }; then -grubby --update-kernel=ALL --args=audit_backlog_limit=8192 +expected_value="8192" + + +if [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; then + KARGS_DIR="/usr/lib/bootc/kargs.d/" + if grep -q -E "audit_backlog_limit" "$KARGS_DIR/*.toml" ; then + sed -i -E "s/^(\s*kargs\s*=\s*\[.*)\"audit_backlog_limit=[^\"]*\"(.*]\s*)/\1\"audit_backlog_limit=$expected_value\"\2/" "$KARGS_DIR/*.toml" + else + echo "kargs = [\"audit_backlog_limit=$expected_value\"]" >> "$KARGS_DIR/10-audit_backlog_limit.toml" + fi +else + + grubby --update-kernel=ALL --args=audit_backlog_limit=8192 + +fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-000830 - NIST-800-53-CM-6(a) + - PCI-DSSv4-10.7 + - PCI-DSSv4-10.7.2 - grub2_audit_backlog_limit_argument - low_disruption - low_severity @@ -39139,76 +118899,84 @@ fi - name: Update grub defaults and the bootloader menu command: /sbin/grubby --update-kernel=ALL --args="audit_backlog_limit=8192" when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"grub2-common" in ansible_facts.packages' tags: + - DISA-STIG-OL09-00-000830 - NIST-800-53-CM-6(a) + - PCI-DSSv4-10.7 + - PCI-DSSv4-10.7.2 - grub2_audit_backlog_limit_argument - low_disruption - low_severity - medium_complexity - reboot_required - restrict_strategy - - [customizations.kernel] + + [customizations.kernel] append = "audit_backlog_limit=8192" - - - - - - - - - - Configure auditd Rules for Comprehensive Auditing - The auditd program can perform comprehensive + + + + + + + + + + Configure auditd Rules for Comprehensive Auditing + The auditd program can perform comprehensive monitoring of system activity. This section describes recommended configuration settings for comprehensive auditing, but a full description of the auditing system's capabilities is beyond the scope of this guide. The mailing list linux-audit@redhat.com exists to facilitate community discussion of the auditing system. - + + The audit subsystem supports extensive collection of events, including: - -Tracing of arbitrary system calls (identified by name or number) + + Tracing of arbitrary system calls (identified by name or number) on entry or exit.Filtering by PID, UID, call success, system call argument (with some limitations), etc.Monitoring of specific files for modifications to the file's contents or metadata. - + Auditing rules at startup are controlled by the file /etc/audit/audit.rules. Add rules to it to meet the auditing requirements for your organization. Each line in /etc/audit/audit.rules represents a series of arguments that can be passed to auditctl and can be individually tested -during runtime. See documentation in /usr/share/doc/audit-VERSION and +during runtime. See documentation in /usr/share/doc/audit-VERSION + and in the related man pages for more details. - + + If copying any example audit rulesets from /usr/share/doc/audit-VERSION, be sure to comment out the lines containing arch= which are not appropriate for your system's architecture. Then review and understand the following rules, ensuring rules are activated as needed for the appropriate architecture. - + + After reviewing all the rules, reading the following sections, and editing as needed, the new rules can be activated as follows: -$ sudo service auditd restart - - - Audit failure mode - This variable is the setting for the -f option in Audit configuration which sets the failure mode of audit. +$ sudo service auditd restart + + + + Audit failure mode + This variable is the setting for the -f option in Audit configuration which sets the failure mode of audit. This option lets you determine how you want the kernel to handle critical errors. Possible values are: 0=silent, 1=printk, 2=panic. If the value is set to "2", the system is configured to panic (shut down) in the event of an auditing failure. -If the value is set to "1", the system is configured to only send information to the kernel log regarding the failure. - 2 - 0 - 1 - 2 - - - Make the auditd Configuration Immutable - If the auditd daemon is configured to use the +If the value is set to "1", the system is configured to only send information to the kernel log regarding the failure. + 2 + 0 + 1 + 2 + + + Make the auditd Configuration Immutable + If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following line to a file with suffix .rules in the directory /etc/audit/rules.d in order to make the auditd configuration @@ -39219,134 +118987,139 @@ utility to read audit rules during daemon startup, add the following line to /etc/audit/audit.rules file in order to make the auditd configuration immutable: -e 2 -With this setting, a reboot will be required to change any audit rules. - BP28(R73) - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 18 - 19 - 3 - 4 - 5 - 6 - 7 - 8 - 5.4.1.1 - APO01.06 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - APO12.06 - BAI03.05 - BAI08.02 - DSS02.02 - DSS02.04 - DSS02.07 - DSS03.01 - DSS05.04 - DSS05.07 - DSS06.02 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.3.1 - 3.4.3 - CCI-000162 - CCI-000163 - CCI-000164 - 164.308(a)(1)(ii)(D) - 164.308(a)(3)(ii)(A) - 164.308(a)(5)(ii)(C) - 164.312(a)(2)(i) - 164.310(a)(2)(iv) - 164.312(d) - 164.310(d)(2)(iii) - 164.312(b) - 164.312(e) - 4.2.3.10 - 4.3.2.6.7 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.3.7.3 - 4.3.4.4.7 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 2.1 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.8 - SR 2.9 - SR 5.2 - SR 6.1 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.15.2.1 - A.15.2.2 - A.16.1.4 - A.16.1.5 - A.16.1.7 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - AC-6(9) - CM-6(a) - DE.AE-3 - DE.AE-5 - ID.SC-4 - PR.AC-4 - PR.DS-5 - PR.PT-1 - RS.AN-1 - RS.AN-4 - Req-10.5.2 - 10.3.2 - SRG-OS-000057-GPOS-00027 - SRG-OS-000058-GPOS-00028 - SRG-OS-000059-GPOS-00029 - Making the audit configuration immutable prevents accidental as +With this setting, a reboot will be required to change any audit rules. + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 18 + 19 + 3 + 4 + 5 + 6 + 7 + 8 + 5.4.1.1 + APO01.06 + APO10.01 + APO10.03 + APO10.04 + APO10.05 + APO11.04 + APO12.06 + BAI03.05 + BAI08.02 + DSS02.02 + DSS02.04 + DSS02.07 + DSS03.01 + DSS05.04 + DSS05.07 + DSS06.02 + MEA01.01 + MEA01.02 + MEA01.03 + MEA01.04 + MEA01.05 + MEA02.01 + 3.3.1 + 3.4.3 + CCI-000163 + CCI-000164 + CCI-000162 + 164.308(a)(1)(ii)(D) + 164.308(a)(3)(ii)(A) + 164.308(a)(5)(ii)(C) + 164.312(a)(2)(i) + 164.310(a)(2)(iv) + 164.312(d) + 164.310(d)(2)(iii) + 164.312(b) + 164.312(e) + 4.2.3.10 + 4.3.2.6.7 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.3.7.3 + 4.3.4.4.7 + 4.3.4.5.6 + 4.3.4.5.7 + 4.3.4.5.8 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 2.1 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.8 + SR 2.9 + SR 5.2 + SR 6.1 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.15.2.1 + A.15.2.2 + A.16.1.4 + A.16.1.5 + A.16.1.7 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + AC-6(9) + CM-6(a) + DE.AE-3 + DE.AE-5 + ID.SC-4 + PR.AC-4 + PR.DS-5 + PR.PT-1 + RS.AN-1 + RS.AN-4 + Req-10.5.2 + SRG-OS-000057-GPOS-00027 + SRG-OS-000058-GPOS-00028 + SRG-OS-000059-GPOS-00029 + SRG-APP-000119-CTR-000245 + SRG-APP-000120-CTR-000250 + R73 + 10.3.2 + 10.3 + OL09-00-008005 + SV-271886r1092370_rule + Making the audit configuration immutable prevents accidental as well as malicious modification of the audit rules, although it may be problematic if legitimate changes are needed during system -operation. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +operation. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then # Traverse all of: # @@ -39369,22 +119142,25 @@ do echo '# Reboot is required to change audit rules once this setting is applied' >> $AUDIT_FILE echo '-e 2' >> $AUDIT_FILE chmod o-rwx $AUDIT_FILE + chmod g-rwx $AUDIT_FILE done else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-008005 - NIST-800-171-3.3.1 - NIST-800-171-3.4.3 - NIST-800-53-AC-6(9) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.2 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.2 - audit_rules_immutable - low_complexity @@ -39400,14 +119176,16 @@ fi register: find_rules_d when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-008005 - NIST-800-171-3.3.1 - NIST-800-171-3.4.3 - NIST-800-53-AC-6(9) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.2 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.2 - audit_rules_immutable - low_complexity @@ -39425,14 +119203,16 @@ fi }}' when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-008005 - NIST-800-171-3.3.1 - NIST-800-171-3.4.3 - NIST-800-53-AC-6(9) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.2 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.2 - audit_rules_immutable - low_complexity @@ -39446,20 +119226,22 @@ fi path: '{{ item }}' create: true line: -e 2 - mode: o-rwx + mode: g-rwx,o-rwx loop: - /etc/audit/audit.rules - /etc/audit/rules.d/immutable.rules when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-008005 - NIST-800-171-3.3.1 - NIST-800-171-3.4.3 - NIST-800-53-AC-6(9) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.2 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.2 - audit_rules_immutable - low_complexity @@ -39467,148 +119249,296 @@ fi - medium_severity - reboot_required - restrict_strategy - - - - - - - - - - Record Events that Modify the System's Mandatory Access Controls - If the auditd daemon is configured to use the + + + + + + + + + + Configure immutable Audit login UIDs + Configure kernel to prevent modification of login UIDs once they are set. +Changing login UIDs while this configuration is enforced requires special capabilities which +are not available to unprivileged users. +If the auditd daemon is configured to use the +augenrules program to read audit rules during daemon startup (the +default), add the following line to a file with suffix .rules in the +directory /etc/audit/rules.d in order to make login UIDs +immutable: +--loginuid-immutable +If the auditd daemon is configured to use the auditctl +utility to read audit rules during daemon startup, add the following line to +/etc/audit/audit.rules file in order to make login UIDs +immutable: +--loginuid-immutable + + CCI-000163 + CCI-000172 + CCI-000164 + CCI-000162 + SRG-OS-000462-GPOS-00206 + SRG-OS-000475-GPOS-00220 + SRG-OS-000057-GPOS-00027 + SRG-OS-000058-GPOS-00028 + SRG-OS-000059-GPOS-00029 + OL09-00-008000 + SV-271885r1092367_rule + If modification of login UIDs is not prevented, they can be changed by unprivileged users and +make auditing complicated or impossible. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# in case auditctl is used +if grep -q '^\s*ExecStartPost=-/sbin/auditctl' /usr/lib/systemd/system/auditd.service; then + if ! grep -q '^\s*--loginuid-immutable\s*$' /etc/audit/audit.rules; then + echo "--loginuid-immutable" >> /etc/audit/audit.rules + fi +else + immutable_found=0 + while IFS= read -r -d '' f; do + if grep -q '^\s*--loginuid-immutable\s*$' "$f"; then + immutable_found=1 + fi + done < <(find /etc/audit/rules.d -maxdepth 1 -name '*.rules' -print0) + if [ $immutable_found -eq 0 ]; then + echo "--loginuid-immutable" >> /etc/audit/rules.d/immutable.rules + fi +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-008000 + - audit_rules_immutable_login_uids + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: 'Configure immutable Audit login UIDs: Determine if rules are loaded by auditctl' + ansible.builtin.find: + paths: /usr/lib/systemd/system + patterns: auditd.service + contains: ^\s*ExecStartPost=-/sbin/auditctl + register: auditctl_used + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-008000 + - audit_rules_immutable_login_uids + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: 'Configure immutable Audit login UIDs: Configure immutable login UIDs in /etc/audit/audit.rules' + ansible.builtin.lineinfile: + path: /etc/audit/audit.rules + line: --loginuid-immutable + regexp: ^\s*--loginuid-immutable\s*$ + mode: '0600' + create: true + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - auditctl_used is defined and auditctl_used.matched >= 1 + tags: + - DISA-STIG-OL09-00-008000 + - audit_rules_immutable_login_uids + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: 'Configure immutable Audit login UIDs: In case Augen-rules is used' + block: + + - name: 'Configure immutable Audit login UIDs: Detect if immutable login UIDs are + already defined in /etc/audit/rules.d/*.rules' + ansible.builtin.find: + paths: /etc/audit/rules.d + patterns: '*.rules' + contains: ^\s*--loginuid-immutable\s*$ + register: immutable_found_in_rules_d + + - name: 'Configure immutable Audit login UIDs: set immutable login UIDS in /etc/audit/rules.d/immutable.rules' + ansible.builtin.lineinfile: + path: /etc/audit/rules.d/immutable.rules + line: --loginuid-immutable + regexp: ^\s*--loginuid-immutable\s*$ + mode: '0600' + create: true + when: immutable_found_in_rules_d is defined and immutable_found_in_rules_d.matched + == 0 + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - auditctl_used is defined and auditctl_used.matched == 0 + tags: + - DISA-STIG-OL09-00-008000 + - audit_rules_immutable_login_uids + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + + + + + + + + + + Record Events that Modify the System's Mandatory Access Controls + If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following line to a file with suffix .rules in the directory /etc/audit/rules.d: + -w /etc/selinux/ -p wa -k MAC-policy + If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following line to /etc/audit/audit.rules file: --w /etc/selinux/ -p wa -k MAC-policy - BP28(R73) - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 19 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 5.4.1.1 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - APO12.06 - APO13.01 - BAI03.05 - BAI08.02 - DSS01.03 - DSS01.04 - DSS02.02 - DSS02.04 - DSS02.07 - DSS03.01 - DSS03.05 - DSS05.02 - DSS05.03 - DSS05.04 - DSS05.05 - DSS05.07 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.1.8 - 164.308(a)(1)(ii)(D) - 164.308(a)(3)(ii)(A) - 164.308(a)(5)(ii)(C) - 164.312(a)(2)(i) - 164.312(b) - 164.312(d) - 164.312(e) - 4.2.3.10 - 4.3.2.6.7 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.3.6.6 - 4.3.4.4.7 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 1.13 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.6 - SR 2.8 - SR 2.9 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 6.1 - SR 6.2 - SR 7.1 - SR 7.6 - A.11.2.6 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.14.2.7 - A.15.2.1 - A.15.2.2 - A.16.1.4 - A.16.1.5 - A.16.1.7 - A.6.2.1 - A.6.2.2 - AU-2(d) - AU-12(c) - CM-6(a) - DE.AE-3 - DE.AE-5 - DE.CM-1 - DE.CM-3 - DE.CM-7 - ID.SC-4 - PR.AC-3 - PR.PT-1 - PR.PT-4 - RS.AN-1 - RS.AN-4 - FAU_GEN.1.1.c - Req-10.5.5 - 10.3.4 - The system's mandatory access policy (SELinux) should not be + +-w /etc/selinux/ -p wa -k MAC-policy + + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 19 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 5.4.1.1 + APO10.01 + APO10.03 + APO10.04 + APO10.05 + APO11.04 + APO12.06 + APO13.01 + BAI03.05 + BAI08.02 + DSS01.03 + DSS01.04 + DSS02.02 + DSS02.04 + DSS02.07 + DSS03.01 + DSS03.05 + DSS05.02 + DSS05.03 + DSS05.04 + DSS05.05 + DSS05.07 + MEA01.01 + MEA01.02 + MEA01.03 + MEA01.04 + MEA01.05 + MEA02.01 + 3.1.8 + 164.308(a)(1)(ii)(D) + 164.308(a)(3)(ii)(A) + 164.308(a)(5)(ii)(C) + 164.312(a)(2)(i) + 164.312(b) + 164.312(d) + 164.312(e) + 4.2.3.10 + 4.3.2.6.7 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.3.6.6 + 4.3.4.4.7 + 4.3.4.5.6 + 4.3.4.5.7 + 4.3.4.5.8 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 1.13 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.6 + SR 2.8 + SR 2.9 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 6.1 + SR 6.2 + SR 7.1 + SR 7.6 + A.11.2.6 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.13.1.1 + A.13.2.1 + A.14.1.3 + A.14.2.7 + A.15.2.1 + A.15.2.2 + A.16.1.4 + A.16.1.5 + A.16.1.7 + A.6.2.1 + A.6.2.2 + AU-2(d) + AU-12(c) + CM-6(a) + DE.AE-3 + DE.AE-5 + DE.CM-1 + DE.CM-3 + DE.CM-7 + ID.SC-4 + PR.AC-3 + PR.PT-1 + PR.PT-4 + RS.AN-1 + RS.AN-4 + Req-10.5.5 + R73 + 10.3.4 + 10.3 + The system's mandatory access policy (SELinux or Apparmor) should not be arbitrarily changed by anything other than administrator action. All changes to -MAC policy should be audited. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +MAC policy should be audited. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' # Create a list of audit *.rules files that should be inspected for presence and correctness @@ -39701,7 +119631,7 @@ then if [ ! -e "$key_rule_file" ] then touch "$key_rule_file" - chmod 0640 "$key_rule_file" + chmod 0600 "$key_rule_file" fi files_to_inspect+=("$key_rule_file") fi @@ -39747,8 +119677,8 @@ done else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: @@ -39758,6 +119688,7 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_mac_modification - low_complexity @@ -39774,7 +119705,7 @@ fi register: find_existing_watch_rules_d when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.4.1.1 - NIST-800-171-3.1.8 @@ -39782,6 +119713,7 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_mac_modification - low_complexity @@ -39798,7 +119730,7 @@ fi register: find_watch_key when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: @@ -39808,6 +119740,7 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_mac_modification - low_complexity @@ -39822,7 +119755,7 @@ fi - /etc/audit/rules.d/MAC-policy.rules when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_watch_key.matched is defined and find_watch_key.matched == 0 and find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: @@ -39832,6 +119765,7 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_mac_modification - low_complexity @@ -39846,7 +119780,7 @@ fi - '{{ find_watch_key.files | map(attribute=''path'') | list | first }}' when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_watch_key.matched is defined and find_watch_key.matched > 0 and find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: @@ -39856,6 +119790,7 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_mac_modification - low_complexity @@ -39869,10 +119804,10 @@ fi path: '{{ all_files[0] }}' line: -w /etc/selinux/ -p wa -k MAC-policy create: true - mode: '0640' + mode: '0600' when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: @@ -39882,6 +119817,7 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_mac_modification - low_complexity @@ -39898,7 +119834,7 @@ fi register: find_existing_watch_audit_rules when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.4.1.1 - NIST-800-171-3.1.8 @@ -39906,6 +119842,7 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_mac_modification - low_complexity @@ -39920,10 +119857,10 @@ fi state: present dest: /etc/audit/audit.rules create: true - mode: '0640' + mode: '0600' when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_existing_watch_audit_rules.matched is defined and find_existing_watch_audit_rules.matched == 0 tags: @@ -39933,6 +119870,7 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_mac_modification - low_complexity @@ -39940,17 +119878,17 @@ fi - medium_severity - reboot_required - restrict_strategy - - - - - - - - - - Record Events that Modify the System's Mandatory Access Controls in usr/share - If the auditd daemon is configured to use the + + + + + + + + + + Record Events that Modify the System's Mandatory Access Controls in usr/share + If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following line to a file with suffix .rules in the directory /etc/audit/rules.d: @@ -39958,111 +119896,111 @@ directory /etc/audit/rules.d: If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following line to /etc/audit/audit.rules file: --w /usr/share/selinux/ -p wa -k MAC-policy - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - APO12.06 - APO13.01 - BAI03.05 - BAI08.02 - DSS01.03 - DSS01.04 - DSS02.02 - DSS02.04 - DSS02.07 - DSS03.01 - DSS03.05 - DSS05.02 - DSS05.03 - DSS05.04 - DSS05.05 - DSS05.07 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.1.8 - 164.308(a)(1)(ii)(D) - 164.308(a)(3)(ii)(A) - 164.308(a)(5)(ii)(C) - 164.312(a)(2)(i) - 164.312(b) - 164.312(d) - 164.312(e) - 4.2.3.10 - 4.3.2.6.7 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.3.6.6 - 4.3.4.4.7 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 1.13 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.6 - SR 2.8 - SR 2.9 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 6.1 - SR 6.2 - SR 7.1 - SR 7.6 - A.11.2.6 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.14.2.7 - A.15.2.1 - A.15.2.2 - A.16.1.4 - A.16.1.5 - A.16.1.7 - A.6.2.1 - A.6.2.2 - AU-2(d) - AU-12(c) - CM-6(a) - DE.AE-3 - DE.AE-5 - DE.CM-1 - DE.CM-3 - DE.CM-7 - ID.SC-4 - PR.AC-3 - PR.PT-1 - PR.PT-4 - RS.AN-1 - RS.AN-4 - FAU_GEN.1.1.c - Req-10.5.5 - The system's mandatory access policy (SELinux) should not be +-w /usr/share/selinux/ -p wa -k MAC-policy + + APO10.01 + APO10.03 + APO10.04 + APO10.05 + APO11.04 + APO12.06 + APO13.01 + BAI03.05 + BAI08.02 + DSS01.03 + DSS01.04 + DSS02.02 + DSS02.04 + DSS02.07 + DSS03.01 + DSS03.05 + DSS05.02 + DSS05.03 + DSS05.04 + DSS05.05 + DSS05.07 + MEA01.01 + MEA01.02 + MEA01.03 + MEA01.04 + MEA01.05 + MEA02.01 + 3.1.8 + 164.308(a)(1)(ii)(D) + 164.308(a)(3)(ii)(A) + 164.308(a)(5)(ii)(C) + 164.312(a)(2)(i) + 164.312(b) + 164.312(d) + 164.312(e) + 4.2.3.10 + 4.3.2.6.7 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.3.6.6 + 4.3.4.4.7 + 4.3.4.5.6 + 4.3.4.5.7 + 4.3.4.5.8 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 1.13 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.6 + SR 2.8 + SR 2.9 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 6.1 + SR 6.2 + SR 7.1 + SR 7.6 + A.11.2.6 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.13.1.1 + A.13.2.1 + A.14.1.3 + A.14.2.7 + A.15.2.1 + A.15.2.2 + A.16.1.4 + A.16.1.5 + A.16.1.7 + A.6.2.1 + A.6.2.2 + AU-2(d) + AU-12(c) + CM-6(a) + DE.AE-3 + DE.AE-5 + DE.CM-1 + DE.CM-3 + DE.CM-7 + ID.SC-4 + PR.AC-3 + PR.PT-1 + PR.PT-4 + RS.AN-1 + RS.AN-4 + Req-10.5.5 + The system's mandatory access policy (SELinux) should not be arbitrarily changed by anything other than administrator action. All changes to -MAC policy should be audited. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +MAC policy should be audited. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' # Create a list of audit *.rules files that should be inspected for presence and correctness @@ -40155,7 +120093,7 @@ then if [ ! -e "$key_rule_file" ] then touch "$key_rule_file" - chmod 0640 "$key_rule_file" + chmod 0600 "$key_rule_file" fi files_to_inspect+=("$key_rule_file") fi @@ -40201,8 +120139,8 @@ done else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: @@ -40226,7 +120164,7 @@ fi register: find_existing_watch_rules_d when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-171-3.1.8 - NIST-800-53-AU-12(c) @@ -40248,7 +120186,7 @@ fi register: find_watch_key when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: @@ -40270,7 +120208,7 @@ fi - /etc/audit/rules.d/MAC-policy.rules when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_watch_key.matched is defined and find_watch_key.matched == 0 and find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: @@ -40292,7 +120230,7 @@ fi - '{{ find_watch_key.files | map(attribute=''path'') | list | first }}' when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_watch_key.matched is defined and find_watch_key.matched > 0 and find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: @@ -40313,10 +120251,10 @@ fi path: '{{ all_files[0] }}' line: -w /usr/share/selinux/ -p wa -k MAC-policy create: true - mode: '0640' + mode: '0600' when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: @@ -40340,7 +120278,7 @@ fi register: find_existing_watch_audit_rules when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-171-3.1.8 - NIST-800-53-AU-12(c) @@ -40360,10 +120298,10 @@ fi state: present dest: /etc/audit/audit.rules create: true - mode: '0640' + mode: '0600' when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_existing_watch_audit_rules.matched is defined and find_existing_watch_audit_rules.matched == 0 tags: @@ -40378,17 +120316,17 @@ fi - medium_severity - reboot_required - restrict_strategy - - - - - - - - - - Ensure auditd Collects Information on Exporting to Media (successful) - At a minimum, the audit system should collect media exportation + + + + + + + + + + Ensure auditd Collects Information on Exporting to Media (successful) + At a minimum, the audit system should collect media exportation events for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following line to a file with suffix .rules in @@ -40399,142 +120337,147 @@ If the auditd daemon is configured to use the utility to read audit rules during daemon startup, add the following line to /etc/audit/audit.rules file, setting ARCH to either b32 or b64 as appropriate for your system: --a always,exit -F arch=ARCH -S mount -F auid>=1000 -F auid!=unset -F key=export - BP28(R73) - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 19 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 5.4.1.1 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - APO12.06 - APO13.01 - BAI03.05 - BAI08.02 - DSS01.03 - DSS01.04 - DSS02.02 - DSS02.04 - DSS02.07 - DSS03.01 - DSS03.05 - DSS05.02 - DSS05.03 - DSS05.04 - DSS05.05 - DSS05.07 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.1.7 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-000172 - CCI-002884 - 164.308(a)(1)(ii)(D) - 164.308(a)(3)(ii)(A) - 164.308(a)(5)(ii)(C) - 164.312(a)(2)(i) - 164.312(b) - 164.312(d) - 164.312(e) - 4.2.3.10 - 4.3.2.6.7 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.3.6.6 - 4.3.4.4.7 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 1.13 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.6 - SR 2.8 - SR 2.9 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 6.1 - SR 6.2 - SR 7.1 - SR 7.6 - A.11.2.6 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.14.2.7 - A.15.2.1 - A.15.2.2 - A.16.1.4 - A.16.1.5 - A.16.1.7 - A.6.2.1 - A.6.2.2 - AU-2(d) - AU-12(c) - AC-6(9) - CM-6(a) - DE.AE-3 - DE.AE-5 - DE.CM-1 - DE.CM-3 - DE.CM-7 - ID.SC-4 - PR.AC-3 - PR.PT-1 - PR.PT-4 - RS.AN-1 - RS.AN-4 - Req-10.2.7 - 10.2.1.7 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - The unauthorized exportation of data to external media could result in an information leak +-a always,exit -F arch=ARCH -S mount -F auid>=1000 -F auid!=unset -F key=export + + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 19 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 5.4.1.1 + APO10.01 + APO10.03 + APO10.04 + APO10.05 + APO11.04 + APO12.06 + APO13.01 + BAI03.05 + BAI08.02 + DSS01.03 + DSS01.04 + DSS02.02 + DSS02.04 + DSS02.07 + DSS03.01 + DSS03.05 + DSS05.02 + DSS05.03 + DSS05.04 + DSS05.05 + DSS05.07 + MEA01.01 + MEA01.02 + MEA01.03 + MEA01.04 + MEA01.05 + MEA02.01 + 3.1.7 + CCI-000130 + CCI-000135 + CCI-000169 + CCI-000172 + CCI-002884 + 164.308(a)(1)(ii)(D) + 164.308(a)(3)(ii)(A) + 164.308(a)(5)(ii)(C) + 164.312(a)(2)(i) + 164.312(b) + 164.312(d) + 164.312(e) + 4.2.3.10 + 4.3.2.6.7 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.3.6.6 + 4.3.4.4.7 + 4.3.4.5.6 + 4.3.4.5.7 + 4.3.4.5.8 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 1.13 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.6 + SR 2.8 + SR 2.9 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 6.1 + SR 6.2 + SR 7.1 + SR 7.6 + A.11.2.6 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.13.1.1 + A.13.2.1 + A.14.1.3 + A.14.2.7 + A.15.2.1 + A.15.2.2 + A.16.1.4 + A.16.1.5 + A.16.1.7 + A.6.2.1 + A.6.2.2 + AU-2(d) + AU-12(c) + AC-6(9) + CM-6(a) + DE.AE-3 + DE.AE-5 + DE.CM-1 + DE.CM-3 + DE.CM-7 + ID.SC-4 + PR.AC-3 + PR.PT-1 + PR.PT-4 + RS.AN-1 + RS.AN-4 + Req-10.2.7 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-APP-000495-CTR-001235 + R73 + A.3.SEC-OL10 + 10.2.1.7 + 10.2.1 + 10.2 + The unauthorized exportation of data to external media could result in an information leak where classified information, Privacy Act information, and intellectual property could be lost. An audit trail should be created each time a filesystem is mounted to help identify and guard against information -loss. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +loss. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then # First perform the remediation of the syscall rule # Retrieve hardware architecture of the underlying system @@ -40579,7 +120522,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -40595,7 +120537,7 @@ then if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -40687,7 +120629,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -40740,7 +120682,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -40834,7 +120775,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -40862,8 +120803,8 @@ done else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: @@ -40874,6 +120815,8 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.7 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.7 - audit_rules_media_export - low_complexity @@ -40887,7 +120830,7 @@ fi audit_arch: b64 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - ansible_architecture == "aarch64" or ansible_architecture == "ppc64" or ansible_architecture == "ppc64le" or ansible_architecture == "s390x" or ansible_architecture == "x86_64" tags: @@ -40898,6 +120841,8 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.7 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.7 - audit_rules_media_export - low_complexity @@ -40969,6 +120914,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -40977,7 +120923,7 @@ fi line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -41015,6 +120961,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -41023,12 +120970,12 @@ fi line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.4.1.1 - NIST-800-171-3.1.7 @@ -41037,6 +120984,8 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.7 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.7 - audit_rules_media_export - low_complexity @@ -41108,6 +121057,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -41116,7 +121066,7 @@ fi line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -41154,6 +121104,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -41162,12 +121113,12 @@ fi line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - audit_arch == "b64" tags: - CJIS-5.4.1.1 @@ -41177,6 +121128,8 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.7 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.7 - audit_rules_media_export - low_complexity @@ -41184,17 +121137,17 @@ fi - medium_severity - reboot_required - restrict_strategy - - - - - - - - - - Record Events that Modify the System's Network Environment - If the auditd daemon is configured to use the + + + + + + + + + + Record Events that Modify the System's Network Environment + If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following lines to a file with suffix .rules in the directory /etc/audit/rules.d, setting ARCH to either b32 or b64 as @@ -41203,7 +121156,9 @@ appropriate for your system: -w /etc/issue -p wa -k audit_rules_networkconfig_modification -w /etc/issue.net -p wa -k audit_rules_networkconfig_modification -w /etc/hosts -p wa -k audit_rules_networkconfig_modification + -w /etc/sysconfig/network -p wa -k audit_rules_networkconfig_modification + If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following lines to /etc/audit/audit.rules file, setting ARCH to either b32 or b64 as @@ -41212,130 +121167,132 @@ appropriate for your system: -w /etc/issue -p wa -k audit_rules_networkconfig_modification -w /etc/issue.net -p wa -k audit_rules_networkconfig_modification -w /etc/hosts -p wa -k audit_rules_networkconfig_modification --w /etc/sysconfig/network -p wa -k audit_rules_networkconfig_modification - BP28(R73) - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 19 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 5.4.1.1 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - APO12.06 - APO13.01 - BAI03.05 - BAI08.02 - DSS01.03 - DSS01.04 - DSS02.02 - DSS02.04 - DSS02.07 - DSS03.01 - DSS03.05 - DSS05.02 - DSS05.03 - DSS05.04 - DSS05.05 - DSS05.07 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.1.7 - 164.308(a)(1)(ii)(D) - 164.308(a)(3)(ii)(A) - 164.308(a)(5)(ii)(C) - 164.312(a)(2)(i) - 164.312(b) - 164.312(d) - 164.312(e) - 4.2.3.10 - 4.3.2.6.7 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.3.6.6 - 4.3.4.4.7 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 1.13 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.6 - SR 2.8 - SR 2.9 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 6.1 - SR 6.2 - SR 7.1 - SR 7.6 - A.11.2.6 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.14.2.7 - A.15.2.1 - A.15.2.2 - A.16.1.4 - A.16.1.5 - A.16.1.7 - A.6.2.1 - A.6.2.2 - AU-2(d) - AU-12(c) - AC-6(9) - CM-6(a) - DE.AE-3 - DE.AE-5 - DE.CM-1 - DE.CM-3 - DE.CM-7 - ID.SC-4 - PR.AC-3 - PR.PT-1 - PR.PT-4 - RS.AN-1 - RS.AN-4 - Req-10.5.5 - 10.3.4 - The network environment should not be modified by anything other +-w /etc/sysconfig/network -p wa -k audit_rules_networkconfig_modification + + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 19 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 5.4.1.1 + APO10.01 + APO10.03 + APO10.04 + APO10.05 + APO11.04 + APO12.06 + APO13.01 + BAI03.05 + BAI08.02 + DSS01.03 + DSS01.04 + DSS02.02 + DSS02.04 + DSS02.07 + DSS03.01 + DSS03.05 + DSS05.02 + DSS05.03 + DSS05.04 + DSS05.05 + DSS05.07 + MEA01.01 + MEA01.02 + MEA01.03 + MEA01.04 + MEA01.05 + MEA02.01 + 3.1.7 + 164.308(a)(1)(ii)(D) + 164.308(a)(3)(ii)(A) + 164.308(a)(5)(ii)(C) + 164.312(a)(2)(i) + 164.312(b) + 164.312(d) + 164.312(e) + 4.2.3.10 + 4.3.2.6.7 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.3.6.6 + 4.3.4.4.7 + 4.3.4.5.6 + 4.3.4.5.7 + 4.3.4.5.8 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 1.13 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.6 + SR 2.8 + SR 2.9 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 6.1 + SR 6.2 + SR 7.1 + SR 7.6 + A.11.2.6 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.13.1.1 + A.13.2.1 + A.14.1.3 + A.14.2.7 + A.15.2.1 + A.15.2.2 + A.16.1.4 + A.16.1.5 + A.16.1.7 + A.6.2.1 + A.6.2.2 + AU-2(d) + AU-12(c) + AC-6(9) + CM-6(a) + DE.AE-3 + DE.AE-5 + DE.CM-1 + DE.CM-3 + DE.CM-7 + ID.SC-4 + PR.AC-3 + PR.PT-1 + PR.PT-4 + RS.AN-1 + RS.AN-4 + Req-10.5.5 + R73 + 10.3.4 + 10.3 + The network environment should not be modified by anything other than administrator action. Any change to network parameters should be -audited. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +audited. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then # First perform the remediation of the syscall rule # Retrieve hardware architecture of the underlying system @@ -41379,7 +121336,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -41395,7 +121351,7 @@ then if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -41487,7 +121443,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -41540,7 +121496,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -41634,7 +121589,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -41751,7 +121706,7 @@ then if [ ! -e "$key_rule_file" ] then touch "$key_rule_file" - chmod 0640 "$key_rule_file" + chmod 0600 "$key_rule_file" fi files_to_inspect+=("$key_rule_file") fi @@ -41883,7 +121838,7 @@ then if [ ! -e "$key_rule_file" ] then touch "$key_rule_file" - chmod 0640 "$key_rule_file" + chmod 0600 "$key_rule_file" fi files_to_inspect+=("$key_rule_file") fi @@ -42015,7 +121970,7 @@ then if [ ! -e "$key_rule_file" ] then touch "$key_rule_file" - chmod 0640 "$key_rule_file" + chmod 0600 "$key_rule_file" fi files_to_inspect+=("$key_rule_file") fi @@ -42057,6 +122012,7 @@ do echo "-w /etc/hosts -p wa -k audit_rules_networkconfig_modification" >> "$audit_rules_file" fi done + # Create a list of audit *.rules files that should be inspected for presence and correctness # of a particular audit rule. The scheme is as follows: # @@ -42147,7 +122103,7 @@ then if [ ! -e "$key_rule_file" ] then touch "$key_rule_file" - chmod 0640 "$key_rule_file" + chmod 0600 "$key_rule_file" fi files_to_inspect+=("$key_rule_file") fi @@ -42193,8 +122149,8 @@ done else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: @@ -42205,6 +122161,7 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_networkconfig_modification - low_complexity @@ -42218,7 +122175,7 @@ fi audit_arch: b64 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - ansible_architecture == "aarch64" or ansible_architecture == "ppc64" or ansible_architecture == "ppc64le" or ansible_architecture == "s390x" or ansible_architecture == "x86_64" tags: @@ -42229,6 +122186,7 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_networkconfig_modification - low_complexity @@ -42302,6 +122260,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -42309,7 +122268,7 @@ fi path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F key=audit_rules_networkconfig_modification create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -42349,6 +122308,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -42356,12 +122316,12 @@ fi path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F key=audit_rules_networkconfig_modification create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.4.1.1 - NIST-800-171-3.1.7 @@ -42370,6 +122330,7 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_networkconfig_modification - low_complexity @@ -42443,6 +122404,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -42450,7 +122412,7 @@ fi path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F key=audit_rules_networkconfig_modification create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -42490,6 +122452,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -42497,12 +122460,12 @@ fi path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F key=audit_rules_networkconfig_modification create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - audit_arch == "b64" tags: - CJIS-5.4.1.1 @@ -42512,6 +122475,7 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_networkconfig_modification - low_complexity @@ -42528,7 +122492,7 @@ fi register: find_existing_watch_rules_d when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.4.1.1 - NIST-800-171-3.1.7 @@ -42537,6 +122501,7 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_networkconfig_modification - low_complexity @@ -42553,7 +122518,7 @@ fi register: find_watch_key when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: @@ -42564,6 +122529,7 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_networkconfig_modification - low_complexity @@ -42579,7 +122545,7 @@ fi - /etc/audit/rules.d/audit_rules_networkconfig_modification.rules when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_watch_key.matched is defined and find_watch_key.matched == 0 and find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: @@ -42590,6 +122556,7 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_networkconfig_modification - low_complexity @@ -42604,7 +122571,7 @@ fi - '{{ find_watch_key.files | map(attribute=''path'') | list | first }}' when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_watch_key.matched is defined and find_watch_key.matched > 0 and find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: @@ -42615,6 +122582,7 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_networkconfig_modification - low_complexity @@ -42628,10 +122596,10 @@ fi path: '{{ all_files[0] }}' line: -w /etc/issue -p wa -k audit_rules_networkconfig_modification create: true - mode: '0640' + mode: '0600' when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: @@ -42642,6 +122610,7 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_networkconfig_modification - low_complexity @@ -42658,7 +122627,7 @@ fi register: find_existing_watch_audit_rules when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.4.1.1 - NIST-800-171-3.1.7 @@ -42667,6 +122636,7 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_networkconfig_modification - low_complexity @@ -42681,10 +122651,10 @@ fi state: present dest: /etc/audit/audit.rules create: true - mode: '0640' + mode: '0600' when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_existing_watch_audit_rules.matched is defined and find_existing_watch_audit_rules.matched == 0 tags: @@ -42695,6 +122665,7 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_networkconfig_modification - low_complexity @@ -42711,7 +122682,7 @@ fi register: find_existing_watch_rules_d when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.4.1.1 - NIST-800-171-3.1.7 @@ -42720,6 +122691,7 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_networkconfig_modification - low_complexity @@ -42736,7 +122708,7 @@ fi register: find_watch_key when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: @@ -42747,6 +122719,7 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_networkconfig_modification - low_complexity @@ -42762,7 +122735,7 @@ fi - /etc/audit/rules.d/audit_rules_networkconfig_modification.rules when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_watch_key.matched is defined and find_watch_key.matched == 0 and find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: @@ -42773,6 +122746,7 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_networkconfig_modification - low_complexity @@ -42787,7 +122761,7 @@ fi - '{{ find_watch_key.files | map(attribute=''path'') | list | first }}' when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_watch_key.matched is defined and find_watch_key.matched > 0 and find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: @@ -42798,6 +122772,7 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_networkconfig_modification - low_complexity @@ -42811,10 +122786,10 @@ fi path: '{{ all_files[0] }}' line: -w /etc/issue.net -p wa -k audit_rules_networkconfig_modification create: true - mode: '0640' + mode: '0600' when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: @@ -42825,6 +122800,7 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_networkconfig_modification - low_complexity @@ -42841,7 +122817,7 @@ fi register: find_existing_watch_audit_rules when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.4.1.1 - NIST-800-171-3.1.7 @@ -42850,6 +122826,7 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_networkconfig_modification - low_complexity @@ -42864,10 +122841,10 @@ fi state: present dest: /etc/audit/audit.rules create: true - mode: '0640' + mode: '0600' when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_existing_watch_audit_rules.matched is defined and find_existing_watch_audit_rules.matched == 0 tags: @@ -42878,6 +122855,7 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_networkconfig_modification - low_complexity @@ -42894,7 +122872,7 @@ fi register: find_existing_watch_rules_d when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.4.1.1 - NIST-800-171-3.1.7 @@ -42903,6 +122881,7 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_networkconfig_modification - low_complexity @@ -42919,7 +122898,7 @@ fi register: find_watch_key when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: @@ -42930,6 +122909,7 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_networkconfig_modification - low_complexity @@ -42945,7 +122925,7 @@ fi - /etc/audit/rules.d/audit_rules_networkconfig_modification.rules when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_watch_key.matched is defined and find_watch_key.matched == 0 and find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: @@ -42956,6 +122936,7 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_networkconfig_modification - low_complexity @@ -42970,7 +122951,7 @@ fi - '{{ find_watch_key.files | map(attribute=''path'') | list | first }}' when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_watch_key.matched is defined and find_watch_key.matched > 0 and find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: @@ -42981,6 +122962,7 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_networkconfig_modification - low_complexity @@ -42994,10 +122976,10 @@ fi path: '{{ all_files[0] }}' line: -w /etc/hosts -p wa -k audit_rules_networkconfig_modification create: true - mode: '0640' + mode: '0600' when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: @@ -43008,6 +122990,7 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_networkconfig_modification - low_complexity @@ -43024,7 +123007,7 @@ fi register: find_existing_watch_audit_rules when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.4.1.1 - NIST-800-171-3.1.7 @@ -43033,6 +123016,7 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_networkconfig_modification - low_complexity @@ -43047,10 +123031,10 @@ fi state: present dest: /etc/audit/audit.rules create: true - mode: '0640' + mode: '0600' when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_existing_watch_audit_rules.matched is defined and find_existing_watch_audit_rules.matched == 0 tags: @@ -43061,6 +123045,7 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_networkconfig_modification - low_complexity @@ -43077,7 +123062,7 @@ fi register: find_existing_watch_rules_d when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.4.1.1 - NIST-800-171-3.1.7 @@ -43086,6 +123071,7 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_networkconfig_modification - low_complexity @@ -43102,7 +123088,7 @@ fi register: find_watch_key when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: @@ -43113,6 +123099,7 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_networkconfig_modification - low_complexity @@ -43128,7 +123115,7 @@ fi - /etc/audit/rules.d/audit_rules_networkconfig_modification.rules when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_watch_key.matched is defined and find_watch_key.matched == 0 and find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: @@ -43139,6 +123126,7 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_networkconfig_modification - low_complexity @@ -43153,7 +123141,7 @@ fi - '{{ find_watch_key.files | map(attribute=''path'') | list | first }}' when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_watch_key.matched is defined and find_watch_key.matched > 0 and find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: @@ -43164,6 +123152,7 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_networkconfig_modification - low_complexity @@ -43177,10 +123166,10 @@ fi path: '{{ all_files[0] }}' line: -w /etc/sysconfig/network -p wa -k audit_rules_networkconfig_modification create: true - mode: '0640' + mode: '0600' when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: @@ -43191,6 +123180,7 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_networkconfig_modification - low_complexity @@ -43207,7 +123197,7 @@ fi register: find_existing_watch_audit_rules when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.4.1.1 - NIST-800-171-3.1.7 @@ -43216,6 +123206,7 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_networkconfig_modification - low_complexity @@ -43230,10 +123221,10 @@ fi state: present dest: /etc/audit/audit.rules create: true - mode: '0640' + mode: '0600' when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_existing_watch_audit_rules.matched is defined and find_existing_watch_audit_rules.matched == 0 tags: @@ -43244,6 +123235,7 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_networkconfig_modification - low_complexity @@ -43251,17 +123243,17 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Record Attempts to Alter Process and Session Initiation Information - The audit system already collects process information for all + + + + + + + + + + Record Attempts to Alter Process and Session Initiation Information + The audit system already collects process information for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following lines to a file with suffix .rules in the @@ -43276,135 +123268,139 @@ utility to read audit rules during daemon startup, add the following lines to edits of files involved in storing such process information: -w /var/run/utmp -p wa -k session -w /var/log/btmp -p wa -k session --w /var/log/wtmp -p wa -k session - BP28(R73) - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 19 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 5.4.1.1 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - APO12.06 - APO13.01 - BAI03.05 - BAI08.02 - DSS01.03 - DSS01.04 - DSS02.02 - DSS02.04 - DSS02.07 - DSS03.01 - DSS03.05 - DSS05.02 - DSS05.03 - DSS05.04 - DSS05.05 - DSS05.07 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.1.7 - 164.308(a)(1)(ii)(D) - 164.308(a)(3)(ii)(A) - 164.308(a)(5)(ii)(C) - 164.312(a)(2)(i) - 164.312(b) - 164.312(d) - 164.312(e) - 4.2.3.10 - 4.3.2.6.7 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.3.6.6 - 4.3.4.4.7 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 1.13 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.6 - SR 2.8 - SR 2.9 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 6.1 - SR 6.2 - SR 7.1 - SR 7.6 - 0582 - 0584 - 05885 - 0586 - 0846 - 0957 - A.11.2.6 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.14.2.7 - A.15.2.1 - A.15.2.2 - A.16.1.4 - A.16.1.5 - A.16.1.7 - A.6.2.1 - A.6.2.2 - AU-2(d) - AU-12(c) - CM-6(a) - DE.AE-3 - DE.AE-5 - DE.CM-1 - DE.CM-3 - DE.CM-7 - ID.SC-4 - PR.AC-3 - PR.PT-1 - PR.PT-4 - RS.AN-1 - RS.AN-4 - FAU_GEN.1.1.c - Req-10.2.3 - 10.2.1.3 - Manual editing of these files may indicate nefarious activity, such -as an attacker attempting to remove evidence of an intrusion. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +-w /var/log/wtmp -p wa -k session + + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 19 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 5.4.1.1 + APO10.01 + APO10.03 + APO10.04 + APO10.05 + APO11.04 + APO12.06 + APO13.01 + BAI03.05 + BAI08.02 + DSS01.03 + DSS01.04 + DSS02.02 + DSS02.04 + DSS02.07 + DSS03.01 + DSS03.05 + DSS05.02 + DSS05.03 + DSS05.04 + DSS05.05 + DSS05.07 + MEA01.01 + MEA01.02 + MEA01.03 + MEA01.04 + MEA01.05 + MEA02.01 + 3.1.7 + 164.308(a)(1)(ii)(D) + 164.308(a)(3)(ii)(A) + 164.308(a)(5)(ii)(C) + 164.312(a)(2)(i) + 164.312(b) + 164.312(d) + 164.312(e) + 4.2.3.10 + 4.3.2.6.7 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.3.6.6 + 4.3.4.4.7 + 4.3.4.5.6 + 4.3.4.5.7 + 4.3.4.5.8 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 1.13 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.6 + SR 2.8 + SR 2.9 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 6.1 + SR 6.2 + SR 7.1 + SR 7.6 + 0582 + 0584 + 05885 + 0586 + 0846 + 0957 + A.11.2.6 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.13.1.1 + A.13.2.1 + A.14.1.3 + A.14.2.7 + A.15.2.1 + A.15.2.2 + A.16.1.4 + A.16.1.5 + A.16.1.7 + A.6.2.1 + A.6.2.2 + AU-2(d) + AU-12(c) + CM-6(a) + DE.AE-3 + DE.AE-5 + DE.CM-1 + DE.CM-3 + DE.CM-7 + ID.SC-4 + PR.AC-3 + PR.PT-1 + PR.PT-4 + RS.AN-1 + RS.AN-4 + Req-10.2.3 + SRG-APP-000505-CTR-001285 + R73 + A.3.SEC-OL1 + 10.2.1.3 + 10.2.1 + 10.2 + Manual editing of these files may indicate nefarious activity, such +as an attacker attempting to remove evidence of an intrusion. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' # Create a list of audit *.rules files that should be inspected for presence and correctness @@ -43497,7 +123493,7 @@ then if [ ! -e "$key_rule_file" ] then touch "$key_rule_file" - chmod 0640 "$key_rule_file" + chmod 0600 "$key_rule_file" fi files_to_inspect+=("$key_rule_file") fi @@ -43629,7 +123625,7 @@ then if [ ! -e "$key_rule_file" ] then touch "$key_rule_file" - chmod 0640 "$key_rule_file" + chmod 0600 "$key_rule_file" fi files_to_inspect+=("$key_rule_file") fi @@ -43761,7 +123757,7 @@ then if [ ! -e "$key_rule_file" ] then touch "$key_rule_file" - chmod 0640 "$key_rule_file" + chmod 0600 "$key_rule_file" fi files_to_inspect+=("$key_rule_file") fi @@ -43807,8 +123803,8 @@ done else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: @@ -43818,6 +123814,8 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.3 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.3 - audit_rules_session_events - low_complexity @@ -43834,7 +123832,7 @@ fi register: find_existing_watch_rules_d when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.4.1.1 - NIST-800-171-3.1.7 @@ -43842,6 +123840,8 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.3 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.3 - audit_rules_session_events - low_complexity @@ -43858,7 +123858,7 @@ fi register: find_watch_key when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: @@ -43868,6 +123868,8 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.3 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.3 - audit_rules_session_events - low_complexity @@ -43882,7 +123884,7 @@ fi - /etc/audit/rules.d/session.rules when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_watch_key.matched is defined and find_watch_key.matched == 0 and find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: @@ -43892,6 +123894,8 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.3 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.3 - audit_rules_session_events - low_complexity @@ -43906,7 +123910,7 @@ fi - '{{ find_watch_key.files | map(attribute=''path'') | list | first }}' when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_watch_key.matched is defined and find_watch_key.matched > 0 and find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: @@ -43916,6 +123920,8 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.3 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.3 - audit_rules_session_events - low_complexity @@ -43929,10 +123935,10 @@ fi path: '{{ all_files[0] }}' line: -w /var/run/utmp -p wa -k session create: true - mode: '0640' + mode: '0600' when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: @@ -43942,6 +123948,8 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.3 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.3 - audit_rules_session_events - low_complexity @@ -43958,7 +123966,7 @@ fi register: find_existing_watch_audit_rules when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.4.1.1 - NIST-800-171-3.1.7 @@ -43966,6 +123974,8 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.3 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.3 - audit_rules_session_events - low_complexity @@ -43980,10 +123990,10 @@ fi state: present dest: /etc/audit/audit.rules create: true - mode: '0640' + mode: '0600' when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_existing_watch_audit_rules.matched is defined and find_existing_watch_audit_rules.matched == 0 tags: @@ -43993,6 +124003,8 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.3 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.3 - audit_rules_session_events - low_complexity @@ -44009,7 +124021,7 @@ fi register: find_existing_watch_rules_d when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.4.1.1 - NIST-800-171-3.1.7 @@ -44017,6 +124029,8 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.3 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.3 - audit_rules_session_events - low_complexity @@ -44033,7 +124047,7 @@ fi register: find_watch_key when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: @@ -44043,6 +124057,8 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.3 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.3 - audit_rules_session_events - low_complexity @@ -44057,7 +124073,7 @@ fi - /etc/audit/rules.d/session.rules when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_watch_key.matched is defined and find_watch_key.matched == 0 and find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: @@ -44067,6 +124083,8 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.3 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.3 - audit_rules_session_events - low_complexity @@ -44081,7 +124099,7 @@ fi - '{{ find_watch_key.files | map(attribute=''path'') | list | first }}' when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_watch_key.matched is defined and find_watch_key.matched > 0 and find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: @@ -44091,6 +124109,8 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.3 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.3 - audit_rules_session_events - low_complexity @@ -44104,10 +124124,10 @@ fi path: '{{ all_files[0] }}' line: -w /var/log/btmp -p wa -k session create: true - mode: '0640' + mode: '0600' when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: @@ -44117,6 +124137,8 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.3 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.3 - audit_rules_session_events - low_complexity @@ -44133,7 +124155,7 @@ fi register: find_existing_watch_audit_rules when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.4.1.1 - NIST-800-171-3.1.7 @@ -44141,6 +124163,8 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.3 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.3 - audit_rules_session_events - low_complexity @@ -44155,10 +124179,10 @@ fi state: present dest: /etc/audit/audit.rules create: true - mode: '0640' + mode: '0600' when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_existing_watch_audit_rules.matched is defined and find_existing_watch_audit_rules.matched == 0 tags: @@ -44168,6 +124192,8 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.3 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.3 - audit_rules_session_events - low_complexity @@ -44184,7 +124210,7 @@ fi register: find_existing_watch_rules_d when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.4.1.1 - NIST-800-171-3.1.7 @@ -44192,6 +124218,8 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.3 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.3 - audit_rules_session_events - low_complexity @@ -44208,7 +124236,7 @@ fi register: find_watch_key when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: @@ -44218,6 +124246,8 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.3 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.3 - audit_rules_session_events - low_complexity @@ -44232,7 +124262,7 @@ fi - /etc/audit/rules.d/session.rules when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_watch_key.matched is defined and find_watch_key.matched == 0 and find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: @@ -44242,6 +124272,8 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.3 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.3 - audit_rules_session_events - low_complexity @@ -44256,7 +124288,7 @@ fi - '{{ find_watch_key.files | map(attribute=''path'') | list | first }}' when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_watch_key.matched is defined and find_watch_key.matched > 0 and find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: @@ -44266,6 +124298,8 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.3 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.3 - audit_rules_session_events - low_complexity @@ -44279,10 +124313,10 @@ fi path: '{{ all_files[0] }}' line: -w /var/log/wtmp -p wa -k session create: true - mode: '0640' + mode: '0600' when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: @@ -44292,6 +124326,8 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.3 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.3 - audit_rules_session_events - low_complexity @@ -44308,7 +124344,7 @@ fi register: find_existing_watch_audit_rules when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.4.1.1 - NIST-800-171-3.1.7 @@ -44316,6 +124352,8 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.3 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.3 - audit_rules_session_events - low_complexity @@ -44330,10 +124368,10 @@ fi state: present dest: /etc/audit/audit.rules create: true - mode: '0640' + mode: '0600' when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_existing_watch_audit_rules.matched is defined and find_existing_watch_audit_rules.matched == 0 tags: @@ -44343,6 +124381,8 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.3 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.3 - audit_rules_session_events - low_complexity @@ -44350,14 +124390,14 @@ fi - medium_severity - reboot_required - restrict_strategy - - - - - - - Ensure auditd Collects System Administrator Actions - /etc/sudoers - At a minimum, the audit system should collect administrator actions + + + + + + + Ensure auditd Collects System Administrator Actions - /etc/sudoers + At a minimum, the audit system should collect administrator actions for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following line to a file with suffix .rules in the directory @@ -44366,39 +124406,46 @@ add the following line to a file with suffix .rules in th If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following line to /etc/audit/audit.rules file: --w /etc/sudoers -p wa -k actions - CCI-000018 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-000172 - CCI-001403 - CCI-001404 - CCI-002130 - CCI-002132 - CCI-002884 - SRG-OS-000004-GPOS-00004 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000304-GPOS-00121 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000470-GPOS-00214 - SRG-OS-000471-GPOS-00215 - SRG-OS-000239-GPOS-00089 - SRG-OS-000240-GPOS-00090 - SRG-OS-000241-GPOS-00091 - SRG-OS-000303-GPOS-00120 - SRG-OS-000466-GPOS-00210 - SRG-OS-000476-GPOS-00221 - The actions taken by system administrators should be audited to keep a record +-w /etc/sudoers -p wa -k actions + + CCI-001403 + CCI-001404 + CCI-001405 + CCI-000172 + CCI-000130 + CCI-002130 + CCI-000135 + CCI-000169 + CCI-002884 + CCI-000018 + CCI-000015 + SRG-OS-000004-GPOS-00004 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000304-GPOS-00121 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000470-GPOS-00214 + SRG-OS-000471-GPOS-00215 + SRG-OS-000239-GPOS-00089 + SRG-OS-000240-GPOS-00090 + SRG-OS-000241-GPOS-00091 + SRG-OS-000303-GPOS-00120 + SRG-OS-000466-GPOS-00210 + SRG-OS-000476-GPOS-00221 + SRG-APP-000495-CTR-001235 + SRG-APP-000499-CTR-001255 + SRG-APP-000503-CTR-001275 + OL09-00-000500 + SV-271527r1092474_rule + The actions taken by system administrators should be audited to keep a record of what was executed on the system, as well as, for accountability purposes. Editing the sudoers file may be sign of an attacker trying to establish persistent methods to a system, auditing the editing of the sudoers -files mitigates this risk. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +files mitigates this risk. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' # Create a list of audit *.rules files that should be inspected for presence and correctness @@ -44491,7 +124538,7 @@ then if [ ! -e "$key_rule_file" ] then touch "$key_rule_file" - chmod 0640 "$key_rule_file" + chmod 0600 "$key_rule_file" fi files_to_inspect+=("$key_rule_file") fi @@ -44537,11 +124584,12 @@ done else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-000500 - audit_rules_sudoers - low_complexity - low_disruption @@ -44557,8 +124605,9 @@ fi register: find_existing_watch_rules_d when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-000500 - audit_rules_sudoers - low_complexity - low_disruption @@ -44574,10 +124623,11 @@ fi register: find_watch_key when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: + - DISA-STIG-OL09-00-000500 - audit_rules_sudoers - low_complexity - low_disruption @@ -44591,10 +124641,11 @@ fi - /etc/audit/rules.d/actions.rules when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_watch_key.matched is defined and find_watch_key.matched == 0 and find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: + - DISA-STIG-OL09-00-000500 - audit_rules_sudoers - low_complexity - low_disruption @@ -44608,10 +124659,11 @@ fi - '{{ find_watch_key.files | map(attribute=''path'') | list | first }}' when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_watch_key.matched is defined and find_watch_key.matched > 0 and find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: + - DISA-STIG-OL09-00-000500 - audit_rules_sudoers - low_complexity - low_disruption @@ -44624,13 +124676,14 @@ fi path: '{{ all_files[0] }}' line: -w /etc/sudoers -p wa -k actions create: true - mode: '0640' + mode: '0600' when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: + - DISA-STIG-OL09-00-000500 - audit_rules_sudoers - low_complexity - low_disruption @@ -44646,8 +124699,9 @@ fi register: find_existing_watch_audit_rules when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-000500 - audit_rules_sudoers - low_complexity - low_disruption @@ -44661,30 +124715,31 @@ fi state: present dest: /etc/audit/audit.rules create: true - mode: '0640' + mode: '0600' when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_existing_watch_audit_rules.matched is defined and find_existing_watch_audit_rules.matched == 0 tags: + - DISA-STIG-OL09-00-000500 - audit_rules_sudoers - low_complexity - low_disruption - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Ensure auditd Collects System Administrator Actions - /etc/sudoers.d/ - At a minimum, the audit system should collect administrator actions + + + + + + + + + + Ensure auditd Collects System Administrator Actions - /etc/sudoers.d/ + At a minimum, the audit system should collect administrator actions for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following line to a file with suffix .rules in the directory @@ -44693,39 +124748,46 @@ add the following line to a file with suffix .rules in th If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following line to /etc/audit/audit.rules file: --w /etc/sudoers.d/ -p wa -k actions - CCI-000018 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-000172 - CCI-001403 - CCI-001404 - CCI-002130 - CCI-002132 - CCI-002884 - SRG-OS-000004-GPOS-00004 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000304-GPOS-00121 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000470-GPOS-00214 - SRG-OS-000471-GPOS-00215 - SRG-OS-000239-GPOS-00089 - SRG-OS-000240-GPOS-00090 - SRG-OS-000241-GPOS-00091 - SRG-OS-000303-GPOS-00120 - SRG-OS-000466-GPOS-00210 - SRG-OS-000476-GPOS-00221 - The actions taken by system administrators should be audited to keep a record +-w /etc/sudoers.d/ -p wa -k actions + + CCI-001403 + CCI-001404 + CCI-001405 + CCI-000172 + CCI-000130 + CCI-002130 + CCI-000135 + CCI-000169 + CCI-002884 + CCI-000018 + CCI-000015 + SRG-OS-000004-GPOS-00004 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000304-GPOS-00121 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000470-GPOS-00214 + SRG-OS-000471-GPOS-00215 + SRG-OS-000239-GPOS-00089 + SRG-OS-000240-GPOS-00090 + SRG-OS-000241-GPOS-00091 + SRG-OS-000303-GPOS-00120 + SRG-OS-000466-GPOS-00210 + SRG-OS-000476-GPOS-00221 + SRG-APP-000495-CTR-001235 + SRG-APP-000499-CTR-001255 + SRG-APP-000503-CTR-001275 + OL09-00-000505 + SV-271528r1092476_rule + The actions taken by system administrators should be audited to keep a record of what was executed on the system, as well as, for accountability purposes. Editing the sudoers file may be sign of an attacker trying to establish persistent methods to a system, auditing the editing of the sudoers -files mitigates this risk. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +files mitigates this risk. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' # Create a list of audit *.rules files that should be inspected for presence and correctness @@ -44818,7 +124880,7 @@ then if [ ! -e "$key_rule_file" ] then touch "$key_rule_file" - chmod 0640 "$key_rule_file" + chmod 0600 "$key_rule_file" fi files_to_inspect+=("$key_rule_file") fi @@ -44864,11 +124926,12 @@ done else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-000505 - audit_rules_sudoers_d - low_complexity - low_disruption @@ -44884,8 +124947,9 @@ fi register: find_existing_watch_rules_d when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-000505 - audit_rules_sudoers_d - low_complexity - low_disruption @@ -44901,10 +124965,11 @@ fi register: find_watch_key when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: + - DISA-STIG-OL09-00-000505 - audit_rules_sudoers_d - low_complexity - low_disruption @@ -44918,10 +124983,11 @@ fi - /etc/audit/rules.d/actions.rules when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_watch_key.matched is defined and find_watch_key.matched == 0 and find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: + - DISA-STIG-OL09-00-000505 - audit_rules_sudoers_d - low_complexity - low_disruption @@ -44935,10 +125001,11 @@ fi - '{{ find_watch_key.files | map(attribute=''path'') | list | first }}' when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_watch_key.matched is defined and find_watch_key.matched > 0 and find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: + - DISA-STIG-OL09-00-000505 - audit_rules_sudoers_d - low_complexity - low_disruption @@ -44951,13 +125018,14 @@ fi path: '{{ all_files[0] }}' line: -w /etc/sudoers.d/ -p wa -k actions create: true - mode: '0640' + mode: '0600' when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: + - DISA-STIG-OL09-00-000505 - audit_rules_sudoers_d - low_complexity - low_disruption @@ -44973,8 +125041,9 @@ fi register: find_existing_watch_audit_rules when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-000505 - audit_rules_sudoers_d - low_complexity - low_disruption @@ -44988,30 +125057,31 @@ fi state: present dest: /etc/audit/audit.rules create: true - mode: '0640' + mode: '0600' when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_existing_watch_audit_rules.matched is defined and find_existing_watch_audit_rules.matched == 0 tags: + - DISA-STIG-OL09-00-000505 - audit_rules_sudoers_d - low_complexity - low_disruption - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Record Events When Privileged Executables Are Run - Verify the system generates an audit record when privileged functions are executed. + + + + + + + + + + Record Events When Privileged Executables Are Run + Verify the system generates an audit record when privileged functions are executed. If audit is using the "auditctl" tool to load the rules, run the following command: @@ -45020,49 +125090,42 @@ If audit is using the "auditctl" tool to load the rules, run the following comma If audit is using the "augenrules" tool to load the rules, run the following command: $ sudo grep -r execve /etc/audit/rules.d - - --a always,exit -F arch=b32 -S execve -C uid!=euid -F euid=0 -k setuid --a always,exit -F arch=b64 -S execve -C uid!=euid -F euid=0 -k setuid --a always,exit -F arch=b32 -S execve -C gid!=egid -F egid=0 -k setgid --a always,exit -F arch=b64 -S execve -C gid!=egid -F egid=0 -k setgid + -a always,exit -F arch=b32 -S execve -C uid!=euid -F euid=0 -k setuid + -a always,exit -F arch=b64 -S execve -C uid!=euid -F euid=0 -k setuid + -a always,exit -F arch=b32 -S execve -C gid!=egid -F egid=0 -k setgid + -a always,exit -F arch=b64 -S execve -C gid!=egid -F egid=0 -k setgid If both the "b32" and "b64" audit rules for "SUID" files are not defined, this is a finding. -If both the "b32" and "b64" audit rules for "SGID" files are not defined, this is a finding. - Note that these rules can be configured in a -number of ways while still achieving the desired effect. - CCI-001814 - CCI-001882 - CCI-001889 - CCI-001880 - CCI-001881 - CCI-001878 - CCI-001879 - CCI-001875 - CCI-001877 - CCI-001914 - CCI-002233 - CCI-002234 - CM-5(1) - AU-7(a) - AU-7(b) - AU-8(b) - AU-12(3) - AC-6(9) - SRG-OS-000326-GPOS-00126 - SRG-OS-000327-GPOS-00127 - SRG-APP-000343-CTR-000780 - SRG-APP-000381-CTR-000905 - Misuse of privileged functions, either intentionally or unintentionally by +If both the "b32" and "b64" audit rules for "SGID" files are not defined, this is a finding. + Note that these rules can be configured in a +number of ways while still achieving the desired effect. + CCI-002233 + CCI-002234 + CM-5(1) + AU-7(a) + AU-7(b) + AU-8(b) + AU-12(3) + AC-6(9) + SRG-OS-000326-GPOS-00126 + SRG-OS-000327-GPOS-00127 + SRG-APP-000343-CTR-000780 + SRG-APP-000381-CTR-000905 + SRG-OS-000755-GPOS-00220 + 10.2.1.2 + 10.2.1 + 10.2 + OL09-00-000715 + SV-271570r1092558_rule + Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised information system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. Auditing the use of privileged functions is one way to detect such misuse and identify the -risk from insider threats and the advanced persistent threat. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +risk from insider threats and the advanced persistent threat. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then # First perform the remediation of the syscall rule # Retrieve hardware architecture of the underlying system @@ -45071,7 +125134,7 @@ if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm -- for ARCH in "${RULE_ARCHS[@]}" do ACTION_ARCH_FILTERS="-a always,exit -F arch=$ARCH" - + OTHER_FILTERS="-C uid!=euid -F euid=0" AUID_FILTERS="" @@ -45108,7 +125171,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -45124,7 +125186,7 @@ then if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -45216,7 +125278,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -45269,7 +125331,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -45363,7 +125424,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -45391,7 +125452,7 @@ done for ARCH in "${RULE_ARCHS[@]}" do ACTION_ARCH_FILTERS="-a always,exit -F arch=$ARCH" - + OTHER_FILTERS="-C gid!=egid -F egid=0" AUID_FILTERS="" @@ -45428,7 +125489,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -45444,7 +125504,7 @@ then if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -45536,7 +125596,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -45589,7 +125649,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -45683,7 +125742,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -45711,17 +125770,21 @@ done else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-000715 - NIST-800-53-AC-6(9) - NIST-800-53-AU-12(3) - NIST-800-53-AU-7(a) - NIST-800-53-AU-7(b) - NIST-800-53-AU-8(b) - NIST-800-53-CM-5(1) + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 + - PCI-DSSv4-10.2.1.2 - audit_rules_suid_privilege_function - low_complexity - low_disruption @@ -45733,36 +125796,18 @@ fi ansible.builtin.service_facts: null when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-6(9) - - NIST-800-53-AU-12(3) - - NIST-800-53-AU-7(a) - - NIST-800-53-AU-7(b) - - NIST-800-53-AU-8(b) - - NIST-800-53-CM-5(1) - - audit_rules_suid_privilege_function - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - -- name: Check the rules script being used - ansible.builtin.command: grep '^ExecStartPost' /usr/lib/systemd/system/auditd.service - register: check_rules_scripts_result - changed_when: false - failed_when: false - when: - - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-000715 - NIST-800-53-AC-6(9) - NIST-800-53-AU-12(3) - NIST-800-53-AU-7(a) - NIST-800-53-AU-7(b) - NIST-800-53-AU-8(b) - NIST-800-53-CM-5(1) + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 + - PCI-DSSv4-10.2.1.2 - audit_rules_suid_privilege_function - low_complexity - low_disruption @@ -45783,14 +125828,18 @@ fi regex: ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+arch=b64[\s]+-S[\s]+execve[\s]+-C[\s]+uid!=euid[\s]+-F[\s]+euid=0[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-000715 - NIST-800-53-AC-6(9) - NIST-800-53-AU-12(3) - NIST-800-53-AU-7(a) - NIST-800-53-AU-7(b) - NIST-800-53-AU-8(b) - NIST-800-53-CM-5(1) + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 + - PCI-DSSv4-10.2.1.2 - audit_rules_suid_privilege_function - low_complexity - low_disruption @@ -45803,21 +125852,25 @@ fi path: /etc/audit/rules.d/privileged.rules line: '{{ item.rule }}' regexp: '{{ item.regex }}' + mode: '0600' create: true when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - '"auditd.service" in ansible_facts.services' - - '"augenrules" in check_rules_scripts_result.stdout' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - ('"auditd.service" in ansible_facts.services' or '"augenrules.service" in ansible_facts.services') register: augenrules_audit_rules_privilege_function_update_result with_items: '{{ suid_audit_rules }}' tags: + - DISA-STIG-OL09-00-000715 - NIST-800-53-AC-6(9) - NIST-800-53-AU-12(3) - NIST-800-53-AU-7(a) - NIST-800-53-AU-7(b) - NIST-800-53-AU-8(b) - NIST-800-53-CM-5(1) + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 + - PCI-DSSv4-10.2.1.2 - audit_rules_suid_privilege_function - low_complexity - low_disruption @@ -45825,7 +125878,7 @@ fi - no_reboot_needed - restrict_strategy -- name: Update Update /etc/audit/audit.rules to audit privileged functions +- name: Update /etc/audit/audit.rules to audit privileged functions ansible.builtin.lineinfile: path: /etc/audit/audit.rules line: '{{ item.rule }}' @@ -45833,18 +125886,21 @@ fi create: true when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - '"auditd.service" in ansible_facts.services' - - '"auditctl" in check_rules_scripts_result.stdout' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - ('"auditd.service" in ansible_facts.services' or '"augenrules.service" in ansible_facts.services') register: auditctl_audit_rules_privilege_function_update_result with_items: '{{ suid_audit_rules }}' tags: + - DISA-STIG-OL09-00-000715 - NIST-800-53-AC-6(9) - NIST-800-53-AU-12(3) - NIST-800-53-AU-7(a) - NIST-800-53-AU-7(b) - NIST-800-53-AU-8(b) - NIST-800-53-CM-5(1) + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 + - PCI-DSSv4-10.2.1.2 - audit_rules_suid_privilege_function - low_complexity - low_disruption @@ -45856,33 +125912,37 @@ fi ansible.builtin.command: /usr/sbin/service auditd restart when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - (augenrules_audit_rules_privilege_function_update_result.changed or auditctl_audit_rules_privilege_function_update_result.changed) - ansible_facts.services["auditd.service"].state == "running" tags: + - DISA-STIG-OL09-00-000715 - NIST-800-53-AC-6(9) - NIST-800-53-AU-12(3) - NIST-800-53-AU-7(a) - NIST-800-53-AU-7(b) - NIST-800-53-AU-8(b) - NIST-800-53-CM-5(1) + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 + - PCI-DSSv4-10.2.1.2 - audit_rules_suid_privilege_function - low_complexity - low_disruption - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Ensure auditd Collects System Administrator Actions - At a minimum, the audit system should collect administrator actions + + + + + + + + + + Ensure auditd Collects System Administrator Actions + At a minimum, the audit system should collect administrator actions for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following line to a file with suffix .rules in the directory @@ -45893,201 +125953,204 @@ If the auditd daemon is configured to use the utility to read audit rules during daemon startup, add the following line to /etc/audit/audit.rules file: -w /etc/sudoers -p wa -k actions --w /etc/sudoers.d/ -p wa -k actions - BP28(R73) - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 18 - 19 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 5.4.1.1 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - APO12.06 - APO13.01 - BAI03.05 - BAI08.02 - DSS01.03 - DSS01.04 - DSS02.02 - DSS02.04 - DSS02.07 - DSS03.01 - DSS03.05 - DSS05.02 - DSS05.03 - DSS05.04 - DSS05.05 - DSS05.07 - DSS06.03 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.1.7 - CCI-000126 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-000172 - CCI-002884 - 164.308(a)(1)(ii)(D) - 164.308(a)(3)(ii)(A) - 164.308(a)(5)(ii)(C) - 164.312(a)(2)(i) - 164.312(b) - 164.312(d) - 164.312(e) - 4.2.3.10 - 4.3.2.6.7 - 4.3.3.2.2 - 4.3.3.3.9 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.8 - 4.3.3.6.6 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.4.7 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 1.1 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.6 - SR 2.8 - SR 2.9 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 6.1 - SR 6.2 - SR 7.1 - SR 7.6 - A.11.2.6 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.14.2.7 - A.15.2.1 - A.15.2.2 - A.16.1.4 - A.16.1.5 - A.16.1.7 - A.6.1.2 - A.6.2.1 - A.6.2.2 - A.7.1.1 - A.9.1.2 - A.9.2.1 - A.9.2.2 - A.9.2.3 - A.9.2.4 - A.9.2.6 - A.9.3.1 - A.9.4.1 - A.9.4.2 - A.9.4.3 - A.9.4.4 - A.9.4.5 - AC-2(7)(b) - AU-2(d) - AU-12(c) - AC-6(9) - CM-6(a) - DE.AE-3 - DE.AE-5 - DE.CM-1 - DE.CM-3 - DE.CM-7 - ID.SC-4 - PR.AC-1 - PR.AC-3 - PR.AC-4 - PR.AC-6 - PR.PT-1 - PR.PT-4 - RS.AN-1 - RS.AN-4 - FAU_GEN.1.1.c - Req-10.2.2 - Req-10.2.5.b - 10.2.1.5 - 10.2.2 - SRG-OS-000004-GPOS-00004 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000304-GPOS-00121 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000470-GPOS-00214 - SRG-OS-000471-GPOS-00215 - SRG-OS-000239-GPOS-00089 - SRG-OS-000240-GPOS-00090 - SRG-OS-000241-GPOS-00091 - SRG-OS-000303-GPOS-00120 - SRG-OS-000304-GPOS-00121 - SRG-OS-000466-GPOS-00210 - SRG-OS-000476-GPOS-00221 - SRG-APP-000026-CTR-000070 - SRG-APP-000027-CTR-000075 - SRG-APP-000028-CTR-000080 - SRG-APP-000291-CTR-000675 - SRG-APP-000292-CTR-000680 - SRG-APP-000293-CTR-000685 - SRG-APP-000294-CTR-000690 - SRG-APP-000319-CTR-000745 - SRG-APP-000320-CTR-000750 - SRG-APP-000509-CTR-001305 - The actions taken by system administrators should be audited to keep a record -of what was executed on the system, as well as, for accountability purposes. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +-w /etc/sudoers.d/ -p wa -k actions + + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 18 + 19 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 5.4.1.1 + APO10.01 + APO10.03 + APO10.04 + APO10.05 + APO11.04 + APO12.06 + APO13.01 + BAI03.05 + BAI08.02 + DSS01.03 + DSS01.04 + DSS02.02 + DSS02.04 + DSS02.07 + DSS03.01 + DSS03.05 + DSS05.02 + DSS05.03 + DSS05.04 + DSS05.05 + DSS05.07 + DSS06.03 + MEA01.01 + MEA01.02 + MEA01.03 + MEA01.04 + MEA01.05 + MEA02.01 + 3.1.7 + CCI-000126 + CCI-000130 + CCI-000135 + CCI-000169 + CCI-000172 + CCI-002884 + 164.308(a)(1)(ii)(D) + 164.308(a)(3)(ii)(A) + 164.308(a)(5)(ii)(C) + 164.312(a)(2)(i) + 164.312(b) + 164.312(d) + 164.312(e) + 4.2.3.10 + 4.3.2.6.7 + 4.3.3.2.2 + 4.3.3.3.9 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.8 + 4.3.3.6.6 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.4.7 + 4.3.4.5.6 + 4.3.4.5.7 + 4.3.4.5.8 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 1.1 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.6 + SR 2.8 + SR 2.9 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 6.1 + SR 6.2 + SR 7.1 + SR 7.6 + A.11.2.6 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.13.1.1 + A.13.2.1 + A.14.1.3 + A.14.2.7 + A.15.2.1 + A.15.2.2 + A.16.1.4 + A.16.1.5 + A.16.1.7 + A.6.1.2 + A.6.2.1 + A.6.2.2 + A.7.1.1 + A.9.1.2 + A.9.2.1 + A.9.2.2 + A.9.2.3 + A.9.2.4 + A.9.2.6 + A.9.3.1 + A.9.4.1 + A.9.4.2 + A.9.4.3 + A.9.4.4 + A.9.4.5 + AC-2(7)(b) + AU-2(d) + AU-12(c) + AC-6(9) + CM-6(a) + DE.AE-3 + DE.AE-5 + DE.CM-1 + DE.CM-3 + DE.CM-7 + ID.SC-4 + PR.AC-1 + PR.AC-3 + PR.AC-4 + PR.AC-6 + PR.PT-1 + PR.PT-4 + RS.AN-1 + RS.AN-4 + Req-10.2.2 + Req-10.2.5.b + SRG-OS-000004-GPOS-00004 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000304-GPOS-00121 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000470-GPOS-00214 + SRG-OS-000471-GPOS-00215 + SRG-OS-000239-GPOS-00089 + SRG-OS-000240-GPOS-00090 + SRG-OS-000241-GPOS-00091 + SRG-OS-000303-GPOS-00120 + SRG-OS-000304-GPOS-00121 + SRG-OS-000466-GPOS-00210 + SRG-OS-000476-GPOS-00221 + SRG-APP-000026-CTR-000070 + SRG-APP-000027-CTR-000075 + SRG-APP-000028-CTR-000080 + SRG-APP-000291-CTR-000675 + SRG-APP-000292-CTR-000680 + SRG-APP-000293-CTR-000685 + SRG-APP-000294-CTR-000690 + SRG-APP-000319-CTR-000745 + SRG-APP-000320-CTR-000750 + SRG-APP-000509-CTR-001305 + R73 + A.3.SEC-OL7 + 10.2.1.5 + 10.2.1 + 10.2 + The actions taken by system administrators should be audited to keep a record +of what was executed on the system, as well as, for accountability purposes. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' + # Create a list of audit *.rules files that should be inspected for presence and correctness # of a particular audit rule. The scheme is as follows: # @@ -46178,7 +126241,7 @@ then if [ ! -e "$key_rule_file" ] then touch "$key_rule_file" - chmod 0640 "$key_rule_file" + chmod 0600 "$key_rule_file" fi files_to_inspect+=("$key_rule_file") fi @@ -46220,7 +126283,6 @@ do echo "-w /etc/sudoers -p wa -k actions" >> "$audit_rules_file" fi done - # Create a list of audit *.rules files that should be inspected for presence and correctness # of a particular audit rule. The scheme is as follows: # @@ -46311,7 +126373,7 @@ then if [ ! -e "$key_rule_file" ] then touch "$key_rule_file" - chmod 0640 "$key_rule_file" + chmod 0600 "$key_rule_file" fi files_to_inspect+=("$key_rule_file") fi @@ -46357,8 +126419,8 @@ done else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: @@ -46371,152 +126433,9 @@ fi - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.2 - PCI-DSS-Req-10.2.5.b + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.5 - - PCI-DSSv4-10.2.2 - - audit_rules_sysadmin_actions - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - -- name: Check if watch rule for /etc/sudoers already exists in /etc/audit/rules.d/ - find: - paths: /etc/audit/rules.d - contains: ^\s*-w\s+/etc/sudoers\s+-p\s+wa(\s|$)+ - patterns: '*.rules' - register: find_existing_watch_rules_d - when: - - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - CJIS-5.4.1.1 - - NIST-800-171-3.1.7 - - NIST-800-53-AC-2(7)(b) - - NIST-800-53-AC-6(9) - - NIST-800-53-AU-12(c) - - NIST-800-53-AU-2(d) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.2.2 - - PCI-DSS-Req-10.2.5.b - - PCI-DSSv4-10.2.1.5 - - PCI-DSSv4-10.2.2 - - audit_rules_sysadmin_actions - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - -- name: Search /etc/audit/rules.d for other rules with specified key actions - find: - paths: /etc/audit/rules.d - contains: ^.*(?:-F key=|-k\s+)actions$ - patterns: '*.rules' - register: find_watch_key - when: - - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched - == 0 - tags: - - CJIS-5.4.1.1 - - NIST-800-171-3.1.7 - - NIST-800-53-AC-2(7)(b) - - NIST-800-53-AC-6(9) - - NIST-800-53-AU-12(c) - - NIST-800-53-AU-2(d) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.2.2 - - PCI-DSS-Req-10.2.5.b - - PCI-DSSv4-10.2.1.5 - - PCI-DSSv4-10.2.2 - - audit_rules_sysadmin_actions - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - -- name: Use /etc/audit/rules.d/actions.rules as the recipient for the rule - set_fact: - all_files: - - /etc/audit/rules.d/actions.rules - when: - - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - find_watch_key.matched is defined and find_watch_key.matched == 0 and find_existing_watch_rules_d.matched - is defined and find_existing_watch_rules_d.matched == 0 - tags: - - CJIS-5.4.1.1 - - NIST-800-171-3.1.7 - - NIST-800-53-AC-2(7)(b) - - NIST-800-53-AC-6(9) - - NIST-800-53-AU-12(c) - - NIST-800-53-AU-2(d) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.2.2 - - PCI-DSS-Req-10.2.5.b - - PCI-DSSv4-10.2.1.5 - - PCI-DSSv4-10.2.2 - - audit_rules_sysadmin_actions - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - -- name: Use matched file as the recipient for the rule - set_fact: - all_files: - - '{{ find_watch_key.files | map(attribute=''path'') | list | first }}' - when: - - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - find_watch_key.matched is defined and find_watch_key.matched > 0 and find_existing_watch_rules_d.matched - is defined and find_existing_watch_rules_d.matched == 0 - tags: - - CJIS-5.4.1.1 - - NIST-800-171-3.1.7 - - NIST-800-53-AC-2(7)(b) - - NIST-800-53-AC-6(9) - - NIST-800-53-AU-12(c) - - NIST-800-53-AU-2(d) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.2.2 - - PCI-DSS-Req-10.2.5.b - - PCI-DSSv4-10.2.1.5 - - PCI-DSSv4-10.2.2 - - audit_rules_sysadmin_actions - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - -- name: Add watch rule for /etc/sudoers in /etc/audit/rules.d/ - lineinfile: - path: '{{ all_files[0] }}' - line: -w /etc/sudoers -p wa -k actions - create: true - mode: '0640' - when: - - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched - == 0 - tags: - - CJIS-5.4.1.1 - - NIST-800-171-3.1.7 - - NIST-800-53-AC-2(7)(b) - - NIST-800-53-AC-6(9) - - NIST-800-53-AU-12(c) - - NIST-800-53-AU-2(d) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.2.2 - - PCI-DSS-Req-10.2.5.b - - PCI-DSSv4-10.2.1.5 - - PCI-DSSv4-10.2.2 - audit_rules_sysadmin_actions - low_complexity - low_disruption @@ -46532,7 +126451,7 @@ fi register: find_existing_watch_audit_rules when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.4.1.1 - NIST-800-171-3.1.7 @@ -46543,8 +126462,9 @@ fi - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.2 - PCI-DSS-Req-10.2.5.b + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.5 - - PCI-DSSv4-10.2.2 - audit_rules_sysadmin_actions - low_complexity - low_disruption @@ -46558,10 +126478,10 @@ fi state: present dest: /etc/audit/audit.rules create: true - mode: '0640' + mode: '0600' when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_existing_watch_audit_rules.matched is defined and find_existing_watch_audit_rules.matched == 0 tags: @@ -46574,8 +126494,9 @@ fi - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.2 - PCI-DSS-Req-10.2.5.b + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.5 - - PCI-DSSv4-10.2.2 - audit_rules_sysadmin_actions - low_complexity - low_disruption @@ -46583,15 +126504,15 @@ fi - no_reboot_needed - restrict_strategy -- name: Check if watch rule for /etc/sudoers.d/ already exists in /etc/audit/rules.d/ +- name: Check if watch rule for /etc/sudoers already exists in /etc/audit/rules.d/ find: paths: /etc/audit/rules.d - contains: ^\s*-w\s+/etc/sudoers.d/\s+-p\s+wa(\s|$)+ + contains: ^\s*-w\s+/etc/sudoers\s+-p\s+wa(\s|$)+ patterns: '*.rules' register: find_existing_watch_rules_d when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.4.1.1 - NIST-800-171-3.1.7 @@ -46602,8 +126523,9 @@ fi - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.2 - PCI-DSS-Req-10.2.5.b + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.5 - - PCI-DSSv4-10.2.2 - audit_rules_sysadmin_actions - low_complexity - low_disruption @@ -46619,7 +126541,7 @@ fi register: find_watch_key when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: @@ -46632,8 +126554,9 @@ fi - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.2 - PCI-DSS-Req-10.2.5.b + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.5 - - PCI-DSSv4-10.2.2 - audit_rules_sysadmin_actions - low_complexity - low_disruption @@ -46647,7 +126570,7 @@ fi - /etc/audit/rules.d/actions.rules when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_watch_key.matched is defined and find_watch_key.matched == 0 and find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: @@ -46660,8 +126583,9 @@ fi - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.2 - PCI-DSS-Req-10.2.5.b + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.5 - - PCI-DSSv4-10.2.2 - audit_rules_sysadmin_actions - low_complexity - low_disruption @@ -46675,7 +126599,7 @@ fi - '{{ find_watch_key.files | map(attribute=''path'') | list | first }}' when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_watch_key.matched is defined and find_watch_key.matched > 0 and find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: @@ -46688,8 +126612,9 @@ fi - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.2 - PCI-DSS-Req-10.2.5.b + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.5 - - PCI-DSSv4-10.2.2 - audit_rules_sysadmin_actions - low_complexity - low_disruption @@ -46697,15 +126622,15 @@ fi - no_reboot_needed - restrict_strategy -- name: Add watch rule for /etc/sudoers.d/ in /etc/audit/rules.d/ +- name: Add watch rule for /etc/sudoers in /etc/audit/rules.d/ lineinfile: path: '{{ all_files[0] }}' - line: -w /etc/sudoers.d/ -p wa -k actions + line: -w /etc/sudoers -p wa -k actions create: true - mode: '0640' + mode: '0600' when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: @@ -46718,8 +126643,9 @@ fi - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.2 - PCI-DSS-Req-10.2.5.b + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.5 - - PCI-DSSv4-10.2.2 - audit_rules_sysadmin_actions - low_complexity - low_disruption @@ -46735,7 +126661,7 @@ fi register: find_existing_watch_audit_rules when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.4.1.1 - NIST-800-171-3.1.7 @@ -46746,8 +126672,9 @@ fi - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.2 - PCI-DSS-Req-10.2.5.b + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.5 - - PCI-DSSv4-10.2.2 - audit_rules_sysadmin_actions - low_complexity - low_disruption @@ -46761,10 +126688,10 @@ fi state: present dest: /etc/audit/audit.rules create: true - mode: '0640' + mode: '0600' when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_existing_watch_audit_rules.matched is defined and find_existing_watch_audit_rules.matched == 0 tags: @@ -46777,90 +126704,246 @@ fi - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.2 - PCI-DSS-Req-10.2.5.b + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.5 - - PCI-DSSv4-10.2.2 - audit_rules_sysadmin_actions - low_complexity - low_disruption - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Shutdown System When Auditing Failures Occur - If the auditd daemon is configured to use the + +- name: Check if watch rule for /etc/sudoers.d/ already exists in /etc/audit/rules.d/ + find: + paths: /etc/audit/rules.d + contains: ^\s*-w\s+/etc/sudoers.d/\s+-p\s+wa(\s|$)+ + patterns: '*.rules' + register: find_existing_watch_rules_d + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.4.1.1 + - NIST-800-171-3.1.7 + - NIST-800-53-AC-2(7)(b) + - NIST-800-53-AC-6(9) + - NIST-800-53-AU-12(c) + - NIST-800-53-AU-2(d) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-10.2.2 + - PCI-DSS-Req-10.2.5.b + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 + - PCI-DSSv4-10.2.1.5 + - audit_rules_sysadmin_actions + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Search /etc/audit/rules.d for other rules with specified key actions + find: + paths: /etc/audit/rules.d + contains: ^.*(?:-F key=|-k\s+)actions$ + patterns: '*.rules' + register: find_watch_key + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched + == 0 + tags: + - CJIS-5.4.1.1 + - NIST-800-171-3.1.7 + - NIST-800-53-AC-2(7)(b) + - NIST-800-53-AC-6(9) + - NIST-800-53-AU-12(c) + - NIST-800-53-AU-2(d) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-10.2.2 + - PCI-DSS-Req-10.2.5.b + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 + - PCI-DSSv4-10.2.1.5 + - audit_rules_sysadmin_actions + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Use /etc/audit/rules.d/actions.rules as the recipient for the rule + set_fact: + all_files: + - /etc/audit/rules.d/actions.rules + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_watch_key.matched is defined and find_watch_key.matched == 0 and find_existing_watch_rules_d.matched + is defined and find_existing_watch_rules_d.matched == 0 + tags: + - CJIS-5.4.1.1 + - NIST-800-171-3.1.7 + - NIST-800-53-AC-2(7)(b) + - NIST-800-53-AC-6(9) + - NIST-800-53-AU-12(c) + - NIST-800-53-AU-2(d) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-10.2.2 + - PCI-DSS-Req-10.2.5.b + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 + - PCI-DSSv4-10.2.1.5 + - audit_rules_sysadmin_actions + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Use matched file as the recipient for the rule + set_fact: + all_files: + - '{{ find_watch_key.files | map(attribute=''path'') | list | first }}' + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_watch_key.matched is defined and find_watch_key.matched > 0 and find_existing_watch_rules_d.matched + is defined and find_existing_watch_rules_d.matched == 0 + tags: + - CJIS-5.4.1.1 + - NIST-800-171-3.1.7 + - NIST-800-53-AC-2(7)(b) + - NIST-800-53-AC-6(9) + - NIST-800-53-AU-12(c) + - NIST-800-53-AU-2(d) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-10.2.2 + - PCI-DSS-Req-10.2.5.b + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 + - PCI-DSSv4-10.2.1.5 + - audit_rules_sysadmin_actions + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Add watch rule for /etc/sudoers.d/ in /etc/audit/rules.d/ + lineinfile: + path: '{{ all_files[0] }}' + line: -w /etc/sudoers.d/ -p wa -k actions + create: true + mode: '0600' + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched + == 0 + tags: + - CJIS-5.4.1.1 + - NIST-800-171-3.1.7 + - NIST-800-53-AC-2(7)(b) + - NIST-800-53-AC-6(9) + - NIST-800-53-AU-12(c) + - NIST-800-53-AU-2(d) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-10.2.2 + - PCI-DSS-Req-10.2.5.b + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 + - PCI-DSSv4-10.2.1.5 + - audit_rules_sysadmin_actions + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + + + + + + + + + + Shutdown System When Auditing Failures Occur + If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following line to to the bottom of a file with suffix .rules in the directory /etc/audit/rules.d: --f +-f + If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following line to the bottom of the /etc/audit/audit.rules file: --f - 1 - 14 - 15 - 16 - 3 - 5 - 6 - APO11.04 - BAI03.05 - DSS05.04 - DSS05.07 - MEA02.01 - 3.3.1 - 3.3.4 - CCI-000139 - CCI-000140 - 164.308(a)(1)(ii)(D) - 164.308(a)(3)(ii)(A) - 164.308(a)(5)(ii)(C) - 164.312(a)(2)(i) - 164.312(b) - 164.312(d) - 164.312(e) - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.4.4.7 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.8 - SR 2.9 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - AU-5(b) - SC-24 - CM-6(a) - PR.PT-1 - SRG-OS-000046-GPOS-00022 - SRG-OS-000047-GPOS-00023 - It is critical for the appropriate personnel to be aware if a system +-f + + + 1 + 14 + 15 + 16 + 3 + 5 + 6 + APO11.04 + BAI03.05 + DSS05.04 + DSS05.07 + MEA02.01 + 3.3.1 + 3.3.4 + CCI-000140 + CCI-000139 + 164.308(a)(1)(ii)(D) + 164.308(a)(3)(ii)(A) + 164.308(a)(5)(ii)(C) + 164.312(a)(2)(i) + 164.312(b) + 164.312(d) + 164.312(e) + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.4.4.7 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.8 + SR 2.9 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + AU-5(b) + SC-24 + CM-6(a) + PR.PT-1 + SRG-OS-000046-GPOS-00022 + SRG-OS-000047-GPOS-00023 + OL09-00-000820 + SV-271590r1091482_rule + It is critical for the appropriate personnel to be aware if a system is at risk of failing to process audit logs as required. Without this notification, the security personnel may be unaware of an impending failure of the audit capability, and system operation may be adversely affected. - + + Audit processing failures include software/hardware errors, failures in the audit capturing mechanisms, and audit storage capacity being reached or -exceeded. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +exceeded. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -var_audit_failure_mode='' +var_audit_failure_mode='' # Traverse all of: @@ -46879,11 +126962,12 @@ done else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-000820 - NIST-800-171-3.3.1 - NIST-800-171-3.3.4 - NIST-800-53-AU-5(b) @@ -46897,7 +126981,7 @@ fi - restrict_strategy - name: XCCDF Value var_audit_failure_mode # promote to variable set_fact: - var_audit_failure_mode: !!str + var_audit_failure_mode: !!str tags: - always @@ -46908,8 +126992,9 @@ fi register: find_rules_d when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-000820 - NIST-800-171-3.3.1 - NIST-800-171-3.3.4 - NIST-800-53-AU-5(b) @@ -46931,8 +127016,9 @@ fi }}' when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-000820 - NIST-800-171-3.3.1 - NIST-800-171-3.3.4 - NIST-800-53-AU-5(b) @@ -46949,14 +127035,16 @@ fi lineinfile: path: '{{ item }}' create: true + mode: '0600' line: -f {{ var_audit_failure_mode }} loop: - /etc/audit/audit.rules - /etc/audit/rules.d/immutable.rules when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-000820 - NIST-800-171-3.3.1 - NIST-800-171-3.3.4 - NIST-800-53-AU-5(b) @@ -46968,18 +127056,18 @@ fi - medium_severity - reboot_required - restrict_strategy - - - - - - - - - - - Record Events that Modify User/Group Information - If the auditd daemon is configured to use the + + + + + + + + + + + Record Events that Modify User/Group Information + If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following lines to a file with suffix .rules in the directory /etc/audit/rules.d, in order to capture events that modify @@ -46989,7 +127077,7 @@ account changes: -w /etc/gshadow -p wa -k audit_rules_usergroup_modification -w /etc/shadow -p wa -k audit_rules_usergroup_modification -w /etc/security/opasswd -p wa -k audit_rules_usergroup_modification - + If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following lines to /etc/audit/audit.rules file, in order to capture events that modify @@ -46998,195 +127086,196 @@ account changes: -w /etc/passwd -p wa -k audit_rules_usergroup_modification -w /etc/gshadow -p wa -k audit_rules_usergroup_modification -w /etc/shadow -p wa -k audit_rules_usergroup_modification --w /etc/security/opasswd -p wa -k audit_rules_usergroup_modification - This rule checks for multiple syscalls related to account changes; +-w /etc/security/opasswd -p wa -k audit_rules_usergroup_modification + + This rule checks for multiple syscalls related to account changes; it was written with DISA STIG in mind. Other policies should use a separate rule for each syscall that needs to be checked. For example: -audit_rules_usergroup_modification_groupaudit_rules_usergroup_modification_gshadowaudit_rules_usergroup_modification_passwd - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 18 - 19 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 5.4.1.1 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - APO12.06 - APO13.01 - BAI03.05 - BAI08.02 - DSS01.03 - DSS01.04 - DSS02.02 - DSS02.04 - DSS02.07 - DSS03.01 - DSS03.05 - DSS05.02 - DSS05.03 - DSS05.04 - DSS05.05 - DSS05.07 - DSS06.03 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.1.7 - CCI-000018 - CCI-000130 - CCI-000172 - CCI-001403 - CCI-002130 - 4.2.3.10 - 4.3.2.6.7 - 4.3.3.2.2 - 4.3.3.3.9 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.8 - 4.3.3.6.6 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.4.7 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 1.1 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.6 - SR 2.8 - SR 2.9 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 6.1 - SR 6.2 - SR 7.1 - SR 7.6 - A.11.2.6 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.14.2.7 - A.15.2.1 - A.15.2.2 - A.16.1.4 - A.16.1.5 - A.16.1.7 - A.6.1.2 - A.6.2.1 - A.6.2.2 - A.7.1.1 - A.9.1.2 - A.9.2.1 - A.9.2.2 - A.9.2.3 - A.9.2.4 - A.9.2.6 - A.9.3.1 - A.9.4.1 - A.9.4.2 - A.9.4.3 - A.9.4.4 - A.9.4.5 - CIP-004-6 R2.2.2 - CIP-004-6 R2.2.3 - CIP-007-3 R.1.3 - CIP-007-3 R5 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.3 - CIP-007-3 R5.2.1 - CIP-007-3 R5.2.3 - AC-2(4) - AU-2(d) - AU-12(c) - AC-6(9) - CM-6(a) - DE.AE-3 - DE.AE-5 - DE.CM-1 - DE.CM-3 - DE.CM-7 - ID.SC-4 - PR.AC-1 - PR.AC-3 - PR.AC-4 - PR.AC-6 - PR.PT-1 - PR.PT-4 - RS.AN-1 - RS.AN-4 - Req-10.2.5 - 10.2.1.5 - SRG-OS-000004-GPOS-00004 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000239-GPOS-00089 - SRG-OS-000241-GPOS-00090 - SRG-OS-000241-GPOS-00091 - SRG-OS-000303-GPOS-00120 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-OS-000476-GPOS-00221 - SRG-APP-000026-CTR-000070 - SRG-APP-000027-CTR-000075 - SRG-APP-000028-CTR-000080 - SRG-APP-000291-CTR-000675 - SRG-APP-000292-CTR-000680 - SRG-APP-000293-CTR-000685 - SRG-APP-000294-CTR-000690 - SRG-APP-000319-CTR-000745 - SRG-APP-000320-CTR-000750 - SRG-APP-000509-CTR-001305 - In addition to auditing new user and group accounts, these watches +audit_rules_usergroup_modification_groupaudit_rules_usergroup_modification_gshadowaudit_rules_usergroup_modification_passwd + + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 18 + 19 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 5.4.1.1 + APO10.01 + APO10.03 + APO10.04 + APO10.05 + APO11.04 + APO12.06 + APO13.01 + BAI03.05 + BAI08.02 + DSS01.03 + DSS01.04 + DSS02.02 + DSS02.04 + DSS02.07 + DSS03.01 + DSS03.05 + DSS05.02 + DSS05.03 + DSS05.04 + DSS05.05 + DSS05.07 + DSS06.03 + MEA01.01 + MEA01.02 + MEA01.03 + MEA01.04 + MEA01.05 + MEA02.01 + 3.1.7 + CCI-000018 + CCI-000130 + CCI-000172 + CCI-001403 + CCI-002130 + 4.2.3.10 + 4.3.2.6.7 + 4.3.3.2.2 + 4.3.3.3.9 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.8 + 4.3.3.6.6 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.4.7 + 4.3.4.5.6 + 4.3.4.5.7 + 4.3.4.5.8 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 1.1 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.6 + SR 2.8 + SR 2.9 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 6.1 + SR 6.2 + SR 7.1 + SR 7.6 + A.11.2.6 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.13.1.1 + A.13.2.1 + A.14.1.3 + A.14.2.7 + A.15.2.1 + A.15.2.2 + A.16.1.4 + A.16.1.5 + A.16.1.7 + A.6.1.2 + A.6.2.1 + A.6.2.2 + A.7.1.1 + A.9.1.2 + A.9.2.1 + A.9.2.2 + A.9.2.3 + A.9.2.4 + A.9.2.6 + A.9.3.1 + A.9.4.1 + A.9.4.2 + A.9.4.3 + A.9.4.4 + A.9.4.5 + CIP-004-6 R2.2.2 + CIP-004-6 R2.2.3 + CIP-007-3 R.1.3 + CIP-007-3 R5 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.3 + CIP-007-3 R5.2.1 + CIP-007-3 R5.2.3 + AC-2(4) + AU-2(d) + AU-12(c) + AC-6(9) + CM-6(a) + DE.AE-3 + DE.AE-5 + DE.CM-1 + DE.CM-3 + DE.CM-7 + ID.SC-4 + PR.AC-1 + PR.AC-3 + PR.AC-4 + PR.AC-6 + PR.PT-1 + PR.PT-4 + RS.AN-1 + RS.AN-4 + Req-10.2.5 + SRG-OS-000004-GPOS-00004 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000239-GPOS-00089 + SRG-OS-000241-GPOS-00090 + SRG-OS-000241-GPOS-00091 + SRG-OS-000303-GPOS-00120 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-OS-000476-GPOS-00221 + SRG-APP-000026-CTR-000070 + SRG-APP-000027-CTR-000075 + SRG-APP-000028-CTR-000080 + SRG-APP-000291-CTR-000675 + SRG-APP-000292-CTR-000680 + SRG-APP-000293-CTR-000685 + SRG-APP-000294-CTR-000690 + SRG-APP-000319-CTR-000745 + SRG-APP-000320-CTR-000750 + SRG-APP-000509-CTR-001305 + In addition to auditing new user and group accounts, these watches will alert the system administrator(s) to any modifications. Any unexpected -users, groups, or modifications should be investigated for legitimacy. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +users, groups, or modifications should be investigated for legitimacy. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' # Create a list of audit *.rules files that should be inspected for presence and correctness @@ -47279,7 +127368,7 @@ then if [ ! -e "$key_rule_file" ] then touch "$key_rule_file" - chmod 0640 "$key_rule_file" + chmod 0600 "$key_rule_file" fi files_to_inspect+=("$key_rule_file") fi @@ -47411,7 +127500,7 @@ then if [ ! -e "$key_rule_file" ] then touch "$key_rule_file" - chmod 0640 "$key_rule_file" + chmod 0600 "$key_rule_file" fi files_to_inspect+=("$key_rule_file") fi @@ -47543,7 +127632,7 @@ then if [ ! -e "$key_rule_file" ] then touch "$key_rule_file" - chmod 0640 "$key_rule_file" + chmod 0600 "$key_rule_file" fi files_to_inspect+=("$key_rule_file") fi @@ -47675,7 +127764,7 @@ then if [ ! -e "$key_rule_file" ] then touch "$key_rule_file" - chmod 0640 "$key_rule_file" + chmod 0600 "$key_rule_file" fi files_to_inspect+=("$key_rule_file") fi @@ -47807,7 +127896,7 @@ then if [ ! -e "$key_rule_file" ] then touch "$key_rule_file" - chmod 0640 "$key_rule_file" + chmod 0600 "$key_rule_file" fi files_to_inspect+=("$key_rule_file") fi @@ -47853,227 +127942,234 @@ done else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - - - - - - - - Record Events that Modify User/Group Information - /etc/group - If the auditd daemon is configured to use the + + + + + + + + + + Record Events that Modify User/Group Information - /etc/group + If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following lines to a file with suffix .rules in the directory /etc/audit/rules.d, in order to capture events that modify account changes: - --w /etc/group -p wa -k audit_rules_usergroup_modification - + + + -w /etc/group -p wa -k audit_rules_usergroup_modification + + If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following lines to /etc/audit/audit.rules file, in order to capture events that modify account changes: - --w /etc/group -p wa -k audit_rules_usergroup_modification - BP28(R73) - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 18 - 19 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 5.4.1.1 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - APO12.06 - APO13.01 - BAI03.05 - BAI08.02 - DSS01.03 - DSS01.04 - DSS02.02 - DSS02.04 - DSS02.07 - DSS03.01 - DSS03.05 - DSS05.02 - DSS05.03 - DSS05.04 - DSS05.05 - DSS05.07 - DSS06.03 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.1.7 - CCI-000018 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-000172 - CCI-001403 - CCI-001404 - CCI-001405 - CCI-001683 - CCI-001684 - CCI-001685 - CCI-001686 - CCI-002130 - CCI-002132 - CCI-002884 - 164.308(a)(1)(ii)(D) - 164.308(a)(3)(ii)(A) - 164.308(a)(5)(ii)(C) - 164.312(a)(2)(i) - 164.312(b) - 164.312(d) - 164.312(e) - 4.2.3.10 - 4.3.2.6.7 - 4.3.3.2.2 - 4.3.3.3.9 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.8 - 4.3.3.6.6 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.4.7 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 1.1 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.6 - SR 2.8 - SR 2.9 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 6.1 - SR 6.2 - SR 7.1 - SR 7.6 - A.11.2.6 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.14.2.7 - A.15.2.1 - A.15.2.2 - A.16.1.4 - A.16.1.5 - A.16.1.7 - A.6.1.2 - A.6.2.1 - A.6.2.2 - A.7.1.1 - A.9.1.2 - A.9.2.1 - A.9.2.2 - A.9.2.3 - A.9.2.4 - A.9.2.6 - A.9.3.1 - A.9.4.1 - A.9.4.2 - A.9.4.3 - A.9.4.4 - A.9.4.5 - CIP-004-6 R2.2.2 - CIP-004-6 R2.2.3 - CIP-007-3 R.1.3 - CIP-007-3 R5 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.3 - CIP-007-3 R5.2.1 - CIP-007-3 R5.2.3 - AC-2(4) - AU-2(d) - AU-12(c) - AC-6(9) - CM-6(a) - DE.AE-3 - DE.AE-5 - DE.CM-1 - DE.CM-3 - DE.CM-7 - ID.SC-4 - PR.AC-1 - PR.AC-3 - PR.AC-4 - PR.AC-6 - PR.PT-1 - PR.PT-4 - RS.AN-1 - RS.AN-4 - FAU_GEN.1.1.c - Req-10.2.5 - 10.2.1.5 - SRG-OS-000004-GPOS-00004 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000304-GPOS-00121 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000470-GPOS-00214 - SRG-OS-000471-GPOS-00215 - SRG-OS-000239-GPOS-00089 - SRG-OS-000240-GPOS-00090 - SRG-OS-000241-GPOS-00091 - SRG-OS-000303-GPOS-00120 - SRG-OS-000466-GPOS-00210 - SRG-OS-000476-GPOS-00221 - In addition to auditing new user and group accounts, these watches + + + -w /etc/group -p wa -k audit_rules_usergroup_modification + + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 18 + 19 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 5.4.1.1 + APO10.01 + APO10.03 + APO10.04 + APO10.05 + APO11.04 + APO12.06 + APO13.01 + BAI03.05 + BAI08.02 + DSS01.03 + DSS01.04 + DSS02.02 + DSS02.04 + DSS02.07 + DSS03.01 + DSS03.05 + DSS05.02 + DSS05.03 + DSS05.04 + DSS05.05 + DSS05.07 + DSS06.03 + MEA01.01 + MEA01.02 + MEA01.03 + MEA01.04 + MEA01.05 + MEA02.01 + 3.1.7 + CCI-001403 + CCI-001404 + CCI-001405 + CCI-000172 + CCI-000130 + CCI-002130 + CCI-000135 + CCI-000169 + CCI-002884 + CCI-000018 + CCI-000015 + 164.308(a)(1)(ii)(D) + 164.308(a)(3)(ii)(A) + 164.308(a)(5)(ii)(C) + 164.312(a)(2)(i) + 164.312(b) + 164.312(d) + 164.312(e) + 4.2.3.10 + 4.3.2.6.7 + 4.3.3.2.2 + 4.3.3.3.9 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.8 + 4.3.3.6.6 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.4.7 + 4.3.4.5.6 + 4.3.4.5.7 + 4.3.4.5.8 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 1.1 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.6 + SR 2.8 + SR 2.9 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 6.1 + SR 6.2 + SR 7.1 + SR 7.6 + A.11.2.6 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.13.1.1 + A.13.2.1 + A.14.1.3 + A.14.2.7 + A.15.2.1 + A.15.2.2 + A.16.1.4 + A.16.1.5 + A.16.1.7 + A.6.1.2 + A.6.2.1 + A.6.2.2 + A.7.1.1 + A.9.1.2 + A.9.2.1 + A.9.2.2 + A.9.2.3 + A.9.2.4 + A.9.2.6 + A.9.3.1 + A.9.4.1 + A.9.4.2 + A.9.4.3 + A.9.4.4 + A.9.4.5 + CIP-004-6 R2.2.2 + CIP-004-6 R2.2.3 + CIP-007-3 R.1.3 + CIP-007-3 R5 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.3 + CIP-007-3 R5.2.1 + CIP-007-3 R5.2.3 + AC-2(4) + AU-2(d) + AU-12(c) + AC-6(9) + CM-6(a) + DE.AE-3 + DE.AE-5 + DE.CM-1 + DE.CM-3 + DE.CM-7 + ID.SC-4 + PR.AC-1 + PR.AC-3 + PR.AC-4 + PR.AC-6 + PR.PT-1 + PR.PT-4 + RS.AN-1 + RS.AN-4 + Req-10.2.5 + SRG-OS-000004-GPOS-00004 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000304-GPOS-00121 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000470-GPOS-00214 + SRG-OS-000471-GPOS-00215 + SRG-OS-000239-GPOS-00089 + SRG-OS-000240-GPOS-00090 + SRG-OS-000241-GPOS-00091 + SRG-OS-000303-GPOS-00120 + SRG-OS-000466-GPOS-00210 + SRG-OS-000476-GPOS-00221 + SRG-APP-000495-CTR-001235 + SRG-APP-000499-CTR-001255 + SRG-APP-000503-CTR-001275 + R73 + A.3.SEC-OL7 + 10.2.1.5 + 10.2.1 + 10.2 + OL09-00-000510 + SV-271529r1092478_rule + In addition to auditing new user and group accounts, these watches will alert the system administrator(s) to any modifications. Any unexpected -users, groups, or modifications should be investigated for legitimacy. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +users, groups, or modifications should be investigated for legitimacy. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' @@ -48167,7 +128263,7 @@ then if [ ! -e "$key_rule_file" ] then touch "$key_rule_file" - chmod 0640 "$key_rule_file" + chmod 0600 "$key_rule_file" fi files_to_inspect+=("$key_rule_file") fi @@ -48213,12 +128309,13 @@ done else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000510 - NIST-800-171-3.1.7 - NIST-800-53-AC-2(4) - NIST-800-53-AC-6(9) @@ -48226,6 +128323,8 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.5 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.5 - audit_rules_usergroup_modification_group - low_complexity @@ -48242,9 +128341,10 @@ fi register: find_existing_watch_rules_d when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000510 - NIST-800-171-3.1.7 - NIST-800-53-AC-2(4) - NIST-800-53-AC-6(9) @@ -48252,6 +128352,8 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.5 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.5 - audit_rules_usergroup_modification_group - low_complexity @@ -48268,11 +128370,12 @@ fi register: find_watch_key when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000510 - NIST-800-171-3.1.7 - NIST-800-53-AC-2(4) - NIST-800-53-AC-6(9) @@ -48280,6 +128383,8 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.5 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.5 - audit_rules_usergroup_modification_group - low_complexity @@ -48295,11 +128400,12 @@ fi - /etc/audit/rules.d/audit_rules_usergroup_modification.rules when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_watch_key.matched is defined and find_watch_key.matched == 0 and find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000510 - NIST-800-171-3.1.7 - NIST-800-53-AC-2(4) - NIST-800-53-AC-6(9) @@ -48307,6 +128413,8 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.5 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.5 - audit_rules_usergroup_modification_group - low_complexity @@ -48321,11 +128429,12 @@ fi - '{{ find_watch_key.files | map(attribute=''path'') | list | first }}' when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_watch_key.matched is defined and find_watch_key.matched > 0 and find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000510 - NIST-800-171-3.1.7 - NIST-800-53-AC-2(4) - NIST-800-53-AC-6(9) @@ -48333,6 +128442,8 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.5 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.5 - audit_rules_usergroup_modification_group - low_complexity @@ -48346,14 +128457,15 @@ fi path: '{{ all_files[0] }}' line: -w /etc/group -p wa -k audit_rules_usergroup_modification create: true - mode: '0640' + mode: '0600' when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000510 - NIST-800-171-3.1.7 - NIST-800-53-AC-2(4) - NIST-800-53-AC-6(9) @@ -48361,6 +128473,8 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.5 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.5 - audit_rules_usergroup_modification_group - low_complexity @@ -48377,9 +128491,10 @@ fi register: find_existing_watch_audit_rules when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000510 - NIST-800-171-3.1.7 - NIST-800-53-AC-2(4) - NIST-800-53-AC-6(9) @@ -48387,6 +128502,8 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.5 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.5 - audit_rules_usergroup_modification_group - low_complexity @@ -48401,14 +128518,15 @@ fi state: present dest: /etc/audit/audit.rules create: true - mode: '0640' + mode: '0600' when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_existing_watch_audit_rules.matched is defined and find_existing_watch_audit_rules.matched == 0 tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000510 - NIST-800-171-3.1.7 - NIST-800-53-AC-2(4) - NIST-800-53-AC-6(9) @@ -48416,6 +128534,8 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.5 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.5 - audit_rules_usergroup_modification_group - low_complexity @@ -48423,227 +128543,234 @@ fi - medium_severity - reboot_required - restrict_strategy - - - - - - - - - - Record Events that Modify User/Group Information - /etc/gshadow - If the auditd daemon is configured to use the + + + + + + + + + + Record Events that Modify User/Group Information - /etc/gshadow + If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following lines to a file with suffix .rules in the directory /etc/audit/rules.d, in order to capture events that modify account changes: - --w /etc/gshadow -p wa -k audit_rules_usergroup_modification - + + + -w /etc/gshadow -p wa -k audit_rules_usergroup_modification + + If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following lines to /etc/audit/audit.rules file, in order to capture events that modify account changes: - --w /etc/gshadow -p wa -k audit_rules_usergroup_modification - BP28(R73) - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 18 - 19 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 5.4.1.1 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - APO12.06 - APO13.01 - BAI03.05 - BAI08.02 - DSS01.03 - DSS01.04 - DSS02.02 - DSS02.04 - DSS02.07 - DSS03.01 - DSS03.05 - DSS05.02 - DSS05.03 - DSS05.04 - DSS05.05 - DSS05.07 - DSS06.03 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.1.7 - CCI-000018 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-000172 - CCI-001403 - CCI-001404 - CCI-001405 - CCI-001683 - CCI-001684 - CCI-001685 - CCI-001686 - CCI-002130 - CCI-002132 - CCI-002884 - 164.308(a)(1)(ii)(D) - 164.308(a)(3)(ii)(A) - 164.308(a)(5)(ii)(C) - 164.312(a)(2)(i) - 164.312(b) - 164.312(d) - 164.312(e) - 4.2.3.10 - 4.3.2.6.7 - 4.3.3.2.2 - 4.3.3.3.9 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.8 - 4.3.3.6.6 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.4.7 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 1.1 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.6 - SR 2.8 - SR 2.9 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 6.1 - SR 6.2 - SR 7.1 - SR 7.6 - A.11.2.6 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.14.2.7 - A.15.2.1 - A.15.2.2 - A.16.1.4 - A.16.1.5 - A.16.1.7 - A.6.1.2 - A.6.2.1 - A.6.2.2 - A.7.1.1 - A.9.1.2 - A.9.2.1 - A.9.2.2 - A.9.2.3 - A.9.2.4 - A.9.2.6 - A.9.3.1 - A.9.4.1 - A.9.4.2 - A.9.4.3 - A.9.4.4 - A.9.4.5 - CIP-004-6 R2.2.2 - CIP-004-6 R2.2.3 - CIP-007-3 R.1.3 - CIP-007-3 R5 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.3 - CIP-007-3 R5.2.1 - CIP-007-3 R5.2.3 - AC-2(4) - AU-2(d) - AU-12(c) - AC-6(9) - CM-6(a) - DE.AE-3 - DE.AE-5 - DE.CM-1 - DE.CM-3 - DE.CM-7 - ID.SC-4 - PR.AC-1 - PR.AC-3 - PR.AC-4 - PR.AC-6 - PR.PT-1 - PR.PT-4 - RS.AN-1 - RS.AN-4 - FAU_GEN.1.1.c - Req-10.2.5 - 10.2.1.5 - SRG-OS-000004-GPOS-00004 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000304-GPOS-00121 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000470-GPOS-00214 - SRG-OS-000471-GPOS-00215 - SRG-OS-000239-GPOS-00089 - SRG-OS-000240-GPOS-00090 - SRG-OS-000241-GPOS-00091 - SRG-OS-000303-GPOS-00120 - SRG-OS-000466-GPOS-00210 - SRG-OS-000476-GPOS-00221 - In addition to auditing new user and group accounts, these watches + + + -w /etc/gshadow -p wa -k audit_rules_usergroup_modification + + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 18 + 19 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 5.4.1.1 + APO10.01 + APO10.03 + APO10.04 + APO10.05 + APO11.04 + APO12.06 + APO13.01 + BAI03.05 + BAI08.02 + DSS01.03 + DSS01.04 + DSS02.02 + DSS02.04 + DSS02.07 + DSS03.01 + DSS03.05 + DSS05.02 + DSS05.03 + DSS05.04 + DSS05.05 + DSS05.07 + DSS06.03 + MEA01.01 + MEA01.02 + MEA01.03 + MEA01.04 + MEA01.05 + MEA02.01 + 3.1.7 + CCI-001403 + CCI-001404 + CCI-001405 + CCI-000172 + CCI-000130 + CCI-002130 + CCI-000135 + CCI-000169 + CCI-002884 + CCI-000018 + CCI-000015 + 164.308(a)(1)(ii)(D) + 164.308(a)(3)(ii)(A) + 164.308(a)(5)(ii)(C) + 164.312(a)(2)(i) + 164.312(b) + 164.312(d) + 164.312(e) + 4.2.3.10 + 4.3.2.6.7 + 4.3.3.2.2 + 4.3.3.3.9 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.8 + 4.3.3.6.6 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.4.7 + 4.3.4.5.6 + 4.3.4.5.7 + 4.3.4.5.8 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 1.1 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.6 + SR 2.8 + SR 2.9 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 6.1 + SR 6.2 + SR 7.1 + SR 7.6 + A.11.2.6 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.13.1.1 + A.13.2.1 + A.14.1.3 + A.14.2.7 + A.15.2.1 + A.15.2.2 + A.16.1.4 + A.16.1.5 + A.16.1.7 + A.6.1.2 + A.6.2.1 + A.6.2.2 + A.7.1.1 + A.9.1.2 + A.9.2.1 + A.9.2.2 + A.9.2.3 + A.9.2.4 + A.9.2.6 + A.9.3.1 + A.9.4.1 + A.9.4.2 + A.9.4.3 + A.9.4.4 + A.9.4.5 + CIP-004-6 R2.2.2 + CIP-004-6 R2.2.3 + CIP-007-3 R.1.3 + CIP-007-3 R5 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.3 + CIP-007-3 R5.2.1 + CIP-007-3 R5.2.3 + AC-2(4) + AU-2(d) + AU-12(c) + AC-6(9) + CM-6(a) + DE.AE-3 + DE.AE-5 + DE.CM-1 + DE.CM-3 + DE.CM-7 + ID.SC-4 + PR.AC-1 + PR.AC-3 + PR.AC-4 + PR.AC-6 + PR.PT-1 + PR.PT-4 + RS.AN-1 + RS.AN-4 + Req-10.2.5 + SRG-OS-000004-GPOS-00004 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000304-GPOS-00121 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000470-GPOS-00214 + SRG-OS-000471-GPOS-00215 + SRG-OS-000239-GPOS-00089 + SRG-OS-000240-GPOS-00090 + SRG-OS-000241-GPOS-00091 + SRG-OS-000303-GPOS-00120 + SRG-OS-000466-GPOS-00210 + SRG-OS-000476-GPOS-00221 + SRG-APP-000495-CTR-001235 + SRG-APP-000499-CTR-001255 + SRG-APP-000503-CTR-001275 + R73 + A.3.SEC-OL7 + 10.2.1.5 + 10.2.1 + 10.2 + OL09-00-000515 + SV-271530r1092480_rule + In addition to auditing new user and group accounts, these watches will alert the system administrator(s) to any modifications. Any unexpected -users, groups, or modifications should be investigated for legitimacy. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +users, groups, or modifications should be investigated for legitimacy. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' @@ -48737,7 +128864,7 @@ then if [ ! -e "$key_rule_file" ] then touch "$key_rule_file" - chmod 0640 "$key_rule_file" + chmod 0600 "$key_rule_file" fi files_to_inspect+=("$key_rule_file") fi @@ -48783,12 +128910,13 @@ done else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000515 - NIST-800-171-3.1.7 - NIST-800-53-AC-2(4) - NIST-800-53-AC-6(9) @@ -48796,6 +128924,8 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.5 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.5 - audit_rules_usergroup_modification_gshadow - low_complexity @@ -48812,9 +128942,10 @@ fi register: find_existing_watch_rules_d when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000515 - NIST-800-171-3.1.7 - NIST-800-53-AC-2(4) - NIST-800-53-AC-6(9) @@ -48822,6 +128953,8 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.5 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.5 - audit_rules_usergroup_modification_gshadow - low_complexity @@ -48838,11 +128971,12 @@ fi register: find_watch_key when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000515 - NIST-800-171-3.1.7 - NIST-800-53-AC-2(4) - NIST-800-53-AC-6(9) @@ -48850,6 +128984,8 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.5 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.5 - audit_rules_usergroup_modification_gshadow - low_complexity @@ -48865,11 +129001,12 @@ fi - /etc/audit/rules.d/audit_rules_usergroup_modification.rules when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_watch_key.matched is defined and find_watch_key.matched == 0 and find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000515 - NIST-800-171-3.1.7 - NIST-800-53-AC-2(4) - NIST-800-53-AC-6(9) @@ -48877,6 +129014,8 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.5 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.5 - audit_rules_usergroup_modification_gshadow - low_complexity @@ -48891,11 +129030,12 @@ fi - '{{ find_watch_key.files | map(attribute=''path'') | list | first }}' when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_watch_key.matched is defined and find_watch_key.matched > 0 and find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000515 - NIST-800-171-3.1.7 - NIST-800-53-AC-2(4) - NIST-800-53-AC-6(9) @@ -48903,6 +129043,8 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.5 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.5 - audit_rules_usergroup_modification_gshadow - low_complexity @@ -48916,14 +129058,15 @@ fi path: '{{ all_files[0] }}' line: -w /etc/gshadow -p wa -k audit_rules_usergroup_modification create: true - mode: '0640' + mode: '0600' when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000515 - NIST-800-171-3.1.7 - NIST-800-53-AC-2(4) - NIST-800-53-AC-6(9) @@ -48931,6 +129074,8 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.5 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.5 - audit_rules_usergroup_modification_gshadow - low_complexity @@ -48947,9 +129092,10 @@ fi register: find_existing_watch_audit_rules when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000515 - NIST-800-171-3.1.7 - NIST-800-53-AC-2(4) - NIST-800-53-AC-6(9) @@ -48957,6 +129103,8 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.5 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.5 - audit_rules_usergroup_modification_gshadow - low_complexity @@ -48971,14 +129119,15 @@ fi state: present dest: /etc/audit/audit.rules create: true - mode: '0640' + mode: '0600' when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_existing_watch_audit_rules.matched is defined and find_existing_watch_audit_rules.matched == 0 tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000515 - NIST-800-171-3.1.7 - NIST-800-53-AC-2(4) - NIST-800-53-AC-6(9) @@ -48986,6 +129135,8 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.5 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.5 - audit_rules_usergroup_modification_gshadow - low_complexity @@ -48993,227 +129144,236 @@ fi - medium_severity - reboot_required - restrict_strategy - - - - - - - - - - Record Events that Modify User/Group Information - /etc/security/opasswd - If the auditd daemon is configured to use the + + + + + + + + + + Record Events that Modify User/Group Information - /etc/security/opasswd + If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following lines to a file with suffix .rules in the directory /etc/audit/rules.d, in order to capture events that modify account changes: - --w /etc/security/opasswd -p wa -k audit_rules_usergroup_modification - + + + -w /etc/security/opasswd -p wa -k audit_rules_usergroup_modification + + If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following lines to /etc/audit/audit.rules file, in order to capture events that modify account changes: - --w /etc/security/opasswd -p wa -k audit_rules_usergroup_modification - BP28(R73) - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 18 - 19 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 5.4.1.1 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - APO12.06 - APO13.01 - BAI03.05 - BAI08.02 - DSS01.03 - DSS01.04 - DSS02.02 - DSS02.04 - DSS02.07 - DSS03.01 - DSS03.05 - DSS05.02 - DSS05.03 - DSS05.04 - DSS05.05 - DSS05.07 - DSS06.03 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.1.7 - CCI-000018 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-000172 - CCI-001403 - CCI-001404 - CCI-001405 - CCI-001683 - CCI-001684 - CCI-001685 - CCI-001686 - CCI-002130 - CCI-002132 - CCI-002884 - 164.308(a)(1)(ii)(D) - 164.308(a)(3)(ii)(A) - 164.308(a)(5)(ii)(C) - 164.312(a)(2)(i) - 164.312(b) - 164.312(d) - 164.312(e) - 4.2.3.10 - 4.3.2.6.7 - 4.3.3.2.2 - 4.3.3.3.9 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.8 - 4.3.3.6.6 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.4.7 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 1.1 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.6 - SR 2.8 - SR 2.9 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 6.1 - SR 6.2 - SR 7.1 - SR 7.6 - A.11.2.6 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.14.2.7 - A.15.2.1 - A.15.2.2 - A.16.1.4 - A.16.1.5 - A.16.1.7 - A.6.1.2 - A.6.2.1 - A.6.2.2 - A.7.1.1 - A.9.1.2 - A.9.2.1 - A.9.2.2 - A.9.2.3 - A.9.2.4 - A.9.2.6 - A.9.3.1 - A.9.4.1 - A.9.4.2 - A.9.4.3 - A.9.4.4 - A.9.4.5 - CIP-004-6 R2.2.2 - CIP-004-6 R2.2.3 - CIP-007-3 R.1.3 - CIP-007-3 R5 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.3 - CIP-007-3 R5.2.1 - CIP-007-3 R5.2.3 - AC-2(4) - AU-2(d) - AU-12(c) - AC-6(9) - CM-6(a) - DE.AE-3 - DE.AE-5 - DE.CM-1 - DE.CM-3 - DE.CM-7 - ID.SC-4 - PR.AC-1 - PR.AC-3 - PR.AC-4 - PR.AC-6 - PR.PT-1 - PR.PT-4 - RS.AN-1 - RS.AN-4 - FAU_GEN.1.1.c - Req-10.2.5 - 10.2.1.5 - SRG-OS-000004-GPOS-00004 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000304-GPOS-00121 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000470-GPOS-00214 - SRG-OS-000471-GPOS-00215 - SRG-OS-000239-GPOS-00089 - SRG-OS-000240-GPOS-00090 - SRG-OS-000241-GPOS-00091 - SRG-OS-000303-GPOS-00120 - SRG-OS-000466-GPOS-00210 - SRG-OS-000476-GPOS-00221 - In addition to auditing new user and group accounts, these watches + + + -w /etc/security/opasswd -p wa -k audit_rules_usergroup_modification + + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 18 + 19 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 5.4.1.1 + APO10.01 + APO10.03 + APO10.04 + APO10.05 + APO11.04 + APO12.06 + APO13.01 + BAI03.05 + BAI08.02 + DSS01.03 + DSS01.04 + DSS02.02 + DSS02.04 + DSS02.07 + DSS03.01 + DSS03.05 + DSS05.02 + DSS05.03 + DSS05.04 + DSS05.05 + DSS05.07 + DSS06.03 + MEA01.01 + MEA01.02 + MEA01.03 + MEA01.04 + MEA01.05 + MEA02.01 + 3.1.7 + CCI-001403 + CCI-001404 + CCI-001405 + CCI-000172 + CCI-000130 + CCI-002130 + CCI-000135 + CCI-000169 + CCI-002884 + CCI-000018 + CCI-000015 + 164.308(a)(1)(ii)(D) + 164.308(a)(3)(ii)(A) + 164.308(a)(5)(ii)(C) + 164.312(a)(2)(i) + 164.312(b) + 164.312(d) + 164.312(e) + 4.2.3.10 + 4.3.2.6.7 + 4.3.3.2.2 + 4.3.3.3.9 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.8 + 4.3.3.6.6 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.4.7 + 4.3.4.5.6 + 4.3.4.5.7 + 4.3.4.5.8 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 1.1 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.6 + SR 2.8 + SR 2.9 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 6.1 + SR 6.2 + SR 7.1 + SR 7.6 + A.11.2.6 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.13.1.1 + A.13.2.1 + A.14.1.3 + A.14.2.7 + A.15.2.1 + A.15.2.2 + A.16.1.4 + A.16.1.5 + A.16.1.7 + A.6.1.2 + A.6.2.1 + A.6.2.2 + A.7.1.1 + A.9.1.2 + A.9.2.1 + A.9.2.2 + A.9.2.3 + A.9.2.4 + A.9.2.6 + A.9.3.1 + A.9.4.1 + A.9.4.2 + A.9.4.3 + A.9.4.4 + A.9.4.5 + CIP-004-6 R2.2.2 + CIP-004-6 R2.2.3 + CIP-007-3 R.1.3 + CIP-007-3 R5 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.3 + CIP-007-3 R5.2.1 + CIP-007-3 R5.2.3 + AC-2(4) + AU-2(d) + AU-12(c) + AC-6(9) + CM-6(a) + DE.AE-3 + DE.AE-5 + DE.CM-1 + DE.CM-3 + DE.CM-7 + ID.SC-4 + PR.AC-1 + PR.AC-3 + PR.AC-4 + PR.AC-6 + PR.PT-1 + PR.PT-4 + RS.AN-1 + RS.AN-4 + Req-10.2.5 + SRG-OS-000004-GPOS-00004 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000304-GPOS-00121 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000470-GPOS-00214 + SRG-OS-000471-GPOS-00215 + SRG-OS-000239-GPOS-00089 + SRG-OS-000240-GPOS-00090 + SRG-OS-000241-GPOS-00091 + SRG-OS-000303-GPOS-00120 + SRG-OS-000466-GPOS-00210 + SRG-OS-000476-GPOS-00221 + SRG-APP-000495-CTR-001235 + SRG-APP-000496-CTR-001240 + SRG-APP-000497-CTR-001245 + SRG-APP-000498-CTR-001250 + SRG-APP-000503-CTR-001275 + R73 + A.3.SEC-OL7 + 10.2.1.5 + 10.2.1 + 10.2 + OL09-00-000520 + SV-271531r1092482_rule + In addition to auditing new user and group accounts, these watches will alert the system administrator(s) to any modifications. Any unexpected -users, groups, or modifications should be investigated for legitimacy. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +users, groups, or modifications should be investigated for legitimacy. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' @@ -49307,7 +129467,7 @@ then if [ ! -e "$key_rule_file" ] then touch "$key_rule_file" - chmod 0640 "$key_rule_file" + chmod 0600 "$key_rule_file" fi files_to_inspect+=("$key_rule_file") fi @@ -49353,12 +129513,13 @@ done else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000520 - NIST-800-171-3.1.7 - NIST-800-53-AC-2(4) - NIST-800-53-AC-6(9) @@ -49366,6 +129527,8 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.5 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.5 - audit_rules_usergroup_modification_opasswd - low_complexity @@ -49382,9 +129545,10 @@ fi register: find_existing_watch_rules_d when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000520 - NIST-800-171-3.1.7 - NIST-800-53-AC-2(4) - NIST-800-53-AC-6(9) @@ -49392,6 +129556,8 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.5 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.5 - audit_rules_usergroup_modification_opasswd - low_complexity @@ -49408,11 +129574,12 @@ fi register: find_watch_key when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000520 - NIST-800-171-3.1.7 - NIST-800-53-AC-2(4) - NIST-800-53-AC-6(9) @@ -49420,6 +129587,8 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.5 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.5 - audit_rules_usergroup_modification_opasswd - low_complexity @@ -49435,11 +129604,12 @@ fi - /etc/audit/rules.d/audit_rules_usergroup_modification.rules when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_watch_key.matched is defined and find_watch_key.matched == 0 and find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000520 - NIST-800-171-3.1.7 - NIST-800-53-AC-2(4) - NIST-800-53-AC-6(9) @@ -49447,6 +129617,8 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.5 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.5 - audit_rules_usergroup_modification_opasswd - low_complexity @@ -49461,11 +129633,12 @@ fi - '{{ find_watch_key.files | map(attribute=''path'') | list | first }}' when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_watch_key.matched is defined and find_watch_key.matched > 0 and find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000520 - NIST-800-171-3.1.7 - NIST-800-53-AC-2(4) - NIST-800-53-AC-6(9) @@ -49473,6 +129646,8 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.5 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.5 - audit_rules_usergroup_modification_opasswd - low_complexity @@ -49486,14 +129661,15 @@ fi path: '{{ all_files[0] }}' line: -w /etc/security/opasswd -p wa -k audit_rules_usergroup_modification create: true - mode: '0640' + mode: '0600' when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000520 - NIST-800-171-3.1.7 - NIST-800-53-AC-2(4) - NIST-800-53-AC-6(9) @@ -49501,6 +129677,8 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.5 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.5 - audit_rules_usergroup_modification_opasswd - low_complexity @@ -49517,9 +129695,10 @@ fi register: find_existing_watch_audit_rules when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000520 - NIST-800-171-3.1.7 - NIST-800-53-AC-2(4) - NIST-800-53-AC-6(9) @@ -49527,6 +129706,8 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.5 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.5 - audit_rules_usergroup_modification_opasswd - low_complexity @@ -49541,14 +129722,15 @@ fi state: present dest: /etc/audit/audit.rules create: true - mode: '0640' + mode: '0600' when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_existing_watch_audit_rules.matched is defined and find_existing_watch_audit_rules.matched == 0 tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000520 - NIST-800-171-3.1.7 - NIST-800-53-AC-2(4) - NIST-800-53-AC-6(9) @@ -49556,6 +129738,8 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.5 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.5 - audit_rules_usergroup_modification_opasswd - low_complexity @@ -49563,232 +129747,239 @@ fi - medium_severity - reboot_required - restrict_strategy - - - - - - - - - - Record Events that Modify User/Group Information - /etc/passwd - If the auditd daemon is configured to use the + + + + + + + + + + Record Events that Modify User/Group Information - /etc/passwd + If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following lines to a file with suffix .rules in the directory /etc/audit/rules.d, in order to capture events that modify account changes: - --w /etc/passwd -p wa -k audit_rules_usergroup_modification - + + + -w /etc/passwd -p wa -k audit_rules_usergroup_modification + + If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following lines to /etc/audit/audit.rules file, in order to capture events that modify account changes: - --w /etc/passwd -p wa -k audit_rules_usergroup_modification - BP28(R73) - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 18 - 19 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 5.4.1.1 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - APO12.06 - APO13.01 - BAI03.05 - BAI08.02 - DSS01.03 - DSS01.04 - DSS02.02 - DSS02.04 - DSS02.07 - DSS03.01 - DSS03.05 - DSS05.02 - DSS05.03 - DSS05.04 - DSS05.05 - DSS05.07 - DSS06.03 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.1.7 - CCI-000018 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-000172 - CCI-001403 - CCI-001404 - CCI-001405 - CCI-001683 - CCI-001684 - CCI-001685 - CCI-001686 - CCI-002130 - CCI-002132 - CCI-002884 - 164.308(a)(1)(ii)(D) - 164.308(a)(3)(ii)(A) - 164.308(a)(5)(ii)(C) - 164.312(a)(2)(i) - 164.312(b) - 164.312(d) - 164.312(e) - 4.2.3.10 - 4.3.2.6.7 - 4.3.3.2.2 - 4.3.3.3.9 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.8 - 4.3.3.6.6 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.4.7 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 1.1 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.6 - SR 2.8 - SR 2.9 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 6.1 - SR 6.2 - SR 7.1 - SR 7.6 - A.11.2.6 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.14.2.7 - A.15.2.1 - A.15.2.2 - A.16.1.4 - A.16.1.5 - A.16.1.7 - A.6.1.2 - A.6.2.1 - A.6.2.2 - A.7.1.1 - A.9.1.2 - A.9.2.1 - A.9.2.2 - A.9.2.3 - A.9.2.4 - A.9.2.6 - A.9.3.1 - A.9.4.1 - A.9.4.2 - A.9.4.3 - A.9.4.4 - A.9.4.5 - CIP-004-6 R2.2.2 - CIP-004-6 R2.2.3 - CIP-007-3 R.1.3 - CIP-007-3 R5 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.3 - CIP-007-3 R5.2.1 - CIP-007-3 R5.2.3 - AC-2(4) - AU-2(d) - AU-12(c) - AC-6(9) - CM-6(a) - DE.AE-3 - DE.AE-5 - DE.CM-1 - DE.CM-3 - DE.CM-7 - ID.SC-4 - PR.AC-1 - PR.AC-3 - PR.AC-4 - PR.AC-6 - PR.PT-1 - PR.PT-4 - RS.AN-1 - RS.AN-4 - FAU_GEN.1.1.c - Req-10.2.5 - 10.2.1.5 - SRG-OS-000004-GPOS-00004 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000304-GPOS-00121 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000470-GPOS-00214 - SRG-OS-000471-GPOS-00215 - SRG-OS-000239-GPOS-00089 - SRG-OS-000240-GPOS-00090 - SRG-OS-000241-GPOS-00091 - SRG-OS-000303-GPOS-00120 - SRG-OS-000304-GPOS-00121 - SRG-OS-000466-GPOS-00210 - SRG-OS-000476-GPOS-00221 - SRG-OS-000274-GPOS-00104 - SRG-OS-000275-GPOS-00105 - SRG-OS-000276-GPOS-00106 - SRG-OS-000277-GPOS-00107 - In addition to auditing new user and group accounts, these watches + + + -w /etc/passwd -p wa -k audit_rules_usergroup_modification + + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 18 + 19 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 5.4.1.1 + APO10.01 + APO10.03 + APO10.04 + APO10.05 + APO11.04 + APO12.06 + APO13.01 + BAI03.05 + BAI08.02 + DSS01.03 + DSS01.04 + DSS02.02 + DSS02.04 + DSS02.07 + DSS03.01 + DSS03.05 + DSS05.02 + DSS05.03 + DSS05.04 + DSS05.05 + DSS05.07 + DSS06.03 + MEA01.01 + MEA01.02 + MEA01.03 + MEA01.04 + MEA01.05 + MEA02.01 + 3.1.7 + CCI-001403 + CCI-001404 + CCI-001405 + CCI-000172 + CCI-000130 + CCI-002130 + CCI-000135 + CCI-000169 + CCI-002884 + CCI-000018 + CCI-000015 + 164.308(a)(1)(ii)(D) + 164.308(a)(3)(ii)(A) + 164.308(a)(5)(ii)(C) + 164.312(a)(2)(i) + 164.312(b) + 164.312(d) + 164.312(e) + 4.2.3.10 + 4.3.2.6.7 + 4.3.3.2.2 + 4.3.3.3.9 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.8 + 4.3.3.6.6 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.4.7 + 4.3.4.5.6 + 4.3.4.5.7 + 4.3.4.5.8 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 1.1 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.6 + SR 2.8 + SR 2.9 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 6.1 + SR 6.2 + SR 7.1 + SR 7.6 + A.11.2.6 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.13.1.1 + A.13.2.1 + A.14.1.3 + A.14.2.7 + A.15.2.1 + A.15.2.2 + A.16.1.4 + A.16.1.5 + A.16.1.7 + A.6.1.2 + A.6.2.1 + A.6.2.2 + A.7.1.1 + A.9.1.2 + A.9.2.1 + A.9.2.2 + A.9.2.3 + A.9.2.4 + A.9.2.6 + A.9.3.1 + A.9.4.1 + A.9.4.2 + A.9.4.3 + A.9.4.4 + A.9.4.5 + CIP-004-6 R2.2.2 + CIP-004-6 R2.2.3 + CIP-007-3 R.1.3 + CIP-007-3 R5 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.3 + CIP-007-3 R5.2.1 + CIP-007-3 R5.2.3 + AC-2(4) + AU-2(d) + AU-12(c) + AC-6(9) + CM-6(a) + DE.AE-3 + DE.AE-5 + DE.CM-1 + DE.CM-3 + DE.CM-7 + ID.SC-4 + PR.AC-1 + PR.AC-3 + PR.AC-4 + PR.AC-6 + PR.PT-1 + PR.PT-4 + RS.AN-1 + RS.AN-4 + Req-10.2.5 + SRG-OS-000004-GPOS-00004 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000304-GPOS-00121 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000470-GPOS-00214 + SRG-OS-000471-GPOS-00215 + SRG-OS-000239-GPOS-00089 + SRG-OS-000240-GPOS-00090 + SRG-OS-000241-GPOS-00091 + SRG-OS-000303-GPOS-00120 + SRG-OS-000304-GPOS-00121 + SRG-OS-000466-GPOS-00210 + SRG-OS-000476-GPOS-00221 + SRG-OS-000274-GPOS-00104 + SRG-OS-000275-GPOS-00105 + SRG-OS-000276-GPOS-00106 + SRG-OS-000277-GPOS-00107 + SRG-APP-000495-CTR-001235 + SRG-APP-000499-CTR-001255 + SRG-APP-000503-CTR-001275 + R73 + A.3.SEC-OL7 + 10.2.1.5 + 10.2.1 + 10.2 + OL09-00-000525 + SV-271532r1092484_rule + In addition to auditing new user and group accounts, these watches will alert the system administrator(s) to any modifications. Any unexpected -users, groups, or modifications should be investigated for legitimacy. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +users, groups, or modifications should be investigated for legitimacy. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' @@ -49882,7 +130073,7 @@ then if [ ! -e "$key_rule_file" ] then touch "$key_rule_file" - chmod 0640 "$key_rule_file" + chmod 0600 "$key_rule_file" fi files_to_inspect+=("$key_rule_file") fi @@ -49928,12 +130119,13 @@ done else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000525 - NIST-800-171-3.1.7 - NIST-800-53-AC-2(4) - NIST-800-53-AC-6(9) @@ -49941,6 +130133,8 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.5 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.5 - audit_rules_usergroup_modification_passwd - low_complexity @@ -49957,9 +130151,10 @@ fi register: find_existing_watch_rules_d when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000525 - NIST-800-171-3.1.7 - NIST-800-53-AC-2(4) - NIST-800-53-AC-6(9) @@ -49967,6 +130162,8 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.5 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.5 - audit_rules_usergroup_modification_passwd - low_complexity @@ -49983,11 +130180,12 @@ fi register: find_watch_key when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000525 - NIST-800-171-3.1.7 - NIST-800-53-AC-2(4) - NIST-800-53-AC-6(9) @@ -49995,6 +130193,8 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.5 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.5 - audit_rules_usergroup_modification_passwd - low_complexity @@ -50010,11 +130210,12 @@ fi - /etc/audit/rules.d/audit_rules_usergroup_modification.rules when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_watch_key.matched is defined and find_watch_key.matched == 0 and find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000525 - NIST-800-171-3.1.7 - NIST-800-53-AC-2(4) - NIST-800-53-AC-6(9) @@ -50022,6 +130223,8 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.5 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.5 - audit_rules_usergroup_modification_passwd - low_complexity @@ -50036,11 +130239,12 @@ fi - '{{ find_watch_key.files | map(attribute=''path'') | list | first }}' when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_watch_key.matched is defined and find_watch_key.matched > 0 and find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000525 - NIST-800-171-3.1.7 - NIST-800-53-AC-2(4) - NIST-800-53-AC-6(9) @@ -50048,6 +130252,8 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.5 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.5 - audit_rules_usergroup_modification_passwd - low_complexity @@ -50061,14 +130267,15 @@ fi path: '{{ all_files[0] }}' line: -w /etc/passwd -p wa -k audit_rules_usergroup_modification create: true - mode: '0640' + mode: '0600' when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000525 - NIST-800-171-3.1.7 - NIST-800-53-AC-2(4) - NIST-800-53-AC-6(9) @@ -50076,6 +130283,8 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.5 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.5 - audit_rules_usergroup_modification_passwd - low_complexity @@ -50092,9 +130301,10 @@ fi register: find_existing_watch_audit_rules when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000525 - NIST-800-171-3.1.7 - NIST-800-53-AC-2(4) - NIST-800-53-AC-6(9) @@ -50102,6 +130312,8 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.5 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.5 - audit_rules_usergroup_modification_passwd - low_complexity @@ -50116,14 +130328,15 @@ fi state: present dest: /etc/audit/audit.rules create: true - mode: '0640' + mode: '0600' when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_existing_watch_audit_rules.matched is defined and find_existing_watch_audit_rules.matched == 0 tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000525 - NIST-800-171-3.1.7 - NIST-800-53-AC-2(4) - NIST-800-53-AC-6(9) @@ -50131,6 +130344,8 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.5 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.5 - audit_rules_usergroup_modification_passwd - low_complexity @@ -50138,227 +130353,234 @@ fi - medium_severity - reboot_required - restrict_strategy - - - - - - - - - - Record Events that Modify User/Group Information - /etc/shadow - If the auditd daemon is configured to use the + + + + + + + + + + Record Events that Modify User/Group Information - /etc/shadow + If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following lines to a file with suffix .rules in the directory /etc/audit/rules.d, in order to capture events that modify account changes: - --w /etc/shadow -p wa -k audit_rules_usergroup_modification - + + + -w /etc/shadow -p wa -k audit_rules_usergroup_modification + + If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following lines to /etc/audit/audit.rules file, in order to capture events that modify account changes: - --w /etc/shadow -p wa -k audit_rules_usergroup_modification - BP28(R73) - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 18 - 19 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 5.4.1.1 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - APO12.06 - APO13.01 - BAI03.05 - BAI08.02 - DSS01.03 - DSS01.04 - DSS02.02 - DSS02.04 - DSS02.07 - DSS03.01 - DSS03.05 - DSS05.02 - DSS05.03 - DSS05.04 - DSS05.05 - DSS05.07 - DSS06.03 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.1.7 - CCI-000018 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-000172 - CCI-001403 - CCI-001404 - CCI-001405 - CCI-001683 - CCI-001684 - CCI-001685 - CCI-001686 - CCI-002130 - CCI-002132 - CCI-002884 - 164.308(a)(1)(ii)(D) - 164.308(a)(3)(ii)(A) - 164.308(a)(5)(ii)(C) - 164.312(a)(2)(i) - 164.312(b) - 164.312(d) - 164.312(e) - 4.2.3.10 - 4.3.2.6.7 - 4.3.3.2.2 - 4.3.3.3.9 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.8 - 4.3.3.6.6 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.4.7 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 1.1 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.6 - SR 2.8 - SR 2.9 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 6.1 - SR 6.2 - SR 7.1 - SR 7.6 - A.11.2.6 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.14.2.7 - A.15.2.1 - A.15.2.2 - A.16.1.4 - A.16.1.5 - A.16.1.7 - A.6.1.2 - A.6.2.1 - A.6.2.2 - A.7.1.1 - A.9.1.2 - A.9.2.1 - A.9.2.2 - A.9.2.3 - A.9.2.4 - A.9.2.6 - A.9.3.1 - A.9.4.1 - A.9.4.2 - A.9.4.3 - A.9.4.4 - A.9.4.5 - CIP-004-6 R2.2.2 - CIP-004-6 R2.2.3 - CIP-007-3 R.1.3 - CIP-007-3 R5 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.3 - CIP-007-3 R5.2.1 - CIP-007-3 R5.2.3 - AC-2(4) - AU-2(d) - AU-12(c) - AC-6(9) - CM-6(a) - DE.AE-3 - DE.AE-5 - DE.CM-1 - DE.CM-3 - DE.CM-7 - ID.SC-4 - PR.AC-1 - PR.AC-3 - PR.AC-4 - PR.AC-6 - PR.PT-1 - PR.PT-4 - RS.AN-1 - RS.AN-4 - FAU_GEN.1.1.c - Req-10.2.5 - 10.2.1.5 - SRG-OS-000004-GPOS-00004 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000304-GPOS-00121 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000470-GPOS-00214 - SRG-OS-000471-GPOS-00215 - SRG-OS-000239-GPOS-00089 - SRG-OS-000240-GPOS-00090 - SRG-OS-000241-GPOS-00091 - SRG-OS-000303-GPOS-00120 - SRG-OS-000466-GPOS-00210 - SRG-OS-000476-GPOS-00221 - In addition to auditing new user and group accounts, these watches + + + -w /etc/shadow -p wa -k audit_rules_usergroup_modification + + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 18 + 19 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 5.4.1.1 + APO10.01 + APO10.03 + APO10.04 + APO10.05 + APO11.04 + APO12.06 + APO13.01 + BAI03.05 + BAI08.02 + DSS01.03 + DSS01.04 + DSS02.02 + DSS02.04 + DSS02.07 + DSS03.01 + DSS03.05 + DSS05.02 + DSS05.03 + DSS05.04 + DSS05.05 + DSS05.07 + DSS06.03 + MEA01.01 + MEA01.02 + MEA01.03 + MEA01.04 + MEA01.05 + MEA02.01 + 3.1.7 + CCI-001403 + CCI-001404 + CCI-001405 + CCI-000172 + CCI-000130 + CCI-002130 + CCI-000135 + CCI-000169 + CCI-002884 + CCI-000018 + CCI-000015 + 164.308(a)(1)(ii)(D) + 164.308(a)(3)(ii)(A) + 164.308(a)(5)(ii)(C) + 164.312(a)(2)(i) + 164.312(b) + 164.312(d) + 164.312(e) + 4.2.3.10 + 4.3.2.6.7 + 4.3.3.2.2 + 4.3.3.3.9 + 4.3.3.5.1 + 4.3.3.5.2 + 4.3.3.5.8 + 4.3.3.6.6 + 4.3.3.7.2 + 4.3.3.7.3 + 4.3.3.7.4 + 4.3.4.4.7 + 4.3.4.5.6 + 4.3.4.5.7 + 4.3.4.5.8 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 1.1 + SR 1.13 + SR 1.2 + SR 1.3 + SR 1.4 + SR 1.5 + SR 1.7 + SR 1.8 + SR 1.9 + SR 2.1 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.6 + SR 2.8 + SR 2.9 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 6.1 + SR 6.2 + SR 7.1 + SR 7.6 + A.11.2.6 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.13.1.1 + A.13.2.1 + A.14.1.3 + A.14.2.7 + A.15.2.1 + A.15.2.2 + A.16.1.4 + A.16.1.5 + A.16.1.7 + A.6.1.2 + A.6.2.1 + A.6.2.2 + A.7.1.1 + A.9.1.2 + A.9.2.1 + A.9.2.2 + A.9.2.3 + A.9.2.4 + A.9.2.6 + A.9.3.1 + A.9.4.1 + A.9.4.2 + A.9.4.3 + A.9.4.4 + A.9.4.5 + CIP-004-6 R2.2.2 + CIP-004-6 R2.2.3 + CIP-007-3 R.1.3 + CIP-007-3 R5 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.3 + CIP-007-3 R5.2.1 + CIP-007-3 R5.2.3 + AC-2(4) + AU-2(d) + AU-12(c) + AC-6(9) + CM-6(a) + DE.AE-3 + DE.AE-5 + DE.CM-1 + DE.CM-3 + DE.CM-7 + ID.SC-4 + PR.AC-1 + PR.AC-3 + PR.AC-4 + PR.AC-6 + PR.PT-1 + PR.PT-4 + RS.AN-1 + RS.AN-4 + Req-10.2.5 + SRG-OS-000004-GPOS-00004 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000304-GPOS-00121 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000470-GPOS-00214 + SRG-OS-000471-GPOS-00215 + SRG-OS-000239-GPOS-00089 + SRG-OS-000240-GPOS-00090 + SRG-OS-000241-GPOS-00091 + SRG-OS-000303-GPOS-00120 + SRG-OS-000466-GPOS-00210 + SRG-OS-000476-GPOS-00221 + SRG-APP-000495-CTR-001235 + SRG-APP-000499-CTR-001255 + SRG-APP-000503-CTR-001275 + R73 + A.3.SEC-OL7 + 10.2.1.5 + 10.2.1 + 10.2 + OL09-00-000530 + SV-271533r1092486_rule + In addition to auditing new user and group accounts, these watches will alert the system administrator(s) to any modifications. Any unexpected -users, groups, or modifications should be investigated for legitimacy. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +users, groups, or modifications should be investigated for legitimacy. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' @@ -50452,7 +130674,7 @@ then if [ ! -e "$key_rule_file" ] then touch "$key_rule_file" - chmod 0640 "$key_rule_file" + chmod 0600 "$key_rule_file" fi files_to_inspect+=("$key_rule_file") fi @@ -50498,12 +130720,13 @@ done else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000530 - NIST-800-171-3.1.7 - NIST-800-53-AC-2(4) - NIST-800-53-AC-6(9) @@ -50511,6 +130734,8 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.5 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.5 - audit_rules_usergroup_modification_shadow - low_complexity @@ -50527,9 +130752,10 @@ fi register: find_existing_watch_rules_d when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000530 - NIST-800-171-3.1.7 - NIST-800-53-AC-2(4) - NIST-800-53-AC-6(9) @@ -50537,6 +130763,8 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.5 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.5 - audit_rules_usergroup_modification_shadow - low_complexity @@ -50553,11 +130781,12 @@ fi register: find_watch_key when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000530 - NIST-800-171-3.1.7 - NIST-800-53-AC-2(4) - NIST-800-53-AC-6(9) @@ -50565,6 +130794,8 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.5 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.5 - audit_rules_usergroup_modification_shadow - low_complexity @@ -50580,11 +130811,12 @@ fi - /etc/audit/rules.d/audit_rules_usergroup_modification.rules when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_watch_key.matched is defined and find_watch_key.matched == 0 and find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000530 - NIST-800-171-3.1.7 - NIST-800-53-AC-2(4) - NIST-800-53-AC-6(9) @@ -50592,6 +130824,8 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.5 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.5 - audit_rules_usergroup_modification_shadow - low_complexity @@ -50606,11 +130840,12 @@ fi - '{{ find_watch_key.files | map(attribute=''path'') | list | first }}' when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_watch_key.matched is defined and find_watch_key.matched > 0 and find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000530 - NIST-800-171-3.1.7 - NIST-800-53-AC-2(4) - NIST-800-53-AC-6(9) @@ -50618,6 +130853,8 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.5 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.5 - audit_rules_usergroup_modification_shadow - low_complexity @@ -50631,14 +130868,15 @@ fi path: '{{ all_files[0] }}' line: -w /etc/shadow -p wa -k audit_rules_usergroup_modification create: true - mode: '0640' + mode: '0600' when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000530 - NIST-800-171-3.1.7 - NIST-800-53-AC-2(4) - NIST-800-53-AC-6(9) @@ -50646,6 +130884,8 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.5 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.5 - audit_rules_usergroup_modification_shadow - low_complexity @@ -50662,9 +130902,10 @@ fi register: find_existing_watch_audit_rules when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000530 - NIST-800-171-3.1.7 - NIST-800-53-AC-2(4) - NIST-800-53-AC-6(9) @@ -50672,6 +130913,8 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.5 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.5 - audit_rules_usergroup_modification_shadow - low_complexity @@ -50686,14 +130929,15 @@ fi state: present dest: /etc/audit/audit.rules create: true - mode: '0640' + mode: '0600' when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_existing_watch_audit_rules.matched is defined and find_existing_watch_audit_rules.matched == 0 tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000530 - NIST-800-171-3.1.7 - NIST-800-53-AC-2(4) - NIST-800-53-AC-6(9) @@ -50701,6 +130945,8 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.5 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.5 - audit_rules_usergroup_modification_shadow - low_complexity @@ -50708,17 +130954,385 @@ fi - medium_severity - reboot_required - restrict_strategy - - - - - - - - - - Record Access Events to Audit Log Directory - The audit system should collect access events to read audit log directory. + + + + + + + + + + Record Attempts to perform maintenance activities + The Oracle Linux 9 operating system must generate audit records for +privileged activities, nonlocal maintenance, diagnostic sessions and +other system-level access. + +Verify the operating system audits activities performed during nonlocal +maintenance and diagnostic sessions. Run the following command: +$ sudo auditctl -l | grep sudo.log +-w /var/log/sudo.log -p wa -k maintenance + + CCI-000172 + CCI-002884 + Req-10.2.2 + Req-10.2.5.b + SRG-OS-000392-GPOS-00172 + SRG-OS-000471-GPOS-00215 + R73 + A.3.SEC-OL7 + 10.2.1.3 + 10.2.1 + 10.2 + If events associated with nonlocal administrative access or diagnostic +sessions are not logged, a major tool for assessing and investigating +attacks would not be available. +This requirement addresses auditing-related issues associated with +maintenance tools used specifically for diagnostic and repair actions +on organizational information systems. +Nonlocal maintenance and diagnostic activities are those activities +conducted by individuals communicating through a network, either an +external network (e.g., the internet) or an internal network. Local +maintenance and diagnostic activities are those activities carried +out by individuals physically present at the information system or +information system component and not communicating across a network +connection. +This requirement applies to hardware/software diagnostic test +equipment or tools. This requirement does not cover hardware/software +components that may support information system maintenance, yet are a +part of the system, for example, the software implementing "ping," +"ls," "ipconfig," or the hardware and software implementing the +monitoring port of an Ethernet switch. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Perform the remediation for both possible tools: 'auditctl' and 'augenrules' + + +# Create a list of audit *.rules files that should be inspected for presence and correctness +# of a particular audit rule. The scheme is as follows: +# +# ----------------------------------------------------------------------------------------- +# Tool used to load audit rules | Rule already defined | Audit rules file to inspect | +# ----------------------------------------------------------------------------------------- +# auditctl | Doesn't matter | /etc/audit/audit.rules | +# ----------------------------------------------------------------------------------------- +# augenrules | Yes | /etc/audit/rules.d/*.rules | +# augenrules | No | /etc/audit/rules.d/$key.rules | +# ----------------------------------------------------------------------------------------- +files_to_inspect=() + + +# If the audit tool is 'auditctl', then add '/etc/audit/audit.rules' +# into the list of files to be inspected +files_to_inspect+=('/etc/audit/audit.rules') + +# Finally perform the inspection and possible subsequent audit rule +# correction for each of the files previously identified for inspection +for audit_rules_file in "${files_to_inspect[@]}" +do + # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/var/log/sudo.log" "$audit_rules_file" + then + # Rule is found => verify yet if existing rule definition contains + # all of the required access type bits + + # Define BRE whitespace class shortcut + sp="[[:space:]]" + # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/var/log/sudo.log $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array + # (to check bit's presence for one bit at a time) + for access_bit in $(echo "wa" | grep -o .) + do + # For each from the required access bits (e.g. 'w', 'a') check + # if they are already present in current access bits for rule. + # If not, append that bit at the end + if ! grep -q "$access_bit" <<< "$current_access_bits" + then + # Concatenate the existing mask with the missing bit + current_access_bits="$current_access_bits$access_bit" + fi + done + # Propagate the updated rule's access bits (original + the required + # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/var/log/sudo.log$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else + # Rule isn't present yet. Append it at the end of $audit_rules_file file + # with proper key + + echo "-w /var/log/sudo.log -p wa -k logins" >> "$audit_rules_file" + fi +done +# Create a list of audit *.rules files that should be inspected for presence and correctness +# of a particular audit rule. The scheme is as follows: +# +# ----------------------------------------------------------------------------------------- +# Tool used to load audit rules | Rule already defined | Audit rules file to inspect | +# ----------------------------------------------------------------------------------------- +# auditctl | Doesn't matter | /etc/audit/audit.rules | +# ----------------------------------------------------------------------------------------- +# augenrules | Yes | /etc/audit/rules.d/*.rules | +# augenrules | No | /etc/audit/rules.d/$key.rules | +# ----------------------------------------------------------------------------------------- +files_to_inspect=() + +# If the audit is 'augenrules', then check if rule is already defined +# If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection. +# If rule isn't defined, add '/etc/audit/rules.d/logins.rules' to list of files for inspection. +readarray -t matches < <(grep -HP "[\s]*-w[\s]+/var/log/sudo.log" /etc/audit/rules.d/*.rules) + +# For each of the matched entries +for match in "${matches[@]}" +do + # Extract filepath from the match + rulesd_audit_file=$(echo $match | cut -f1 -d ':') + # Append that path into list of files for inspection + files_to_inspect+=("$rulesd_audit_file") +done +# Case when particular audit rule isn't defined yet +if [ "${#files_to_inspect[@]}" -eq "0" ] +then + # Append '/etc/audit/rules.d/logins.rules' into list of files for inspection + key_rule_file="/etc/audit/rules.d/logins.rules" + # If the logins.rules file doesn't exist yet, create it with correct permissions + if [ ! -e "$key_rule_file" ] + then + touch "$key_rule_file" + chmod 0600 "$key_rule_file" + fi + files_to_inspect+=("$key_rule_file") +fi + +# Finally perform the inspection and possible subsequent audit rule +# correction for each of the files previously identified for inspection +for audit_rules_file in "${files_to_inspect[@]}" +do + # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/var/log/sudo.log" "$audit_rules_file" + then + # Rule is found => verify yet if existing rule definition contains + # all of the required access type bits + + # Define BRE whitespace class shortcut + sp="[[:space:]]" + # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/var/log/sudo.log $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array + # (to check bit's presence for one bit at a time) + for access_bit in $(echo "wa" | grep -o .) + do + # For each from the required access bits (e.g. 'w', 'a') check + # if they are already present in current access bits for rule. + # If not, append that bit at the end + if ! grep -q "$access_bit" <<< "$current_access_bits" + then + # Concatenate the existing mask with the missing bit + current_access_bits="$current_access_bits$access_bit" + fi + done + # Propagate the updated rule's access bits (original + the required + # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/var/log/sudo.log$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else + # Rule isn't present yet. Append it at the end of $audit_rules_file file + # with proper key + + echo "-w /var/log/sudo.log -p wa -k logins" >> "$audit_rules_file" + fi +done + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - PCI-DSS-Req-10.2.2 + - PCI-DSS-Req-10.2.5.b + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 + - PCI-DSSv4-10.2.1.3 + - audit_sudo_log_events + - low_complexity + - low_disruption + - medium_severity + - reboot_required + - restrict_strategy + +- name: Check if watch rule for /var/log/sudo.log already exists in /etc/audit/rules.d/ + find: + paths: /etc/audit/rules.d + contains: ^\s*-w\s+/var/log/sudo.log\s+-p\s+wa(\s|$)+ + patterns: '*.rules' + register: find_existing_watch_rules_d + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - PCI-DSS-Req-10.2.2 + - PCI-DSS-Req-10.2.5.b + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 + - PCI-DSSv4-10.2.1.3 + - audit_sudo_log_events + - low_complexity + - low_disruption + - medium_severity + - reboot_required + - restrict_strategy + +- name: Search /etc/audit/rules.d for other rules with specified key logins + find: + paths: /etc/audit/rules.d + contains: ^.*(?:-F key=|-k\s+)logins$ + patterns: '*.rules' + register: find_watch_key + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched + == 0 + tags: + - PCI-DSS-Req-10.2.2 + - PCI-DSS-Req-10.2.5.b + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 + - PCI-DSSv4-10.2.1.3 + - audit_sudo_log_events + - low_complexity + - low_disruption + - medium_severity + - reboot_required + - restrict_strategy + +- name: Use /etc/audit/rules.d/logins.rules as the recipient for the rule + set_fact: + all_files: + - /etc/audit/rules.d/logins.rules + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_watch_key.matched is defined and find_watch_key.matched == 0 and find_existing_watch_rules_d.matched + is defined and find_existing_watch_rules_d.matched == 0 + tags: + - PCI-DSS-Req-10.2.2 + - PCI-DSS-Req-10.2.5.b + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 + - PCI-DSSv4-10.2.1.3 + - audit_sudo_log_events + - low_complexity + - low_disruption + - medium_severity + - reboot_required + - restrict_strategy + +- name: Use matched file as the recipient for the rule + set_fact: + all_files: + - '{{ find_watch_key.files | map(attribute=''path'') | list | first }}' + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_watch_key.matched is defined and find_watch_key.matched > 0 and find_existing_watch_rules_d.matched + is defined and find_existing_watch_rules_d.matched == 0 + tags: + - PCI-DSS-Req-10.2.2 + - PCI-DSS-Req-10.2.5.b + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 + - PCI-DSSv4-10.2.1.3 + - audit_sudo_log_events + - low_complexity + - low_disruption + - medium_severity + - reboot_required + - restrict_strategy + +- name: Add watch rule for /var/log/sudo.log in /etc/audit/rules.d/ + lineinfile: + path: '{{ all_files[0] }}' + line: -w /var/log/sudo.log -p wa -k logins + create: true + mode: '0600' + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched + == 0 + tags: + - PCI-DSS-Req-10.2.2 + - PCI-DSS-Req-10.2.5.b + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 + - PCI-DSSv4-10.2.1.3 + - audit_sudo_log_events + - low_complexity + - low_disruption + - medium_severity + - reboot_required + - restrict_strategy + +- name: Check if watch rule for /var/log/sudo.log already exists in /etc/audit/audit.rules + find: + paths: /etc/audit/ + contains: ^\s*-w\s+/var/log/sudo.log\s+-p\s+wa(\s|$)+ + patterns: audit.rules + register: find_existing_watch_audit_rules + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - PCI-DSS-Req-10.2.2 + - PCI-DSS-Req-10.2.5.b + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 + - PCI-DSSv4-10.2.1.3 + - audit_sudo_log_events + - low_complexity + - low_disruption + - medium_severity + - reboot_required + - restrict_strategy + +- name: Add watch rule for /var/log/sudo.log in /etc/audit/audit.rules + lineinfile: + line: -w /var/log/sudo.log -p wa -k logins + state: present + dest: /etc/audit/audit.rules + create: true + mode: '0600' + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_existing_watch_audit_rules.matched is defined and find_existing_watch_audit_rules.matched + == 0 + tags: + - PCI-DSS-Req-10.2.2 + - PCI-DSS-Req-10.2.5.b + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 + - PCI-DSSv4-10.2.1.3 + - audit_sudo_log_events + - low_complexity + - low_disruption + - medium_severity + - reboot_required + - restrict_strategy + + + + + + + + + + Record Access Events to Audit Log Directory + The audit system should collect access events to read audit log directory. The following audit rule will assure that access to audit log directory are collected. -a always,exit -F dir=/var/log/audit/ -F perm=r -F auid>=1000 -F auid!=unset -F key=access-audit-trail @@ -50728,17 +131342,17 @@ rule to a file with suffix .rules in the directory /etc/audit/rules.d. If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the rule to -/etc/audit/audit.rules file. - AU-2(d) - AU-12(c) - AC-6(9) - CM-6(a) - FAU_GEN.1.1.c - Attempts to read the logs should be recorded, suspicious access to audit log files could be an indicator of malicious activity on a system. -Auditing these events could serve as evidence of potential system compromise.' - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +/etc/audit/audit.rules file. + AU-2(d) + AU-12(c) + AC-6(9) + CM-6(a) + 10.3.1 + 10.3 + Attempts to read the logs should be recorded, suspicious access to audit log files could be an indicator of malicious activity on a system. +Auditing these events could serve as evidence of potential system compromise.' + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then ACTION_ARCH_FILTERS="-a always,exit" OTHER_FILTERS="-F dir=/var/log/audit/ -F perm=r" @@ -50776,7 +131390,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -50792,7 +131405,7 @@ then if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -50884,7 +131497,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -50937,7 +131550,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -51031,7 +131643,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -51058,8 +131670,8 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: @@ -51067,6 +131679,8 @@ fi - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) + - PCI-DSSv4-10.3 + - PCI-DSSv4-10.3.1 - directory_access_var_log_audit - low_complexity - low_disruption @@ -51136,6 +131750,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -51144,7 +131759,7 @@ fi line: -a always,exit{{ syscalls | join(',') }} -F dir=/var/log/audit/ -F perm=r -F auid>=1000 -F auid!=unset -F key=access-audit-trail create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -51181,6 +131796,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -51189,143 +131805,147 @@ fi line: -a always,exit{{ syscalls | join(',') }} -F dir=/var/log/audit/ -F perm=r -F auid>=1000 -F auid!=unset -F key=access-audit-trail create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AC-6(9) - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) + - PCI-DSSv4-10.3 + - PCI-DSSv4-10.3.1 - directory_access_var_log_audit - low_complexity - low_disruption - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - System Audit Directories Must Be Group Owned By Root - All audit directories must be group owned by root user. By default, the path for audit log is /var/log/audit/. + + + + + + + + + + System Audit Directories Must Be Group Owned By Root + All audit directories must be group owned by root user. By default, the path for audit log is /var/log/audit/. To properly set the group owner of /var/log/audit, run the command: $ sudo chgrp root /var/log/audit If log_group in /etc/audit/auditd.conf is set to a group other than the root -group account, change the group ownership of the audit directories to this specific group. - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 18 - 19 - 3 - 4 - 5 - 6 - 7 - 8 - 5.4.1.1 - APO01.06 - APO11.04 - APO12.06 - BAI03.05 - BAI08.02 - DSS02.02 - DSS02.04 - DSS02.07 - DSS03.01 - DSS05.04 - DSS05.07 - DSS06.02 - MEA02.01 - 3.3.1 - CCI-000162 - CCI-000163 - CCI-000164 - CCI-001314 - 4.2.3.10 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.3.7.3 - 4.3.4.4.7 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 2.1 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.8 - SR 2.9 - SR 5.2 - SR 6.1 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.16.1.4 - A.16.1.5 - A.16.1.7 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CM-6(a) - AC-6(1) - AU-9(4) - DE.AE-3 - DE.AE-5 - PR.AC-4 - PR.DS-5 - PR.PT-1 - RS.AN-1 - RS.AN-4 - Req-10.5.1 - SRG-OS-000057-GPOS-00027 - SRG-OS-000058-GPOS-00028 - SRG-OS-000059-GPOS-00029 - SRG-OS-000206-GPOS-00084 - Unauthorized disclosure of audit records can reveal system and configuration data to -attackers, thus compromising its confidentiality. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +group account, change the group ownership of the audit directories to this specific group. + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 18 + 19 + 3 + 4 + 5 + 6 + 7 + 8 + 5.4.1.1 + APO01.06 + APO11.04 + APO12.06 + BAI03.05 + BAI08.02 + DSS02.02 + DSS02.04 + DSS02.07 + DSS03.01 + DSS05.04 + DSS05.07 + DSS06.02 + MEA02.01 + 3.3.1 + CCI-000163 + CCI-000164 + CCI-001314 + CCI-000162 + 4.2.3.10 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.3.7.3 + 4.3.4.4.7 + 4.3.4.5.6 + 4.3.4.5.7 + 4.3.4.5.8 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 2.1 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.8 + SR 2.9 + SR 5.2 + SR 6.1 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.16.1.4 + A.16.1.5 + A.16.1.7 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CM-6(a) + AC-6(1) + AU-9(4) + DE.AE-3 + DE.AE-5 + PR.AC-4 + PR.DS-5 + PR.PT-1 + RS.AN-1 + RS.AN-4 + Req-10.5.1 + SRG-OS-000057-GPOS-00027 + SRG-OS-000058-GPOS-00028 + SRG-OS-000059-GPOS-00029 + SRG-OS-000206-GPOS-00084 + OL09-00-000785 + SV-271583r1091461_rule + Unauthorized disclosure of audit records can reveal system and configuration data to +attackers, thus compromising its confidentiality. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then if LC_ALL=C grep -m 1 -q ^log_group /etc/audit/auditd.conf; then GROUP=$(awk -F "=" '/log_group/ {print $2}' /etc/audit/auditd.conf | tr -d ' ') @@ -51344,123 +131964,194 @@ find ${DIR} -type d -exec chgrp ${GROUP} {} \; else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - - - - - - - - System Audit Directories Must Be Owned By Root - All audit directories must be owned by root user. By default, the path for audit log is /var/log/audit/. + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000785 + - NIST-800-171-3.3.1 + - NIST-800-53-AC-6(1) + - NIST-800-53-AU-9(4) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-10.5.1 + - configure_strategy + - directory_group_ownership_var_log_audit + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: System Audit Directories Must Be Group Owned By Root - Register Audit Configuration + Text + ansible.builtin.slurp: + src: /etc/audit/auditd.conf + register: auditd_config_slurp + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000785 + - NIST-800-171-3.3.1 + - NIST-800-53-AC-6(1) + - NIST-800-53-AU-9(4) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-10.5.1 + - configure_strategy + - directory_group_ownership_var_log_audit + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: System Audit Directories Must Be Group Owned By Root - Set Permissions Custom + Location + ansible.builtin.file: + group: |- + {{ auditd_config_slurp['content'] | b64decode | regex_findall(' + log_group\s*=\s*(.+)') | default(['root',], boolean=True) | first }} + path: |- + {{ auditd_config_slurp['content'] | b64decode | regex_findall(' + log_file\s*=\s*(.+)') | default(['/var/log/audit/audit.log',], boolean=True) | first | dirname }} + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000785 + - NIST-800-171-3.3.1 + - NIST-800-53-AC-6(1) + - NIST-800-53-AU-9(4) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-10.5.1 + - configure_strategy + - directory_group_ownership_var_log_audit + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + System Audit Directories Must Be Owned By Root + All audit directories must be owned by root user. By default, the path for audit log is /var/log/audit/. To properly set the owner of /var/log/audit, run the command: -$ sudo chown root /var/log/audit - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 18 - 19 - 3 - 4 - 5 - 6 - 7 - 8 - 5.4.1.1 - APO01.06 - APO11.04 - APO12.06 - BAI03.05 - BAI08.02 - DSS02.02 - DSS02.04 - DSS02.07 - DSS03.01 - DSS05.04 - DSS05.07 - DSS06.02 - MEA02.01 - 3.3.1 - CCI-000162 - CCI-000163 - CCI-000164 - CCI-001314 - 4.2.3.10 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.3.7.3 - 4.3.4.4.7 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 2.1 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.8 - SR 2.9 - SR 5.2 - SR 6.1 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.16.1.4 - A.16.1.5 - A.16.1.7 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CM-6(a) - AC-6(1) - AU-9(4) - DE.AE-3 - DE.AE-5 - PR.AC-4 - PR.DS-5 - PR.PT-1 - RS.AN-1 - RS.AN-4 - Req-10.5.1 - SRG-OS-000057-GPOS-00027 - SRG-OS-000058-GPOS-00028 - SRG-OS-000059-GPOS-00029 - SRG-OS-000206-GPOS-00084 - Unauthorized disclosure of audit records can reveal system and configuration data to -attackers, thus compromising its confidentiality. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +$ sudo chown root /var/log/audit + + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 18 + 19 + 3 + 4 + 5 + 6 + 7 + 8 + 5.4.1.1 + APO01.06 + APO11.04 + APO12.06 + BAI03.05 + BAI08.02 + DSS02.02 + DSS02.04 + DSS02.07 + DSS03.01 + DSS05.04 + DSS05.07 + DSS06.02 + MEA02.01 + 3.3.1 + CCI-000163 + CCI-000164 + CCI-001314 + CCI-000162 + 4.2.3.10 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.3.7.3 + 4.3.4.4.7 + 4.3.4.5.6 + 4.3.4.5.7 + 4.3.4.5.8 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 2.1 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.8 + SR 2.9 + SR 5.2 + SR 6.1 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.16.1.4 + A.16.1.5 + A.16.1.7 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CM-6(a) + AC-6(1) + AU-9(4) + DE.AE-3 + DE.AE-5 + PR.AC-4 + PR.DS-5 + PR.PT-1 + RS.AN-1 + RS.AN-4 + Req-10.5.1 + SRG-OS-000057-GPOS-00027 + SRG-OS-000058-GPOS-00028 + SRG-OS-000059-GPOS-00029 + SRG-OS-000206-GPOS-00084 + OL09-00-000790 + SV-271584r1091464_rule + Unauthorized disclosure of audit records can reveal system and configuration data to +attackers, thus compromising its confidentiality. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then if LC_ALL=C grep -iw ^log_file /etc/audit/auditd.conf; then FILE=$(awk -F "=" '/^log_file/ {print $2}' /etc/audit/auditd.conf | tr -d ' ') @@ -51473,132 +132164,199 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - - - - - - - - System Audit Logs Must Have Mode 0750 or Less Permissive - + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000790 + - NIST-800-171-3.3.1 + - NIST-800-53-AC-6(1) + - NIST-800-53-AU-9(4) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-10.5.1 + - configure_strategy + - directory_ownership_var_log_audit + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: System Audit Directories Must Be Owned By Root - Register Audit Configuration + Text + ansible.builtin.slurp: + src: /etc/audit/auditd.conf + register: auditd_config_slurp + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000790 + - NIST-800-171-3.3.1 + - NIST-800-53-AC-6(1) + - NIST-800-53-AU-9(4) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-10.5.1 + - configure_strategy + - directory_ownership_var_log_audit + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: System Audit Directories Must Be Owned By Root - Set Permissions Custom Location + ansible.builtin.file: + owner: root + path: |- + {{ auditd_config_slurp['content'] | b64decode | regex_findall(' + log_file\s*=\s*(.+)') | default(['/var/log/audit/audit.log',], boolean=True) | first | dirname }} + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000790 + - NIST-800-171-3.3.1 + - NIST-800-53-AC-6(1) + - NIST-800-53-AU-9(4) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-10.5.1 + - configure_strategy + - directory_ownership_var_log_audit + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + System Audit Logs Must Have Mode 0750 or Less Permissive + If log_group in /etc/audit/auditd.conf is set to a group other than the root group account, change the mode of the audit log files with the following command: $ sudo chmod 0750 /var/log/audit - + Otherwise, change the mode of the audit log files with the following command: -$ sudo chmod 0700 /var/log/audit - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 18 - 19 - 3 - 4 - 5 - 6 - 7 - 8 - APO01.06 - APO11.04 - APO12.06 - BAI03.05 - BAI08.02 - DSS02.02 - DSS02.04 - DSS02.07 - DSS03.01 - DSS05.04 - DSS05.07 - DSS06.02 - MEA02.01 - CCI-000162 - CCI-000163 - CCI-000164 - 4.2.3.10 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.3.7.3 - 4.3.4.4.7 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 2.1 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.8 - SR 2.9 - SR 5.2 - SR 6.1 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.16.1.4 - A.16.1.5 - A.16.1.7 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.2 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-004-6 R3.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 - CIP-007-3 R6.5 - CM-6(a) - AC-6(1) - AU-9 - DE.AE-3 - DE.AE-5 - PR.AC-4 - PR.DS-5 - PR.PT-1 - RS.AN-1 - RS.AN-4 - SRG-OS-000057-GPOS-00027 - SRG-OS-000058-GPOS-00028 - SRG-OS-000059-GPOS-00029 - If users can write to audit logs, audit trails can be modified or destroyed. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +$ sudo chmod 0700 /var/log/audit + + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 18 + 19 + 3 + 4 + 5 + 6 + 7 + 8 + APO01.06 + APO11.04 + APO12.06 + BAI03.05 + BAI08.02 + DSS02.02 + DSS02.04 + DSS02.07 + DSS03.01 + DSS05.04 + DSS05.07 + DSS06.02 + MEA02.01 + CCI-000162 + CCI-000163 + CCI-000164 + 4.2.3.10 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.3.7.3 + 4.3.4.4.7 + 4.3.4.5.6 + 4.3.4.5.7 + 4.3.4.5.8 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 2.1 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.8 + SR 2.9 + SR 5.2 + SR 6.1 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.16.1.4 + A.16.1.5 + A.16.1.7 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CIP-003-8 R5.1.1 + CIP-003-8 R5.2 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-004-6 R3.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 + CIP-007-3 R6.5 + CM-6(a) + AC-6(1) + AU-9 + DE.AE-3 + DE.AE-5 + PR.AC-4 + PR.DS-5 + PR.PT-1 + RS.AN-1 + RS.AN-4 + SRG-OS-000057-GPOS-00027 + SRG-OS-000058-GPOS-00028 + SRG-OS-000059-GPOS-00029 + A.3.SEC-OL2 + If users can write to audit logs, audit trails can be modified or destroyed. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then if LC_ALL=C grep -iw ^log_file /etc/audit/auditd.conf; then DIR=$(awk -F "=" '/^log_file/ {print $2}' /etc/audit/auditd.conf | tr -d ' ' | rev | cut -d"/" -f2- | rev) @@ -51621,17 +132379,17 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - - - - - - - - System Audit Logs Must Be Group Owned By Root - All audit logs must be group owned by root user. The path for audit log can + + + + + + + + + + System Audit Logs Must Be Group Owned By Root + All audit logs must be group owned by root user. The path for audit log can be configured via log_file parameter in /etc/audit/auditd.conf or, by default, the path for audit log is /var/log/audit/. @@ -51640,110 +132398,113 @@ To properly set the group owner of /var/log/audit/*, run If log_group in /etc/audit/auditd.conf is set to a group other than the root group account, change the group ownership of the audit logs -to this specific group. - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 18 - 19 - 3 - 4 - 5 - 6 - 7 - 8 - 5.4.1.1 - APO01.06 - APO11.04 - APO12.06 - BAI03.05 - BAI08.02 - DSS02.02 - DSS02.04 - DSS02.07 - DSS03.01 - DSS05.04 - DSS05.07 - DSS06.02 - MEA02.01 - 3.3.1 - CCI-000162 - CCI-000163 - CCI-000164 - CCI-001314 - 4.2.3.10 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.3.7.3 - 4.3.4.4.7 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 2.1 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.8 - SR 2.9 - SR 5.2 - SR 6.1 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.16.1.4 - A.16.1.5 - A.16.1.7 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CM-6(a) - AC-6(1) - AU-9(4) - DE.AE-3 - DE.AE-5 - PR.AC-4 - PR.DS-5 - PR.PT-1 - RS.AN-1 - RS.AN-4 - Req-10.5.1 - SRG-OS-000057-GPOS-00027 - SRG-OS-000058-GPOS-00028 - SRG-OS-000059-GPOS-00029 - SRG-OS-000206-GPOS-00084 - Unauthorized disclosure of audit records can reveal system and configuration data to -attackers, thus compromising its confidentiality. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +to this specific group. + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 18 + 19 + 3 + 4 + 5 + 6 + 7 + 8 + 5.4.1.1 + APO01.06 + APO11.04 + APO12.06 + BAI03.05 + BAI08.02 + DSS02.02 + DSS02.04 + DSS02.07 + DSS03.01 + DSS05.04 + DSS05.07 + DSS06.02 + MEA02.01 + 3.3.1 + CCI-000162 + CCI-000163 + CCI-000164 + CCI-001314 + 4.2.3.10 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.3.7.3 + 4.3.4.4.7 + 4.3.4.5.6 + 4.3.4.5.7 + 4.3.4.5.8 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 2.1 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.8 + SR 2.9 + SR 5.2 + SR 6.1 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.16.1.4 + A.16.1.5 + A.16.1.7 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CM-6(a) + AC-6(1) + AU-9(4) + DE.AE-3 + DE.AE-5 + PR.AC-4 + PR.DS-5 + PR.PT-1 + RS.AN-1 + RS.AN-4 + Req-10.5.1 + SRG-OS-000057-GPOS-00027 + SRG-OS-000058-GPOS-00028 + SRG-OS-000059-GPOS-00029 + SRG-OS-000206-GPOS-00084 + A.3.SEC-OL2 + 10.3.2 + 10.3 + Unauthorized disclosure of audit records can reveal system and configuration data to +attackers, thus compromising its confidentiality. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then if LC_ALL=C grep -iw log_file /etc/audit/auditd.conf; then FILE=$(awk -F "=" '/^log_file/ {print $2}' /etc/audit/auditd.conf | tr -d ' ') @@ -51766,39 +132527,41 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - - - - - - - - Audit Configuration Files Must Be Owned By Group root - All audit configuration files must be owned by group root. -chown :root /etc/audit/audit*.{rules,conf} /etc/audit/rules.d/* - CCI-000171 - SRG-OS-000063-GPOS-00032 - Without the capability to restrict which roles and individuals can + + + + + + + + + + Audit Configuration Files Must Be Owned By Group root + All audit configuration files must be owned by group root. +chown :root /etc/audit/audit*.{rules,conf} /etc/audit/rules.d/* + + CCI-000171 + SRG-OS-000063-GPOS-00032 + A.3.SEC-OL4 + Without the capability to restrict which roles and individuals can select which events are audited, unauthorized personnel may be able to prevent the auditing of critical events. Misconfigured audits may degrade the system's performance by overwhelming the audit log. Misconfigured audits may also make it more difficult to establish, correlate, and investigate the events relating -to an incident or identify those responsible for one. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +to an incident or identify those responsible for one. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -find /etc/audit/ -maxdepth 1 -type f ! -group 0 -regex '^audit(\.rules|d\.conf)$' -exec chgrp 0 {} \; +find -L /etc/audit/ -maxdepth 1 -type f ! -group 0 -regextype posix-extended -regex '^.*audit(\.rules|d\.conf)$' -exec chgrp -L 0 {} \; -find /etc/audit/rules.d/ -maxdepth 1 -type f ! -group 0 -regex '^.*\.rules$' -exec chgrp 0 {} \; +find -L /etc/audit/rules.d/ -maxdepth 1 -type f ! -group 0 -regextype posix-extended -regex '^.*\.rules$' -exec chgrp -L 0 {} \; else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: @@ -51809,15 +132572,16 @@ fi - medium_severity - no_reboot_needed -- name: Find /etc/audit/ file(s) matching ^audit(\.rules|d\.conf)$ - command: find -H /etc/audit/ -maxdepth 1 -type f ! -group 0 -regex "^audit(\.rules|d\.conf)$" +- name: Find /etc/audit/ file(s) matching ^.*audit(\.rules|d\.conf)$ + command: find -H /etc/audit/ -maxdepth 1 -type f ! -group 0 -regextype posix-extended + -regex "^.*audit(\.rules|d\.conf)$" register: files_found changed_when: false failed_when: false check_mode: false when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - configure_strategy - file_groupownership_audit_configuration @@ -51826,7 +132590,7 @@ fi - medium_severity - no_reboot_needed -- name: Ensure group owner on /etc/audit/ file(s) matching ^audit(\.rules|d\.conf)$ +- name: Ensure group owner on /etc/audit/ file(s) matching ^.*audit(\.rules|d\.conf)$ file: path: '{{ item }}' group: '0' @@ -51835,7 +132599,7 @@ fi - '{{ files_found.stdout_lines }}' when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - configure_strategy - file_groupownership_audit_configuration @@ -51845,14 +132609,15 @@ fi - no_reboot_needed - name: Find /etc/audit/rules.d/ file(s) matching ^.*\.rules$ - command: find -H /etc/audit/rules.d/ -maxdepth 1 -type f ! -group 0 -regex "^.*\.rules$" + command: find -H /etc/audit/rules.d/ -maxdepth 1 -type f ! -group 0 -regextype posix-extended + -regex "^.*\.rules$" register: files_found changed_when: false failed_when: false check_mode: false when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - configure_strategy - file_groupownership_audit_configuration @@ -51870,7 +132635,7 @@ fi - '{{ files_found.stdout_lines }}' when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - configure_strategy - file_groupownership_audit_configuration @@ -51878,44 +132643,46 @@ fi - low_disruption - medium_severity - no_reboot_needed - - - - - - - - - - Audit Configuration Files Must Be Owned By Root - All audit configuration files must be owned by root user. + + + + + + + + + + Audit Configuration Files Must Be Owned By Root + All audit configuration files must be owned by root user. To properly set the owner of /etc/audit/, run the command: $ sudo chown root /etc/audit/ To properly set the owner of /etc/audit/rules.d/, run the command: -$ sudo chown root /etc/audit/rules.d/ - CCI-000171 - SRG-OS-000063-GPOS-00032 - Without the capability to restrict which roles and individuals can +$ sudo chown root /etc/audit/rules.d/ + + CCI-000171 + SRG-OS-000063-GPOS-00032 + A.3.SEC-OL4 + Without the capability to restrict which roles and individuals can select which events are audited, unauthorized personnel may be able to prevent the auditing of critical events. Misconfigured audits may degrade the system's performance by overwhelming the audit log. Misconfigured audits may also make it more difficult to establish, correlate, and investigate the events relating -to an incident or identify those responsible for one. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +to an incident or identify those responsible for one. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -find /etc/audit/ -maxdepth 1 -type f ! -uid 0 -regex '^audit(\.rules|d\.conf)$' -exec chown 0 {} \; +find -L /etc/audit/ -maxdepth 1 -type f ! -uid 0 -regextype posix-extended -regex '^.*audit(\.rules|d\.conf)$' -exec chown -L 0 {} \; -find /etc/audit/rules.d/ -maxdepth 1 -type f ! -uid 0 -regex '^.*\.rules$' -exec chown 0 {} \; +find -L /etc/audit/rules.d/ -maxdepth 1 -type f ! -uid 0 -regextype posix-extended -regex '^.*\.rules$' -exec chown -L 0 {} \; else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: @@ -51926,15 +132693,16 @@ fi - medium_severity - no_reboot_needed -- name: Find /etc/audit/ file(s) matching ^audit(\.rules|d\.conf)$ - command: find -H /etc/audit/ -maxdepth 1 -type f ! -uid 0 -regex "^audit(\.rules|d\.conf)$" +- name: Find /etc/audit/ file(s) matching ^.*audit(\.rules|d\.conf)$ + command: find -H /etc/audit/ -maxdepth 1 -type f ! -uid 0 -regextype posix-extended + -regex "^.*audit(\.rules|d\.conf)$" register: files_found changed_when: false failed_when: false check_mode: false when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - configure_strategy - file_ownership_audit_configuration @@ -51943,7 +132711,7 @@ fi - medium_severity - no_reboot_needed -- name: Ensure owner on /etc/audit/ file(s) matching ^audit(\.rules|d\.conf)$ +- name: Ensure owner on /etc/audit/ file(s) matching ^.*audit(\.rules|d\.conf)$ file: path: '{{ item }}' owner: '0' @@ -51952,7 +132720,7 @@ fi - '{{ files_found.stdout_lines }}' when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - configure_strategy - file_ownership_audit_configuration @@ -51962,14 +132730,15 @@ fi - no_reboot_needed - name: Find /etc/audit/rules.d/ file(s) matching ^.*\.rules$ - command: find -H /etc/audit/rules.d/ -maxdepth 1 -type f ! -uid 0 -regex "^.*\.rules$" + command: find -H /etc/audit/rules.d/ -maxdepth 1 -type f ! -uid 0 -regextype posix-extended + -regex "^.*\.rules$" register: files_found changed_when: false failed_when: false check_mode: false when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - configure_strategy - file_ownership_audit_configuration @@ -51987,7 +132756,7 @@ fi - '{{ files_found.stdout_lines }}' when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - configure_strategy - file_ownership_audit_configuration @@ -51995,136 +132764,139 @@ fi - low_disruption - medium_severity - no_reboot_needed - - - - - - - - - - System Audit Logs Must Be Owned By Root - All audit logs must be owned by root user and group. By default, the path for audit log is /var/log/audit/. + + + + + + + + + + System Audit Logs Must Be Owned By Root + All audit logs must be owned by root user and group. By default, the path for audit log is /var/log/audit/. To properly set the owner of /var/log/audit, run the command: $ sudo chown root /var/log/audit To properly set the owner of /var/log/audit/*, run the command: -$ sudo chown root /var/log/audit/* - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 18 - 19 - 3 - 4 - 5 - 6 - 7 - 8 - 5.4.1.1 - APO01.06 - APO11.04 - APO12.06 - BAI03.05 - BAI08.02 - DSS02.02 - DSS02.04 - DSS02.07 - DSS03.01 - DSS05.04 - DSS05.07 - DSS06.02 - MEA02.01 - 3.3.1 - CCI-000162 - CCI-000163 - CCI-000164 - CCI-001314 - 4.2.3.10 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.3.7.3 - 4.3.4.4.7 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 2.1 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.8 - SR 2.9 - SR 5.2 - SR 6.1 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.16.1.4 - A.16.1.5 - A.16.1.7 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 - CM-6(a) - AC-6(1) - AU-9(4) - DE.AE-3 - DE.AE-5 - PR.AC-4 - PR.DS-5 - PR.PT-1 - RS.AN-1 - RS.AN-4 - Req-10.5.1 - 10.3.1 - SRG-OS-000057-GPOS-00027 - SRG-OS-000058-GPOS-00028 - SRG-OS-000059-GPOS-00029 - SRG-APP-000118-CTR-000240 - Unauthorized disclosure of audit records can reveal system and configuration data to -attackers, thus compromising its confidentiality. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +$ sudo chown root /var/log/audit/* + + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 18 + 19 + 3 + 4 + 5 + 6 + 7 + 8 + 5.4.1.1 + APO01.06 + APO11.04 + APO12.06 + BAI03.05 + BAI08.02 + DSS02.02 + DSS02.04 + DSS02.07 + DSS03.01 + DSS05.04 + DSS05.07 + DSS06.02 + MEA02.01 + 3.3.1 + CCI-000162 + CCI-000163 + CCI-000164 + CCI-001314 + 4.2.3.10 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.3.7.3 + 4.3.4.4.7 + 4.3.4.5.6 + 4.3.4.5.7 + 4.3.4.5.8 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 2.1 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.8 + SR 2.9 + SR 5.2 + SR 6.1 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.16.1.4 + A.16.1.5 + A.16.1.7 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 + CM-6(a) + AC-6(1) + AU-9(4) + DE.AE-3 + DE.AE-5 + PR.AC-4 + PR.DS-5 + PR.PT-1 + RS.AN-1 + RS.AN-4 + Req-10.5.1 + SRG-OS-000057-GPOS-00027 + SRG-OS-000058-GPOS-00028 + SRG-OS-000059-GPOS-00029 + SRG-APP-000118-CTR-000240 + A.3.SEC-OL2 + 10.3.2 + 10.3 + Unauthorized disclosure of audit records can reveal system and configuration data to +attackers, thus compromising its confidentiality. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then if LC_ALL=C grep -m 1 -q ^log_group /etc/audit/auditd.conf; then GROUP=$(awk -F "=" '/log_group/ {print $2}' /etc/audit/auditd.conf | tr -d ' ') @@ -52143,170 +132915,46 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - - - - - - - - System Audit Logs Must Be Owned By Root - All audit logs must be owned by root user. The path for audit log can be -configured via log_file parameter in /etc/audit/auditd.conf -or by default, the path for audit log is /var/log/audit/. - -To properly set the owner of /var/log/audit/*, run the command: -$ sudo chown root /var/log/audit/* - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 18 - 19 - 3 - 4 - 5 - 6 - 7 - 8 - 5.4.1.1 - APO01.06 - APO11.04 - APO12.06 - BAI03.05 - BAI08.02 - DSS02.02 - DSS02.04 - DSS02.07 - DSS03.01 - DSS05.04 - DSS05.07 - DSS06.02 - MEA02.01 - 3.3.1 - CCI-000162 - CCI-000163 - CCI-000164 - CCI-001314 - 4.2.3.10 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.3.7.3 - 4.3.4.4.7 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 2.1 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.8 - SR 2.9 - SR 5.2 - SR 6.1 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.16.1.4 - A.16.1.5 - A.16.1.7 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CM-6(a) - AC-6(1) - AU-9(4) - DE.AE-3 - DE.AE-5 - PR.AC-4 - PR.DS-5 - PR.PT-1 - RS.AN-1 - RS.AN-4 - Req-10.5.1 - SRG-OS-000057-GPOS-00027 - SRG-OS-000058-GPOS-00028 - SRG-OS-000059-GPOS-00029 - SRG-OS-000206-GPOS-00084 - Unauthorized disclosure of audit records can reveal system and configuration data to -attackers, thus compromising its confidentiality. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then - -if LC_ALL=C grep -iw log_file /etc/audit/auditd.conf; then - FILE=$(awk -F "=" '/^log_file/ {print $2}' /etc/audit/auditd.conf | tr -d ' ') - chown root $FILE* -else - chown root /var/log/audit/audit.log* -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - - - - - - - - Audit Configuration Files Permissions are 640 or More Restrictive - All audit configuration files permissions must be 640 or more restrictive. -chmod 0640 /etc/audit/audit*.{rules,conf} /etc/audit/rules.d/* - Without the capability to restrict which roles and individuals can + + + + + + + + + + Audit Configuration Files Permissions are 640 or More Restrictive + All audit configuration files permissions must be 640 or more restrictive. +chmod 0640 /etc/audit/audit*.{rules,conf} /etc/audit/rules.d/* + + CCI-000171 + AU-12 b + SRG-OS-000063-GPOS-00032 + A.3.SEC-OL4 + Without the capability to restrict which roles and individuals can select which events are audited, unauthorized personnel may be able to prevent the auditing of critical events. Misconfigured audits may degrade the system's performance by overwhelming the audit log. Misconfigured audits may also make it more difficult to establish, correlate, and investigate the events relating -to an incident or identify those responsible for one. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +to an incident or identify those responsible for one. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -find -H /etc/audit/ -maxdepth 1 -perm /u+xs,g+xws,o+xwrt -type f -regex '.*audit\(\.rules\|d\.conf\)$' -exec chmod u-xs,g-xws,o-xwrt {} \; +find -L /etc/audit/ -maxdepth 1 -perm /u+xs,g+xws,o+xwrt -type f -regextype posix-extended -regex '^.*audit(\.rules|d\.conf)$' -exec chmod u-xs,g-xws,o-xwrt {} \; -find -H /etc/audit/rules.d/ -maxdepth 1 -perm /u+xs,g+xws,o+xwrt -type f -regex '.*\.rules$' -exec chmod u-xs,g-xws,o-xwrt {} \; +find -L /etc/audit/rules.d/ -maxdepth 1 -perm /u+xs,g+xws,o+xwrt -type f -regextype posix-extended -regex '^.*\.rules$' -exec chmod u-xs,g-xws,o-xwrt {} \; else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - NIST-800-53-AU-12 b - configure_strategy - file_permissions_audit_configuration - low_complexity @@ -52315,16 +132963,17 @@ fi - no_reboot_needed - name: Find /etc/audit/ file(s) - command: find -H /etc/audit/ -maxdepth 1 -perm /u+xs,g+xws,o+xwrt -type f -regex - ".*audit\(\.rules\|d\.conf\)$" + command: find -H /etc/audit/ -maxdepth 1 -perm /u+xs,g+xws,o+xwrt -type f -regextype + posix-extended -regex "^.*audit(\.rules|d\.conf)$" register: files_found changed_when: false failed_when: false check_mode: false when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - NIST-800-53-AU-12 b - configure_strategy - file_permissions_audit_configuration - low_complexity @@ -52341,8 +132990,9 @@ fi - '{{ files_found.stdout_lines }}' when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - NIST-800-53-AU-12 b - configure_strategy - file_permissions_audit_configuration - low_complexity @@ -52352,15 +133002,16 @@ fi - name: Find /etc/audit/rules.d/ file(s) command: find -H /etc/audit/rules.d/ -maxdepth 1 -perm /u+xs,g+xws,o+xwrt -type - f -regex ".*\.rules$" + f -regextype posix-extended -regex "^.*\.rules$" register: files_found changed_when: false failed_when: false check_mode: false when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - NIST-800-53-AU-12 b - configure_strategy - file_permissions_audit_configuration - low_complexity @@ -52377,145 +133028,151 @@ fi - '{{ files_found.stdout_lines }}' when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - NIST-800-53-AU-12 b - configure_strategy - file_permissions_audit_configuration - low_complexity - low_disruption - medium_severity - no_reboot_needed - - - - - - - - - - System Audit Logs Must Have Mode 0640 or Less Permissive - + + + + + + + + + + System Audit Logs Must Have Mode 0640 or Less Permissive + Determine where the audit logs are stored with the following command: $ sudo grep -iw log_file /etc/audit/auditd.conf log_file = /var/log/audit/audit.log Configure the audit log to be protected from unauthorized read access by setting the correct permissive mode with the following command: -$ sudo chmod 0600 audit_log_file -By default, audit_log_file is "/var/log/audit/audit.log". - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 18 - 19 - 3 - 4 - 5 - 6 - 7 - 8 - 5.4.1.1 - APO01.06 - APO11.04 - APO12.06 - BAI03.05 - BAI08.02 - DSS02.02 - DSS02.04 - DSS02.07 - DSS03.01 - DSS05.04 - DSS05.07 - DSS06.02 - MEA02.01 - 3.3.1 - CCI-000162 - CCI-000163 - CCI-000164 - CCI-001314 - 4.2.3.10 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.3.7.3 - 4.3.4.4.7 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 2.1 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.8 - SR 2.9 - SR 5.2 - SR 6.1 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.16.1.4 - A.16.1.5 - A.16.1.7 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 - CM-6(a) - AC-6(1) - AU-9(4) - DE.AE-3 - DE.AE-5 - PR.AC-4 - PR.DS-5 - PR.PT-1 - RS.AN-1 - RS.AN-4 - Req-10.5 - 10.3.1 - SRG-OS-000057-GPOS-00027 - SRG-OS-000058-GPOS-00028 - SRG-OS-000059-GPOS-00029 - SRG-OS-000206-GPOS-00084 - SRG-APP-000118-CTR-000240 - If users can write to audit logs, audit trails can be modified or destroyed. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +$ sudo chmod 0600 audit_log_file + +By default, audit_log_file is "/var/log/audit/audit.log". + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 18 + 19 + 3 + 4 + 5 + 6 + 7 + 8 + 5.4.1.1 + APO01.06 + APO11.04 + APO12.06 + BAI03.05 + BAI08.02 + DSS02.02 + DSS02.04 + DSS02.07 + DSS03.01 + DSS05.04 + DSS05.07 + DSS06.02 + MEA02.01 + 3.3.1 + CCI-000163 + CCI-000164 + CCI-001314 + CCI-000162 + 4.2.3.10 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.3.7.3 + 4.3.4.4.7 + 4.3.4.5.6 + 4.3.4.5.7 + 4.3.4.5.8 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 2.1 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.8 + SR 2.9 + SR 5.2 + SR 6.1 + A.10.1.1 + A.11.1.4 + A.11.1.5 + A.11.2.1 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.13.1.1 + A.13.1.3 + A.13.2.1 + A.13.2.3 + A.13.2.4 + A.14.1.2 + A.14.1.3 + A.16.1.4 + A.16.1.5 + A.16.1.7 + A.6.1.2 + A.7.1.1 + A.7.1.2 + A.7.3.1 + A.8.2.2 + A.8.2.3 + A.9.1.1 + A.9.1.2 + A.9.2.3 + A.9.4.1 + A.9.4.4 + A.9.4.5 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 + CM-6(a) + AC-6(1) + AU-9(4) + DE.AE-3 + DE.AE-5 + PR.AC-4 + PR.DS-5 + PR.PT-1 + RS.AN-1 + RS.AN-4 + Req-10.5 + SRG-OS-000057-GPOS-00027 + SRG-OS-000058-GPOS-00028 + SRG-OS-000059-GPOS-00029 + SRG-OS-000206-GPOS-00084 + SRG-APP-000118-CTR-000240 + A.3.SEC-OL2 + 10.3.1 + 10.3 + OL09-00-000795 + SV-271585r1091467_rule + If users can write to audit logs, audit trails can be modified or destroyed. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then if LC_ALL=C grep -iw ^log_file /etc/audit/auditd.conf; then FILE=$(awk -F "=" '/^log_file/ {print $2}' /etc/audit/auditd.conf | tr -d ' ') @@ -52529,17 +133186,19 @@ chmod 0600 $FILE else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000795 - NIST-800-171-3.3.1 - NIST-800-53-AC-6(1) - NIST-800-53-AU-9(4) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.1 - file_permissions_var_log_audit - low_complexity @@ -52554,14 +133213,16 @@ fi register: log_file_exists when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000795 - NIST-800-171-3.3.1 - NIST-800-53-AC-6(1) - NIST-800-53-AU-9(4) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.1 - file_permissions_var_log_audit - low_complexity @@ -52575,15 +133236,17 @@ fi register: log_file_line when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - (log_file_exists.stdout | length > 0) + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - log_file_exists is not skipped and (log_file_exists.stdout | length > 0) tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000795 - NIST-800-171-3.3.1 - NIST-800-53-AC-6(1) - NIST-800-53-AU-9(4) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.1 - file_permissions_var_log_audit - low_complexity @@ -52597,15 +133260,18 @@ fi log_file: /var/log/audit/audit.log when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - (log_file_exists is undefined) or (log_file_exists.stdout | length == 0) + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - (log_file_exists is skipped) or (log_file_exists is undefined) or (log_file_exists.stdout + | length == 0) tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000795 - NIST-800-171-3.3.1 - NIST-800-53-AC-6(1) - NIST-800-53-AU-9(4) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.1 - file_permissions_var_log_audit - low_complexity @@ -52619,15 +133285,18 @@ fi log_file: '{{ log_file_line.stdout | trim }}' when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - (log_file_line.stdout is defined) and (log_file_line.stdout | length > 0) + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - (log_file_exists is not skipped) and (log_file_line.stdout is defined) and (log_file_line.stdout + | length > 0) tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000795 - NIST-800-171-3.3.1 - NIST-800-53-AC-6(1) - NIST-800-53-AU-9(4) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.1 - file_permissions_var_log_audit - low_complexity @@ -52643,14 +133312,16 @@ fi failed_when: false when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000795 - NIST-800-171-3.3.1 - NIST-800-53-AC-6(1) - NIST-800-53-AU-9(4) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.1 - file_permissions_var_log_audit - low_complexity @@ -52658,17 +133329,17 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Record Events that Modify the System's Discretionary Access Controls - At a minimum, the audit system should collect file permission + + + + + + + + + + Record Events that Modify the System's Discretionary Access Controls + At a minimum, the audit system should collect file permission changes for all users and root. Note that the "-F arch=b32" lines should be present even on a 64 bit system. These commands identify system calls for auditing. Even if the system is 64 bit it can still execute 32 bit system @@ -52683,10 +133354,11 @@ If your system is 64 bit then these lines should be duplicated and the arch=b32 replaced with arch=b64 as follows: -a always,exit -F arch=b64 -S chmod,fchmod,fchmodat -F auid>=1000 -F auid!=unset -F key=perm_mod -a always,exit -F arch=b64 -S chown,fchown,fchownat,lchown -F auid>=1000 -F auid!=unset -F key=perm_mod - -a always,exit -F arch=b64 -S setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F auid>=1000 -F auid!=unset -F key=perm_mod - - Record Events that Modify the System's Discretionary Access Controls - chmod - At a minimum, the audit system should collect file permission + -a always,exit -F arch=b64 -S setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F auid>=1000 -F auid!=unset -F key=perm_mod + + + Record Events that Modify the System's Discretionary Access Controls - chmod + At a minimum, the audit system should collect file permission changes for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following line to a file with suffix .rules in @@ -52699,150 +133371,162 @@ utility to read audit rules during daemon startup, add the following line to /etc/audit/audit.rules file: -a always,exit -F arch=b32 -S chmod -F auid>=1000 -F auid!=unset -F key=perm_mod If the system is 64 bit then also add the following line: --a always,exit -F arch=b64 -S chmod -F auid>=1000 -F auid!=unset -F key=perm_mod - Note that these rules can be configured in a +-a always,exit -F arch=b64 -S chmod -F auid>=1000 -F auid!=unset -F key=perm_mod + + Note that these rules can be configured in a number of ways while still achieving the desired effect. Here the system calls have been placed independent of other system calls. Grouping these system -calls with others as identifying earlier in this guide is more efficient. - BP28(R73) - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 19 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 5.4.1.1 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - APO12.06 - APO13.01 - BAI03.05 - BAI08.02 - DSS01.03 - DSS01.04 - DSS02.02 - DSS02.04 - DSS02.07 - DSS03.01 - DSS03.05 - DSS05.02 - DSS05.03 - DSS05.04 - DSS05.05 - DSS05.07 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.1.7 - CCI-000126 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-000172 - CCI-002884 - 164.308(a)(1)(ii)(D) - 164.308(a)(3)(ii)(A) - 164.308(a)(5)(ii)(C) - 164.312(a)(2)(i) - 164.312(b) - 164.312(d) - 164.312(e) - 4.2.3.10 - 4.3.2.6.7 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.3.6.6 - 4.3.4.4.7 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 1.13 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.6 - SR 2.8 - SR 2.9 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 6.1 - SR 6.2 - SR 7.1 - SR 7.6 - A.11.2.6 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.14.2.7 - A.15.2.1 - A.15.2.2 - A.16.1.4 - A.16.1.5 - A.16.1.7 - A.6.2.1 - A.6.2.2 - AU-2(d) - AU-12(c) - CM-6(a) - DE.AE-3 - DE.AE-5 - DE.CM-1 - DE.CM-3 - DE.CM-7 - ID.SC-4 - PR.AC-3 - PR.PT-1 - PR.PT-4 - RS.AN-1 - RS.AN-4 - FAU_GEN.1.1.c - Req-10.5.5 - 10.3.4 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-OS-000064-GPOS-00033 - SRG-OS-000466-GPOS-00210 - SRG-OS-000458-GPOS-00203 - The changing of file permissions could indicate that a user is attempting to +calls with others as identifying earlier in this guide is more efficient. + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 19 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 5.4.1.1 + APO10.01 + APO10.03 + APO10.04 + APO10.05 + APO11.04 + APO12.06 + APO13.01 + BAI03.05 + BAI08.02 + DSS01.03 + DSS01.04 + DSS02.02 + DSS02.04 + DSS02.07 + DSS03.01 + DSS03.05 + DSS05.02 + DSS05.03 + DSS05.04 + DSS05.05 + DSS05.07 + MEA01.01 + MEA01.02 + MEA01.03 + MEA01.04 + MEA01.05 + MEA02.01 + 3.1.7 + CCI-000172 + CCI-000130 + CCI-000135 + CCI-000169 + CCI-002884 + 164.308(a)(1)(ii)(D) + 164.308(a)(3)(ii)(A) + 164.308(a)(5)(ii)(C) + 164.312(a)(2)(i) + 164.312(b) + 164.312(d) + 164.312(e) + 4.2.3.10 + 4.3.2.6.7 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.3.6.6 + 4.3.4.4.7 + 4.3.4.5.6 + 4.3.4.5.7 + 4.3.4.5.8 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 1.13 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.6 + SR 2.8 + SR 2.9 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 6.1 + SR 6.2 + SR 7.1 + SR 7.6 + A.11.2.6 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.13.1.1 + A.13.2.1 + A.14.1.3 + A.14.2.7 + A.15.2.1 + A.15.2.2 + A.16.1.4 + A.16.1.5 + A.16.1.7 + A.6.2.1 + A.6.2.2 + AU-2(d) + AU-12(c) + CM-6(a) + DE.AE-3 + DE.AE-5 + DE.CM-1 + DE.CM-3 + DE.CM-7 + ID.SC-4 + PR.AC-3 + PR.PT-1 + PR.PT-4 + RS.AN-1 + RS.AN-4 + Req-10.5.5 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-OS-000064-GPOS-00033 + SRG-OS-000466-GPOS-00210 + SRG-OS-000458-GPOS-00203 + SRG-APP-000091-CTR-000160 + SRG-APP-000492-CTR-001220 + SRG-APP-000493-CTR-001225 + SRG-APP-000494-CTR-001230 + SRG-APP-000500-CTR-001260 + SRG-APP-000507-CTR-001295 + SRG-APP-000495-CTR-001235 + SRG-APP-000499-CTR-001255 + R73 + A.3.SEC-OL7 + 10.3.4 + 10.3 + OL09-00-000640 + SV-271555r1092530_rule + The changing of file permissions could indicate that a user is attempting to gain access to information that would otherwise be disallowed. Auditing DAC modifications can facilitate the identification of patterns of abuse among both authorized and -unauthorized users. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +unauthorized users. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { ! ( ( grep -sqE "^.*\.aarch64$" /proc/sys/kernel/osrelease || grep -sqE "^aarch64$" /proc/sys/kernel/arch; ) ); }; then # First perform the remediation of the syscall rule # Retrieve hardware architecture of the underlying system @@ -52887,7 +133571,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -52903,7 +133586,7 @@ then if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -52995,7 +133678,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -53048,7 +133731,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -53142,7 +133824,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -53170,17 +133852,19 @@ done else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000640 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_dac_modification_chmod - low_complexity @@ -53194,16 +133878,19 @@ fi audit_arch: b64 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - not ( ansible_architecture == "aarch64" ) - ansible_architecture == "aarch64" or ansible_architecture == "ppc64" or ansible_architecture == "ppc64le" or ansible_architecture == "s390x" or ansible_architecture == "x86_64" tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000640 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_dac_modification_chmod - low_complexity @@ -53278,6 +133965,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -53286,7 +133974,7 @@ fi line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -53327,6 +134015,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -53335,19 +134024,22 @@ fi line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - not ( ansible_architecture == "aarch64" ) tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000640 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_dac_modification_chmod - low_complexity @@ -53422,6 +134114,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -53430,7 +134123,7 @@ fi line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -53471,6 +134164,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -53479,20 +134173,23 @@ fi line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - not ( ansible_architecture == "aarch64" ) - audit_arch == "b64" tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000640 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_dac_modification_chmod - low_complexity @@ -53500,17 +134197,17 @@ fi - medium_severity - reboot_required - restrict_strategy - - - - - - - - - - Record Events that Modify the System's Discretionary Access Controls - chown - At a minimum, the audit system should collect file permission + + + + + + + + + + Record Events that Modify the System's Discretionary Access Controls - chown + At a minimum, the audit system should collect file permission changes for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following line to a file with suffix .rules in @@ -53523,151 +134220,163 @@ utility to read audit rules during daemon startup, add the following line to /etc/audit/audit.rules file: -a always,exit -F arch=b32 -S chown -F auid>=1000 -F auid!=unset -F key=perm_mod If the system is 64 bit then also add the following line: --a always,exit -F arch=b64 -S chown -F auid>=1000 -F auid!=unset -F key=perm_mod - Note that these rules can be configured in a +-a always,exit -F arch=b64 -S chown -F auid>=1000 -F auid!=unset -F key=perm_mod + + Note that these rules can be configured in a number of ways while still achieving the desired effect. Here the system calls have been placed independent of other system calls. Grouping these system -calls with others as identifying earlier in this guide is more efficient. - BP28(R73) - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 19 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 5.4.1.1 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - APO12.06 - APO13.01 - BAI03.05 - BAI08.02 - DSS01.03 - DSS01.04 - DSS02.02 - DSS02.04 - DSS02.07 - DSS03.01 - DSS03.05 - DSS05.02 - DSS05.03 - DSS05.04 - DSS05.05 - DSS05.07 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.1.7 - CCI-000126 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-000172 - CCI-002884 - 164.308(a)(1)(ii)(D) - 164.308(a)(3)(ii)(A) - 164.308(a)(5)(ii)(C) - 164.312(a)(2)(i) - 164.312(b) - 164.312(d) - 164.312(e) - 4.2.3.10 - 4.3.2.6.7 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.3.6.6 - 4.3.4.4.7 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 1.13 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.6 - SR 2.8 - SR 2.9 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 6.1 - SR 6.2 - SR 7.1 - SR 7.6 - A.11.2.6 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.14.2.7 - A.15.2.1 - A.15.2.2 - A.16.1.4 - A.16.1.5 - A.16.1.7 - A.6.2.1 - A.6.2.2 - AU-2(d) - AU-12(c) - CM-6(a) - DE.AE-3 - DE.AE-5 - DE.CM-1 - DE.CM-3 - DE.CM-7 - ID.SC-4 - PR.AC-3 - PR.PT-1 - PR.PT-4 - RS.AN-1 - RS.AN-4 - FAU_GEN.1.1.c - Req-10.5.5 - 10.3.4 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-OS-000064-GPOS-00033 - SRG-OS-000466-GPOS-00210 - SRG-OS-000458-GPOS-00203 - SRG-OS-000474-GPOS-00219 - The changing of file permissions could indicate that a user is attempting to +calls with others as identifying earlier in this guide is more efficient. + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 19 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 5.4.1.1 + APO10.01 + APO10.03 + APO10.04 + APO10.05 + APO11.04 + APO12.06 + APO13.01 + BAI03.05 + BAI08.02 + DSS01.03 + DSS01.04 + DSS02.02 + DSS02.04 + DSS02.07 + DSS03.01 + DSS03.05 + DSS05.02 + DSS05.03 + DSS05.04 + DSS05.05 + DSS05.07 + MEA01.01 + MEA01.02 + MEA01.03 + MEA01.04 + MEA01.05 + MEA02.01 + 3.1.7 + CCI-000172 + CCI-000130 + CCI-000135 + CCI-000169 + CCI-002884 + 164.308(a)(1)(ii)(D) + 164.308(a)(3)(ii)(A) + 164.308(a)(5)(ii)(C) + 164.312(a)(2)(i) + 164.312(b) + 164.312(d) + 164.312(e) + 4.2.3.10 + 4.3.2.6.7 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.3.6.6 + 4.3.4.4.7 + 4.3.4.5.6 + 4.3.4.5.7 + 4.3.4.5.8 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 1.13 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.6 + SR 2.8 + SR 2.9 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 6.1 + SR 6.2 + SR 7.1 + SR 7.6 + A.11.2.6 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.13.1.1 + A.13.2.1 + A.14.1.3 + A.14.2.7 + A.15.2.1 + A.15.2.2 + A.16.1.4 + A.16.1.5 + A.16.1.7 + A.6.2.1 + A.6.2.2 + AU-2(d) + AU-12(c) + CM-6(a) + DE.AE-3 + DE.AE-5 + DE.CM-1 + DE.CM-3 + DE.CM-7 + ID.SC-4 + PR.AC-3 + PR.PT-1 + PR.PT-4 + RS.AN-1 + RS.AN-4 + Req-10.5.5 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-OS-000064-GPOS-00033 + SRG-OS-000466-GPOS-00210 + SRG-OS-000458-GPOS-00203 + SRG-OS-000474-GPOS-00219 + SRG-APP-000091-CTR-000160 + SRG-APP-000492-CTR-001220 + SRG-APP-000493-CTR-001225 + SRG-APP-000494-CTR-001230 + SRG-APP-000500-CTR-001260 + SRG-APP-000507-CTR-001295 + SRG-APP-000495-CTR-001235 + SRG-APP-000499-CTR-001255 + R73 + A.3.SEC-OL7 + 10.3.4 + 10.3 + OL09-00-000645 + SV-271556r1092532_rule + The changing of file permissions could indicate that a user is attempting to gain access to information that would otherwise be disallowed. Auditing DAC modifications can facilitate the identification of patterns of abuse among both authorized and -unauthorized users. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +unauthorized users. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { ! ( ( grep -sqE "^.*\.aarch64$" /proc/sys/kernel/osrelease || grep -sqE "^aarch64$" /proc/sys/kernel/arch; ) ); }; then # First perform the remediation of the syscall rule # Retrieve hardware architecture of the underlying system @@ -53712,7 +134421,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -53728,7 +134436,7 @@ then if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -53820,7 +134528,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -53873,7 +134581,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -53967,7 +134674,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -53995,17 +134702,19 @@ done else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000645 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_dac_modification_chown - low_complexity @@ -54019,16 +134728,19 @@ fi audit_arch: b64 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - not ( ansible_architecture == "aarch64" ) - ansible_architecture == "aarch64" or ansible_architecture == "ppc64" or ansible_architecture == "ppc64le" or ansible_architecture == "s390x" or ansible_architecture == "x86_64" tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000645 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_dac_modification_chown - low_complexity @@ -54104,6 +134816,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -54112,7 +134825,7 @@ fi line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -54154,6 +134867,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -54162,19 +134876,22 @@ fi line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - not ( ansible_architecture == "aarch64" ) tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000645 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_dac_modification_chown - low_complexity @@ -54250,6 +134967,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -54258,7 +134976,7 @@ fi line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -54300,6 +135018,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -54308,20 +135027,23 @@ fi line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - not ( ansible_architecture == "aarch64" ) - audit_arch == "b64" tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000645 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_dac_modification_chown - low_complexity @@ -54329,17 +135051,17 @@ fi - medium_severity - reboot_required - restrict_strategy - - - - - - - - - - Record Events that Modify the System's Discretionary Access Controls - fchmod - At a minimum, the audit system should collect file permission + + + + + + + + + + Record Events that Modify the System's Discretionary Access Controls - fchmod + At a minimum, the audit system should collect file permission changes for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following line to a file with suffix .rules in @@ -54352,150 +135074,161 @@ utility to read audit rules during daemon startup, add the following line to /etc/audit/audit.rules file: -a always,exit -F arch=b32 -S fchmod -F auid>=1000 -F auid!=unset -F key=perm_mod If the system is 64 bit then also add the following line: --a always,exit -F arch=b64 -S fchmod -F auid>=1000 -F auid!=unset -F key=perm_mod - Note that these rules can be configured in a +-a always,exit -F arch=b64 -S fchmod -F auid>=1000 -F auid!=unset -F key=perm_mod + + Note that these rules can be configured in a number of ways while still achieving the desired effect. Here the system calls have been placed independent of other system calls. Grouping these system -calls with others as identifying earlier in this guide is more efficient. - BP28(R73) - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 19 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 5.4.1.1 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - APO12.06 - APO13.01 - BAI03.05 - BAI08.02 - DSS01.03 - DSS01.04 - DSS02.02 - DSS02.04 - DSS02.07 - DSS03.01 - DSS03.05 - DSS05.02 - DSS05.03 - DSS05.04 - DSS05.05 - DSS05.07 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.1.7 - CCI-000126 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-000172 - CCI-002884 - 164.308(a)(1)(ii)(D) - 164.308(a)(3)(ii)(A) - 164.308(a)(5)(ii)(C) - 164.312(a)(2)(i) - 164.312(b) - 164.312(d) - 164.312(e) - 4.2.3.10 - 4.3.2.6.7 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.3.6.6 - 4.3.4.4.7 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 1.13 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.6 - SR 2.8 - SR 2.9 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 6.1 - SR 6.2 - SR 7.1 - SR 7.6 - A.11.2.6 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.14.2.7 - A.15.2.1 - A.15.2.2 - A.16.1.4 - A.16.1.5 - A.16.1.7 - A.6.2.1 - A.6.2.2 - AU-2(d) - AU-12(c) - CM-6(a) - DE.AE-3 - DE.AE-5 - DE.CM-1 - DE.CM-3 - DE.CM-7 - ID.SC-4 - PR.AC-3 - PR.PT-1 - PR.PT-4 - RS.AN-1 - RS.AN-4 - FAU_GEN.1.1.c - Req-10.5.5 - 10.3.4 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-OS-000064-GPOS-00033 - SRG-OS-000466-GPOS-00210 - SRG-OS-000458-GPOS-00203 - The changing of file permissions could indicate that a user is attempting to +calls with others as identifying earlier in this guide is more efficient. + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 19 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 5.4.1.1 + APO10.01 + APO10.03 + APO10.04 + APO10.05 + APO11.04 + APO12.06 + APO13.01 + BAI03.05 + BAI08.02 + DSS01.03 + DSS01.04 + DSS02.02 + DSS02.04 + DSS02.07 + DSS03.01 + DSS03.05 + DSS05.02 + DSS05.03 + DSS05.04 + DSS05.05 + DSS05.07 + MEA01.01 + MEA01.02 + MEA01.03 + MEA01.04 + MEA01.05 + MEA02.01 + 3.1.7 + CCI-000172 + CCI-000130 + CCI-000135 + CCI-000169 + CCI-002884 + 164.308(a)(1)(ii)(D) + 164.308(a)(3)(ii)(A) + 164.308(a)(5)(ii)(C) + 164.312(a)(2)(i) + 164.312(b) + 164.312(d) + 164.312(e) + 4.2.3.10 + 4.3.2.6.7 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.3.6.6 + 4.3.4.4.7 + 4.3.4.5.6 + 4.3.4.5.7 + 4.3.4.5.8 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 1.13 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.6 + SR 2.8 + SR 2.9 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 6.1 + SR 6.2 + SR 7.1 + SR 7.6 + A.11.2.6 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.13.1.1 + A.13.2.1 + A.14.1.3 + A.14.2.7 + A.15.2.1 + A.15.2.2 + A.16.1.4 + A.16.1.5 + A.16.1.7 + A.6.2.1 + A.6.2.2 + AU-2(d) + AU-12(c) + CM-6(a) + DE.AE-3 + DE.AE-5 + DE.CM-1 + DE.CM-3 + DE.CM-7 + ID.SC-4 + PR.AC-3 + PR.PT-1 + PR.PT-4 + RS.AN-1 + RS.AN-4 + Req-10.5.5 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-OS-000064-GPOS-00033 + SRG-OS-000466-GPOS-00210 + SRG-OS-000458-GPOS-00203 + SRG-APP-000091-CTR-000160 + SRG-APP-000492-CTR-001220 + SRG-APP-000493-CTR-001225 + SRG-APP-000494-CTR-001230 + SRG-APP-000500-CTR-001260 + SRG-APP-000507-CTR-001295 + SRG-APP-000495-CTR-001235 + SRG-APP-000499-CTR-001255 + R73 + A.3.SEC-OL7 + 10.3.4 + 10.3 + OL09-00-000640 + SV-271555r1092530_rule + The changing of file permissions could indicate that a user is attempting to gain access to information that would otherwise be disallowed. Auditing DAC modifications can facilitate the identification of patterns of abuse among both authorized and -unauthorized users. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +unauthorized users. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then # First perform the remediation of the syscall rule # Retrieve hardware architecture of the underlying system @@ -54540,7 +135273,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -54556,7 +135288,7 @@ then if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -54648,7 +135380,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -54701,7 +135433,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -54795,7 +135526,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -54823,17 +135554,19 @@ done else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000640 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_dac_modification_fchmod - low_complexity @@ -54847,16 +135580,18 @@ fi audit_arch: b64 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - ansible_architecture == "aarch64" or ansible_architecture == "ppc64" or ansible_architecture == "ppc64le" or ansible_architecture == "s390x" or ansible_architecture == "x86_64" tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000640 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_dac_modification_fchmod - low_complexity @@ -54931,6 +135666,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -54939,7 +135675,7 @@ fi line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -54980,6 +135716,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -54988,19 +135725,21 @@ fi line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000640 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_dac_modification_fchmod - low_complexity @@ -55075,6 +135814,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -55083,7 +135823,7 @@ fi line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -55124,6 +135864,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -55132,20 +135873,22 @@ fi line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - audit_arch == "b64" tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000640 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_dac_modification_fchmod - low_complexity @@ -55153,17 +135896,17 @@ fi - medium_severity - reboot_required - restrict_strategy - - - - - - - - - - Record Events that Modify the System's Discretionary Access Controls - fchmodat - At a minimum, the audit system should collect file permission + + + + + + + + + + Record Events that Modify the System's Discretionary Access Controls - fchmodat + At a minimum, the audit system should collect file permission changes for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following line to a file with suffix .rules in @@ -55176,150 +135919,161 @@ utility to read audit rules during daemon startup, add the following line to /etc/audit/audit.rules file: -a always,exit -F arch=b32 -S fchmodat -F auid>=1000 -F auid!=unset -F key=perm_mod If the system is 64 bit then also add the following line: --a always,exit -F arch=b64 -S fchmodat -F auid>=1000 -F auid!=unset -F key=perm_mod - Note that these rules can be configured in a +-a always,exit -F arch=b64 -S fchmodat -F auid>=1000 -F auid!=unset -F key=perm_mod + + Note that these rules can be configured in a number of ways while still achieving the desired effect. Here the system calls have been placed independent of other system calls. Grouping these system -calls with others as identifying earlier in this guide is more efficient. - BP28(R73) - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 19 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 5.4.1.1 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - APO12.06 - APO13.01 - BAI03.05 - BAI08.02 - DSS01.03 - DSS01.04 - DSS02.02 - DSS02.04 - DSS02.07 - DSS03.01 - DSS03.05 - DSS05.02 - DSS05.03 - DSS05.04 - DSS05.05 - DSS05.07 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.1.7 - CCI-000126 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-000172 - CCI-002884 - 164.308(a)(1)(ii)(D) - 164.308(a)(3)(ii)(A) - 164.308(a)(5)(ii)(C) - 164.312(a)(2)(i) - 164.312(b) - 164.312(d) - 164.312(e) - 4.2.3.10 - 4.3.2.6.7 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.3.6.6 - 4.3.4.4.7 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 1.13 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.6 - SR 2.8 - SR 2.9 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 6.1 - SR 6.2 - SR 7.1 - SR 7.6 - A.11.2.6 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.14.2.7 - A.15.2.1 - A.15.2.2 - A.16.1.4 - A.16.1.5 - A.16.1.7 - A.6.2.1 - A.6.2.2 - AU-2(d) - AU-12(c) - CM-6(a) - DE.AE-3 - DE.AE-5 - DE.CM-1 - DE.CM-3 - DE.CM-7 - ID.SC-4 - PR.AC-3 - PR.PT-1 - PR.PT-4 - RS.AN-1 - RS.AN-4 - FAU_GEN.1.1.c - Req-10.5.5 - 10.3.4 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-OS-000064-GPOS-00033 - SRG-OS-000466-GPOS-00210 - SRG-OS-000458-GPOS-00203 - The changing of file permissions could indicate that a user is attempting to +calls with others as identifying earlier in this guide is more efficient. + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 19 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 5.4.1.1 + APO10.01 + APO10.03 + APO10.04 + APO10.05 + APO11.04 + APO12.06 + APO13.01 + BAI03.05 + BAI08.02 + DSS01.03 + DSS01.04 + DSS02.02 + DSS02.04 + DSS02.07 + DSS03.01 + DSS03.05 + DSS05.02 + DSS05.03 + DSS05.04 + DSS05.05 + DSS05.07 + MEA01.01 + MEA01.02 + MEA01.03 + MEA01.04 + MEA01.05 + MEA02.01 + 3.1.7 + CCI-000172 + CCI-000130 + CCI-000135 + CCI-000169 + CCI-002884 + 164.308(a)(1)(ii)(D) + 164.308(a)(3)(ii)(A) + 164.308(a)(5)(ii)(C) + 164.312(a)(2)(i) + 164.312(b) + 164.312(d) + 164.312(e) + 4.2.3.10 + 4.3.2.6.7 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.3.6.6 + 4.3.4.4.7 + 4.3.4.5.6 + 4.3.4.5.7 + 4.3.4.5.8 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 1.13 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.6 + SR 2.8 + SR 2.9 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 6.1 + SR 6.2 + SR 7.1 + SR 7.6 + A.11.2.6 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.13.1.1 + A.13.2.1 + A.14.1.3 + A.14.2.7 + A.15.2.1 + A.15.2.2 + A.16.1.4 + A.16.1.5 + A.16.1.7 + A.6.2.1 + A.6.2.2 + AU-2(d) + AU-12(c) + CM-6(a) + DE.AE-3 + DE.AE-5 + DE.CM-1 + DE.CM-3 + DE.CM-7 + ID.SC-4 + PR.AC-3 + PR.PT-1 + PR.PT-4 + RS.AN-1 + RS.AN-4 + Req-10.5.5 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-OS-000064-GPOS-00033 + SRG-OS-000466-GPOS-00210 + SRG-OS-000458-GPOS-00203 + SRG-APP-000091-CTR-000160 + SRG-APP-000492-CTR-001220 + SRG-APP-000493-CTR-001225 + SRG-APP-000494-CTR-001230 + SRG-APP-000500-CTR-001260 + SRG-APP-000507-CTR-001295 + SRG-APP-000495-CTR-001235 + SRG-APP-000499-CTR-001255 + R73 + A.3.SEC-OL7 + 10.3.4 + 10.3 + OL09-00-000640 + SV-271555r1092530_rule + The changing of file permissions could indicate that a user is attempting to gain access to information that would otherwise be disallowed. Auditing DAC modifications can facilitate the identification of patterns of abuse among both authorized and -unauthorized users. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +unauthorized users. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then # First perform the remediation of the syscall rule # Retrieve hardware architecture of the underlying system @@ -55364,7 +136118,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -55380,7 +136133,7 @@ then if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -55472,7 +136225,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -55525,7 +136278,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -55619,7 +136371,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -55647,17 +136399,19 @@ done else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000640 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_dac_modification_fchmodat - low_complexity @@ -55671,16 +136425,18 @@ fi audit_arch: b64 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - ansible_architecture == "aarch64" or ansible_architecture == "ppc64" or ansible_architecture == "ppc64le" or ansible_architecture == "s390x" or ansible_architecture == "x86_64" tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000640 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_dac_modification_fchmodat - low_complexity @@ -55755,6 +136511,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -55763,7 +136520,7 @@ fi line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -55804,6 +136561,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -55812,19 +136570,21 @@ fi line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000640 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_dac_modification_fchmodat - low_complexity @@ -55899,6 +136659,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -55907,7 +136668,7 @@ fi line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -55948,6 +136709,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -55956,20 +136718,22 @@ fi line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - audit_arch == "b64" tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000640 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_dac_modification_fchmodat - low_complexity @@ -55977,17 +136741,17 @@ fi - medium_severity - reboot_required - restrict_strategy - - - - - - - - - - Record Events that Modify the System's Discretionary Access Controls - fchown - At a minimum, the audit system should collect file permission + + + + + + + + + + Record Events that Modify the System's Discretionary Access Controls - fchown + At a minimum, the audit system should collect file permission changes for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following line to a file with suffix @@ -56003,151 +136767,162 @@ utility to read audit rules during daemon startup, add the following line to -a always,exit -F arch=b32 -S fchown -F auid>=1000 -F auid!=unset -F key=perm_mod If the system is 64 bit then also add the following line: --a always,exit -F arch=b64 -S fchown -F auid>=1000 -F auid!=unset -F key=perm_mod - Note that these rules can be configured in a +-a always,exit -F arch=b64 -S fchown -F auid>=1000 -F auid!=unset -F key=perm_mod + + Note that these rules can be configured in a number of ways while still achieving the desired effect. Here the system calls have been placed independent of other system calls. Grouping these system -calls with others as identifying earlier in this guide is more efficient. - BP28(R73) - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 19 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 5.4.1.1 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - APO12.06 - APO13.01 - BAI03.05 - BAI08.02 - DSS01.03 - DSS01.04 - DSS02.02 - DSS02.04 - DSS02.07 - DSS03.01 - DSS03.05 - DSS05.02 - DSS05.03 - DSS05.04 - DSS05.05 - DSS05.07 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.1.7 - CCI-000126 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-000172 - CCI-002884 - 164.308(a)(1)(ii)(D) - 164.308(a)(3)(ii)(A) - 164.308(a)(5)(ii)(C) - 164.312(a)(2)(i) - 164.312(b) - 164.312(d) - 164.312(e) - 4.2.3.10 - 4.3.2.6.7 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.3.6.6 - 4.3.4.4.7 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 1.13 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.6 - SR 2.8 - SR 2.9 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 6.1 - SR 6.2 - SR 7.1 - SR 7.6 - A.11.2.6 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.14.2.7 - A.15.2.1 - A.15.2.2 - A.16.1.4 - A.16.1.5 - A.16.1.7 - A.6.2.1 - A.6.2.2 - AU-2(d) - AU-12(c) - CM-6(a) - DE.AE-3 - DE.AE-5 - DE.CM-1 - DE.CM-3 - DE.CM-7 - ID.SC-4 - PR.AC-3 - PR.PT-1 - PR.PT-4 - RS.AN-1 - RS.AN-4 - FAU_GEN.1.1.c - Req-10.5.5 - 10.3.4 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-OS-000064-GPOS-00033 - SRG-OS-000466-GPOS-00210 - SRG-OS-000458-GPOS-00203 - SRG-OS-000474-GPOS-00219 - The changing of file permissions could indicate that a user is attempting to +calls with others as identifying earlier in this guide is more efficient. + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 19 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 5.4.1.1 + APO10.01 + APO10.03 + APO10.04 + APO10.05 + APO11.04 + APO12.06 + APO13.01 + BAI03.05 + BAI08.02 + DSS01.03 + DSS01.04 + DSS02.02 + DSS02.04 + DSS02.07 + DSS03.01 + DSS03.05 + DSS05.02 + DSS05.03 + DSS05.04 + DSS05.05 + DSS05.07 + MEA01.01 + MEA01.02 + MEA01.03 + MEA01.04 + MEA01.05 + MEA02.01 + 3.1.7 + CCI-000172 + CCI-000130 + CCI-000135 + CCI-000169 + CCI-002884 + 164.308(a)(1)(ii)(D) + 164.308(a)(3)(ii)(A) + 164.308(a)(5)(ii)(C) + 164.312(a)(2)(i) + 164.312(b) + 164.312(d) + 164.312(e) + 4.2.3.10 + 4.3.2.6.7 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.3.6.6 + 4.3.4.4.7 + 4.3.4.5.6 + 4.3.4.5.7 + 4.3.4.5.8 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 1.13 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.6 + SR 2.8 + SR 2.9 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 6.1 + SR 6.2 + SR 7.1 + SR 7.6 + A.11.2.6 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.13.1.1 + A.13.2.1 + A.14.1.3 + A.14.2.7 + A.15.2.1 + A.15.2.2 + A.16.1.4 + A.16.1.5 + A.16.1.7 + A.6.2.1 + A.6.2.2 + AU-2(d) + AU-12(c) + CM-6(a) + DE.AE-3 + DE.AE-5 + DE.CM-1 + DE.CM-3 + DE.CM-7 + ID.SC-4 + PR.AC-3 + PR.PT-1 + PR.PT-4 + RS.AN-1 + RS.AN-4 + Req-10.5.5 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-OS-000064-GPOS-00033 + SRG-OS-000466-GPOS-00210 + SRG-OS-000458-GPOS-00203 + SRG-OS-000474-GPOS-00219 + SRG-APP-000091-CTR-000160 + SRG-APP-000492-CTR-001220 + SRG-APP-000493-CTR-001225 + SRG-APP-000494-CTR-001230 + SRG-APP-000500-CTR-001260 + SRG-APP-000507-CTR-001295 + SRG-APP-000495-CTR-001235 + SRG-APP-000499-CTR-001255 + R73 + A.3.SEC-OL7 + 10.3.4 + 10.3 + OL09-00-000645 + SV-271556r1092532_rule + The changing of file permissions could indicate that a user is attempting to gain access to information that would otherwise be disallowed. Auditing DAC modifications can facilitate the identification of patterns of abuse among both authorized and -unauthorized users. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +unauthorized users. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then # First perform the remediation of the syscall rule # Retrieve hardware architecture of the underlying system @@ -56192,7 +136967,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -56208,7 +136982,7 @@ then if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -56300,7 +137074,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -56353,7 +137127,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -56447,7 +137220,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -56475,17 +137248,19 @@ done else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000645 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_dac_modification_fchown - low_complexity @@ -56499,16 +137274,18 @@ fi audit_arch: b64 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - ansible_architecture == "aarch64" or ansible_architecture == "ppc64" or ansible_architecture == "ppc64le" or ansible_architecture == "s390x" or ansible_architecture == "x86_64" tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000645 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_dac_modification_fchown - low_complexity @@ -56584,6 +137361,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -56592,7 +137370,7 @@ fi line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -56634,6 +137412,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -56642,19 +137421,21 @@ fi line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000645 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_dac_modification_fchown - low_complexity @@ -56730,6 +137511,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -56738,7 +137520,7 @@ fi line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -56780,6 +137562,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -56788,20 +137571,22 @@ fi line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - audit_arch == "b64" tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000645 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_dac_modification_fchown - low_complexity @@ -56809,17 +137594,17 @@ fi - medium_severity - reboot_required - restrict_strategy - - - - - - - - - - Record Events that Modify the System's Discretionary Access Controls - fchownat - At a minimum, the audit system should collect file permission + + + + + + + + + + Record Events that Modify the System's Discretionary Access Controls - fchownat + At a minimum, the audit system should collect file permission changes for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following line to a file with suffix @@ -56832,151 +137617,162 @@ utility to read audit rules during daemon startup, add the following line to /etc/audit/audit.rules file: -a always,exit -F arch=b32 -S fchownat -F auid>=1000 -F auid!=unset -F key=perm_mod If the system is 64 bit then also add the following line: --a always,exit -F arch=b64 -S fchownat -F auid>=1000 -F auid!=unset -F key=perm_mod - Note that these rules can be configured in a +-a always,exit -F arch=b64 -S fchownat -F auid>=1000 -F auid!=unset -F key=perm_mod + + Note that these rules can be configured in a number of ways while still achieving the desired effect. Here the system calls have been placed independent of other system calls. Grouping these system -calls with others as identifying earlier in this guide is more efficient. - BP28(R73) - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 19 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 5.4.1.1 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - APO12.06 - APO13.01 - BAI03.05 - BAI08.02 - DSS01.03 - DSS01.04 - DSS02.02 - DSS02.04 - DSS02.07 - DSS03.01 - DSS03.05 - DSS05.02 - DSS05.03 - DSS05.04 - DSS05.05 - DSS05.07 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.1.7 - CCI-000126 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-000172 - CCI-002884 - 164.308(a)(1)(ii)(D) - 164.308(a)(3)(ii)(A) - 164.308(a)(5)(ii)(C) - 164.312(a)(2)(i) - 164.312(b) - 164.312(d) - 164.312(e) - 4.2.3.10 - 4.3.2.6.7 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.3.6.6 - 4.3.4.4.7 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 1.13 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.6 - SR 2.8 - SR 2.9 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 6.1 - SR 6.2 - SR 7.1 - SR 7.6 - A.11.2.6 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.14.2.7 - A.15.2.1 - A.15.2.2 - A.16.1.4 - A.16.1.5 - A.16.1.7 - A.6.2.1 - A.6.2.2 - AU-2(d) - AU-12(c) - CM-6(a) - DE.AE-3 - DE.AE-5 - DE.CM-1 - DE.CM-3 - DE.CM-7 - ID.SC-4 - PR.AC-3 - PR.PT-1 - PR.PT-4 - RS.AN-1 - RS.AN-4 - FAU_GEN.1.1.c - Req-10.5.5 - 10.3.4 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-OS-000064-GPOS-00033 - SRG-OS-000466-GPOS-00210 - SRG-OS-000458-GPOS-00203 - SRG-OS-000474-GPOS-00219 - The changing of file permissions could indicate that a user is attempting to +calls with others as identifying earlier in this guide is more efficient. + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 19 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 5.4.1.1 + APO10.01 + APO10.03 + APO10.04 + APO10.05 + APO11.04 + APO12.06 + APO13.01 + BAI03.05 + BAI08.02 + DSS01.03 + DSS01.04 + DSS02.02 + DSS02.04 + DSS02.07 + DSS03.01 + DSS03.05 + DSS05.02 + DSS05.03 + DSS05.04 + DSS05.05 + DSS05.07 + MEA01.01 + MEA01.02 + MEA01.03 + MEA01.04 + MEA01.05 + MEA02.01 + 3.1.7 + CCI-000172 + CCI-000130 + CCI-000135 + CCI-000169 + CCI-002884 + 164.308(a)(1)(ii)(D) + 164.308(a)(3)(ii)(A) + 164.308(a)(5)(ii)(C) + 164.312(a)(2)(i) + 164.312(b) + 164.312(d) + 164.312(e) + 4.2.3.10 + 4.3.2.6.7 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.3.6.6 + 4.3.4.4.7 + 4.3.4.5.6 + 4.3.4.5.7 + 4.3.4.5.8 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 1.13 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.6 + SR 2.8 + SR 2.9 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 6.1 + SR 6.2 + SR 7.1 + SR 7.6 + A.11.2.6 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.13.1.1 + A.13.2.1 + A.14.1.3 + A.14.2.7 + A.15.2.1 + A.15.2.2 + A.16.1.4 + A.16.1.5 + A.16.1.7 + A.6.2.1 + A.6.2.2 + AU-2(d) + AU-12(c) + CM-6(a) + DE.AE-3 + DE.AE-5 + DE.CM-1 + DE.CM-3 + DE.CM-7 + ID.SC-4 + PR.AC-3 + PR.PT-1 + PR.PT-4 + RS.AN-1 + RS.AN-4 + Req-10.5.5 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-OS-000064-GPOS-00033 + SRG-OS-000466-GPOS-00210 + SRG-OS-000458-GPOS-00203 + SRG-OS-000474-GPOS-00219 + SRG-APP-000091-CTR-000160 + SRG-APP-000492-CTR-001220 + SRG-APP-000493-CTR-001225 + SRG-APP-000494-CTR-001230 + SRG-APP-000500-CTR-001260 + SRG-APP-000507-CTR-001295 + SRG-APP-000495-CTR-001235 + SRG-APP-000499-CTR-001255 + R73 + A.3.SEC-OL7 + 10.3.4 + 10.3 + OL09-00-000645 + SV-271556r1092532_rule + The changing of file permissions could indicate that a user is attempting to gain access to information that would otherwise be disallowed. Auditing DAC modifications can facilitate the identification of patterns of abuse among both authorized and -unauthorized users. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +unauthorized users. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then # First perform the remediation of the syscall rule # Retrieve hardware architecture of the underlying system @@ -57021,7 +137817,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -57037,7 +137832,7 @@ then if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -57129,7 +137924,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -57182,7 +137977,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -57276,7 +138070,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -57304,17 +138098,19 @@ done else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000645 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_dac_modification_fchownat - low_complexity @@ -57328,16 +138124,18 @@ fi audit_arch: b64 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - ansible_architecture == "aarch64" or ansible_architecture == "ppc64" or ansible_architecture == "ppc64le" or ansible_architecture == "s390x" or ansible_architecture == "x86_64" tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000645 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_dac_modification_fchownat - low_complexity @@ -57413,6 +138211,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -57421,7 +138220,7 @@ fi line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -57463,6 +138262,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -57471,19 +138271,21 @@ fi line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000645 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_dac_modification_fchownat - low_complexity @@ -57559,6 +138361,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -57567,7 +138370,7 @@ fi line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -57609,6 +138412,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -57617,20 +138421,22 @@ fi line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - audit_arch == "b64" tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000645 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_dac_modification_fchownat - low_complexity @@ -57638,184 +138444,203 @@ fi - medium_severity - reboot_required - restrict_strategy - - - - - - - - - - Record Events that Modify the System's Discretionary Access Controls - fremovexattr - At a minimum, the audit system should collect file permission + + + + + + + + + + Record Events that Modify the System's Discretionary Access Controls - fremovexattr + At a minimum, the audit system should collect file permission changes for all users and root. - + + If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following line to a file with suffix .rules in the directory /etc/audit/rules.d: -a always,exit -F arch=b32 -S fremovexattr -F auid>=1000 -F auid!=unset -F key=perm_mod --a always,exit -F arch=b32 -S fremovexattr -F auid=0 -F key=perm_mod - + -a always,exit -F arch=b32 -S fremovexattr -F auid=0 -F key=perm_mod + + If the system is 64 bit then also add the following line: -a always,exit -F arch=b64 -S fremovexattr -F auid>=1000 -F auid!=unset -F key=perm_mod --a always,exit -F arch=b64 -S fremovexattr -F auid=0 -F key=perm_mod - + -a always,exit -F arch=b64 -S fremovexattr -F auid=0 -F key=perm_mod + + If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following line to /etc/audit/audit.rules file: -a always,exit -F arch=b32 -S fremovexattr -F auid>=1000 -F auid!=unset -F key=perm_mod --a always,exit -F arch=b32 -S fremovexattr -F auid=0 -F key=perm_mod - + -a always,exit -F arch=b32 -S fremovexattr -F auid=0 -F key=perm_mod + + If the system is 64 bit then also add the following line: -a always,exit -F arch=b64 -S fremovexattr -F auid>=1000 -F auid!=unset -F key=perm_mod --a always,exit -F arch=b64 -S fremovexattr -F auid=0 -F key=perm_mod - Note that these rules can be configured in a + -a always,exit -F arch=b64 -S fremovexattr -F auid=0 -F key=perm_mod + + Note that these rules can be configured in a number of ways while still achieving the desired effect. Here the system calls have been placed independent of other system calls. Grouping these system -calls with others as identifying earlier in this guide is more efficient. - BP28(R73) - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 19 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 5.4.1.1 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - APO12.06 - APO13.01 - BAI03.05 - BAI08.02 - DSS01.03 - DSS01.04 - DSS02.02 - DSS02.04 - DSS02.07 - DSS03.01 - DSS03.05 - DSS05.02 - DSS05.03 - DSS05.04 - DSS05.05 - DSS05.07 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.1.7 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-000172 - CCI-002884 - 164.308(a)(1)(ii)(D) - 164.308(a)(3)(ii)(A) - 164.308(a)(5)(ii)(C) - 164.312(a)(2)(i) - 164.312(b) - 164.312(d) - 164.312(e) - 4.2.3.10 - 4.3.2.6.7 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.3.6.6 - 4.3.4.4.7 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 1.13 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.6 - SR 2.8 - SR 2.9 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 6.1 - SR 6.2 - SR 7.1 - SR 7.6 - A.11.2.6 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.14.2.7 - A.15.2.1 - A.15.2.2 - A.16.1.4 - A.16.1.5 - A.16.1.7 - A.6.2.1 - A.6.2.2 - AU-2(d) - AU-12(c) - CM-6(a) - DE.AE-3 - DE.AE-5 - DE.CM-1 - DE.CM-3 - DE.CM-7 - ID.SC-4 - PR.AC-3 - PR.PT-1 - PR.PT-4 - RS.AN-1 - RS.AN-4 - FAU_GEN.1.1.c - Req-10.5.5 - 10.3.4 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000458-GPOS-00203 - SRG-OS-000462-GPOS-00206 - SRG-OS-000463-GPOS-00207 - SRG-OS-000471-GPOS-00215 - SRG-OS-000474-GPOS-00219 - SRG-OS-000466-GPOS-00210 - SRG-OS-000468-GPOS-00212 - SRG-OS-000064-GPOS-00033 - The changing of file permissions could indicate that a user is attempting to +calls with others as identifying earlier in this guide is more efficient. + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 19 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 5.4.1.1 + APO10.01 + APO10.03 + APO10.04 + APO10.05 + APO11.04 + APO12.06 + APO13.01 + BAI03.05 + BAI08.02 + DSS01.03 + DSS01.04 + DSS02.02 + DSS02.04 + DSS02.07 + DSS03.01 + DSS03.05 + DSS05.02 + DSS05.03 + DSS05.04 + DSS05.05 + DSS05.07 + MEA01.01 + MEA01.02 + MEA01.03 + MEA01.04 + MEA01.05 + MEA02.01 + 3.1.7 + CCI-000172 + CCI-000130 + CCI-000135 + CCI-000169 + CCI-002884 + 164.308(a)(1)(ii)(D) + 164.308(a)(3)(ii)(A) + 164.308(a)(5)(ii)(C) + 164.312(a)(2)(i) + 164.312(b) + 164.312(d) + 164.312(e) + 4.2.3.10 + 4.3.2.6.7 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.3.6.6 + 4.3.4.4.7 + 4.3.4.5.6 + 4.3.4.5.7 + 4.3.4.5.8 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 1.13 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.6 + SR 2.8 + SR 2.9 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 6.1 + SR 6.2 + SR 7.1 + SR 7.6 + A.11.2.6 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.13.1.1 + A.13.2.1 + A.14.1.3 + A.14.2.7 + A.15.2.1 + A.15.2.2 + A.16.1.4 + A.16.1.5 + A.16.1.7 + A.6.2.1 + A.6.2.2 + AU-2(d) + AU-12(c) + CM-6(a) + DE.AE-3 + DE.AE-5 + DE.CM-1 + DE.CM-3 + DE.CM-7 + ID.SC-4 + PR.AC-3 + PR.PT-1 + PR.PT-4 + RS.AN-1 + RS.AN-4 + Req-10.5.5 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000458-GPOS-00203 + SRG-OS-000462-GPOS-00206 + SRG-OS-000463-GPOS-00207 + SRG-OS-000471-GPOS-00215 + SRG-OS-000474-GPOS-00219 + SRG-OS-000466-GPOS-00210 + SRG-OS-000468-GPOS-00212 + SRG-OS-000064-GPOS-00033 + SRG-APP-000091-CTR-000160 + SRG-APP-000492-CTR-001220 + SRG-APP-000493-CTR-001225 + SRG-APP-000494-CTR-001230 + SRG-APP-000500-CTR-001260 + SRG-APP-000507-CTR-001295 + SRG-APP-000495-CTR-001235 + SRG-APP-000496-CTR-001240 + SRG-APP-000497-CTR-001245 + SRG-APP-000498-CTR-001250 + SRG-APP-000499-CTR-001255 + R73 + A.3.SEC-OL7 + 10.3.4 + 10.3 + OL09-00-000545 + SV-271536r1092492_rule + The changing of file permissions could indicate that a user is attempting to gain access to information that would otherwise be disallowed. Auditing DAC modifications can facilitate the identification of patterns of abuse among both authorized and -unauthorized users. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +unauthorized users. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then # First perform the remediation of the syscall rule # Retrieve hardware architecture of the underlying system @@ -57860,7 +138685,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -57876,7 +138700,7 @@ then if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -57968,7 +138792,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -58021,7 +138845,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -58115,7 +138938,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -58143,17 +138966,19 @@ done else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000545 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_dac_modification_fremovexattr - low_complexity @@ -58167,16 +138992,18 @@ fi audit_arch: b64 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - ansible_architecture == "aarch64" or ansible_architecture == "ppc64" or ansible_architecture == "ppc64le" or ansible_architecture == "s390x" or ansible_architecture == "x86_64" tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000545 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_dac_modification_fremovexattr - low_complexity @@ -58254,6 +139081,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -58262,7 +139090,7 @@ fi line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -58306,6 +139134,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -58314,19 +139143,21 @@ fi line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000545 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_dac_modification_fremovexattr - low_complexity @@ -58404,6 +139235,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -58412,7 +139244,7 @@ fi line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -58456,6 +139288,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -58464,20 +139297,22 @@ fi line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - audit_arch == "b64" tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000545 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_dac_modification_fremovexattr - low_complexity @@ -58485,180 +139320,195 @@ fi - medium_severity - reboot_required - restrict_strategy - - - - - - - - - - Record Events that Modify the System's Discretionary Access Controls - fsetxattr - At a minimum, the audit system should collect file permission + + + + + + + + + + Record Events that Modify the System's Discretionary Access Controls - fsetxattr + At a minimum, the audit system should collect file permission changes for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following line to a file with suffix .rules in the directory /etc/audit/rules.d: -a always,exit -F arch=b32 -S fsetxattr -F auid>=1000 -F auid!=unset -F key=perm_mod --a always,exit -F arch=b32 -S fsetxattr -F auid=0 -F key=perm_mod + -a always,exit -F arch=b32 -S fsetxattr -F auid=0 -F key=perm_mod If the system is 64 bit then also add the following line: -a always,exit -F arch=b64 -S fsetxattr -F auid>=1000 -F auid!=unset -F key=perm_mod --a always,exit -F arch=b64 -S fsetxattr -F auid=0 -F key=perm_mod + -a always,exit -F arch=b64 -S fsetxattr -F auid=0 -F key=perm_mod If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following line to /etc/audit/audit.rules file: -a always,exit -F arch=b32 -S fsetxattr -F auid>=1000 -F auid!=unset -F key=perm_mod --a always,exit -F arch=b32 -S fsetxattr -F auid=0 -F key=perm_mod + -a always,exit -F arch=b32 -S fsetxattr -F auid=0 -F key=perm_mod If the system is 64 bit then also add the following line: -a always,exit -F arch=b64 -S fsetxattr -F auid>=1000 -F auid!=unset -F key=perm_mod --a always,exit -F arch=b64 -S fsetxattr -F auid=0 -F key=perm_mod - Note that these rules can be configured in a + -a always,exit -F arch=b64 -S fsetxattr -F auid=0 -F key=perm_mod + + Note that these rules can be configured in a number of ways while still achieving the desired effect. Here the system calls have been placed independent of other system calls. Grouping these system -calls with others as identifying earlier in this guide is more efficient. - BP28(R73) - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 19 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 5.4.1.1 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - APO12.06 - APO13.01 - BAI03.05 - BAI08.02 - DSS01.03 - DSS01.04 - DSS02.02 - DSS02.04 - DSS02.07 - DSS03.01 - DSS03.05 - DSS05.02 - DSS05.03 - DSS05.04 - DSS05.05 - DSS05.07 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.1.7 - CCI-000126 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-000172 - CCI-002884 - 164.308(a)(1)(ii)(D) - 164.308(a)(3)(ii)(A) - 164.308(a)(5)(ii)(C) - 164.312(a)(2)(i) - 164.312(b) - 164.312(d) - 164.312(e) - 4.2.3.10 - 4.3.2.6.7 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.3.6.6 - 4.3.4.4.7 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 1.13 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.6 - SR 2.8 - SR 2.9 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 6.1 - SR 6.2 - SR 7.1 - SR 7.6 - A.11.2.6 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.14.2.7 - A.15.2.1 - A.15.2.2 - A.16.1.4 - A.16.1.5 - A.16.1.7 - A.6.2.1 - A.6.2.2 - AU-2(d) - AU-12(c) - CM-6(a) - DE.AE-3 - DE.AE-5 - DE.CM-1 - DE.CM-3 - DE.CM-7 - ID.SC-4 - PR.AC-3 - PR.PT-1 - PR.PT-4 - RS.AN-1 - RS.AN-4 - FAU_GEN.1.1.c - Req-10.5.5 - 10.3.4 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000458-GPOS-00203 - SRG-OS-000462-GPOS-00206 - SRG-OS-000463-GPOS-00207 - SRG-OS-000466-GPOS-00210 - SRG-OS-000468-GPOS-00212 - SRG-OS-000471-GPOS-00215 - SRG-OS-000474-GPOS-00219 - SRG-OS-000064-GPOS-00033 - The changing of file permissions could indicate that a user is attempting to +calls with others as identifying earlier in this guide is more efficient. + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 19 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 5.4.1.1 + APO10.01 + APO10.03 + APO10.04 + APO10.05 + APO11.04 + APO12.06 + APO13.01 + BAI03.05 + BAI08.02 + DSS01.03 + DSS01.04 + DSS02.02 + DSS02.04 + DSS02.07 + DSS03.01 + DSS03.05 + DSS05.02 + DSS05.03 + DSS05.04 + DSS05.05 + DSS05.07 + MEA01.01 + MEA01.02 + MEA01.03 + MEA01.04 + MEA01.05 + MEA02.01 + 3.1.7 + CCI-000172 + CCI-000130 + CCI-000135 + CCI-000169 + CCI-002884 + 164.308(a)(1)(ii)(D) + 164.308(a)(3)(ii)(A) + 164.308(a)(5)(ii)(C) + 164.312(a)(2)(i) + 164.312(b) + 164.312(d) + 164.312(e) + 4.2.3.10 + 4.3.2.6.7 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.3.6.6 + 4.3.4.4.7 + 4.3.4.5.6 + 4.3.4.5.7 + 4.3.4.5.8 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 1.13 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.6 + SR 2.8 + SR 2.9 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 6.1 + SR 6.2 + SR 7.1 + SR 7.6 + A.11.2.6 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.13.1.1 + A.13.2.1 + A.14.1.3 + A.14.2.7 + A.15.2.1 + A.15.2.2 + A.16.1.4 + A.16.1.5 + A.16.1.7 + A.6.2.1 + A.6.2.2 + AU-2(d) + AU-12(c) + CM-6(a) + DE.AE-3 + DE.AE-5 + DE.CM-1 + DE.CM-3 + DE.CM-7 + ID.SC-4 + PR.AC-3 + PR.PT-1 + PR.PT-4 + RS.AN-1 + RS.AN-4 + Req-10.5.5 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000458-GPOS-00203 + SRG-OS-000462-GPOS-00206 + SRG-OS-000463-GPOS-00207 + SRG-OS-000466-GPOS-00210 + SRG-OS-000468-GPOS-00212 + SRG-OS-000471-GPOS-00215 + SRG-OS-000474-GPOS-00219 + SRG-OS-000064-GPOS-00033 + SRG-APP-000091-CTR-000160 + SRG-APP-000492-CTR-001220 + SRG-APP-000493-CTR-001225 + SRG-APP-000494-CTR-001230 + SRG-APP-000500-CTR-001260 + SRG-APP-000507-CTR-001295 + SRG-APP-000495-CTR-001235 + SRG-APP-000496-CTR-001240 + SRG-APP-000497-CTR-001245 + SRG-APP-000498-CTR-001250 + SRG-APP-000501-CTR-001265 + SRG-APP-000502-CTR-001270 + R73 + A.3.SEC-OL7 + 10.3.4 + 10.3 + OL09-00-000545 + SV-271536r1092492_rule + The changing of file permissions could indicate that a user is attempting to gain access to information that would otherwise be disallowed. Auditing DAC modifications can facilitate the identification of patterns of abuse among both authorized and -unauthorized users. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +unauthorized users. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then # First perform the remediation of the syscall rule # Retrieve hardware architecture of the underlying system @@ -58703,7 +139553,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -58719,7 +139568,7 @@ then if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -58811,7 +139660,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -58864,7 +139713,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -58958,7 +139806,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -58986,17 +139834,19 @@ done else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000545 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_dac_modification_fsetxattr - low_complexity @@ -59010,16 +139860,18 @@ fi audit_arch: b64 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - ansible_architecture == "aarch64" or ansible_architecture == "ppc64" or ansible_architecture == "ppc64le" or ansible_architecture == "s390x" or ansible_architecture == "x86_64" tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000545 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_dac_modification_fsetxattr - low_complexity @@ -59097,6 +139949,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -59105,7 +139958,7 @@ fi line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -59149,6 +140002,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -59157,19 +140011,21 @@ fi line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000545 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_dac_modification_fsetxattr - low_complexity @@ -59247,6 +140103,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -59255,7 +140112,7 @@ fi line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -59299,6 +140156,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -59307,20 +140165,22 @@ fi line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - audit_arch == "b64" tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000545 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_dac_modification_fsetxattr - low_complexity @@ -59328,17 +140188,17 @@ fi - medium_severity - reboot_required - restrict_strategy - - - - - - - - - - Record Events that Modify the System's Discretionary Access Controls - lchown - At a minimum, the audit system should collect file permission + + + + + + + + + + Record Events that Modify the System's Discretionary Access Controls - lchown + At a minimum, the audit system should collect file permission changes for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following line to a file with suffix @@ -59351,151 +140211,163 @@ utility to read audit rules during daemon startup, add the following line to /etc/audit/audit.rules file: -a always,exit -F arch=b32 -S lchown -F auid>=1000 -F auid!=unset -F key=perm_mod If the system is 64 bit then also add the following line: --a always,exit -F arch=b64 -S lchown -F auid>=1000 -F auid!=unset -F key=perm_mod - Note that these rules can be configured in a +-a always,exit -F arch=b64 -S lchown -F auid>=1000 -F auid!=unset -F key=perm_mod + + Note that these rules can be configured in a number of ways while still achieving the desired effect. Here the system calls have been placed independent of other system calls. Grouping these system -calls with others as identifying earlier in this guide is more efficient. - BP28(R73) - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 19 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 5.4.1.1 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - APO12.06 - APO13.01 - BAI03.05 - BAI08.02 - DSS01.03 - DSS01.04 - DSS02.02 - DSS02.04 - DSS02.07 - DSS03.01 - DSS03.05 - DSS05.02 - DSS05.03 - DSS05.04 - DSS05.05 - DSS05.07 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.1.7 - CCI-000126 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-000172 - CCI-002884 - 164.308(a)(1)(ii)(D) - 164.308(a)(3)(ii)(A) - 164.308(a)(5)(ii)(C) - 164.312(a)(2)(i) - 164.312(b) - 164.312(d) - 164.312(e) - 4.2.3.10 - 4.3.2.6.7 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.3.6.6 - 4.3.4.4.7 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 1.13 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.6 - SR 2.8 - SR 2.9 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 6.1 - SR 6.2 - SR 7.1 - SR 7.6 - A.11.2.6 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.14.2.7 - A.15.2.1 - A.15.2.2 - A.16.1.4 - A.16.1.5 - A.16.1.7 - A.6.2.1 - A.6.2.2 - AU-2(d) - AU-12(c) - CM-6(a) - DE.AE-3 - DE.AE-5 - DE.CM-1 - DE.CM-3 - DE.CM-7 - ID.SC-4 - PR.AC-3 - PR.PT-1 - PR.PT-4 - RS.AN-1 - RS.AN-4 - FAU_GEN.1.1.c - Req-10.5.5 - 10.3.4 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-OS-000064-GPOS-00033 - SRG-OS-000466-GPOS-00210 - SRG-OS-000458-GPOS-00203 - SRG-OS-000474-GPOS-00219 - The changing of file permissions could indicate that a user is attempting to +calls with others as identifying earlier in this guide is more efficient. + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 19 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 5.4.1.1 + APO10.01 + APO10.03 + APO10.04 + APO10.05 + APO11.04 + APO12.06 + APO13.01 + BAI03.05 + BAI08.02 + DSS01.03 + DSS01.04 + DSS02.02 + DSS02.04 + DSS02.07 + DSS03.01 + DSS03.05 + DSS05.02 + DSS05.03 + DSS05.04 + DSS05.05 + DSS05.07 + MEA01.01 + MEA01.02 + MEA01.03 + MEA01.04 + MEA01.05 + MEA02.01 + 3.1.7 + CCI-000172 + CCI-000130 + CCI-000135 + CCI-000169 + CCI-002884 + 164.308(a)(1)(ii)(D) + 164.308(a)(3)(ii)(A) + 164.308(a)(5)(ii)(C) + 164.312(a)(2)(i) + 164.312(b) + 164.312(d) + 164.312(e) + 4.2.3.10 + 4.3.2.6.7 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.3.6.6 + 4.3.4.4.7 + 4.3.4.5.6 + 4.3.4.5.7 + 4.3.4.5.8 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 1.13 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.6 + SR 2.8 + SR 2.9 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 6.1 + SR 6.2 + SR 7.1 + SR 7.6 + A.11.2.6 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.13.1.1 + A.13.2.1 + A.14.1.3 + A.14.2.7 + A.15.2.1 + A.15.2.2 + A.16.1.4 + A.16.1.5 + A.16.1.7 + A.6.2.1 + A.6.2.2 + AU-2(d) + AU-12(c) + CM-6(a) + DE.AE-3 + DE.AE-5 + DE.CM-1 + DE.CM-3 + DE.CM-7 + ID.SC-4 + PR.AC-3 + PR.PT-1 + PR.PT-4 + RS.AN-1 + RS.AN-4 + Req-10.5.5 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-OS-000064-GPOS-00033 + SRG-OS-000466-GPOS-00210 + SRG-OS-000458-GPOS-00203 + SRG-OS-000474-GPOS-00219 + SRG-APP-000091-CTR-000160 + SRG-APP-000492-CTR-001220 + SRG-APP-000493-CTR-001225 + SRG-APP-000494-CTR-001230 + SRG-APP-000500-CTR-001260 + SRG-APP-000507-CTR-001295 + SRG-APP-000495-CTR-001235 + SRG-APP-000499-CTR-001255 + R73 + A.3.SEC-OL7 + 10.3.4 + 10.3 + OL09-00-000645 + SV-271556r1092532_rule + The changing of file permissions could indicate that a user is attempting to gain access to information that would otherwise be disallowed. Auditing DAC modifications can facilitate the identification of patterns of abuse among both authorized and -unauthorized users. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +unauthorized users. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { ! ( ( grep -sqE "^.*\.aarch64$" /proc/sys/kernel/osrelease || grep -sqE "^aarch64$" /proc/sys/kernel/arch; ) ); }; then # First perform the remediation of the syscall rule # Retrieve hardware architecture of the underlying system @@ -59540,7 +140412,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -59556,7 +140427,7 @@ then if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -59648,7 +140519,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -59701,7 +140572,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -59795,7 +140665,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -59823,17 +140693,19 @@ done else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000645 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_dac_modification_lchown - low_complexity @@ -59847,16 +140719,19 @@ fi audit_arch: b64 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - not ( ansible_architecture == "aarch64" ) - ansible_architecture == "aarch64" or ansible_architecture == "ppc64" or ansible_architecture == "ppc64le" or ansible_architecture == "s390x" or ansible_architecture == "x86_64" tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000645 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_dac_modification_lchown - low_complexity @@ -59932,6 +140807,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -59940,7 +140816,7 @@ fi line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -59982,6 +140858,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -59990,19 +140867,22 @@ fi line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - not ( ansible_architecture == "aarch64" ) tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000645 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_dac_modification_lchown - low_complexity @@ -60078,6 +140958,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -60086,7 +140967,7 @@ fi line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -60128,6 +141009,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -60136,20 +141018,23 @@ fi line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - not ( ansible_architecture == "aarch64" ) - audit_arch == "b64" tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000645 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_dac_modification_lchown - low_complexity @@ -60157,184 +141042,205 @@ fi - medium_severity - reboot_required - restrict_strategy - - - - - - - - - - Record Events that Modify the System's Discretionary Access Controls - lremovexattr - At a minimum, the audit system should collect file permission + + + + + + + + + + Record Events that Modify the System's Discretionary Access Controls - lremovexattr + At a minimum, the audit system should collect file permission changes for all users and root. - + + If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following line to a file with suffix .rules in the directory /etc/audit/rules.d: -a always,exit -F arch=b32 -S lremovexattr -F auid>=1000 -F auid!=unset -F key=perm_mod --a always,exit -F arch=b32 -S lremovexattr -F auid=0 -F key=perm_mod - + -a always,exit -F arch=b32 -S lremovexattr -F auid=0 -F key=perm_mod + + If the system is 64 bit then also add the following line: -a always,exit -F arch=b64 -S lremovexattr -F auid>=1000 -F auid!=unset -F key=perm_mod --a always,exit -F arch=b64 -S lremovexattr -F auid=0 -F key=perm_mod - + -a always,exit -F arch=b64 -S lremovexattr -F auid=0 -F key=perm_mod + + If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following line to /etc/audit/audit.rules file: -a always,exit -F arch=b32 -S lremovexattr -F auid>=1000 -F auid!=unset -F key=perm_mod --a always,exit -F arch=b32 -S lremovexattr -F auid=0 -F key=perm_mod - + -a always,exit -F arch=b32 -S lremovexattr -F auid=0 -F key=perm_mod + + If the system is 64 bit then also add the following line: -a always,exit -F arch=b64 -S lremovexattr -F auid>=1000 -F auid!=unset -F key=perm_mod --a always,exit -F arch=b64 -S lremovexattr -F auid=0 -F key=perm_mod - Note that these rules can be configured in a + -a always,exit -F arch=b64 -S lremovexattr -F auid=0 -F key=perm_mod + + Note that these rules can be configured in a number of ways while still achieving the desired effect. Here the system calls have been placed independent of other system calls. Grouping these system -calls with others as identifying earlier in this guide is more efficient. - BP28(R73) - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 19 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 5.4.1.1 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - APO12.06 - APO13.01 - BAI03.05 - BAI08.02 - DSS01.03 - DSS01.04 - DSS02.02 - DSS02.04 - DSS02.07 - DSS03.01 - DSS03.05 - DSS05.02 - DSS05.03 - DSS05.04 - DSS05.05 - DSS05.07 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.1.7 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-000172 - CCI-002884 - 164.308(a)(1)(ii)(D) - 164.308(a)(3)(ii)(A) - 164.308(a)(5)(ii)(C) - 164.312(a)(2)(i) - 164.312(b) - 164.312(d) - 164.312(e) - 4.2.3.10 - 4.3.2.6.7 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.3.6.6 - 4.3.4.4.7 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 1.13 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.6 - SR 2.8 - SR 2.9 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 6.1 - SR 6.2 - SR 7.1 - SR 7.6 - A.11.2.6 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.14.2.7 - A.15.2.1 - A.15.2.2 - A.16.1.4 - A.16.1.5 - A.16.1.7 - A.6.2.1 - A.6.2.2 - AU-2(d) - AU-12(c) - CM-6(a) - DE.AE-3 - DE.AE-5 - DE.CM-1 - DE.CM-3 - DE.CM-7 - ID.SC-4 - PR.AC-3 - PR.PT-1 - PR.PT-4 - RS.AN-1 - RS.AN-4 - FAU_GEN.1.1.c - Req-10.5.5 - 10.3.4 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000458-GPOS-00203 - SRG-OS-000462-GPOS-00206 - SRG-OS-000463-GPOS-00207 - SRG-OS-000468-GPOS-00212 - SRG-OS-000471-GPOS-00215 - SRG-OS-000474-GPOS-00219 - SRG-OS-000466-GPOS-00210 - SRG-OS-000064-GPOS-00033 - The changing of file permissions could indicate that a user is attempting to +calls with others as identifying earlier in this guide is more efficient. + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 19 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 5.4.1.1 + APO10.01 + APO10.03 + APO10.04 + APO10.05 + APO11.04 + APO12.06 + APO13.01 + BAI03.05 + BAI08.02 + DSS01.03 + DSS01.04 + DSS02.02 + DSS02.04 + DSS02.07 + DSS03.01 + DSS03.05 + DSS05.02 + DSS05.03 + DSS05.04 + DSS05.05 + DSS05.07 + MEA01.01 + MEA01.02 + MEA01.03 + MEA01.04 + MEA01.05 + MEA02.01 + 3.1.7 + CCI-000172 + CCI-000130 + CCI-000135 + CCI-000169 + CCI-002884 + 164.308(a)(1)(ii)(D) + 164.308(a)(3)(ii)(A) + 164.308(a)(5)(ii)(C) + 164.312(a)(2)(i) + 164.312(b) + 164.312(d) + 164.312(e) + 4.2.3.10 + 4.3.2.6.7 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.3.6.6 + 4.3.4.4.7 + 4.3.4.5.6 + 4.3.4.5.7 + 4.3.4.5.8 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 1.13 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.6 + SR 2.8 + SR 2.9 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 6.1 + SR 6.2 + SR 7.1 + SR 7.6 + A.11.2.6 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.13.1.1 + A.13.2.1 + A.14.1.3 + A.14.2.7 + A.15.2.1 + A.15.2.2 + A.16.1.4 + A.16.1.5 + A.16.1.7 + A.6.2.1 + A.6.2.2 + AU-2(d) + AU-12(c) + CM-6(a) + DE.AE-3 + DE.AE-5 + DE.CM-1 + DE.CM-3 + DE.CM-7 + ID.SC-4 + PR.AC-3 + PR.PT-1 + PR.PT-4 + RS.AN-1 + RS.AN-4 + Req-10.5.5 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000458-GPOS-00203 + SRG-OS-000462-GPOS-00206 + SRG-OS-000463-GPOS-00207 + SRG-OS-000468-GPOS-00212 + SRG-OS-000471-GPOS-00215 + SRG-OS-000474-GPOS-00219 + SRG-OS-000466-GPOS-00210 + SRG-OS-000064-GPOS-00033 + SRG-APP-000091-CTR-000160 + SRG-APP-000492-CTR-001220 + SRG-APP-000493-CTR-001225 + SRG-APP-000494-CTR-001230 + SRG-APP-000500-CTR-001260 + SRG-APP-000507-CTR-001295 + SRG-APP-000495-CTR-001235 + SRG-APP-000496-CTR-001240 + SRG-APP-000497-CTR-001245 + SRG-APP-000498-CTR-001250 + SRG-APP-000499-CTR-001255 + SRG-APP-000501-CTR-001265 + SRG-APP-000502-CTR-001270 + R73 + A.3.SEC-OL7 + 10.3.4 + 10.3 + OL09-00-000545 + SV-271536r1092492_rule + The changing of file permissions could indicate that a user is attempting to gain access to information that would otherwise be disallowed. Auditing DAC modifications can facilitate the identification of patterns of abuse among both authorized and -unauthorized users. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +unauthorized users. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then # First perform the remediation of the syscall rule # Retrieve hardware architecture of the underlying system @@ -60379,7 +141285,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -60395,7 +141300,7 @@ then if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -60487,7 +141392,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -60540,7 +141445,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -60634,7 +141538,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -60662,17 +141566,19 @@ done else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000545 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_dac_modification_lremovexattr - low_complexity @@ -60686,16 +141592,18 @@ fi audit_arch: b64 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - ansible_architecture == "aarch64" or ansible_architecture == "ppc64" or ansible_architecture == "ppc64le" or ansible_architecture == "s390x" or ansible_architecture == "x86_64" tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000545 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_dac_modification_lremovexattr - low_complexity @@ -60773,6 +141681,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -60781,7 +141690,7 @@ fi line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -60825,6 +141734,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -60833,19 +141743,21 @@ fi line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000545 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_dac_modification_lremovexattr - low_complexity @@ -60923,6 +141835,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -60931,7 +141844,7 @@ fi line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -60975,6 +141888,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -60983,20 +141897,22 @@ fi line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - audit_arch == "b64" tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000545 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_dac_modification_lremovexattr - low_complexity @@ -61004,180 +141920,195 @@ fi - medium_severity - reboot_required - restrict_strategy - - - - - - - - - - Record Events that Modify the System's Discretionary Access Controls - lsetxattr - At a minimum, the audit system should collect file permission + + + + + + + + + + Record Events that Modify the System's Discretionary Access Controls - lsetxattr + At a minimum, the audit system should collect file permission changes for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following line to a file with suffix .rules in the directory /etc/audit/rules.d: -a always,exit -F arch=b32 -S lsetxattr -F auid>=1000 -F auid!=unset -F key=perm_mod --a always,exit -F arch=b32 -S lsetxattr -F auid=0 -F key=perm_mod + -a always,exit -F arch=b32 -S lsetxattr -F auid=0 -F key=perm_mod If the system is 64 bit then also add the following line: -a always,exit -F arch=b64 -S lsetxattr -F auid>=1000 -F auid!=unset -F key=perm_mod --a always,exit -F arch=b64 -S lsetxattr -F auid=0 -F key=perm_mod + -a always,exit -F arch=b64 -S lsetxattr -F auid=0 -F key=perm_mod If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following line to /etc/audit/audit.rules file: -a always,exit -F arch=b32 -S lsetxattr -F auid>=1000 -F auid!=unset -F key=perm_mod --a always,exit -F arch=b32 -S lsetxattr -F auid=0 -F key=perm_mod + -a always,exit -F arch=b32 -S lsetxattr -F auid=0 -F key=perm_mod If the system is 64 bit then also add the following line: -a always,exit -F arch=b64 -S lsetxattr -F auid>=1000 -F auid!=unset -F key=perm_mod --a always,exit -F arch=b64 -S lsetxattr -F auid=0 -F key=perm_mod - Note that these rules can be configured in a + -a always,exit -F arch=b64 -S lsetxattr -F auid=0 -F key=perm_mod + + Note that these rules can be configured in a number of ways while still achieving the desired effect. Here the system calls have been placed independent of other system calls. Grouping these system -calls with others as identifying earlier in this guide is more efficient. - BP28(R73) - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 19 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 5.4.1.1 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - APO12.06 - APO13.01 - BAI03.05 - BAI08.02 - DSS01.03 - DSS01.04 - DSS02.02 - DSS02.04 - DSS02.07 - DSS03.01 - DSS03.05 - DSS05.02 - DSS05.03 - DSS05.04 - DSS05.05 - DSS05.07 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.1.7 - CCI-000126 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-000172 - CCI-002884 - 164.308(a)(1)(ii)(D) - 164.308(a)(3)(ii)(A) - 164.308(a)(5)(ii)(C) - 164.312(a)(2)(i) - 164.312(b) - 164.312(d) - 164.312(e) - 4.2.3.10 - 4.3.2.6.7 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.3.6.6 - 4.3.4.4.7 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 1.13 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.6 - SR 2.8 - SR 2.9 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 6.1 - SR 6.2 - SR 7.1 - SR 7.6 - A.11.2.6 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.14.2.7 - A.15.2.1 - A.15.2.2 - A.16.1.4 - A.16.1.5 - A.16.1.7 - A.6.2.1 - A.6.2.2 - AU-2(d) - AU-12(c) - CM-6(a) - DE.AE-3 - DE.AE-5 - DE.CM-1 - DE.CM-3 - DE.CM-7 - ID.SC-4 - PR.AC-3 - PR.PT-1 - PR.PT-4 - RS.AN-1 - RS.AN-4 - FAU_GEN.1.1.c - Req-10.5.5 - 10.3.4 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000458-GPOS-00203 - SRG-OS-000462-GPOS-00206 - SRG-OS-000463-GPOS-00207 - SRG-OS-000466-GPOS-00210 - SRG-OS-000468-GPOS-00212 - SRG-OS-000471-GPOS-00215 - SRG-OS-000474-GPOS-00219 - SRG-OS-000064-GPOS-00033 - The changing of file permissions could indicate that a user is attempting to +calls with others as identifying earlier in this guide is more efficient. + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 19 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 5.4.1.1 + APO10.01 + APO10.03 + APO10.04 + APO10.05 + APO11.04 + APO12.06 + APO13.01 + BAI03.05 + BAI08.02 + DSS01.03 + DSS01.04 + DSS02.02 + DSS02.04 + DSS02.07 + DSS03.01 + DSS03.05 + DSS05.02 + DSS05.03 + DSS05.04 + DSS05.05 + DSS05.07 + MEA01.01 + MEA01.02 + MEA01.03 + MEA01.04 + MEA01.05 + MEA02.01 + 3.1.7 + CCI-000172 + CCI-000130 + CCI-000135 + CCI-000169 + CCI-002884 + 164.308(a)(1)(ii)(D) + 164.308(a)(3)(ii)(A) + 164.308(a)(5)(ii)(C) + 164.312(a)(2)(i) + 164.312(b) + 164.312(d) + 164.312(e) + 4.2.3.10 + 4.3.2.6.7 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.3.6.6 + 4.3.4.4.7 + 4.3.4.5.6 + 4.3.4.5.7 + 4.3.4.5.8 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 1.13 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.6 + SR 2.8 + SR 2.9 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 6.1 + SR 6.2 + SR 7.1 + SR 7.6 + A.11.2.6 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.13.1.1 + A.13.2.1 + A.14.1.3 + A.14.2.7 + A.15.2.1 + A.15.2.2 + A.16.1.4 + A.16.1.5 + A.16.1.7 + A.6.2.1 + A.6.2.2 + AU-2(d) + AU-12(c) + CM-6(a) + DE.AE-3 + DE.AE-5 + DE.CM-1 + DE.CM-3 + DE.CM-7 + ID.SC-4 + PR.AC-3 + PR.PT-1 + PR.PT-4 + RS.AN-1 + RS.AN-4 + Req-10.5.5 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000458-GPOS-00203 + SRG-OS-000462-GPOS-00206 + SRG-OS-000463-GPOS-00207 + SRG-OS-000466-GPOS-00210 + SRG-OS-000468-GPOS-00212 + SRG-OS-000471-GPOS-00215 + SRG-OS-000474-GPOS-00219 + SRG-OS-000064-GPOS-00033 + SRG-APP-000091-CTR-000160 + SRG-APP-000492-CTR-001220 + SRG-APP-000493-CTR-001225 + SRG-APP-000494-CTR-001230 + SRG-APP-000500-CTR-001260 + SRG-APP-000507-CTR-001295 + SRG-APP-000495-CTR-001235 + SRG-APP-000496-CTR-001240 + SRG-APP-000497-CTR-001245 + SRG-APP-000498-CTR-001250 + SRG-APP-000501-CTR-001265 + SRG-APP-000502-CTR-001270 + R73 + A.3.SEC-OL7 + 10.3.4 + 10.3 + OL09-00-000545 + SV-271536r1092492_rule + The changing of file permissions could indicate that a user is attempting to gain access to information that would otherwise be disallowed. Auditing DAC modifications can facilitate the identification of patterns of abuse among both authorized and -unauthorized users. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +unauthorized users. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then # First perform the remediation of the syscall rule # Retrieve hardware architecture of the underlying system @@ -61222,7 +142153,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -61238,7 +142168,7 @@ then if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -61330,7 +142260,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -61383,7 +142313,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -61477,7 +142406,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -61505,17 +142434,19 @@ done else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000545 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_dac_modification_lsetxattr - low_complexity @@ -61529,16 +142460,18 @@ fi audit_arch: b64 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - ansible_architecture == "aarch64" or ansible_architecture == "ppc64" or ansible_architecture == "ppc64le" or ansible_architecture == "s390x" or ansible_architecture == "x86_64" tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000545 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_dac_modification_lsetxattr - low_complexity @@ -61616,6 +142549,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -61624,7 +142558,7 @@ fi line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -61668,6 +142602,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -61676,19 +142611,21 @@ fi line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000545 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_dac_modification_lsetxattr - low_complexity @@ -61766,6 +142703,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -61774,7 +142712,7 @@ fi line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -61818,6 +142756,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -61826,20 +142765,22 @@ fi line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - audit_arch == "b64" tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000545 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_dac_modification_lsetxattr - low_complexity @@ -61847,183 +142788,204 @@ fi - medium_severity - reboot_required - restrict_strategy - - - - - - - - - - Record Events that Modify the System's Discretionary Access Controls - removexattr - At a minimum, the audit system should collect file permission + + + + + + + + + + Record Events that Modify the System's Discretionary Access Controls - removexattr + At a minimum, the audit system should collect file permission changes for all users and root. - + + If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following line to a file with suffix .rules in the directory /etc/audit/rules.d: -a always,exit -F arch=b32 -S removexattr -F auid>=1000 -F auid!=unset -F key=perm_mod --a always,exit -F arch=b32 -S removexattr -F auid=0 -F key=perm_mod - + -a always,exit -F arch=b32 -S removexattr -F auid=0 -F key=perm_mod + + If the system is 64 bit then also add the following line: -a always,exit -F arch=b64 -S removexattr -F auid>=1000 -F auid!=unset -F key=perm_mod --a always,exit -F arch=b64 -S removexattr -F auid=0 -F key=perm_mod - + -a always,exit -F arch=b64 -S removexattr -F auid=0 -F key=perm_mod + + If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following line to /etc/audit/audit.rules file: -a always,exit -F arch=b32 -S removexattr -F auid>=1000 -F auid!=unset -F key=perm_mod --a always,exit -F arch=b32 -S removexattr -F auid=0 -F key=perm_mod - + -a always,exit -F arch=b32 -S removexattr -F auid=0 -F key=perm_mod + + If the system is 64 bit then also add the following line: -a always,exit -F arch=b64 -S removexattr -F auid>=1000 -F auid!=unset -F key=perm_mod --a always,exit -F arch=b64 -S removexattr -F auid=0 -F key=perm_mod - Note that these rules can be configured in a + -a always,exit -F arch=b64 -S removexattr -F auid=0 -F key=perm_mod + + Note that these rules can be configured in a number of ways while still achieving the desired effect. Here the system calls have been placed independent of other system calls. Grouping these system -calls with others as identifying earlier in this guide is more efficient. - BP28(R73) - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 19 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 5.4.1.1 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - APO12.06 - APO13.01 - BAI03.05 - BAI08.02 - DSS01.03 - DSS01.04 - DSS02.02 - DSS02.04 - DSS02.07 - DSS03.01 - DSS03.05 - DSS05.02 - DSS05.03 - DSS05.04 - DSS05.05 - DSS05.07 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.1.7 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-000172 - CCI-002884 - 164.308(a)(1)(ii)(D) - 164.308(a)(3)(ii)(A) - 164.308(a)(5)(ii)(C) - 164.312(a)(2)(i) - 164.312(b) - 164.312(d) - 164.312(e) - 4.2.3.10 - 4.3.2.6.7 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.3.6.6 - 4.3.4.4.7 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 1.13 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.6 - SR 2.8 - SR 2.9 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 6.1 - SR 6.2 - SR 7.1 - SR 7.6 - A.11.2.6 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.14.2.7 - A.15.2.1 - A.15.2.2 - A.16.1.4 - A.16.1.5 - A.16.1.7 - A.6.2.1 - A.6.2.2 - AU-2(d) - AU-12(c) - CM-6(a) - DE.AE-3 - DE.AE-5 - DE.CM-1 - DE.CM-3 - DE.CM-7 - ID.SC-4 - PR.AC-3 - PR.PT-1 - PR.PT-4 - RS.AN-1 - RS.AN-4 - FAU_GEN.1.1.c - Req-10.5.5 - 10.3.4 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000458-GPOS-00203 - SRG-OS-000462-GPOS-00206 - SRG-OS-000463-GPOS-00207 - SRG-OS-000468-GPOS-00212 - SRG-OS-000471-GPOS-00215 - SRG-OS-000474-GPOS-00219 - SRG-OS-000466-GPOS-00210 - SRG-OS-000064-GPOS-00033 - The changing of file permissions could indicate that a user is attempting to +calls with others as identifying earlier in this guide is more efficient. + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 19 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 5.4.1.1 + APO10.01 + APO10.03 + APO10.04 + APO10.05 + APO11.04 + APO12.06 + APO13.01 + BAI03.05 + BAI08.02 + DSS01.03 + DSS01.04 + DSS02.02 + DSS02.04 + DSS02.07 + DSS03.01 + DSS03.05 + DSS05.02 + DSS05.03 + DSS05.04 + DSS05.05 + DSS05.07 + MEA01.01 + MEA01.02 + MEA01.03 + MEA01.04 + MEA01.05 + MEA02.01 + 3.1.7 + CCI-000172 + CCI-000130 + CCI-000135 + CCI-000169 + CCI-002884 + 164.308(a)(1)(ii)(D) + 164.308(a)(3)(ii)(A) + 164.308(a)(5)(ii)(C) + 164.312(a)(2)(i) + 164.312(b) + 164.312(d) + 164.312(e) + 4.2.3.10 + 4.3.2.6.7 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.3.6.6 + 4.3.4.4.7 + 4.3.4.5.6 + 4.3.4.5.7 + 4.3.4.5.8 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 1.13 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.6 + SR 2.8 + SR 2.9 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 6.1 + SR 6.2 + SR 7.1 + SR 7.6 + A.11.2.6 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.13.1.1 + A.13.2.1 + A.14.1.3 + A.14.2.7 + A.15.2.1 + A.15.2.2 + A.16.1.4 + A.16.1.5 + A.16.1.7 + A.6.2.1 + A.6.2.2 + AU-2(d) + AU-12(c) + CM-6(a) + DE.AE-3 + DE.AE-5 + DE.CM-1 + DE.CM-3 + DE.CM-7 + ID.SC-4 + PR.AC-3 + PR.PT-1 + PR.PT-4 + RS.AN-1 + RS.AN-4 + Req-10.5.5 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000458-GPOS-00203 + SRG-OS-000462-GPOS-00206 + SRG-OS-000463-GPOS-00207 + SRG-OS-000468-GPOS-00212 + SRG-OS-000471-GPOS-00215 + SRG-OS-000474-GPOS-00219 + SRG-OS-000466-GPOS-00210 + SRG-OS-000064-GPOS-00033 + SRG-APP-000091-CTR-000160 + SRG-APP-000492-CTR-001220 + SRG-APP-000493-CTR-001225 + SRG-APP-000494-CTR-001230 + SRG-APP-000500-CTR-001260 + SRG-APP-000507-CTR-001295 + SRG-APP-000495-CTR-001235 + SRG-APP-000496-CTR-001240 + SRG-APP-000497-CTR-001245 + SRG-APP-000498-CTR-001250 + SRG-APP-000499-CTR-001255 + SRG-APP-000501-CTR-001265 + SRG-APP-000502-CTR-001270 + R73 + A.3.SEC-OL7 + 10.3.4 + 10.3 + OL09-00-000545 + SV-271536r1092492_rule + The changing of file permissions could indicate that a user is attempting to gain access to information that would otherwise be disallowed. Auditing DAC modifications can facilitate the identification of patterns of abuse among both authorized and -unauthorized users. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +unauthorized users. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then # First perform the remediation of the syscall rule # Retrieve hardware architecture of the underlying system @@ -62068,7 +143030,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -62084,7 +143045,7 @@ then if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -62176,7 +143137,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -62229,7 +143190,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -62323,7 +143283,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -62351,17 +143311,19 @@ done else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000545 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_dac_modification_removexattr - low_complexity @@ -62375,16 +143337,18 @@ fi audit_arch: b64 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - ansible_architecture == "aarch64" or ansible_architecture == "ppc64" or ansible_architecture == "ppc64le" or ansible_architecture == "s390x" or ansible_architecture == "x86_64" tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000545 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_dac_modification_removexattr - low_complexity @@ -62462,6 +143426,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -62470,7 +143435,7 @@ fi line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -62514,6 +143479,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -62522,19 +143488,21 @@ fi line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000545 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_dac_modification_removexattr - low_complexity @@ -62612,6 +143580,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -62620,7 +143589,7 @@ fi line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -62664,6 +143633,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -62672,20 +143642,22 @@ fi line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - audit_arch == "b64" tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000545 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_dac_modification_removexattr - low_complexity @@ -62693,177 +143665,187 @@ fi - medium_severity - reboot_required - restrict_strategy - - - - - - - - - - Record Events that Modify the System's Discretionary Access Controls - setxattr - At a minimum, the audit system should collect file permission + + + + + + + + + + Record Events that Modify the System's Discretionary Access Controls - setxattr + At a minimum, the audit system should collect file permission changes for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following line to a file with suffix .rules in the directory /etc/audit/rules.d: -a always,exit -F arch=b32 -S setxattr -F auid>=1000 -F auid!=unset -F key=perm_mod --a always,exit -F arch=b32 -S setxattr -F auid=0 -F key=perm_mod + -a always,exit -F arch=b32 -S setxattr -F auid=0 -F key=perm_mod If the system is 64 bit then also add the following line: -a always,exit -F arch=b64 -S setxattr -F auid>=1000 -F auid!=unset -F key=perm_mod --a always,exit -F arch=b64 -S setxattr -F auid=0 -F key=perm_mod + -a always,exit -F arch=b64 -S setxattr -F auid=0 -F key=perm_mod If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following line to /etc/audit/audit.rules file: -a always,exit -F arch=b32 -S setxattr -F auid>=1000 -F auid!=unset -F key=perm_mod --a always,exit -F arch=b32 -S setxattr -F auid=0 -F key=perm_mod + -a always,exit -F arch=b32 -S setxattr -F auid=0 -F key=perm_mod If the system is 64 bit then also add the following line: -a always,exit -F arch=b64 -S setxattr -F auid>=1000 -F auid!=unset -F key=perm_mod --a always,exit -F arch=b64 -S setxattr -F auid=0 -F key=perm_mod - Note that these rules can be configured in a + -a always,exit -F arch=b64 -S setxattr -F auid=0 -F key=perm_mod + + Note that these rules can be configured in a number of ways while still achieving the desired effect. Here the system calls have been placed independent of other system calls. Grouping these system -calls with others as identifying earlier in this guide is more efficient. - BP28(R73) - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 19 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 5.4.1.1 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - APO12.06 - APO13.01 - BAI03.05 - BAI08.02 - DSS01.03 - DSS01.04 - DSS02.02 - DSS02.04 - DSS02.07 - DSS03.01 - DSS03.05 - DSS05.02 - DSS05.03 - DSS05.04 - DSS05.05 - DSS05.07 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.1.7 - CCI-000126 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-000172 - CCI-002884 - 164.308(a)(1)(ii)(D) - 164.308(a)(3)(ii)(A) - 164.308(a)(5)(ii)(C) - 164.312(a)(2)(i) - 164.312(b) - 164.312(d) - 164.312(e) - 4.2.3.10 - 4.3.2.6.7 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.3.6.6 - 4.3.4.4.7 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 1.13 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.6 - SR 2.8 - SR 2.9 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 6.1 - SR 6.2 - SR 7.1 - SR 7.6 - A.11.2.6 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.14.2.7 - A.15.2.1 - A.15.2.2 - A.16.1.4 - A.16.1.5 - A.16.1.7 - A.6.2.1 - A.6.2.2 - AU-2(d) - AU-12(c) - CM-6(a) - DE.AE-3 - DE.AE-5 - DE.CM-1 - DE.CM-3 - DE.CM-7 - ID.SC-4 - PR.AC-3 - PR.PT-1 - PR.PT-4 - RS.AN-1 - RS.AN-4 - FAU_GEN.1.1.c - Req-10.5.5 - 10.3.4 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000466-GPOS-00210 - SRG-OS-000471-GPOS-00215 - SRG-OS-000064-GPOS-00033 - SRG-OS-000458-GPOS-00203 - The changing of file permissions could indicate that a user is attempting to +calls with others as identifying earlier in this guide is more efficient. + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 19 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 5.4.1.1 + APO10.01 + APO10.03 + APO10.04 + APO10.05 + APO11.04 + APO12.06 + APO13.01 + BAI03.05 + BAI08.02 + DSS01.03 + DSS01.04 + DSS02.02 + DSS02.04 + DSS02.07 + DSS03.01 + DSS03.05 + DSS05.02 + DSS05.03 + DSS05.04 + DSS05.05 + DSS05.07 + MEA01.01 + MEA01.02 + MEA01.03 + MEA01.04 + MEA01.05 + MEA02.01 + 3.1.7 + CCI-000172 + CCI-000130 + CCI-000135 + CCI-000169 + CCI-002884 + 164.308(a)(1)(ii)(D) + 164.308(a)(3)(ii)(A) + 164.308(a)(5)(ii)(C) + 164.312(a)(2)(i) + 164.312(b) + 164.312(d) + 164.312(e) + 4.2.3.10 + 4.3.2.6.7 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.3.6.6 + 4.3.4.4.7 + 4.3.4.5.6 + 4.3.4.5.7 + 4.3.4.5.8 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 1.13 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.6 + SR 2.8 + SR 2.9 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 6.1 + SR 6.2 + SR 7.1 + SR 7.6 + A.11.2.6 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.13.1.1 + A.13.2.1 + A.14.1.3 + A.14.2.7 + A.15.2.1 + A.15.2.2 + A.16.1.4 + A.16.1.5 + A.16.1.7 + A.6.2.1 + A.6.2.2 + AU-2(d) + AU-12(c) + CM-6(a) + DE.AE-3 + DE.AE-5 + DE.CM-1 + DE.CM-3 + DE.CM-7 + ID.SC-4 + PR.AC-3 + PR.PT-1 + PR.PT-4 + RS.AN-1 + RS.AN-4 + Req-10.5.5 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000466-GPOS-00210 + SRG-OS-000471-GPOS-00215 + SRG-OS-000064-GPOS-00033 + SRG-OS-000458-GPOS-00203 + SRG-APP-000091-CTR-000160 + SRG-APP-000492-CTR-001220 + SRG-APP-000493-CTR-001225 + SRG-APP-000494-CTR-001230 + SRG-APP-000500-CTR-001260 + SRG-APP-000507-CTR-001295 + SRG-APP-000495-CTR-001235 + R73 + A.3.SEC-OL7 + 10.3.4 + 10.3 + OL09-00-000545 + SV-271536r1092492_rule + The changing of file permissions could indicate that a user is attempting to gain access to information that would otherwise be disallowed. Auditing DAC modifications can facilitate the identification of patterns of abuse among both authorized and -unauthorized users. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +unauthorized users. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then # First perform the remediation of the syscall rule # Retrieve hardware architecture of the underlying system @@ -62908,7 +143890,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -62924,7 +143905,7 @@ then if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -63016,7 +143997,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -63069,7 +144050,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -63163,7 +144143,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -63191,17 +144171,19 @@ done else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000545 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_dac_modification_setxattr - low_complexity @@ -63215,16 +144197,18 @@ fi audit_arch: b64 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - ansible_architecture == "aarch64" or ansible_architecture == "ppc64" or ansible_architecture == "ppc64le" or ansible_architecture == "s390x" or ansible_architecture == "x86_64" tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000545 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_dac_modification_setxattr - low_complexity @@ -63302,6 +144286,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -63310,7 +144295,7 @@ fi line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -63354,6 +144339,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -63362,19 +144348,21 @@ fi line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000545 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_dac_modification_setxattr - low_complexity @@ -63452,6 +144440,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -63460,7 +144449,7 @@ fi line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -63504,6 +144493,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -63512,20 +144502,22 @@ fi line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - audit_arch == "b64" tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000545 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.4 - audit_rules_dac_modification_setxattr - low_complexity @@ -63533,17 +144525,17 @@ fi - medium_severity - reboot_required - restrict_strategy - - - - - - - - - - Record Events that Modify the System's Discretionary Access Controls - umount - At a minimum, the audit system should collect file system umount + + + + + + + + + + Record Events that Modify the System's Discretionary Access Controls - umount + At a minimum, the audit system should collect file system umount changes. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following line to a file with suffix @@ -63552,26 +144544,31 @@ startup (the default), add the following line to a file with suffix If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following line to /etc/audit/audit.rules file: --a always,exit -F arch=b32 -S umount -F auid>=1000 -F auid!=unset -F key=perm_mod - Note that these rules can be configured in a +-a always,exit -F arch=b32 -S umount -F auid>=1000 -F auid!=unset -F key=perm_mod + + Note that these rules can be configured in a number of ways while still achieving the desired effect. Here the system calls have been placed independent of other system calls. Grouping these system -calls with others as identifying earlier in this guide is more efficient. - CCI-000130 - CCI-000169 - CCI-000172 - CCI-002884 - SRG-OS-000037-GPOS-00015 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - The changing of file permissions could indicate that a user is attempting to +calls with others as identifying earlier in this guide is more efficient. + CCI-000172 + CCI-000130 + CCI-000169 + CCI-002884 + SRG-OS-000037-GPOS-00015 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-APP-000495-CTR-001235 + OL09-00-000840 + SV-271594r1092582_rule + The changing of file permissions could indicate that a user is attempting to gain access to information that would otherwise be disallowed. Auditing DAC modifications can facilitate the identification of patterns of abuse among both authorized and -unauthorized users. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +unauthorized users. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { ! ( ( grep -sqE "^.*\.aarch64$" /proc/sys/kernel/osrelease || grep -sqE "^aarch64$" /proc/sys/kernel/arch; ) ); }; then ACTION_ARCH_FILTERS="-a always,exit -F arch=b32" OTHER_FILTERS="" @@ -63610,7 +144607,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -63626,7 +144622,7 @@ then if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -63718,7 +144714,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -63771,7 +144767,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -63865,7 +144860,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -63892,11 +144887,12 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-000840 - audit_rules_dac_modification_umount - low_complexity - low_disruption @@ -63967,6 +144963,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -63975,7 +144972,7 @@ fi line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -64013,6 +145010,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -64021,30 +145019,32 @@ fi line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - not ( ansible_architecture == "aarch64" ) tags: + - DISA-STIG-OL09-00-000840 - audit_rules_dac_modification_umount - low_complexity - low_disruption - medium_severity - reboot_required - restrict_strategy - - - - - - - - - - Record Events that Modify the System's Discretionary Access Controls - umount2 - At a minimum, the audit system should collect file system umount2 + + + + + + + + + + Record Events that Modify the System's Discretionary Access Controls - umount2 + At a minimum, the audit system should collect file system umount2 changes. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following line to a file with suffix @@ -64057,27 +145057,31 @@ utility to read audit rules during daemon startup, add the following line to /etc/audit/audit.rules file: -a always,exit -F arch=b32 -S umount2 -F auid>=1000 -F auid!=unset -F key=perm_mod If the system is 64 bit then also add the following line: --a always,exit -F arch=b64 -S umount2 -F auid>=1000 -F auid!=unset -F key=perm_mod - Note that these rules can be configured in a +-a always,exit -F arch=b64 -S umount2 -F auid>=1000 -F auid!=unset -F key=perm_mod + + Note that these rules can be configured in a number of ways while still achieving the desired effect. Here the system calls have been placed independent of other system calls. Grouping these system -calls with others as identifying earlier in this guide is more efficient. - BP28(R73) - CCI-000130 - CCI-000169 - CCI-000172 - CCI-002884 - SRG-OS-000037-GPOS-00015 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - The changing of file permissions could indicate that a user is attempting to +calls with others as identifying earlier in this guide is more efficient. + CCI-000172 + CCI-000130 + CCI-000169 + CCI-002884 + SRG-OS-000037-GPOS-00015 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-APP-000495-CTR-001235 + R73 + OL09-00-000845 + SV-271595r1092584_rule + The changing of file permissions could indicate that a user is attempting to gain access to information that would otherwise be disallowed. Auditing DAC modifications can facilitate the identification of patterns of abuse among both authorized and -unauthorized users. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +unauthorized users. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then # First perform the remediation of the syscall rule # Retrieve hardware architecture of the underlying system @@ -64122,7 +145126,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -64138,7 +145141,7 @@ then if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -64230,7 +145233,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -64283,7 +145286,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -64377,7 +145379,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -64405,11 +145407,12 @@ done else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-000845 - audit_rules_dac_modification_umount2 - low_complexity - low_disruption @@ -64422,10 +145425,11 @@ fi audit_arch: b64 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - ansible_architecture == "aarch64" or ansible_architecture == "ppc64" or ansible_architecture == "ppc64le" or ansible_architecture == "s390x" or ansible_architecture == "x86_64" tags: + - DISA-STIG-OL09-00-000845 - audit_rules_dac_modification_umount2 - low_complexity - low_disruption @@ -64496,6 +145500,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -64504,7 +145509,7 @@ fi line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -64542,6 +145547,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -64550,13 +145556,14 @@ fi line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-000845 - audit_rules_dac_modification_umount2 - low_complexity - low_disruption @@ -64627,6 +145634,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -64635,7 +145643,7 @@ fi line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -64673,6 +145681,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -64681,36 +145690,37 @@ fi line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - audit_arch == "b64" tags: + - DISA-STIG-OL09-00-000845 - audit_rules_dac_modification_umount2 - low_complexity - low_disruption - medium_severity - reboot_required - restrict_strategy - - - - - - - - - - - Record Execution Attempts to Run ACL Privileged Commands - At a minimum, the audit system should collect the execution of -ACL privileged commands for all users and root. - - Record Any Attempts to Run chacl - At a minimum, the audit system should collect any execution attempt + + + + + + + + + + + Record Execution Attempts to Run ACL Privileged Commands + At a minimum, the audit system should collect the execution of +ACL privileged commands for all users and root. + + Record Any Attempts to Run chacl + At a minimum, the audit system should collect any execution attempt of the chacl command for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following lines to a file with suffix @@ -64719,27 +145729,32 @@ during daemon startup (the default), add the following lines to a file with suff If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following lines to /etc/audit/audit.rules file: --a always,exit -F path=/usr/bin/chacl -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged - CCI-000130 - CCI-000135 - CCI-000169 - CCI-000172 - CCI-002884 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-OS-000466-GPOS-00210 - Without generating audit records that are specific to the security and +-a always,exit -F path=/usr/bin/chacl -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + + CCI-000172 + CCI-000130 + CCI-000135 + CCI-000169 + CCI-002884 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-OS-000466-GPOS-00210 + SRG-APP-000495-CTR-001235 + SRG-APP-000499-CTR-001255 + OL09-00-000665 + SV-271560r1092540_rule + Without generating audit records that are specific to the security and mission needs of the organization, it would be difficult to establish, correlate, and investigate the events relating to an incident or identify those responsible for one. Audit records can be generated from various components within the -information system (e.g., module or policy filter). - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +information system (e.g., module or policy filter). + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then ACTION_ARCH_FILTERS="-a always,exit" OTHER_FILTERS="-F path=/usr/bin/chacl -F perm=x" @@ -64777,7 +145792,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -64793,7 +145807,7 @@ then if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -64885,7 +145899,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -64938,7 +145952,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -65032,7 +146045,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -65059,11 +146072,12 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-000665 - audit_rules_execution_chacl - low_complexity - low_disruption @@ -65133,6 +146147,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -65141,7 +146156,7 @@ fi line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/chacl -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -65178,6 +146193,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -65186,30 +146202,31 @@ fi line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/chacl -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-000665 - audit_rules_execution_chacl - low_complexity - low_disruption - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Record Any Attempts to Run setfacl - At a minimum, the audit system should collect any execution attempt + + + + + + + + + + Record Any Attempts to Run setfacl + At a minimum, the audit system should collect any execution attempt of the setfacl command for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following lines to a file with suffix @@ -65218,26 +146235,30 @@ during daemon startup (the default), add the following lines to a file with suff If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following lines to /etc/audit/audit.rules file: --a always,exit -F path=/usr/bin/setfacl -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged - CCI-000130 - CCI-000135 - CCI-000169 - CCI-000172 - CCI-002884 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - Without generating audit records that are specific to the security and +-a always,exit -F path=/usr/bin/setfacl -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + + CCI-000172 + CCI-000130 + CCI-000135 + CCI-000169 + CCI-002884 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-APP-000495-CTR-001235 + OL09-00-000560 + SV-271539r1092498_rule + Without generating audit records that are specific to the security and mission needs of the organization, it would be difficult to establish, correlate, and investigate the events relating to an incident or identify those responsible for one. Audit records can be generated from various components within the -information system (e.g., module or policy filter). - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +information system (e.g., module or policy filter). + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then ACTION_ARCH_FILTERS="-a always,exit" OTHER_FILTERS="-F path=/usr/bin/setfacl -F perm=x" @@ -65275,7 +146296,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -65291,7 +146311,7 @@ then if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -65383,7 +146403,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -65436,7 +146456,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -65530,7 +146549,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -65557,11 +146576,12 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-000560 - audit_rules_execution_setfacl - low_complexity - low_disruption @@ -65631,6 +146651,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -65639,7 +146660,7 @@ fi line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/setfacl -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -65676,6 +146697,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -65684,35 +146706,36 @@ fi line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/setfacl -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-000560 - audit_rules_execution_setfacl - low_complexity - low_disruption - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - - Record Execution Attempts to Run SELinux Privileged Commands - At a minimum, the audit system should collect the execution of -SELinux privileged commands for all users and root. - - Record Any Attempts to Run chcon - At a minimum, the audit system should collect any execution attempt + + + + + + + + + + + Record Execution Attempts to Run SELinux Privileged Commands + At a minimum, the audit system should collect the execution of +SELinux privileged commands for all users and root. + + Record Any Attempts to Run chcon + At a minimum, the audit system should collect any execution attempt of the chcon command for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following lines to a file with suffix @@ -65721,104 +146744,113 @@ during daemon startup (the default), add the following lines to a file with suff If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following lines to /etc/audit/audit.rules file: --a always,exit -F path=/usr/bin/chcon -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged - 1 - 12 - 13 - 14 - 15 - 16 - 2 - 3 - 5 - 6 - 7 - 8 - 9 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - BAI03.05 - DSS01.03 - DSS03.05 - DSS05.02 - DSS05.04 - DSS05.05 - DSS05.07 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.1.7 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-000172 - CCI-002884 - 164.308(a)(1)(ii)(D) - 164.308(a)(3)(ii)(A) - 164.308(a)(5)(ii)(C) - 164.312(a)(2)(i) - 164.312(b) - 164.312(d) - 164.312(e) - 4.3.2.6.7 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.4.4.7 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.8 - SR 2.9 - SR 6.1 - SR 6.2 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.14.2.7 - A.15.2.1 - A.15.2.2 - AU-2(d) - AU-12(c) - AC-6(9) - CM-6(a) - DE.CM-1 - DE.CM-3 - DE.CM-7 - ID.SC-4 - PR.PT-1 - FAU_GEN.1.1.c - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000468-GPOS-00212 - SRG-OS-000471-GPOS-00215 - SRG-OS-000463-GPOS-00207 - SRG-OS-000465-GPOS-00209 - Misuse of privileged functions, either intentionally or unintentionally by +-a always,exit -F path=/usr/bin/chcon -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + + 1 + 12 + 13 + 14 + 15 + 16 + 2 + 3 + 5 + 6 + 7 + 8 + 9 + APO10.01 + APO10.03 + APO10.04 + APO10.05 + APO11.04 + BAI03.05 + DSS01.03 + DSS03.05 + DSS05.02 + DSS05.04 + DSS05.05 + DSS05.07 + MEA01.01 + MEA01.02 + MEA01.03 + MEA01.04 + MEA01.05 + MEA02.01 + 3.1.7 + CCI-000172 + CCI-000130 + CCI-000135 + CCI-000169 + CCI-002884 + 164.308(a)(1)(ii)(D) + 164.308(a)(3)(ii)(A) + 164.308(a)(5)(ii)(C) + 164.312(a)(2)(i) + 164.312(b) + 164.312(d) + 164.312(e) + 4.3.2.6.7 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.4.4.7 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.8 + SR 2.9 + SR 6.1 + SR 6.2 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.14.2.7 + A.15.2.1 + A.15.2.2 + AU-2(d) + AU-12(c) + AC-6(9) + CM-6(a) + DE.CM-1 + DE.CM-3 + DE.CM-7 + ID.SC-4 + PR.PT-1 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000468-GPOS-00212 + SRG-OS-000471-GPOS-00215 + SRG-OS-000463-GPOS-00207 + SRG-OS-000465-GPOS-00209 + SRG-APP-000495-CTR-001235 + SRG-APP-000496-CTR-001240 + SRG-APP-000497-CTR-001245 + SRG-APP-000498-CTR-001250 + SRG-APP-000501-CTR-001265 + SRG-APP-000502-CTR-001270 + OL09-00-000555 + SV-271538r1092496_rule + Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. Auditing the use of privileged functions is one way to detect such misuse and identify the risk from insider and advanced persistent threats. - + + Privileged programs are subject to escalation-of-privilege attacks, which attempt to subvert their normal role of providing some necessary but limited capability. As such, motivation exists to monitor these programs for -unusual activity. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +unusual activity. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then ACTION_ARCH_FILTERS="-a always,exit" OTHER_FILTERS="-F path=/usr/bin/chcon -F perm=x" @@ -65856,7 +146888,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -65872,7 +146903,7 @@ then if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -65964,7 +146995,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -66017,7 +147048,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -66111,7 +147141,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -66138,11 +147168,12 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-000555 - NIST-800-171-3.1.7 - NIST-800-53-AC-6(9) - NIST-800-53-AU-12(c) @@ -66217,6 +147248,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -66225,7 +147257,7 @@ fi line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/chcon -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -66262,6 +147294,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -66270,13 +147303,14 @@ fi line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/chcon -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-000555 - NIST-800-171-3.1.7 - NIST-800-53-AC-6(9) - NIST-800-53-AU-12(c) @@ -66288,17 +147322,17 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Record Any Attempts to Run restorecon - At a minimum, the audit system should collect any execution attempt + + + + + + + + + + Record Any Attempts to Run restorecon + At a minimum, the audit system should collect any execution attempt of the restorecon command for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following lines to a file with suffix @@ -66307,95 +147341,96 @@ during daemon startup (the default), add the following lines to a file with suff If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following lines to /etc/audit/audit.rules file: --a always,exit -F path=/usr/sbin/restorecon -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged - 1 - 12 - 13 - 14 - 15 - 16 - 2 - 3 - 5 - 6 - 7 - 8 - 9 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - BAI03.05 - DSS01.03 - DSS03.05 - DSS05.02 - DSS05.04 - DSS05.05 - DSS05.07 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.1.7 - CCI-000172 - CCI-002884 - 164.308(a)(1)(ii)(D) - 164.308(a)(3)(ii)(A) - 164.308(a)(5)(ii)(C) - 164.312(a)(2)(i) - 164.312(b) - 164.312(d) - 164.312(e) - 4.3.2.6.7 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.4.4.7 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.8 - SR 2.9 - SR 6.1 - SR 6.2 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.14.2.7 - A.15.2.1 - A.15.2.2 - AU-2(d) - AU-12(c) - AC-6(9) - CM-6(a) - DE.CM-1 - DE.CM-3 - DE.CM-7 - ID.SC-4 - PR.PT-1 - FAU_GEN.1.1.c - SRG-OS-000392-GPOS-00172 - SRG-OS-000463-GPOS-00207 - SRG-OS-000465-GPOS-00209 - Misuse of privileged functions, either intentionally or unintentionally by +-a always,exit -F path=/usr/sbin/restorecon -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + + 1 + 12 + 13 + 14 + 15 + 16 + 2 + 3 + 5 + 6 + 7 + 8 + 9 + APO10.01 + APO10.03 + APO10.04 + APO10.05 + APO11.04 + BAI03.05 + DSS01.03 + DSS03.05 + DSS05.02 + DSS05.04 + DSS05.05 + DSS05.07 + MEA01.01 + MEA01.02 + MEA01.03 + MEA01.04 + MEA01.05 + MEA02.01 + 3.1.7 + CCI-000172 + CCI-002884 + 164.308(a)(1)(ii)(D) + 164.308(a)(3)(ii)(A) + 164.308(a)(5)(ii)(C) + 164.312(a)(2)(i) + 164.312(b) + 164.312(d) + 164.312(e) + 4.3.2.6.7 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.4.4.7 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.8 + SR 2.9 + SR 6.1 + SR 6.2 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.14.2.7 + A.15.2.1 + A.15.2.2 + AU-2(d) + AU-12(c) + AC-6(9) + CM-6(a) + DE.CM-1 + DE.CM-3 + DE.CM-7 + ID.SC-4 + PR.PT-1 + SRG-OS-000392-GPOS-00172 + SRG-OS-000463-GPOS-00207 + SRG-OS-000465-GPOS-00209 + Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. Auditing the use of privileged functions is one way to detect such misuse and identify the risk from insider and advanced persistent threats. - + + Privileged programs are subject to escalation-of-privilege attacks, which attempt to subvert their normal role of providing some necessary but limited capability. As such, motivation exists to monitor these programs for -unusual activity. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +unusual activity. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then ACTION_ARCH_FILTERS="-a always,exit" OTHER_FILTERS="-F path=/usr/sbin/restorecon -F perm=x" @@ -66433,7 +147468,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -66449,7 +147483,7 @@ then if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -66541,7 +147575,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -66594,7 +147628,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -66688,7 +147721,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -66715,8 +147748,8 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: @@ -66794,6 +147827,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -66802,7 +147836,7 @@ fi line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/restorecon -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -66839,6 +147873,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -66847,12 +147882,12 @@ fi line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/restorecon -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-171-3.1.7 - NIST-800-53-AC-6(9) @@ -66865,17 +147900,17 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Record Any Attempts to Run semanage - At a minimum, the audit system should collect any execution attempt + + + + + + + + + + Record Any Attempts to Run semanage + At a minimum, the audit system should collect any execution attempt of the semanage command for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following lines to a file with suffix @@ -66884,110 +147919,119 @@ during daemon startup (the default), add the following lines to a file with suff If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following lines to /etc/audit/audit.rules file: --a always,exit -F path=/usr/sbin/semanage -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged - 1 - 12 - 13 - 14 - 15 - 16 - 2 - 3 - 5 - 6 - 7 - 8 - 9 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - BAI03.05 - DSS01.03 - DSS03.05 - DSS05.02 - DSS05.04 - DSS05.05 - DSS05.07 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.1.7 - CCI-000169 - CCI-000172 - CCI-002884 - 164.308(a)(1)(ii)(D) - 164.308(a)(3)(ii)(A) - 164.308(a)(5)(ii)(C) - 164.312(a)(2)(i) - 164.312(b) - 164.312(d) - 164.312(e) - 4.3.2.6.7 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.4.4.7 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.8 - SR 2.9 - SR 6.1 - SR 6.2 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.14.2.7 - A.15.2.1 - A.15.2.2 - CIP-004-6 R2.2.2 - CIP-004-6 R2.2.3 - CIP-007-3 R.1.3 - CIP-007-3 R5 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.3 - CIP-007-3 R5.2.1 - CIP-007-3 R5.2.3 - AC-2(4) - AU-2(d) - AU-12(c) - AC-6(9) - CM-6(a) - DE.CM-1 - DE.CM-3 - DE.CM-7 - ID.SC-4 - PR.PT-1 - FAU_GEN.1.1.c - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-OS-000463-GPOS-00207 - SRG-OS-000465-GPOS-00209 - Misuse of privileged functions, either intentionally or unintentionally by +-a always,exit -F path=/usr/sbin/semanage -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + + 1 + 12 + 13 + 14 + 15 + 16 + 2 + 3 + 5 + 6 + 7 + 8 + 9 + APO10.01 + APO10.03 + APO10.04 + APO10.05 + APO11.04 + BAI03.05 + DSS01.03 + DSS03.05 + DSS05.02 + DSS05.04 + DSS05.05 + DSS05.07 + MEA01.01 + MEA01.02 + MEA01.03 + MEA01.04 + MEA01.05 + MEA02.01 + 3.1.7 + CCI-000172 + CCI-000130 + CCI-000135 + CCI-000169 + CCI-002884 + 164.308(a)(1)(ii)(D) + 164.308(a)(3)(ii)(A) + 164.308(a)(5)(ii)(C) + 164.312(a)(2)(i) + 164.312(b) + 164.312(d) + 164.312(e) + 4.3.2.6.7 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.4.4.7 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.8 + SR 2.9 + SR 6.1 + SR 6.2 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.14.2.7 + A.15.2.1 + A.15.2.2 + CIP-004-6 R2.2.2 + CIP-004-6 R2.2.3 + CIP-007-3 R.1.3 + CIP-007-3 R5 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.3 + CIP-007-3 R5.2.1 + CIP-007-3 R5.2.3 + AC-2(4) + AU-2(d) + AU-12(c) + AC-6(9) + CM-6(a) + DE.CM-1 + DE.CM-3 + DE.CM-7 + ID.SC-4 + PR.PT-1 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-OS-000463-GPOS-00207 + SRG-OS-000465-GPOS-00209 + SRG-APP-000495-CTR-001235 + SRG-APP-000496-CTR-001240 + SRG-APP-000497-CTR-001245 + SRG-APP-000498-CTR-001250 + OL09-00-000650 + SV-271557r1092534_rule + Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. Auditing the use of privileged functions is one way to detect such misuse and identify the risk from insider and advanced persistent threats. - + + Privileged programs are subject to escalation-of-privilege attacks, which attempt to subvert their normal role of providing some necessary but limited capability. As such, motivation exists to monitor these programs for -unusual activity. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +unusual activity. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then ACTION_ARCH_FILTERS="-a always,exit" OTHER_FILTERS="-F path=/usr/sbin/semanage -F perm=x" @@ -67025,7 +148069,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -67041,7 +148084,7 @@ then if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -67133,7 +148176,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -67186,7 +148229,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -67280,7 +148322,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -67307,11 +148349,12 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-000650 - NIST-800-171-3.1.7 - NIST-800-53-AC-2(4) - NIST-800-53-AC-6(9) @@ -67387,6 +148430,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -67395,7 +148439,7 @@ fi line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/semanage -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -67432,6 +148476,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -67440,13 +148485,14 @@ fi line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/semanage -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-000650 - NIST-800-171-3.1.7 - NIST-800-53-AC-2(4) - NIST-800-53-AC-6(9) @@ -67459,17 +148505,17 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Record Any Attempts to Run setfiles - At a minimum, the audit system should collect any execution attempt + + + + + + + + + + Record Any Attempts to Run setfiles + At a minimum, the audit system should collect any execution attempt of the setfiles command for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following lines to a file with suffix @@ -67478,34 +148524,44 @@ during daemon startup (the default), add the following lines to a file with suff If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following lines to /etc/audit/audit.rules file: --a always,exit -F path=/usr/sbin/setfiles -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged - CCI-000169 - CCI-000172 - CCI-002884 - AU-2(d) - AU-12(c) - AC-6(9) - CM-6(a) - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-OS-000463-GPOS-00207 - SRG-OS-000465-GPOS-00209 - Misuse of privileged functions, either intentionally or unintentionally by +-a always,exit -F path=/usr/sbin/setfiles -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + + CCI-000172 + CCI-000130 + CCI-000135 + CCI-000169 + CCI-002884 + AU-2(d) + AU-12(c) + AC-6(9) + CM-6(a) + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-OS-000463-GPOS-00207 + SRG-OS-000465-GPOS-00209 + SRG-APP-000495-CTR-001235 + SRG-APP-000496-CTR-001240 + SRG-APP-000497-CTR-001245 + SRG-APP-000498-CTR-001250 + OL09-00-000655 + SV-271558r1092536_rule + Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. Auditing the use of privileged functions is one way to detect such misuse and identify the risk from insider and advanced persistent threats. - + + Privileged programs are subject to escalation-of-privilege attacks, which attempt to subvert their normal role of providing some necessary but limited capability. As such, motivation exists to monitor these programs for -unusual activity. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +unusual activity. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then ACTION_ARCH_FILTERS="-a always,exit" OTHER_FILTERS="-F path=/usr/sbin/setfiles -F perm=x" @@ -67543,7 +148599,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -67559,7 +148614,7 @@ then if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -67651,7 +148706,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -67704,7 +148759,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -67798,7 +148852,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -67825,11 +148879,12 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-000655 - NIST-800-53-AC-6(9) - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) @@ -67903,6 +148958,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -67911,7 +148967,7 @@ fi line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/setfiles -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -67948,6 +149004,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -67956,13 +149013,14 @@ fi line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/setfiles -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-000655 - NIST-800-53-AC-6(9) - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) @@ -67973,17 +149031,17 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Record Any Attempts to Run setsebool - At a minimum, the audit system should collect any execution attempt + + + + + + + + + + Record Any Attempts to Run setsebool + At a minimum, the audit system should collect any execution attempt of the setsebool command for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following lines to a file with suffix @@ -67992,103 +149050,110 @@ during daemon startup (the default), add the following lines to a file with suff If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following lines to /etc/audit/audit.rules file: --a always,exit -F path=/usr/sbin/setsebool -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged - 1 - 12 - 13 - 14 - 15 - 16 - 2 - 3 - 5 - 6 - 7 - 8 - 9 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - BAI03.05 - DSS01.03 - DSS03.05 - DSS05.02 - DSS05.04 - DSS05.05 - DSS05.07 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.1.7 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-000172 - CCI-002884 - 164.308(a)(1)(ii)(D) - 164.308(a)(3)(ii)(A) - 164.308(a)(5)(ii)(C) - 164.312(a)(2)(i) - 164.312(b) - 164.312(d) - 164.312(e) - 4.3.2.6.7 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.4.4.7 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.8 - SR 2.9 - SR 6.1 - SR 6.2 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.14.2.7 - A.15.2.1 - A.15.2.2 - AU-2(d) - AU-12(c) - AC-6(9) - CM-6(a) - DE.CM-1 - DE.CM-3 - DE.CM-7 - ID.SC-4 - PR.PT-1 - FAU_GEN.1.1.c - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-OS-000463-GPOS-00207 - SRG-OS-000465-GPOS-00209 - Misuse of privileged functions, either intentionally or unintentionally by +-a always,exit -F path=/usr/sbin/setsebool -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + + 1 + 12 + 13 + 14 + 15 + 16 + 2 + 3 + 5 + 6 + 7 + 8 + 9 + APO10.01 + APO10.03 + APO10.04 + APO10.05 + APO11.04 + BAI03.05 + DSS01.03 + DSS03.05 + DSS05.02 + DSS05.04 + DSS05.05 + DSS05.07 + MEA01.01 + MEA01.02 + MEA01.03 + MEA01.04 + MEA01.05 + MEA02.01 + 3.1.7 + CCI-000172 + CCI-000130 + CCI-000135 + CCI-000169 + CCI-002884 + 164.308(a)(1)(ii)(D) + 164.308(a)(3)(ii)(A) + 164.308(a)(5)(ii)(C) + 164.312(a)(2)(i) + 164.312(b) + 164.312(d) + 164.312(e) + 4.3.2.6.7 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.4.4.7 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.8 + SR 2.9 + SR 6.1 + SR 6.2 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.14.2.7 + A.15.2.1 + A.15.2.2 + AU-2(d) + AU-12(c) + AC-6(9) + CM-6(a) + DE.CM-1 + DE.CM-3 + DE.CM-7 + ID.SC-4 + PR.PT-1 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-OS-000463-GPOS-00207 + SRG-OS-000465-GPOS-00209 + SRG-APP-000495-CTR-001235 + SRG-APP-000496-CTR-001240 + SRG-APP-000497-CTR-001245 + SRG-APP-000498-CTR-001250 + OL09-00-000660 + SV-271559r1092538_rule + Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. Auditing the use of privileged functions is one way to detect such misuse and identify the risk from insider and advanced persistent threats. - + + Privileged programs are subject to escalation-of-privilege attacks, which attempt to subvert their normal role of providing some necessary but limited capability. As such, motivation exists to monitor these programs for -unusual activity. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +unusual activity. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then ACTION_ARCH_FILTERS="-a always,exit" OTHER_FILTERS="-F path=/usr/sbin/setsebool -F perm=x" @@ -68126,7 +149191,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -68142,7 +149206,7 @@ then if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -68234,7 +149298,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -68287,7 +149351,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -68381,7 +149444,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -68408,11 +149471,12 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-000660 - NIST-800-171-3.1.7 - NIST-800-53-AC-6(9) - NIST-800-53-AU-12(c) @@ -68487,6 +149551,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -68495,7 +149560,7 @@ fi line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/setsebool -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -68532,6 +149597,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -68540,13 +149606,14 @@ fi line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/setsebool -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-000660 - NIST-800-171-3.1.7 - NIST-800-53-AC-6(9) - NIST-800-53-AU-12(c) @@ -68558,17 +149625,17 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Record Any Attempts to Run seunshare - At a minimum, the audit system should collect any execution attempt + + + + + + + + + + Record Any Attempts to Run seunshare + At a minimum, the audit system should collect any execution attempt of the seunshare command for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following lines to a file with suffix @@ -68577,25 +149644,26 @@ during daemon startup (the default), add the following lines to a file with suff If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following lines to /etc/audit/audit.rules file: --a always,exit -F path=/usr/sbin/seunshare -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged - CCI-000172 - AU-2(d) - AU-12(c) - AC-6(9) - CM-6(a) - FAU_GEN.1.1.c - Misuse of privileged functions, either intentionally or unintentionally by +-a always,exit -F path=/usr/sbin/seunshare -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + + CCI-000172 + AU-2(d) + AU-12(c) + AC-6(9) + CM-6(a) + Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. Auditing the use of privileged functions is one way to detect such misuse and identify the risk from insider and advanced persistent threats. - + + Privileged programs are subject to escalation-of-privilege attacks, which attempt to subvert their normal role of providing some necessary but limited capability. As such, motivation exists to monitor these programs for -unusual activity. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +unusual activity. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then ACTION_ARCH_FILTERS="-a always,exit" OTHER_FILTERS="-F path=/usr/sbin/seunshare -F perm=x" @@ -68633,7 +149701,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -68649,7 +149716,7 @@ then if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -68741,7 +149808,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -68794,7 +149861,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -68888,7 +149954,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -68915,8 +149981,8 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: @@ -68993,6 +150059,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -69001,7 +150068,7 @@ fi line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/seunshare -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -69038,6 +150105,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -69046,12 +150114,12 @@ fi line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/seunshare -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AC-6(9) - NIST-800-53-AU-12(c) @@ -69063,18 +150131,18 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - - Record File Deletion Events by User - At a minimum, the audit system should collect file deletion events + + + + + + + + + + + Record File Deletion Events by User + At a minimum, the audit system should collect file deletion events for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following line to a file with suffix .rules in the @@ -69085,10 +150153,11 @@ If the auditd daemon is configured to use the utility to read audit rules during daemon startup, add the following line to /etc/audit/audit.rules file, setting ARCH to either b32 or b64 as appropriate for your system: --a always,exit -F arch=ARCH -S rmdir,unlink,unlinkat,rename,renameat -F auid>=1000 -F auid!=unset -F key=delete - - Ensure auditd Collects File Deletion Events by User - At a minimum the audit system should collect file deletion events +-a always,exit -F arch=ARCH -S rmdir,unlink,unlinkat,rename,renameat -F auid>=1000 -F auid!=unset -F key=delete + + + Ensure auditd Collects File Deletion Events by User + At a minimum the audit system should collect file deletion events for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following line to a file with suffix .rules in the @@ -69099,129 +150168,129 @@ If the auditd daemon is configured to use the utility to read audit rules during daemon startup, add the following line to /etc/audit/audit.rules file, setting ARCH to either b32 or b64 as appropriate for your system: --a always,exit -F arch=ARCH -S rmdir,unlink,unlinkat,rename -S renameat -F auid>=1000 -F auid!=unset -F key=delete - This rule checks for multiple syscalls related to file deletion; +-a always,exit -F arch=ARCH -S rmdir,unlink,unlinkat,rename -S renameat -F auid>=1000 -F auid!=unset -F key=delete + + This rule checks for multiple syscalls related to file deletion; it was written with DISA STIG in mind. Other policies should use a separate rule for each syscall that needs to be checked. For example: -audit_rules_file_deletion_events_rmdiraudit_rules_file_deletion_events_unlinkaudit_rules_file_deletion_events_unlinkat - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 19 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 5.4.1.1 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - APO12.06 - APO13.01 - BAI03.05 - BAI08.02 - DSS01.03 - DSS01.04 - DSS02.02 - DSS02.04 - DSS02.07 - DSS03.01 - DSS03.05 - DSS05.02 - DSS05.03 - DSS05.04 - DSS05.05 - DSS05.07 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.1.7 - CCI-000366 - CCI-000172 - CCI-002884 - 4.2.3.10 - 4.3.2.6.7 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.3.6.6 - 4.3.4.4.7 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 1.13 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.6 - SR 2.8 - SR 2.9 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 6.1 - SR 6.2 - SR 7.1 - SR 7.6 - A.11.2.6 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.14.2.7 - A.15.2.1 - A.15.2.2 - A.16.1.4 - A.16.1.5 - A.16.1.7 - A.6.2.1 - A.6.2.2 - AU-2(d) - AU-12(c) - CM-6(a) - DE.AE-3 - DE.AE-5 - DE.CM-1 - DE.CM-3 - DE.CM-7 - ID.SC-4 - PR.AC-3 - PR.PT-1 - PR.PT-4 - RS.AN-1 - RS.AN-4 - FAU_GEN.1.1.c - Req-10.2.7 - 10.2.1.7 - Auditing file deletions will create an audit trail for files that are removed +audit_rules_file_deletion_events_rmdiraudit_rules_file_deletion_events_unlinkaudit_rules_file_deletion_events_unlinkat + + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 19 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 5.4.1.1 + APO10.01 + APO10.03 + APO10.04 + APO10.05 + APO11.04 + APO12.06 + APO13.01 + BAI03.05 + BAI08.02 + DSS01.03 + DSS01.04 + DSS02.02 + DSS02.04 + DSS02.07 + DSS03.01 + DSS03.05 + DSS05.02 + DSS05.03 + DSS05.04 + DSS05.05 + DSS05.07 + MEA01.01 + MEA01.02 + MEA01.03 + MEA01.04 + MEA01.05 + MEA02.01 + 3.1.7 + CCI-000366 + CCI-000172 + CCI-002884 + 4.2.3.10 + 4.3.2.6.7 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.3.6.6 + 4.3.4.4.7 + 4.3.4.5.6 + 4.3.4.5.7 + 4.3.4.5.8 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 1.13 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.6 + SR 2.8 + SR 2.9 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 6.1 + SR 6.2 + SR 7.1 + SR 7.6 + A.11.2.6 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.13.1.1 + A.13.2.1 + A.14.1.3 + A.14.2.7 + A.15.2.1 + A.15.2.2 + A.16.1.4 + A.16.1.5 + A.16.1.7 + A.6.2.1 + A.6.2.2 + AU-2(d) + AU-12(c) + CM-6(a) + DE.AE-3 + DE.AE-5 + DE.CM-1 + DE.CM-3 + DE.CM-7 + ID.SC-4 + PR.AC-3 + PR.PT-1 + PR.PT-4 + RS.AN-1 + RS.AN-4 + Req-10.2.7 + Auditing file deletions will create an audit trail for files that are removed from the system. The audit trail could aid in system troubleshooting, as well as, detecting -malicious processes that attempt to delete log files to conceal their presence. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +malicious processes that attempt to delete log files to conceal their presence. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then # Perform the remediation for the syscall rule # Retrieve hardware architecture of the underlying system @@ -69265,7 +150334,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -69281,7 +150349,7 @@ then if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -69373,7 +150441,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -69426,7 +150494,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -69520,7 +150587,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -69548,17 +150615,17 @@ done else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - - - - - - - - Ensure auditd Collects File Deletion Events by User - rename - At a minimum, the audit system should collect file deletion events + + + + + + + + + + Ensure auditd Collects File Deletion Events by User - rename + At a minimum, the audit system should collect file deletion events for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following line to a file with suffix .rules in the @@ -69569,150 +150636,158 @@ If the auditd daemon is configured to use the utility to read audit rules during daemon startup, add the following line to /etc/audit/audit.rules file, setting ARCH to either b32 or b64 as appropriate for your system: --a always,exit -F arch=ARCH -S rename -F auid>=1000 -F auid!=unset -F key=delete - BP28(R73) - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 19 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - APO12.06 - APO13.01 - BAI03.05 - BAI08.02 - DSS01.03 - DSS01.04 - DSS02.02 - DSS02.04 - DSS02.07 - DSS03.01 - DSS03.05 - DSS05.02 - DSS05.03 - DSS05.04 - DSS05.05 - DSS05.07 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.1.7 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-000172 - CCI-000366 - CCI-002884 - 164.308(a)(1)(ii)(D) - 164.308(a)(3)(ii)(A) - 164.308(a)(5)(ii)(C) - 164.312(a)(2)(i) - 164.312(b) - 164.312(d) - 164.312(e) - 4.2.3.10 - 4.3.2.6.7 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.4.4.7 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 1.13 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.6 - SR 2.8 - SR 2.9 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 6.1 - SR 6.2 - SR 7.1 - SR 7.6 - A.11.2.4 - A.11.2.6 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.14.2.7 - A.15.1.1 - A.15.2.1 - A.15.2.2 - A.16.1.4 - A.16.1.5 - A.16.1.7 - A.6.2.1 - A.6.2.2 - AU-2(d) - AU-12(c) - CM-6(a) - DE.AE-3 - DE.AE-5 - DE.CM-1 - DE.CM-3 - DE.CM-7 - ID.SC-4 - PR.AC-3 - PR.MA-2 - PR.PT-1 - PR.PT-4 - RS.AN-1 - RS.AN-4 - FAU_GEN.1.1.c - Req-10.2.7 - 10.2.1.7 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-OS-000466-GPOS-00210 - SRG-OS-000467-GPOS-00211 - SRG-OS-000468-GPOS-00212 - Auditing file deletions will create an audit trail for files that are removed +-a always,exit -F arch=ARCH -S rename -F auid>=1000 -F auid!=unset -F key=delete + + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 19 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + APO10.01 + APO10.03 + APO10.04 + APO10.05 + APO11.04 + APO12.06 + APO13.01 + BAI03.05 + BAI08.02 + DSS01.03 + DSS01.04 + DSS02.02 + DSS02.04 + DSS02.07 + DSS03.01 + DSS03.05 + DSS05.02 + DSS05.03 + DSS05.04 + DSS05.05 + DSS05.07 + MEA01.01 + MEA01.02 + MEA01.03 + MEA01.04 + MEA01.05 + MEA02.01 + 3.1.7 + CCI-000172 + CCI-000130 + CCI-000135 + CCI-000169 + CCI-002884 + 164.308(a)(1)(ii)(D) + 164.308(a)(3)(ii)(A) + 164.308(a)(5)(ii)(C) + 164.312(a)(2)(i) + 164.312(b) + 164.312(d) + 164.312(e) + 4.2.3.10 + 4.3.2.6.7 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.4.4.7 + 4.3.4.5.6 + 4.3.4.5.7 + 4.3.4.5.8 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 1.13 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.6 + SR 2.8 + SR 2.9 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 6.1 + SR 6.2 + SR 7.1 + SR 7.6 + A.11.2.4 + A.11.2.6 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.13.1.1 + A.13.2.1 + A.14.1.3 + A.14.2.7 + A.15.1.1 + A.15.2.1 + A.15.2.2 + A.16.1.4 + A.16.1.5 + A.16.1.7 + A.6.2.1 + A.6.2.2 + AU-2(d) + AU-12(c) + CM-6(a) + DE.AE-3 + DE.AE-5 + DE.CM-1 + DE.CM-3 + DE.CM-7 + ID.SC-4 + PR.AC-3 + PR.MA-2 + PR.PT-1 + PR.PT-4 + RS.AN-1 + RS.AN-4 + Req-10.2.7 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-OS-000466-GPOS-00210 + SRG-OS-000467-GPOS-00211 + SRG-OS-000468-GPOS-00212 + SRG-APP-000495-CTR-001235 + SRG-APP-000499-CTR-001255 + SRG-APP-000501-CTR-001265 + SRG-APP-000502-CTR-001270 + R73 + 10.2.1.7 + 10.2.1 + 10.2 + OL09-00-000680 + SV-271563r1092546_rule + Auditing file deletions will create an audit trail for files that are removed from the system. The audit trail could aid in system troubleshooting, as well as, detecting -malicious processes that attempt to delete log files to conceal their presence. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +malicious processes that attempt to delete log files to conceal their presence. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { ! ( ( grep -sqE "^.*\.aarch64$" /proc/sys/kernel/osrelease || grep -sqE "^aarch64$" /proc/sys/kernel/arch; ) ); }; then # First perform the remediation of the syscall rule # Retrieve hardware architecture of the underlying system @@ -69756,7 +150831,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -69772,7 +150846,7 @@ then if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -69864,7 +150938,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -69917,7 +150991,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -70011,7 +151084,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -70039,16 +151112,19 @@ done else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-000680 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.7 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.7 - audit_rules_file_deletion_events_rename - low_complexity @@ -70062,15 +151138,19 @@ fi audit_arch: b64 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - not ( ansible_architecture == "aarch64" ) - ansible_architecture == "aarch64" or ansible_architecture == "ppc64" or ansible_architecture == "ppc64le" or ansible_architecture == "s390x" or ansible_architecture == "x86_64" tags: + - DISA-STIG-OL09-00-000680 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.7 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.7 - audit_rules_file_deletion_events_rename - low_complexity @@ -70147,6 +151227,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -70155,7 +151236,7 @@ fi line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=delete create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -70198,6 +151279,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -70206,18 +151288,22 @@ fi line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=delete create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - not ( ansible_architecture == "aarch64" ) tags: + - DISA-STIG-OL09-00-000680 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.7 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.7 - audit_rules_file_deletion_events_rename - low_complexity @@ -70294,6 +151380,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -70302,7 +151389,7 @@ fi line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=delete create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -70345,6 +151432,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -70353,19 +151441,23 @@ fi line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=delete create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - not ( ansible_architecture == "aarch64" ) - audit_arch == "b64" tags: + - DISA-STIG-OL09-00-000680 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.7 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.7 - audit_rules_file_deletion_events_rename - low_complexity @@ -70373,17 +151465,17 @@ fi - medium_severity - reboot_required - restrict_strategy - - - - - - - - - - Ensure auditd Collects File Deletion Events by User - renameat - At a minimum, the audit system should collect file deletion events + + + + + + + + + + Ensure auditd Collects File Deletion Events by User - renameat + At a minimum, the audit system should collect file deletion events for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following line to a file with suffix .rules in the @@ -70394,150 +151486,157 @@ If the auditd daemon is configured to use the utility to read audit rules during daemon startup, add the following line to /etc/audit/audit.rules file, setting ARCH to either b32 or b64 as appropriate for your system: --a always,exit -F arch=ARCH -S renameat -F auid>=1000 -F auid!=unset -F key=delete - BP28(R73) - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 19 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - APO12.06 - APO13.01 - BAI03.05 - BAI08.02 - DSS01.03 - DSS01.04 - DSS02.02 - DSS02.04 - DSS02.07 - DSS03.01 - DSS03.05 - DSS05.02 - DSS05.03 - DSS05.04 - DSS05.05 - DSS05.07 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.1.7 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-000172 - CCI-000366 - CCI-002884 - 164.308(a)(1)(ii)(D) - 164.308(a)(3)(ii)(A) - 164.308(a)(5)(ii)(C) - 164.312(a)(2)(i) - 164.312(b) - 164.312(d) - 164.312(e) - 4.2.3.10 - 4.3.2.6.7 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.4.4.7 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 1.13 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.6 - SR 2.8 - SR 2.9 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 6.1 - SR 6.2 - SR 7.1 - SR 7.6 - A.11.2.4 - A.11.2.6 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.14.2.7 - A.15.1.1 - A.15.2.1 - A.15.2.2 - A.16.1.4 - A.16.1.5 - A.16.1.7 - A.6.2.1 - A.6.2.2 - AU-2(d) - AU-12(c) - CM-6(a) - DE.AE-3 - DE.AE-5 - DE.CM-1 - DE.CM-3 - DE.CM-7 - ID.SC-4 - PR.AC-3 - PR.MA-2 - PR.PT-1 - PR.PT-4 - RS.AN-1 - RS.AN-4 - FAU_GEN.1.1.c - Req-10.2.7 - 10.2.1.7 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-OS-000466-GPOS-00210 - SRG-OS-000467-GPOS-00211 - SRG-OS-000468-GPOS-00212 - Auditing file deletions will create an audit trail for files that are removed +-a always,exit -F arch=ARCH -S renameat -F auid>=1000 -F auid!=unset -F key=delete + + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 19 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + APO10.01 + APO10.03 + APO10.04 + APO10.05 + APO11.04 + APO12.06 + APO13.01 + BAI03.05 + BAI08.02 + DSS01.03 + DSS01.04 + DSS02.02 + DSS02.04 + DSS02.07 + DSS03.01 + DSS03.05 + DSS05.02 + DSS05.03 + DSS05.04 + DSS05.05 + DSS05.07 + MEA01.01 + MEA01.02 + MEA01.03 + MEA01.04 + MEA01.05 + MEA02.01 + 3.1.7 + CCI-000172 + CCI-000130 + CCI-000135 + CCI-000169 + CCI-002884 + 164.308(a)(1)(ii)(D) + 164.308(a)(3)(ii)(A) + 164.308(a)(5)(ii)(C) + 164.312(a)(2)(i) + 164.312(b) + 164.312(d) + 164.312(e) + 4.2.3.10 + 4.3.2.6.7 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.4.4.7 + 4.3.4.5.6 + 4.3.4.5.7 + 4.3.4.5.8 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 1.13 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.6 + SR 2.8 + SR 2.9 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 6.1 + SR 6.2 + SR 7.1 + SR 7.6 + A.11.2.4 + A.11.2.6 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.13.1.1 + A.13.2.1 + A.14.1.3 + A.14.2.7 + A.15.1.1 + A.15.2.1 + A.15.2.2 + A.16.1.4 + A.16.1.5 + A.16.1.7 + A.6.2.1 + A.6.2.2 + AU-2(d) + AU-12(c) + CM-6(a) + DE.AE-3 + DE.AE-5 + DE.CM-1 + DE.CM-3 + DE.CM-7 + ID.SC-4 + PR.AC-3 + PR.MA-2 + PR.PT-1 + PR.PT-4 + RS.AN-1 + RS.AN-4 + Req-10.2.7 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-OS-000466-GPOS-00210 + SRG-OS-000467-GPOS-00211 + SRG-OS-000468-GPOS-00212 + SRG-APP-000495-CTR-001235 + SRG-APP-000499-CTR-001255 + SRG-APP-000501-CTR-001265 + SRG-APP-000502-CTR-001270 + R73 + 10.2.1.7 + 10.2.1 + 10.2 + OL09-00-000680 + SV-271563r1092546_rule + Auditing file deletions will create an audit trail for files that are removed from the system. The audit trail could aid in system troubleshooting, as well as, detecting -malicious processes that attempt to delete log files to conceal their presence. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +malicious processes that attempt to delete log files to conceal their presence. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then # First perform the remediation of the syscall rule # Retrieve hardware architecture of the underlying system @@ -70581,7 +151680,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -70597,7 +151695,7 @@ then if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -70689,7 +151787,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -70742,7 +151840,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -70836,7 +151933,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -70864,16 +151961,19 @@ done else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-000680 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.7 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.7 - audit_rules_file_deletion_events_renameat - low_complexity @@ -70887,15 +151987,18 @@ fi audit_arch: b64 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - ansible_architecture == "aarch64" or ansible_architecture == "ppc64" or ansible_architecture == "ppc64le" or ansible_architecture == "s390x" or ansible_architecture == "x86_64" tags: + - DISA-STIG-OL09-00-000680 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.7 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.7 - audit_rules_file_deletion_events_renameat - low_complexity @@ -70972,6 +152075,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -70980,7 +152084,7 @@ fi line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=delete create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -71023,6 +152127,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -71031,18 +152136,21 @@ fi line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=delete create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-000680 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.7 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.7 - audit_rules_file_deletion_events_renameat - low_complexity @@ -71119,6 +152227,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -71127,7 +152236,7 @@ fi line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=delete create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -71170,6 +152279,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -71178,19 +152288,22 @@ fi line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=delete create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - audit_arch == "b64" tags: + - DISA-STIG-OL09-00-000680 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.7 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.7 - audit_rules_file_deletion_events_renameat - low_complexity @@ -71198,17 +152311,17 @@ fi - medium_severity - reboot_required - restrict_strategy - - - - - - - - - - Ensure auditd Collects File Deletion Events by User - rmdir - At a minimum, the audit system should collect file deletion events + + + + + + + + + + Ensure auditd Collects File Deletion Events by User - rmdir + At a minimum, the audit system should collect file deletion events for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following line to a file with suffix .rules in the @@ -71219,150 +152332,158 @@ If the auditd daemon is configured to use the utility to read audit rules during daemon startup, add the following line to /etc/audit/audit.rules file, setting ARCH to either b32 or b64 as appropriate for your system: --a always,exit -F arch=ARCH -S rmdir -F auid>=1000 -F auid!=unset -F key=delete - BP28(R73) - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 19 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - APO12.06 - APO13.01 - BAI03.05 - BAI08.02 - DSS01.03 - DSS01.04 - DSS02.02 - DSS02.04 - DSS02.07 - DSS03.01 - DSS03.05 - DSS05.02 - DSS05.03 - DSS05.04 - DSS05.05 - DSS05.07 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.1.7 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-000172 - CCI-000366 - CCI-002884 - 164.308(a)(1)(ii)(D) - 164.308(a)(3)(ii)(A) - 164.308(a)(5)(ii)(C) - 164.312(a)(2)(i) - 164.312(b) - 164.312(d) - 164.312(e) - 4.2.3.10 - 4.3.2.6.7 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.4.4.7 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 1.13 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.6 - SR 2.8 - SR 2.9 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 6.1 - SR 6.2 - SR 7.1 - SR 7.6 - A.11.2.4 - A.11.2.6 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.14.2.7 - A.15.1.1 - A.15.2.1 - A.15.2.2 - A.16.1.4 - A.16.1.5 - A.16.1.7 - A.6.2.1 - A.6.2.2 - AU-2(d) - AU-12(c) - CM-6(a) - DE.AE-3 - DE.AE-5 - DE.CM-1 - DE.CM-3 - DE.CM-7 - ID.SC-4 - PR.AC-3 - PR.MA-2 - PR.PT-1 - PR.PT-4 - RS.AN-1 - RS.AN-4 - FAU_GEN.1.1.c - Req-10.2.7 - 10.2.1.7 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-OS-000466-GPOS-00210 - SRG-OS-000467-GPOS-00211 - SRG-OS-000468-GPOS-00212 - Auditing file deletions will create an audit trail for files that are removed +-a always,exit -F arch=ARCH -S rmdir -F auid>=1000 -F auid!=unset -F key=delete + + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 19 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + APO10.01 + APO10.03 + APO10.04 + APO10.05 + APO11.04 + APO12.06 + APO13.01 + BAI03.05 + BAI08.02 + DSS01.03 + DSS01.04 + DSS02.02 + DSS02.04 + DSS02.07 + DSS03.01 + DSS03.05 + DSS05.02 + DSS05.03 + DSS05.04 + DSS05.05 + DSS05.07 + MEA01.01 + MEA01.02 + MEA01.03 + MEA01.04 + MEA01.05 + MEA02.01 + 3.1.7 + CCI-000172 + CCI-000130 + CCI-000135 + CCI-000169 + CCI-002884 + 164.308(a)(1)(ii)(D) + 164.308(a)(3)(ii)(A) + 164.308(a)(5)(ii)(C) + 164.312(a)(2)(i) + 164.312(b) + 164.312(d) + 164.312(e) + 4.2.3.10 + 4.3.2.6.7 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.4.4.7 + 4.3.4.5.6 + 4.3.4.5.7 + 4.3.4.5.8 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 1.13 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.6 + SR 2.8 + SR 2.9 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 6.1 + SR 6.2 + SR 7.1 + SR 7.6 + A.11.2.4 + A.11.2.6 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.13.1.1 + A.13.2.1 + A.14.1.3 + A.14.2.7 + A.15.1.1 + A.15.2.1 + A.15.2.2 + A.16.1.4 + A.16.1.5 + A.16.1.7 + A.6.2.1 + A.6.2.2 + AU-2(d) + AU-12(c) + CM-6(a) + DE.AE-3 + DE.AE-5 + DE.CM-1 + DE.CM-3 + DE.CM-7 + ID.SC-4 + PR.AC-3 + PR.MA-2 + PR.PT-1 + PR.PT-4 + RS.AN-1 + RS.AN-4 + Req-10.2.7 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-OS-000466-GPOS-00210 + SRG-OS-000467-GPOS-00211 + SRG-OS-000468-GPOS-00212 + SRG-APP-000495-CTR-001235 + SRG-APP-000499-CTR-001255 + SRG-APP-000501-CTR-001265 + SRG-APP-000502-CTR-001270 + R73 + 10.2.1.7 + 10.2.1 + 10.2 + OL09-00-000680 + SV-271563r1092546_rule + Auditing file deletions will create an audit trail for files that are removed from the system. The audit trail could aid in system troubleshooting, as well as, detecting -malicious processes that attempt to delete log files to conceal their presence. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +malicious processes that attempt to delete log files to conceal their presence. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { ! ( ( grep -sqE "^.*\.aarch64$" /proc/sys/kernel/osrelease || grep -sqE "^aarch64$" /proc/sys/kernel/arch; ) ); }; then # First perform the remediation of the syscall rule # Retrieve hardware architecture of the underlying system @@ -71406,7 +152527,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -71422,7 +152542,7 @@ then if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -71514,7 +152634,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -71567,7 +152687,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -71661,7 +152780,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -71689,16 +152808,19 @@ done else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-000680 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.7 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.7 - audit_rules_file_deletion_events_rmdir - low_complexity @@ -71712,15 +152834,19 @@ fi audit_arch: b64 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - not ( ansible_architecture == "aarch64" ) - ansible_architecture == "aarch64" or ansible_architecture == "ppc64" or ansible_architecture == "ppc64le" or ansible_architecture == "s390x" or ansible_architecture == "x86_64" tags: + - DISA-STIG-OL09-00-000680 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.7 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.7 - audit_rules_file_deletion_events_rmdir - low_complexity @@ -71797,6 +152923,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -71805,7 +152932,7 @@ fi line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=delete create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -71848,6 +152975,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -71856,18 +152984,22 @@ fi line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=delete create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - not ( ansible_architecture == "aarch64" ) tags: + - DISA-STIG-OL09-00-000680 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.7 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.7 - audit_rules_file_deletion_events_rmdir - low_complexity @@ -71944,6 +153076,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -71952,7 +153085,7 @@ fi line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=delete create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -71995,6 +153128,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -72003,19 +153137,23 @@ fi line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=delete create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - not ( ansible_architecture == "aarch64" ) - audit_arch == "b64" tags: + - DISA-STIG-OL09-00-000680 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.7 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.7 - audit_rules_file_deletion_events_rmdir - low_complexity @@ -72023,17 +153161,17 @@ fi - medium_severity - reboot_required - restrict_strategy - - - - - - - - - - Ensure auditd Collects File Deletion Events by User - unlink - At a minimum, the audit system should collect file deletion events + + + + + + + + + + Ensure auditd Collects File Deletion Events by User - unlink + At a minimum, the audit system should collect file deletion events for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following line to a file with suffix .rules in the @@ -72044,150 +153182,158 @@ If the auditd daemon is configured to use the utility to read audit rules during daemon startup, add the following line to /etc/audit/audit.rules file, setting ARCH to either b32 or b64 as appropriate for your system: --a always,exit -F arch=ARCH -S unlink -F auid>=1000 -F auid!=unset -F key=delete - BP28(R73) - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 19 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - APO12.06 - APO13.01 - BAI03.05 - BAI08.02 - DSS01.03 - DSS01.04 - DSS02.02 - DSS02.04 - DSS02.07 - DSS03.01 - DSS03.05 - DSS05.02 - DSS05.03 - DSS05.04 - DSS05.05 - DSS05.07 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.1.7 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-000172 - CCI-000366 - CCI-002884 - 164.308(a)(1)(ii)(D) - 164.308(a)(3)(ii)(A) - 164.308(a)(5)(ii)(C) - 164.312(a)(2)(i) - 164.312(b) - 164.312(d) - 164.312(e) - 4.2.3.10 - 4.3.2.6.7 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.4.4.7 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 1.13 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.6 - SR 2.8 - SR 2.9 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 6.1 - SR 6.2 - SR 7.1 - SR 7.6 - A.11.2.4 - A.11.2.6 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.14.2.7 - A.15.1.1 - A.15.2.1 - A.15.2.2 - A.16.1.4 - A.16.1.5 - A.16.1.7 - A.6.2.1 - A.6.2.2 - AU-2(d) - AU-12(c) - CM-6(a) - DE.AE-3 - DE.AE-5 - DE.CM-1 - DE.CM-3 - DE.CM-7 - ID.SC-4 - PR.AC-3 - PR.MA-2 - PR.PT-1 - PR.PT-4 - RS.AN-1 - RS.AN-4 - FAU_GEN.1.1.c - Req-10.2.7 - 10.2.1.7 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-OS-000466-GPOS-00210 - SRG-OS-000467-GPOS-00211 - SRG-OS-000468-GPOS-00212 - Auditing file deletions will create an audit trail for files that are removed +-a always,exit -F arch=ARCH -S unlink -F auid>=1000 -F auid!=unset -F key=delete + + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 19 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + APO10.01 + APO10.03 + APO10.04 + APO10.05 + APO11.04 + APO12.06 + APO13.01 + BAI03.05 + BAI08.02 + DSS01.03 + DSS01.04 + DSS02.02 + DSS02.04 + DSS02.07 + DSS03.01 + DSS03.05 + DSS05.02 + DSS05.03 + DSS05.04 + DSS05.05 + DSS05.07 + MEA01.01 + MEA01.02 + MEA01.03 + MEA01.04 + MEA01.05 + MEA02.01 + 3.1.7 + CCI-000172 + CCI-000130 + CCI-000135 + CCI-000169 + CCI-002884 + 164.308(a)(1)(ii)(D) + 164.308(a)(3)(ii)(A) + 164.308(a)(5)(ii)(C) + 164.312(a)(2)(i) + 164.312(b) + 164.312(d) + 164.312(e) + 4.2.3.10 + 4.3.2.6.7 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.4.4.7 + 4.3.4.5.6 + 4.3.4.5.7 + 4.3.4.5.8 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 1.13 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.6 + SR 2.8 + SR 2.9 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 6.1 + SR 6.2 + SR 7.1 + SR 7.6 + A.11.2.4 + A.11.2.6 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.13.1.1 + A.13.2.1 + A.14.1.3 + A.14.2.7 + A.15.1.1 + A.15.2.1 + A.15.2.2 + A.16.1.4 + A.16.1.5 + A.16.1.7 + A.6.2.1 + A.6.2.2 + AU-2(d) + AU-12(c) + CM-6(a) + DE.AE-3 + DE.AE-5 + DE.CM-1 + DE.CM-3 + DE.CM-7 + ID.SC-4 + PR.AC-3 + PR.MA-2 + PR.PT-1 + PR.PT-4 + RS.AN-1 + RS.AN-4 + Req-10.2.7 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-OS-000466-GPOS-00210 + SRG-OS-000467-GPOS-00211 + SRG-OS-000468-GPOS-00212 + SRG-APP-000495-CTR-001235 + SRG-APP-000499-CTR-001255 + SRG-APP-000501-CTR-001265 + SRG-APP-000502-CTR-001270 + R73 + 10.2.1.7 + 10.2.1 + 10.2 + OL09-00-000680 + SV-271563r1092546_rule + Auditing file deletions will create an audit trail for files that are removed from the system. The audit trail could aid in system troubleshooting, as well as, detecting -malicious processes that attempt to delete log files to conceal their presence. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +malicious processes that attempt to delete log files to conceal their presence. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { ! ( ( grep -sqE "^.*\.aarch64$" /proc/sys/kernel/osrelease || grep -sqE "^aarch64$" /proc/sys/kernel/arch; ) ); }; then # First perform the remediation of the syscall rule # Retrieve hardware architecture of the underlying system @@ -72231,7 +153377,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -72247,7 +153392,7 @@ then if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -72339,7 +153484,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -72392,7 +153537,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -72486,7 +153630,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -72514,16 +153658,19 @@ done else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-000680 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.7 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.7 - audit_rules_file_deletion_events_unlink - low_complexity @@ -72537,15 +153684,19 @@ fi audit_arch: b64 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - not ( ansible_architecture == "aarch64" ) - ansible_architecture == "aarch64" or ansible_architecture == "ppc64" or ansible_architecture == "ppc64le" or ansible_architecture == "s390x" or ansible_architecture == "x86_64" tags: + - DISA-STIG-OL09-00-000680 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.7 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.7 - audit_rules_file_deletion_events_unlink - low_complexity @@ -72622,6 +153773,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -72630,7 +153782,7 @@ fi line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=delete create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -72673,6 +153825,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -72681,18 +153834,22 @@ fi line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=delete create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - not ( ansible_architecture == "aarch64" ) tags: + - DISA-STIG-OL09-00-000680 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.7 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.7 - audit_rules_file_deletion_events_unlink - low_complexity @@ -72769,6 +153926,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -72777,7 +153935,7 @@ fi line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=delete create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -72820,6 +153978,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -72828,19 +153987,23 @@ fi line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=delete create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - not ( ansible_architecture == "aarch64" ) - audit_arch == "b64" tags: + - DISA-STIG-OL09-00-000680 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.7 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.7 - audit_rules_file_deletion_events_unlink - low_complexity @@ -72848,17 +154011,17 @@ fi - medium_severity - reboot_required - restrict_strategy - - - - - - - - - - Ensure auditd Collects File Deletion Events by User - unlinkat - At a minimum, the audit system should collect file deletion events + + + + + + + + + + Ensure auditd Collects File Deletion Events by User - unlinkat + At a minimum, the audit system should collect file deletion events for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following line to a file with suffix .rules in the @@ -72869,150 +154032,157 @@ If the auditd daemon is configured to use the utility to read audit rules during daemon startup, add the following line to /etc/audit/audit.rules file, setting ARCH to either b32 or b64 as appropriate for your system: --a always,exit -F arch=ARCH -S unlinkat -F auid>=1000 -F auid!=unset -F key=delete - BP28(R73) - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 19 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - APO12.06 - APO13.01 - BAI03.05 - BAI08.02 - DSS01.03 - DSS01.04 - DSS02.02 - DSS02.04 - DSS02.07 - DSS03.01 - DSS03.05 - DSS05.02 - DSS05.03 - DSS05.04 - DSS05.05 - DSS05.07 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.1.7 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-000172 - CCI-000366 - CCI-002884 - 164.308(a)(1)(ii)(D) - 164.308(a)(3)(ii)(A) - 164.308(a)(5)(ii)(C) - 164.312(a)(2)(i) - 164.312(b) - 164.312(d) - 164.312(e) - 4.2.3.10 - 4.3.2.6.7 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.4.4.7 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 1.13 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.6 - SR 2.8 - SR 2.9 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 6.1 - SR 6.2 - SR 7.1 - SR 7.6 - A.11.2.4 - A.11.2.6 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.14.2.7 - A.15.1.1 - A.15.2.1 - A.15.2.2 - A.16.1.4 - A.16.1.5 - A.16.1.7 - A.6.2.1 - A.6.2.2 - AU-2(d) - AU-12(c) - CM-6(a) - DE.AE-3 - DE.AE-5 - DE.CM-1 - DE.CM-3 - DE.CM-7 - ID.SC-4 - PR.AC-3 - PR.MA-2 - PR.PT-1 - PR.PT-4 - RS.AN-1 - RS.AN-4 - FAU_GEN.1.1.c - Req-10.2.7 - 10.2.1.7 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-OS-000466-GPOS-00210 - SRG-OS-000467-GPOS-00211 - SRG-OS-000468-GPOS-00212 - Auditing file deletions will create an audit trail for files that are removed +-a always,exit -F arch=ARCH -S unlinkat -F auid>=1000 -F auid!=unset -F key=delete + + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 19 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + APO10.01 + APO10.03 + APO10.04 + APO10.05 + APO11.04 + APO12.06 + APO13.01 + BAI03.05 + BAI08.02 + DSS01.03 + DSS01.04 + DSS02.02 + DSS02.04 + DSS02.07 + DSS03.01 + DSS03.05 + DSS05.02 + DSS05.03 + DSS05.04 + DSS05.05 + DSS05.07 + MEA01.01 + MEA01.02 + MEA01.03 + MEA01.04 + MEA01.05 + MEA02.01 + 3.1.7 + CCI-000172 + CCI-000130 + CCI-000135 + CCI-000169 + CCI-002884 + 164.308(a)(1)(ii)(D) + 164.308(a)(3)(ii)(A) + 164.308(a)(5)(ii)(C) + 164.312(a)(2)(i) + 164.312(b) + 164.312(d) + 164.312(e) + 4.2.3.10 + 4.3.2.6.7 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.3.6.5 + 4.3.3.6.6 + 4.3.3.6.7 + 4.3.3.6.8 + 4.3.4.4.7 + 4.3.4.5.6 + 4.3.4.5.7 + 4.3.4.5.8 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 1.13 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.6 + SR 2.8 + SR 2.9 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 6.1 + SR 6.2 + SR 7.1 + SR 7.6 + A.11.2.4 + A.11.2.6 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.13.1.1 + A.13.2.1 + A.14.1.3 + A.14.2.7 + A.15.1.1 + A.15.2.1 + A.15.2.2 + A.16.1.4 + A.16.1.5 + A.16.1.7 + A.6.2.1 + A.6.2.2 + AU-2(d) + AU-12(c) + CM-6(a) + DE.AE-3 + DE.AE-5 + DE.CM-1 + DE.CM-3 + DE.CM-7 + ID.SC-4 + PR.AC-3 + PR.MA-2 + PR.PT-1 + PR.PT-4 + RS.AN-1 + RS.AN-4 + Req-10.2.7 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-OS-000466-GPOS-00210 + SRG-OS-000467-GPOS-00211 + SRG-OS-000468-GPOS-00212 + SRG-APP-000495-CTR-001235 + SRG-APP-000499-CTR-001255 + SRG-APP-000501-CTR-001265 + SRG-APP-000502-CTR-001270 + R73 + 10.2.1.7 + 10.2.1 + 10.2 + OL09-00-000680 + SV-271563r1092546_rule + Auditing file deletions will create an audit trail for files that are removed from the system. The audit trail could aid in system troubleshooting, as well as, detecting -malicious processes that attempt to delete log files to conceal their presence. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +malicious processes that attempt to delete log files to conceal their presence. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then # First perform the remediation of the syscall rule # Retrieve hardware architecture of the underlying system @@ -73056,7 +154226,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -73072,7 +154241,7 @@ then if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -73164,7 +154333,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -73217,7 +154386,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -73311,7 +154479,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -73339,16 +154507,19 @@ done else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-000680 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.7 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.7 - audit_rules_file_deletion_events_unlinkat - low_complexity @@ -73362,15 +154533,18 @@ fi audit_arch: b64 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - ansible_architecture == "aarch64" or ansible_architecture == "ppc64" or ansible_architecture == "ppc64le" or ansible_architecture == "s390x" or ansible_architecture == "x86_64" tags: + - DISA-STIG-OL09-00-000680 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.7 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.7 - audit_rules_file_deletion_events_unlinkat - low_complexity @@ -73447,6 +154621,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -73455,7 +154630,7 @@ fi line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=delete create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -73498,6 +154673,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -73506,18 +154682,21 @@ fi line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=delete create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-000680 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.7 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.7 - audit_rules_file_deletion_events_unlinkat - low_complexity @@ -73594,6 +154773,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -73602,7 +154782,7 @@ fi line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=delete create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -73645,6 +154825,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -73653,19 +154834,22 @@ fi line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=delete create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - audit_arch == "b64" tags: + - DISA-STIG-OL09-00-000680 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.7 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.7 - audit_rules_file_deletion_events_unlinkat - low_complexity @@ -73673,18 +154857,18 @@ fi - medium_severity - reboot_required - restrict_strategy - - - - - - - - - - - Record Unauthorized Access Attempts Events to Files (unsuccessful) - At a minimum, the audit system should collect unauthorized file + + + + + + + + + + + Record Unauthorized Access Attempts Events to Files (unsuccessful) + At a minimum, the audit system should collect unauthorized file accesses for all users and root. Note that the "-F arch=b32" lines should be present even on a 64 bit system. These commands identify system calls for auditing. Even if the system is 64 bit it can still execute 32 bit system @@ -73697,10 +154881,11 @@ Add the following to /etc/audit/audit.rules: If your system is 64 bit then these lines should be duplicated and the arch=b32 replaced with arch=b64 as follows: -a always,exit -F arch=b64 -S creat,open,openat,open_by_handle_at,truncate,ftruncate -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access - -a always,exit -F arch=b64 -S creat,open,openat,open_by_handle_at,truncate,ftruncate -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access - - Ensure auditd Collects Unauthorized Access Attempts to Files (unsuccessful) - At a minimum the audit system should collect unauthorized file + -a always,exit -F arch=b64 -S creat,open,openat,open_by_handle_at,truncate,ftruncate -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access + + + Ensure auditd Collects Unauthorized Access Attempts to Files (unsuccessful) + At a minimum the audit system should collect unauthorized file accesses for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following lines to a file with suffix @@ -73719,134 +154904,135 @@ utility to read audit rules during daemon startup, add the following lines to If the system is 64 bit then also add the following lines: -a always,exit -F arch=b64 -S creat,open,openat,open_by_handle_at,truncate,ftruncate -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access --a always,exit -F arch=b64 -S creat,open,openat,open_by_handle_at,truncate,ftruncate -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access - This rule checks for multiple syscalls related to unsuccessful file modification; +-a always,exit -F arch=b64 -S creat,open,openat,open_by_handle_at,truncate,ftruncate -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access + + This rule checks for multiple syscalls related to unsuccessful file modification; it was written with DISA STIG in mind. Other policies should use a separate rule for each syscall that needs to be checked. For example: -audit_rules_unsuccessful_file_modification_openaudit_rules_unsuccessful_file_modification_ftruncateaudit_rules_unsuccessful_file_modification_creat - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 19 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 5.4.1.1 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - APO12.06 - APO13.01 - BAI03.05 - BAI08.02 - DSS01.03 - DSS01.04 - DSS02.02 - DSS02.04 - DSS02.07 - DSS03.01 - DSS03.05 - DSS05.02 - DSS05.03 - DSS05.04 - DSS05.05 - DSS05.07 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.1.7 - CCI-000172 - CCI-002884 - 4.2.3.10 - 4.3.2.6.7 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.3.6.6 - 4.3.4.4.7 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 1.13 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.6 - SR 2.8 - SR 2.9 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 6.1 - SR 6.2 - SR 7.1 - SR 7.6 - 0582 - 0584 - 05885 - 0586 - 0846 - 0957 - A.11.2.6 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.14.2.7 - A.15.2.1 - A.15.2.2 - A.16.1.4 - A.16.1.5 - A.16.1.7 - A.6.2.1 - A.6.2.2 - AU-2(d) - AU-12(c) - CM-6(a) - DE.AE-3 - DE.AE-5 - DE.CM-1 - DE.CM-3 - DE.CM-7 - ID.SC-4 - PR.AC-3 - PR.PT-1 - PR.PT-4 - RS.AN-1 - RS.AN-4 - Req-10.2.4 - Req-10.2.1 - 10.2.1.1 - 10.2.1.4 - Unsuccessful attempts to access files could be an indicator of malicious activity on a system. Auditing -these events could serve as evidence of potential system compromise. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +audit_rules_unsuccessful_file_modification_openaudit_rules_unsuccessful_file_modification_ftruncateaudit_rules_unsuccessful_file_modification_creat + + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 19 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 5.4.1.1 + APO10.01 + APO10.03 + APO10.04 + APO10.05 + APO11.04 + APO12.06 + APO13.01 + BAI03.05 + BAI08.02 + DSS01.03 + DSS01.04 + DSS02.02 + DSS02.04 + DSS02.07 + DSS03.01 + DSS03.05 + DSS05.02 + DSS05.03 + DSS05.04 + DSS05.05 + DSS05.07 + MEA01.01 + MEA01.02 + MEA01.03 + MEA01.04 + MEA01.05 + MEA02.01 + 3.1.7 + CCI-000172 + CCI-002884 + 4.2.3.10 + 4.3.2.6.7 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.3.6.6 + 4.3.4.4.7 + 4.3.4.5.6 + 4.3.4.5.7 + 4.3.4.5.8 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 1.13 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.6 + SR 2.8 + SR 2.9 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 6.1 + SR 6.2 + SR 7.1 + SR 7.6 + 0582 + 0584 + 05885 + 0586 + 0846 + 0957 + A.11.2.6 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.13.1.1 + A.13.2.1 + A.14.1.3 + A.14.2.7 + A.15.2.1 + A.15.2.2 + A.16.1.4 + A.16.1.5 + A.16.1.7 + A.6.2.1 + A.6.2.2 + AU-2(d) + AU-12(c) + CM-6(a) + DE.AE-3 + DE.AE-5 + DE.CM-1 + DE.CM-3 + DE.CM-7 + ID.SC-4 + PR.AC-3 + PR.PT-1 + PR.PT-4 + RS.AN-1 + RS.AN-4 + Req-10.2.4 + Req-10.2.1 + Unsuccessful attempts to access files could be an indicator of malicious activity on a system. Auditing +these events could serve as evidence of potential system compromise. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { ! ( ( grep -sqE "^.*\.aarch64$" /proc/sys/kernel/osrelease || grep -sqE "^aarch64$" /proc/sys/kernel/arch; ) ); }; then # Perform the remediation of the syscall rule # Retrieve hardware architecture of the underlying system @@ -73892,7 +155078,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -73908,7 +155093,7 @@ then if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -74000,7 +155185,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -74053,7 +155238,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -74147,7 +155331,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -74209,7 +155393,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -74225,7 +155408,7 @@ then if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -74317,7 +155500,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -74370,7 +155553,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -74464,7 +155646,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -74493,17 +155675,17 @@ done else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - - - - - - - - Record Unsuccessful Access Attempts to Files - creat - At a minimum, the audit system should collect unauthorized file + + + + + + + + + + Record Unsuccessful Access Attempts to Files - creat + At a minimum, the audit system should collect unauthorized file accesses for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following lines to a file with suffix @@ -74522,148 +155704,151 @@ utility to read audit rules during daemon startup, add the following lines to If the system is 64 bit then also add the following lines: -a always,exit -F arch=b64 -S creat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access --a always,exit -F arch=b64 -S creat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access - Note that these rules can be configured in a +-a always,exit -F arch=b64 -S creat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access + + Note that these rules can be configured in a number of ways while still achieving the desired effect. Here the system calls have been placed independent of other system calls. Grouping these system -calls with others as identifying earlier in this guide is more efficient. - BP28(R73) - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 19 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - APO12.06 - APO13.01 - BAI03.05 - BAI08.02 - DSS01.03 - DSS01.04 - DSS02.02 - DSS02.04 - DSS02.07 - DSS03.01 - DSS03.05 - DSS05.02 - DSS05.03 - DSS05.04 - DSS05.05 - DSS05.07 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.1.7 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-000172 - CCI-002884 - 164.308(a)(1)(ii)(D) - 164.308(a)(3)(ii)(A) - 164.308(a)(5)(ii)(C) - 164.312(a)(2)(i) - 164.312(b) - 164.312(d) - 164.312(e) - 4.2.3.10 - 4.3.2.6.7 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.3.6.6 - 4.3.4.4.7 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 1.13 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.6 - SR 2.8 - SR 2.9 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 6.1 - SR 6.2 - SR 7.1 - SR 7.6 - A.11.2.6 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.14.2.7 - A.15.2.1 - A.15.2.2 - A.16.1.4 - A.16.1.5 - A.16.1.7 - A.6.2.1 - A.6.2.2 - AU-2(d) - AU-12(c) - CM-6(a) - DE.AE-3 - DE.AE-5 - DE.CM-1 - DE.CM-3 - DE.CM-7 - ID.SC-4 - PR.AC-3 - PR.PT-1 - PR.PT-4 - RS.AN-1 - RS.AN-4 - FAU_GEN.1.1.c - Req-10.2.4 - Req-10.2.1 - 10.2.1.1 - 10.2.1.4 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-OS-000064-GPOS-00033 - SRG-OS-000458-GPOS-00203 - SRG-OS-000461-GPOS-00205 - Unsuccessful attempts to access files could be an indicator of malicious activity on a system. Auditing -these events could serve as evidence of potential system compromise. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +calls with others as identifying earlier in this guide is more efficient. + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 19 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + APO10.01 + APO10.03 + APO10.04 + APO10.05 + APO11.04 + APO12.06 + APO13.01 + BAI03.05 + BAI08.02 + DSS01.03 + DSS01.04 + DSS02.02 + DSS02.04 + DSS02.07 + DSS03.01 + DSS03.05 + DSS05.02 + DSS05.03 + DSS05.04 + DSS05.05 + DSS05.07 + MEA01.01 + MEA01.02 + MEA01.03 + MEA01.04 + MEA01.05 + MEA02.01 + 3.1.7 + CCI-000172 + CCI-000130 + CCI-000135 + CCI-000169 + CCI-002884 + 164.308(a)(1)(ii)(D) + 164.308(a)(3)(ii)(A) + 164.308(a)(5)(ii)(C) + 164.312(a)(2)(i) + 164.312(b) + 164.312(d) + 164.312(e) + 4.2.3.10 + 4.3.2.6.7 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.3.6.6 + 4.3.4.4.7 + 4.3.4.5.6 + 4.3.4.5.7 + 4.3.4.5.8 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 1.13 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.6 + SR 2.8 + SR 2.9 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 6.1 + SR 6.2 + SR 7.1 + SR 7.6 + A.11.2.6 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.13.1.1 + A.13.2.1 + A.14.1.3 + A.14.2.7 + A.15.2.1 + A.15.2.2 + A.16.1.4 + A.16.1.5 + A.16.1.7 + A.6.2.1 + A.6.2.2 + AU-2(d) + AU-12(c) + CM-6(a) + DE.AE-3 + DE.AE-5 + DE.CM-1 + DE.CM-3 + DE.CM-7 + ID.SC-4 + PR.AC-3 + PR.PT-1 + PR.PT-4 + RS.AN-1 + RS.AN-4 + Req-10.2.4 + Req-10.2.1 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-OS-000064-GPOS-00033 + SRG-OS-000458-GPOS-00203 + SRG-OS-000461-GPOS-00205 + SRG-APP-000495-CTR-001235 + R73 + A.3.SEC-OL9 + OL09-00-000635 + SV-271554r1092528_rule + Unsuccessful attempts to access files could be an indicator of malicious activity on a system. Auditing +these events could serve as evidence of potential system compromise. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { ! ( ( grep -sqE "^.*\.aarch64$" /proc/sys/kernel/osrelease || grep -sqE "^aarch64$" /proc/sys/kernel/arch; ) ); }; then # First perform the remediation of the syscall rule # Retrieve hardware architecture of the underlying system @@ -74708,7 +155893,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -74724,7 +155908,7 @@ then if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -74816,7 +156000,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -74869,7 +156053,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -74963,7 +156146,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -75022,7 +156205,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -75038,7 +156220,7 @@ then if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -75130,7 +156312,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -75183,7 +156365,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -75277,7 +156458,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -75305,19 +156486,18 @@ done else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-000635 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.1 - PCI-DSS-Req-10.2.4 - - PCI-DSSv4-10.2.1.1 - - PCI-DSSv4-10.2.1.4 - audit_rules_unsuccessful_file_modification_creat - low_complexity - low_disruption @@ -75330,18 +156510,18 @@ fi audit_arch: b64 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - not ( ansible_architecture == "aarch64" ) - ansible_architecture == "aarch64" or ansible_architecture == "ppc64" or ansible_architecture == "ppc64le" or ansible_architecture == "s390x" or ansible_architecture == "x86_64" tags: + - DISA-STIG-OL09-00-000635 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.1 - PCI-DSS-Req-10.2.4 - - PCI-DSSv4-10.2.1.1 - - PCI-DSSv4-10.2.1.4 - audit_rules_unsuccessful_file_modification_creat - low_complexity - low_disruption @@ -75418,6 +156598,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -75426,7 +156607,7 @@ fi line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -75470,6 +156651,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -75478,21 +156660,21 @@ fi line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - not ( ansible_architecture == "aarch64" ) tags: + - DISA-STIG-OL09-00-000635 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.1 - PCI-DSS-Req-10.2.4 - - PCI-DSSv4-10.2.1.1 - - PCI-DSSv4-10.2.1.4 - audit_rules_unsuccessful_file_modification_creat - low_complexity - low_disruption @@ -75569,6 +156751,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -75577,7 +156760,7 @@ fi line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -75621,6 +156804,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -75629,22 +156813,22 @@ fi line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - not ( ansible_architecture == "aarch64" ) - audit_arch == "b64" tags: + - DISA-STIG-OL09-00-000635 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.1 - PCI-DSS-Req-10.2.4 - - PCI-DSSv4-10.2.1.1 - - PCI-DSSv4-10.2.1.4 - audit_rules_unsuccessful_file_modification_creat - low_complexity - low_disruption @@ -75721,6 +156905,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -75729,7 +156914,7 @@ fi line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -75773,6 +156958,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -75781,21 +156967,21 @@ fi line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - not ( ansible_architecture == "aarch64" ) tags: + - DISA-STIG-OL09-00-000635 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.1 - PCI-DSS-Req-10.2.4 - - PCI-DSSv4-10.2.1.1 - - PCI-DSSv4-10.2.1.4 - audit_rules_unsuccessful_file_modification_creat - low_complexity - low_disruption @@ -75872,6 +157058,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -75880,7 +157067,7 @@ fi line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -75924,6 +157111,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -75932,39 +157120,39 @@ fi line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - not ( ansible_architecture == "aarch64" ) - audit_arch == "b64" tags: + - DISA-STIG-OL09-00-000635 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.1 - PCI-DSS-Req-10.2.4 - - PCI-DSSv4-10.2.1.1 - - PCI-DSSv4-10.2.1.4 - audit_rules_unsuccessful_file_modification_creat - low_complexity - low_disruption - medium_severity - reboot_required - restrict_strategy - - - - - - - - - - Record Unsuccessful Access Attempts to Files - ftruncate - At a minimum, the audit system should collect unauthorized file + + + + + + + + + + Record Unsuccessful Access Attempts to Files - ftruncate + At a minimum, the audit system should collect unauthorized file accesses for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following lines to a file with suffix @@ -75986,148 +157174,150 @@ utility to read audit rules during daemon startup, add the following lines to If the system is 64 bit then also add the following lines: -a always,exit -F arch=b64 -S ftruncate -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access --a always,exit -F arch=b64 -S ftruncate -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access - Note that these rules can be configured in a +-a always,exit -F arch=b64 -S ftruncate -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access + + Note that these rules can be configured in a number of ways while still achieving the desired effect. Here the system calls have been placed independent of other system calls. Grouping these system -calls with others as identifying earlier in this guide is more efficient. - BP28(R73) - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 19 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - APO12.06 - APO13.01 - BAI03.05 - BAI08.02 - DSS01.03 - DSS01.04 - DSS02.02 - DSS02.04 - DSS02.07 - DSS03.01 - DSS03.05 - DSS05.02 - DSS05.03 - DSS05.04 - DSS05.05 - DSS05.07 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.1.7 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-000172 - CCI-002884 - 164.308(a)(1)(ii)(D) - 164.308(a)(3)(ii)(A) - 164.308(a)(5)(ii)(C) - 164.312(a)(2)(i) - 164.312(b) - 164.312(d) - 164.312(e) - 4.2.3.10 - 4.3.2.6.7 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.3.6.6 - 4.3.4.4.7 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 1.13 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.6 - SR 2.8 - SR 2.9 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 6.1 - SR 6.2 - SR 7.1 - SR 7.6 - A.11.2.6 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.14.2.7 - A.15.2.1 - A.15.2.2 - A.16.1.4 - A.16.1.5 - A.16.1.7 - A.6.2.1 - A.6.2.2 - AU-2(d) - AU-12(c) - CM-6(a) - DE.AE-3 - DE.AE-5 - DE.CM-1 - DE.CM-3 - DE.CM-7 - ID.SC-4 - PR.AC-3 - PR.PT-1 - PR.PT-4 - RS.AN-1 - RS.AN-4 - FAU_GEN.1.1.c - Req-10.2.4 - Req-10.2.1 - 10.2.1.1 - 10.2.1.4 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-OS-000064-GPOS-00033 - SRG-OS-000458-GPOS-00203 - SRG-OS-000461-GPOS-00205 - Unsuccessful attempts to access files could be an indicator of malicious activity on a system. Auditing -these events could serve as evidence of potential system compromise. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +calls with others as identifying earlier in this guide is more efficient. + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 19 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + APO10.01 + APO10.03 + APO10.04 + APO10.05 + APO11.04 + APO12.06 + APO13.01 + BAI03.05 + BAI08.02 + DSS01.03 + DSS01.04 + DSS02.02 + DSS02.04 + DSS02.07 + DSS03.01 + DSS03.05 + DSS05.02 + DSS05.03 + DSS05.04 + DSS05.05 + DSS05.07 + MEA01.01 + MEA01.02 + MEA01.03 + MEA01.04 + MEA01.05 + MEA02.01 + 3.1.7 + CCI-000172 + CCI-000130 + CCI-000135 + CCI-000169 + CCI-002884 + 164.308(a)(1)(ii)(D) + 164.308(a)(3)(ii)(A) + 164.308(a)(5)(ii)(C) + 164.312(a)(2)(i) + 164.312(b) + 164.312(d) + 164.312(e) + 4.2.3.10 + 4.3.2.6.7 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.3.6.6 + 4.3.4.4.7 + 4.3.4.5.6 + 4.3.4.5.7 + 4.3.4.5.8 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 1.13 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.6 + SR 2.8 + SR 2.9 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 6.1 + SR 6.2 + SR 7.1 + SR 7.6 + A.11.2.6 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.13.1.1 + A.13.2.1 + A.14.1.3 + A.14.2.7 + A.15.2.1 + A.15.2.2 + A.16.1.4 + A.16.1.5 + A.16.1.7 + A.6.2.1 + A.6.2.2 + AU-2(d) + AU-12(c) + CM-6(a) + DE.AE-3 + DE.AE-5 + DE.CM-1 + DE.CM-3 + DE.CM-7 + ID.SC-4 + PR.AC-3 + PR.PT-1 + PR.PT-4 + RS.AN-1 + RS.AN-4 + Req-10.2.4 + Req-10.2.1 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-OS-000064-GPOS-00033 + SRG-OS-000458-GPOS-00203 + SRG-OS-000461-GPOS-00205 + SRG-APP-000495-CTR-001235 + R73 + A.3.SEC-OL9 + OL09-00-000635 + SV-271554r1092528_rule + Unsuccessful attempts to access files could be an indicator of malicious activity on a system. Auditing +these events could serve as evidence of potential system compromise. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then # First perform the remediation of the syscall rule # Retrieve hardware architecture of the underlying system @@ -76172,7 +157362,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -76188,7 +157377,7 @@ then if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -76280,7 +157469,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -76333,7 +157522,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -76427,7 +157615,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -76486,7 +157674,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -76502,7 +157689,7 @@ then if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -76594,7 +157781,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -76647,7 +157834,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -76741,7 +157927,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -76769,19 +157955,18 @@ done else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-000635 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.1 - PCI-DSS-Req-10.2.4 - - PCI-DSSv4-10.2.1.1 - - PCI-DSSv4-10.2.1.4 - audit_rules_unsuccessful_file_modification_ftruncate - low_complexity - low_disruption @@ -76794,18 +157979,17 @@ fi audit_arch: b64 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - ansible_architecture == "aarch64" or ansible_architecture == "ppc64" or ansible_architecture == "ppc64le" or ansible_architecture == "s390x" or ansible_architecture == "x86_64" tags: + - DISA-STIG-OL09-00-000635 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.1 - PCI-DSS-Req-10.2.4 - - PCI-DSSv4-10.2.1.1 - - PCI-DSSv4-10.2.1.4 - audit_rules_unsuccessful_file_modification_ftruncate - low_complexity - low_disruption @@ -76882,6 +158066,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -76890,7 +158075,7 @@ fi line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -76934,6 +158119,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -76942,21 +158128,20 @@ fi line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-000635 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.1 - PCI-DSS-Req-10.2.4 - - PCI-DSSv4-10.2.1.1 - - PCI-DSSv4-10.2.1.4 - audit_rules_unsuccessful_file_modification_ftruncate - low_complexity - low_disruption @@ -77033,6 +158218,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -77041,7 +158227,7 @@ fi line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -77085,6 +158271,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -77093,22 +158280,21 @@ fi line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - audit_arch == "b64" tags: + - DISA-STIG-OL09-00-000635 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.1 - PCI-DSS-Req-10.2.4 - - PCI-DSSv4-10.2.1.1 - - PCI-DSSv4-10.2.1.4 - audit_rules_unsuccessful_file_modification_ftruncate - low_complexity - low_disruption @@ -77185,6 +158371,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -77193,7 +158380,7 @@ fi line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -77237,6 +158424,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -77245,21 +158433,20 @@ fi line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-000635 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.1 - PCI-DSS-Req-10.2.4 - - PCI-DSSv4-10.2.1.1 - - PCI-DSSv4-10.2.1.4 - audit_rules_unsuccessful_file_modification_ftruncate - low_complexity - low_disruption @@ -77336,6 +158523,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -77344,7 +158532,7 @@ fi line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -77388,6 +158576,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -77396,39 +158585,38 @@ fi line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - audit_arch == "b64" tags: + - DISA-STIG-OL09-00-000635 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.1 - PCI-DSS-Req-10.2.4 - - PCI-DSSv4-10.2.1.1 - - PCI-DSSv4-10.2.1.4 - audit_rules_unsuccessful_file_modification_ftruncate - low_complexity - low_disruption - medium_severity - reboot_required - restrict_strategy - - - - - - - - - - Record Unsuccessful Access Attempts to Files - open - At a minimum, the audit system should collect unauthorized file + + + + + + + + + + Record Unsuccessful Access Attempts to Files - open + At a minimum, the audit system should collect unauthorized file accesses for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following lines to a file with suffix @@ -77450,148 +158638,151 @@ utility to read audit rules during daemon startup, add the following lines to If the system is 64 bit then also add the following lines: -a always,exit -F arch=b64 -S open -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access --a always,exit -F arch=b64 -S open -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access - Note that these rules can be configured in a +-a always,exit -F arch=b64 -S open -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access + + Note that these rules can be configured in a number of ways while still achieving the desired effect. Here the system calls have been placed independent of other system calls. Grouping these system -calls with others as identifying earlier in this guide is more efficient. - BP28(R73) - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 19 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - APO12.06 - APO13.01 - BAI03.05 - BAI08.02 - DSS01.03 - DSS01.04 - DSS02.02 - DSS02.04 - DSS02.07 - DSS03.01 - DSS03.05 - DSS05.02 - DSS05.03 - DSS05.04 - DSS05.05 - DSS05.07 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.1.7 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-000172 - CCI-002884 - 164.308(a)(1)(ii)(D) - 164.308(a)(3)(ii)(A) - 164.308(a)(5)(ii)(C) - 164.312(a)(2)(i) - 164.312(b) - 164.312(d) - 164.312(e) - 4.2.3.10 - 4.3.2.6.7 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.3.6.6 - 4.3.4.4.7 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 1.13 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.6 - SR 2.8 - SR 2.9 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 6.1 - SR 6.2 - SR 7.1 - SR 7.6 - A.11.2.6 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.14.2.7 - A.15.2.1 - A.15.2.2 - A.16.1.4 - A.16.1.5 - A.16.1.7 - A.6.2.1 - A.6.2.2 - AU-2(d) - AU-12(c) - CM-6(a) - DE.AE-3 - DE.AE-5 - DE.CM-1 - DE.CM-3 - DE.CM-7 - ID.SC-4 - PR.AC-3 - PR.PT-1 - PR.PT-4 - RS.AN-1 - RS.AN-4 - FAU_GEN.1.1.c - Req-10.2.4 - Req-10.2.1 - 10.2.1.1 - 10.2.1.4 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-OS-000064-GPOS-00033 - SRG-OS-000458-GPOS-00203 - SRG-OS-000461-GPOS-00205 - Unsuccessful attempts to access files could be an indicator of malicious activity on a system. Auditing -these events could serve as evidence of potential system compromise. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +calls with others as identifying earlier in this guide is more efficient. + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 19 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + APO10.01 + APO10.03 + APO10.04 + APO10.05 + APO11.04 + APO12.06 + APO13.01 + BAI03.05 + BAI08.02 + DSS01.03 + DSS01.04 + DSS02.02 + DSS02.04 + DSS02.07 + DSS03.01 + DSS03.05 + DSS05.02 + DSS05.03 + DSS05.04 + DSS05.05 + DSS05.07 + MEA01.01 + MEA01.02 + MEA01.03 + MEA01.04 + MEA01.05 + MEA02.01 + 3.1.7 + CCI-000172 + CCI-000130 + CCI-000135 + CCI-000169 + CCI-002884 + 164.308(a)(1)(ii)(D) + 164.308(a)(3)(ii)(A) + 164.308(a)(5)(ii)(C) + 164.312(a)(2)(i) + 164.312(b) + 164.312(d) + 164.312(e) + 4.2.3.10 + 4.3.2.6.7 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.3.6.6 + 4.3.4.4.7 + 4.3.4.5.6 + 4.3.4.5.7 + 4.3.4.5.8 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 1.13 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.6 + SR 2.8 + SR 2.9 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 6.1 + SR 6.2 + SR 7.1 + SR 7.6 + A.11.2.6 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.13.1.1 + A.13.2.1 + A.14.1.3 + A.14.2.7 + A.15.2.1 + A.15.2.2 + A.16.1.4 + A.16.1.5 + A.16.1.7 + A.6.2.1 + A.6.2.2 + AU-2(d) + AU-12(c) + CM-6(a) + DE.AE-3 + DE.AE-5 + DE.CM-1 + DE.CM-3 + DE.CM-7 + ID.SC-4 + PR.AC-3 + PR.PT-1 + PR.PT-4 + RS.AN-1 + RS.AN-4 + Req-10.2.4 + Req-10.2.1 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-OS-000064-GPOS-00033 + SRG-OS-000458-GPOS-00203 + SRG-OS-000461-GPOS-00205 + SRG-APP-000495-CTR-001235 + R73 + A.3.SEC-OL9 + OL09-00-000635 + SV-271554r1092528_rule + Unsuccessful attempts to access files could be an indicator of malicious activity on a system. Auditing +these events could serve as evidence of potential system compromise. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { ! ( ( grep -sqE "^.*\.aarch64$" /proc/sys/kernel/osrelease || grep -sqE "^aarch64$" /proc/sys/kernel/arch; ) ); }; then # First perform the remediation of the syscall rule # Retrieve hardware architecture of the underlying system @@ -77636,7 +158827,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -77652,7 +158842,7 @@ then if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -77744,7 +158934,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -77797,7 +158987,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -77891,7 +159080,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -77950,7 +159139,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -77966,7 +159154,7 @@ then if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -78058,7 +159246,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -78111,7 +159299,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -78205,7 +159392,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -78233,19 +159420,18 @@ done else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-000635 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.1 - PCI-DSS-Req-10.2.4 - - PCI-DSSv4-10.2.1.1 - - PCI-DSSv4-10.2.1.4 - audit_rules_unsuccessful_file_modification_open - low_complexity - low_disruption @@ -78258,18 +159444,18 @@ fi audit_arch: b64 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - not ( ansible_architecture == "aarch64" ) - ansible_architecture == "aarch64" or ansible_architecture == "ppc64" or ansible_architecture == "ppc64le" or ansible_architecture == "s390x" or ansible_architecture == "x86_64" tags: + - DISA-STIG-OL09-00-000635 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.1 - PCI-DSS-Req-10.2.4 - - PCI-DSSv4-10.2.1.1 - - PCI-DSSv4-10.2.1.4 - audit_rules_unsuccessful_file_modification_open - low_complexity - low_disruption @@ -78346,6 +159532,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -78354,7 +159541,7 @@ fi line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -78398,6 +159585,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -78406,21 +159594,21 @@ fi line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - not ( ansible_architecture == "aarch64" ) tags: + - DISA-STIG-OL09-00-000635 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.1 - PCI-DSS-Req-10.2.4 - - PCI-DSSv4-10.2.1.1 - - PCI-DSSv4-10.2.1.4 - audit_rules_unsuccessful_file_modification_open - low_complexity - low_disruption @@ -78497,6 +159685,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -78505,7 +159694,7 @@ fi line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -78549,6 +159738,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -78557,22 +159747,22 @@ fi line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - not ( ansible_architecture == "aarch64" ) - audit_arch == "b64" tags: + - DISA-STIG-OL09-00-000635 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.1 - PCI-DSS-Req-10.2.4 - - PCI-DSSv4-10.2.1.1 - - PCI-DSSv4-10.2.1.4 - audit_rules_unsuccessful_file_modification_open - low_complexity - low_disruption @@ -78649,6 +159839,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -78657,7 +159848,7 @@ fi line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -78701,6 +159892,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -78709,21 +159901,21 @@ fi line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - not ( ansible_architecture == "aarch64" ) tags: + - DISA-STIG-OL09-00-000635 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.1 - PCI-DSS-Req-10.2.4 - - PCI-DSSv4-10.2.1.1 - - PCI-DSSv4-10.2.1.4 - audit_rules_unsuccessful_file_modification_open - low_complexity - low_disruption @@ -78800,6 +159992,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -78808,7 +160001,7 @@ fi line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -78852,6 +160045,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -78860,39 +160054,39 @@ fi line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - not ( ansible_architecture == "aarch64" ) - audit_arch == "b64" tags: + - DISA-STIG-OL09-00-000635 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.1 - PCI-DSS-Req-10.2.4 - - PCI-DSSv4-10.2.1.1 - - PCI-DSSv4-10.2.1.4 - audit_rules_unsuccessful_file_modification_open - low_complexity - low_disruption - medium_severity - reboot_required - restrict_strategy - - - - - - - - - - Record Unsuccessful Access Attempts to Files - open_by_handle_at - At a minimum, the audit system should collect unauthorized file + + + + + + + + + + Record Unsuccessful Access Attempts to Files - open_by_handle_at + At a minimum, the audit system should collect unauthorized file accesses for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following lines to a file with suffix @@ -78911,147 +160105,148 @@ utility to read audit rules during daemon startup, add the following lines to If the system is 64 bit then also add the following lines: -a always,exit -F arch=b64 -S open_by_handle_at,truncate,ftruncate -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access --a always,exit -F arch=b64 -S open_by_handle_at,truncate,ftruncate -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access - Note that these rules can be configured in a +-a always,exit -F arch=b64 -S open_by_handle_at,truncate,ftruncate -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access + + Note that these rules can be configured in a number of ways while still achieving the desired effect. Here the system calls have been placed independent of other system calls. Grouping these system -calls with others as identifying earlier in this guide is more efficient. - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 19 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - APO12.06 - APO13.01 - BAI03.05 - BAI08.02 - DSS01.03 - DSS01.04 - DSS02.02 - DSS02.04 - DSS02.07 - DSS03.01 - DSS03.05 - DSS05.02 - DSS05.03 - DSS05.04 - DSS05.05 - DSS05.07 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.1.7 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-000172 - CCI-002884 - 164.308(a)(1)(ii)(D) - 164.308(a)(3)(ii)(A) - 164.308(a)(5)(ii)(C) - 164.312(a)(2)(i) - 164.312(b) - 164.312(d) - 164.312(e) - 4.2.3.10 - 4.3.2.6.7 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.3.6.6 - 4.3.4.4.7 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 1.13 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.6 - SR 2.8 - SR 2.9 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 6.1 - SR 6.2 - SR 7.1 - SR 7.6 - A.11.2.6 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.14.2.7 - A.15.2.1 - A.15.2.2 - A.16.1.4 - A.16.1.5 - A.16.1.7 - A.6.2.1 - A.6.2.2 - AU-2(d) - AU-12(c) - CM-6(a) - DE.AE-3 - DE.AE-5 - DE.CM-1 - DE.CM-3 - DE.CM-7 - ID.SC-4 - PR.AC-3 - PR.PT-1 - PR.PT-4 - RS.AN-1 - RS.AN-4 - FAU_GEN.1.1.c - Req-10.2.4 - Req-10.2.1 - 10.2.1.1 - 10.2.1.4 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-OS-000064-GPOS-00033 - SRG-OS-000458-GPOS-00203 - SRG-OS-000461-GPOS-00205 - Unsuccessful attempts to access files could be an indicator of malicious activity on a system. Auditing -these events could serve as evidence of potential system compromise. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +calls with others as identifying earlier in this guide is more efficient. + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 19 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + APO10.01 + APO10.03 + APO10.04 + APO10.05 + APO11.04 + APO12.06 + APO13.01 + BAI03.05 + BAI08.02 + DSS01.03 + DSS01.04 + DSS02.02 + DSS02.04 + DSS02.07 + DSS03.01 + DSS03.05 + DSS05.02 + DSS05.03 + DSS05.04 + DSS05.05 + DSS05.07 + MEA01.01 + MEA01.02 + MEA01.03 + MEA01.04 + MEA01.05 + MEA02.01 + 3.1.7 + CCI-000172 + CCI-000130 + CCI-000135 + CCI-000169 + CCI-002884 + 164.308(a)(1)(ii)(D) + 164.308(a)(3)(ii)(A) + 164.308(a)(5)(ii)(C) + 164.312(a)(2)(i) + 164.312(b) + 164.312(d) + 164.312(e) + 4.2.3.10 + 4.3.2.6.7 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.3.6.6 + 4.3.4.4.7 + 4.3.4.5.6 + 4.3.4.5.7 + 4.3.4.5.8 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 1.13 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.6 + SR 2.8 + SR 2.9 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 6.1 + SR 6.2 + SR 7.1 + SR 7.6 + A.11.2.6 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.13.1.1 + A.13.2.1 + A.14.1.3 + A.14.2.7 + A.15.2.1 + A.15.2.2 + A.16.1.4 + A.16.1.5 + A.16.1.7 + A.6.2.1 + A.6.2.2 + AU-2(d) + AU-12(c) + CM-6(a) + DE.AE-3 + DE.AE-5 + DE.CM-1 + DE.CM-3 + DE.CM-7 + ID.SC-4 + PR.AC-3 + PR.PT-1 + PR.PT-4 + RS.AN-1 + RS.AN-4 + Req-10.2.4 + Req-10.2.1 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-OS-000064-GPOS-00033 + SRG-OS-000458-GPOS-00203 + SRG-OS-000461-GPOS-00205 + SRG-APP-000495-CTR-001235 + OL09-00-000635 + SV-271554r1092528_rule + Unsuccessful attempts to access files could be an indicator of malicious activity on a system. Auditing +these events could serve as evidence of potential system compromise. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then # First perform the remediation of the syscall rule # Retrieve hardware architecture of the underlying system @@ -79096,7 +160291,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -79112,7 +160306,7 @@ then if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -79204,7 +160398,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -79257,7 +160451,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -79351,7 +160544,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -79410,7 +160603,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -79426,7 +160618,7 @@ then if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -79518,7 +160710,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -79571,7 +160763,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -79665,7 +160856,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -79693,19 +160884,18 @@ done else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-000635 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.1 - PCI-DSS-Req-10.2.4 - - PCI-DSSv4-10.2.1.1 - - PCI-DSSv4-10.2.1.4 - audit_rules_unsuccessful_file_modification_open_by_handle_at - low_complexity - low_disruption @@ -79718,18 +160908,17 @@ fi audit_arch: b64 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - ansible_architecture == "aarch64" or ansible_architecture == "ppc64" or ansible_architecture == "ppc64le" or ansible_architecture == "s390x" or ansible_architecture == "x86_64" tags: + - DISA-STIG-OL09-00-000635 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.1 - PCI-DSS-Req-10.2.4 - - PCI-DSSv4-10.2.1.1 - - PCI-DSSv4-10.2.1.4 - audit_rules_unsuccessful_file_modification_open_by_handle_at - low_complexity - low_disruption @@ -79807,6 +160996,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -79815,7 +161005,7 @@ fi line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -79859,6 +161049,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -79867,21 +161058,20 @@ fi line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-000635 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.1 - PCI-DSS-Req-10.2.4 - - PCI-DSSv4-10.2.1.1 - - PCI-DSSv4-10.2.1.4 - audit_rules_unsuccessful_file_modification_open_by_handle_at - low_complexity - low_disruption @@ -79959,6 +161149,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -79967,7 +161158,7 @@ fi line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -80011,6 +161202,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -80019,22 +161211,21 @@ fi line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - audit_arch == "b64" tags: + - DISA-STIG-OL09-00-000635 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.1 - PCI-DSS-Req-10.2.4 - - PCI-DSSv4-10.2.1.1 - - PCI-DSSv4-10.2.1.4 - audit_rules_unsuccessful_file_modification_open_by_handle_at - low_complexity - low_disruption @@ -80111,6 +161302,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -80119,7 +161311,7 @@ fi line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -80163,6 +161355,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -80171,21 +161364,20 @@ fi line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-000635 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.1 - PCI-DSS-Req-10.2.4 - - PCI-DSSv4-10.2.1.1 - - PCI-DSSv4-10.2.1.4 - audit_rules_unsuccessful_file_modification_open_by_handle_at - low_complexity - low_disruption @@ -80262,6 +161454,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -80270,7 +161463,7 @@ fi line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -80314,6 +161507,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -80322,39 +161516,38 @@ fi line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - audit_arch == "b64" tags: + - DISA-STIG-OL09-00-000635 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.1 - PCI-DSS-Req-10.2.4 - - PCI-DSSv4-10.2.1.1 - - PCI-DSSv4-10.2.1.4 - audit_rules_unsuccessful_file_modification_open_by_handle_at - low_complexity - low_disruption - medium_severity - reboot_required - restrict_strategy - - - - - - - - - - Record Unsuccessful Access Attempts to Files - openat - At a minimum, the audit system should collect unauthorized file + + + + + + + + + + Record Unsuccessful Access Attempts to Files - openat + At a minimum, the audit system should collect unauthorized file accesses for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following lines to a file with suffix @@ -80376,148 +161569,150 @@ utility to read audit rules during daemon startup, add the following lines to If the system is 64 bit then also add the following lines: -a always,exit -F arch=b64 -S openat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access --a always,exit -F arch=b64 -S openat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access - Note that these rules can be configured in a +-a always,exit -F arch=b64 -S openat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access + + Note that these rules can be configured in a number of ways while still achieving the desired effect. Here the system calls have been placed independent of other system calls. Grouping these system -calls with others as identifying earlier in this guide is more efficient. - BP28(R73) - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 19 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - APO12.06 - APO13.01 - BAI03.05 - BAI08.02 - DSS01.03 - DSS01.04 - DSS02.02 - DSS02.04 - DSS02.07 - DSS03.01 - DSS03.05 - DSS05.02 - DSS05.03 - DSS05.04 - DSS05.05 - DSS05.07 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.1.7 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-000172 - CCI-002884 - 164.308(a)(1)(ii)(D) - 164.308(a)(3)(ii)(A) - 164.308(a)(5)(ii)(C) - 164.312(a)(2)(i) - 164.312(b) - 164.312(d) - 164.312(e) - 4.2.3.10 - 4.3.2.6.7 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.3.6.6 - 4.3.4.4.7 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 1.13 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.6 - SR 2.8 - SR 2.9 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 6.1 - SR 6.2 - SR 7.1 - SR 7.6 - A.11.2.6 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.14.2.7 - A.15.2.1 - A.15.2.2 - A.16.1.4 - A.16.1.5 - A.16.1.7 - A.6.2.1 - A.6.2.2 - AU-2(d) - AU-12(c) - CM-6(a) - DE.AE-3 - DE.AE-5 - DE.CM-1 - DE.CM-3 - DE.CM-7 - ID.SC-4 - PR.AC-3 - PR.PT-1 - PR.PT-4 - RS.AN-1 - RS.AN-4 - FAU_GEN.1.1.c - Req-10.2.4 - Req-10.2.1 - 10.2.1.1 - 10.2.1.4 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-OS-000064-GPOS-00033 - SRG-OS-000458-GPOS-00203 - SRG-OS-000461-GPOS-00205 - Unsuccessful attempts to access files could be an indicator of malicious activity on a system. Auditing -these events could serve as evidence of potential system compromise. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +calls with others as identifying earlier in this guide is more efficient. + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 19 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + APO10.01 + APO10.03 + APO10.04 + APO10.05 + APO11.04 + APO12.06 + APO13.01 + BAI03.05 + BAI08.02 + DSS01.03 + DSS01.04 + DSS02.02 + DSS02.04 + DSS02.07 + DSS03.01 + DSS03.05 + DSS05.02 + DSS05.03 + DSS05.04 + DSS05.05 + DSS05.07 + MEA01.01 + MEA01.02 + MEA01.03 + MEA01.04 + MEA01.05 + MEA02.01 + 3.1.7 + CCI-000172 + CCI-000130 + CCI-000135 + CCI-000169 + CCI-002884 + 164.308(a)(1)(ii)(D) + 164.308(a)(3)(ii)(A) + 164.308(a)(5)(ii)(C) + 164.312(a)(2)(i) + 164.312(b) + 164.312(d) + 164.312(e) + 4.2.3.10 + 4.3.2.6.7 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.3.6.6 + 4.3.4.4.7 + 4.3.4.5.6 + 4.3.4.5.7 + 4.3.4.5.8 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 1.13 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.6 + SR 2.8 + SR 2.9 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 6.1 + SR 6.2 + SR 7.1 + SR 7.6 + A.11.2.6 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.13.1.1 + A.13.2.1 + A.14.1.3 + A.14.2.7 + A.15.2.1 + A.15.2.2 + A.16.1.4 + A.16.1.5 + A.16.1.7 + A.6.2.1 + A.6.2.2 + AU-2(d) + AU-12(c) + CM-6(a) + DE.AE-3 + DE.AE-5 + DE.CM-1 + DE.CM-3 + DE.CM-7 + ID.SC-4 + PR.AC-3 + PR.PT-1 + PR.PT-4 + RS.AN-1 + RS.AN-4 + Req-10.2.4 + Req-10.2.1 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-OS-000064-GPOS-00033 + SRG-OS-000458-GPOS-00203 + SRG-OS-000461-GPOS-00205 + SRG-APP-000495-CTR-001235 + R73 + A.3.SEC-OL9 + OL09-00-000635 + SV-271554r1092528_rule + Unsuccessful attempts to access files could be an indicator of malicious activity on a system. Auditing +these events could serve as evidence of potential system compromise. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then # First perform the remediation of the syscall rule # Retrieve hardware architecture of the underlying system @@ -80562,7 +161757,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -80578,7 +161772,7 @@ then if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -80670,7 +161864,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -80723,7 +161917,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -80817,7 +162010,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -80876,7 +162069,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -80892,7 +162084,7 @@ then if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -80984,7 +162176,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -81037,7 +162229,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -81131,7 +162322,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -81159,19 +162350,18 @@ done else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-000635 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.1 - PCI-DSS-Req-10.2.4 - - PCI-DSSv4-10.2.1.1 - - PCI-DSSv4-10.2.1.4 - audit_rules_unsuccessful_file_modification_openat - low_complexity - low_disruption @@ -81184,18 +162374,17 @@ fi audit_arch: b64 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - ansible_architecture == "aarch64" or ansible_architecture == "ppc64" or ansible_architecture == "ppc64le" or ansible_architecture == "s390x" or ansible_architecture == "x86_64" tags: + - DISA-STIG-OL09-00-000635 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.1 - PCI-DSS-Req-10.2.4 - - PCI-DSSv4-10.2.1.1 - - PCI-DSSv4-10.2.1.4 - audit_rules_unsuccessful_file_modification_openat - low_complexity - low_disruption @@ -81272,6 +162461,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -81280,7 +162470,7 @@ fi line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -81324,6 +162514,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -81332,21 +162523,20 @@ fi line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-000635 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.1 - PCI-DSS-Req-10.2.4 - - PCI-DSSv4-10.2.1.1 - - PCI-DSSv4-10.2.1.4 - audit_rules_unsuccessful_file_modification_openat - low_complexity - low_disruption @@ -81423,6 +162613,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -81431,7 +162622,7 @@ fi line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -81475,6 +162666,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -81483,22 +162675,21 @@ fi line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - audit_arch == "b64" tags: + - DISA-STIG-OL09-00-000635 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.1 - PCI-DSS-Req-10.2.4 - - PCI-DSSv4-10.2.1.1 - - PCI-DSSv4-10.2.1.4 - audit_rules_unsuccessful_file_modification_openat - low_complexity - low_disruption @@ -81575,6 +162766,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -81583,7 +162775,7 @@ fi line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -81627,6 +162819,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -81635,21 +162828,20 @@ fi line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-000635 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.1 - PCI-DSS-Req-10.2.4 - - PCI-DSSv4-10.2.1.1 - - PCI-DSSv4-10.2.1.4 - audit_rules_unsuccessful_file_modification_openat - low_complexity - low_disruption @@ -81726,6 +162918,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -81734,7 +162927,7 @@ fi line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -81778,6 +162971,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -81786,2905 +162980,38 @@ fi line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - audit_arch == "b64" tags: + - DISA-STIG-OL09-00-000635 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.1 - PCI-DSS-Req-10.2.4 - - PCI-DSSv4-10.2.1.1 - - PCI-DSSv4-10.2.1.4 - audit_rules_unsuccessful_file_modification_openat - low_complexity - low_disruption - medium_severity - reboot_required - restrict_strategy - - - - - - - - - - Record Unsuccessful Delete Attempts to Files - rename - The audit system should collect unsuccessful file deletion -attempts for all users and root. If the auditd daemon is configured -to use the augenrules program to read audit rules during daemon -startup (the default), add the following lines to a file with suffix -.rules in the directory /etc/audit/rules.d. -If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add the following lines to -/etc/audit/audit.rules file. --a always,exit -F arch=b32 -S rename -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-delete --a always,exit -F arch=b32 -S rename -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-delete -If the system is 64 bit then also add the following lines: - --a always,exit -F arch=b64 -S rename -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-delete --a always,exit -F arch=b64 -S rename -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-delete - Note that these rules can be configured in a -number of ways while still achieving the desired effect. Here the system calls -have been placed independent of other system calls. Grouping system calls related -to the same event is more efficient. See the following example: --a always,exit -F arch=b32 -S unlink,unlinkat,rename,renameat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccesful-delete - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 19 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - APO12.06 - APO13.01 - BAI03.05 - BAI08.02 - DSS01.03 - DSS01.04 - DSS02.02 - DSS02.04 - DSS02.07 - DSS03.01 - DSS03.05 - DSS05.02 - DSS05.03 - DSS05.04 - DSS05.05 - DSS05.07 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.1.7 - CCI-000172 - CCI-002884 - 164.308(a)(1)(ii)(D) - 164.308(a)(3)(ii)(A) - 164.308(a)(5)(ii)(C) - 164.312(a)(2)(i) - 164.312(b) - 164.312(d) - 164.312(e) - 4.2.3.10 - 4.3.2.6.7 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.3.6.6 - 4.3.4.4.7 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 1.13 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.6 - SR 2.8 - SR 2.9 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 6.1 - SR 6.2 - SR 7.1 - SR 7.6 - A.11.2.6 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.14.2.7 - A.15.2.1 - A.15.2.2 - A.16.1.4 - A.16.1.5 - A.16.1.7 - A.6.2.1 - A.6.2.2 - AU-2(d) - AU-12(c) - CM-6(a) - DE.AE-3 - DE.AE-5 - DE.CM-1 - DE.CM-3 - DE.CM-7 - ID.SC-4 - PR.AC-3 - PR.PT-1 - PR.PT-4 - RS.AN-1 - RS.AN-4 - FAU_GEN.1.1.c - Req-10.2.4 - Req-10.2.1 - 10.2.1.1 - 10.2.1.4 - SRG-OS-000064-GPOS-00033 - SRG-OS-000392-GPOS-00172 - SRG-OS-000458-GPOS-00203 - SRG-OS-000461-GPOS-00205 - SRG-OS-000468-GPOS-00212 - Unsuccessful attempts to delete files could be an indicator of malicious activity on a system. Auditing -these events could serve as evidence of potential system compromise. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then - -# First perform the remediation of the syscall rule -# Retrieve hardware architecture of the underlying system -[ "$(getconf LONG_BIT)" = "32" ] && RULE_ARCHS=("b32") || RULE_ARCHS=("b32" "b64") - -AUID_FILTERS="-F auid>=1000 -F auid!=unset" -SYSCALL="rename" -KEY="access" -SYSCALL_GROUPING="rename renameat unlink unlinkat" - -for ARCH in "${RULE_ARCHS[@]}" -do - ACTION_ARCH_FILTERS="-a always,exit -F arch=$ARCH" - OTHER_FILTERS="-F exit=-EACCES" - # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' - unset syscall_a -unset syscall_grouping -unset syscall_string -unset syscall -unset file_to_edit -unset rule_to_edit -unset rule_syscalls_to_edit -unset other_string -unset auid_string -unset full_rule - -# Load macro arguments into arrays -read -a syscall_a <<< $SYSCALL -read -a syscall_grouping <<< $SYSCALL_GROUPING - -# Create a list of audit *.rules files that should be inspected for presence and correctness -# of a particular audit rule. The scheme is as follows: -# -# ----------------------------------------------------------------------------------------- -# Tool used to load audit rules | Rule already defined | Audit rules file to inspect | -# ----------------------------------------------------------------------------------------- -# auditctl | Doesn't matter | /etc/audit/audit.rules | -# ----------------------------------------------------------------------------------------- -# augenrules | Yes | /etc/audit/rules.d/*.rules | -# augenrules | No | /etc/audit/rules.d/$key.rules | -# ----------------------------------------------------------------------------------------- -# -files_to_inspect=() - - -# If audit tool is 'augenrules', then check if the audit rule is defined -# If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection -# If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection -default_file="/etc/audit/rules.d/$KEY.rules" -# As other_filters may include paths, lets use a different delimiter for it -# The "F" script expression tells sed to print the filenames where the expressions matched -readarray -t files_to_inspect < <(sed -s -n -e "/^$ACTION_ARCH_FILTERS/!d" -e "\#$OTHER_FILTERS#!d" -e "/$AUID_FILTERS/!d" -e "F" /etc/audit/rules.d/*.rules) -# Case when particular rule isn't defined in /etc/audit/rules.d/*.rules yet -if [ ${#files_to_inspect[@]} -eq "0" ] -then - file_to_inspect="/etc/audit/rules.d/$KEY.rules" - files_to_inspect=("$file_to_inspect") - if [ ! -e "$file_to_inspect" ] - then - touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" - fi -fi - -# After converting to jinja, we cannot return; therefore we skip the rest of the macro if needed instead -skip=1 - -for audit_file in "${files_to_inspect[@]}" -do - # Filter existing $audit_file rules' definitions to select those that satisfy the rule pattern, - # i.e, collect rules that match: - # * the action, list and arch, (2-nd argument) - # * the other filters, (3-rd argument) - # * the auid filters, (4-rd argument) - readarray -t similar_rules < <(sed -e "/^$ACTION_ARCH_FILTERS/!d" -e "\#$OTHER_FILTERS#!d" -e "/$AUID_FILTERS/!d" "$audit_file") - - candidate_rules=() - # Filter out rules that have more fields then required. This will remove rules more specific than the required scope - for s_rule in "${similar_rules[@]}" - do - # Strip all the options and fields we know of, - # than check if there was any field left over - extra_fields=$(sed -E -e "s/^$ACTION_ARCH_FILTERS//" -e "s#$OTHER_FILTERS##" -e "s/$AUID_FILTERS//" -e "s/((:?-S [[:alnum:],]+)+)//g" -e "s/-F key=\w+|-k \w+//"<<< "$s_rule") - grep -q -- "-F" <<< "$extra_fields" || candidate_rules+=("$s_rule") - done - - if [[ ${#syscall_a[@]} -ge 1 ]] - then - # Check if the syscall we want is present in any of the similar existing rules - for rule in "${candidate_rules[@]}" - do - rule_syscalls=$(echo "$rule" | grep -o -P '(-S [\w,]+)+' | xargs) - all_syscalls_found=0 - for syscall in "${syscall_a[@]}" - do - grep -q -- "\b${syscall}\b" <<< "$rule_syscalls" || { - # A syscall was not found in the candidate rule - all_syscalls_found=1 - } - done - if [[ $all_syscalls_found -eq 0 ]] - then - # We found a rule with all the syscall(s) we want; skip rest of macro - skip=0 - break - fi - - # Check if this rule can be grouped with our target syscall and keep track of it - for syscall_g in "${syscall_grouping[@]}" - do - if grep -q -- "\b${syscall_g}\b" <<< "$rule_syscalls" - then - file_to_edit=${audit_file} - rule_to_edit=${rule} - rule_syscalls_to_edit=${rule_syscalls} - fi - done - done - else - # If there is any candidate rule, it is compliant; skip rest of macro - if [ "${#candidate_rules[@]}" -gt 0 ] - then - skip=0 - fi - fi - - if [ "$skip" -eq 0 ]; then - break - fi -done - -if [ "$skip" -ne 0 ]; then - # We checked all rules that matched the expected resemblance pattern (action, arch & auid) - # At this point we know if we need to either append the $full_rule or group - # the syscall together with an exsiting rule - - # Append the full_rule if it cannot be grouped to any other rule - if [ -z ${rule_to_edit+x} ] - then - # Build full_rule while avoid adding double spaces when other_filters is empty - if [ "${#syscall_a[@]}" -gt 0 ] - then - syscall_string="" - for syscall in "${syscall_a[@]}" - do - syscall_string+=" -S $syscall" - done - fi - other_string=$([[ $OTHER_FILTERS ]] && echo " $OTHER_FILTERS") || /bin/true - auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true - full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true - echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} - else - # Check if the syscalls are declared as a comma separated list or - # as multiple -S parameters - if grep -q -- "," <<< "${rule_syscalls_to_edit}" - then - delimiter="," - else - delimiter=" -S " - fi - new_grouped_syscalls="${rule_syscalls_to_edit}" - for syscall in "${syscall_a[@]}" - do - grep -q -- "\b${syscall}\b" <<< "${rule_syscalls_to_edit}" || { - # A syscall was not found in the candidate rule - new_grouped_syscalls+="${delimiter}${syscall}" - } - done - - # Group the syscall in the rule - sed -i -e "\#${rule_to_edit}#s#${rule_syscalls_to_edit}#${new_grouped_syscalls}#" "$file_to_edit" - fi -fi - unset syscall_a -unset syscall_grouping -unset syscall_string -unset syscall -unset file_to_edit -unset rule_to_edit -unset rule_syscalls_to_edit -unset other_string -unset auid_string -unset full_rule - -# Load macro arguments into arrays -read -a syscall_a <<< $SYSCALL -read -a syscall_grouping <<< $SYSCALL_GROUPING - -# Create a list of audit *.rules files that should be inspected for presence and correctness -# of a particular audit rule. The scheme is as follows: -# -# ----------------------------------------------------------------------------------------- -# Tool used to load audit rules | Rule already defined | Audit rules file to inspect | -# ----------------------------------------------------------------------------------------- -# auditctl | Doesn't matter | /etc/audit/audit.rules | -# ----------------------------------------------------------------------------------------- -# augenrules | Yes | /etc/audit/rules.d/*.rules | -# augenrules | No | /etc/audit/rules.d/$key.rules | -# ----------------------------------------------------------------------------------------- -# -files_to_inspect=() - - - -# If audit tool is 'auditctl', then add '/etc/audit/audit.rules' -# file to the list of files to be inspected -default_file="/etc/audit/audit.rules" -files_to_inspect+=('/etc/audit/audit.rules' ) - -# After converting to jinja, we cannot return; therefore we skip the rest of the macro if needed instead -skip=1 - -for audit_file in "${files_to_inspect[@]}" -do - # Filter existing $audit_file rules' definitions to select those that satisfy the rule pattern, - # i.e, collect rules that match: - # * the action, list and arch, (2-nd argument) - # * the other filters, (3-rd argument) - # * the auid filters, (4-rd argument) - readarray -t similar_rules < <(sed -e "/^$ACTION_ARCH_FILTERS/!d" -e "\#$OTHER_FILTERS#!d" -e "/$AUID_FILTERS/!d" "$audit_file") - - candidate_rules=() - # Filter out rules that have more fields then required. This will remove rules more specific than the required scope - for s_rule in "${similar_rules[@]}" - do - # Strip all the options and fields we know of, - # than check if there was any field left over - extra_fields=$(sed -E -e "s/^$ACTION_ARCH_FILTERS//" -e "s#$OTHER_FILTERS##" -e "s/$AUID_FILTERS//" -e "s/((:?-S [[:alnum:],]+)+)//g" -e "s/-F key=\w+|-k \w+//"<<< "$s_rule") - grep -q -- "-F" <<< "$extra_fields" || candidate_rules+=("$s_rule") - done - - if [[ ${#syscall_a[@]} -ge 1 ]] - then - # Check if the syscall we want is present in any of the similar existing rules - for rule in "${candidate_rules[@]}" - do - rule_syscalls=$(echo "$rule" | grep -o -P '(-S [\w,]+)+' | xargs) - all_syscalls_found=0 - for syscall in "${syscall_a[@]}" - do - grep -q -- "\b${syscall}\b" <<< "$rule_syscalls" || { - # A syscall was not found in the candidate rule - all_syscalls_found=1 - } - done - if [[ $all_syscalls_found -eq 0 ]] - then - # We found a rule with all the syscall(s) we want; skip rest of macro - skip=0 - break - fi - - # Check if this rule can be grouped with our target syscall and keep track of it - for syscall_g in "${syscall_grouping[@]}" - do - if grep -q -- "\b${syscall_g}\b" <<< "$rule_syscalls" - then - file_to_edit=${audit_file} - rule_to_edit=${rule} - rule_syscalls_to_edit=${rule_syscalls} - fi - done - done - else - # If there is any candidate rule, it is compliant; skip rest of macro - if [ "${#candidate_rules[@]}" -gt 0 ] - then - skip=0 - fi - fi - - if [ "$skip" -eq 0 ]; then - break - fi -done - -if [ "$skip" -ne 0 ]; then - # We checked all rules that matched the expected resemblance pattern (action, arch & auid) - # At this point we know if we need to either append the $full_rule or group - # the syscall together with an exsiting rule - - # Append the full_rule if it cannot be grouped to any other rule - if [ -z ${rule_to_edit+x} ] - then - # Build full_rule while avoid adding double spaces when other_filters is empty - if [ "${#syscall_a[@]}" -gt 0 ] - then - syscall_string="" - for syscall in "${syscall_a[@]}" - do - syscall_string+=" -S $syscall" - done - fi - other_string=$([[ $OTHER_FILTERS ]] && echo " $OTHER_FILTERS") || /bin/true - auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true - full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true - echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} - else - # Check if the syscalls are declared as a comma separated list or - # as multiple -S parameters - if grep -q -- "," <<< "${rule_syscalls_to_edit}" - then - delimiter="," - else - delimiter=" -S " - fi - new_grouped_syscalls="${rule_syscalls_to_edit}" - for syscall in "${syscall_a[@]}" - do - grep -q -- "\b${syscall}\b" <<< "${rule_syscalls_to_edit}" || { - # A syscall was not found in the candidate rule - new_grouped_syscalls+="${delimiter}${syscall}" - } - done - - # Group the syscall in the rule - sed -i -e "\#${rule_to_edit}#s#${rule_syscalls_to_edit}#${new_grouped_syscalls}#" "$file_to_edit" - fi -fi -done - -for ARCH in "${RULE_ARCHS[@]}" -do - ACTION_ARCH_FILTERS="-a always,exit -F arch=$ARCH" - OTHER_FILTERS="-F exit=-EPERM" - # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' - unset syscall_a -unset syscall_grouping -unset syscall_string -unset syscall -unset file_to_edit -unset rule_to_edit -unset rule_syscalls_to_edit -unset other_string -unset auid_string -unset full_rule - -# Load macro arguments into arrays -read -a syscall_a <<< $SYSCALL -read -a syscall_grouping <<< $SYSCALL_GROUPING - -# Create a list of audit *.rules files that should be inspected for presence and correctness -# of a particular audit rule. The scheme is as follows: -# -# ----------------------------------------------------------------------------------------- -# Tool used to load audit rules | Rule already defined | Audit rules file to inspect | -# ----------------------------------------------------------------------------------------- -# auditctl | Doesn't matter | /etc/audit/audit.rules | -# ----------------------------------------------------------------------------------------- -# augenrules | Yes | /etc/audit/rules.d/*.rules | -# augenrules | No | /etc/audit/rules.d/$key.rules | -# ----------------------------------------------------------------------------------------- -# -files_to_inspect=() - - -# If audit tool is 'augenrules', then check if the audit rule is defined -# If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection -# If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection -default_file="/etc/audit/rules.d/$KEY.rules" -# As other_filters may include paths, lets use a different delimiter for it -# The "F" script expression tells sed to print the filenames where the expressions matched -readarray -t files_to_inspect < <(sed -s -n -e "/^$ACTION_ARCH_FILTERS/!d" -e "\#$OTHER_FILTERS#!d" -e "/$AUID_FILTERS/!d" -e "F" /etc/audit/rules.d/*.rules) -# Case when particular rule isn't defined in /etc/audit/rules.d/*.rules yet -if [ ${#files_to_inspect[@]} -eq "0" ] -then - file_to_inspect="/etc/audit/rules.d/$KEY.rules" - files_to_inspect=("$file_to_inspect") - if [ ! -e "$file_to_inspect" ] - then - touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" - fi -fi - -# After converting to jinja, we cannot return; therefore we skip the rest of the macro if needed instead -skip=1 - -for audit_file in "${files_to_inspect[@]}" -do - # Filter existing $audit_file rules' definitions to select those that satisfy the rule pattern, - # i.e, collect rules that match: - # * the action, list and arch, (2-nd argument) - # * the other filters, (3-rd argument) - # * the auid filters, (4-rd argument) - readarray -t similar_rules < <(sed -e "/^$ACTION_ARCH_FILTERS/!d" -e "\#$OTHER_FILTERS#!d" -e "/$AUID_FILTERS/!d" "$audit_file") - - candidate_rules=() - # Filter out rules that have more fields then required. This will remove rules more specific than the required scope - for s_rule in "${similar_rules[@]}" - do - # Strip all the options and fields we know of, - # than check if there was any field left over - extra_fields=$(sed -E -e "s/^$ACTION_ARCH_FILTERS//" -e "s#$OTHER_FILTERS##" -e "s/$AUID_FILTERS//" -e "s/((:?-S [[:alnum:],]+)+)//g" -e "s/-F key=\w+|-k \w+//"<<< "$s_rule") - grep -q -- "-F" <<< "$extra_fields" || candidate_rules+=("$s_rule") - done - - if [[ ${#syscall_a[@]} -ge 1 ]] - then - # Check if the syscall we want is present in any of the similar existing rules - for rule in "${candidate_rules[@]}" - do - rule_syscalls=$(echo "$rule" | grep -o -P '(-S [\w,]+)+' | xargs) - all_syscalls_found=0 - for syscall in "${syscall_a[@]}" - do - grep -q -- "\b${syscall}\b" <<< "$rule_syscalls" || { - # A syscall was not found in the candidate rule - all_syscalls_found=1 - } - done - if [[ $all_syscalls_found -eq 0 ]] - then - # We found a rule with all the syscall(s) we want; skip rest of macro - skip=0 - break - fi - - # Check if this rule can be grouped with our target syscall and keep track of it - for syscall_g in "${syscall_grouping[@]}" - do - if grep -q -- "\b${syscall_g}\b" <<< "$rule_syscalls" - then - file_to_edit=${audit_file} - rule_to_edit=${rule} - rule_syscalls_to_edit=${rule_syscalls} - fi - done - done - else - # If there is any candidate rule, it is compliant; skip rest of macro - if [ "${#candidate_rules[@]}" -gt 0 ] - then - skip=0 - fi - fi - - if [ "$skip" -eq 0 ]; then - break - fi -done - -if [ "$skip" -ne 0 ]; then - # We checked all rules that matched the expected resemblance pattern (action, arch & auid) - # At this point we know if we need to either append the $full_rule or group - # the syscall together with an exsiting rule - - # Append the full_rule if it cannot be grouped to any other rule - if [ -z ${rule_to_edit+x} ] - then - # Build full_rule while avoid adding double spaces when other_filters is empty - if [ "${#syscall_a[@]}" -gt 0 ] - then - syscall_string="" - for syscall in "${syscall_a[@]}" - do - syscall_string+=" -S $syscall" - done - fi - other_string=$([[ $OTHER_FILTERS ]] && echo " $OTHER_FILTERS") || /bin/true - auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true - full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true - echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} - else - # Check if the syscalls are declared as a comma separated list or - # as multiple -S parameters - if grep -q -- "," <<< "${rule_syscalls_to_edit}" - then - delimiter="," - else - delimiter=" -S " - fi - new_grouped_syscalls="${rule_syscalls_to_edit}" - for syscall in "${syscall_a[@]}" - do - grep -q -- "\b${syscall}\b" <<< "${rule_syscalls_to_edit}" || { - # A syscall was not found in the candidate rule - new_grouped_syscalls+="${delimiter}${syscall}" - } - done - - # Group the syscall in the rule - sed -i -e "\#${rule_to_edit}#s#${rule_syscalls_to_edit}#${new_grouped_syscalls}#" "$file_to_edit" - fi -fi - unset syscall_a -unset syscall_grouping -unset syscall_string -unset syscall -unset file_to_edit -unset rule_to_edit -unset rule_syscalls_to_edit -unset other_string -unset auid_string -unset full_rule - -# Load macro arguments into arrays -read -a syscall_a <<< $SYSCALL -read -a syscall_grouping <<< $SYSCALL_GROUPING - -# Create a list of audit *.rules files that should be inspected for presence and correctness -# of a particular audit rule. The scheme is as follows: -# -# ----------------------------------------------------------------------------------------- -# Tool used to load audit rules | Rule already defined | Audit rules file to inspect | -# ----------------------------------------------------------------------------------------- -# auditctl | Doesn't matter | /etc/audit/audit.rules | -# ----------------------------------------------------------------------------------------- -# augenrules | Yes | /etc/audit/rules.d/*.rules | -# augenrules | No | /etc/audit/rules.d/$key.rules | -# ----------------------------------------------------------------------------------------- -# -files_to_inspect=() - - - -# If audit tool is 'auditctl', then add '/etc/audit/audit.rules' -# file to the list of files to be inspected -default_file="/etc/audit/audit.rules" -files_to_inspect+=('/etc/audit/audit.rules' ) - -# After converting to jinja, we cannot return; therefore we skip the rest of the macro if needed instead -skip=1 - -for audit_file in "${files_to_inspect[@]}" -do - # Filter existing $audit_file rules' definitions to select those that satisfy the rule pattern, - # i.e, collect rules that match: - # * the action, list and arch, (2-nd argument) - # * the other filters, (3-rd argument) - # * the auid filters, (4-rd argument) - readarray -t similar_rules < <(sed -e "/^$ACTION_ARCH_FILTERS/!d" -e "\#$OTHER_FILTERS#!d" -e "/$AUID_FILTERS/!d" "$audit_file") - - candidate_rules=() - # Filter out rules that have more fields then required. This will remove rules more specific than the required scope - for s_rule in "${similar_rules[@]}" - do - # Strip all the options and fields we know of, - # than check if there was any field left over - extra_fields=$(sed -E -e "s/^$ACTION_ARCH_FILTERS//" -e "s#$OTHER_FILTERS##" -e "s/$AUID_FILTERS//" -e "s/((:?-S [[:alnum:],]+)+)//g" -e "s/-F key=\w+|-k \w+//"<<< "$s_rule") - grep -q -- "-F" <<< "$extra_fields" || candidate_rules+=("$s_rule") - done - - if [[ ${#syscall_a[@]} -ge 1 ]] - then - # Check if the syscall we want is present in any of the similar existing rules - for rule in "${candidate_rules[@]}" - do - rule_syscalls=$(echo "$rule" | grep -o -P '(-S [\w,]+)+' | xargs) - all_syscalls_found=0 - for syscall in "${syscall_a[@]}" - do - grep -q -- "\b${syscall}\b" <<< "$rule_syscalls" || { - # A syscall was not found in the candidate rule - all_syscalls_found=1 - } - done - if [[ $all_syscalls_found -eq 0 ]] - then - # We found a rule with all the syscall(s) we want; skip rest of macro - skip=0 - break - fi - - # Check if this rule can be grouped with our target syscall and keep track of it - for syscall_g in "${syscall_grouping[@]}" - do - if grep -q -- "\b${syscall_g}\b" <<< "$rule_syscalls" - then - file_to_edit=${audit_file} - rule_to_edit=${rule} - rule_syscalls_to_edit=${rule_syscalls} - fi - done - done - else - # If there is any candidate rule, it is compliant; skip rest of macro - if [ "${#candidate_rules[@]}" -gt 0 ] - then - skip=0 - fi - fi - - if [ "$skip" -eq 0 ]; then - break - fi -done - -if [ "$skip" -ne 0 ]; then - # We checked all rules that matched the expected resemblance pattern (action, arch & auid) - # At this point we know if we need to either append the $full_rule or group - # the syscall together with an exsiting rule - - # Append the full_rule if it cannot be grouped to any other rule - if [ -z ${rule_to_edit+x} ] - then - # Build full_rule while avoid adding double spaces when other_filters is empty - if [ "${#syscall_a[@]}" -gt 0 ] - then - syscall_string="" - for syscall in "${syscall_a[@]}" - do - syscall_string+=" -S $syscall" - done - fi - other_string=$([[ $OTHER_FILTERS ]] && echo " $OTHER_FILTERS") || /bin/true - auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true - full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true - echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} - else - # Check if the syscalls are declared as a comma separated list or - # as multiple -S parameters - if grep -q -- "," <<< "${rule_syscalls_to_edit}" - then - delimiter="," - else - delimiter=" -S " - fi - new_grouped_syscalls="${rule_syscalls_to_edit}" - for syscall in "${syscall_a[@]}" - do - grep -q -- "\b${syscall}\b" <<< "${rule_syscalls_to_edit}" || { - # A syscall was not found in the candidate rule - new_grouped_syscalls+="${delimiter}${syscall}" - } - done - - # Group the syscall in the rule - sed -i -e "\#${rule_to_edit}#s#${rule_syscalls_to_edit}#${new_grouped_syscalls}#" "$file_to_edit" - fi -fi -done - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Gather the package facts - package_facts: - manager: auto - tags: - - NIST-800-171-3.1.7 - - NIST-800-53-AU-12(c) - - NIST-800-53-AU-2(d) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.2.1 - - PCI-DSS-Req-10.2.4 - - PCI-DSSv4-10.2.1.1 - - PCI-DSSv4-10.2.1.4 - - audit_rules_unsuccessful_file_modification_rename - - low_complexity - - low_disruption - - medium_severity - - reboot_required - - restrict_strategy - -- name: Set architecture for audit rename tasks - set_fact: - audit_arch: b64 - when: - - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - ansible_architecture == "aarch64" or ansible_architecture == "ppc64" or ansible_architecture - == "ppc64le" or ansible_architecture == "s390x" or ansible_architecture == "x86_64" - tags: - - NIST-800-171-3.1.7 - - NIST-800-53-AU-12(c) - - NIST-800-53-AU-2(d) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.2.1 - - PCI-DSS-Req-10.2.4 - - PCI-DSSv4-10.2.1.1 - - PCI-DSSv4-10.2.1.4 - - audit_rules_unsuccessful_file_modification_rename - - low_complexity - - low_disruption - - medium_severity - - reboot_required - - restrict_strategy - -- name: Perform remediation of Audit rules for rename EACCES for 32bit platform - block: - - - name: Declare list of syscalls - set_fact: - syscalls: - - rename - syscall_grouping: - - rename - - renameat - - unlink - - unlinkat - - - name: Check existence of rename in /etc/audit/rules.d/ - find: - paths: /etc/audit/rules.d - contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S - |,)\w+)* -F exit=-EACCES -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ - patterns: '*.rules' - register: find_command - loop: '{{ (syscall_grouping + syscalls) | unique }}' - - - name: Reset syscalls found per file - set_fact: - syscalls_per_file: {} - found_paths_dict: {} - - - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path - :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" - loop: '{{ find_command.results | selectattr(''matched'') | list }}' - - - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" - - - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, - 0) }) }}" - loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') - | list }}' - - - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') - | last).key }}" - when: found_paths | length >= 1 - - - name: No file with syscall found, set path to /etc/audit/rules.d/access.rules - set_fact: audit_file="/etc/audit/rules.d/access.rules" - when: found_paths | length == 0 - - - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" - - - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" - - - name: Replace the audit rule in {{ audit_file }} - lineinfile: - path: '{{ audit_file }}' - regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] - | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EACCES -F auid>=1000 -F auid!=unset - (?:-k |-F key=)\w+) - line: \1\2\3{{ missing_syscalls | join("\3") }}\4 - backrefs: true - state: present - when: syscalls_found | length > 0 and missing_syscalls | length > 0 - - - name: Add the audit rule to {{ audit_file }} - lineinfile: - path: '{{ audit_file }}' - line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EACCES - -F auid>=1000 -F auid!=unset -F key=access - create: true - mode: o-rwx - state: present - when: syscalls_found | length == 0 - - - name: Declare list of syscalls - set_fact: - syscalls: - - rename - syscall_grouping: - - rename - - renameat - - unlink - - unlinkat - - - name: Check existence of rename in /etc/audit/audit.rules - find: - paths: /etc/audit - contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S - |,)\w+)* -F exit=-EACCES -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ - patterns: audit.rules - register: find_command - loop: '{{ (syscall_grouping + syscalls) | unique }}' - - - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" - - - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" - - - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" - - - name: Replace the audit rule in {{ audit_file }} - lineinfile: - path: '{{ audit_file }}' - regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | - join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EACCES -F auid>=1000 -F auid!=unset - (?:-k |-F key=)\w+) - line: \1\2\3{{ missing_syscalls | join("\3") }}\4 - backrefs: true - state: present - when: syscalls_found | length > 0 and missing_syscalls | length > 0 - - - name: Add the audit rule to {{ audit_file }} - lineinfile: - path: '{{ audit_file }}' - line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EACCES - -F auid>=1000 -F auid!=unset -F key=access - create: true - mode: o-rwx - state: present - when: syscalls_found | length == 0 - when: - - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.7 - - NIST-800-53-AU-12(c) - - NIST-800-53-AU-2(d) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.2.1 - - PCI-DSS-Req-10.2.4 - - PCI-DSSv4-10.2.1.1 - - PCI-DSSv4-10.2.1.4 - - audit_rules_unsuccessful_file_modification_rename - - low_complexity - - low_disruption - - medium_severity - - reboot_required - - restrict_strategy - -- name: Perform remediation of Audit rules for rename EACCES for 64bit platform - block: - - - name: Declare list of syscalls - set_fact: - syscalls: - - rename - syscall_grouping: - - rename - - renameat - - unlink - - unlinkat - - - name: Check existence of rename in /etc/audit/rules.d/ - find: - paths: /etc/audit/rules.d - contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S - |,)\w+)* -F exit=-EACCES -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ - patterns: '*.rules' - register: find_command - loop: '{{ (syscall_grouping + syscalls) | unique }}' - - - name: Reset syscalls found per file - set_fact: - syscalls_per_file: {} - found_paths_dict: {} - - - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path - :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" - loop: '{{ find_command.results | selectattr(''matched'') | list }}' - - - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" - - - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, - 0) }) }}" - loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') - | list }}' - - - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') - | last).key }}" - when: found_paths | length >= 1 - - - name: No file with syscall found, set path to /etc/audit/rules.d/access.rules - set_fact: audit_file="/etc/audit/rules.d/access.rules" - when: found_paths | length == 0 - - - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" - - - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" - - - name: Replace the audit rule in {{ audit_file }} - lineinfile: - path: '{{ audit_file }}' - regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] - | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EACCES -F auid>=1000 -F auid!=unset - (?:-k |-F key=)\w+) - line: \1\2\3{{ missing_syscalls | join("\3") }}\4 - backrefs: true - state: present - when: syscalls_found | length > 0 and missing_syscalls | length > 0 - - - name: Add the audit rule to {{ audit_file }} - lineinfile: - path: '{{ audit_file }}' - line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EACCES - -F auid>=1000 -F auid!=unset -F key=access - create: true - mode: o-rwx - state: present - when: syscalls_found | length == 0 - - - name: Declare list of syscalls - set_fact: - syscalls: - - rename - syscall_grouping: - - rename - - renameat - - unlink - - unlinkat - - - name: Check existence of rename in /etc/audit/audit.rules - find: - paths: /etc/audit - contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S - |,)\w+)* -F exit=-EACCES -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ - patterns: audit.rules - register: find_command - loop: '{{ (syscall_grouping + syscalls) | unique }}' - - - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" - - - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" - - - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" - - - name: Replace the audit rule in {{ audit_file }} - lineinfile: - path: '{{ audit_file }}' - regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | - join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EACCES -F auid>=1000 -F auid!=unset - (?:-k |-F key=)\w+) - line: \1\2\3{{ missing_syscalls | join("\3") }}\4 - backrefs: true - state: present - when: syscalls_found | length > 0 and missing_syscalls | length > 0 - - - name: Add the audit rule to {{ audit_file }} - lineinfile: - path: '{{ audit_file }}' - line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EACCES - -F auid>=1000 -F auid!=unset -F key=access - create: true - mode: o-rwx - state: present - when: syscalls_found | length == 0 - when: - - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - audit_arch == "b64" - tags: - - NIST-800-171-3.1.7 - - NIST-800-53-AU-12(c) - - NIST-800-53-AU-2(d) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.2.1 - - PCI-DSS-Req-10.2.4 - - PCI-DSSv4-10.2.1.1 - - PCI-DSSv4-10.2.1.4 - - audit_rules_unsuccessful_file_modification_rename - - low_complexity - - low_disruption - - medium_severity - - reboot_required - - restrict_strategy - -- name: Perform remediation of Audit rules for rename EPERM for 32bit platform - block: - - - name: Declare list of syscalls - set_fact: - syscalls: - - rename - syscall_grouping: - - rename - - renameat - - unlink - - unlinkat - - - name: Check existence of rename in /etc/audit/rules.d/ - find: - paths: /etc/audit/rules.d - contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S - |,)\w+)* -F exit=-EPERM -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ - patterns: '*.rules' - register: find_command - loop: '{{ (syscall_grouping + syscalls) | unique }}' - - - name: Reset syscalls found per file - set_fact: - syscalls_per_file: {} - found_paths_dict: {} - - - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path - :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" - loop: '{{ find_command.results | selectattr(''matched'') | list }}' - - - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" - - - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, - 0) }) }}" - loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') - | list }}' - - - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') - | last).key }}" - when: found_paths | length >= 1 - - - name: No file with syscall found, set path to /etc/audit/rules.d/access.rules - set_fact: audit_file="/etc/audit/rules.d/access.rules" - when: found_paths | length == 0 - - - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" - - - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" - - - name: Replace the audit rule in {{ audit_file }} - lineinfile: - path: '{{ audit_file }}' - regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] - | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EPERM -F auid>=1000 -F auid!=unset - (?:-k |-F key=)\w+) - line: \1\2\3{{ missing_syscalls | join("\3") }}\4 - backrefs: true - state: present - when: syscalls_found | length > 0 and missing_syscalls | length > 0 - - - name: Add the audit rule to {{ audit_file }} - lineinfile: - path: '{{ audit_file }}' - line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EPERM - -F auid>=1000 -F auid!=unset -F key=access - create: true - mode: o-rwx - state: present - when: syscalls_found | length == 0 - - - name: Declare list of syscalls - set_fact: - syscalls: - - rename - syscall_grouping: - - rename - - renameat - - unlink - - unlinkat - - - name: Check existence of rename in /etc/audit/audit.rules - find: - paths: /etc/audit - contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S - |,)\w+)* -F exit=-EPERM -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ - patterns: audit.rules - register: find_command - loop: '{{ (syscall_grouping + syscalls) | unique }}' - - - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" - - - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" - - - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" - - - name: Replace the audit rule in {{ audit_file }} - lineinfile: - path: '{{ audit_file }}' - regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | - join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EPERM -F auid>=1000 -F auid!=unset - (?:-k |-F key=)\w+) - line: \1\2\3{{ missing_syscalls | join("\3") }}\4 - backrefs: true - state: present - when: syscalls_found | length > 0 and missing_syscalls | length > 0 - - - name: Add the audit rule to {{ audit_file }} - lineinfile: - path: '{{ audit_file }}' - line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EPERM - -F auid>=1000 -F auid!=unset -F key=access - create: true - mode: o-rwx - state: present - when: syscalls_found | length == 0 - when: - - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.7 - - NIST-800-53-AU-12(c) - - NIST-800-53-AU-2(d) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.2.1 - - PCI-DSS-Req-10.2.4 - - PCI-DSSv4-10.2.1.1 - - PCI-DSSv4-10.2.1.4 - - audit_rules_unsuccessful_file_modification_rename - - low_complexity - - low_disruption - - medium_severity - - reboot_required - - restrict_strategy - -- name: Perform remediation of Audit rules for rename EPERM for 64bit platform - block: - - - name: Declare list of syscalls - set_fact: - syscalls: - - rename - syscall_grouping: - - rename - - renameat - - unlink - - unlinkat - - - name: Check existence of rename in /etc/audit/rules.d/ - find: - paths: /etc/audit/rules.d - contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S - |,)\w+)* -F exit=-EPERM -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ - patterns: '*.rules' - register: find_command - loop: '{{ (syscall_grouping + syscalls) | unique }}' - - - name: Reset syscalls found per file - set_fact: - syscalls_per_file: {} - found_paths_dict: {} - - - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path - :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" - loop: '{{ find_command.results | selectattr(''matched'') | list }}' - - - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" - - - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, - 0) }) }}" - loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') - | list }}' - - - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') - | last).key }}" - when: found_paths | length >= 1 - - - name: No file with syscall found, set path to /etc/audit/rules.d/access.rules - set_fact: audit_file="/etc/audit/rules.d/access.rules" - when: found_paths | length == 0 - - - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" - - - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" - - - name: Replace the audit rule in {{ audit_file }} - lineinfile: - path: '{{ audit_file }}' - regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] - | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EPERM -F auid>=1000 -F auid!=unset - (?:-k |-F key=)\w+) - line: \1\2\3{{ missing_syscalls | join("\3") }}\4 - backrefs: true - state: present - when: syscalls_found | length > 0 and missing_syscalls | length > 0 - - - name: Add the audit rule to {{ audit_file }} - lineinfile: - path: '{{ audit_file }}' - line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EPERM - -F auid>=1000 -F auid!=unset -F key=access - create: true - mode: o-rwx - state: present - when: syscalls_found | length == 0 - - - name: Declare list of syscalls - set_fact: - syscalls: - - rename - syscall_grouping: - - rename - - renameat - - unlink - - unlinkat - - - name: Check existence of rename in /etc/audit/audit.rules - find: - paths: /etc/audit - contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S - |,)\w+)* -F exit=-EPERM -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ - patterns: audit.rules - register: find_command - loop: '{{ (syscall_grouping + syscalls) | unique }}' - - - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" - - - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" - - - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" - - - name: Replace the audit rule in {{ audit_file }} - lineinfile: - path: '{{ audit_file }}' - regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | - join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EPERM -F auid>=1000 -F auid!=unset - (?:-k |-F key=)\w+) - line: \1\2\3{{ missing_syscalls | join("\3") }}\4 - backrefs: true - state: present - when: syscalls_found | length > 0 and missing_syscalls | length > 0 - - - name: Add the audit rule to {{ audit_file }} - lineinfile: - path: '{{ audit_file }}' - line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EPERM - -F auid>=1000 -F auid!=unset -F key=access - create: true - mode: o-rwx - state: present - when: syscalls_found | length == 0 - when: - - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - audit_arch == "b64" - tags: - - NIST-800-171-3.1.7 - - NIST-800-53-AU-12(c) - - NIST-800-53-AU-2(d) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.2.1 - - PCI-DSS-Req-10.2.4 - - PCI-DSSv4-10.2.1.1 - - PCI-DSSv4-10.2.1.4 - - audit_rules_unsuccessful_file_modification_rename - - low_complexity - - low_disruption - - medium_severity - - reboot_required - - restrict_strategy - - - - - - - - - - Record Unsuccessful Delete Attempts to Files - renameat - -The audit system should collect unsuccessful file deletion -attempts for all users and root. If the auditd daemon is configured -to use the augenrules program to read audit rules during daemon -startup (the default), add the following lines to a file with suffix -.rules in the directory /etc/audit/rules.d. -If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add the following lines to -/etc/audit/audit.rules file. --a always,exit -F arch=b32 -S renameat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-delete --a always,exit -F arch=b32 -S renameat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-delete -If the system is 64 bit then also add the following lines: - --a always,exit -F arch=b64 -S renameat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-delete --a always,exit -F arch=b64 -S renameat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-delete - Note that these rules can be configured in a -number of ways while still achieving the desired effect. Here the system calls -have been placed independent of other system calls. Grouping system calls related -to the same event is more efficient. See the following example: - --a always,exit -F arch=b32 -S unlink,unlinkat,rename,renameat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccesful-delete - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 19 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - APO12.06 - APO13.01 - BAI03.05 - BAI08.02 - DSS01.03 - DSS01.04 - DSS02.02 - DSS02.04 - DSS02.07 - DSS03.01 - DSS03.05 - DSS05.02 - DSS05.03 - DSS05.04 - DSS05.05 - DSS05.07 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.1.7 - CCI-000172 - CCI-002884 - 164.308(a)(1)(ii)(D) - 164.308(a)(3)(ii)(A) - 164.308(a)(5)(ii)(C) - 164.312(a)(2)(i) - 164.312(b) - 164.312(d) - 164.312(e) - 4.2.3.10 - 4.3.2.6.7 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.3.6.6 - 4.3.4.4.7 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 1.13 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.6 - SR 2.8 - SR 2.9 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 6.1 - SR 6.2 - SR 7.1 - SR 7.6 - A.11.2.6 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.14.2.7 - A.15.2.1 - A.15.2.2 - A.16.1.4 - A.16.1.5 - A.16.1.7 - A.6.2.1 - A.6.2.2 - AU-2(d) - AU-12(c) - CM-6(a) - DE.AE-3 - DE.AE-5 - DE.CM-1 - DE.CM-3 - DE.CM-7 - ID.SC-4 - PR.AC-3 - PR.PT-1 - PR.PT-4 - RS.AN-1 - RS.AN-4 - FAU_GEN.1.1.c - Req-10.2.4 - Req-10.2.1 - 10.2.1.1 - 10.2.1.4 - SRG-OS-000064-GPOS-00033 - SRG-OS-000392-GPOS-00172 - SRG-OS-000458-GPOS-00203 - SRG-OS-000461-GPOS-00205 - SRG-OS-000468-GPOS-00212 - Unsuccessful attempts to delete files could be an indicator of malicious activity on a system. Auditing -these events could serve as evidence of potential system compromise. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then - -# First perform the remediation of the syscall rule -# Retrieve hardware architecture of the underlying system -[ "$(getconf LONG_BIT)" = "32" ] && RULE_ARCHS=("b32") || RULE_ARCHS=("b32" "b64") - -AUID_FILTERS="-F auid>=1000 -F auid!=unset" -SYSCALL="renameat" -KEY="access" -SYSCALL_GROUPING="rename renameat unlink unlinkat" - -for ARCH in "${RULE_ARCHS[@]}" -do - ACTION_ARCH_FILTERS="-a always,exit -F arch=$ARCH" - OTHER_FILTERS="-F exit=-EACCES" - # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' - unset syscall_a -unset syscall_grouping -unset syscall_string -unset syscall -unset file_to_edit -unset rule_to_edit -unset rule_syscalls_to_edit -unset other_string -unset auid_string -unset full_rule - -# Load macro arguments into arrays -read -a syscall_a <<< $SYSCALL -read -a syscall_grouping <<< $SYSCALL_GROUPING - -# Create a list of audit *.rules files that should be inspected for presence and correctness -# of a particular audit rule. The scheme is as follows: -# -# ----------------------------------------------------------------------------------------- -# Tool used to load audit rules | Rule already defined | Audit rules file to inspect | -# ----------------------------------------------------------------------------------------- -# auditctl | Doesn't matter | /etc/audit/audit.rules | -# ----------------------------------------------------------------------------------------- -# augenrules | Yes | /etc/audit/rules.d/*.rules | -# augenrules | No | /etc/audit/rules.d/$key.rules | -# ----------------------------------------------------------------------------------------- -# -files_to_inspect=() - - -# If audit tool is 'augenrules', then check if the audit rule is defined -# If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection -# If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection -default_file="/etc/audit/rules.d/$KEY.rules" -# As other_filters may include paths, lets use a different delimiter for it -# The "F" script expression tells sed to print the filenames where the expressions matched -readarray -t files_to_inspect < <(sed -s -n -e "/^$ACTION_ARCH_FILTERS/!d" -e "\#$OTHER_FILTERS#!d" -e "/$AUID_FILTERS/!d" -e "F" /etc/audit/rules.d/*.rules) -# Case when particular rule isn't defined in /etc/audit/rules.d/*.rules yet -if [ ${#files_to_inspect[@]} -eq "0" ] -then - file_to_inspect="/etc/audit/rules.d/$KEY.rules" - files_to_inspect=("$file_to_inspect") - if [ ! -e "$file_to_inspect" ] - then - touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" - fi -fi - -# After converting to jinja, we cannot return; therefore we skip the rest of the macro if needed instead -skip=1 - -for audit_file in "${files_to_inspect[@]}" -do - # Filter existing $audit_file rules' definitions to select those that satisfy the rule pattern, - # i.e, collect rules that match: - # * the action, list and arch, (2-nd argument) - # * the other filters, (3-rd argument) - # * the auid filters, (4-rd argument) - readarray -t similar_rules < <(sed -e "/^$ACTION_ARCH_FILTERS/!d" -e "\#$OTHER_FILTERS#!d" -e "/$AUID_FILTERS/!d" "$audit_file") - - candidate_rules=() - # Filter out rules that have more fields then required. This will remove rules more specific than the required scope - for s_rule in "${similar_rules[@]}" - do - # Strip all the options and fields we know of, - # than check if there was any field left over - extra_fields=$(sed -E -e "s/^$ACTION_ARCH_FILTERS//" -e "s#$OTHER_FILTERS##" -e "s/$AUID_FILTERS//" -e "s/((:?-S [[:alnum:],]+)+)//g" -e "s/-F key=\w+|-k \w+//"<<< "$s_rule") - grep -q -- "-F" <<< "$extra_fields" || candidate_rules+=("$s_rule") - done - - if [[ ${#syscall_a[@]} -ge 1 ]] - then - # Check if the syscall we want is present in any of the similar existing rules - for rule in "${candidate_rules[@]}" - do - rule_syscalls=$(echo "$rule" | grep -o -P '(-S [\w,]+)+' | xargs) - all_syscalls_found=0 - for syscall in "${syscall_a[@]}" - do - grep -q -- "\b${syscall}\b" <<< "$rule_syscalls" || { - # A syscall was not found in the candidate rule - all_syscalls_found=1 - } - done - if [[ $all_syscalls_found -eq 0 ]] - then - # We found a rule with all the syscall(s) we want; skip rest of macro - skip=0 - break - fi - - # Check if this rule can be grouped with our target syscall and keep track of it - for syscall_g in "${syscall_grouping[@]}" - do - if grep -q -- "\b${syscall_g}\b" <<< "$rule_syscalls" - then - file_to_edit=${audit_file} - rule_to_edit=${rule} - rule_syscalls_to_edit=${rule_syscalls} - fi - done - done - else - # If there is any candidate rule, it is compliant; skip rest of macro - if [ "${#candidate_rules[@]}" -gt 0 ] - then - skip=0 - fi - fi - - if [ "$skip" -eq 0 ]; then - break - fi -done - -if [ "$skip" -ne 0 ]; then - # We checked all rules that matched the expected resemblance pattern (action, arch & auid) - # At this point we know if we need to either append the $full_rule or group - # the syscall together with an exsiting rule - - # Append the full_rule if it cannot be grouped to any other rule - if [ -z ${rule_to_edit+x} ] - then - # Build full_rule while avoid adding double spaces when other_filters is empty - if [ "${#syscall_a[@]}" -gt 0 ] - then - syscall_string="" - for syscall in "${syscall_a[@]}" - do - syscall_string+=" -S $syscall" - done - fi - other_string=$([[ $OTHER_FILTERS ]] && echo " $OTHER_FILTERS") || /bin/true - auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true - full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true - echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} - else - # Check if the syscalls are declared as a comma separated list or - # as multiple -S parameters - if grep -q -- "," <<< "${rule_syscalls_to_edit}" - then - delimiter="," - else - delimiter=" -S " - fi - new_grouped_syscalls="${rule_syscalls_to_edit}" - for syscall in "${syscall_a[@]}" - do - grep -q -- "\b${syscall}\b" <<< "${rule_syscalls_to_edit}" || { - # A syscall was not found in the candidate rule - new_grouped_syscalls+="${delimiter}${syscall}" - } - done - - # Group the syscall in the rule - sed -i -e "\#${rule_to_edit}#s#${rule_syscalls_to_edit}#${new_grouped_syscalls}#" "$file_to_edit" - fi -fi - unset syscall_a -unset syscall_grouping -unset syscall_string -unset syscall -unset file_to_edit -unset rule_to_edit -unset rule_syscalls_to_edit -unset other_string -unset auid_string -unset full_rule - -# Load macro arguments into arrays -read -a syscall_a <<< $SYSCALL -read -a syscall_grouping <<< $SYSCALL_GROUPING - -# Create a list of audit *.rules files that should be inspected for presence and correctness -# of a particular audit rule. The scheme is as follows: -# -# ----------------------------------------------------------------------------------------- -# Tool used to load audit rules | Rule already defined | Audit rules file to inspect | -# ----------------------------------------------------------------------------------------- -# auditctl | Doesn't matter | /etc/audit/audit.rules | -# ----------------------------------------------------------------------------------------- -# augenrules | Yes | /etc/audit/rules.d/*.rules | -# augenrules | No | /etc/audit/rules.d/$key.rules | -# ----------------------------------------------------------------------------------------- -# -files_to_inspect=() - - - -# If audit tool is 'auditctl', then add '/etc/audit/audit.rules' -# file to the list of files to be inspected -default_file="/etc/audit/audit.rules" -files_to_inspect+=('/etc/audit/audit.rules' ) - -# After converting to jinja, we cannot return; therefore we skip the rest of the macro if needed instead -skip=1 - -for audit_file in "${files_to_inspect[@]}" -do - # Filter existing $audit_file rules' definitions to select those that satisfy the rule pattern, - # i.e, collect rules that match: - # * the action, list and arch, (2-nd argument) - # * the other filters, (3-rd argument) - # * the auid filters, (4-rd argument) - readarray -t similar_rules < <(sed -e "/^$ACTION_ARCH_FILTERS/!d" -e "\#$OTHER_FILTERS#!d" -e "/$AUID_FILTERS/!d" "$audit_file") - - candidate_rules=() - # Filter out rules that have more fields then required. This will remove rules more specific than the required scope - for s_rule in "${similar_rules[@]}" - do - # Strip all the options and fields we know of, - # than check if there was any field left over - extra_fields=$(sed -E -e "s/^$ACTION_ARCH_FILTERS//" -e "s#$OTHER_FILTERS##" -e "s/$AUID_FILTERS//" -e "s/((:?-S [[:alnum:],]+)+)//g" -e "s/-F key=\w+|-k \w+//"<<< "$s_rule") - grep -q -- "-F" <<< "$extra_fields" || candidate_rules+=("$s_rule") - done - - if [[ ${#syscall_a[@]} -ge 1 ]] - then - # Check if the syscall we want is present in any of the similar existing rules - for rule in "${candidate_rules[@]}" - do - rule_syscalls=$(echo "$rule" | grep -o -P '(-S [\w,]+)+' | xargs) - all_syscalls_found=0 - for syscall in "${syscall_a[@]}" - do - grep -q -- "\b${syscall}\b" <<< "$rule_syscalls" || { - # A syscall was not found in the candidate rule - all_syscalls_found=1 - } - done - if [[ $all_syscalls_found -eq 0 ]] - then - # We found a rule with all the syscall(s) we want; skip rest of macro - skip=0 - break - fi - - # Check if this rule can be grouped with our target syscall and keep track of it - for syscall_g in "${syscall_grouping[@]}" - do - if grep -q -- "\b${syscall_g}\b" <<< "$rule_syscalls" - then - file_to_edit=${audit_file} - rule_to_edit=${rule} - rule_syscalls_to_edit=${rule_syscalls} - fi - done - done - else - # If there is any candidate rule, it is compliant; skip rest of macro - if [ "${#candidate_rules[@]}" -gt 0 ] - then - skip=0 - fi - fi - - if [ "$skip" -eq 0 ]; then - break - fi -done - -if [ "$skip" -ne 0 ]; then - # We checked all rules that matched the expected resemblance pattern (action, arch & auid) - # At this point we know if we need to either append the $full_rule or group - # the syscall together with an exsiting rule - - # Append the full_rule if it cannot be grouped to any other rule - if [ -z ${rule_to_edit+x} ] - then - # Build full_rule while avoid adding double spaces when other_filters is empty - if [ "${#syscall_a[@]}" -gt 0 ] - then - syscall_string="" - for syscall in "${syscall_a[@]}" - do - syscall_string+=" -S $syscall" - done - fi - other_string=$([[ $OTHER_FILTERS ]] && echo " $OTHER_FILTERS") || /bin/true - auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true - full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true - echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} - else - # Check if the syscalls are declared as a comma separated list or - # as multiple -S parameters - if grep -q -- "," <<< "${rule_syscalls_to_edit}" - then - delimiter="," - else - delimiter=" -S " - fi - new_grouped_syscalls="${rule_syscalls_to_edit}" - for syscall in "${syscall_a[@]}" - do - grep -q -- "\b${syscall}\b" <<< "${rule_syscalls_to_edit}" || { - # A syscall was not found in the candidate rule - new_grouped_syscalls+="${delimiter}${syscall}" - } - done - - # Group the syscall in the rule - sed -i -e "\#${rule_to_edit}#s#${rule_syscalls_to_edit}#${new_grouped_syscalls}#" "$file_to_edit" - fi -fi -done - -for ARCH in "${RULE_ARCHS[@]}" -do - ACTION_ARCH_FILTERS="-a always,exit -F arch=$ARCH" - OTHER_FILTERS="-F exit=-EPERM" - # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' - unset syscall_a -unset syscall_grouping -unset syscall_string -unset syscall -unset file_to_edit -unset rule_to_edit -unset rule_syscalls_to_edit -unset other_string -unset auid_string -unset full_rule - -# Load macro arguments into arrays -read -a syscall_a <<< $SYSCALL -read -a syscall_grouping <<< $SYSCALL_GROUPING - -# Create a list of audit *.rules files that should be inspected for presence and correctness -# of a particular audit rule. The scheme is as follows: -# -# ----------------------------------------------------------------------------------------- -# Tool used to load audit rules | Rule already defined | Audit rules file to inspect | -# ----------------------------------------------------------------------------------------- -# auditctl | Doesn't matter | /etc/audit/audit.rules | -# ----------------------------------------------------------------------------------------- -# augenrules | Yes | /etc/audit/rules.d/*.rules | -# augenrules | No | /etc/audit/rules.d/$key.rules | -# ----------------------------------------------------------------------------------------- -# -files_to_inspect=() - - -# If audit tool is 'augenrules', then check if the audit rule is defined -# If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection -# If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection -default_file="/etc/audit/rules.d/$KEY.rules" -# As other_filters may include paths, lets use a different delimiter for it -# The "F" script expression tells sed to print the filenames where the expressions matched -readarray -t files_to_inspect < <(sed -s -n -e "/^$ACTION_ARCH_FILTERS/!d" -e "\#$OTHER_FILTERS#!d" -e "/$AUID_FILTERS/!d" -e "F" /etc/audit/rules.d/*.rules) -# Case when particular rule isn't defined in /etc/audit/rules.d/*.rules yet -if [ ${#files_to_inspect[@]} -eq "0" ] -then - file_to_inspect="/etc/audit/rules.d/$KEY.rules" - files_to_inspect=("$file_to_inspect") - if [ ! -e "$file_to_inspect" ] - then - touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" - fi -fi - -# After converting to jinja, we cannot return; therefore we skip the rest of the macro if needed instead -skip=1 - -for audit_file in "${files_to_inspect[@]}" -do - # Filter existing $audit_file rules' definitions to select those that satisfy the rule pattern, - # i.e, collect rules that match: - # * the action, list and arch, (2-nd argument) - # * the other filters, (3-rd argument) - # * the auid filters, (4-rd argument) - readarray -t similar_rules < <(sed -e "/^$ACTION_ARCH_FILTERS/!d" -e "\#$OTHER_FILTERS#!d" -e "/$AUID_FILTERS/!d" "$audit_file") - - candidate_rules=() - # Filter out rules that have more fields then required. This will remove rules more specific than the required scope - for s_rule in "${similar_rules[@]}" - do - # Strip all the options and fields we know of, - # than check if there was any field left over - extra_fields=$(sed -E -e "s/^$ACTION_ARCH_FILTERS//" -e "s#$OTHER_FILTERS##" -e "s/$AUID_FILTERS//" -e "s/((:?-S [[:alnum:],]+)+)//g" -e "s/-F key=\w+|-k \w+//"<<< "$s_rule") - grep -q -- "-F" <<< "$extra_fields" || candidate_rules+=("$s_rule") - done - - if [[ ${#syscall_a[@]} -ge 1 ]] - then - # Check if the syscall we want is present in any of the similar existing rules - for rule in "${candidate_rules[@]}" - do - rule_syscalls=$(echo "$rule" | grep -o -P '(-S [\w,]+)+' | xargs) - all_syscalls_found=0 - for syscall in "${syscall_a[@]}" - do - grep -q -- "\b${syscall}\b" <<< "$rule_syscalls" || { - # A syscall was not found in the candidate rule - all_syscalls_found=1 - } - done - if [[ $all_syscalls_found -eq 0 ]] - then - # We found a rule with all the syscall(s) we want; skip rest of macro - skip=0 - break - fi - - # Check if this rule can be grouped with our target syscall and keep track of it - for syscall_g in "${syscall_grouping[@]}" - do - if grep -q -- "\b${syscall_g}\b" <<< "$rule_syscalls" - then - file_to_edit=${audit_file} - rule_to_edit=${rule} - rule_syscalls_to_edit=${rule_syscalls} - fi - done - done - else - # If there is any candidate rule, it is compliant; skip rest of macro - if [ "${#candidate_rules[@]}" -gt 0 ] - then - skip=0 - fi - fi - - if [ "$skip" -eq 0 ]; then - break - fi -done - -if [ "$skip" -ne 0 ]; then - # We checked all rules that matched the expected resemblance pattern (action, arch & auid) - # At this point we know if we need to either append the $full_rule or group - # the syscall together with an exsiting rule - - # Append the full_rule if it cannot be grouped to any other rule - if [ -z ${rule_to_edit+x} ] - then - # Build full_rule while avoid adding double spaces when other_filters is empty - if [ "${#syscall_a[@]}" -gt 0 ] - then - syscall_string="" - for syscall in "${syscall_a[@]}" - do - syscall_string+=" -S $syscall" - done - fi - other_string=$([[ $OTHER_FILTERS ]] && echo " $OTHER_FILTERS") || /bin/true - auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true - full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true - echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} - else - # Check if the syscalls are declared as a comma separated list or - # as multiple -S parameters - if grep -q -- "," <<< "${rule_syscalls_to_edit}" - then - delimiter="," - else - delimiter=" -S " - fi - new_grouped_syscalls="${rule_syscalls_to_edit}" - for syscall in "${syscall_a[@]}" - do - grep -q -- "\b${syscall}\b" <<< "${rule_syscalls_to_edit}" || { - # A syscall was not found in the candidate rule - new_grouped_syscalls+="${delimiter}${syscall}" - } - done - - # Group the syscall in the rule - sed -i -e "\#${rule_to_edit}#s#${rule_syscalls_to_edit}#${new_grouped_syscalls}#" "$file_to_edit" - fi -fi - unset syscall_a -unset syscall_grouping -unset syscall_string -unset syscall -unset file_to_edit -unset rule_to_edit -unset rule_syscalls_to_edit -unset other_string -unset auid_string -unset full_rule - -# Load macro arguments into arrays -read -a syscall_a <<< $SYSCALL -read -a syscall_grouping <<< $SYSCALL_GROUPING - -# Create a list of audit *.rules files that should be inspected for presence and correctness -# of a particular audit rule. The scheme is as follows: -# -# ----------------------------------------------------------------------------------------- -# Tool used to load audit rules | Rule already defined | Audit rules file to inspect | -# ----------------------------------------------------------------------------------------- -# auditctl | Doesn't matter | /etc/audit/audit.rules | -# ----------------------------------------------------------------------------------------- -# augenrules | Yes | /etc/audit/rules.d/*.rules | -# augenrules | No | /etc/audit/rules.d/$key.rules | -# ----------------------------------------------------------------------------------------- -# -files_to_inspect=() - - - -# If audit tool is 'auditctl', then add '/etc/audit/audit.rules' -# file to the list of files to be inspected -default_file="/etc/audit/audit.rules" -files_to_inspect+=('/etc/audit/audit.rules' ) - -# After converting to jinja, we cannot return; therefore we skip the rest of the macro if needed instead -skip=1 - -for audit_file in "${files_to_inspect[@]}" -do - # Filter existing $audit_file rules' definitions to select those that satisfy the rule pattern, - # i.e, collect rules that match: - # * the action, list and arch, (2-nd argument) - # * the other filters, (3-rd argument) - # * the auid filters, (4-rd argument) - readarray -t similar_rules < <(sed -e "/^$ACTION_ARCH_FILTERS/!d" -e "\#$OTHER_FILTERS#!d" -e "/$AUID_FILTERS/!d" "$audit_file") - - candidate_rules=() - # Filter out rules that have more fields then required. This will remove rules more specific than the required scope - for s_rule in "${similar_rules[@]}" - do - # Strip all the options and fields we know of, - # than check if there was any field left over - extra_fields=$(sed -E -e "s/^$ACTION_ARCH_FILTERS//" -e "s#$OTHER_FILTERS##" -e "s/$AUID_FILTERS//" -e "s/((:?-S [[:alnum:],]+)+)//g" -e "s/-F key=\w+|-k \w+//"<<< "$s_rule") - grep -q -- "-F" <<< "$extra_fields" || candidate_rules+=("$s_rule") - done - - if [[ ${#syscall_a[@]} -ge 1 ]] - then - # Check if the syscall we want is present in any of the similar existing rules - for rule in "${candidate_rules[@]}" - do - rule_syscalls=$(echo "$rule" | grep -o -P '(-S [\w,]+)+' | xargs) - all_syscalls_found=0 - for syscall in "${syscall_a[@]}" - do - grep -q -- "\b${syscall}\b" <<< "$rule_syscalls" || { - # A syscall was not found in the candidate rule - all_syscalls_found=1 - } - done - if [[ $all_syscalls_found -eq 0 ]] - then - # We found a rule with all the syscall(s) we want; skip rest of macro - skip=0 - break - fi - - # Check if this rule can be grouped with our target syscall and keep track of it - for syscall_g in "${syscall_grouping[@]}" - do - if grep -q -- "\b${syscall_g}\b" <<< "$rule_syscalls" - then - file_to_edit=${audit_file} - rule_to_edit=${rule} - rule_syscalls_to_edit=${rule_syscalls} - fi - done - done - else - # If there is any candidate rule, it is compliant; skip rest of macro - if [ "${#candidate_rules[@]}" -gt 0 ] - then - skip=0 - fi - fi - - if [ "$skip" -eq 0 ]; then - break - fi -done - -if [ "$skip" -ne 0 ]; then - # We checked all rules that matched the expected resemblance pattern (action, arch & auid) - # At this point we know if we need to either append the $full_rule or group - # the syscall together with an exsiting rule - - # Append the full_rule if it cannot be grouped to any other rule - if [ -z ${rule_to_edit+x} ] - then - # Build full_rule while avoid adding double spaces when other_filters is empty - if [ "${#syscall_a[@]}" -gt 0 ] - then - syscall_string="" - for syscall in "${syscall_a[@]}" - do - syscall_string+=" -S $syscall" - done - fi - other_string=$([[ $OTHER_FILTERS ]] && echo " $OTHER_FILTERS") || /bin/true - auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true - full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true - echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} - else - # Check if the syscalls are declared as a comma separated list or - # as multiple -S parameters - if grep -q -- "," <<< "${rule_syscalls_to_edit}" - then - delimiter="," - else - delimiter=" -S " - fi - new_grouped_syscalls="${rule_syscalls_to_edit}" - for syscall in "${syscall_a[@]}" - do - grep -q -- "\b${syscall}\b" <<< "${rule_syscalls_to_edit}" || { - # A syscall was not found in the candidate rule - new_grouped_syscalls+="${delimiter}${syscall}" - } - done - - # Group the syscall in the rule - sed -i -e "\#${rule_to_edit}#s#${rule_syscalls_to_edit}#${new_grouped_syscalls}#" "$file_to_edit" - fi -fi -done - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Gather the package facts - package_facts: - manager: auto - tags: - - NIST-800-171-3.1.7 - - NIST-800-53-AU-12(c) - - NIST-800-53-AU-2(d) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.2.1 - - PCI-DSS-Req-10.2.4 - - PCI-DSSv4-10.2.1.1 - - PCI-DSSv4-10.2.1.4 - - audit_rules_unsuccessful_file_modification_renameat - - low_complexity - - low_disruption - - medium_severity - - reboot_required - - restrict_strategy - -- name: Set architecture for audit renameat tasks - set_fact: - audit_arch: b64 - when: - - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - ansible_architecture == "aarch64" or ansible_architecture == "ppc64" or ansible_architecture - == "ppc64le" or ansible_architecture == "s390x" or ansible_architecture == "x86_64" - tags: - - NIST-800-171-3.1.7 - - NIST-800-53-AU-12(c) - - NIST-800-53-AU-2(d) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.2.1 - - PCI-DSS-Req-10.2.4 - - PCI-DSSv4-10.2.1.1 - - PCI-DSSv4-10.2.1.4 - - audit_rules_unsuccessful_file_modification_renameat - - low_complexity - - low_disruption - - medium_severity - - reboot_required - - restrict_strategy - -- name: Perform remediation of Audit rules for renameat EACCES for 32bit platform - block: - - - name: Declare list of syscalls - set_fact: - syscalls: - - renameat - syscall_grouping: - - rename - - renameat - - unlink - - unlinkat - - - name: Check existence of renameat in /etc/audit/rules.d/ - find: - paths: /etc/audit/rules.d - contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S - |,)\w+)* -F exit=-EACCES -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ - patterns: '*.rules' - register: find_command - loop: '{{ (syscall_grouping + syscalls) | unique }}' - - - name: Reset syscalls found per file - set_fact: - syscalls_per_file: {} - found_paths_dict: {} - - - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path - :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" - loop: '{{ find_command.results | selectattr(''matched'') | list }}' - - - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" - - - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, - 0) }) }}" - loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') - | list }}' - - - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') - | last).key }}" - when: found_paths | length >= 1 - - - name: No file with syscall found, set path to /etc/audit/rules.d/access.rules - set_fact: audit_file="/etc/audit/rules.d/access.rules" - when: found_paths | length == 0 - - - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" - - - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" - - - name: Replace the audit rule in {{ audit_file }} - lineinfile: - path: '{{ audit_file }}' - regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] - | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EACCES -F auid>=1000 -F auid!=unset - (?:-k |-F key=)\w+) - line: \1\2\3{{ missing_syscalls | join("\3") }}\4 - backrefs: true - state: present - when: syscalls_found | length > 0 and missing_syscalls | length > 0 - - - name: Add the audit rule to {{ audit_file }} - lineinfile: - path: '{{ audit_file }}' - line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EACCES - -F auid>=1000 -F auid!=unset -F key=access - create: true - mode: o-rwx - state: present - when: syscalls_found | length == 0 - - - name: Declare list of syscalls - set_fact: - syscalls: - - renameat - syscall_grouping: - - rename - - renameat - - unlink - - unlinkat - - - name: Check existence of renameat in /etc/audit/audit.rules - find: - paths: /etc/audit - contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S - |,)\w+)* -F exit=-EACCES -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ - patterns: audit.rules - register: find_command - loop: '{{ (syscall_grouping + syscalls) | unique }}' - - - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" - - - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" - - - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" - - - name: Replace the audit rule in {{ audit_file }} - lineinfile: - path: '{{ audit_file }}' - regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | - join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EACCES -F auid>=1000 -F auid!=unset - (?:-k |-F key=)\w+) - line: \1\2\3{{ missing_syscalls | join("\3") }}\4 - backrefs: true - state: present - when: syscalls_found | length > 0 and missing_syscalls | length > 0 - - - name: Add the audit rule to {{ audit_file }} - lineinfile: - path: '{{ audit_file }}' - line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EACCES - -F auid>=1000 -F auid!=unset -F key=access - create: true - mode: o-rwx - state: present - when: syscalls_found | length == 0 - when: - - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.7 - - NIST-800-53-AU-12(c) - - NIST-800-53-AU-2(d) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.2.1 - - PCI-DSS-Req-10.2.4 - - PCI-DSSv4-10.2.1.1 - - PCI-DSSv4-10.2.1.4 - - audit_rules_unsuccessful_file_modification_renameat - - low_complexity - - low_disruption - - medium_severity - - reboot_required - - restrict_strategy - -- name: Perform remediation of Audit rules for renameat EACCES for 64bit platform - block: - - - name: Declare list of syscalls - set_fact: - syscalls: - - renameat - syscall_grouping: - - rename - - renameat - - unlink - - unlinkat - - - name: Check existence of renameat in /etc/audit/rules.d/ - find: - paths: /etc/audit/rules.d - contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S - |,)\w+)* -F exit=-EACCES -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ - patterns: '*.rules' - register: find_command - loop: '{{ (syscall_grouping + syscalls) | unique }}' - - - name: Reset syscalls found per file - set_fact: - syscalls_per_file: {} - found_paths_dict: {} - - - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path - :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" - loop: '{{ find_command.results | selectattr(''matched'') | list }}' - - - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" - - - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, - 0) }) }}" - loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') - | list }}' - - - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') - | last).key }}" - when: found_paths | length >= 1 - - - name: No file with syscall found, set path to /etc/audit/rules.d/access.rules - set_fact: audit_file="/etc/audit/rules.d/access.rules" - when: found_paths | length == 0 - - - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" - - - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" - - - name: Replace the audit rule in {{ audit_file }} - lineinfile: - path: '{{ audit_file }}' - regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] - | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EACCES -F auid>=1000 -F auid!=unset - (?:-k |-F key=)\w+) - line: \1\2\3{{ missing_syscalls | join("\3") }}\4 - backrefs: true - state: present - when: syscalls_found | length > 0 and missing_syscalls | length > 0 - - - name: Add the audit rule to {{ audit_file }} - lineinfile: - path: '{{ audit_file }}' - line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EACCES - -F auid>=1000 -F auid!=unset -F key=access - create: true - mode: o-rwx - state: present - when: syscalls_found | length == 0 - - - name: Declare list of syscalls - set_fact: - syscalls: - - renameat - syscall_grouping: - - rename - - renameat - - unlink - - unlinkat - - - name: Check existence of renameat in /etc/audit/audit.rules - find: - paths: /etc/audit - contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S - |,)\w+)* -F exit=-EACCES -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ - patterns: audit.rules - register: find_command - loop: '{{ (syscall_grouping + syscalls) | unique }}' - - - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" - - - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" - - - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" - - - name: Replace the audit rule in {{ audit_file }} - lineinfile: - path: '{{ audit_file }}' - regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | - join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EACCES -F auid>=1000 -F auid!=unset - (?:-k |-F key=)\w+) - line: \1\2\3{{ missing_syscalls | join("\3") }}\4 - backrefs: true - state: present - when: syscalls_found | length > 0 and missing_syscalls | length > 0 - - - name: Add the audit rule to {{ audit_file }} - lineinfile: - path: '{{ audit_file }}' - line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EACCES - -F auid>=1000 -F auid!=unset -F key=access - create: true - mode: o-rwx - state: present - when: syscalls_found | length == 0 - when: - - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - audit_arch == "b64" - tags: - - NIST-800-171-3.1.7 - - NIST-800-53-AU-12(c) - - NIST-800-53-AU-2(d) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.2.1 - - PCI-DSS-Req-10.2.4 - - PCI-DSSv4-10.2.1.1 - - PCI-DSSv4-10.2.1.4 - - audit_rules_unsuccessful_file_modification_renameat - - low_complexity - - low_disruption - - medium_severity - - reboot_required - - restrict_strategy - -- name: Perform remediation of Audit rules for renameat EPERM for 32bit platform - block: - - - name: Declare list of syscalls - set_fact: - syscalls: - - renameat - syscall_grouping: - - rename - - renameat - - unlink - - unlinkat - - - name: Check existence of renameat in /etc/audit/rules.d/ - find: - paths: /etc/audit/rules.d - contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S - |,)\w+)* -F exit=-EPERM -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ - patterns: '*.rules' - register: find_command - loop: '{{ (syscall_grouping + syscalls) | unique }}' - - - name: Reset syscalls found per file - set_fact: - syscalls_per_file: {} - found_paths_dict: {} - - - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path - :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" - loop: '{{ find_command.results | selectattr(''matched'') | list }}' - - - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" - - - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, - 0) }) }}" - loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') - | list }}' - - - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') - | last).key }}" - when: found_paths | length >= 1 - - - name: No file with syscall found, set path to /etc/audit/rules.d/access.rules - set_fact: audit_file="/etc/audit/rules.d/access.rules" - when: found_paths | length == 0 - - - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" - - - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" - - - name: Replace the audit rule in {{ audit_file }} - lineinfile: - path: '{{ audit_file }}' - regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] - | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EPERM -F auid>=1000 -F auid!=unset - (?:-k |-F key=)\w+) - line: \1\2\3{{ missing_syscalls | join("\3") }}\4 - backrefs: true - state: present - when: syscalls_found | length > 0 and missing_syscalls | length > 0 - - - name: Add the audit rule to {{ audit_file }} - lineinfile: - path: '{{ audit_file }}' - line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EPERM - -F auid>=1000 -F auid!=unset -F key=access - create: true - mode: o-rwx - state: present - when: syscalls_found | length == 0 - - - name: Declare list of syscalls - set_fact: - syscalls: - - renameat - syscall_grouping: - - rename - - renameat - - unlink - - unlinkat - - - name: Check existence of renameat in /etc/audit/audit.rules - find: - paths: /etc/audit - contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S - |,)\w+)* -F exit=-EPERM -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ - patterns: audit.rules - register: find_command - loop: '{{ (syscall_grouping + syscalls) | unique }}' - - - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" - - - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" - - - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" - - - name: Replace the audit rule in {{ audit_file }} - lineinfile: - path: '{{ audit_file }}' - regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | - join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EPERM -F auid>=1000 -F auid!=unset - (?:-k |-F key=)\w+) - line: \1\2\3{{ missing_syscalls | join("\3") }}\4 - backrefs: true - state: present - when: syscalls_found | length > 0 and missing_syscalls | length > 0 - - - name: Add the audit rule to {{ audit_file }} - lineinfile: - path: '{{ audit_file }}' - line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EPERM - -F auid>=1000 -F auid!=unset -F key=access - create: true - mode: o-rwx - state: present - when: syscalls_found | length == 0 - when: - - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.7 - - NIST-800-53-AU-12(c) - - NIST-800-53-AU-2(d) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.2.1 - - PCI-DSS-Req-10.2.4 - - PCI-DSSv4-10.2.1.1 - - PCI-DSSv4-10.2.1.4 - - audit_rules_unsuccessful_file_modification_renameat - - low_complexity - - low_disruption - - medium_severity - - reboot_required - - restrict_strategy - -- name: Perform remediation of Audit rules for renameat EPERM for 64bit platform - block: - - - name: Declare list of syscalls - set_fact: - syscalls: - - renameat - syscall_grouping: - - rename - - renameat - - unlink - - unlinkat - - - name: Check existence of renameat in /etc/audit/rules.d/ - find: - paths: /etc/audit/rules.d - contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S - |,)\w+)* -F exit=-EPERM -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ - patterns: '*.rules' - register: find_command - loop: '{{ (syscall_grouping + syscalls) | unique }}' - - - name: Reset syscalls found per file - set_fact: - syscalls_per_file: {} - found_paths_dict: {} - - - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path - :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" - loop: '{{ find_command.results | selectattr(''matched'') | list }}' - - - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" - - - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, - 0) }) }}" - loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') - | list }}' - - - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') - | last).key }}" - when: found_paths | length >= 1 - - - name: No file with syscall found, set path to /etc/audit/rules.d/access.rules - set_fact: audit_file="/etc/audit/rules.d/access.rules" - when: found_paths | length == 0 - - - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" - - - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" - - - name: Replace the audit rule in {{ audit_file }} - lineinfile: - path: '{{ audit_file }}' - regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] - | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EPERM -F auid>=1000 -F auid!=unset - (?:-k |-F key=)\w+) - line: \1\2\3{{ missing_syscalls | join("\3") }}\4 - backrefs: true - state: present - when: syscalls_found | length > 0 and missing_syscalls | length > 0 - - - name: Add the audit rule to {{ audit_file }} - lineinfile: - path: '{{ audit_file }}' - line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EPERM - -F auid>=1000 -F auid!=unset -F key=access - create: true - mode: o-rwx - state: present - when: syscalls_found | length == 0 - - - name: Declare list of syscalls - set_fact: - syscalls: - - renameat - syscall_grouping: - - rename - - renameat - - unlink - - unlinkat - - - name: Check existence of renameat in /etc/audit/audit.rules - find: - paths: /etc/audit - contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S - |,)\w+)* -F exit=-EPERM -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ - patterns: audit.rules - register: find_command - loop: '{{ (syscall_grouping + syscalls) | unique }}' - - - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" - - - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" - - - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" - - - name: Replace the audit rule in {{ audit_file }} - lineinfile: - path: '{{ audit_file }}' - regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | - join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EPERM -F auid>=1000 -F auid!=unset - (?:-k |-F key=)\w+) - line: \1\2\3{{ missing_syscalls | join("\3") }}\4 - backrefs: true - state: present - when: syscalls_found | length > 0 and missing_syscalls | length > 0 - - - name: Add the audit rule to {{ audit_file }} - lineinfile: - path: '{{ audit_file }}' - line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EPERM - -F auid>=1000 -F auid!=unset -F key=access - create: true - mode: o-rwx - state: present - when: syscalls_found | length == 0 - when: - - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - audit_arch == "b64" - tags: - - NIST-800-171-3.1.7 - - NIST-800-53-AU-12(c) - - NIST-800-53-AU-2(d) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.2.1 - - PCI-DSS-Req-10.2.4 - - PCI-DSSv4-10.2.1.1 - - PCI-DSSv4-10.2.1.4 - - audit_rules_unsuccessful_file_modification_renameat - - low_complexity - - low_disruption - - medium_severity - - reboot_required - - restrict_strategy - - - - - - - - - - Record Unsuccessful Access Attempts to Files - truncate - At a minimum, the audit system should collect unauthorized file + + + + + + + + + + Record Unsuccessful Access Attempts to Files - truncate + At a minimum, the audit system should collect unauthorized file accesses for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following lines to a file with suffix @@ -84706,148 +163033,150 @@ utility to read audit rules during daemon startup, add the following lines to If the system is 64 bit then also add the following lines: -a always,exit -F arch=b64 -S truncate -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access --a always,exit -F arch=b64 -S truncate -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access - Note that these rules can be configured in a +-a always,exit -F arch=b64 -S truncate -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access + + Note that these rules can be configured in a number of ways while still achieving the desired effect. Here the system calls have been placed independent of other system calls. Grouping these system -calls with others as identifying earlier in this guide is more efficient. - BP28(R73) - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 19 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - APO12.06 - APO13.01 - BAI03.05 - BAI08.02 - DSS01.03 - DSS01.04 - DSS02.02 - DSS02.04 - DSS02.07 - DSS03.01 - DSS03.05 - DSS05.02 - DSS05.03 - DSS05.04 - DSS05.05 - DSS05.07 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.1.7 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-000172 - CCI-002884 - 164.308(a)(1)(ii)(D) - 164.308(a)(3)(ii)(A) - 164.308(a)(5)(ii)(C) - 164.312(a)(2)(i) - 164.312(b) - 164.312(d) - 164.312(e) - 4.2.3.10 - 4.3.2.6.7 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.3.6.6 - 4.3.4.4.7 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 1.13 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.6 - SR 2.8 - SR 2.9 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 6.1 - SR 6.2 - SR 7.1 - SR 7.6 - A.11.2.6 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.14.2.7 - A.15.2.1 - A.15.2.2 - A.16.1.4 - A.16.1.5 - A.16.1.7 - A.6.2.1 - A.6.2.2 - AU-2(d) - AU-12(c) - CM-6(a) - DE.AE-3 - DE.AE-5 - DE.CM-1 - DE.CM-3 - DE.CM-7 - ID.SC-4 - PR.AC-3 - PR.PT-1 - PR.PT-4 - RS.AN-1 - RS.AN-4 - FAU_GEN.1.1.c - Req-10.2.4 - Req-10.2.1 - 10.2.1.1 - 10.2.1.4 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-OS-000064-GPOS-00033 - SRG-OS-000458-GPOS-00203 - SRG-OS-000461-GPOS-00205 - Unsuccessful attempts to access files could be an indicator of malicious activity on a system. Auditing -these events could serve as evidence of potential system compromise. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +calls with others as identifying earlier in this guide is more efficient. + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 19 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + APO10.01 + APO10.03 + APO10.04 + APO10.05 + APO11.04 + APO12.06 + APO13.01 + BAI03.05 + BAI08.02 + DSS01.03 + DSS01.04 + DSS02.02 + DSS02.04 + DSS02.07 + DSS03.01 + DSS03.05 + DSS05.02 + DSS05.03 + DSS05.04 + DSS05.05 + DSS05.07 + MEA01.01 + MEA01.02 + MEA01.03 + MEA01.04 + MEA01.05 + MEA02.01 + 3.1.7 + CCI-000172 + CCI-000130 + CCI-000135 + CCI-000169 + CCI-002884 + 164.308(a)(1)(ii)(D) + 164.308(a)(3)(ii)(A) + 164.308(a)(5)(ii)(C) + 164.312(a)(2)(i) + 164.312(b) + 164.312(d) + 164.312(e) + 4.2.3.10 + 4.3.2.6.7 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.3.6.6 + 4.3.4.4.7 + 4.3.4.5.6 + 4.3.4.5.7 + 4.3.4.5.8 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 1.13 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.6 + SR 2.8 + SR 2.9 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 6.1 + SR 6.2 + SR 7.1 + SR 7.6 + A.11.2.6 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.13.1.1 + A.13.2.1 + A.14.1.3 + A.14.2.7 + A.15.2.1 + A.15.2.2 + A.16.1.4 + A.16.1.5 + A.16.1.7 + A.6.2.1 + A.6.2.2 + AU-2(d) + AU-12(c) + CM-6(a) + DE.AE-3 + DE.AE-5 + DE.CM-1 + DE.CM-3 + DE.CM-7 + ID.SC-4 + PR.AC-3 + PR.PT-1 + PR.PT-4 + RS.AN-1 + RS.AN-4 + Req-10.2.4 + Req-10.2.1 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-OS-000064-GPOS-00033 + SRG-OS-000458-GPOS-00203 + SRG-OS-000461-GPOS-00205 + SRG-APP-000495-CTR-001235 + R73 + A.3.SEC-OL9 + OL09-00-000635 + SV-271554r1092528_rule + Unsuccessful attempts to access files could be an indicator of malicious activity on a system. Auditing +these events could serve as evidence of potential system compromise. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then # First perform the remediation of the syscall rule # Retrieve hardware architecture of the underlying system @@ -84892,7 +163221,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -84908,7 +163236,7 @@ then if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -85000,7 +163328,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -85053,7 +163381,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -85147,7 +163474,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -85206,7 +163533,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -85222,7 +163548,7 @@ then if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -85314,7 +163640,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -85367,7 +163693,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -85461,7 +163786,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -85489,19 +163814,18 @@ done else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-000635 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.1 - PCI-DSS-Req-10.2.4 - - PCI-DSSv4-10.2.1.1 - - PCI-DSSv4-10.2.1.4 - audit_rules_unsuccessful_file_modification_truncate - low_complexity - low_disruption @@ -85514,18 +163838,17 @@ fi audit_arch: b64 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - ansible_architecture == "aarch64" or ansible_architecture == "ppc64" or ansible_architecture == "ppc64le" or ansible_architecture == "s390x" or ansible_architecture == "x86_64" tags: + - DISA-STIG-OL09-00-000635 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.1 - PCI-DSS-Req-10.2.4 - - PCI-DSSv4-10.2.1.1 - - PCI-DSSv4-10.2.1.4 - audit_rules_unsuccessful_file_modification_truncate - low_complexity - low_disruption @@ -85602,6 +163925,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -85610,7 +163934,7 @@ fi line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -85654,6 +163978,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -85662,21 +163987,20 @@ fi line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-000635 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.1 - PCI-DSS-Req-10.2.4 - - PCI-DSSv4-10.2.1.1 - - PCI-DSSv4-10.2.1.4 - audit_rules_unsuccessful_file_modification_truncate - low_complexity - low_disruption @@ -85753,6 +164077,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -85761,7 +164086,7 @@ fi line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -85805,6 +164130,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -85813,22 +164139,21 @@ fi line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - audit_arch == "b64" tags: + - DISA-STIG-OL09-00-000635 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.1 - PCI-DSS-Req-10.2.4 - - PCI-DSSv4-10.2.1.1 - - PCI-DSSv4-10.2.1.4 - audit_rules_unsuccessful_file_modification_truncate - low_complexity - low_disruption @@ -85905,6 +164230,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -85913,7 +164239,7 @@ fi line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -85957,6 +164283,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -85965,21 +164292,20 @@ fi line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-000635 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.1 - PCI-DSS-Req-10.2.4 - - PCI-DSSv4-10.2.1.1 - - PCI-DSSv4-10.2.1.4 - audit_rules_unsuccessful_file_modification_truncate - low_complexity - low_disruption @@ -86056,6 +164382,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -86064,7 +164391,7 @@ fi line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -86108,6 +164435,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -86116,2912 +164444,39 @@ fi line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - audit_arch == "b64" tags: + - DISA-STIG-OL09-00-000635 - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.1 - PCI-DSS-Req-10.2.4 - - PCI-DSSv4-10.2.1.1 - - PCI-DSSv4-10.2.1.4 - audit_rules_unsuccessful_file_modification_truncate - low_complexity - low_disruption - medium_severity - reboot_required - restrict_strategy - - - - - - - - - - Record Unsuccessful Delete Attempts to Files - unlink - -The audit system should collect unsuccessful file deletion -attempts for all users and root. If the auditd daemon is configured -to use the augenrules program to read audit rules during daemon -startup (the default), add the following lines to a file with suffix -.rules in the directory /etc/audit/rules.d. - -If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add the following lines to -/etc/audit/audit.rules file. --a always,exit -F arch=b32 -S unlink -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-delete --a always,exit -F arch=b32 -S unlink -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-delete - -If the system is 64 bit then also add the following lines: - --a always,exit -F arch=b64 -S unlink -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-delete --a always,exit -F arch=b64 -S unlink -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-delete - Note that these rules can be configured in a -number of ways while still achieving the desired effect. Here the system calls -have been placed independent of other system calls. Grouping system calls related -to the same event is more efficient. See the following example: - --a always,exit -F arch=b32 -S unlink,unlinkat,rename,renameat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccesful-delete - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 19 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - APO12.06 - APO13.01 - BAI03.05 - BAI08.02 - DSS01.03 - DSS01.04 - DSS02.02 - DSS02.04 - DSS02.07 - DSS03.01 - DSS03.05 - DSS05.02 - DSS05.03 - DSS05.04 - DSS05.05 - DSS05.07 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.1.7 - CCI-000172 - CCI-002884 - 164.308(a)(1)(ii)(D) - 164.308(a)(3)(ii)(A) - 164.308(a)(5)(ii)(C) - 164.312(a)(2)(i) - 164.312(b) - 164.312(d) - 164.312(e) - 4.2.3.10 - 4.3.2.6.7 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.3.6.6 - 4.3.4.4.7 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 1.13 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.6 - SR 2.8 - SR 2.9 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 6.1 - SR 6.2 - SR 7.1 - SR 7.6 - A.11.2.6 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.14.2.7 - A.15.2.1 - A.15.2.2 - A.16.1.4 - A.16.1.5 - A.16.1.7 - A.6.2.1 - A.6.2.2 - AU-2(d) - AU-12(c) - CM-6(a) - DE.AE-3 - DE.AE-5 - DE.CM-1 - DE.CM-3 - DE.CM-7 - ID.SC-4 - PR.AC-3 - PR.PT-1 - PR.PT-4 - RS.AN-1 - RS.AN-4 - FAU_GEN.1.1.c - Req-10.2.4 - Req-10.2.1 - 10.2.1.1 - 10.2.1.4 - SRG-OS-000064-GPOS-00033 - SRG-OS-000392-GPOS-00172 - SRG-OS-000458-GPOS-00203 - SRG-OS-000461-GPOS-00205 - SRG-OS-000468-GPOS-00212 - Unsuccessful attempts to delete files could be an indicator of malicious activity on a system. Auditing -these events could serve as evidence of potential system compromise. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then - -# First perform the remediation of the syscall rule -# Retrieve hardware architecture of the underlying system -[ "$(getconf LONG_BIT)" = "32" ] && RULE_ARCHS=("b32") || RULE_ARCHS=("b32" "b64") - -AUID_FILTERS="-F auid>=1000 -F auid!=unset" -SYSCALL="unlink" -KEY="access" -SYSCALL_GROUPING="rename renameat unlink unlinkat" - -for ARCH in "${RULE_ARCHS[@]}" -do - ACTION_ARCH_FILTERS="-a always,exit -F arch=$ARCH" - OTHER_FILTERS="-F exit=-EACCES" - # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' - unset syscall_a -unset syscall_grouping -unset syscall_string -unset syscall -unset file_to_edit -unset rule_to_edit -unset rule_syscalls_to_edit -unset other_string -unset auid_string -unset full_rule - -# Load macro arguments into arrays -read -a syscall_a <<< $SYSCALL -read -a syscall_grouping <<< $SYSCALL_GROUPING - -# Create a list of audit *.rules files that should be inspected for presence and correctness -# of a particular audit rule. The scheme is as follows: -# -# ----------------------------------------------------------------------------------------- -# Tool used to load audit rules | Rule already defined | Audit rules file to inspect | -# ----------------------------------------------------------------------------------------- -# auditctl | Doesn't matter | /etc/audit/audit.rules | -# ----------------------------------------------------------------------------------------- -# augenrules | Yes | /etc/audit/rules.d/*.rules | -# augenrules | No | /etc/audit/rules.d/$key.rules | -# ----------------------------------------------------------------------------------------- -# -files_to_inspect=() - - -# If audit tool is 'augenrules', then check if the audit rule is defined -# If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection -# If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection -default_file="/etc/audit/rules.d/$KEY.rules" -# As other_filters may include paths, lets use a different delimiter for it -# The "F" script expression tells sed to print the filenames where the expressions matched -readarray -t files_to_inspect < <(sed -s -n -e "/^$ACTION_ARCH_FILTERS/!d" -e "\#$OTHER_FILTERS#!d" -e "/$AUID_FILTERS/!d" -e "F" /etc/audit/rules.d/*.rules) -# Case when particular rule isn't defined in /etc/audit/rules.d/*.rules yet -if [ ${#files_to_inspect[@]} -eq "0" ] -then - file_to_inspect="/etc/audit/rules.d/$KEY.rules" - files_to_inspect=("$file_to_inspect") - if [ ! -e "$file_to_inspect" ] - then - touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" - fi -fi - -# After converting to jinja, we cannot return; therefore we skip the rest of the macro if needed instead -skip=1 - -for audit_file in "${files_to_inspect[@]}" -do - # Filter existing $audit_file rules' definitions to select those that satisfy the rule pattern, - # i.e, collect rules that match: - # * the action, list and arch, (2-nd argument) - # * the other filters, (3-rd argument) - # * the auid filters, (4-rd argument) - readarray -t similar_rules < <(sed -e "/^$ACTION_ARCH_FILTERS/!d" -e "\#$OTHER_FILTERS#!d" -e "/$AUID_FILTERS/!d" "$audit_file") - - candidate_rules=() - # Filter out rules that have more fields then required. This will remove rules more specific than the required scope - for s_rule in "${similar_rules[@]}" - do - # Strip all the options and fields we know of, - # than check if there was any field left over - extra_fields=$(sed -E -e "s/^$ACTION_ARCH_FILTERS//" -e "s#$OTHER_FILTERS##" -e "s/$AUID_FILTERS//" -e "s/((:?-S [[:alnum:],]+)+)//g" -e "s/-F key=\w+|-k \w+//"<<< "$s_rule") - grep -q -- "-F" <<< "$extra_fields" || candidate_rules+=("$s_rule") - done - - if [[ ${#syscall_a[@]} -ge 1 ]] - then - # Check if the syscall we want is present in any of the similar existing rules - for rule in "${candidate_rules[@]}" - do - rule_syscalls=$(echo "$rule" | grep -o -P '(-S [\w,]+)+' | xargs) - all_syscalls_found=0 - for syscall in "${syscall_a[@]}" - do - grep -q -- "\b${syscall}\b" <<< "$rule_syscalls" || { - # A syscall was not found in the candidate rule - all_syscalls_found=1 - } - done - if [[ $all_syscalls_found -eq 0 ]] - then - # We found a rule with all the syscall(s) we want; skip rest of macro - skip=0 - break - fi - - # Check if this rule can be grouped with our target syscall and keep track of it - for syscall_g in "${syscall_grouping[@]}" - do - if grep -q -- "\b${syscall_g}\b" <<< "$rule_syscalls" - then - file_to_edit=${audit_file} - rule_to_edit=${rule} - rule_syscalls_to_edit=${rule_syscalls} - fi - done - done - else - # If there is any candidate rule, it is compliant; skip rest of macro - if [ "${#candidate_rules[@]}" -gt 0 ] - then - skip=0 - fi - fi - - if [ "$skip" -eq 0 ]; then - break - fi -done - -if [ "$skip" -ne 0 ]; then - # We checked all rules that matched the expected resemblance pattern (action, arch & auid) - # At this point we know if we need to either append the $full_rule or group - # the syscall together with an exsiting rule - - # Append the full_rule if it cannot be grouped to any other rule - if [ -z ${rule_to_edit+x} ] - then - # Build full_rule while avoid adding double spaces when other_filters is empty - if [ "${#syscall_a[@]}" -gt 0 ] - then - syscall_string="" - for syscall in "${syscall_a[@]}" - do - syscall_string+=" -S $syscall" - done - fi - other_string=$([[ $OTHER_FILTERS ]] && echo " $OTHER_FILTERS") || /bin/true - auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true - full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true - echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} - else - # Check if the syscalls are declared as a comma separated list or - # as multiple -S parameters - if grep -q -- "," <<< "${rule_syscalls_to_edit}" - then - delimiter="," - else - delimiter=" -S " - fi - new_grouped_syscalls="${rule_syscalls_to_edit}" - for syscall in "${syscall_a[@]}" - do - grep -q -- "\b${syscall}\b" <<< "${rule_syscalls_to_edit}" || { - # A syscall was not found in the candidate rule - new_grouped_syscalls+="${delimiter}${syscall}" - } - done - - # Group the syscall in the rule - sed -i -e "\#${rule_to_edit}#s#${rule_syscalls_to_edit}#${new_grouped_syscalls}#" "$file_to_edit" - fi -fi - unset syscall_a -unset syscall_grouping -unset syscall_string -unset syscall -unset file_to_edit -unset rule_to_edit -unset rule_syscalls_to_edit -unset other_string -unset auid_string -unset full_rule - -# Load macro arguments into arrays -read -a syscall_a <<< $SYSCALL -read -a syscall_grouping <<< $SYSCALL_GROUPING - -# Create a list of audit *.rules files that should be inspected for presence and correctness -# of a particular audit rule. The scheme is as follows: -# -# ----------------------------------------------------------------------------------------- -# Tool used to load audit rules | Rule already defined | Audit rules file to inspect | -# ----------------------------------------------------------------------------------------- -# auditctl | Doesn't matter | /etc/audit/audit.rules | -# ----------------------------------------------------------------------------------------- -# augenrules | Yes | /etc/audit/rules.d/*.rules | -# augenrules | No | /etc/audit/rules.d/$key.rules | -# ----------------------------------------------------------------------------------------- -# -files_to_inspect=() - - - -# If audit tool is 'auditctl', then add '/etc/audit/audit.rules' -# file to the list of files to be inspected -default_file="/etc/audit/audit.rules" -files_to_inspect+=('/etc/audit/audit.rules' ) - -# After converting to jinja, we cannot return; therefore we skip the rest of the macro if needed instead -skip=1 - -for audit_file in "${files_to_inspect[@]}" -do - # Filter existing $audit_file rules' definitions to select those that satisfy the rule pattern, - # i.e, collect rules that match: - # * the action, list and arch, (2-nd argument) - # * the other filters, (3-rd argument) - # * the auid filters, (4-rd argument) - readarray -t similar_rules < <(sed -e "/^$ACTION_ARCH_FILTERS/!d" -e "\#$OTHER_FILTERS#!d" -e "/$AUID_FILTERS/!d" "$audit_file") - - candidate_rules=() - # Filter out rules that have more fields then required. This will remove rules more specific than the required scope - for s_rule in "${similar_rules[@]}" - do - # Strip all the options and fields we know of, - # than check if there was any field left over - extra_fields=$(sed -E -e "s/^$ACTION_ARCH_FILTERS//" -e "s#$OTHER_FILTERS##" -e "s/$AUID_FILTERS//" -e "s/((:?-S [[:alnum:],]+)+)//g" -e "s/-F key=\w+|-k \w+//"<<< "$s_rule") - grep -q -- "-F" <<< "$extra_fields" || candidate_rules+=("$s_rule") - done - - if [[ ${#syscall_a[@]} -ge 1 ]] - then - # Check if the syscall we want is present in any of the similar existing rules - for rule in "${candidate_rules[@]}" - do - rule_syscalls=$(echo "$rule" | grep -o -P '(-S [\w,]+)+' | xargs) - all_syscalls_found=0 - for syscall in "${syscall_a[@]}" - do - grep -q -- "\b${syscall}\b" <<< "$rule_syscalls" || { - # A syscall was not found in the candidate rule - all_syscalls_found=1 - } - done - if [[ $all_syscalls_found -eq 0 ]] - then - # We found a rule with all the syscall(s) we want; skip rest of macro - skip=0 - break - fi - - # Check if this rule can be grouped with our target syscall and keep track of it - for syscall_g in "${syscall_grouping[@]}" - do - if grep -q -- "\b${syscall_g}\b" <<< "$rule_syscalls" - then - file_to_edit=${audit_file} - rule_to_edit=${rule} - rule_syscalls_to_edit=${rule_syscalls} - fi - done - done - else - # If there is any candidate rule, it is compliant; skip rest of macro - if [ "${#candidate_rules[@]}" -gt 0 ] - then - skip=0 - fi - fi - - if [ "$skip" -eq 0 ]; then - break - fi -done - -if [ "$skip" -ne 0 ]; then - # We checked all rules that matched the expected resemblance pattern (action, arch & auid) - # At this point we know if we need to either append the $full_rule or group - # the syscall together with an exsiting rule - - # Append the full_rule if it cannot be grouped to any other rule - if [ -z ${rule_to_edit+x} ] - then - # Build full_rule while avoid adding double spaces when other_filters is empty - if [ "${#syscall_a[@]}" -gt 0 ] - then - syscall_string="" - for syscall in "${syscall_a[@]}" - do - syscall_string+=" -S $syscall" - done - fi - other_string=$([[ $OTHER_FILTERS ]] && echo " $OTHER_FILTERS") || /bin/true - auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true - full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true - echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} - else - # Check if the syscalls are declared as a comma separated list or - # as multiple -S parameters - if grep -q -- "," <<< "${rule_syscalls_to_edit}" - then - delimiter="," - else - delimiter=" -S " - fi - new_grouped_syscalls="${rule_syscalls_to_edit}" - for syscall in "${syscall_a[@]}" - do - grep -q -- "\b${syscall}\b" <<< "${rule_syscalls_to_edit}" || { - # A syscall was not found in the candidate rule - new_grouped_syscalls+="${delimiter}${syscall}" - } - done - - # Group the syscall in the rule - sed -i -e "\#${rule_to_edit}#s#${rule_syscalls_to_edit}#${new_grouped_syscalls}#" "$file_to_edit" - fi -fi -done - -for ARCH in "${RULE_ARCHS[@]}" -do - ACTION_ARCH_FILTERS="-a always,exit -F arch=$ARCH" - OTHER_FILTERS="-F exit=-EPERM" - # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' - unset syscall_a -unset syscall_grouping -unset syscall_string -unset syscall -unset file_to_edit -unset rule_to_edit -unset rule_syscalls_to_edit -unset other_string -unset auid_string -unset full_rule - -# Load macro arguments into arrays -read -a syscall_a <<< $SYSCALL -read -a syscall_grouping <<< $SYSCALL_GROUPING - -# Create a list of audit *.rules files that should be inspected for presence and correctness -# of a particular audit rule. The scheme is as follows: -# -# ----------------------------------------------------------------------------------------- -# Tool used to load audit rules | Rule already defined | Audit rules file to inspect | -# ----------------------------------------------------------------------------------------- -# auditctl | Doesn't matter | /etc/audit/audit.rules | -# ----------------------------------------------------------------------------------------- -# augenrules | Yes | /etc/audit/rules.d/*.rules | -# augenrules | No | /etc/audit/rules.d/$key.rules | -# ----------------------------------------------------------------------------------------- -# -files_to_inspect=() - - -# If audit tool is 'augenrules', then check if the audit rule is defined -# If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection -# If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection -default_file="/etc/audit/rules.d/$KEY.rules" -# As other_filters may include paths, lets use a different delimiter for it -# The "F" script expression tells sed to print the filenames where the expressions matched -readarray -t files_to_inspect < <(sed -s -n -e "/^$ACTION_ARCH_FILTERS/!d" -e "\#$OTHER_FILTERS#!d" -e "/$AUID_FILTERS/!d" -e "F" /etc/audit/rules.d/*.rules) -# Case when particular rule isn't defined in /etc/audit/rules.d/*.rules yet -if [ ${#files_to_inspect[@]} -eq "0" ] -then - file_to_inspect="/etc/audit/rules.d/$KEY.rules" - files_to_inspect=("$file_to_inspect") - if [ ! -e "$file_to_inspect" ] - then - touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" - fi -fi - -# After converting to jinja, we cannot return; therefore we skip the rest of the macro if needed instead -skip=1 - -for audit_file in "${files_to_inspect[@]}" -do - # Filter existing $audit_file rules' definitions to select those that satisfy the rule pattern, - # i.e, collect rules that match: - # * the action, list and arch, (2-nd argument) - # * the other filters, (3-rd argument) - # * the auid filters, (4-rd argument) - readarray -t similar_rules < <(sed -e "/^$ACTION_ARCH_FILTERS/!d" -e "\#$OTHER_FILTERS#!d" -e "/$AUID_FILTERS/!d" "$audit_file") - - candidate_rules=() - # Filter out rules that have more fields then required. This will remove rules more specific than the required scope - for s_rule in "${similar_rules[@]}" - do - # Strip all the options and fields we know of, - # than check if there was any field left over - extra_fields=$(sed -E -e "s/^$ACTION_ARCH_FILTERS//" -e "s#$OTHER_FILTERS##" -e "s/$AUID_FILTERS//" -e "s/((:?-S [[:alnum:],]+)+)//g" -e "s/-F key=\w+|-k \w+//"<<< "$s_rule") - grep -q -- "-F" <<< "$extra_fields" || candidate_rules+=("$s_rule") - done - - if [[ ${#syscall_a[@]} -ge 1 ]] - then - # Check if the syscall we want is present in any of the similar existing rules - for rule in "${candidate_rules[@]}" - do - rule_syscalls=$(echo "$rule" | grep -o -P '(-S [\w,]+)+' | xargs) - all_syscalls_found=0 - for syscall in "${syscall_a[@]}" - do - grep -q -- "\b${syscall}\b" <<< "$rule_syscalls" || { - # A syscall was not found in the candidate rule - all_syscalls_found=1 - } - done - if [[ $all_syscalls_found -eq 0 ]] - then - # We found a rule with all the syscall(s) we want; skip rest of macro - skip=0 - break - fi - - # Check if this rule can be grouped with our target syscall and keep track of it - for syscall_g in "${syscall_grouping[@]}" - do - if grep -q -- "\b${syscall_g}\b" <<< "$rule_syscalls" - then - file_to_edit=${audit_file} - rule_to_edit=${rule} - rule_syscalls_to_edit=${rule_syscalls} - fi - done - done - else - # If there is any candidate rule, it is compliant; skip rest of macro - if [ "${#candidate_rules[@]}" -gt 0 ] - then - skip=0 - fi - fi - - if [ "$skip" -eq 0 ]; then - break - fi -done - -if [ "$skip" -ne 0 ]; then - # We checked all rules that matched the expected resemblance pattern (action, arch & auid) - # At this point we know if we need to either append the $full_rule or group - # the syscall together with an exsiting rule - - # Append the full_rule if it cannot be grouped to any other rule - if [ -z ${rule_to_edit+x} ] - then - # Build full_rule while avoid adding double spaces when other_filters is empty - if [ "${#syscall_a[@]}" -gt 0 ] - then - syscall_string="" - for syscall in "${syscall_a[@]}" - do - syscall_string+=" -S $syscall" - done - fi - other_string=$([[ $OTHER_FILTERS ]] && echo " $OTHER_FILTERS") || /bin/true - auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true - full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true - echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} - else - # Check if the syscalls are declared as a comma separated list or - # as multiple -S parameters - if grep -q -- "," <<< "${rule_syscalls_to_edit}" - then - delimiter="," - else - delimiter=" -S " - fi - new_grouped_syscalls="${rule_syscalls_to_edit}" - for syscall in "${syscall_a[@]}" - do - grep -q -- "\b${syscall}\b" <<< "${rule_syscalls_to_edit}" || { - # A syscall was not found in the candidate rule - new_grouped_syscalls+="${delimiter}${syscall}" - } - done - - # Group the syscall in the rule - sed -i -e "\#${rule_to_edit}#s#${rule_syscalls_to_edit}#${new_grouped_syscalls}#" "$file_to_edit" - fi -fi - unset syscall_a -unset syscall_grouping -unset syscall_string -unset syscall -unset file_to_edit -unset rule_to_edit -unset rule_syscalls_to_edit -unset other_string -unset auid_string -unset full_rule - -# Load macro arguments into arrays -read -a syscall_a <<< $SYSCALL -read -a syscall_grouping <<< $SYSCALL_GROUPING - -# Create a list of audit *.rules files that should be inspected for presence and correctness -# of a particular audit rule. The scheme is as follows: -# -# ----------------------------------------------------------------------------------------- -# Tool used to load audit rules | Rule already defined | Audit rules file to inspect | -# ----------------------------------------------------------------------------------------- -# auditctl | Doesn't matter | /etc/audit/audit.rules | -# ----------------------------------------------------------------------------------------- -# augenrules | Yes | /etc/audit/rules.d/*.rules | -# augenrules | No | /etc/audit/rules.d/$key.rules | -# ----------------------------------------------------------------------------------------- -# -files_to_inspect=() - - - -# If audit tool is 'auditctl', then add '/etc/audit/audit.rules' -# file to the list of files to be inspected -default_file="/etc/audit/audit.rules" -files_to_inspect+=('/etc/audit/audit.rules' ) - -# After converting to jinja, we cannot return; therefore we skip the rest of the macro if needed instead -skip=1 - -for audit_file in "${files_to_inspect[@]}" -do - # Filter existing $audit_file rules' definitions to select those that satisfy the rule pattern, - # i.e, collect rules that match: - # * the action, list and arch, (2-nd argument) - # * the other filters, (3-rd argument) - # * the auid filters, (4-rd argument) - readarray -t similar_rules < <(sed -e "/^$ACTION_ARCH_FILTERS/!d" -e "\#$OTHER_FILTERS#!d" -e "/$AUID_FILTERS/!d" "$audit_file") - - candidate_rules=() - # Filter out rules that have more fields then required. This will remove rules more specific than the required scope - for s_rule in "${similar_rules[@]}" - do - # Strip all the options and fields we know of, - # than check if there was any field left over - extra_fields=$(sed -E -e "s/^$ACTION_ARCH_FILTERS//" -e "s#$OTHER_FILTERS##" -e "s/$AUID_FILTERS//" -e "s/((:?-S [[:alnum:],]+)+)//g" -e "s/-F key=\w+|-k \w+//"<<< "$s_rule") - grep -q -- "-F" <<< "$extra_fields" || candidate_rules+=("$s_rule") - done - - if [[ ${#syscall_a[@]} -ge 1 ]] - then - # Check if the syscall we want is present in any of the similar existing rules - for rule in "${candidate_rules[@]}" - do - rule_syscalls=$(echo "$rule" | grep -o -P '(-S [\w,]+)+' | xargs) - all_syscalls_found=0 - for syscall in "${syscall_a[@]}" - do - grep -q -- "\b${syscall}\b" <<< "$rule_syscalls" || { - # A syscall was not found in the candidate rule - all_syscalls_found=1 - } - done - if [[ $all_syscalls_found -eq 0 ]] - then - # We found a rule with all the syscall(s) we want; skip rest of macro - skip=0 - break - fi - - # Check if this rule can be grouped with our target syscall and keep track of it - for syscall_g in "${syscall_grouping[@]}" - do - if grep -q -- "\b${syscall_g}\b" <<< "$rule_syscalls" - then - file_to_edit=${audit_file} - rule_to_edit=${rule} - rule_syscalls_to_edit=${rule_syscalls} - fi - done - done - else - # If there is any candidate rule, it is compliant; skip rest of macro - if [ "${#candidate_rules[@]}" -gt 0 ] - then - skip=0 - fi - fi - - if [ "$skip" -eq 0 ]; then - break - fi -done - -if [ "$skip" -ne 0 ]; then - # We checked all rules that matched the expected resemblance pattern (action, arch & auid) - # At this point we know if we need to either append the $full_rule or group - # the syscall together with an exsiting rule - - # Append the full_rule if it cannot be grouped to any other rule - if [ -z ${rule_to_edit+x} ] - then - # Build full_rule while avoid adding double spaces when other_filters is empty - if [ "${#syscall_a[@]}" -gt 0 ] - then - syscall_string="" - for syscall in "${syscall_a[@]}" - do - syscall_string+=" -S $syscall" - done - fi - other_string=$([[ $OTHER_FILTERS ]] && echo " $OTHER_FILTERS") || /bin/true - auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true - full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true - echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} - else - # Check if the syscalls are declared as a comma separated list or - # as multiple -S parameters - if grep -q -- "," <<< "${rule_syscalls_to_edit}" - then - delimiter="," - else - delimiter=" -S " - fi - new_grouped_syscalls="${rule_syscalls_to_edit}" - for syscall in "${syscall_a[@]}" - do - grep -q -- "\b${syscall}\b" <<< "${rule_syscalls_to_edit}" || { - # A syscall was not found in the candidate rule - new_grouped_syscalls+="${delimiter}${syscall}" - } - done - - # Group the syscall in the rule - sed -i -e "\#${rule_to_edit}#s#${rule_syscalls_to_edit}#${new_grouped_syscalls}#" "$file_to_edit" - fi -fi -done - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Gather the package facts - package_facts: - manager: auto - tags: - - NIST-800-171-3.1.7 - - NIST-800-53-AU-12(c) - - NIST-800-53-AU-2(d) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.2.1 - - PCI-DSS-Req-10.2.4 - - PCI-DSSv4-10.2.1.1 - - PCI-DSSv4-10.2.1.4 - - audit_rules_unsuccessful_file_modification_unlink - - low_complexity - - low_disruption - - medium_severity - - reboot_required - - restrict_strategy - -- name: Set architecture for audit unlink tasks - set_fact: - audit_arch: b64 - when: - - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - ansible_architecture == "aarch64" or ansible_architecture == "ppc64" or ansible_architecture - == "ppc64le" or ansible_architecture == "s390x" or ansible_architecture == "x86_64" - tags: - - NIST-800-171-3.1.7 - - NIST-800-53-AU-12(c) - - NIST-800-53-AU-2(d) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.2.1 - - PCI-DSS-Req-10.2.4 - - PCI-DSSv4-10.2.1.1 - - PCI-DSSv4-10.2.1.4 - - audit_rules_unsuccessful_file_modification_unlink - - low_complexity - - low_disruption - - medium_severity - - reboot_required - - restrict_strategy - -- name: Perform remediation of Audit rules for unlink EACCES for 32bit platform - block: - - - name: Declare list of syscalls - set_fact: - syscalls: - - unlink - syscall_grouping: - - rename - - renameat - - unlink - - unlinkat - - - name: Check existence of unlink in /etc/audit/rules.d/ - find: - paths: /etc/audit/rules.d - contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S - |,)\w+)* -F exit=-EACCES -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ - patterns: '*.rules' - register: find_command - loop: '{{ (syscall_grouping + syscalls) | unique }}' - - - name: Reset syscalls found per file - set_fact: - syscalls_per_file: {} - found_paths_dict: {} - - - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path - :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" - loop: '{{ find_command.results | selectattr(''matched'') | list }}' - - - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" - - - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, - 0) }) }}" - loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') - | list }}' - - - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') - | last).key }}" - when: found_paths | length >= 1 - - - name: No file with syscall found, set path to /etc/audit/rules.d/access.rules - set_fact: audit_file="/etc/audit/rules.d/access.rules" - when: found_paths | length == 0 - - - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" - - - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" - - - name: Replace the audit rule in {{ audit_file }} - lineinfile: - path: '{{ audit_file }}' - regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] - | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EACCES -F auid>=1000 -F auid!=unset - (?:-k |-F key=)\w+) - line: \1\2\3{{ missing_syscalls | join("\3") }}\4 - backrefs: true - state: present - when: syscalls_found | length > 0 and missing_syscalls | length > 0 - - - name: Add the audit rule to {{ audit_file }} - lineinfile: - path: '{{ audit_file }}' - line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EACCES - -F auid>=1000 -F auid!=unset -F key=access - create: true - mode: o-rwx - state: present - when: syscalls_found | length == 0 - - - name: Declare list of syscalls - set_fact: - syscalls: - - unlink - syscall_grouping: - - rename - - renameat - - unlink - - unlinkat - - - name: Check existence of unlink in /etc/audit/audit.rules - find: - paths: /etc/audit - contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S - |,)\w+)* -F exit=-EACCES -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ - patterns: audit.rules - register: find_command - loop: '{{ (syscall_grouping + syscalls) | unique }}' - - - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" - - - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" - - - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" - - - name: Replace the audit rule in {{ audit_file }} - lineinfile: - path: '{{ audit_file }}' - regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | - join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EACCES -F auid>=1000 -F auid!=unset - (?:-k |-F key=)\w+) - line: \1\2\3{{ missing_syscalls | join("\3") }}\4 - backrefs: true - state: present - when: syscalls_found | length > 0 and missing_syscalls | length > 0 - - - name: Add the audit rule to {{ audit_file }} - lineinfile: - path: '{{ audit_file }}' - line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EACCES - -F auid>=1000 -F auid!=unset -F key=access - create: true - mode: o-rwx - state: present - when: syscalls_found | length == 0 - when: - - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.7 - - NIST-800-53-AU-12(c) - - NIST-800-53-AU-2(d) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.2.1 - - PCI-DSS-Req-10.2.4 - - PCI-DSSv4-10.2.1.1 - - PCI-DSSv4-10.2.1.4 - - audit_rules_unsuccessful_file_modification_unlink - - low_complexity - - low_disruption - - medium_severity - - reboot_required - - restrict_strategy - -- name: Perform remediation of Audit rules for unlink EACCES for 64bit platform - block: - - - name: Declare list of syscalls - set_fact: - syscalls: - - unlink - syscall_grouping: - - rename - - renameat - - unlink - - unlinkat - - - name: Check existence of unlink in /etc/audit/rules.d/ - find: - paths: /etc/audit/rules.d - contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S - |,)\w+)* -F exit=-EACCES -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ - patterns: '*.rules' - register: find_command - loop: '{{ (syscall_grouping + syscalls) | unique }}' - - - name: Reset syscalls found per file - set_fact: - syscalls_per_file: {} - found_paths_dict: {} - - - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path - :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" - loop: '{{ find_command.results | selectattr(''matched'') | list }}' - - - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" - - - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, - 0) }) }}" - loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') - | list }}' - - - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') - | last).key }}" - when: found_paths | length >= 1 - - - name: No file with syscall found, set path to /etc/audit/rules.d/access.rules - set_fact: audit_file="/etc/audit/rules.d/access.rules" - when: found_paths | length == 0 - - - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" - - - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" - - - name: Replace the audit rule in {{ audit_file }} - lineinfile: - path: '{{ audit_file }}' - regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] - | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EACCES -F auid>=1000 -F auid!=unset - (?:-k |-F key=)\w+) - line: \1\2\3{{ missing_syscalls | join("\3") }}\4 - backrefs: true - state: present - when: syscalls_found | length > 0 and missing_syscalls | length > 0 - - - name: Add the audit rule to {{ audit_file }} - lineinfile: - path: '{{ audit_file }}' - line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EACCES - -F auid>=1000 -F auid!=unset -F key=access - create: true - mode: o-rwx - state: present - when: syscalls_found | length == 0 - - - name: Declare list of syscalls - set_fact: - syscalls: - - unlink - syscall_grouping: - - rename - - renameat - - unlink - - unlinkat - - - name: Check existence of unlink in /etc/audit/audit.rules - find: - paths: /etc/audit - contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S - |,)\w+)* -F exit=-EACCES -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ - patterns: audit.rules - register: find_command - loop: '{{ (syscall_grouping + syscalls) | unique }}' - - - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" - - - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" - - - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" - - - name: Replace the audit rule in {{ audit_file }} - lineinfile: - path: '{{ audit_file }}' - regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | - join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EACCES -F auid>=1000 -F auid!=unset - (?:-k |-F key=)\w+) - line: \1\2\3{{ missing_syscalls | join("\3") }}\4 - backrefs: true - state: present - when: syscalls_found | length > 0 and missing_syscalls | length > 0 - - - name: Add the audit rule to {{ audit_file }} - lineinfile: - path: '{{ audit_file }}' - line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EACCES - -F auid>=1000 -F auid!=unset -F key=access - create: true - mode: o-rwx - state: present - when: syscalls_found | length == 0 - when: - - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - audit_arch == "b64" - tags: - - NIST-800-171-3.1.7 - - NIST-800-53-AU-12(c) - - NIST-800-53-AU-2(d) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.2.1 - - PCI-DSS-Req-10.2.4 - - PCI-DSSv4-10.2.1.1 - - PCI-DSSv4-10.2.1.4 - - audit_rules_unsuccessful_file_modification_unlink - - low_complexity - - low_disruption - - medium_severity - - reboot_required - - restrict_strategy - -- name: Perform remediation of Audit rules for unlink EPERM for 32bit platform - block: - - - name: Declare list of syscalls - set_fact: - syscalls: - - unlink - syscall_grouping: - - rename - - renameat - - unlink - - unlinkat - - - name: Check existence of unlink in /etc/audit/rules.d/ - find: - paths: /etc/audit/rules.d - contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S - |,)\w+)* -F exit=-EPERM -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ - patterns: '*.rules' - register: find_command - loop: '{{ (syscall_grouping + syscalls) | unique }}' - - - name: Reset syscalls found per file - set_fact: - syscalls_per_file: {} - found_paths_dict: {} - - - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path - :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" - loop: '{{ find_command.results | selectattr(''matched'') | list }}' - - - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" - - - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, - 0) }) }}" - loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') - | list }}' - - - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') - | last).key }}" - when: found_paths | length >= 1 - - - name: No file with syscall found, set path to /etc/audit/rules.d/access.rules - set_fact: audit_file="/etc/audit/rules.d/access.rules" - when: found_paths | length == 0 - - - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" - - - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" - - - name: Replace the audit rule in {{ audit_file }} - lineinfile: - path: '{{ audit_file }}' - regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] - | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EPERM -F auid>=1000 -F auid!=unset - (?:-k |-F key=)\w+) - line: \1\2\3{{ missing_syscalls | join("\3") }}\4 - backrefs: true - state: present - when: syscalls_found | length > 0 and missing_syscalls | length > 0 - - - name: Add the audit rule to {{ audit_file }} - lineinfile: - path: '{{ audit_file }}' - line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EPERM - -F auid>=1000 -F auid!=unset -F key=access - create: true - mode: o-rwx - state: present - when: syscalls_found | length == 0 - - - name: Declare list of syscalls - set_fact: - syscalls: - - unlink - syscall_grouping: - - rename - - renameat - - unlink - - unlinkat - - - name: Check existence of unlink in /etc/audit/audit.rules - find: - paths: /etc/audit - contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S - |,)\w+)* -F exit=-EPERM -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ - patterns: audit.rules - register: find_command - loop: '{{ (syscall_grouping + syscalls) | unique }}' - - - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" - - - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" - - - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" - - - name: Replace the audit rule in {{ audit_file }} - lineinfile: - path: '{{ audit_file }}' - regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | - join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EPERM -F auid>=1000 -F auid!=unset - (?:-k |-F key=)\w+) - line: \1\2\3{{ missing_syscalls | join("\3") }}\4 - backrefs: true - state: present - when: syscalls_found | length > 0 and missing_syscalls | length > 0 - - - name: Add the audit rule to {{ audit_file }} - lineinfile: - path: '{{ audit_file }}' - line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EPERM - -F auid>=1000 -F auid!=unset -F key=access - create: true - mode: o-rwx - state: present - when: syscalls_found | length == 0 - when: - - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.7 - - NIST-800-53-AU-12(c) - - NIST-800-53-AU-2(d) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.2.1 - - PCI-DSS-Req-10.2.4 - - PCI-DSSv4-10.2.1.1 - - PCI-DSSv4-10.2.1.4 - - audit_rules_unsuccessful_file_modification_unlink - - low_complexity - - low_disruption - - medium_severity - - reboot_required - - restrict_strategy - -- name: Perform remediation of Audit rules for unlink EPERM for 64bit platform - block: - - - name: Declare list of syscalls - set_fact: - syscalls: - - unlink - syscall_grouping: - - rename - - renameat - - unlink - - unlinkat - - - name: Check existence of unlink in /etc/audit/rules.d/ - find: - paths: /etc/audit/rules.d - contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S - |,)\w+)* -F exit=-EPERM -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ - patterns: '*.rules' - register: find_command - loop: '{{ (syscall_grouping + syscalls) | unique }}' - - - name: Reset syscalls found per file - set_fact: - syscalls_per_file: {} - found_paths_dict: {} - - - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path - :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" - loop: '{{ find_command.results | selectattr(''matched'') | list }}' - - - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" - - - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, - 0) }) }}" - loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') - | list }}' - - - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') - | last).key }}" - when: found_paths | length >= 1 - - - name: No file with syscall found, set path to /etc/audit/rules.d/access.rules - set_fact: audit_file="/etc/audit/rules.d/access.rules" - when: found_paths | length == 0 - - - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" - - - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" - - - name: Replace the audit rule in {{ audit_file }} - lineinfile: - path: '{{ audit_file }}' - regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] - | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EPERM -F auid>=1000 -F auid!=unset - (?:-k |-F key=)\w+) - line: \1\2\3{{ missing_syscalls | join("\3") }}\4 - backrefs: true - state: present - when: syscalls_found | length > 0 and missing_syscalls | length > 0 - - - name: Add the audit rule to {{ audit_file }} - lineinfile: - path: '{{ audit_file }}' - line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EPERM - -F auid>=1000 -F auid!=unset -F key=access - create: true - mode: o-rwx - state: present - when: syscalls_found | length == 0 - - - name: Declare list of syscalls - set_fact: - syscalls: - - unlink - syscall_grouping: - - rename - - renameat - - unlink - - unlinkat - - - name: Check existence of unlink in /etc/audit/audit.rules - find: - paths: /etc/audit - contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S - |,)\w+)* -F exit=-EPERM -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ - patterns: audit.rules - register: find_command - loop: '{{ (syscall_grouping + syscalls) | unique }}' - - - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" - - - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" - - - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" - - - name: Replace the audit rule in {{ audit_file }} - lineinfile: - path: '{{ audit_file }}' - regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | - join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EPERM -F auid>=1000 -F auid!=unset - (?:-k |-F key=)\w+) - line: \1\2\3{{ missing_syscalls | join("\3") }}\4 - backrefs: true - state: present - when: syscalls_found | length > 0 and missing_syscalls | length > 0 - - - name: Add the audit rule to {{ audit_file }} - lineinfile: - path: '{{ audit_file }}' - line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EPERM - -F auid>=1000 -F auid!=unset -F key=access - create: true - mode: o-rwx - state: present - when: syscalls_found | length == 0 - when: - - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - audit_arch == "b64" - tags: - - NIST-800-171-3.1.7 - - NIST-800-53-AU-12(c) - - NIST-800-53-AU-2(d) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.2.1 - - PCI-DSS-Req-10.2.4 - - PCI-DSSv4-10.2.1.1 - - PCI-DSSv4-10.2.1.4 - - audit_rules_unsuccessful_file_modification_unlink - - low_complexity - - low_disruption - - medium_severity - - reboot_required - - restrict_strategy - - - - - - - - - - Record Unsuccessful Delete Attempts to Files - unlinkat - -The audit system should collect unsuccessful file deletion -attempts for all users and root. If the auditd daemon is configured -to use the augenrules program to read audit rules during daemon -startup (the default), add the following lines to a file with suffix -.rules in the directory /etc/audit/rules.d. - -If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add the following lines to -/etc/audit/audit.rules file. --a always,exit -F arch=b32 -S unlinkat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-delete --a always,exit -F arch=b32 -S unlinkat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-delete - -If the system is 64 bit then also add the following lines: - --a always,exit -F arch=b64 -S unlinkat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-delete --a always,exit -F arch=b64 -S unlinkat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-delete - Note that these rules can be configured in a -number of ways while still achieving the desired effect. Here the system calls -have been placed independent of other system calls. Grouping system calls related -to the same event is more efficient. See the following example: - --a always,exit -F arch=b32 -S unlink,unlinkat,rename,renameat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccesful-delete - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 19 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - APO12.06 - APO13.01 - BAI03.05 - BAI08.02 - DSS01.03 - DSS01.04 - DSS02.02 - DSS02.04 - DSS02.07 - DSS03.01 - DSS03.05 - DSS05.02 - DSS05.03 - DSS05.04 - DSS05.05 - DSS05.07 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.1.7 - CCI-000172 - CCI-002884 - 164.308(a)(1)(ii)(D) - 164.308(a)(3)(ii)(A) - 164.308(a)(5)(ii)(C) - 164.312(a)(2)(i) - 164.312(b) - 164.312(d) - 164.312(e) - 4.2.3.10 - 4.3.2.6.7 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.3.6.6 - 4.3.4.4.7 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 1.13 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.6 - SR 2.8 - SR 2.9 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 6.1 - SR 6.2 - SR 7.1 - SR 7.6 - A.11.2.6 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.14.2.7 - A.15.2.1 - A.15.2.2 - A.16.1.4 - A.16.1.5 - A.16.1.7 - A.6.2.1 - A.6.2.2 - AU-2(d) - AU-12(c) - CM-6(a) - DE.AE-3 - DE.AE-5 - DE.CM-1 - DE.CM-3 - DE.CM-7 - ID.SC-4 - PR.AC-3 - PR.PT-1 - PR.PT-4 - RS.AN-1 - RS.AN-4 - FAU_GEN.1.1.c - Req-10.2.4 - Req-10.2.1 - 10.2.1.1 - 10.2.1.4 - SRG-OS-000064-GPOS-00033 - SRG-OS-000392-GPOS-00172 - SRG-OS-000458-GPOS-00203 - SRG-OS-000461-GPOS-00205 - SRG-OS-000468-GPOS-00212 - Unsuccessful attempts to delete files could be an indicator of malicious activity on a system. Auditing -these events could serve as evidence of potential system compromise. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then - -# First perform the remediation of the syscall rule -# Retrieve hardware architecture of the underlying system -[ "$(getconf LONG_BIT)" = "32" ] && RULE_ARCHS=("b32") || RULE_ARCHS=("b32" "b64") - -AUID_FILTERS="-F auid>=1000 -F auid!=unset" -SYSCALL="unlinkat" -KEY="access" -SYSCALL_GROUPING="rename renameat unlink unlinkat" - -for ARCH in "${RULE_ARCHS[@]}" -do - ACTION_ARCH_FILTERS="-a always,exit -F arch=$ARCH" - OTHER_FILTERS="-F exit=-EACCES" - # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' - unset syscall_a -unset syscall_grouping -unset syscall_string -unset syscall -unset file_to_edit -unset rule_to_edit -unset rule_syscalls_to_edit -unset other_string -unset auid_string -unset full_rule - -# Load macro arguments into arrays -read -a syscall_a <<< $SYSCALL -read -a syscall_grouping <<< $SYSCALL_GROUPING - -# Create a list of audit *.rules files that should be inspected for presence and correctness -# of a particular audit rule. The scheme is as follows: -# -# ----------------------------------------------------------------------------------------- -# Tool used to load audit rules | Rule already defined | Audit rules file to inspect | -# ----------------------------------------------------------------------------------------- -# auditctl | Doesn't matter | /etc/audit/audit.rules | -# ----------------------------------------------------------------------------------------- -# augenrules | Yes | /etc/audit/rules.d/*.rules | -# augenrules | No | /etc/audit/rules.d/$key.rules | -# ----------------------------------------------------------------------------------------- -# -files_to_inspect=() - - -# If audit tool is 'augenrules', then check if the audit rule is defined -# If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection -# If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection -default_file="/etc/audit/rules.d/$KEY.rules" -# As other_filters may include paths, lets use a different delimiter for it -# The "F" script expression tells sed to print the filenames where the expressions matched -readarray -t files_to_inspect < <(sed -s -n -e "/^$ACTION_ARCH_FILTERS/!d" -e "\#$OTHER_FILTERS#!d" -e "/$AUID_FILTERS/!d" -e "F" /etc/audit/rules.d/*.rules) -# Case when particular rule isn't defined in /etc/audit/rules.d/*.rules yet -if [ ${#files_to_inspect[@]} -eq "0" ] -then - file_to_inspect="/etc/audit/rules.d/$KEY.rules" - files_to_inspect=("$file_to_inspect") - if [ ! -e "$file_to_inspect" ] - then - touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" - fi -fi - -# After converting to jinja, we cannot return; therefore we skip the rest of the macro if needed instead -skip=1 - -for audit_file in "${files_to_inspect[@]}" -do - # Filter existing $audit_file rules' definitions to select those that satisfy the rule pattern, - # i.e, collect rules that match: - # * the action, list and arch, (2-nd argument) - # * the other filters, (3-rd argument) - # * the auid filters, (4-rd argument) - readarray -t similar_rules < <(sed -e "/^$ACTION_ARCH_FILTERS/!d" -e "\#$OTHER_FILTERS#!d" -e "/$AUID_FILTERS/!d" "$audit_file") - - candidate_rules=() - # Filter out rules that have more fields then required. This will remove rules more specific than the required scope - for s_rule in "${similar_rules[@]}" - do - # Strip all the options and fields we know of, - # than check if there was any field left over - extra_fields=$(sed -E -e "s/^$ACTION_ARCH_FILTERS//" -e "s#$OTHER_FILTERS##" -e "s/$AUID_FILTERS//" -e "s/((:?-S [[:alnum:],]+)+)//g" -e "s/-F key=\w+|-k \w+//"<<< "$s_rule") - grep -q -- "-F" <<< "$extra_fields" || candidate_rules+=("$s_rule") - done - - if [[ ${#syscall_a[@]} -ge 1 ]] - then - # Check if the syscall we want is present in any of the similar existing rules - for rule in "${candidate_rules[@]}" - do - rule_syscalls=$(echo "$rule" | grep -o -P '(-S [\w,]+)+' | xargs) - all_syscalls_found=0 - for syscall in "${syscall_a[@]}" - do - grep -q -- "\b${syscall}\b" <<< "$rule_syscalls" || { - # A syscall was not found in the candidate rule - all_syscalls_found=1 - } - done - if [[ $all_syscalls_found -eq 0 ]] - then - # We found a rule with all the syscall(s) we want; skip rest of macro - skip=0 - break - fi - - # Check if this rule can be grouped with our target syscall and keep track of it - for syscall_g in "${syscall_grouping[@]}" - do - if grep -q -- "\b${syscall_g}\b" <<< "$rule_syscalls" - then - file_to_edit=${audit_file} - rule_to_edit=${rule} - rule_syscalls_to_edit=${rule_syscalls} - fi - done - done - else - # If there is any candidate rule, it is compliant; skip rest of macro - if [ "${#candidate_rules[@]}" -gt 0 ] - then - skip=0 - fi - fi - - if [ "$skip" -eq 0 ]; then - break - fi -done - -if [ "$skip" -ne 0 ]; then - # We checked all rules that matched the expected resemblance pattern (action, arch & auid) - # At this point we know if we need to either append the $full_rule or group - # the syscall together with an exsiting rule - - # Append the full_rule if it cannot be grouped to any other rule - if [ -z ${rule_to_edit+x} ] - then - # Build full_rule while avoid adding double spaces when other_filters is empty - if [ "${#syscall_a[@]}" -gt 0 ] - then - syscall_string="" - for syscall in "${syscall_a[@]}" - do - syscall_string+=" -S $syscall" - done - fi - other_string=$([[ $OTHER_FILTERS ]] && echo " $OTHER_FILTERS") || /bin/true - auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true - full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true - echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} - else - # Check if the syscalls are declared as a comma separated list or - # as multiple -S parameters - if grep -q -- "," <<< "${rule_syscalls_to_edit}" - then - delimiter="," - else - delimiter=" -S " - fi - new_grouped_syscalls="${rule_syscalls_to_edit}" - for syscall in "${syscall_a[@]}" - do - grep -q -- "\b${syscall}\b" <<< "${rule_syscalls_to_edit}" || { - # A syscall was not found in the candidate rule - new_grouped_syscalls+="${delimiter}${syscall}" - } - done - - # Group the syscall in the rule - sed -i -e "\#${rule_to_edit}#s#${rule_syscalls_to_edit}#${new_grouped_syscalls}#" "$file_to_edit" - fi -fi - unset syscall_a -unset syscall_grouping -unset syscall_string -unset syscall -unset file_to_edit -unset rule_to_edit -unset rule_syscalls_to_edit -unset other_string -unset auid_string -unset full_rule - -# Load macro arguments into arrays -read -a syscall_a <<< $SYSCALL -read -a syscall_grouping <<< $SYSCALL_GROUPING - -# Create a list of audit *.rules files that should be inspected for presence and correctness -# of a particular audit rule. The scheme is as follows: -# -# ----------------------------------------------------------------------------------------- -# Tool used to load audit rules | Rule already defined | Audit rules file to inspect | -# ----------------------------------------------------------------------------------------- -# auditctl | Doesn't matter | /etc/audit/audit.rules | -# ----------------------------------------------------------------------------------------- -# augenrules | Yes | /etc/audit/rules.d/*.rules | -# augenrules | No | /etc/audit/rules.d/$key.rules | -# ----------------------------------------------------------------------------------------- -# -files_to_inspect=() - - - -# If audit tool is 'auditctl', then add '/etc/audit/audit.rules' -# file to the list of files to be inspected -default_file="/etc/audit/audit.rules" -files_to_inspect+=('/etc/audit/audit.rules' ) - -# After converting to jinja, we cannot return; therefore we skip the rest of the macro if needed instead -skip=1 - -for audit_file in "${files_to_inspect[@]}" -do - # Filter existing $audit_file rules' definitions to select those that satisfy the rule pattern, - # i.e, collect rules that match: - # * the action, list and arch, (2-nd argument) - # * the other filters, (3-rd argument) - # * the auid filters, (4-rd argument) - readarray -t similar_rules < <(sed -e "/^$ACTION_ARCH_FILTERS/!d" -e "\#$OTHER_FILTERS#!d" -e "/$AUID_FILTERS/!d" "$audit_file") - - candidate_rules=() - # Filter out rules that have more fields then required. This will remove rules more specific than the required scope - for s_rule in "${similar_rules[@]}" - do - # Strip all the options and fields we know of, - # than check if there was any field left over - extra_fields=$(sed -E -e "s/^$ACTION_ARCH_FILTERS//" -e "s#$OTHER_FILTERS##" -e "s/$AUID_FILTERS//" -e "s/((:?-S [[:alnum:],]+)+)//g" -e "s/-F key=\w+|-k \w+//"<<< "$s_rule") - grep -q -- "-F" <<< "$extra_fields" || candidate_rules+=("$s_rule") - done - - if [[ ${#syscall_a[@]} -ge 1 ]] - then - # Check if the syscall we want is present in any of the similar existing rules - for rule in "${candidate_rules[@]}" - do - rule_syscalls=$(echo "$rule" | grep -o -P '(-S [\w,]+)+' | xargs) - all_syscalls_found=0 - for syscall in "${syscall_a[@]}" - do - grep -q -- "\b${syscall}\b" <<< "$rule_syscalls" || { - # A syscall was not found in the candidate rule - all_syscalls_found=1 - } - done - if [[ $all_syscalls_found -eq 0 ]] - then - # We found a rule with all the syscall(s) we want; skip rest of macro - skip=0 - break - fi - - # Check if this rule can be grouped with our target syscall and keep track of it - for syscall_g in "${syscall_grouping[@]}" - do - if grep -q -- "\b${syscall_g}\b" <<< "$rule_syscalls" - then - file_to_edit=${audit_file} - rule_to_edit=${rule} - rule_syscalls_to_edit=${rule_syscalls} - fi - done - done - else - # If there is any candidate rule, it is compliant; skip rest of macro - if [ "${#candidate_rules[@]}" -gt 0 ] - then - skip=0 - fi - fi - - if [ "$skip" -eq 0 ]; then - break - fi -done - -if [ "$skip" -ne 0 ]; then - # We checked all rules that matched the expected resemblance pattern (action, arch & auid) - # At this point we know if we need to either append the $full_rule or group - # the syscall together with an exsiting rule - - # Append the full_rule if it cannot be grouped to any other rule - if [ -z ${rule_to_edit+x} ] - then - # Build full_rule while avoid adding double spaces when other_filters is empty - if [ "${#syscall_a[@]}" -gt 0 ] - then - syscall_string="" - for syscall in "${syscall_a[@]}" - do - syscall_string+=" -S $syscall" - done - fi - other_string=$([[ $OTHER_FILTERS ]] && echo " $OTHER_FILTERS") || /bin/true - auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true - full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true - echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} - else - # Check if the syscalls are declared as a comma separated list or - # as multiple -S parameters - if grep -q -- "," <<< "${rule_syscalls_to_edit}" - then - delimiter="," - else - delimiter=" -S " - fi - new_grouped_syscalls="${rule_syscalls_to_edit}" - for syscall in "${syscall_a[@]}" - do - grep -q -- "\b${syscall}\b" <<< "${rule_syscalls_to_edit}" || { - # A syscall was not found in the candidate rule - new_grouped_syscalls+="${delimiter}${syscall}" - } - done - - # Group the syscall in the rule - sed -i -e "\#${rule_to_edit}#s#${rule_syscalls_to_edit}#${new_grouped_syscalls}#" "$file_to_edit" - fi -fi -done - -for ARCH in "${RULE_ARCHS[@]}" -do - ACTION_ARCH_FILTERS="-a always,exit -F arch=$ARCH" - OTHER_FILTERS="-F exit=-EPERM" - # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' - unset syscall_a -unset syscall_grouping -unset syscall_string -unset syscall -unset file_to_edit -unset rule_to_edit -unset rule_syscalls_to_edit -unset other_string -unset auid_string -unset full_rule - -# Load macro arguments into arrays -read -a syscall_a <<< $SYSCALL -read -a syscall_grouping <<< $SYSCALL_GROUPING - -# Create a list of audit *.rules files that should be inspected for presence and correctness -# of a particular audit rule. The scheme is as follows: -# -# ----------------------------------------------------------------------------------------- -# Tool used to load audit rules | Rule already defined | Audit rules file to inspect | -# ----------------------------------------------------------------------------------------- -# auditctl | Doesn't matter | /etc/audit/audit.rules | -# ----------------------------------------------------------------------------------------- -# augenrules | Yes | /etc/audit/rules.d/*.rules | -# augenrules | No | /etc/audit/rules.d/$key.rules | -# ----------------------------------------------------------------------------------------- -# -files_to_inspect=() - - -# If audit tool is 'augenrules', then check if the audit rule is defined -# If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection -# If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection -default_file="/etc/audit/rules.d/$KEY.rules" -# As other_filters may include paths, lets use a different delimiter for it -# The "F" script expression tells sed to print the filenames where the expressions matched -readarray -t files_to_inspect < <(sed -s -n -e "/^$ACTION_ARCH_FILTERS/!d" -e "\#$OTHER_FILTERS#!d" -e "/$AUID_FILTERS/!d" -e "F" /etc/audit/rules.d/*.rules) -# Case when particular rule isn't defined in /etc/audit/rules.d/*.rules yet -if [ ${#files_to_inspect[@]} -eq "0" ] -then - file_to_inspect="/etc/audit/rules.d/$KEY.rules" - files_to_inspect=("$file_to_inspect") - if [ ! -e "$file_to_inspect" ] - then - touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" - fi -fi - -# After converting to jinja, we cannot return; therefore we skip the rest of the macro if needed instead -skip=1 - -for audit_file in "${files_to_inspect[@]}" -do - # Filter existing $audit_file rules' definitions to select those that satisfy the rule pattern, - # i.e, collect rules that match: - # * the action, list and arch, (2-nd argument) - # * the other filters, (3-rd argument) - # * the auid filters, (4-rd argument) - readarray -t similar_rules < <(sed -e "/^$ACTION_ARCH_FILTERS/!d" -e "\#$OTHER_FILTERS#!d" -e "/$AUID_FILTERS/!d" "$audit_file") - - candidate_rules=() - # Filter out rules that have more fields then required. This will remove rules more specific than the required scope - for s_rule in "${similar_rules[@]}" - do - # Strip all the options and fields we know of, - # than check if there was any field left over - extra_fields=$(sed -E -e "s/^$ACTION_ARCH_FILTERS//" -e "s#$OTHER_FILTERS##" -e "s/$AUID_FILTERS//" -e "s/((:?-S [[:alnum:],]+)+)//g" -e "s/-F key=\w+|-k \w+//"<<< "$s_rule") - grep -q -- "-F" <<< "$extra_fields" || candidate_rules+=("$s_rule") - done - - if [[ ${#syscall_a[@]} -ge 1 ]] - then - # Check if the syscall we want is present in any of the similar existing rules - for rule in "${candidate_rules[@]}" - do - rule_syscalls=$(echo "$rule" | grep -o -P '(-S [\w,]+)+' | xargs) - all_syscalls_found=0 - for syscall in "${syscall_a[@]}" - do - grep -q -- "\b${syscall}\b" <<< "$rule_syscalls" || { - # A syscall was not found in the candidate rule - all_syscalls_found=1 - } - done - if [[ $all_syscalls_found -eq 0 ]] - then - # We found a rule with all the syscall(s) we want; skip rest of macro - skip=0 - break - fi - - # Check if this rule can be grouped with our target syscall and keep track of it - for syscall_g in "${syscall_grouping[@]}" - do - if grep -q -- "\b${syscall_g}\b" <<< "$rule_syscalls" - then - file_to_edit=${audit_file} - rule_to_edit=${rule} - rule_syscalls_to_edit=${rule_syscalls} - fi - done - done - else - # If there is any candidate rule, it is compliant; skip rest of macro - if [ "${#candidate_rules[@]}" -gt 0 ] - then - skip=0 - fi - fi - - if [ "$skip" -eq 0 ]; then - break - fi -done - -if [ "$skip" -ne 0 ]; then - # We checked all rules that matched the expected resemblance pattern (action, arch & auid) - # At this point we know if we need to either append the $full_rule or group - # the syscall together with an exsiting rule - - # Append the full_rule if it cannot be grouped to any other rule - if [ -z ${rule_to_edit+x} ] - then - # Build full_rule while avoid adding double spaces when other_filters is empty - if [ "${#syscall_a[@]}" -gt 0 ] - then - syscall_string="" - for syscall in "${syscall_a[@]}" - do - syscall_string+=" -S $syscall" - done - fi - other_string=$([[ $OTHER_FILTERS ]] && echo " $OTHER_FILTERS") || /bin/true - auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true - full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true - echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} - else - # Check if the syscalls are declared as a comma separated list or - # as multiple -S parameters - if grep -q -- "," <<< "${rule_syscalls_to_edit}" - then - delimiter="," - else - delimiter=" -S " - fi - new_grouped_syscalls="${rule_syscalls_to_edit}" - for syscall in "${syscall_a[@]}" - do - grep -q -- "\b${syscall}\b" <<< "${rule_syscalls_to_edit}" || { - # A syscall was not found in the candidate rule - new_grouped_syscalls+="${delimiter}${syscall}" - } - done - - # Group the syscall in the rule - sed -i -e "\#${rule_to_edit}#s#${rule_syscalls_to_edit}#${new_grouped_syscalls}#" "$file_to_edit" - fi -fi - unset syscall_a -unset syscall_grouping -unset syscall_string -unset syscall -unset file_to_edit -unset rule_to_edit -unset rule_syscalls_to_edit -unset other_string -unset auid_string -unset full_rule - -# Load macro arguments into arrays -read -a syscall_a <<< $SYSCALL -read -a syscall_grouping <<< $SYSCALL_GROUPING - -# Create a list of audit *.rules files that should be inspected for presence and correctness -# of a particular audit rule. The scheme is as follows: -# -# ----------------------------------------------------------------------------------------- -# Tool used to load audit rules | Rule already defined | Audit rules file to inspect | -# ----------------------------------------------------------------------------------------- -# auditctl | Doesn't matter | /etc/audit/audit.rules | -# ----------------------------------------------------------------------------------------- -# augenrules | Yes | /etc/audit/rules.d/*.rules | -# augenrules | No | /etc/audit/rules.d/$key.rules | -# ----------------------------------------------------------------------------------------- -# -files_to_inspect=() - - - -# If audit tool is 'auditctl', then add '/etc/audit/audit.rules' -# file to the list of files to be inspected -default_file="/etc/audit/audit.rules" -files_to_inspect+=('/etc/audit/audit.rules' ) - -# After converting to jinja, we cannot return; therefore we skip the rest of the macro if needed instead -skip=1 - -for audit_file in "${files_to_inspect[@]}" -do - # Filter existing $audit_file rules' definitions to select those that satisfy the rule pattern, - # i.e, collect rules that match: - # * the action, list and arch, (2-nd argument) - # * the other filters, (3-rd argument) - # * the auid filters, (4-rd argument) - readarray -t similar_rules < <(sed -e "/^$ACTION_ARCH_FILTERS/!d" -e "\#$OTHER_FILTERS#!d" -e "/$AUID_FILTERS/!d" "$audit_file") - - candidate_rules=() - # Filter out rules that have more fields then required. This will remove rules more specific than the required scope - for s_rule in "${similar_rules[@]}" - do - # Strip all the options and fields we know of, - # than check if there was any field left over - extra_fields=$(sed -E -e "s/^$ACTION_ARCH_FILTERS//" -e "s#$OTHER_FILTERS##" -e "s/$AUID_FILTERS//" -e "s/((:?-S [[:alnum:],]+)+)//g" -e "s/-F key=\w+|-k \w+//"<<< "$s_rule") - grep -q -- "-F" <<< "$extra_fields" || candidate_rules+=("$s_rule") - done - - if [[ ${#syscall_a[@]} -ge 1 ]] - then - # Check if the syscall we want is present in any of the similar existing rules - for rule in "${candidate_rules[@]}" - do - rule_syscalls=$(echo "$rule" | grep -o -P '(-S [\w,]+)+' | xargs) - all_syscalls_found=0 - for syscall in "${syscall_a[@]}" - do - grep -q -- "\b${syscall}\b" <<< "$rule_syscalls" || { - # A syscall was not found in the candidate rule - all_syscalls_found=1 - } - done - if [[ $all_syscalls_found -eq 0 ]] - then - # We found a rule with all the syscall(s) we want; skip rest of macro - skip=0 - break - fi - - # Check if this rule can be grouped with our target syscall and keep track of it - for syscall_g in "${syscall_grouping[@]}" - do - if grep -q -- "\b${syscall_g}\b" <<< "$rule_syscalls" - then - file_to_edit=${audit_file} - rule_to_edit=${rule} - rule_syscalls_to_edit=${rule_syscalls} - fi - done - done - else - # If there is any candidate rule, it is compliant; skip rest of macro - if [ "${#candidate_rules[@]}" -gt 0 ] - then - skip=0 - fi - fi - - if [ "$skip" -eq 0 ]; then - break - fi -done - -if [ "$skip" -ne 0 ]; then - # We checked all rules that matched the expected resemblance pattern (action, arch & auid) - # At this point we know if we need to either append the $full_rule or group - # the syscall together with an exsiting rule - - # Append the full_rule if it cannot be grouped to any other rule - if [ -z ${rule_to_edit+x} ] - then - # Build full_rule while avoid adding double spaces when other_filters is empty - if [ "${#syscall_a[@]}" -gt 0 ] - then - syscall_string="" - for syscall in "${syscall_a[@]}" - do - syscall_string+=" -S $syscall" - done - fi - other_string=$([[ $OTHER_FILTERS ]] && echo " $OTHER_FILTERS") || /bin/true - auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true - full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true - echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} - else - # Check if the syscalls are declared as a comma separated list or - # as multiple -S parameters - if grep -q -- "," <<< "${rule_syscalls_to_edit}" - then - delimiter="," - else - delimiter=" -S " - fi - new_grouped_syscalls="${rule_syscalls_to_edit}" - for syscall in "${syscall_a[@]}" - do - grep -q -- "\b${syscall}\b" <<< "${rule_syscalls_to_edit}" || { - # A syscall was not found in the candidate rule - new_grouped_syscalls+="${delimiter}${syscall}" - } - done - - # Group the syscall in the rule - sed -i -e "\#${rule_to_edit}#s#${rule_syscalls_to_edit}#${new_grouped_syscalls}#" "$file_to_edit" - fi -fi -done - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Gather the package facts - package_facts: - manager: auto - tags: - - NIST-800-171-3.1.7 - - NIST-800-53-AU-12(c) - - NIST-800-53-AU-2(d) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.2.1 - - PCI-DSS-Req-10.2.4 - - PCI-DSSv4-10.2.1.1 - - PCI-DSSv4-10.2.1.4 - - audit_rules_unsuccessful_file_modification_unlinkat - - low_complexity - - low_disruption - - medium_severity - - reboot_required - - restrict_strategy - -- name: Set architecture for audit unlinkat tasks - set_fact: - audit_arch: b64 - when: - - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - ansible_architecture == "aarch64" or ansible_architecture == "ppc64" or ansible_architecture - == "ppc64le" or ansible_architecture == "s390x" or ansible_architecture == "x86_64" - tags: - - NIST-800-171-3.1.7 - - NIST-800-53-AU-12(c) - - NIST-800-53-AU-2(d) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.2.1 - - PCI-DSS-Req-10.2.4 - - PCI-DSSv4-10.2.1.1 - - PCI-DSSv4-10.2.1.4 - - audit_rules_unsuccessful_file_modification_unlinkat - - low_complexity - - low_disruption - - medium_severity - - reboot_required - - restrict_strategy - -- name: Perform remediation of Audit rules for unlinkat EACCES for 32bit platform - block: - - - name: Declare list of syscalls - set_fact: - syscalls: - - unlinkat - syscall_grouping: - - rename - - renameat - - unlink - - unlinkat - - - name: Check existence of unlinkat in /etc/audit/rules.d/ - find: - paths: /etc/audit/rules.d - contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S - |,)\w+)* -F exit=-EACCES -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ - patterns: '*.rules' - register: find_command - loop: '{{ (syscall_grouping + syscalls) | unique }}' - - - name: Reset syscalls found per file - set_fact: - syscalls_per_file: {} - found_paths_dict: {} - - - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path - :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" - loop: '{{ find_command.results | selectattr(''matched'') | list }}' - - - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" - - - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, - 0) }) }}" - loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') - | list }}' - - - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') - | last).key }}" - when: found_paths | length >= 1 - - - name: No file with syscall found, set path to /etc/audit/rules.d/access.rules - set_fact: audit_file="/etc/audit/rules.d/access.rules" - when: found_paths | length == 0 - - - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" - - - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" - - - name: Replace the audit rule in {{ audit_file }} - lineinfile: - path: '{{ audit_file }}' - regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] - | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EACCES -F auid>=1000 -F auid!=unset - (?:-k |-F key=)\w+) - line: \1\2\3{{ missing_syscalls | join("\3") }}\4 - backrefs: true - state: present - when: syscalls_found | length > 0 and missing_syscalls | length > 0 - - - name: Add the audit rule to {{ audit_file }} - lineinfile: - path: '{{ audit_file }}' - line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EACCES - -F auid>=1000 -F auid!=unset -F key=access - create: true - mode: o-rwx - state: present - when: syscalls_found | length == 0 - - - name: Declare list of syscalls - set_fact: - syscalls: - - unlinkat - syscall_grouping: - - rename - - renameat - - unlink - - unlinkat - - - name: Check existence of unlinkat in /etc/audit/audit.rules - find: - paths: /etc/audit - contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S - |,)\w+)* -F exit=-EACCES -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ - patterns: audit.rules - register: find_command - loop: '{{ (syscall_grouping + syscalls) | unique }}' - - - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" - - - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" - - - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" - - - name: Replace the audit rule in {{ audit_file }} - lineinfile: - path: '{{ audit_file }}' - regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | - join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EACCES -F auid>=1000 -F auid!=unset - (?:-k |-F key=)\w+) - line: \1\2\3{{ missing_syscalls | join("\3") }}\4 - backrefs: true - state: present - when: syscalls_found | length > 0 and missing_syscalls | length > 0 - - - name: Add the audit rule to {{ audit_file }} - lineinfile: - path: '{{ audit_file }}' - line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EACCES - -F auid>=1000 -F auid!=unset -F key=access - create: true - mode: o-rwx - state: present - when: syscalls_found | length == 0 - when: - - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.7 - - NIST-800-53-AU-12(c) - - NIST-800-53-AU-2(d) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.2.1 - - PCI-DSS-Req-10.2.4 - - PCI-DSSv4-10.2.1.1 - - PCI-DSSv4-10.2.1.4 - - audit_rules_unsuccessful_file_modification_unlinkat - - low_complexity - - low_disruption - - medium_severity - - reboot_required - - restrict_strategy - -- name: Perform remediation of Audit rules for unlinkat EACCES for 64bit platform - block: - - - name: Declare list of syscalls - set_fact: - syscalls: - - unlinkat - syscall_grouping: - - rename - - renameat - - unlink - - unlinkat - - - name: Check existence of unlinkat in /etc/audit/rules.d/ - find: - paths: /etc/audit/rules.d - contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S - |,)\w+)* -F exit=-EACCES -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ - patterns: '*.rules' - register: find_command - loop: '{{ (syscall_grouping + syscalls) | unique }}' - - - name: Reset syscalls found per file - set_fact: - syscalls_per_file: {} - found_paths_dict: {} - - - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path - :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" - loop: '{{ find_command.results | selectattr(''matched'') | list }}' - - - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" - - - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, - 0) }) }}" - loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') - | list }}' - - - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') - | last).key }}" - when: found_paths | length >= 1 - - - name: No file with syscall found, set path to /etc/audit/rules.d/access.rules - set_fact: audit_file="/etc/audit/rules.d/access.rules" - when: found_paths | length == 0 - - - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" - - - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" - - - name: Replace the audit rule in {{ audit_file }} - lineinfile: - path: '{{ audit_file }}' - regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] - | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EACCES -F auid>=1000 -F auid!=unset - (?:-k |-F key=)\w+) - line: \1\2\3{{ missing_syscalls | join("\3") }}\4 - backrefs: true - state: present - when: syscalls_found | length > 0 and missing_syscalls | length > 0 - - - name: Add the audit rule to {{ audit_file }} - lineinfile: - path: '{{ audit_file }}' - line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EACCES - -F auid>=1000 -F auid!=unset -F key=access - create: true - mode: o-rwx - state: present - when: syscalls_found | length == 0 - - - name: Declare list of syscalls - set_fact: - syscalls: - - unlinkat - syscall_grouping: - - rename - - renameat - - unlink - - unlinkat - - - name: Check existence of unlinkat in /etc/audit/audit.rules - find: - paths: /etc/audit - contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S - |,)\w+)* -F exit=-EACCES -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ - patterns: audit.rules - register: find_command - loop: '{{ (syscall_grouping + syscalls) | unique }}' - - - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" - - - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" - - - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" - - - name: Replace the audit rule in {{ audit_file }} - lineinfile: - path: '{{ audit_file }}' - regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | - join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EACCES -F auid>=1000 -F auid!=unset - (?:-k |-F key=)\w+) - line: \1\2\3{{ missing_syscalls | join("\3") }}\4 - backrefs: true - state: present - when: syscalls_found | length > 0 and missing_syscalls | length > 0 - - - name: Add the audit rule to {{ audit_file }} - lineinfile: - path: '{{ audit_file }}' - line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EACCES - -F auid>=1000 -F auid!=unset -F key=access - create: true - mode: o-rwx - state: present - when: syscalls_found | length == 0 - when: - - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - audit_arch == "b64" - tags: - - NIST-800-171-3.1.7 - - NIST-800-53-AU-12(c) - - NIST-800-53-AU-2(d) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.2.1 - - PCI-DSS-Req-10.2.4 - - PCI-DSSv4-10.2.1.1 - - PCI-DSSv4-10.2.1.4 - - audit_rules_unsuccessful_file_modification_unlinkat - - low_complexity - - low_disruption - - medium_severity - - reboot_required - - restrict_strategy - -- name: Perform remediation of Audit rules for unlinkat EPERM for 32bit platform - block: - - - name: Declare list of syscalls - set_fact: - syscalls: - - unlinkat - syscall_grouping: - - rename - - renameat - - unlink - - unlinkat - - - name: Check existence of unlinkat in /etc/audit/rules.d/ - find: - paths: /etc/audit/rules.d - contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S - |,)\w+)* -F exit=-EPERM -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ - patterns: '*.rules' - register: find_command - loop: '{{ (syscall_grouping + syscalls) | unique }}' - - - name: Reset syscalls found per file - set_fact: - syscalls_per_file: {} - found_paths_dict: {} - - - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path - :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" - loop: '{{ find_command.results | selectattr(''matched'') | list }}' - - - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" - - - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, - 0) }) }}" - loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') - | list }}' - - - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') - | last).key }}" - when: found_paths | length >= 1 - - - name: No file with syscall found, set path to /etc/audit/rules.d/access.rules - set_fact: audit_file="/etc/audit/rules.d/access.rules" - when: found_paths | length == 0 - - - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" - - - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" - - - name: Replace the audit rule in {{ audit_file }} - lineinfile: - path: '{{ audit_file }}' - regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] - | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EPERM -F auid>=1000 -F auid!=unset - (?:-k |-F key=)\w+) - line: \1\2\3{{ missing_syscalls | join("\3") }}\4 - backrefs: true - state: present - when: syscalls_found | length > 0 and missing_syscalls | length > 0 - - - name: Add the audit rule to {{ audit_file }} - lineinfile: - path: '{{ audit_file }}' - line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EPERM - -F auid>=1000 -F auid!=unset -F key=access - create: true - mode: o-rwx - state: present - when: syscalls_found | length == 0 - - - name: Declare list of syscalls - set_fact: - syscalls: - - unlinkat - syscall_grouping: - - rename - - renameat - - unlink - - unlinkat - - - name: Check existence of unlinkat in /etc/audit/audit.rules - find: - paths: /etc/audit - contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S - |,)\w+)* -F exit=-EPERM -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ - patterns: audit.rules - register: find_command - loop: '{{ (syscall_grouping + syscalls) | unique }}' - - - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" - - - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" - - - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" - - - name: Replace the audit rule in {{ audit_file }} - lineinfile: - path: '{{ audit_file }}' - regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | - join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EPERM -F auid>=1000 -F auid!=unset - (?:-k |-F key=)\w+) - line: \1\2\3{{ missing_syscalls | join("\3") }}\4 - backrefs: true - state: present - when: syscalls_found | length > 0 and missing_syscalls | length > 0 - - - name: Add the audit rule to {{ audit_file }} - lineinfile: - path: '{{ audit_file }}' - line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EPERM - -F auid>=1000 -F auid!=unset -F key=access - create: true - mode: o-rwx - state: present - when: syscalls_found | length == 0 - when: - - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.7 - - NIST-800-53-AU-12(c) - - NIST-800-53-AU-2(d) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.2.1 - - PCI-DSS-Req-10.2.4 - - PCI-DSSv4-10.2.1.1 - - PCI-DSSv4-10.2.1.4 - - audit_rules_unsuccessful_file_modification_unlinkat - - low_complexity - - low_disruption - - medium_severity - - reboot_required - - restrict_strategy - -- name: Perform remediation of Audit rules for unlinkat EPERM for 64bit platform - block: - - - name: Declare list of syscalls - set_fact: - syscalls: - - unlinkat - syscall_grouping: - - rename - - renameat - - unlink - - unlinkat - - - name: Check existence of unlinkat in /etc/audit/rules.d/ - find: - paths: /etc/audit/rules.d - contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S - |,)\w+)* -F exit=-EPERM -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ - patterns: '*.rules' - register: find_command - loop: '{{ (syscall_grouping + syscalls) | unique }}' - - - name: Reset syscalls found per file - set_fact: - syscalls_per_file: {} - found_paths_dict: {} - - - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path - :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" - loop: '{{ find_command.results | selectattr(''matched'') | list }}' - - - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" - - - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, - 0) }) }}" - loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') - | list }}' - - - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') - | last).key }}" - when: found_paths | length >= 1 - - - name: No file with syscall found, set path to /etc/audit/rules.d/access.rules - set_fact: audit_file="/etc/audit/rules.d/access.rules" - when: found_paths | length == 0 - - - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" - - - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" - - - name: Replace the audit rule in {{ audit_file }} - lineinfile: - path: '{{ audit_file }}' - regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] - | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EPERM -F auid>=1000 -F auid!=unset - (?:-k |-F key=)\w+) - line: \1\2\3{{ missing_syscalls | join("\3") }}\4 - backrefs: true - state: present - when: syscalls_found | length > 0 and missing_syscalls | length > 0 - - - name: Add the audit rule to {{ audit_file }} - lineinfile: - path: '{{ audit_file }}' - line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EPERM - -F auid>=1000 -F auid!=unset -F key=access - create: true - mode: o-rwx - state: present - when: syscalls_found | length == 0 - - - name: Declare list of syscalls - set_fact: - syscalls: - - unlinkat - syscall_grouping: - - rename - - renameat - - unlink - - unlinkat - - - name: Check existence of unlinkat in /etc/audit/audit.rules - find: - paths: /etc/audit - contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S - |,)\w+)* -F exit=-EPERM -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ - patterns: audit.rules - register: find_command - loop: '{{ (syscall_grouping + syscalls) | unique }}' - - - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" - - - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" - - - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" - - - name: Replace the audit rule in {{ audit_file }} - lineinfile: - path: '{{ audit_file }}' - regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | - join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EPERM -F auid>=1000 -F auid!=unset - (?:-k |-F key=)\w+) - line: \1\2\3{{ missing_syscalls | join("\3") }}\4 - backrefs: true - state: present - when: syscalls_found | length > 0 and missing_syscalls | length > 0 - - - name: Add the audit rule to {{ audit_file }} - lineinfile: - path: '{{ audit_file }}' - line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EPERM - -F auid>=1000 -F auid!=unset -F key=access - create: true - mode: o-rwx - state: present - when: syscalls_found | length == 0 - when: - - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - audit_arch == "b64" - tags: - - NIST-800-171-3.1.7 - - NIST-800-53-AU-12(c) - - NIST-800-53-AU-2(d) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.2.1 - - PCI-DSS-Req-10.2.4 - - PCI-DSSv4-10.2.1.1 - - PCI-DSSv4-10.2.1.4 - - audit_rules_unsuccessful_file_modification_unlinkat - - low_complexity - - low_disruption - - medium_severity - - reboot_required - - restrict_strategy - - - - - - - - - - - Record Information on Kernel Modules Loading and Unloading - To capture kernel module loading and unloading events, use following lines, setting ARCH to + + + + + + + + + + + Record Information on Kernel Modules Loading and Unloading + To capture kernel module loading and unloading events, use following lines, setting ARCH to either b32 for 32-bit system, or having two lines for both b32 and b64 in case your system is 64-bit: -a always,exit -F arch=ARCH -S init_module,delete_module -F key=modules @@ -89032,13 +164487,13 @@ to use the augenrules program (the default), add the line .rules in the directory /etc/audit/rules.d. If the auditd daemon is configured to use the auditctl utility, -add the lines to file /etc/audit/audit.rules. - - Ensure auditd Collects Information on Kernel Module Loading and Unloading - To capture kernel module loading and unloading events, use following lines, setting ARCH to +add the lines to file /etc/audit/audit.rules. + + Ensure auditd Collects Information on Kernel Module Loading and Unloading + To capture kernel module loading and unloading events, use following lines, setting ARCH to either b32 for 32-bit system, or having two lines for both b32 and b64 in case your system is 64-bit: --a always,exit -F arch=ARCH -S init_module,finit_module,delete_module -F key=modules +-a always,exit -F arch=ARCH -S init_module,finit_module,delete_module -F auid>=1000 -F auid!=unset -F key=modules The place to add the lines depends on a way auditd daemon is configured. If it is configured @@ -89046,123 +164501,122 @@ to use the augenrules program (the default), add the line .rules in the directory /etc/audit/rules.d. If the auditd daemon is configured to use the auditctl utility, -add the lines to file /etc/audit/audit.rules. - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 19 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 5.4.1.1 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - APO12.06 - APO13.01 - BAI03.05 - BAI08.02 - DSS01.03 - DSS01.04 - DSS02.02 - DSS02.04 - DSS02.07 - DSS03.01 - DSS03.05 - DSS05.02 - DSS05.03 - DSS05.04 - DSS05.05 - DSS05.07 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.1.7 - CCI-000172 - 4.2.3.10 - 4.3.2.6.7 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.3.6.6 - 4.3.4.4.7 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 1.13 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.6 - SR 2.8 - SR 2.9 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 6.1 - SR 6.2 - SR 7.1 - SR 7.6 - A.11.2.6 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.14.2.7 - A.15.2.1 - A.15.2.2 - A.16.1.4 - A.16.1.5 - A.16.1.7 - A.6.2.1 - A.6.2.2 - AU-2(d) - AU-12(c) - AC-6(9) - CM-6(a) - DE.AE-3 - DE.AE-5 - DE.CM-1 - DE.CM-3 - DE.CM-7 - ID.SC-4 - PR.AC-3 - PR.PT-1 - PR.PT-4 - RS.AN-1 - RS.AN-4 - Req-10.2.7 - 10.2.1.7 - The addition/removal of kernel modules can be used to alter the behavior of +add the lines to file /etc/audit/audit.rules. + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 19 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 5.4.1.1 + APO10.01 + APO10.03 + APO10.04 + APO10.05 + APO11.04 + APO12.06 + APO13.01 + BAI03.05 + BAI08.02 + DSS01.03 + DSS01.04 + DSS02.02 + DSS02.04 + DSS02.07 + DSS03.01 + DSS03.05 + DSS05.02 + DSS05.03 + DSS05.04 + DSS05.05 + DSS05.07 + MEA01.01 + MEA01.02 + MEA01.03 + MEA01.04 + MEA01.05 + MEA02.01 + 3.1.7 + CCI-000172 + 4.2.3.10 + 4.3.2.6.7 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.3.6.6 + 4.3.4.4.7 + 4.3.4.5.6 + 4.3.4.5.7 + 4.3.4.5.8 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 1.13 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.6 + SR 2.8 + SR 2.9 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 6.1 + SR 6.2 + SR 7.1 + SR 7.6 + A.11.2.6 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.13.1.1 + A.13.2.1 + A.14.1.3 + A.14.2.7 + A.15.2.1 + A.15.2.2 + A.16.1.4 + A.16.1.5 + A.16.1.7 + A.6.2.1 + A.6.2.2 + AU-2(d) + AU-12(c) + AC-6(9) + CM-6(a) + DE.AE-3 + DE.AE-5 + DE.CM-1 + DE.CM-3 + DE.CM-7 + ID.SC-4 + PR.AC-3 + PR.PT-1 + PR.PT-4 + RS.AN-1 + RS.AN-4 + Req-10.2.7 + The addition/removal of kernel modules can be used to alter the behavior of the kernel and potentially introduce malicious code into kernel space. It is important -to have an audit trail of modules that have been introduced into the kernel. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +to have an audit trail of modules that have been introduced into the kernel. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then # First perform the remediation of the syscall rule # Retrieve hardware architecture of the underlying system @@ -89212,7 +164666,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -89228,7 +164681,7 @@ then if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -89320,7 +164773,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -89373,7 +164826,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -89467,7 +164919,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -89495,8 +164947,8 @@ done else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: @@ -89507,7 +164959,6 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.7 - - PCI-DSSv4-10.2.1.7 - audit_rules_kernel_module_loading - low_complexity - low_disruption @@ -89520,7 +164971,7 @@ fi audit_arch: b64 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - ansible_architecture == "aarch64" or ansible_architecture == "ppc64" or ansible_architecture == "ppc64le" or ansible_architecture == "s390x" or ansible_architecture == "x86_64" tags: @@ -89531,7 +164982,6 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.7 - - PCI-DSSv4-10.2.1.7 - audit_rules_kernel_module_loading - low_complexity - low_disruption @@ -89607,6 +165057,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -89615,7 +165066,7 @@ fi line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=modules create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -89658,6 +165109,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -89666,12 +165118,12 @@ fi line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=modules create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.4.1.1 - NIST-800-171-3.1.7 @@ -89680,7 +165132,6 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.7 - - PCI-DSSv4-10.2.1.7 - audit_rules_kernel_module_loading - low_complexity - low_disruption @@ -89756,6 +165207,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -89764,7 +165216,7 @@ fi line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=modules create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -89807,6 +165259,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -89815,12 +165268,12 @@ fi line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=modules create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - audit_arch == "b64" tags: - CJIS-5.4.1.1 @@ -89830,24 +165283,23 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.7 - - PCI-DSSv4-10.2.1.7 - audit_rules_kernel_module_loading - low_complexity - low_disruption - medium_severity - reboot_required - restrict_strategy - - - - - - - - - - Ensure auditd Collects Information on Kernel Module Unloading - delete_module - To capture kernel module unloading events, use following line, setting ARCH to + + + + + + + + + + Ensure auditd Collects Information on Kernel Module Unloading - delete_module + To capture kernel module unloading events, use following line, setting ARCH to either b32 for 32-bit system, or having two lines for both b32 and b64 in case your system is 64-bit: -a always,exit -F arch=ARCH -S delete_module -F auid>=1000 -F auid!=unset -F key=modules @@ -89858,143 +165310,145 @@ to use the augenrules program (the default), add the line .rules in the directory /etc/audit/rules.d. If the auditd daemon is configured to use the auditctl utility, -add the line to file /etc/audit/audit.rules. - BP28(R73) - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 19 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - APO12.06 - APO13.01 - BAI03.05 - BAI08.02 - DSS01.03 - DSS01.04 - DSS02.02 - DSS02.04 - DSS02.07 - DSS03.01 - DSS03.05 - DSS05.02 - DSS05.03 - DSS05.04 - DSS05.05 - DSS05.07 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.1.7 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-000172 - CCI-002884 - 164.308(a)(1)(ii)(D) - 164.308(a)(3)(ii)(A) - 164.308(a)(5)(ii)(C) - 164.312(a)(2)(i) - 164.312(b) - 164.312(d) - 164.312(e) - 4.2.3.10 - 4.3.2.6.7 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.3.6.6 - 4.3.4.4.7 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 1.13 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.6 - SR 2.8 - SR 2.9 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 6.1 - SR 6.2 - SR 7.1 - SR 7.6 - A.11.2.6 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.14.2.7 - A.15.2.1 - A.15.2.2 - A.16.1.4 - A.16.1.5 - A.16.1.7 - A.6.2.1 - A.6.2.2 - AU-2(d) - AU-12(c) - AC-6(9) - CM-6(a) - DE.AE-3 - DE.AE-5 - DE.CM-1 - DE.CM-3 - DE.CM-7 - ID.SC-4 - PR.AC-3 - PR.PT-1 - PR.PT-4 - RS.AN-1 - RS.AN-4 - FAU_GEN.1.1.c - Req-10.2.7 - 10.2.1.7 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-OS-000471-GPOS-00216 - SRG-OS-000477-GPOS-00222 - The removal of kernel modules can be used to alter the behavior of +add the line to file /etc/audit/audit.rules. + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 19 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + APO10.01 + APO10.03 + APO10.04 + APO10.05 + APO11.04 + APO12.06 + APO13.01 + BAI03.05 + BAI08.02 + DSS01.03 + DSS01.04 + DSS02.02 + DSS02.04 + DSS02.07 + DSS03.01 + DSS03.05 + DSS05.02 + DSS05.03 + DSS05.04 + DSS05.05 + DSS05.07 + MEA01.01 + MEA01.02 + MEA01.03 + MEA01.04 + MEA01.05 + MEA02.01 + 3.1.7 + CCI-000172 + CCI-000130 + CCI-000135 + CCI-000169 + CCI-002884 + 164.308(a)(1)(ii)(D) + 164.308(a)(3)(ii)(A) + 164.308(a)(5)(ii)(C) + 164.312(a)(2)(i) + 164.312(b) + 164.312(d) + 164.312(e) + 4.2.3.10 + 4.3.2.6.7 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.3.6.6 + 4.3.4.4.7 + 4.3.4.5.6 + 4.3.4.5.7 + 4.3.4.5.8 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 1.13 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.6 + SR 2.8 + SR 2.9 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 6.1 + SR 6.2 + SR 7.1 + SR 7.6 + A.11.2.6 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.13.1.1 + A.13.2.1 + A.14.1.3 + A.14.2.7 + A.15.2.1 + A.15.2.2 + A.16.1.4 + A.16.1.5 + A.16.1.7 + A.6.2.1 + A.6.2.2 + AU-2(d) + AU-12(c) + AC-6(9) + CM-6(a) + DE.AE-3 + DE.AE-5 + DE.CM-1 + DE.CM-3 + DE.CM-7 + ID.SC-4 + PR.AC-3 + PR.PT-1 + PR.PT-4 + RS.AN-1 + RS.AN-4 + Req-10.2.7 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-OS-000471-GPOS-00216 + SRG-OS-000477-GPOS-00222 + SRG-APP-000495-CTR-001235 + SRG-APP-000504-CTR-001280 + R73 + OL09-00-000685 + SV-271564r1092548_rule + The removal of kernel modules can be used to alter the behavior of the kernel and potentially introduce malicious code into kernel space. It is important -to have an audit trail of modules that have been introduced into the kernel. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +to have an audit trail of modules that have been introduced into the kernel. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then # First perform the remediation of the syscall rule # Retrieve hardware architecture of the underlying system @@ -90044,7 +165498,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -90060,7 +165513,7 @@ then if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -90152,7 +165605,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -90205,7 +165658,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -90299,7 +165751,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -90327,18 +165779,18 @@ done else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-000685 - NIST-800-171-3.1.7 - NIST-800-53-AC-6(9) - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.7 - - PCI-DSSv4-10.2.1.7 - audit_rules_kernel_module_loading_delete - configure_strategy - low_complexity @@ -90351,17 +165803,17 @@ fi audit_arch: b64 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - ansible_architecture == "aarch64" or ansible_architecture == "ppc64" or ansible_architecture == "ppc64le" or ansible_architecture == "s390x" or ansible_architecture == "x86_64" tags: + - DISA-STIG-OL09-00-000685 - NIST-800-171-3.1.7 - NIST-800-53-AC-6(9) - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.7 - - PCI-DSSv4-10.2.1.7 - audit_rules_kernel_module_loading_delete - configure_strategy - low_complexity @@ -90432,6 +165884,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -90440,7 +165893,7 @@ fi line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=module-change create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -90478,6 +165931,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -90486,20 +165940,20 @@ fi line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=module-change create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-000685 - NIST-800-171-3.1.7 - NIST-800-53-AC-6(9) - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.7 - - PCI-DSSv4-10.2.1.7 - audit_rules_kernel_module_loading_delete - configure_strategy - low_complexity @@ -90570,6 +166024,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -90578,7 +166033,7 @@ fi line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=module-change create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -90616,6 +166071,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -90624,38 +166080,38 @@ fi line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=module-change create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - audit_arch == "b64" tags: + - DISA-STIG-OL09-00-000685 - NIST-800-171-3.1.7 - NIST-800-53-AC-6(9) - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.7 - - PCI-DSSv4-10.2.1.7 - audit_rules_kernel_module_loading_delete - configure_strategy - low_complexity - low_disruption - medium_severity - no_reboot_needed - - - - - - - - - - Ensure auditd Collects Information on Kernel Module Loading and Unloading - finit_module - If the auditd daemon is configured to use the augenrules program + + + + + + + + + + Ensure auditd Collects Information on Kernel Module Loading and Unloading - finit_module + If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following lines to a file with suffix .rules in the directory /etc/audit/rules.d to capture kernel module loading and unloading events, setting ARCH to either b32 or b64 as appropriate for your system: @@ -90666,143 +166122,146 @@ rules during daemon startup, add the following lines to /etc/audit/au in order to capture kernel module loading and unloading events, setting ARCH to either b32 or b64 as appropriate for your system: --a always,exit -F arch=ARCH -S finit_module -F auid>=1000 -F auid!=unset -F key=modules - BP28(R73) - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 19 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - APO12.06 - APO13.01 - BAI03.05 - BAI08.02 - DSS01.03 - DSS01.04 - DSS02.02 - DSS02.04 - DSS02.07 - DSS03.01 - DSS03.05 - DSS05.02 - DSS05.03 - DSS05.04 - DSS05.05 - DSS05.07 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.1.7 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-000172 - CCI-002884 - 164.308(a)(1)(ii)(D) - 164.308(a)(3)(ii)(A) - 164.308(a)(5)(ii)(C) - 164.312(a)(2)(i) - 164.312(b) - 164.312(d) - 164.312(e) - 4.2.3.10 - 4.3.2.6.7 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.3.6.6 - 4.3.4.4.7 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 1.13 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.6 - SR 2.8 - SR 2.9 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 6.1 - SR 6.2 - SR 7.1 - SR 7.6 - A.11.2.6 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.14.2.7 - A.15.2.1 - A.15.2.2 - A.16.1.4 - A.16.1.5 - A.16.1.7 - A.6.2.1 - A.6.2.2 - AU-2(d) - AU-12(c) - AC-6(9) - CM-6(a) - DE.AE-3 - DE.AE-5 - DE.CM-1 - DE.CM-3 - DE.CM-7 - ID.SC-4 - PR.AC-3 - PR.PT-1 - PR.PT-4 - RS.AN-1 - RS.AN-4 - FAU_GEN.1.1.c - Req-10.2.7 - 10.2.1.7 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-OS-000471-GPOS-00216 - SRG-OS-000477-GPOS-00222 - The addition/removal of kernel modules can be used to alter the behavior of +-a always,exit -F arch=ARCH -S finit_module -F auid>=1000 -F auid!=unset -F key=modules + + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 19 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + APO10.01 + APO10.03 + APO10.04 + APO10.05 + APO11.04 + APO12.06 + APO13.01 + BAI03.05 + BAI08.02 + DSS01.03 + DSS01.04 + DSS02.02 + DSS02.04 + DSS02.07 + DSS03.01 + DSS03.05 + DSS05.02 + DSS05.03 + DSS05.04 + DSS05.05 + DSS05.07 + MEA01.01 + MEA01.02 + MEA01.03 + MEA01.04 + MEA01.05 + MEA02.01 + 3.1.7 + CCI-000172 + CCI-000130 + CCI-000135 + CCI-000169 + CCI-002884 + 164.308(a)(1)(ii)(D) + 164.308(a)(3)(ii)(A) + 164.308(a)(5)(ii)(C) + 164.312(a)(2)(i) + 164.312(b) + 164.312(d) + 164.312(e) + 4.2.3.10 + 4.3.2.6.7 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.3.6.6 + 4.3.4.4.7 + 4.3.4.5.6 + 4.3.4.5.7 + 4.3.4.5.8 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 1.13 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.6 + SR 2.8 + SR 2.9 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 6.1 + SR 6.2 + SR 7.1 + SR 7.6 + A.11.2.6 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.13.1.1 + A.13.2.1 + A.14.1.3 + A.14.2.7 + A.15.2.1 + A.15.2.2 + A.16.1.4 + A.16.1.5 + A.16.1.7 + A.6.2.1 + A.6.2.2 + AU-2(d) + AU-12(c) + AC-6(9) + CM-6(a) + DE.AE-3 + DE.AE-5 + DE.CM-1 + DE.CM-3 + DE.CM-7 + ID.SC-4 + PR.AC-3 + PR.PT-1 + PR.PT-4 + RS.AN-1 + RS.AN-4 + Req-10.2.7 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-OS-000471-GPOS-00216 + SRG-OS-000477-GPOS-00222 + SRG-APP-000495-CTR-001235 + SRG-APP-000504-CTR-001280 + R73 + OL09-00-000690 + SV-271565r1092550_rule + The addition/removal of kernel modules can be used to alter the behavior of the kernel and potentially introduce malicious code into kernel space. It is important -to have an audit trail of modules that have been introduced into the kernel. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +to have an audit trail of modules that have been introduced into the kernel. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then # First perform the remediation of the syscall rule # Retrieve hardware architecture of the underlying system @@ -90852,7 +166311,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -90868,7 +166326,7 @@ then if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -90960,7 +166418,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -91013,7 +166471,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -91107,7 +166564,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -91135,18 +166592,18 @@ done else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-000690 - NIST-800-171-3.1.7 - NIST-800-53-AC-6(9) - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.7 - - PCI-DSSv4-10.2.1.7 - audit_rules_kernel_module_loading_finit - configure_strategy - low_complexity @@ -91159,17 +166616,17 @@ fi audit_arch: b64 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - ansible_architecture == "aarch64" or ansible_architecture == "ppc64" or ansible_architecture == "ppc64le" or ansible_architecture == "s390x" or ansible_architecture == "x86_64" tags: + - DISA-STIG-OL09-00-000690 - NIST-800-171-3.1.7 - NIST-800-53-AC-6(9) - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.7 - - PCI-DSSv4-10.2.1.7 - audit_rules_kernel_module_loading_finit - configure_strategy - low_complexity @@ -91242,6 +166699,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -91250,7 +166708,7 @@ fi line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=module-change create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -91290,6 +166748,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -91298,20 +166757,20 @@ fi line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=module-change create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-000690 - NIST-800-171-3.1.7 - NIST-800-53-AC-6(9) - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.7 - - PCI-DSSv4-10.2.1.7 - audit_rules_kernel_module_loading_finit - configure_strategy - low_complexity @@ -91384,6 +166843,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -91392,7 +166852,7 @@ fi line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=module-change create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -91432,6 +166892,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -91440,38 +166901,38 @@ fi line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=module-change create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - audit_arch == "b64" tags: + - DISA-STIG-OL09-00-000690 - NIST-800-171-3.1.7 - NIST-800-53-AC-6(9) - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.7 - - PCI-DSSv4-10.2.1.7 - audit_rules_kernel_module_loading_finit - configure_strategy - low_complexity - low_disruption - medium_severity - no_reboot_needed - - - - - - - - - - Ensure auditd Collects Information on Kernel Module Loading - init_module - To capture kernel module loading events, use following line, setting ARCH to + + + + + + + + + + Ensure auditd Collects Information on Kernel Module Loading - init_module + To capture kernel module loading events, use following line, setting ARCH to either b32 for 32-bit system, or having two lines for both b32 and b64 in case your system is 64-bit: -a always,exit -F arch=ARCH -S init_module -F auid>=1000 -F auid!=unset -F key=modules @@ -91482,143 +166943,145 @@ to use the augenrules program (the default), add the line .rules in the directory /etc/audit/rules.d. If the auditd daemon is configured to use the auditctl utility, -add the line to file /etc/audit/audit.rules. - BP28(R73) - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 19 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - APO12.06 - APO13.01 - BAI03.05 - BAI08.02 - DSS01.03 - DSS01.04 - DSS02.02 - DSS02.04 - DSS02.07 - DSS03.01 - DSS03.05 - DSS05.02 - DSS05.03 - DSS05.04 - DSS05.05 - DSS05.07 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.1.7 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-000172 - CCI-002884 - 164.308(a)(1)(ii)(D) - 164.308(a)(3)(ii)(A) - 164.308(a)(5)(ii)(C) - 164.312(a)(2)(i) - 164.312(b) - 164.312(d) - 164.312(e) - 4.2.3.10 - 4.3.2.6.7 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.3.6.6 - 4.3.4.4.7 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 1.13 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.6 - SR 2.8 - SR 2.9 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 6.1 - SR 6.2 - SR 7.1 - SR 7.6 - A.11.2.6 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.14.2.7 - A.15.2.1 - A.15.2.2 - A.16.1.4 - A.16.1.5 - A.16.1.7 - A.6.2.1 - A.6.2.2 - AU-2(d) - AU-12(c) - AC-6(9) - CM-6(a) - DE.AE-3 - DE.AE-5 - DE.CM-1 - DE.CM-3 - DE.CM-7 - ID.SC-4 - PR.AC-3 - PR.PT-1 - PR.PT-4 - RS.AN-1 - RS.AN-4 - FAU_GEN.1.1.c - Req-10.2.7 - 10.2.1.7 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-OS-000471-GPOS-00216 - SRG-OS-000477-GPOS-00222 - The addition of kernel modules can be used to alter the behavior of +add the line to file /etc/audit/audit.rules. + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 19 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + APO10.01 + APO10.03 + APO10.04 + APO10.05 + APO11.04 + APO12.06 + APO13.01 + BAI03.05 + BAI08.02 + DSS01.03 + DSS01.04 + DSS02.02 + DSS02.04 + DSS02.07 + DSS03.01 + DSS03.05 + DSS05.02 + DSS05.03 + DSS05.04 + DSS05.05 + DSS05.07 + MEA01.01 + MEA01.02 + MEA01.03 + MEA01.04 + MEA01.05 + MEA02.01 + 3.1.7 + CCI-000172 + CCI-000130 + CCI-000135 + CCI-000169 + CCI-002884 + 164.308(a)(1)(ii)(D) + 164.308(a)(3)(ii)(A) + 164.308(a)(5)(ii)(C) + 164.312(a)(2)(i) + 164.312(b) + 164.312(d) + 164.312(e) + 4.2.3.10 + 4.3.2.6.7 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.3.6.6 + 4.3.4.4.7 + 4.3.4.5.6 + 4.3.4.5.7 + 4.3.4.5.8 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 1.13 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.6 + SR 2.8 + SR 2.9 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 6.1 + SR 6.2 + SR 7.1 + SR 7.6 + A.11.2.6 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.13.1.1 + A.13.2.1 + A.14.1.3 + A.14.2.7 + A.15.2.1 + A.15.2.2 + A.16.1.4 + A.16.1.5 + A.16.1.7 + A.6.2.1 + A.6.2.2 + AU-2(d) + AU-12(c) + AC-6(9) + CM-6(a) + DE.AE-3 + DE.AE-5 + DE.CM-1 + DE.CM-3 + DE.CM-7 + ID.SC-4 + PR.AC-3 + PR.PT-1 + PR.PT-4 + RS.AN-1 + RS.AN-4 + Req-10.2.7 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-OS-000471-GPOS-00216 + SRG-OS-000477-GPOS-00222 + SRG-APP-000495-CTR-001235 + SRG-APP-000504-CTR-001280 + R73 + OL09-00-000690 + SV-271565r1092550_rule + The addition of kernel modules can be used to alter the behavior of the kernel and potentially introduce malicious code into kernel space. It is important -to have an audit trail of modules that have been introduced into the kernel. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +to have an audit trail of modules that have been introduced into the kernel. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then # First perform the remediation of the syscall rule # Retrieve hardware architecture of the underlying system @@ -91668,7 +167131,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -91684,7 +167146,7 @@ then if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -91776,7 +167238,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -91829,7 +167291,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -91923,7 +167384,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -91951,18 +167412,18 @@ done else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-000690 - NIST-800-171-3.1.7 - NIST-800-53-AC-6(9) - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.7 - - PCI-DSSv4-10.2.1.7 - audit_rules_kernel_module_loading_init - configure_strategy - low_complexity @@ -91975,17 +167436,17 @@ fi audit_arch: b64 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - ansible_architecture == "aarch64" or ansible_architecture == "ppc64" or ansible_architecture == "ppc64le" or ansible_architecture == "s390x" or ansible_architecture == "x86_64" tags: + - DISA-STIG-OL09-00-000690 - NIST-800-171-3.1.7 - NIST-800-53-AC-6(9) - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.7 - - PCI-DSSv4-10.2.1.7 - audit_rules_kernel_module_loading_init - configure_strategy - low_complexity @@ -92058,6 +167519,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -92066,7 +167528,7 @@ fi line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=module-change create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -92106,6 +167568,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -92114,20 +167577,20 @@ fi line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=module-change create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-000690 - NIST-800-171-3.1.7 - NIST-800-53-AC-6(9) - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.7 - - PCI-DSSv4-10.2.1.7 - audit_rules_kernel_module_loading_init - configure_strategy - low_complexity @@ -92200,6 +167663,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -92208,7 +167672,7 @@ fi line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=module-change create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -92248,6 +167712,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -92256,195 +167721,200 @@ fi line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=module-change create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - audit_arch == "b64" tags: + - DISA-STIG-OL09-00-000690 - NIST-800-171-3.1.7 - NIST-800-53-AC-6(9) - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.7 - - PCI-DSSv4-10.2.1.7 - audit_rules_kernel_module_loading_init - configure_strategy - low_complexity - low_disruption - medium_severity - no_reboot_needed - - - - - - - - - - - Record Attempts to Alter Logon and Logout Events - The audit system already collects login information for all users + + + + + + + + + + + Record Attempts to Alter Logon and Logout Events + The audit system already collects login information for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following lines to a file with suffix .rules in the directory /etc/audit/rules.d in order to watch for attempted manual edits of files involved in storing logon events: -w /var/log/tallylog -p wa -k logins --w /var/log/faillock -p wa -k logins +-w -p wa -k logins -w /var/log/lastlog -p wa -k logins If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following lines to /etc/audit/audit.rules file in order to watch for unattempted manual edits of files involved in storing logon events: -w /var/log/tallylog -p wa -k logins --w /var/log/faillock -p wa -k logins --w /var/log/lastlog -p wa -k logins - - Record Attempts to Alter Logon and Logout Events - The audit system already collects login information for all users +-w -p wa -k logins +-w /var/log/lastlog -p wa -k logins + + + Record Attempts to Alter Logon and Logout Events + The audit system already collects login information for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following lines to a file with suffix .rules in the directory /etc/audit/rules.d in order to watch for attempted manual edits of files involved in storing logon events: -w /var/log/tallylog -p wa -k logins --w /var/log/faillock -p wa -k logins +-w -p wa -k logins -w /var/log/lastlog -p wa -k logins If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following lines to /etc/audit/audit.rules file in order to watch for unattempted manual edits of files involved in storing logon events: -w /var/log/tallylog -p wa -k logins --w /var/log/faillock -p wa -k logins --w /var/log/lastlog -p wa -k logins - This rule checks for multiple syscalls related to login events; +-w -p wa -k logins +-w /var/log/lastlog -p wa -k logins + + This rule checks for multiple syscalls related to login events; it was written with DISA STIG in mind. Other policies should use a separate rule for each syscall that needs to be checked. For example: -audit_rules_login_events_tallylogaudit_rules_login_events_faillockaudit_rules_login_events_lastlog - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 19 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 5.4.1.1 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - APO12.06 - APO13.01 - BAI03.05 - BAI08.02 - DSS01.03 - DSS01.04 - DSS02.02 - DSS02.04 - DSS02.07 - DSS03.01 - DSS03.05 - DSS05.02 - DSS05.03 - DSS05.04 - DSS05.05 - DSS05.07 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.1.7 - CCI-000172 - CCI-002884 - 4.2.3.10 - 4.3.2.6.7 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.3.6.6 - 4.3.4.4.7 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 1.13 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.6 - SR 2.8 - SR 2.9 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 6.1 - SR 6.2 - SR 7.1 - SR 7.6 - A.11.2.6 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.14.2.7 - A.15.2.1 - A.15.2.2 - A.16.1.4 - A.16.1.5 - A.16.1.7 - A.6.2.1 - A.6.2.2 - AU-2(d) - AU-12(c) - AC-6(9) - CM-6(a) - DE.AE-3 - DE.AE-5 - DE.CM-1 - DE.CM-3 - DE.CM-7 - ID.SC-4 - PR.AC-3 - PR.PT-1 - PR.PT-4 - RS.AN-1 - RS.AN-4 - Req-10.2.3 - 10.2.1.3 - Manual editing of these files may indicate nefarious activity, such -as an attacker attempting to remove evidence of an intrusion. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +audit_rules_login_events_tallylogaudit_rules_login_events_faillockaudit_rules_login_events_lastlog + + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 19 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 5.4.1.1 + APO10.01 + APO10.03 + APO10.04 + APO10.05 + APO11.04 + APO12.06 + APO13.01 + BAI03.05 + BAI08.02 + DSS01.03 + DSS01.04 + DSS02.02 + DSS02.04 + DSS02.07 + DSS03.01 + DSS03.05 + DSS05.02 + DSS05.03 + DSS05.04 + DSS05.05 + DSS05.07 + MEA01.01 + MEA01.02 + MEA01.03 + MEA01.04 + MEA01.05 + MEA02.01 + 3.1.7 + CCI-000172 + CCI-002884 + 4.2.3.10 + 4.3.2.6.7 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.3.6.6 + 4.3.4.4.7 + 4.3.4.5.6 + 4.3.4.5.7 + 4.3.4.5.8 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 1.13 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.6 + SR 2.8 + SR 2.9 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 6.1 + SR 6.2 + SR 7.1 + SR 7.6 + A.11.2.6 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.13.1.1 + A.13.2.1 + A.14.1.3 + A.14.2.7 + A.15.2.1 + A.15.2.2 + A.16.1.4 + A.16.1.5 + A.16.1.7 + A.6.2.1 + A.6.2.2 + AU-2(d) + AU-12(c) + AC-6(9) + CM-6(a) + DE.AE-3 + DE.AE-5 + DE.CM-1 + DE.CM-3 + DE.CM-7 + ID.SC-4 + PR.AC-3 + PR.PT-1 + PR.PT-4 + RS.AN-1 + RS.AN-4 + Req-10.2.3 + Manual editing of these files may indicate nefarious activity, such +as an attacker attempting to remove evidence of an intrusion. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' +var_accounts_passwords_pam_faillock_dir='' + + # Create a list of audit *.rules files that should be inspected for presence and correctness # of a particular audit rule. The scheme is as follows: # @@ -92535,7 +168005,7 @@ then if [ ! -e "$key_rule_file" ] then touch "$key_rule_file" - chmod 0640 "$key_rule_file" + chmod 0600 "$key_rule_file" fi files_to_inspect+=("$key_rule_file") fi @@ -92601,7 +168071,7 @@ files_to_inspect+=('/etc/audit/audit.rules') for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present - if grep -q -P -- "^[\s]*-w[\s]+/var/log/faillock" "$audit_rules_file" + if grep -q -P -- "^[\s]*-w[\s]+${var_accounts_passwords_pam_faillock_dir}" "$audit_rules_file" then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -92609,7 +168079,7 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule - current_access_bits=$(sed -ne "s#$sp*-w$sp\+/var/log/faillock $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + current_access_bits=$(sed -ne "s#$sp*-w$sp\+${var_accounts_passwords_pam_faillock_dir} $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -92625,12 +168095,12 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule - sed -i "s#\($sp*-w$sp\+/var/log/faillock$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + sed -i "s#\($sp*-w$sp\+${var_accounts_passwords_pam_faillock_dir}$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key - echo "-w /var/log/faillock -p wa -k logins" >> "$audit_rules_file" + echo "-w ${var_accounts_passwords_pam_faillock_dir} -p wa -k logins" >> "$audit_rules_file" fi done # Create a list of audit *.rules files that should be inspected for presence and correctness @@ -92649,7 +168119,7 @@ files_to_inspect=() # If the audit is 'augenrules', then check if rule is already defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection. # If rule isn't defined, add '/etc/audit/rules.d/logins.rules' to list of files for inspection. -readarray -t matches < <(grep -HP "[\s]*-w[\s]+/var/log/faillock" /etc/audit/rules.d/*.rules) +readarray -t matches < <(grep -HP "[\s]*-w[\s]+${var_accounts_passwords_pam_faillock_dir}" /etc/audit/rules.d/*.rules) # For each of the matched entries for match in "${matches[@]}" @@ -92668,7 +168138,7 @@ then if [ ! -e "$key_rule_file" ] then touch "$key_rule_file" - chmod 0640 "$key_rule_file" + chmod 0600 "$key_rule_file" fi files_to_inspect+=("$key_rule_file") fi @@ -92678,7 +168148,7 @@ fi for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present - if grep -q -P -- "^[\s]*-w[\s]+/var/log/faillock" "$audit_rules_file" + if grep -q -P -- "^[\s]*-w[\s]+${var_accounts_passwords_pam_faillock_dir}" "$audit_rules_file" then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -92686,7 +168156,7 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule - current_access_bits=$(sed -ne "s#$sp*-w$sp\+/var/log/faillock $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + current_access_bits=$(sed -ne "s#$sp*-w$sp\+${var_accounts_passwords_pam_faillock_dir} $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -92702,12 +168172,12 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule - sed -i "s#\($sp*-w$sp\+/var/log/faillock$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + sed -i "s#\($sp*-w$sp\+${var_accounts_passwords_pam_faillock_dir}$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key - echo "-w /var/log/faillock -p wa -k logins" >> "$audit_rules_file" + echo "-w ${var_accounts_passwords_pam_faillock_dir} -p wa -k logins" >> "$audit_rules_file" fi done @@ -92801,7 +168271,7 @@ then if [ ! -e "$key_rule_file" ] then touch "$key_rule_file" - chmod 0640 "$key_rule_file" + chmod 0600 "$key_rule_file" fi files_to_inspect+=("$key_rule_file") fi @@ -92847,156 +168317,166 @@ done else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - - - - - Record Attempts to Alter Logon and Logout Events - faillock - The audit system already collects login information for all users + + + + + + + + Record Attempts to Alter Logon and Logout Events - faillock + The audit system already collects login information for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following lines to a file with suffix .rules in the directory /etc/audit/rules.d in order to watch for attempted manual edits of files involved in storing logon events: --w /var/log/faillock -p wa -k logins +-w -p wa -k logins If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following lines to /etc/audit/audit.rules file in order to watch for unattempted manual edits of files involved in storing logon events: --w /var/log/faillock -p wa -k logins - BP28(R73) - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 19 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - APO12.06 - APO13.01 - BAI03.05 - BAI08.02 - DSS01.03 - DSS01.04 - DSS02.02 - DSS02.04 - DSS02.07 - DSS03.01 - DSS03.05 - DSS05.02 - DSS05.03 - DSS05.04 - DSS05.05 - DSS05.07 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.1.7 - CCI-000126 - CCI-000172 - CCI-002884 - 164.308(a)(1)(ii)(D) - 164.308(a)(3)(ii)(A) - 164.308(a)(5)(ii)(C) - 164.312(a)(2)(i) - 164.312(b) - 164.312(d) - 164.312(e) - 4.2.3.10 - 4.3.2.6.7 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.3.6.6 - 4.3.4.4.7 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 1.13 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.6 - SR 2.8 - SR 2.9 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 6.1 - SR 6.2 - SR 7.1 - SR 7.6 - A.11.2.6 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.14.2.7 - A.15.2.1 - A.15.2.2 - A.16.1.4 - A.16.1.5 - A.16.1.7 - A.6.2.1 - A.6.2.2 - AU-2(d) - AU-12(c) - AC-6(9) - CM-6(a) - DE.AE-3 - DE.AE-5 - DE.CM-1 - DE.CM-3 - DE.CM-7 - ID.SC-4 - PR.AC-3 - PR.PT-1 - PR.PT-4 - RS.AN-1 - RS.AN-4 - FAU_GEN.1.1.c - Req-10.2.3 - 10.2.1.3 - SRG-OS-000392-GPOS-00172 - SRG-OS-000470-GPOS-00214 - SRG-OS-000473-GPOS-00218 - Manual editing of these files may indicate nefarious activity, such -as an attacker attempting to remove evidence of an intrusion. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +-w -p wa -k logins + + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 19 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + APO10.01 + APO10.03 + APO10.04 + APO10.05 + APO11.04 + APO12.06 + APO13.01 + BAI03.05 + BAI08.02 + DSS01.03 + DSS01.04 + DSS02.02 + DSS02.04 + DSS02.07 + DSS03.01 + DSS03.05 + DSS05.02 + DSS05.03 + DSS05.04 + DSS05.05 + DSS05.07 + MEA01.01 + MEA01.02 + MEA01.03 + MEA01.04 + MEA01.05 + MEA02.01 + 3.1.7 + CCI-000172 + CCI-002884 + 164.308(a)(1)(ii)(D) + 164.308(a)(3)(ii)(A) + 164.308(a)(5)(ii)(C) + 164.312(a)(2)(i) + 164.312(b) + 164.312(d) + 164.312(e) + 4.2.3.10 + 4.3.2.6.7 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.3.6.6 + 4.3.4.4.7 + 4.3.4.5.6 + 4.3.4.5.7 + 4.3.4.5.8 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 1.13 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.6 + SR 2.8 + SR 2.9 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 6.1 + SR 6.2 + SR 7.1 + SR 7.6 + A.11.2.6 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.13.1.1 + A.13.2.1 + A.14.1.3 + A.14.2.7 + A.15.2.1 + A.15.2.2 + A.16.1.4 + A.16.1.5 + A.16.1.7 + A.6.2.1 + A.6.2.2 + AU-2(d) + AU-12(c) + AC-6(9) + CM-6(a) + DE.AE-3 + DE.AE-5 + DE.CM-1 + DE.CM-3 + DE.CM-7 + ID.SC-4 + PR.AC-3 + PR.PT-1 + PR.PT-4 + RS.AN-1 + RS.AN-4 + Req-10.2.3 + SRG-OS-000392-GPOS-00172 + SRG-OS-000470-GPOS-00214 + SRG-OS-000473-GPOS-00218 + SRG-APP-000503-CTR-001275 + SRG-APP-000506-CTR-001290 + R73 + A.3.SEC-OL1 + 10.2.1.3 + 10.2.1 + 10.2 + OL09-00-000720 + SV-271571r1092560_rule + Manual editing of these files may indicate nefarious activity, such +as an attacker attempting to remove evidence of an intrusion. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' + +var_accounts_passwords_pam_faillock_dir='' + # Create a list of audit *.rules files that should be inspected for presence and correctness # of a particular audit rule. The scheme is as follows: # @@ -93020,7 +168500,7 @@ files_to_inspect+=('/etc/audit/audit.rules') for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present - if grep -q -P -- "^[\s]*-w[\s]+/var/log/faillock" "$audit_rules_file" + if grep -q -P -- "^[\s]*-w[\s]+${var_accounts_passwords_pam_faillock_dir}" "$audit_rules_file" then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -93028,7 +168508,7 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule - current_access_bits=$(sed -ne "s#$sp*-w$sp\+/var/log/faillock $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + current_access_bits=$(sed -ne "s#$sp*-w$sp\+${var_accounts_passwords_pam_faillock_dir} $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -93044,12 +168524,12 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule - sed -i "s#\($sp*-w$sp\+/var/log/faillock$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + sed -i "s#\($sp*-w$sp\+${var_accounts_passwords_pam_faillock_dir}$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key - echo "-w /var/log/faillock -p wa -k logins" >> "$audit_rules_file" + echo "-w ${var_accounts_passwords_pam_faillock_dir} -p wa -k logins" >> "$audit_rules_file" fi done # Create a list of audit *.rules files that should be inspected for presence and correctness @@ -93068,7 +168548,7 @@ files_to_inspect=() # If the audit is 'augenrules', then check if rule is already defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection. # If rule isn't defined, add '/etc/audit/rules.d/logins.rules' to list of files for inspection. -readarray -t matches < <(grep -HP "[\s]*-w[\s]+/var/log/faillock" /etc/audit/rules.d/*.rules) +readarray -t matches < <(grep -HP "[\s]*-w[\s]+${var_accounts_passwords_pam_faillock_dir}" /etc/audit/rules.d/*.rules) # For each of the matched entries for match in "${matches[@]}" @@ -93087,7 +168567,7 @@ then if [ ! -e "$key_rule_file" ] then touch "$key_rule_file" - chmod 0640 "$key_rule_file" + chmod 0600 "$key_rule_file" fi files_to_inspect+=("$key_rule_file") fi @@ -93097,7 +168577,7 @@ fi for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present - if grep -q -P -- "^[\s]*-w[\s]+/var/log/faillock" "$audit_rules_file" + if grep -q -P -- "^[\s]*-w[\s]+${var_accounts_passwords_pam_faillock_dir}" "$audit_rules_file" then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -93105,7 +168585,7 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule - current_access_bits=$(sed -ne "s#$sp*-w$sp\+/var/log/faillock $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + current_access_bits=$(sed -ne "s#$sp*-w$sp\+${var_accounts_passwords_pam_faillock_dir} $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -93121,29 +168601,32 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule - sed -i "s#\($sp*-w$sp\+/var/log/faillock$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + sed -i "s#\($sp*-w$sp\+${var_accounts_passwords_pam_faillock_dir}$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key - echo "-w /var/log/faillock -p wa -k logins" >> "$audit_rules_file" + echo "-w ${var_accounts_passwords_pam_faillock_dir} -p wa -k logins" >> "$audit_rules_file" fi done else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-000720 - NIST-800-171-3.1.7 - NIST-800-53-AC-6(9) - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.3 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.3 - audit_rules_login_events_faillock - low_complexity @@ -93151,23 +168634,32 @@ fi - medium_severity - reboot_required - restrict_strategy +- name: XCCDF Value var_accounts_passwords_pam_faillock_dir # promote to variable + set_fact: + var_accounts_passwords_pam_faillock_dir: !!str + tags: + - always -- name: Check if watch rule for /var/log/faillock already exists in /etc/audit/rules.d/ +- name: Check if watch rule for {{ var_accounts_passwords_pam_faillock_dir }} already + exists in /etc/audit/rules.d/ find: paths: /etc/audit/rules.d - contains: ^\s*-w\s+/var/log/faillock\s+-p\s+wa(\s|$)+ + contains: ^\s*-w\s+{{ var_accounts_passwords_pam_faillock_dir }}\s+-p\s+wa(\s|$)+ patterns: '*.rules' register: find_existing_watch_rules_d when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-000720 - NIST-800-171-3.1.7 - NIST-800-53-AC-6(9) - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.3 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.3 - audit_rules_login_events_faillock - low_complexity @@ -93184,16 +168676,19 @@ fi register: find_watch_key when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: + - DISA-STIG-OL09-00-000720 - NIST-800-171-3.1.7 - NIST-800-53-AC-6(9) - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.3 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.3 - audit_rules_login_events_faillock - low_complexity @@ -93208,16 +168703,19 @@ fi - /etc/audit/rules.d/logins.rules when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_watch_key.matched is defined and find_watch_key.matched == 0 and find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: + - DISA-STIG-OL09-00-000720 - NIST-800-171-3.1.7 - NIST-800-53-AC-6(9) - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.3 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.3 - audit_rules_login_events_faillock - low_complexity @@ -93232,16 +168730,19 @@ fi - '{{ find_watch_key.files | map(attribute=''path'') | list | first }}' when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_watch_key.matched is defined and find_watch_key.matched > 0 and find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: + - DISA-STIG-OL09-00-000720 - NIST-800-171-3.1.7 - NIST-800-53-AC-6(9) - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.3 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.3 - audit_rules_login_events_faillock - low_complexity @@ -93250,24 +168751,27 @@ fi - reboot_required - restrict_strategy -- name: Add watch rule for /var/log/faillock in /etc/audit/rules.d/ +- name: Add watch rule for {{ var_accounts_passwords_pam_faillock_dir }} in /etc/audit/rules.d/ lineinfile: path: '{{ all_files[0] }}' - line: -w /var/log/faillock -p wa -k logins + line: -w {{ var_accounts_passwords_pam_faillock_dir }} -p wa -k logins create: true - mode: '0640' + mode: '0600' when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: + - DISA-STIG-OL09-00-000720 - NIST-800-171-3.1.7 - NIST-800-53-AC-6(9) - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.3 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.3 - audit_rules_login_events_faillock - low_complexity @@ -93276,22 +168780,26 @@ fi - reboot_required - restrict_strategy -- name: Check if watch rule for /var/log/faillock already exists in /etc/audit/audit.rules +- name: Check if watch rule for {{ var_accounts_passwords_pam_faillock_dir }} already + exists in /etc/audit/audit.rules find: paths: /etc/audit/ - contains: ^\s*-w\s+/var/log/faillock\s+-p\s+wa(\s|$)+ + contains: ^\s*-w\s+{{ var_accounts_passwords_pam_faillock_dir }}\s+-p\s+wa(\s|$)+ patterns: audit.rules register: find_existing_watch_audit_rules when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-000720 - NIST-800-171-3.1.7 - NIST-800-53-AC-6(9) - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.3 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.3 - audit_rules_login_events_faillock - low_complexity @@ -93300,25 +168808,28 @@ fi - reboot_required - restrict_strategy -- name: Add watch rule for /var/log/faillock in /etc/audit/audit.rules +- name: Add watch rule for {{ var_accounts_passwords_pam_faillock_dir }} in /etc/audit/audit.rules lineinfile: - line: -w /var/log/faillock -p wa -k logins + line: -w {{ var_accounts_passwords_pam_faillock_dir }} -p wa -k logins state: present dest: /etc/audit/audit.rules create: true - mode: '0640' + mode: '0600' when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_existing_watch_audit_rules.matched is defined and find_existing_watch_audit_rules.matched == 0 tags: + - DISA-STIG-OL09-00-000720 - NIST-800-171-3.1.7 - NIST-800-53-AC-6(9) - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.3 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.3 - audit_rules_login_events_faillock - low_complexity @@ -93326,17 +168837,18 @@ fi - medium_severity - reboot_required - restrict_strategy - - - - - - - - - - Record Attempts to Alter Logon and Logout Events - lastlog - The audit system already collects login information for all users + + + + + + + + + + + Record Attempts to Alter Logon and Logout Events - lastlog + The audit system already collects login information for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following lines to a file with suffix .rules in the @@ -93347,146 +168859,154 @@ If the auditd daemon is configured to use the utility to read audit rules during daemon startup, add the following lines to /etc/audit/audit.rules file in order to watch for unattempted manual edits of files involved in storing logon events: --w /var/log/lastlog -p wa -k logins - BP28(R73) - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 19 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - APO12.06 - APO13.01 - BAI03.05 - BAI08.02 - DSS01.03 - DSS01.04 - DSS02.02 - DSS02.04 - DSS02.07 - DSS03.01 - DSS03.05 - DSS05.02 - DSS05.03 - DSS05.04 - DSS05.05 - DSS05.07 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.1.7 - CCI-000126 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-000172 - CCI-002884 - 164.308(a)(1)(ii)(D) - 164.308(a)(3)(ii)(A) - 164.308(a)(5)(ii)(C) - 164.312(a)(2)(i) - 164.312(b) - 164.312(d) - 164.312(e) - 4.2.3.10 - 4.3.2.6.7 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.3.6.6 - 4.3.4.4.7 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 1.13 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.6 - SR 2.8 - SR 2.9 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 6.1 - SR 6.2 - SR 7.1 - SR 7.6 - A.11.2.6 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.14.2.7 - A.15.2.1 - A.15.2.2 - A.16.1.4 - A.16.1.5 - A.16.1.7 - A.6.2.1 - A.6.2.2 - AU-2(d) - AU-12(c) - AC-6(9) - CM-6(a) - DE.AE-3 - DE.AE-5 - DE.CM-1 - DE.CM-3 - DE.CM-7 - ID.SC-4 - PR.AC-3 - PR.PT-1 - PR.PT-4 - RS.AN-1 - RS.AN-4 - FAU_GEN.1.1.c - Req-10.2.3 - 10.2.1.3 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-OS-000473-GPOS-00218 - SRG-OS-000470-GPOS-00214 - Manual editing of these files may indicate nefarious activity, such -as an attacker attempting to remove evidence of an intrusion. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +-w /var/log/lastlog -p wa -k logins + + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 19 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + APO10.01 + APO10.03 + APO10.04 + APO10.05 + APO11.04 + APO12.06 + APO13.01 + BAI03.05 + BAI08.02 + DSS01.03 + DSS01.04 + DSS02.02 + DSS02.04 + DSS02.07 + DSS03.01 + DSS03.05 + DSS05.02 + DSS05.03 + DSS05.04 + DSS05.05 + DSS05.07 + MEA01.01 + MEA01.02 + MEA01.03 + MEA01.04 + MEA01.05 + MEA02.01 + 3.1.7 + CCI-000172 + CCI-000130 + CCI-000135 + CCI-000169 + CCI-002884 + 164.308(a)(1)(ii)(D) + 164.308(a)(3)(ii)(A) + 164.308(a)(5)(ii)(C) + 164.312(a)(2)(i) + 164.312(b) + 164.312(d) + 164.312(e) + 4.2.3.10 + 4.3.2.6.7 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.3.6.6 + 4.3.4.4.7 + 4.3.4.5.6 + 4.3.4.5.7 + 4.3.4.5.8 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 1.13 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.6 + SR 2.8 + SR 2.9 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 6.1 + SR 6.2 + SR 7.1 + SR 7.6 + A.11.2.6 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.13.1.1 + A.13.2.1 + A.14.1.3 + A.14.2.7 + A.15.2.1 + A.15.2.2 + A.16.1.4 + A.16.1.5 + A.16.1.7 + A.6.2.1 + A.6.2.2 + AU-2(d) + AU-12(c) + AC-6(9) + CM-6(a) + DE.AE-3 + DE.AE-5 + DE.CM-1 + DE.CM-3 + DE.CM-7 + ID.SC-4 + PR.AC-3 + PR.PT-1 + PR.PT-4 + RS.AN-1 + RS.AN-4 + Req-10.2.3 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-OS-000473-GPOS-00218 + SRG-OS-000470-GPOS-00214 + SRG-APP-000495-CTR-001235 + SRG-APP-000503-CTR-001275 + SRG-APP-000506-CTR-001290 + R73 + A.3.SEC-OL1 + 10.2.1.3 + 10.2.1 + 10.2 + OL09-00-000700 + SV-271567r1092554_rule + Manual editing of these files may indicate nefarious activity, such +as an attacker attempting to remove evidence of an intrusion. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' + # Create a list of audit *.rules files that should be inspected for presence and correctness # of a particular audit rule. The scheme is as follows: # @@ -93577,7 +169097,7 @@ then if [ ! -e "$key_rule_file" ] then touch "$key_rule_file" - chmod 0640 "$key_rule_file" + chmod 0600 "$key_rule_file" fi files_to_inspect+=("$key_rule_file") fi @@ -93623,17 +169143,20 @@ done else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-000700 - NIST-800-171-3.1.7 - NIST-800-53-AC-6(9) - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.3 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.3 - audit_rules_login_events_lastlog - low_complexity @@ -93650,14 +169173,17 @@ fi register: find_existing_watch_rules_d when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-000700 - NIST-800-171-3.1.7 - NIST-800-53-AC-6(9) - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.3 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.3 - audit_rules_login_events_lastlog - low_complexity @@ -93674,16 +169200,19 @@ fi register: find_watch_key when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: + - DISA-STIG-OL09-00-000700 - NIST-800-171-3.1.7 - NIST-800-53-AC-6(9) - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.3 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.3 - audit_rules_login_events_lastlog - low_complexity @@ -93698,16 +169227,19 @@ fi - /etc/audit/rules.d/logins.rules when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_watch_key.matched is defined and find_watch_key.matched == 0 and find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: + - DISA-STIG-OL09-00-000700 - NIST-800-171-3.1.7 - NIST-800-53-AC-6(9) - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.3 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.3 - audit_rules_login_events_lastlog - low_complexity @@ -93722,16 +169254,19 @@ fi - '{{ find_watch_key.files | map(attribute=''path'') | list | first }}' when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_watch_key.matched is defined and find_watch_key.matched > 0 and find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: + - DISA-STIG-OL09-00-000700 - NIST-800-171-3.1.7 - NIST-800-53-AC-6(9) - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.3 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.3 - audit_rules_login_events_lastlog - low_complexity @@ -93745,19 +169280,22 @@ fi path: '{{ all_files[0] }}' line: -w /var/log/lastlog -p wa -k logins create: true - mode: '0640' + mode: '0600' when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: + - DISA-STIG-OL09-00-000700 - NIST-800-171-3.1.7 - NIST-800-53-AC-6(9) - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.3 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.3 - audit_rules_login_events_lastlog - low_complexity @@ -93774,14 +169312,17 @@ fi register: find_existing_watch_audit_rules when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-000700 - NIST-800-171-3.1.7 - NIST-800-53-AC-6(9) - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.3 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.3 - audit_rules_login_events_lastlog - low_complexity @@ -93796,19 +169337,22 @@ fi state: present dest: /etc/audit/audit.rules create: true - mode: '0640' + mode: '0600' when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_existing_watch_audit_rules.matched is defined and find_existing_watch_audit_rules.matched == 0 tags: + - DISA-STIG-OL09-00-000700 - NIST-800-171-3.1.7 - NIST-800-53-AC-6(9) - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.3 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.3 - audit_rules_login_events_lastlog - low_complexity @@ -93816,17 +169360,17 @@ fi - medium_severity - reboot_required - restrict_strategy - - - - - - - - - - Record Attempts to Alter Logon and Logout Events - tallylog - The audit system already collects login information for all users + + + + + + + + + + Record Attempts to Alter Logon and Logout Events - tallylog + The audit system already collects login information for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following lines to a file with suffix .rules in the @@ -93837,137 +169381,142 @@ If the auditd daemon is configured to use the utility to read audit rules during daemon startup, add the following lines to /etc/audit/audit.rules file in order to watch for unattempted manual edits of files involved in storing logon events: --w /var/log/tallylog -p wa -k logins - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 19 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - APO12.06 - APO13.01 - BAI03.05 - BAI08.02 - DSS01.03 - DSS01.04 - DSS02.02 - DSS02.04 - DSS02.07 - DSS03.01 - DSS03.05 - DSS05.02 - DSS05.03 - DSS05.04 - DSS05.05 - DSS05.07 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.1.7 - CCI-000172 - CCI-002884 - CCI-000126 - 164.308(a)(1)(ii)(D) - 164.308(a)(3)(ii)(A) - 164.308(a)(5)(ii)(C) - 164.312(a)(2)(i) - 164.312(b) - 164.312(d) - 164.312(e) - 4.2.3.10 - 4.3.2.6.7 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.3.6.6 - 4.3.4.4.7 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 1.13 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.6 - SR 2.8 - SR 2.9 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 6.1 - SR 6.2 - SR 7.1 - SR 7.6 - A.11.2.6 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.14.2.7 - A.15.2.1 - A.15.2.2 - A.16.1.4 - A.16.1.5 - A.16.1.7 - A.6.2.1 - A.6.2.2 - AU-2(d) - AU-12(c) - AC-6(9) - CM-6(a) - DE.AE-3 - DE.AE-5 - DE.CM-1 - DE.CM-3 - DE.CM-7 - ID.SC-4 - PR.AC-3 - PR.PT-1 - PR.PT-4 - RS.AN-1 - RS.AN-4 - FAU_GEN.1.1.c - Req-10.2.3 - 10.2.1.3 - SRG-OS-000392-GPOS-00172 - SRG-OS-000470-GPOS-00214 - SRG-OS-000473-GPOS-00218 - Manual editing of these files may indicate nefarious activity, such -as an attacker attempting to remove evidence of an intrusion. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +-w /var/log/tallylog -p wa -k logins + + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 19 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + APO10.01 + APO10.03 + APO10.04 + APO10.05 + APO11.04 + APO12.06 + APO13.01 + BAI03.05 + BAI08.02 + DSS01.03 + DSS01.04 + DSS02.02 + DSS02.04 + DSS02.07 + DSS03.01 + DSS03.05 + DSS05.02 + DSS05.03 + DSS05.04 + DSS05.05 + DSS05.07 + MEA01.01 + MEA01.02 + MEA01.03 + MEA01.04 + MEA01.05 + MEA02.01 + 3.1.7 + CCI-000172 + CCI-002884 + 164.308(a)(1)(ii)(D) + 164.308(a)(3)(ii)(A) + 164.308(a)(5)(ii)(C) + 164.312(a)(2)(i) + 164.312(b) + 164.312(d) + 164.312(e) + 4.2.3.10 + 4.3.2.6.7 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.3.6.6 + 4.3.4.4.7 + 4.3.4.5.6 + 4.3.4.5.7 + 4.3.4.5.8 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 1.13 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.6 + SR 2.8 + SR 2.9 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 6.1 + SR 6.2 + SR 7.1 + SR 7.6 + A.11.2.6 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.13.1.1 + A.13.2.1 + A.14.1.3 + A.14.2.7 + A.15.2.1 + A.15.2.2 + A.16.1.4 + A.16.1.5 + A.16.1.7 + A.6.2.1 + A.6.2.2 + AU-2(d) + AU-12(c) + AC-6(9) + CM-6(a) + DE.AE-3 + DE.AE-5 + DE.CM-1 + DE.CM-3 + DE.CM-7 + ID.SC-4 + PR.AC-3 + PR.PT-1 + PR.PT-4 + RS.AN-1 + RS.AN-4 + Req-10.2.3 + SRG-OS-000392-GPOS-00172 + SRG-OS-000470-GPOS-00214 + SRG-OS-000473-GPOS-00218 + SRG-APP-000503-CTR-001275 + 10.2.1.3 + 10.2.1 + 10.2 + OL09-00-000725 + SV-271572r1092562_rule + Manual editing of these files may indicate nefarious activity, such +as an attacker attempting to remove evidence of an intrusion. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' + # Create a list of audit *.rules files that should be inspected for presence and correctness # of a particular audit rule. The scheme is as follows: # @@ -94058,7 +169607,7 @@ then if [ ! -e "$key_rule_file" ] then touch "$key_rule_file" - chmod 0640 "$key_rule_file" + chmod 0600 "$key_rule_file" fi files_to_inspect+=("$key_rule_file") fi @@ -94104,17 +169653,20 @@ done else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-000725 - NIST-800-171-3.1.7 - NIST-800-53-AC-6(9) - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.3 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.3 - audit_rules_login_events_tallylog - low_complexity @@ -94131,14 +169683,17 @@ fi register: find_existing_watch_rules_d when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-000725 - NIST-800-171-3.1.7 - NIST-800-53-AC-6(9) - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.3 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.3 - audit_rules_login_events_tallylog - low_complexity @@ -94155,16 +169710,19 @@ fi register: find_watch_key when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: + - DISA-STIG-OL09-00-000725 - NIST-800-171-3.1.7 - NIST-800-53-AC-6(9) - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.3 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.3 - audit_rules_login_events_tallylog - low_complexity @@ -94179,16 +169737,19 @@ fi - /etc/audit/rules.d/logins.rules when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_watch_key.matched is defined and find_watch_key.matched == 0 and find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: + - DISA-STIG-OL09-00-000725 - NIST-800-171-3.1.7 - NIST-800-53-AC-6(9) - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.3 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.3 - audit_rules_login_events_tallylog - low_complexity @@ -94203,16 +169764,19 @@ fi - '{{ find_watch_key.files | map(attribute=''path'') | list | first }}' when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_watch_key.matched is defined and find_watch_key.matched > 0 and find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: + - DISA-STIG-OL09-00-000725 - NIST-800-171-3.1.7 - NIST-800-53-AC-6(9) - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.3 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.3 - audit_rules_login_events_tallylog - low_complexity @@ -94226,19 +169790,22 @@ fi path: '{{ all_files[0] }}' line: -w /var/log/tallylog -p wa -k logins create: true - mode: '0640' + mode: '0600' when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: + - DISA-STIG-OL09-00-000725 - NIST-800-171-3.1.7 - NIST-800-53-AC-6(9) - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.3 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.3 - audit_rules_login_events_tallylog - low_complexity @@ -94255,14 +169822,17 @@ fi register: find_existing_watch_audit_rules when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-000725 - NIST-800-171-3.1.7 - NIST-800-53-AC-6(9) - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.3 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.3 - audit_rules_login_events_tallylog - low_complexity @@ -94277,19 +169847,22 @@ fi state: present dest: /etc/audit/audit.rules create: true - mode: '0640' + mode: '0600' when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_existing_watch_audit_rules.matched is defined and find_existing_watch_audit_rules.matched == 0 tags: + - DISA-STIG-OL09-00-000725 - NIST-800-171-3.1.7 - NIST-800-53-AC-6(9) - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.3 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.3 - audit_rules_login_events_tallylog - low_complexity @@ -94297,22 +169870,22 @@ fi - medium_severity - reboot_required - restrict_strategy - - - - - - - - - - - Record Information on the Use of Privileged Commands - At a minimum, the audit system should collect the execution of -privileged commands for all users and root. - - Ensure auditd Collects Information on the Use of Privileged Commands - init - At a minimum, the audit system should collect the execution of + + + + + + + + + + + Record Information on the Use of Privileged Commands + At a minimum, the audit system should collect the execution of +privileged commands for all users and root. + + Ensure auditd Collects Information on the Use of Privileged Commands - init + At a minimum, the audit system should collect the execution of privileged commands for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add a line of the following form to a file with @@ -94321,13 +169894,16 @@ suffix .rules in the directory /etc/audit/rule If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add a line of the following form to /etc/audit/audit.rules: --a always,exit -F path=/usr/sbin/init -F auid>=1000 -F auid!=unset -F key=privileged - CCI-000172 - AU-12(c) - SRG-OS-000477-GPOS-00222 - Misuse of the init command may cause availability issues for the system. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +-a always,exit -F path=/usr/sbin/init -F auid>=1000 -F auid!=unset -F key=privileged + + CCI-000172 + AU-12(c) + SRG-OS-000477-GPOS-00222 + OL09-00-000730 + SV-271573r1092564_rule + Misuse of the init command may cause availability issues for the system. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then ACTION_ARCH_FILTERS="-a always,exit" OTHER_FILTERS="-F path=/usr/sbin/init -F perm=x" @@ -94365,7 +169941,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -94381,7 +169956,7 @@ then if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -94473,7 +170048,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -94526,7 +170101,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -94620,7 +170194,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -94647,11 +170221,12 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-000730 - NIST-800-53-AU-12(c) - audit_privileged_commands_init - low_complexity @@ -94722,6 +170297,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -94730,7 +170306,7 @@ fi line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/init -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -94767,6 +170343,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -94775,13 +170352,14 @@ fi line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/init -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-000730 - NIST-800-53-AU-12(c) - audit_privileged_commands_init - low_complexity @@ -94789,17 +170367,17 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Ensure auditd Collects Information on the Use of Privileged Commands - poweroff - At a minimum, the audit system should collect the execution of + + + + + + + + + + Ensure auditd Collects Information on the Use of Privileged Commands - poweroff + At a minimum, the audit system should collect the execution of privileged commands for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add a line of the following form to a file with @@ -94808,13 +170386,16 @@ suffix .rules in the directory /etc/audit/rule If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add a line of the following form to /etc/audit/audit.rules: --a always,exit -F path=/usr/sbin/poweroff -F auid>=1000 -F auid!=unset -F key=privileged - CCI-000172 - AU-12(c) - SRG-OS-000477-GPOS-00222 - Misuse of the poweroff command may cause availability issues for the system. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +-a always,exit -F path=/usr/sbin/poweroff -F auid>=1000 -F auid!=unset -F key=privileged + + CCI-000172 + AU-12(c) + SRG-OS-000477-GPOS-00222 + OL09-00-000735 + SV-271574r1092566_rule + Misuse of the poweroff command may cause availability issues for the system. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then ACTION_ARCH_FILTERS="-a always,exit" OTHER_FILTERS="-F path=/usr/sbin/poweroff -F perm=x" @@ -94852,7 +170433,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -94868,7 +170448,7 @@ then if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -94960,7 +170540,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -95013,7 +170593,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -95107,7 +170686,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -95134,11 +170713,12 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-000735 - NIST-800-53-AU-12(c) - audit_privileged_commands_poweroff - low_complexity @@ -95209,6 +170789,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -95217,7 +170798,7 @@ fi line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/poweroff -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -95254,6 +170835,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -95262,13 +170844,14 @@ fi line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/poweroff -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-000735 - NIST-800-53-AU-12(c) - audit_privileged_commands_poweroff - low_complexity @@ -95276,17 +170859,17 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Ensure auditd Collects Information on the Use of Privileged Commands - reboot - At a minimum, the audit system should collect the execution of + + + + + + + + + + Ensure auditd Collects Information on the Use of Privileged Commands - reboot + At a minimum, the audit system should collect the execution of privileged commands for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add a line of the following form to a file with @@ -95295,13 +170878,16 @@ suffix .rules in the directory /etc/audit/rule If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add a line of the following form to /etc/audit/audit.rules: --a always,exit -F path=/usr/sbin/reboot -F auid>=1000 -F auid!=unset -F key=privileged - CCI-000172 - AU-12(c) - SRG-OS-000477-GPOS-00222 - Misuse of the reboot command may cause availability issues for the system. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +-a always,exit -F path=/usr/sbin/reboot -F auid>=1000 -F auid!=unset -F key=privileged + + CCI-000172 + AU-12(c) + SRG-OS-000477-GPOS-00222 + OL09-00-000740 + SV-271575r1092568_rule + Misuse of the reboot command may cause availability issues for the system. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then ACTION_ARCH_FILTERS="-a always,exit" OTHER_FILTERS="-F path=/usr/sbin/reboot -F perm=x" @@ -95339,7 +170925,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -95355,7 +170940,7 @@ then if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -95447,7 +171032,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -95500,7 +171085,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -95594,7 +171178,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -95621,11 +171205,12 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-000740 - NIST-800-53-AU-12(c) - audit_privileged_commands_reboot - low_complexity @@ -95696,6 +171281,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -95704,7 +171290,7 @@ fi line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/reboot -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -95741,6 +171327,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -95749,13 +171336,14 @@ fi line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/reboot -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-000740 - NIST-800-53-AU-12(c) - audit_privileged_commands_reboot - low_complexity @@ -95763,17 +171351,17 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Ensure auditd Collects Information on the Use of Privileged Commands - shutdown - At a minimum, the audit system should collect the execution of + + + + + + + + + + Ensure auditd Collects Information on the Use of Privileged Commands - shutdown + At a minimum, the audit system should collect the execution of privileged commands for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add a line of the following form to a file with @@ -95782,13 +171370,16 @@ suffix .rules in the directory /etc/audit/rule If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add a line of the following form to /etc/audit/audit.rules: --a always,exit -F path=/usr/sbin/shutdown -F auid>=1000 -F auid!=unset -F key=privileged - CCI-000172 - AU-12(c) - SRG-OS-000477-GPOS-00222 - Misuse of the shutdown command may cause availability issues for the system. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +-a always,exit -F path=/usr/sbin/shutdown -F auid>=1000 -F auid!=unset -F key=privileged + + CCI-000172 + AU-12(c) + SRG-OS-000477-GPOS-00222 + OL09-00-000745 + SV-271576r1092570_rule + Misuse of the shutdown command may cause availability issues for the system. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then ACTION_ARCH_FILTERS="-a always,exit" OTHER_FILTERS="-F path=/usr/sbin/shutdown -F perm=x" @@ -95826,7 +171417,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -95842,7 +171432,7 @@ then if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -95934,7 +171524,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -95987,7 +171577,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -96081,7 +171670,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -96108,11 +171697,12 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-000745 - NIST-800-53-AU-12(c) - audit_privileged_commands_shutdown - low_complexity @@ -96183,6 +171773,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -96191,7 +171782,7 @@ fi line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/shutdown -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -96228,6 +171819,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -96236,13 +171828,14 @@ fi line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/shutdown -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-000745 - NIST-800-53-AU-12(c) - audit_privileged_commands_shutdown - low_complexity @@ -96250,17 +171843,17 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Ensure auditd Collects Information on the Use of Privileged Commands - The audit system should collect information about usage of privileged commands for all users. + + + + + + + + + + Ensure auditd Collects Information on the Use of Privileged Commands + The audit system should collect information about usage of privileged commands for all users. These are commands with suid or sgid bits on and they are specially risky in local block device partitions not mounted with noexec and nosuid options. Therefore, these partitions should be first identified by the following command: @@ -96281,166 +171874,167 @@ of that setuid / setgid identified program. If the auditd daemon is configured to use the auditctl utility instead, add the line to the /etc/audit/audit.rules file, also replacing the PROG_PATH part -with the full path of that setuid / setgid identified program. - This rule checks for multiple syscalls related to privileged commands. If needed to check +with the full path of that setuid / setgid identified program. + This rule checks for multiple syscalls related to privileged commands. If needed to check specific privileged commands, other more specific rules should be considered. For example: -audit_rules_privileged_commands_suaudit_rules_privileged_commands_umountaudit_rules_privileged_commands_passwd - Note that OVAL check and Bash / Ansible remediation of this rule -explicitly excludes file systems mounted at /proc directory +audit_rules_privileged_commands_suaudit_rules_privileged_commands_umountaudit_rules_privileged_commands_passwd + + Note that OVAL check and Bash / Ansible remediation of this rule +explicitly excludes file systems mounted at /proc directory and its subdirectories. It is a virtual file system and it doesn't contain executable applications. At the same time, interacting with this -file system during check or remediation caused undesirable errors. - BP28(R73) - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 19 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 5.4.1.1 - APO08.04 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - APO12.06 - APO13.01 - BAI03.05 - BAI08.02 - DSS01.03 - DSS01.04 - DSS02.02 - DSS02.04 - DSS02.05 - DSS02.07 - DSS03.01 - DSS03.05 - DSS05.02 - DSS05.03 - DSS05.04 - DSS05.05 - DSS05.07 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.1.7 - CCI-002234 - 4.2.3.10 - 4.3.2.6.7 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.3.6.6 - 4.3.4.4.7 - 4.3.4.5.5 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.3.4.5.9 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 1.13 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.6 - SR 2.8 - SR 2.9 - SR 3.1 - SR 3.5 - SR 3.8 - SR 3.9 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 6.1 - SR 6.2 - SR 7.1 - SR 7.6 - 0582 - 0584 - 05885 - 0586 - 0846 - 0957 - A.11.2.6 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.14.2.7 - A.15.2.1 - A.15.2.2 - A.16.1.1 - A.16.1.2 - A.16.1.3 - A.16.1.4 - A.16.1.5 - A.16.1.7 - A.6.1.3 - A.6.2.1 - A.6.2.2 - CIP-004-6 R2.2.2 - CIP-004-6 R2.2.3 - CIP-007-3 R.1.3 - CIP-007-3 R5 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.3 - CIP-007-3 R5.2.1 - CIP-007-3 R5.2.3 - AC-2(4) - AU-2(d) - AU-12(c) - AC-6(9) - CM-6(a) - DE.AE-2 - DE.AE-3 - DE.AE-5 - DE.CM-1 - DE.CM-3 - DE.CM-7 - DE.DP-4 - ID.SC-4 - PR.AC-3 - PR.PT-1 - PR.PT-4 - RS.AN-1 - RS.AN-4 - RS.CO-2 - Req-10.2.2 - 10.2.1.2 - SRG-OS-000327-GPOS-00127 - Misuse of privileged functions, either intentionally or unintentionally by authorized users, +file system during check or remediation caused undesirable errors. + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 19 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 5.4.1.1 + APO08.04 + APO10.01 + APO10.03 + APO10.04 + APO10.05 + APO11.04 + APO12.06 + APO13.01 + BAI03.05 + BAI08.02 + DSS01.03 + DSS01.04 + DSS02.02 + DSS02.04 + DSS02.05 + DSS02.07 + DSS03.01 + DSS03.05 + DSS05.02 + DSS05.03 + DSS05.04 + DSS05.05 + DSS05.07 + MEA01.01 + MEA01.02 + MEA01.03 + MEA01.04 + MEA01.05 + MEA02.01 + 3.1.7 + CCI-002234 + 4.2.3.10 + 4.3.2.6.7 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.3.6.6 + 4.3.4.4.7 + 4.3.4.5.5 + 4.3.4.5.6 + 4.3.4.5.7 + 4.3.4.5.8 + 4.3.4.5.9 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 1.13 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.6 + SR 2.8 + SR 2.9 + SR 3.1 + SR 3.5 + SR 3.8 + SR 3.9 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 6.1 + SR 6.2 + SR 7.1 + SR 7.6 + 0582 + 0584 + 05885 + 0586 + 0846 + 0957 + A.11.2.6 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.13.1.1 + A.13.2.1 + A.14.1.3 + A.14.2.7 + A.15.2.1 + A.15.2.2 + A.16.1.1 + A.16.1.2 + A.16.1.3 + A.16.1.4 + A.16.1.5 + A.16.1.7 + A.6.1.3 + A.6.2.1 + A.6.2.2 + CIP-004-6 R2.2.2 + CIP-004-6 R2.2.3 + CIP-007-3 R.1.3 + CIP-007-3 R5 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.3 + CIP-007-3 R5.2.1 + CIP-007-3 R5.2.3 + AC-2(4) + AU-2(d) + AU-12(c) + AC-6(9) + CM-6(a) + DE.AE-2 + DE.AE-3 + DE.AE-5 + DE.CM-1 + DE.CM-3 + DE.CM-7 + DE.DP-4 + ID.SC-4 + PR.AC-3 + PR.PT-1 + PR.PT-4 + RS.AN-1 + RS.AN-4 + RS.CO-2 + Req-10.2.2 + SRG-OS-000327-GPOS-00127 + R73 + Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern that can have significant adverse impacts on organizations. Auditing the use of privileged functions is one way to detect such misuse and identify the risk from insider and advanced persistent threats. - + + Privileged programs are subject to escalation-of-privilege attacks, which attempt to subvert their normal role of providing some necessary but limited capability. As such, motivation -exists to monitor these programs for unusual activity. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +exists to monitor these programs for unusual activity. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then ACTION_ARCH_FILTERS="-a always,exit" AUID_FILTERS="-F auid>=1000 -F auid!=unset" @@ -96448,12 +172042,10 @@ SYSCALL="" KEY="privileged" SYSCALL_GROUPING="" -FILTER_NODEV=$(awk '/nodev/ { print $2 }' /proc/filesystems | paste -sd,) -PARTITIONS=$(findmnt -n -l -k -it $FILTER_NODEV | grep -Pv "noexec|nosuid|/proc($|/.*$)" | awk '{ print $1 }') -for PARTITION in $PARTITIONS; do - PRIV_CMDS=$(find "${PARTITION}" -xdev -perm /6000 -type f 2>/dev/null) - for PRIV_CMD in $PRIV_CMDS; do - OTHER_FILTERS="-F path=$PRIV_CMD -F perm=x" +function add_audit_rule() +{ + local PRIV_CMD="$1" + local OTHER_FILTERS="-F path=$PRIV_CMD -F perm=x" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -96484,7 +172076,6 @@ for PARTITION in $PARTITIONS; do # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -96500,7 +172091,7 @@ for PARTITION in $PARTITIONS; do if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -96592,7 +172183,7 @@ for PARTITION in $PARTITIONS; do auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -96645,7 +172236,6 @@ for PARTITION in $PARTITIONS; do files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -96739,7 +172329,7 @@ for PARTITION in $PARTITIONS; do auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -96762,14 +172352,29 @@ for PARTITION in $PARTITIONS; do sed -i -e "\#${rule_to_edit}#s#${rule_syscalls_to_edit}#${new_grouped_syscalls}#" "$file_to_edit" fi fi +} + +if [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; then + PRIV_CMDS=$(find / -perm /6000 -type f -not -path "/sysroot/*" 2>/dev/null) + for PRIV_CMD in $PRIV_CMDS; do + add_audit_rule $PRIV_CMD done -done +else + FILTER_NODEV=$(awk '/nodev/ { print $2 }' /proc/filesystems | paste -sd,) + PARTITIONS=$(findmnt -n -l -k -it "$FILTER_NODEV" | grep -Pv "noexec|nosuid|/proc($|/.*$)" | awk '{ print $1 }') + for PARTITION in $PARTITIONS; do + PRIV_CMDS=$(find "${PARTITION}" -xdev -perm /6000 -type f 2>/dev/null) + for PRIV_CMD in $PRIV_CMDS; do + add_audit_rule $PRIV_CMD + done + done +fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: @@ -96781,7 +172386,6 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.2 - - PCI-DSSv4-10.2.1.2 - audit_rules_privileged_commands - configure_strategy - low_complexity @@ -96792,12 +172396,12 @@ fi - name: Ensure auditd Collects Information on the Use of Privileged Commands - Set List of Mount Points Which Permits Execution of Privileged Commands ansible.builtin.set_fact: - privileged_mount_points: '{{(ansible_facts.mounts | rejectattr(''options'', ''search'', + privileged_mount_points: '{{ (ansible_facts.mounts | rejectattr(''options'', ''search'', ''noexec|nosuid'') | rejectattr(''mount'', ''match'', ''/proc($|/.*$)'') | map(attribute=''mount'') | list ) }}' when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.4.1.1 - NIST-800-171-3.1.7 @@ -96807,7 +172411,6 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.2 - - PCI-DSSv4-10.2.1.2 - audit_rules_privileged_commands - configure_strategy - low_complexity @@ -96825,7 +172428,7 @@ fi with_items: '{{ privileged_mount_points }}' when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.4.1.1 - NIST-800-171-3.1.7 @@ -96835,7 +172438,6 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.2 - - PCI-DSSv4-10.2.1.2 - audit_rules_privileged_commands - configure_strategy - low_complexity @@ -96846,11 +172448,13 @@ fi - name: Ensure auditd Collects Information on the Use of Privileged Commands - Set List of Privileged Commands Found in Eligible Mount Points ansible.builtin.set_fact: - privileged_commands: '{{( result_privileged_commands_search.results | map(attribute=''stdout_lines'') - | select() | list )[-1] }}' + privileged_commands: '{{ privileged_commands | default([]) + item.stdout_lines + }}' + loop: '{{ result_privileged_commands_search.results }}' when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - item is not skipped tags: - CJIS-5.4.1.1 - NIST-800-171-3.1.7 @@ -96860,7 +172464,6 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.2 - - PCI-DSSv4-10.2.1.2 - audit_rules_privileged_commands - configure_strategy - low_complexity @@ -96918,7 +172521,7 @@ fi - item.1.path != '/etc/audit/rules.d/privileged.rules' when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - privileged_commands is defined tags: - CJIS-5.4.1.1 @@ -96929,24 +172532,23 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.2.2 - - PCI-DSSv4-10.2.1.2 - audit_rules_privileged_commands - configure_strategy - low_complexity - low_disruption - medium_severity - no_reboot_needed - - - - - - - - - - Ensure auditd Collects Information on the Use of Privileged Commands - at - At a minimum, the audit system should collect the execution of + + + + + + + + + + Ensure auditd Collects Information on the Use of Privileged Commands - at + At a minimum, the audit system should collect the execution of privileged commands for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add a line of the following form to a file with @@ -96955,25 +172557,26 @@ suffix .rules in the directory /etc/audit/rule If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add a line of the following form to /etc/audit/audit.rules: --a always,exit -F path=/usr/bin/at -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged - CCI-000172 - AU-2(d) - AU-12(c) - AC-6(9) - CM-6(a) - FAU_GEN.1.1.c - Misuse of privileged functions, either intentionally or unintentionally by +-a always,exit -F path=/usr/bin/at -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + + CCI-000172 + AU-2(d) + AU-12(c) + AC-6(9) + CM-6(a) + Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. Auditing the use of privileged functions is one way to detect such misuse and identify the risk from insider and advanced persistent threats. - + + Privileged programs are subject to escalation-of-privilege attacks, which attempt to subvert their normal role of providing some necessary but limited capability. As such, motivation exists to monitor these programs for -unusual activity. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +unusual activity. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then ACTION_ARCH_FILTERS="-a always,exit" OTHER_FILTERS="-F path=/usr/bin/at -F perm=x" @@ -97011,7 +172614,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -97027,7 +172629,7 @@ then if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -97119,7 +172721,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -97172,7 +172774,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -97266,7 +172867,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -97293,8 +172894,8 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: @@ -97371,6 +172972,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -97379,7 +172981,7 @@ fi line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/at -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -97416,6 +173018,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -97424,12 +173027,12 @@ fi line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/at -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AC-6(9) - NIST-800-53-AU-12(c) @@ -97441,17 +173044,17 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Ensure auditd Collects Information on the Use of Privileged Commands - chage - At a minimum, the audit system should collect the execution of + + + + + + + + + + Ensure auditd Collects Information on the Use of Privileged Commands - chage + At a minimum, the audit system should collect the execution of privileged commands for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add a line of the following form to a file with @@ -97460,111 +173063,118 @@ suffix .rules in the directory /etc/audit/rule If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add a line of the following form to /etc/audit/audit.rules: --a always,exit -F path=/usr/bin/chage -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged - 1 - 12 - 13 - 14 - 15 - 16 - 2 - 3 - 5 - 6 - 7 - 8 - 9 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - BAI03.05 - DSS01.03 - DSS03.05 - DSS05.02 - DSS05.04 - DSS05.05 - DSS05.07 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.1.7 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-000172 - CCI-002884 - 164.308(a)(1)(ii)(D) - 164.308(a)(3)(ii)(A) - 164.308(a)(5)(ii)(C) - 164.312(a)(2)(i) - 164.312(b) - 164.312(d) - 164.312(e) - 4.3.2.6.7 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.4.4.7 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.8 - SR 2.9 - SR 6.1 - SR 6.2 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.14.2.7 - A.15.2.1 - A.15.2.2 - CIP-004-6 R2.2.2 - CIP-004-6 R2.2.3 - CIP-007-3 R.1.3 - CIP-007-3 R5 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.3 - CIP-007-3 R5.2.1 - CIP-007-3 R5.2.3 - AC-2(4) - AU-2(d) - AU-12(c) - AC-6(9) - CM-6(a) - DE.CM-1 - DE.CM-3 - DE.CM-7 - ID.SC-4 - PR.PT-1 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000468-GPOS-00212 - SRG-OS-000471-GPOS-00215 - SRG-APP-000029-CTR-000085 - Misuse of privileged functions, either intentionally or unintentionally by +-a always,exit -F path=/usr/bin/chage -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + + 1 + 12 + 13 + 14 + 15 + 16 + 2 + 3 + 5 + 6 + 7 + 8 + 9 + APO10.01 + APO10.03 + APO10.04 + APO10.05 + APO11.04 + BAI03.05 + DSS01.03 + DSS03.05 + DSS05.02 + DSS05.04 + DSS05.05 + DSS05.07 + MEA01.01 + MEA01.02 + MEA01.03 + MEA01.04 + MEA01.05 + MEA02.01 + 3.1.7 + CCI-000172 + CCI-000130 + CCI-000135 + CCI-000169 + CCI-002884 + 164.308(a)(1)(ii)(D) + 164.308(a)(3)(ii)(A) + 164.308(a)(5)(ii)(C) + 164.312(a)(2)(i) + 164.312(b) + 164.312(d) + 164.312(e) + 4.3.2.6.7 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.4.4.7 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.8 + SR 2.9 + SR 6.1 + SR 6.2 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.14.2.7 + A.15.2.1 + A.15.2.2 + CIP-004-6 R2.2.2 + CIP-004-6 R2.2.3 + CIP-007-3 R.1.3 + CIP-007-3 R5 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.3 + CIP-007-3 R5.2.1 + CIP-007-3 R5.2.3 + AC-2(4) + AU-2(d) + AU-12(c) + AC-6(9) + CM-6(a) + DE.CM-1 + DE.CM-3 + DE.CM-7 + ID.SC-4 + PR.PT-1 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000468-GPOS-00212 + SRG-OS-000471-GPOS-00215 + SRG-APP-000029-CTR-000085 + SRG-APP-000495-CTR-001235 + SRG-APP-000501-CTR-001265 + SRG-APP-000502-CTR-001270 + OL09-00-000550 + SV-271537r1092494_rule + Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. Auditing the use of privileged functions is one way to detect such misuse and identify the risk from insider and advanced persistent threats. - + + Privileged programs are subject to escalation-of-privilege attacks, which attempt to subvert their normal role of providing some necessary but limited capability. As such, motivation exists to monitor these programs for -unusual activity. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +unusual activity. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then ACTION_ARCH_FILTERS="-a always,exit" OTHER_FILTERS="-F path=/usr/bin/chage -F perm=x" @@ -97602,7 +173212,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -97618,7 +173227,7 @@ then if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -97710,7 +173319,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -97763,7 +173372,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -97857,7 +173465,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -97884,11 +173492,12 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-000550 - NIST-800-171-3.1.7 - NIST-800-53-AC-2(4) - NIST-800-53-AC-6(9) @@ -97964,6 +173573,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -97972,7 +173582,7 @@ fi line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/chage -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -98009,6 +173619,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -98017,13 +173628,14 @@ fi line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/chage -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-000550 - NIST-800-171-3.1.7 - NIST-800-53-AC-2(4) - NIST-800-53-AC-6(9) @@ -98036,17 +173648,17 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Ensure auditd Collects Information on the Use of Privileged Commands - chsh - At a minimum, the audit system should collect the execution of + + + + + + + + + + Ensure auditd Collects Information on the Use of Privileged Commands - chsh + At a minimum, the audit system should collect the execution of privileged commands for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add a line of the following form to a file with @@ -98055,109 +173667,114 @@ suffix .rules in the directory /etc/audit/rule If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add a line of the following form to /etc/audit/audit.rules: --a always,exit -F path=/usr/bin/chsh -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged - 1 - 12 - 13 - 14 - 15 - 16 - 2 - 3 - 5 - 6 - 7 - 8 - 9 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - BAI03.05 - DSS01.03 - DSS03.05 - DSS05.02 - DSS05.04 - DSS05.05 - DSS05.07 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.1.7 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-000172 - CCI-002884 - 164.308(a)(1)(ii)(D) - 164.308(a)(3)(ii)(A) - 164.308(a)(5)(ii)(C) - 164.312(a)(2)(i) - 164.312(b) - 164.312(d) - 164.312(e) - 4.3.2.6.7 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.4.4.7 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.8 - SR 2.9 - SR 6.1 - SR 6.2 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.14.2.7 - A.15.2.1 - A.15.2.2 - CIP-004-6 R2.2.2 - CIP-004-6 R2.2.3 - CIP-007-3 R.1.3 - CIP-007-3 R5 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.3 - CIP-007-3 R5.2.1 - CIP-007-3 R5.2.3 - AC-2(4) - AU-2(d) - AU-12(c) - AC-6(9) - CM-6(a) - DE.CM-1 - DE.CM-3 - DE.CM-7 - ID.SC-4 - PR.PT-1 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - Misuse of privileged functions, either intentionally or unintentionally by +-a always,exit -F path=/usr/bin/chsh -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + + 1 + 12 + 13 + 14 + 15 + 16 + 2 + 3 + 5 + 6 + 7 + 8 + 9 + APO10.01 + APO10.03 + APO10.04 + APO10.05 + APO11.04 + BAI03.05 + DSS01.03 + DSS03.05 + DSS05.02 + DSS05.04 + DSS05.05 + DSS05.07 + MEA01.01 + MEA01.02 + MEA01.03 + MEA01.04 + MEA01.05 + MEA02.01 + 3.1.7 + CCI-000172 + CCI-000130 + CCI-000135 + CCI-000169 + CCI-002884 + 164.308(a)(1)(ii)(D) + 164.308(a)(3)(ii)(A) + 164.308(a)(5)(ii)(C) + 164.312(a)(2)(i) + 164.312(b) + 164.312(d) + 164.312(e) + 4.3.2.6.7 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.4.4.7 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.8 + SR 2.9 + SR 6.1 + SR 6.2 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.14.2.7 + A.15.2.1 + A.15.2.2 + CIP-004-6 R2.2.2 + CIP-004-6 R2.2.3 + CIP-007-3 R.1.3 + CIP-007-3 R5 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.3 + CIP-007-3 R5.2.1 + CIP-007-3 R5.2.3 + AC-2(4) + AU-2(d) + AU-12(c) + AC-6(9) + CM-6(a) + DE.CM-1 + DE.CM-3 + DE.CM-7 + ID.SC-4 + PR.PT-1 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-APP-000495-CTR-001235 + OL09-00-000565 + SV-271540r1092500_rule + Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. Auditing the use of privileged functions is one way to detect such misuse and identify the risk from insider and advanced persistent threats. - + + Privileged programs are subject to escalation-of-privilege attacks, which attempt to subvert their normal role of providing some necessary but limited capability. As such, motivation exists to monitor these programs for -unusual activity. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +unusual activity. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then ACTION_ARCH_FILTERS="-a always,exit" OTHER_FILTERS="-F path=/usr/bin/chsh -F perm=x" @@ -98195,7 +173812,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -98211,7 +173827,7 @@ then if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -98303,7 +173919,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -98356,7 +173972,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -98450,7 +174065,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -98477,11 +174092,12 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-000565 - NIST-800-171-3.1.7 - NIST-800-53-AC-2(4) - NIST-800-53-AC-6(9) @@ -98557,6 +174173,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -98565,7 +174182,7 @@ fi line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/chsh -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -98602,6 +174219,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -98610,13 +174228,14 @@ fi line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/chsh -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-000565 - NIST-800-171-3.1.7 - NIST-800-53-AC-2(4) - NIST-800-53-AC-6(9) @@ -98629,17 +174248,17 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Ensure auditd Collects Information on the Use of Privileged Commands - crontab - At a minimum, the audit system should collect the execution of + + + + + + + + + + Ensure auditd Collects Information on the Use of Privileged Commands - crontab + At a minimum, the audit system should collect the execution of privileged commands for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add a line of the following form to a file with @@ -98648,100 +174267,105 @@ suffix .rules in the directory /etc/audit/rule If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add a line of the following form to /etc/audit/audit.rules: --a always,exit -F path=/usr/bin/crontab -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged - 1 - 12 - 13 - 14 - 15 - 16 - 2 - 3 - 5 - 6 - 7 - 8 - 9 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - BAI03.05 - DSS01.03 - DSS03.05 - DSS05.02 - DSS05.04 - DSS05.05 - DSS05.07 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.1.7 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-000172 - CCI-002884 - 164.308(a)(1)(ii)(D) - 164.308(a)(3)(ii)(A) - 164.308(a)(5)(ii)(C) - 164.312(a)(2)(i) - 164.312(b) - 164.312(d) - 164.312(e) - 4.3.2.6.7 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.4.4.7 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.8 - SR 2.9 - SR 6.1 - SR 6.2 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.14.2.7 - A.15.2.1 - A.15.2.2 - AU-2(d) - AU-12(c) - AC-6(9) - CM-6(a) - DE.CM-1 - DE.CM-3 - DE.CM-7 - ID.SC-4 - PR.PT-1 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - Misuse of privileged functions, either intentionally or unintentionally by +-a always,exit -F path=/usr/bin/crontab -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + + 1 + 12 + 13 + 14 + 15 + 16 + 2 + 3 + 5 + 6 + 7 + 8 + 9 + APO10.01 + APO10.03 + APO10.04 + APO10.05 + APO11.04 + BAI03.05 + DSS01.03 + DSS03.05 + DSS05.02 + DSS05.04 + DSS05.05 + DSS05.07 + MEA01.01 + MEA01.02 + MEA01.03 + MEA01.04 + MEA01.05 + MEA02.01 + 3.1.7 + CCI-000172 + CCI-000130 + CCI-000135 + CCI-000169 + CCI-002884 + 164.308(a)(1)(ii)(D) + 164.308(a)(3)(ii)(A) + 164.308(a)(5)(ii)(C) + 164.312(a)(2)(i) + 164.312(b) + 164.312(d) + 164.312(e) + 4.3.2.6.7 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.4.4.7 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.8 + SR 2.9 + SR 6.1 + SR 6.2 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.14.2.7 + A.15.2.1 + A.15.2.2 + AU-2(d) + AU-12(c) + AC-6(9) + CM-6(a) + DE.CM-1 + DE.CM-3 + DE.CM-7 + ID.SC-4 + PR.PT-1 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-APP-000495-CTR-001235 + OL09-00-000570 + SV-271541r1092502_rule + Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. Auditing the use of privileged functions is one way to detect such misuse and identify the risk from insider and advanced persistent threats. - + + Privileged programs are subject to escalation-of-privilege attacks, which attempt to subvert their normal role of providing some necessary but limited capability. As such, motivation exists to monitor these programs for -unusual activity. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +unusual activity. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then ACTION_ARCH_FILTERS="-a always,exit" OTHER_FILTERS="-F path=/usr/bin/crontab -F perm=x" @@ -98779,7 +174403,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -98795,7 +174418,7 @@ then if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -98887,7 +174510,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -98940,7 +174563,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -99034,7 +174656,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -99061,11 +174683,12 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-000570 - NIST-800-171-3.1.7 - NIST-800-53-AC-6(9) - NIST-800-53-AU-12(c) @@ -99140,6 +174763,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -99148,7 +174772,7 @@ fi line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/crontab -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -99185,6 +174809,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -99193,13 +174818,14 @@ fi line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/crontab -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-000570 - NIST-800-171-3.1.7 - NIST-800-53-AC-6(9) - NIST-800-53-AU-12(c) @@ -99211,17 +174837,17 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Ensure auditd Collects Information on the Use of Privileged Commands - gpasswd - At a minimum, the audit system should collect the execution of + + + + + + + + + + Ensure auditd Collects Information on the Use of Privileged Commands - gpasswd + At a minimum, the audit system should collect the execution of privileged commands for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add a line of the following form to a file with @@ -99230,111 +174856,115 @@ suffix .rules in the directory /etc/audit/rule If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add a line of the following form to /etc/audit/audit.rules: --a always,exit -F path=/usr/bin/gpasswd -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged - 1 - 12 - 13 - 14 - 15 - 16 - 2 - 3 - 5 - 6 - 7 - 8 - 9 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - BAI03.05 - DSS01.03 - DSS03.05 - DSS05.02 - DSS05.04 - DSS05.05 - DSS05.07 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.1.7 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-000172 - CCI-002884 - 164.308(a)(1)(ii)(D) - 164.308(a)(3)(ii)(A) - 164.308(a)(5)(ii)(C) - 164.312(a)(2)(i) - 164.312(b) - 164.312(d) - 164.312(e) - 4.3.2.6.7 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.4.4.7 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.8 - SR 2.9 - SR 6.1 - SR 6.2 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.14.2.7 - A.15.2.1 - A.15.2.2 - CIP-004-6 R2.2.2 - CIP-004-6 R2.2.3 - CIP-007-3 R.1.3 - CIP-007-3 R5 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.3 - CIP-007-3 R5.2.1 - CIP-007-3 R5.2.3 - AC-2(4) - AU-2(d) - AU-12(c) - AC-6(9) - CM-6(a) - DE.CM-1 - DE.CM-3 - DE.CM-7 - ID.SC-4 - PR.PT-1 - FAU_GEN.1.1.c - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-APP-000029-CTR-000085 - Misuse of privileged functions, either intentionally or unintentionally by +-a always,exit -F path=/usr/bin/gpasswd -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + + 1 + 12 + 13 + 14 + 15 + 16 + 2 + 3 + 5 + 6 + 7 + 8 + 9 + APO10.01 + APO10.03 + APO10.04 + APO10.05 + APO11.04 + BAI03.05 + DSS01.03 + DSS03.05 + DSS05.02 + DSS05.04 + DSS05.05 + DSS05.07 + MEA01.01 + MEA01.02 + MEA01.03 + MEA01.04 + MEA01.05 + MEA02.01 + 3.1.7 + CCI-000172 + CCI-000130 + CCI-000135 + CCI-000169 + CCI-002884 + 164.308(a)(1)(ii)(D) + 164.308(a)(3)(ii)(A) + 164.308(a)(5)(ii)(C) + 164.312(a)(2)(i) + 164.312(b) + 164.312(d) + 164.312(e) + 4.3.2.6.7 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.4.4.7 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.8 + SR 2.9 + SR 6.1 + SR 6.2 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.14.2.7 + A.15.2.1 + A.15.2.2 + CIP-004-6 R2.2.2 + CIP-004-6 R2.2.3 + CIP-007-3 R.1.3 + CIP-007-3 R5 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.3 + CIP-007-3 R5.2.1 + CIP-007-3 R5.2.3 + AC-2(4) + AU-2(d) + AU-12(c) + AC-6(9) + CM-6(a) + DE.CM-1 + DE.CM-3 + DE.CM-7 + ID.SC-4 + PR.PT-1 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-APP-000029-CTR-000085 + SRG-APP-000495-CTR-001235 + OL09-00-000575 + SV-271542r1092504_rule + Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. Auditing the use of privileged functions is one way to detect such misuse and identify the risk from insider and advanced persistent threats. - + + Privileged programs are subject to escalation-of-privilege attacks, which attempt to subvert their normal role of providing some necessary but limited capability. As such, motivation exists to monitor these programs for -unusual activity. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +unusual activity. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then ACTION_ARCH_FILTERS="-a always,exit" OTHER_FILTERS="-F path=/usr/bin/gpasswd -F perm=x" @@ -99372,7 +175002,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -99388,7 +175017,7 @@ then if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -99480,7 +175109,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -99533,7 +175162,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -99627,7 +175255,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -99654,11 +175282,12 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-000575 - NIST-800-171-3.1.7 - NIST-800-53-AC-2(4) - NIST-800-53-AC-6(9) @@ -99734,6 +175363,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -99742,7 +175372,7 @@ fi line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/gpasswd -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -99779,6 +175409,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -99787,13 +175418,14 @@ fi line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/gpasswd -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-000575 - NIST-800-171-3.1.7 - NIST-800-53-AC-2(4) - NIST-800-53-AC-6(9) @@ -99806,56 +175438,60 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Ensure auditd Collects Information on the Use of Privileged Commands - kmod - At a minimum, the audit system should collect the execution of + + + + + + + + + + Ensure auditd Collects Information on the Use of Privileged Commands - kmod + At a minimum, the audit system should collect the execution of privileged commands for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add a line of the following form to a file with suffix .rules in the directory /etc/audit/rules.d: --w /usr/bin/kmod -p x -k modules +-a always,exit -F path=/usr/bin/kmod -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add a line of the following form to /etc/audit/audit.rules: --w /usr/bin/kmod -p x -k modules - BP28(R73) - CCI-000130 - CCI-000135 - CCI-000169 - CCI-000172 - CCI-002884 - AU-3 - AU-3.1 - AU-12(a) - AU-12.1(ii) - AU-12.1(iv)AU-12(c) - MA-4(1)(a) - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-OS-000471-GPOS-00216 - SRG-OS-000477-GPOS-00222 - Without generating audit records that are specific to the security and +-a always,exit -F path=/usr/bin/kmod -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + + CCI-000172 + CCI-000130 + CCI-000135 + CCI-000169 + CCI-002884 + AU-3 + AU-3.1 + AU-12(a) + AU-12.1(ii) + AU-12.1(iv)AU-12(c) + MA-4(1)(a) + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-OS-000471-GPOS-00216 + SRG-OS-000477-GPOS-00222 + SRG-APP-000495-CTR-001235 + SRG-APP-000504-CTR-001280 + R73 + OL09-00-000695 + SV-271566r1092552_rule + Without generating audit records that are specific to the security and mission needs of the organization, it would be difficult to establish, correlate, and investigate the events relating to an incident or identify those responsible for one. Audit records can be generated from various components within the -information system (e.g., module or policy filter). - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +information system (e.g., module or policy filter). + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then ACTION_ARCH_FILTERS="-a always,exit" OTHER_FILTERS="-F path=/usr/bin/kmod -F perm=x" @@ -99893,7 +175529,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -99909,7 +175544,7 @@ then if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -100001,7 +175636,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -100054,7 +175689,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -100148,7 +175782,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -100175,11 +175809,12 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-000695 - NIST-800-53-AU-12(a) - NIST-800-53-AU-12.1(ii) - NIST-800-53-AU-12.1(iv)AU-12(c) @@ -100255,6 +175890,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -100263,7 +175899,7 @@ fi line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/kmod -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -100300,6 +175936,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -100308,13 +175945,14 @@ fi line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/kmod -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-000695 - NIST-800-53-AU-12(a) - NIST-800-53-AU-12.1(ii) - NIST-800-53-AU-12.1(iv)AU-12(c) @@ -100327,17 +175965,17 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Ensure auditd Collects Information on the Use of Privileged Commands - mount - At a minimum, the audit system should collect the execution of + + + + + + + + + + Ensure auditd Collects Information on the Use of Privileged Commands - mount + At a minimum, the audit system should collect the execution of privileged commands for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add a line of the following form to a file with @@ -100346,36 +175984,39 @@ suffix .rules in the directory /etc/audit/rule If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add a line of the following form to /etc/audit/audit.rules: --a always,exit -F path=/usr/bin/mount -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged - CCI-000130 - CCI-000135 - CCI-000169 - CCI-000172 - CCI-002884 - AU-2(d) - AU-12(c) - AC-6(9) - CM-6(a) - FAU_GEN.1.1.c - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-APP-000029-CTR-000085 - Misuse of privileged functions, either intentionally or unintentionally by +-a always,exit -F path=/usr/bin/mount -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + + CCI-000172 + CCI-000130 + CCI-000135 + CCI-000169 + CCI-002884 + AU-2(d) + AU-12(c) + AC-6(9) + CM-6(a) + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-APP-000029-CTR-000085 + OL09-00-000630 + SV-271553r1092526_rule + Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. Auditing the use of privileged functions is one way to detect such misuse and identify the risk from insider and advanced persistent threats. - + + Privileged programs are subject to escalation-of-privilege attacks, which attempt to subvert their normal role of providing some necessary but limited capability. As such, motivation exists to monitor these programs for -unusual activity. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +unusual activity. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then ACTION_ARCH_FILTERS="-a always,exit" OTHER_FILTERS="-F path=/usr/bin/mount -F perm=x" @@ -100413,7 +176054,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -100429,7 +176069,7 @@ then if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -100521,7 +176161,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -100574,7 +176214,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -100668,7 +176307,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -100695,11 +176334,12 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-000630 - NIST-800-53-AC-6(9) - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) @@ -100773,6 +176413,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -100781,7 +176422,7 @@ fi line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/mount -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -100818,6 +176459,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -100826,13 +176468,14 @@ fi line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/mount -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-000630 - NIST-800-53-AC-6(9) - NIST-800-53-AU-12(c) - NIST-800-53-AU-2(d) @@ -100843,17 +176486,17 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Ensure auditd Collects Information on the Use of Privileged Commands - newgrp - At a minimum, the audit system should collect the execution of + + + + + + + + + + Ensure auditd Collects Information on the Use of Privileged Commands - newgrp + At a minimum, the audit system should collect the execution of privileged commands for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add a line of the following form to a file with @@ -100862,111 +176505,115 @@ suffix .rules in the directory /etc/audit/rule If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add a line of the following form to /etc/audit/audit.rules: --a always,exit -F path=/usr/bin/newgrp -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged - 1 - 12 - 13 - 14 - 15 - 16 - 2 - 3 - 5 - 6 - 7 - 8 - 9 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - BAI03.05 - DSS01.03 - DSS03.05 - DSS05.02 - DSS05.04 - DSS05.05 - DSS05.07 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.1.7 - CCI-000130 - CCI-000169 - CCI-000135 - CCI-000172 - CCI-002884 - 164.308(a)(1)(ii)(D) - 164.308(a)(3)(ii)(A) - 164.308(a)(5)(ii)(C) - 164.312(a)(2)(i) - 164.312(b) - 164.312(d) - 164.312(e) - 4.3.2.6.7 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.4.4.7 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.8 - SR 2.9 - SR 6.1 - SR 6.2 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.14.2.7 - A.15.2.1 - A.15.2.2 - CIP-004-6 R2.2.2 - CIP-004-6 R2.2.3 - CIP-007-3 R.1.3 - CIP-007-3 R5 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.3 - CIP-007-3 R5.2.1 - CIP-007-3 R5.2.3 - AC-2(4) - AU-2(d) - AU-12(c) - AC-6(9) - CM-6(a) - DE.CM-1 - DE.CM-3 - DE.CM-7 - ID.SC-4 - PR.PT-1 - FAU_GEN.1.1.c - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-APP-000029-CTR-000085 - Misuse of privileged functions, either intentionally or unintentionally by +-a always,exit -F path=/usr/bin/newgrp -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + + 1 + 12 + 13 + 14 + 15 + 16 + 2 + 3 + 5 + 6 + 7 + 8 + 9 + APO10.01 + APO10.03 + APO10.04 + APO10.05 + APO11.04 + BAI03.05 + DSS01.03 + DSS03.05 + DSS05.02 + DSS05.04 + DSS05.05 + DSS05.07 + MEA01.01 + MEA01.02 + MEA01.03 + MEA01.04 + MEA01.05 + MEA02.01 + 3.1.7 + CCI-000172 + CCI-000130 + CCI-000135 + CCI-000169 + CCI-002884 + 164.308(a)(1)(ii)(D) + 164.308(a)(3)(ii)(A) + 164.308(a)(5)(ii)(C) + 164.312(a)(2)(i) + 164.312(b) + 164.312(d) + 164.312(e) + 4.3.2.6.7 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.4.4.7 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.8 + SR 2.9 + SR 6.1 + SR 6.2 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.14.2.7 + A.15.2.1 + A.15.2.2 + CIP-004-6 R2.2.2 + CIP-004-6 R2.2.3 + CIP-007-3 R.1.3 + CIP-007-3 R5 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.3 + CIP-007-3 R5.2.1 + CIP-007-3 R5.2.3 + AC-2(4) + AU-2(d) + AU-12(c) + AC-6(9) + CM-6(a) + DE.CM-1 + DE.CM-3 + DE.CM-7 + ID.SC-4 + PR.PT-1 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-APP-000029-CTR-000085 + SRG-APP-000495-CTR-001235 + OL09-00-000580 + SV-271543r1092506_rule + Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. Auditing the use of privileged functions is one way to detect such misuse and identify the risk from insider and advanced persistent threats. - + + Privileged programs are subject to escalation-of-privilege attacks, which attempt to subvert their normal role of providing some necessary but limited capability. As such, motivation exists to monitor these programs for -unusual activity. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +unusual activity. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then ACTION_ARCH_FILTERS="-a always,exit" OTHER_FILTERS="-F path=/usr/bin/newgrp -F perm=x" @@ -101004,7 +176651,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -101020,7 +176666,7 @@ then if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -101112,7 +176758,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -101165,7 +176811,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -101259,7 +176904,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -101286,11 +176931,12 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-000580 - NIST-800-171-3.1.7 - NIST-800-53-AC-2(4) - NIST-800-53-AC-6(9) @@ -101366,6 +177012,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -101374,7 +177021,7 @@ fi line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/newgrp -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -101411,6 +177058,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -101419,13 +177067,14 @@ fi line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/newgrp -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-000580 - NIST-800-171-3.1.7 - NIST-800-53-AC-2(4) - NIST-800-53-AC-6(9) @@ -101438,17 +177087,17 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Ensure auditd Collects Information on the Use of Privileged Commands - pam_timestamp_check - At a minimum, the audit system should collect the execution of + + + + + + + + + + Ensure auditd Collects Information on the Use of Privileged Commands - pam_timestamp_check + At a minimum, the audit system should collect the execution of privileged commands for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add a line of the following form to a file with @@ -101459,101 +177108,106 @@ If the auditd daemon is configured to use the utility to read audit rules during daemon startup, add a line of the following form to /etc/audit/audit.rules: -a always,exit -F path=/usr/sbin/pam_timestamp_check --F perm=x -F auid>=1000 -F auid!=unset -F key=privileged - 1 - 12 - 13 - 14 - 15 - 16 - 2 - 3 - 5 - 6 - 7 - 8 - 9 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - BAI03.05 - DSS01.03 - DSS03.05 - DSS05.02 - DSS05.04 - DSS05.05 - DSS05.07 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.1.7 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-000172 - CCI-002884 - 164.308(a)(1)(ii)(D) - 164.308(a)(3)(ii)(A) - 164.308(a)(5)(ii)(C) - 164.312(a)(2)(i) - 164.312(b) - 164.312(d) - 164.312(e) - 4.3.2.6.7 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.4.4.7 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.8 - SR 2.9 - SR 6.1 - SR 6.2 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.14.2.7 - A.15.2.1 - A.15.2.2 - AU-2(d) - AU-12(c) - AC-6(9) - CM-6(a) - DE.CM-1 - DE.CM-3 - DE.CM-7 - ID.SC-4 - PR.PT-1 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-APP-000029-CTR-000085 - Misuse of privileged functions, either intentionally or unintentionally by +-F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + + 1 + 12 + 13 + 14 + 15 + 16 + 2 + 3 + 5 + 6 + 7 + 8 + 9 + APO10.01 + APO10.03 + APO10.04 + APO10.05 + APO11.04 + BAI03.05 + DSS01.03 + DSS03.05 + DSS05.02 + DSS05.04 + DSS05.05 + DSS05.07 + MEA01.01 + MEA01.02 + MEA01.03 + MEA01.04 + MEA01.05 + MEA02.01 + 3.1.7 + CCI-000172 + CCI-000130 + CCI-000135 + CCI-000169 + CCI-002884 + 164.308(a)(1)(ii)(D) + 164.308(a)(3)(ii)(A) + 164.308(a)(5)(ii)(C) + 164.312(a)(2)(i) + 164.312(b) + 164.312(d) + 164.312(e) + 4.3.2.6.7 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.4.4.7 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.8 + SR 2.9 + SR 6.1 + SR 6.2 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.14.2.7 + A.15.2.1 + A.15.2.2 + AU-2(d) + AU-12(c) + AC-6(9) + CM-6(a) + DE.CM-1 + DE.CM-3 + DE.CM-7 + ID.SC-4 + PR.PT-1 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-APP-000029-CTR-000085 + SRG-APP-000495-CTR-001235 + OL09-00-000585 + SV-271544r1092508_rule + Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. Auditing the use of privileged functions is one way to detect such misuse and identify the risk from insider and advanced persistent threats. - + + Privileged programs are subject to escalation-of-privilege attacks, which attempt to subvert their normal role of providing some necessary but limited capability. As such, motivation exists to monitor these programs for -unusual activity. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +unusual activity. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then ACTION_ARCH_FILTERS="-a always,exit" OTHER_FILTERS="-F path=/usr/sbin/pam_timestamp_check -F perm=x" @@ -101591,7 +177245,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -101607,7 +177260,7 @@ then if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -101699,7 +177352,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -101752,7 +177405,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -101846,7 +177498,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -101873,11 +177525,12 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-000585 - NIST-800-171-3.1.7 - NIST-800-53-AC-6(9) - NIST-800-53-AU-12(c) @@ -101953,6 +177606,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -101961,7 +177615,7 @@ fi line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/pam_timestamp_check -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -101999,6 +177653,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -102007,13 +177662,14 @@ fi line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/pam_timestamp_check -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-000585 - NIST-800-171-3.1.7 - NIST-800-53-AC-6(9) - NIST-800-53-AU-12(c) @@ -102025,17 +177681,17 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Ensure auditd Collects Information on the Use of Privileged Commands - passwd - At a minimum, the audit system should collect the execution of + + + + + + + + + + Ensure auditd Collects Information on the Use of Privileged Commands - passwd + At a minimum, the audit system should collect the execution of privileged commands for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add a line of the following form to a file with @@ -102044,111 +177700,115 @@ suffix .rules in the directory /etc/audit/rule If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add a line of the following form to /etc/audit/audit.rules: --a always,exit -F path=/usr/bin/passwd -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged - 1 - 12 - 13 - 14 - 15 - 16 - 2 - 3 - 5 - 6 - 7 - 8 - 9 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - BAI03.05 - DSS01.03 - DSS03.05 - DSS05.02 - DSS05.04 - DSS05.05 - DSS05.07 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.1.7 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-000172 - CCI-002884 - 164.308(a)(1)(ii)(D) - 164.308(a)(3)(ii)(A) - 164.308(a)(5)(ii)(C) - 164.312(a)(2)(i) - 164.312(b) - 164.312(d) - 164.312(e) - 4.3.2.6.7 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.4.4.7 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.8 - SR 2.9 - SR 6.1 - SR 6.2 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.14.2.7 - A.15.2.1 - A.15.2.2 - CIP-004-6 R2.2.2 - CIP-004-6 R2.2.3 - CIP-007-3 R.1.3 - CIP-007-3 R5 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.3 - CIP-007-3 R5.2.1 - CIP-007-3 R5.2.3 - AC-2(4) - AU-2(d) - AU-12(c) - AC-6(9) - CM-6(a) - DE.CM-1 - DE.CM-3 - DE.CM-7 - ID.SC-4 - PR.PT-1 - FAU_GEN.1.1.c - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-APP-000029-CTR-000085 - Misuse of privileged functions, either intentionally or unintentionally by +-a always,exit -F path=/usr/bin/passwd -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + + 1 + 12 + 13 + 14 + 15 + 16 + 2 + 3 + 5 + 6 + 7 + 8 + 9 + APO10.01 + APO10.03 + APO10.04 + APO10.05 + APO11.04 + BAI03.05 + DSS01.03 + DSS03.05 + DSS05.02 + DSS05.04 + DSS05.05 + DSS05.07 + MEA01.01 + MEA01.02 + MEA01.03 + MEA01.04 + MEA01.05 + MEA02.01 + 3.1.7 + CCI-000172 + CCI-000130 + CCI-000135 + CCI-000169 + CCI-002884 + 164.308(a)(1)(ii)(D) + 164.308(a)(3)(ii)(A) + 164.308(a)(5)(ii)(C) + 164.312(a)(2)(i) + 164.312(b) + 164.312(d) + 164.312(e) + 4.3.2.6.7 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.4.4.7 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.8 + SR 2.9 + SR 6.1 + SR 6.2 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.14.2.7 + A.15.2.1 + A.15.2.2 + CIP-004-6 R2.2.2 + CIP-004-6 R2.2.3 + CIP-007-3 R.1.3 + CIP-007-3 R5 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.3 + CIP-007-3 R5.2.1 + CIP-007-3 R5.2.3 + AC-2(4) + AU-2(d) + AU-12(c) + AC-6(9) + CM-6(a) + DE.CM-1 + DE.CM-3 + DE.CM-7 + ID.SC-4 + PR.PT-1 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-APP-000029-CTR-000085 + SRG-APP-000495-CTR-001235 + OL09-00-000590 + SV-271545r1092510_rule + Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. Auditing the use of privileged functions is one way to detect such misuse and identify the risk from insider and advanced persistent threats. - + + Privileged programs are subject to escalation-of-privilege attacks, which attempt to subvert their normal role of providing some necessary but limited capability. As such, motivation exists to monitor these programs for -unusual activity. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +unusual activity. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then ACTION_ARCH_FILTERS="-a always,exit" OTHER_FILTERS="-F path=/usr/bin/passwd -F perm=x" @@ -102186,7 +177846,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -102202,7 +177861,7 @@ then if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -102294,7 +177953,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -102347,7 +178006,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -102441,7 +178099,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -102468,11 +178126,12 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-000590 - NIST-800-171-3.1.7 - NIST-800-53-AC-2(4) - NIST-800-53-AC-6(9) @@ -102548,6 +178207,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -102556,7 +178216,7 @@ fi line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/passwd -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -102593,6 +178253,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -102601,13 +178262,14 @@ fi line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/passwd -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-000590 - NIST-800-171-3.1.7 - NIST-800-53-AC-2(4) - NIST-800-53-AC-6(9) @@ -102620,17 +178282,17 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Ensure auditd Collects Information on the Use of Privileged Commands - postdrop - At a minimum, the audit system should collect the execution of + + + + + + + + + + Ensure auditd Collects Information on the Use of Privileged Commands - postdrop + At a minimum, the audit system should collect the execution of privileged commands for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add a line of the following form to a file with @@ -102639,100 +178301,105 @@ suffix .rules in the directory /etc/audit/rule If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add a line of the following form to /etc/audit/audit.rules: --a always,exit -F path=/usr/sbin/postdrop -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged - 1 - 12 - 13 - 14 - 15 - 16 - 2 - 3 - 5 - 6 - 7 - 8 - 9 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - BAI03.05 - DSS01.03 - DSS03.05 - DSS05.02 - DSS05.04 - DSS05.05 - DSS05.07 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.1.7 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-000172 - CCI-002884 - 164.308(a)(1)(ii)(D) - 164.308(a)(3)(ii)(A) - 164.308(a)(5)(ii)(C) - 164.312(a)(2)(i) - 164.312(b) - 164.312(d) - 164.312(e) - 4.3.2.6.7 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.4.4.7 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.8 - SR 2.9 - SR 6.1 - SR 6.2 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.14.2.7 - A.15.2.1 - A.15.2.2 - AU-2(d) - AU-12(c) - AC-6(9) - CM-6(a) - DE.CM-1 - DE.CM-3 - DE.CM-7 - ID.SC-4 - PR.PT-1 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - Misuse of privileged functions, either intentionally or unintentionally by +-a always,exit -F path=/usr/sbin/postdrop -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + + 1 + 12 + 13 + 14 + 15 + 16 + 2 + 3 + 5 + 6 + 7 + 8 + 9 + APO10.01 + APO10.03 + APO10.04 + APO10.05 + APO11.04 + BAI03.05 + DSS01.03 + DSS03.05 + DSS05.02 + DSS05.04 + DSS05.05 + DSS05.07 + MEA01.01 + MEA01.02 + MEA01.03 + MEA01.04 + MEA01.05 + MEA02.01 + 3.1.7 + CCI-000172 + CCI-000130 + CCI-000135 + CCI-000169 + CCI-002884 + 164.308(a)(1)(ii)(D) + 164.308(a)(3)(ii)(A) + 164.308(a)(5)(ii)(C) + 164.312(a)(2)(i) + 164.312(b) + 164.312(d) + 164.312(e) + 4.3.2.6.7 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.4.4.7 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.8 + SR 2.9 + SR 6.1 + SR 6.2 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.14.2.7 + A.15.2.1 + A.15.2.2 + AU-2(d) + AU-12(c) + AC-6(9) + CM-6(a) + DE.CM-1 + DE.CM-3 + DE.CM-7 + ID.SC-4 + PR.PT-1 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-APP-000495-CTR-001235 + OL09-00-000595 + SV-271546r1092512_rule + Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. Auditing the use of privileged functions is one way to detect such misuse and identify the risk from insider and advanced persistent threats. - + + Privileged programs are subject to escalation-of-privilege attacks, which attempt to subvert their normal role of providing some necessary but limited capability. As such, motivation exists to monitor these programs for -unusual activity. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +unusual activity. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then ACTION_ARCH_FILTERS="-a always,exit" OTHER_FILTERS="-F path=/usr/sbin/postdrop -F perm=x" @@ -102770,7 +178437,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -102786,7 +178452,7 @@ then if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -102878,7 +178544,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -102931,7 +178597,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -103025,7 +178690,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -103052,11 +178717,12 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-000595 - NIST-800-171-3.1.7 - NIST-800-53-AC-6(9) - NIST-800-53-AU-12(c) @@ -103131,6 +178797,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -103139,7 +178806,7 @@ fi line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/postdrop -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -103176,6 +178843,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -103184,13 +178852,14 @@ fi line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/postdrop -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-000595 - NIST-800-171-3.1.7 - NIST-800-53-AC-6(9) - NIST-800-53-AU-12(c) @@ -103202,17 +178871,17 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Ensure auditd Collects Information on the Use of Privileged Commands - postqueue - At a minimum, the audit system should collect the execution of + + + + + + + + + + Ensure auditd Collects Information on the Use of Privileged Commands - postqueue + At a minimum, the audit system should collect the execution of privileged commands for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add a line of the following form to a file with @@ -103221,100 +178890,105 @@ suffix .rules in the directory /etc/audit/rule If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add a line of the following form to /etc/audit/audit.rules: --a always,exit -F path=/usr/sbin/postqueue -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged - 1 - 12 - 13 - 14 - 15 - 16 - 2 - 3 - 5 - 6 - 7 - 8 - 9 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - BAI03.05 - DSS01.03 - DSS03.05 - DSS05.02 - DSS05.04 - DSS05.05 - DSS05.07 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.1.7 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-000172 - CCI-002884 - 164.308(a)(1)(ii)(D) - 164.308(a)(3)(ii)(A) - 164.308(a)(5)(ii)(C) - 164.312(a)(2)(i) - 164.312(b) - 164.312(d) - 164.312(e) - 4.3.2.6.7 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.4.4.7 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.8 - SR 2.9 - SR 6.1 - SR 6.2 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.14.2.7 - A.15.2.1 - A.15.2.2 - AU-2(d) - AU-12(c) - AC-6(9) - CM-6(a) - DE.CM-1 - DE.CM-3 - DE.CM-7 - ID.SC-4 - PR.PT-1 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - Misuse of privileged functions, either intentionally or unintentionally by +-a always,exit -F path=/usr/sbin/postqueue -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + + 1 + 12 + 13 + 14 + 15 + 16 + 2 + 3 + 5 + 6 + 7 + 8 + 9 + APO10.01 + APO10.03 + APO10.04 + APO10.05 + APO11.04 + BAI03.05 + DSS01.03 + DSS03.05 + DSS05.02 + DSS05.04 + DSS05.05 + DSS05.07 + MEA01.01 + MEA01.02 + MEA01.03 + MEA01.04 + MEA01.05 + MEA02.01 + 3.1.7 + CCI-000172 + CCI-000130 + CCI-000135 + CCI-000169 + CCI-002884 + 164.308(a)(1)(ii)(D) + 164.308(a)(3)(ii)(A) + 164.308(a)(5)(ii)(C) + 164.312(a)(2)(i) + 164.312(b) + 164.312(d) + 164.312(e) + 4.3.2.6.7 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.4.4.7 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.8 + SR 2.9 + SR 6.1 + SR 6.2 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.14.2.7 + A.15.2.1 + A.15.2.2 + AU-2(d) + AU-12(c) + AC-6(9) + CM-6(a) + DE.CM-1 + DE.CM-3 + DE.CM-7 + ID.SC-4 + PR.PT-1 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-APP-000495-CTR-001235 + OL09-00-000600 + SV-271547r1092514_rule + Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. Auditing the use of privileged functions is one way to detect such misuse and identify the risk from insider and advanced persistent threats. - + + Privileged programs are subject to escalation-of-privilege attacks, which attempt to subvert their normal role of providing some necessary but limited capability. As such, motivation exists to monitor these programs for -unusual activity. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +unusual activity. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then ACTION_ARCH_FILTERS="-a always,exit" OTHER_FILTERS="-F path=/usr/sbin/postqueue -F perm=x" @@ -103352,7 +179026,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -103368,7 +179041,7 @@ then if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -103460,7 +179133,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -103513,7 +179186,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -103607,7 +179279,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -103634,11 +179306,12 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-000600 - NIST-800-171-3.1.7 - NIST-800-53-AC-6(9) - NIST-800-53-AU-12(c) @@ -103713,6 +179386,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -103721,7 +179395,7 @@ fi line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/postqueue -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -103758,6 +179432,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -103766,13 +179441,14 @@ fi line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/postqueue -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-000600 - NIST-800-171-3.1.7 - NIST-800-53-AC-6(9) - NIST-800-53-AU-12(c) @@ -103784,587 +179460,17 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Ensure auditd Collects Information on the Use of Privileged Commands - pt_chown - At a minimum, the audit system should collect the execution of -privileged commands for all users and root. If the auditd daemon is -configured to use the augenrules program to read audit rules during -daemon startup (the default), add a line of the following form to a file with -suffix .rules in the directory /etc/audit/rules.d: --a always,exit -F path=/usr/libexec/pt_chown -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged -If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add a line of the following -form to /etc/audit/audit.rules: --a always,exit -F path=/usr/libexec/pt_chown -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged - 1 - 12 - 13 - 14 - 15 - 16 - 2 - 3 - 5 - 6 - 7 - 8 - 9 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - BAI03.05 - DSS01.03 - DSS03.05 - DSS05.02 - DSS05.04 - DSS05.05 - DSS05.07 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.1.7 - CCI-000135 - CCI-000172 - CCI-002884 - 4.3.2.6.7 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.4.4.7 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.8 - SR 2.9 - SR 6.1 - SR 6.2 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.14.2.7 - A.15.2.1 - A.15.2.2 - AU-2(d) - AU-12(c) - AC-6(9) - CM-6(a) - DE.CM-1 - DE.CM-3 - DE.CM-7 - ID.SC-4 - PR.PT-1 - SRG-OS-000042-GPOS-00020 - SRG-OS-000392-GPOS-00172 - SRG-OS-000471-GPOS-00215 - Misuse of privileged functions, either intentionally or unintentionally by -authorized users, or by unauthorized external entities that have compromised system accounts, -is a serious and ongoing concern and can have significant adverse impacts on organizations. -Auditing the use of privileged functions is one way to detect such misuse and identify -the risk from insider and advanced persistent threats. - -Privileged programs are subject to escalation-of-privilege attacks, -which attempt to subvert their normal role of providing some necessary but -limited capability. As such, motivation exists to monitor these programs for -unusual activity. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then - -ACTION_ARCH_FILTERS="-a always,exit" -OTHER_FILTERS="-F path=/usr/libexec/pt_chown -F perm=x" -AUID_FILTERS="-F auid>=1000 -F auid!=unset" -SYSCALL="" -KEY="privileged" -SYSCALL_GROUPING="" -# Perform the remediation for both possible tools: 'auditctl' and 'augenrules' -unset syscall_a -unset syscall_grouping -unset syscall_string -unset syscall -unset file_to_edit -unset rule_to_edit -unset rule_syscalls_to_edit -unset other_string -unset auid_string -unset full_rule - -# Load macro arguments into arrays -read -a syscall_a <<< $SYSCALL -read -a syscall_grouping <<< $SYSCALL_GROUPING - -# Create a list of audit *.rules files that should be inspected for presence and correctness -# of a particular audit rule. The scheme is as follows: -# -# ----------------------------------------------------------------------------------------- -# Tool used to load audit rules | Rule already defined | Audit rules file to inspect | -# ----------------------------------------------------------------------------------------- -# auditctl | Doesn't matter | /etc/audit/audit.rules | -# ----------------------------------------------------------------------------------------- -# augenrules | Yes | /etc/audit/rules.d/*.rules | -# augenrules | No | /etc/audit/rules.d/$key.rules | -# ----------------------------------------------------------------------------------------- -# -files_to_inspect=() - - -# If audit tool is 'augenrules', then check if the audit rule is defined -# If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection -# If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection -default_file="/etc/audit/rules.d/$KEY.rules" -# As other_filters may include paths, lets use a different delimiter for it -# The "F" script expression tells sed to print the filenames where the expressions matched -readarray -t files_to_inspect < <(sed -s -n -e "/^$ACTION_ARCH_FILTERS/!d" -e "\#$OTHER_FILTERS#!d" -e "/$AUID_FILTERS/!d" -e "F" /etc/audit/rules.d/*.rules) -# Case when particular rule isn't defined in /etc/audit/rules.d/*.rules yet -if [ ${#files_to_inspect[@]} -eq "0" ] -then - file_to_inspect="/etc/audit/rules.d/$KEY.rules" - files_to_inspect=("$file_to_inspect") - if [ ! -e "$file_to_inspect" ] - then - touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" - fi -fi - -# After converting to jinja, we cannot return; therefore we skip the rest of the macro if needed instead -skip=1 - -for audit_file in "${files_to_inspect[@]}" -do - # Filter existing $audit_file rules' definitions to select those that satisfy the rule pattern, - # i.e, collect rules that match: - # * the action, list and arch, (2-nd argument) - # * the other filters, (3-rd argument) - # * the auid filters, (4-rd argument) - readarray -t similar_rules < <(sed -e "/^$ACTION_ARCH_FILTERS/!d" -e "\#$OTHER_FILTERS#!d" -e "/$AUID_FILTERS/!d" "$audit_file") - - candidate_rules=() - # Filter out rules that have more fields then required. This will remove rules more specific than the required scope - for s_rule in "${similar_rules[@]}" - do - # Strip all the options and fields we know of, - # than check if there was any field left over - extra_fields=$(sed -E -e "s/^$ACTION_ARCH_FILTERS//" -e "s#$OTHER_FILTERS##" -e "s/$AUID_FILTERS//" -e "s/((:?-S [[:alnum:],]+)+)//g" -e "s/-F key=\w+|-k \w+//"<<< "$s_rule") - grep -q -- "-F" <<< "$extra_fields" || candidate_rules+=("$s_rule") - done - - if [[ ${#syscall_a[@]} -ge 1 ]] - then - # Check if the syscall we want is present in any of the similar existing rules - for rule in "${candidate_rules[@]}" - do - rule_syscalls=$(echo "$rule" | grep -o -P '(-S [\w,]+)+' | xargs) - all_syscalls_found=0 - for syscall in "${syscall_a[@]}" - do - grep -q -- "\b${syscall}\b" <<< "$rule_syscalls" || { - # A syscall was not found in the candidate rule - all_syscalls_found=1 - } - done - if [[ $all_syscalls_found -eq 0 ]] - then - # We found a rule with all the syscall(s) we want; skip rest of macro - skip=0 - break - fi - - # Check if this rule can be grouped with our target syscall and keep track of it - for syscall_g in "${syscall_grouping[@]}" - do - if grep -q -- "\b${syscall_g}\b" <<< "$rule_syscalls" - then - file_to_edit=${audit_file} - rule_to_edit=${rule} - rule_syscalls_to_edit=${rule_syscalls} - fi - done - done - else - # If there is any candidate rule, it is compliant; skip rest of macro - if [ "${#candidate_rules[@]}" -gt 0 ] - then - skip=0 - fi - fi - - if [ "$skip" -eq 0 ]; then - break - fi -done - -if [ "$skip" -ne 0 ]; then - # We checked all rules that matched the expected resemblance pattern (action, arch & auid) - # At this point we know if we need to either append the $full_rule or group - # the syscall together with an exsiting rule - - # Append the full_rule if it cannot be grouped to any other rule - if [ -z ${rule_to_edit+x} ] - then - # Build full_rule while avoid adding double spaces when other_filters is empty - if [ "${#syscall_a[@]}" -gt 0 ] - then - syscall_string="" - for syscall in "${syscall_a[@]}" - do - syscall_string+=" -S $syscall" - done - fi - other_string=$([[ $OTHER_FILTERS ]] && echo " $OTHER_FILTERS") || /bin/true - auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true - full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true - echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} - else - # Check if the syscalls are declared as a comma separated list or - # as multiple -S parameters - if grep -q -- "," <<< "${rule_syscalls_to_edit}" - then - delimiter="," - else - delimiter=" -S " - fi - new_grouped_syscalls="${rule_syscalls_to_edit}" - for syscall in "${syscall_a[@]}" - do - grep -q -- "\b${syscall}\b" <<< "${rule_syscalls_to_edit}" || { - # A syscall was not found in the candidate rule - new_grouped_syscalls+="${delimiter}${syscall}" - } - done - - # Group the syscall in the rule - sed -i -e "\#${rule_to_edit}#s#${rule_syscalls_to_edit}#${new_grouped_syscalls}#" "$file_to_edit" - fi -fi -unset syscall_a -unset syscall_grouping -unset syscall_string -unset syscall -unset file_to_edit -unset rule_to_edit -unset rule_syscalls_to_edit -unset other_string -unset auid_string -unset full_rule - -# Load macro arguments into arrays -read -a syscall_a <<< $SYSCALL -read -a syscall_grouping <<< $SYSCALL_GROUPING - -# Create a list of audit *.rules files that should be inspected for presence and correctness -# of a particular audit rule. The scheme is as follows: -# -# ----------------------------------------------------------------------------------------- -# Tool used to load audit rules | Rule already defined | Audit rules file to inspect | -# ----------------------------------------------------------------------------------------- -# auditctl | Doesn't matter | /etc/audit/audit.rules | -# ----------------------------------------------------------------------------------------- -# augenrules | Yes | /etc/audit/rules.d/*.rules | -# augenrules | No | /etc/audit/rules.d/$key.rules | -# ----------------------------------------------------------------------------------------- -# -files_to_inspect=() - - - -# If audit tool is 'auditctl', then add '/etc/audit/audit.rules' -# file to the list of files to be inspected -default_file="/etc/audit/audit.rules" -files_to_inspect+=('/etc/audit/audit.rules' ) - -# After converting to jinja, we cannot return; therefore we skip the rest of the macro if needed instead -skip=1 - -for audit_file in "${files_to_inspect[@]}" -do - # Filter existing $audit_file rules' definitions to select those that satisfy the rule pattern, - # i.e, collect rules that match: - # * the action, list and arch, (2-nd argument) - # * the other filters, (3-rd argument) - # * the auid filters, (4-rd argument) - readarray -t similar_rules < <(sed -e "/^$ACTION_ARCH_FILTERS/!d" -e "\#$OTHER_FILTERS#!d" -e "/$AUID_FILTERS/!d" "$audit_file") - - candidate_rules=() - # Filter out rules that have more fields then required. This will remove rules more specific than the required scope - for s_rule in "${similar_rules[@]}" - do - # Strip all the options and fields we know of, - # than check if there was any field left over - extra_fields=$(sed -E -e "s/^$ACTION_ARCH_FILTERS//" -e "s#$OTHER_FILTERS##" -e "s/$AUID_FILTERS//" -e "s/((:?-S [[:alnum:],]+)+)//g" -e "s/-F key=\w+|-k \w+//"<<< "$s_rule") - grep -q -- "-F" <<< "$extra_fields" || candidate_rules+=("$s_rule") - done - - if [[ ${#syscall_a[@]} -ge 1 ]] - then - # Check if the syscall we want is present in any of the similar existing rules - for rule in "${candidate_rules[@]}" - do - rule_syscalls=$(echo "$rule" | grep -o -P '(-S [\w,]+)+' | xargs) - all_syscalls_found=0 - for syscall in "${syscall_a[@]}" - do - grep -q -- "\b${syscall}\b" <<< "$rule_syscalls" || { - # A syscall was not found in the candidate rule - all_syscalls_found=1 - } - done - if [[ $all_syscalls_found -eq 0 ]] - then - # We found a rule with all the syscall(s) we want; skip rest of macro - skip=0 - break - fi - - # Check if this rule can be grouped with our target syscall and keep track of it - for syscall_g in "${syscall_grouping[@]}" - do - if grep -q -- "\b${syscall_g}\b" <<< "$rule_syscalls" - then - file_to_edit=${audit_file} - rule_to_edit=${rule} - rule_syscalls_to_edit=${rule_syscalls} - fi - done - done - else - # If there is any candidate rule, it is compliant; skip rest of macro - if [ "${#candidate_rules[@]}" -gt 0 ] - then - skip=0 - fi - fi - - if [ "$skip" -eq 0 ]; then - break - fi -done - -if [ "$skip" -ne 0 ]; then - # We checked all rules that matched the expected resemblance pattern (action, arch & auid) - # At this point we know if we need to either append the $full_rule or group - # the syscall together with an exsiting rule - - # Append the full_rule if it cannot be grouped to any other rule - if [ -z ${rule_to_edit+x} ] - then - # Build full_rule while avoid adding double spaces when other_filters is empty - if [ "${#syscall_a[@]}" -gt 0 ] - then - syscall_string="" - for syscall in "${syscall_a[@]}" - do - syscall_string+=" -S $syscall" - done - fi - other_string=$([[ $OTHER_FILTERS ]] && echo " $OTHER_FILTERS") || /bin/true - auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true - full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true - echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} - else - # Check if the syscalls are declared as a comma separated list or - # as multiple -S parameters - if grep -q -- "," <<< "${rule_syscalls_to_edit}" - then - delimiter="," - else - delimiter=" -S " - fi - new_grouped_syscalls="${rule_syscalls_to_edit}" - for syscall in "${syscall_a[@]}" - do - grep -q -- "\b${syscall}\b" <<< "${rule_syscalls_to_edit}" || { - # A syscall was not found in the candidate rule - new_grouped_syscalls+="${delimiter}${syscall}" - } - done - - # Group the syscall in the rule - sed -i -e "\#${rule_to_edit}#s#${rule_syscalls_to_edit}#${new_grouped_syscalls}#" "$file_to_edit" - fi -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Gather the package facts - package_facts: - manager: auto - tags: - - NIST-800-171-3.1.7 - - NIST-800-53-AC-6(9) - - NIST-800-53-AU-12(c) - - NIST-800-53-AU-2(d) - - NIST-800-53-CM-6(a) - - audit_rules_privileged_commands_pt_chown - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - -- name: Perform remediation of Audit rules for /usr/libexec/pt_chown - block: - - - name: Declare list of syscalls - set_fact: - syscalls: [] - syscall_grouping: [] - - - name: Check existence of in /etc/audit/rules.d/ - find: - paths: /etc/audit/rules.d - contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F - path=/usr/libexec/pt_chown -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ - patterns: '*.rules' - register: find_command - loop: '{{ (syscall_grouping + syscalls) | unique }}' - - - name: Reset syscalls found per file - set_fact: - syscalls_per_file: {} - found_paths_dict: {} - - - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path - :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" - loop: '{{ find_command.results | selectattr(''matched'') | list }}' - - - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" - - - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, - 0) }) }}" - loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') - | list }}' - - - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') - | last).key }}" - when: found_paths | length >= 1 - - - name: No file with syscall found, set path to /etc/audit/rules.d/privileged.rules - set_fact: audit_file="/etc/audit/rules.d/privileged.rules" - when: found_paths | length == 0 - - - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" - - - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" - - - name: Replace the audit rule in {{ audit_file }} - lineinfile: - path: '{{ audit_file }}' - regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] - | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/libexec/pt_chown -F perm=x - -F auid>=1000 -F auid!=unset (?:-k |-F key=)\w+) - line: \1\2\3{{ missing_syscalls | join("\3") }}\4 - backrefs: true - state: present - when: syscalls_found | length > 0 and missing_syscalls | length > 0 - - - name: Add the audit rule to {{ audit_file }} - lineinfile: - path: '{{ audit_file }}' - line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/libexec/pt_chown - -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged - create: true - mode: o-rwx - state: present - when: syscalls_found | length == 0 - - - name: Declare list of syscalls - set_fact: - syscalls: [] - syscall_grouping: [] - - - name: Check existence of in /etc/audit/audit.rules - find: - paths: /etc/audit - contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F - path=/usr/libexec/pt_chown -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ - patterns: audit.rules - register: find_command - loop: '{{ (syscall_grouping + syscalls) | unique }}' - - - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" - - - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" - - - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" - - - name: Replace the audit rule in {{ audit_file }} - lineinfile: - path: '{{ audit_file }}' - regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( - -S |,)\w+)+)( -F path=/usr/libexec/pt_chown -F perm=x -F auid>=1000 -F auid!=unset - (?:-k |-F key=)\w+) - line: \1\2\3{{ missing_syscalls | join("\3") }}\4 - backrefs: true - state: present - when: syscalls_found | length > 0 and missing_syscalls | length > 0 - - - name: Add the audit rule to {{ audit_file }} - lineinfile: - path: '{{ audit_file }}' - line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/libexec/pt_chown - -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged - create: true - mode: o-rwx - state: present - when: syscalls_found | length == 0 - when: - - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.7 - - NIST-800-53-AC-6(9) - - NIST-800-53-AU-12(c) - - NIST-800-53-AU-2(d) - - NIST-800-53-CM-6(a) - - audit_rules_privileged_commands_pt_chown - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - - - - - - - - - Record Any Attempts to Run ssh-agent - At a minimum, the audit system should collect any execution attempt + + + + + + + + + + Record Any Attempts to Run ssh-agent + At a minimum, the audit system should collect any execution attempt of the ssh-agent command for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following lines to a file with suffix @@ -104373,27 +179479,31 @@ during daemon startup (the default), add the following lines to a file with suff If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following lines to /etc/audit/audit.rules file: --a always,exit -F path=/usr/bin/ssh-agent -F perm=x -F auid>=1000 -F auid!=unset -k privileged-ssh-agent - CCI-000130 - CCI-000135 - CCI-000169 - CCI-000172 - CCI-002884 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - Without generating audit records that are specific to the security and +-a always,exit -F path=/usr/bin/ssh-agent -F perm=x -F auid>=1000 -F auid!=unset -k privileged-ssh-agent + + CCI-000172 + CCI-000130 + CCI-000135 + CCI-000169 + CCI-002884 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-APP-000495-CTR-001235 + OL09-00-000605 + SV-271548r1092516_rule + Without generating audit records that are specific to the security and mission needs of the organization, it would be difficult to establish, correlate, and investigate the events relating to an incident or identify those responsible for one. Audit records can be generated from various components within the -information system (e.g., module or policy filter). - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +information system (e.g., module or policy filter). + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then ACTION_ARCH_FILTERS="-a always,exit" OTHER_FILTERS="-F path=/usr/bin/ssh-agent -F perm=x" @@ -104431,7 +179541,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -104447,7 +179556,7 @@ then if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -104539,7 +179648,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -104592,7 +179701,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -104686,7 +179794,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -104713,11 +179821,12 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-000605 - audit_rules_privileged_commands_ssh_agent - low_complexity - low_disruption @@ -104787,6 +179896,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -104795,7 +179905,7 @@ fi line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/ssh-agent -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -104832,6 +179942,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -104840,30 +179951,31 @@ fi line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/ssh-agent -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-000605 - audit_rules_privileged_commands_ssh_agent - low_complexity - low_disruption - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Ensure auditd Collects Information on the Use of Privileged Commands - ssh-keysign - At a minimum, the audit system should collect the execution of + + + + + + + + + + Ensure auditd Collects Information on the Use of Privileged Commands - ssh-keysign + At a minimum, the audit system should collect the execution of privileged commands for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add a line of the following form to a file with @@ -104872,102 +179984,106 @@ suffix .rules in the directory /etc/audit/rule If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add a line of the following form to /etc/audit/audit.rules: --a always,exit -F path=/usr/libexec/openssh/ssh-keysign -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged - 1 - 12 - 13 - 14 - 15 - 16 - 2 - 3 - 5 - 6 - 7 - 8 - 9 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - BAI03.05 - DSS01.03 - DSS03.05 - DSS05.02 - DSS05.04 - DSS05.05 - DSS05.07 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.1.7 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-000172 - CCI-002884 - 164.308(a)(1)(ii)(D) - 164.308(a)(3)(ii)(A) - 164.308(a)(5)(ii)(C) - 164.312(a)(2)(i) - 164.312(b) - 164.312(d) - 164.312(e) - 4.3.2.6.7 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.4.4.7 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.8 - SR 2.9 - SR 6.1 - SR 6.2 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.14.2.7 - A.15.2.1 - A.15.2.2 - AU-2(d) - AU-12(c) - AC-6(9) - CM-6(a) - DE.CM-1 - DE.CM-3 - DE.CM-7 - ID.SC-4 - PR.PT-1 - FAU_GEN.1.1.c - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-APP-000029-CTR-000085 - Misuse of privileged functions, either intentionally or unintentionally by +-a always,exit -F path=/usr/libexec/openssh/ssh-keysign -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + + 1 + 12 + 13 + 14 + 15 + 16 + 2 + 3 + 5 + 6 + 7 + 8 + 9 + APO10.01 + APO10.03 + APO10.04 + APO10.05 + APO11.04 + BAI03.05 + DSS01.03 + DSS03.05 + DSS05.02 + DSS05.04 + DSS05.05 + DSS05.07 + MEA01.01 + MEA01.02 + MEA01.03 + MEA01.04 + MEA01.05 + MEA02.01 + 3.1.7 + CCI-000172 + CCI-000130 + CCI-000135 + CCI-000169 + CCI-002884 + 164.308(a)(1)(ii)(D) + 164.308(a)(3)(ii)(A) + 164.308(a)(5)(ii)(C) + 164.312(a)(2)(i) + 164.312(b) + 164.312(d) + 164.312(e) + 4.3.2.6.7 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.4.4.7 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.8 + SR 2.9 + SR 6.1 + SR 6.2 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.14.2.7 + A.15.2.1 + A.15.2.2 + AU-2(d) + AU-12(c) + AC-6(9) + CM-6(a) + DE.CM-1 + DE.CM-3 + DE.CM-7 + ID.SC-4 + PR.PT-1 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-APP-000029-CTR-000085 + SRG-APP-000495-CTR-001235 + OL09-00-000610 + SV-271549r1092518_rule + Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. Auditing the use of privileged functions is one way to detect such misuse and identify the risk from insider and advanced persistent threats. - + + Privileged programs are subject to escalation-of-privilege attacks, which attempt to subvert their normal role of providing some necessary but limited capability. As such, motivation exists to monitor these programs for -unusual activity. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +unusual activity. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then ACTION_ARCH_FILTERS="-a always,exit" OTHER_FILTERS="-F path=/usr/libexec/openssh/ssh-keysign -F perm=x" @@ -105005,7 +180121,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -105021,7 +180136,7 @@ then if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -105113,7 +180228,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -105166,7 +180281,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -105260,7 +180374,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -105287,11 +180401,12 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-000610 - NIST-800-171-3.1.7 - NIST-800-53-AC-6(9) - NIST-800-53-AU-12(c) @@ -105367,6 +180482,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -105375,7 +180491,7 @@ fi line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/libexec/openssh/ssh-keysign -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -105413,6 +180529,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -105421,13 +180538,14 @@ fi line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/libexec/openssh/ssh-keysign -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-000610 - NIST-800-171-3.1.7 - NIST-800-53-AC-6(9) - NIST-800-53-AU-12(c) @@ -105439,17 +180557,17 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Ensure auditd Collects Information on the Use of Privileged Commands - su - At a minimum, the audit system should collect the execution of + + + + + + + + + + Ensure auditd Collects Information on the Use of Privileged Commands - su + At a minimum, the audit system should collect the execution of privileged commands for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add a line of the following form to a file with @@ -105458,104 +180576,110 @@ suffix .rules in the directory /etc/audit/rule If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add a line of the following form to /etc/audit/audit.rules: --a always,exit -F path=/usr/bin/su -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged - 1 - 12 - 13 - 14 - 15 - 16 - 2 - 3 - 5 - 6 - 7 - 8 - 9 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - BAI03.05 - DSS01.03 - DSS03.05 - DSS05.02 - DSS05.04 - DSS05.05 - DSS05.07 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.1.7 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-000172 - CCI-002884 - 164.308(a)(1)(ii)(D) - 164.308(a)(3)(ii)(A) - 164.308(a)(5)(ii)(C) - 164.312(a)(2)(i) - 164.312(b) - 164.312(d) - 164.312(e) - 4.3.2.6.7 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.4.4.7 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.8 - SR 2.9 - SR 6.1 - SR 6.2 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.14.2.7 - A.15.2.1 - A.15.2.2 - AU-2(d) - AU-12(c) - AC-6(9) - CM-6(a) - DE.CM-1 - DE.CM-3 - DE.CM-7 - ID.SC-4 - PR.PT-1 - FAU_GEN.1.1.c - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000064-GPOS-0003 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-OS-000466-GPOS-00210 - SRG-APP-000029-CTR-000085 - Misuse of privileged functions, either intentionally or unintentionally by +-a always,exit -F path=/usr/bin/su -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + + 1 + 12 + 13 + 14 + 15 + 16 + 2 + 3 + 5 + 6 + 7 + 8 + 9 + APO10.01 + APO10.03 + APO10.04 + APO10.05 + APO11.04 + BAI03.05 + DSS01.03 + DSS03.05 + DSS05.02 + DSS05.04 + DSS05.05 + DSS05.07 + MEA01.01 + MEA01.02 + MEA01.03 + MEA01.04 + MEA01.05 + MEA02.01 + 3.1.7 + CCI-000172 + CCI-000130 + CCI-000135 + CCI-000169 + CCI-002884 + 164.308(a)(1)(ii)(D) + 164.308(a)(3)(ii)(A) + 164.308(a)(5)(ii)(C) + 164.312(a)(2)(i) + 164.312(b) + 164.312(d) + 164.312(e) + 4.3.2.6.7 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.4.4.7 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.8 + SR 2.9 + SR 6.1 + SR 6.2 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.14.2.7 + A.15.2.1 + A.15.2.2 + AU-2(d) + AU-12(c) + AC-6(9) + CM-6(a) + DE.CM-1 + DE.CM-3 + DE.CM-7 + ID.SC-4 + PR.PT-1 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000064-GPOS-0003 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-OS-000466-GPOS-00210 + SRG-APP-000029-CTR-000085 + SRG-APP-000495-CTR-001235 + SRG-APP-000499-CTR-001255 + SRG-OS-000755-GPOS-00220 + OL09-00-000540 + SV-271535r1092490_rule + Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. Auditing the use of privileged functions is one way to detect such misuse and identify the risk from insider and advanced persistent threats. - + + Privileged programs are subject to escalation-of-privilege attacks, which attempt to subvert their normal role of providing some necessary but limited capability. As such, motivation exists to monitor these programs for -unusual activity. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +unusual activity. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then ACTION_ARCH_FILTERS="-a always,exit" OTHER_FILTERS="-F path=/usr/bin/su -F perm=x" @@ -105593,7 +180717,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -105609,7 +180732,7 @@ then if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -105701,7 +180824,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -105754,7 +180877,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -105848,7 +180970,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -105875,11 +180997,12 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-000540 - NIST-800-171-3.1.7 - NIST-800-53-AC-6(9) - NIST-800-53-AU-12(c) @@ -105954,6 +181077,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -105962,7 +181086,7 @@ fi line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/su -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -105999,6 +181123,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -106007,13 +181132,14 @@ fi line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/su -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-000540 - NIST-800-171-3.1.7 - NIST-800-53-AC-6(9) - NIST-800-53-AU-12(c) @@ -106025,17 +181151,17 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Ensure auditd Collects Information on the Use of Privileged Commands - sudo - At a minimum, the audit system should collect the execution of + + + + + + + + + + Ensure auditd Collects Information on the Use of Privileged Commands - sudo + At a minimum, the audit system should collect the execution of privileged commands for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add a line of the following form to a file with @@ -106044,104 +181170,110 @@ suffix .rules in the directory /etc/audit/rule If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add a line of the following form to /etc/audit/audit.rules: --a always,exit -F path=/usr/bin/sudo -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged - BP28(R19) - 1 - 12 - 13 - 14 - 15 - 16 - 2 - 3 - 5 - 6 - 7 - 8 - 9 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - BAI03.05 - DSS01.03 - DSS03.05 - DSS05.02 - DSS05.04 - DSS05.05 - DSS05.07 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.1.7 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-000172 - CCI-002884 - 164.308(a)(1)(ii)(D) - 164.308(a)(3)(ii)(A) - 164.308(a)(5)(ii)(C) - 164.312(a)(2)(i) - 164.312(b) - 164.312(d) - 164.312(e) - 4.3.2.6.7 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.4.4.7 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.8 - SR 2.9 - SR 6.1 - SR 6.2 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.14.2.7 - A.15.2.1 - A.15.2.2 - AU-2(d) - AU-12(c) - AC-6(9) - CM-6(a) - DE.CM-1 - DE.CM-3 - DE.CM-7 - ID.SC-4 - PR.PT-1 - FAU_GEN.1.1.c - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-OS-000466-GPOS-00210 - SRG-APP-000029-CTR-000085 - Misuse of privileged functions, either intentionally or unintentionally by +-a always,exit -F path=/usr/bin/sudo -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + + 1 + 12 + 13 + 14 + 15 + 16 + 2 + 3 + 5 + 6 + 7 + 8 + 9 + APO10.01 + APO10.03 + APO10.04 + APO10.05 + APO11.04 + BAI03.05 + DSS01.03 + DSS03.05 + DSS05.02 + DSS05.04 + DSS05.05 + DSS05.07 + MEA01.01 + MEA01.02 + MEA01.03 + MEA01.04 + MEA01.05 + MEA02.01 + 3.1.7 + CCI-000172 + CCI-000130 + CCI-000135 + CCI-000169 + CCI-002884 + 164.308(a)(1)(ii)(D) + 164.308(a)(3)(ii)(A) + 164.308(a)(5)(ii)(C) + 164.312(a)(2)(i) + 164.312(b) + 164.312(d) + 164.312(e) + 4.3.2.6.7 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.4.4.7 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.8 + SR 2.9 + SR 6.1 + SR 6.2 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.14.2.7 + A.15.2.1 + A.15.2.2 + AU-2(d) + AU-12(c) + AC-6(9) + CM-6(a) + DE.CM-1 + DE.CM-3 + DE.CM-7 + ID.SC-4 + PR.PT-1 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-OS-000466-GPOS-00210 + SRG-APP-000029-CTR-000085 + SRG-APP-000495-CTR-001235 + SRG-APP-000499-CTR-001255 + SRG-OS-000755-GPOS-00220 + R33 + OL09-00-000670 + SV-271561r1092542_rule + Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. Auditing the use of privileged functions is one way to detect such misuse and identify the risk from insider and advanced persistent threats. - + + Privileged programs are subject to escalation-of-privilege attacks, which attempt to subvert their normal role of providing some necessary but limited capability. As such, motivation exists to monitor these programs for -unusual activity. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +unusual activity. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then ACTION_ARCH_FILTERS="-a always,exit" OTHER_FILTERS="-F path=/usr/bin/sudo -F perm=x" @@ -106179,7 +181311,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -106195,7 +181326,7 @@ then if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -106287,7 +181418,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -106340,7 +181471,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -106434,7 +181564,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -106461,11 +181591,12 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-000670 - NIST-800-171-3.1.7 - NIST-800-53-AC-6(9) - NIST-800-53-AU-12(c) @@ -106540,6 +181671,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -106548,7 +181680,7 @@ fi line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/sudo -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -106585,6 +181717,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -106593,13 +181726,14 @@ fi line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/sudo -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-000670 - NIST-800-171-3.1.7 - NIST-800-53-AC-6(9) - NIST-800-53-AU-12(c) @@ -106611,17 +181745,17 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Ensure auditd Collects Information on the Use of Privileged Commands - sudoedit - At a minimum, the audit system should collect the execution of + + + + + + + + + + Ensure auditd Collects Information on the Use of Privileged Commands - sudoedit + At a minimum, the audit system should collect the execution of privileged commands for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add a line of the following form to a file with @@ -106630,101 +181764,106 @@ suffix .rules in the directory /etc/audit/rule If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add a line of the following form to /etc/audit/audit.rules: --a always,exit -F path=/usr/bin/sudoedit -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged - 1 - 12 - 13 - 14 - 15 - 16 - 2 - 3 - 5 - 6 - 7 - 8 - 9 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - BAI03.05 - DSS01.03 - DSS03.05 - DSS05.02 - DSS05.04 - DSS05.05 - DSS05.07 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.1.7 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-000172 - CCI-002884 - 164.308(a)(1)(ii)(D) - 164.308(a)(3)(ii)(A) - 164.308(a)(5)(ii)(C) - 164.312(a)(2)(i) - 164.312(b) - 164.312(d) - 164.312(e) - 4.3.2.6.7 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.4.4.7 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.8 - SR 2.9 - SR 6.1 - SR 6.2 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.14.2.7 - A.15.2.1 - A.15.2.2 - AU-2(d) - AU-12(c) - AC-6(9) - CM-6(a) - DE.CM-1 - DE.CM-3 - DE.CM-7 - ID.SC-4 - PR.PT-1 - FAU_GEN.1.1.c - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - Misuse of privileged functions, either intentionally or unintentionally by +-a always,exit -F path=/usr/bin/sudoedit -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + + 1 + 12 + 13 + 14 + 15 + 16 + 2 + 3 + 5 + 6 + 7 + 8 + 9 + APO10.01 + APO10.03 + APO10.04 + APO10.05 + APO11.04 + BAI03.05 + DSS01.03 + DSS03.05 + DSS05.02 + DSS05.04 + DSS05.05 + DSS05.07 + MEA01.01 + MEA01.02 + MEA01.03 + MEA01.04 + MEA01.05 + MEA02.01 + 3.1.7 + CCI-000172 + CCI-000130 + CCI-000135 + CCI-000169 + CCI-002884 + 164.308(a)(1)(ii)(D) + 164.308(a)(3)(ii)(A) + 164.308(a)(5)(ii)(C) + 164.312(a)(2)(i) + 164.312(b) + 164.312(d) + 164.312(e) + 4.3.2.6.7 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.4.4.7 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.8 + SR 2.9 + SR 6.1 + SR 6.2 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.14.2.7 + A.15.2.1 + A.15.2.2 + AU-2(d) + AU-12(c) + AC-6(9) + CM-6(a) + DE.CM-1 + DE.CM-3 + DE.CM-7 + ID.SC-4 + PR.PT-1 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-APP-000495-CTR-001235 + SRG-OS-000755-GPOS-00220 + OL09-00-000615 + SV-271550r1092520_rule + Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. Auditing the use of privileged functions is one way to detect such misuse and identify the risk from insider and advanced persistent threats. - + + Privileged programs are subject to escalation-of-privilege attacks, which attempt to subvert their normal role of providing some necessary but limited capability. As such, motivation exists to monitor these programs for -unusual activity. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +unusual activity. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then ACTION_ARCH_FILTERS="-a always,exit" OTHER_FILTERS="-F path=/usr/bin/sudoedit -F perm=x" @@ -106762,7 +181901,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -106778,7 +181916,7 @@ then if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -106870,7 +182008,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -106923,7 +182061,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -107017,7 +182154,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -107044,11 +182181,12 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-000615 - NIST-800-171-3.1.7 - NIST-800-53-AC-6(9) - NIST-800-53-AU-12(c) @@ -107123,6 +182261,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -107131,7 +182270,7 @@ fi line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/sudoedit -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -107168,6 +182307,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -107176,13 +182316,14 @@ fi line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/sudoedit -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-000615 - NIST-800-171-3.1.7 - NIST-800-53-AC-6(9) - NIST-800-53-AU-12(c) @@ -107194,17 +182335,17 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Ensure auditd Collects Information on the Use of Privileged Commands - umount - At a minimum, the audit system should collect the execution of + + + + + + + + + + Ensure auditd Collects Information on the Use of Privileged Commands - umount + At a minimum, the audit system should collect the execution of privileged commands for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add a line of the following form to a file with @@ -107213,101 +182354,104 @@ suffix .rules in the directory /etc/audit/rule If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add a line of the following form to /etc/audit/audit.rules: --a always,exit -F path=/usr/bin/umount -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged - 1 - 12 - 13 - 14 - 15 - 16 - 2 - 3 - 5 - 6 - 7 - 8 - 9 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - BAI03.05 - DSS01.03 - DSS03.05 - DSS05.02 - DSS05.04 - DSS05.05 - DSS05.07 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.1.7 - CCI-000130 - CCI-000169 - CCI-000135 - CCI-000172 - CCI-002884 - 164.308(a)(1)(ii)(D) - 164.308(a)(3)(ii)(A) - 164.308(a)(5)(ii)(C) - 164.312(a)(2)(i) - 164.312(b) - 164.312(d) - 164.312(e) - 4.3.2.6.7 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.4.4.7 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.8 - SR 2.9 - SR 6.1 - SR 6.2 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.14.2.7 - A.15.2.1 - A.15.2.2 - AU-2(d) - AU-12(c) - AC-6(9) - CM-6(a) - DE.CM-1 - DE.CM-3 - DE.CM-7 - ID.SC-4 - PR.PT-1 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-APP-000029-CTR-000085 - Misuse of privileged functions, either intentionally or unintentionally by +-a always,exit -F path=/usr/bin/umount -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + + 1 + 12 + 13 + 14 + 15 + 16 + 2 + 3 + 5 + 6 + 7 + 8 + 9 + APO10.01 + APO10.03 + APO10.04 + APO10.05 + APO11.04 + BAI03.05 + DSS01.03 + DSS03.05 + DSS05.02 + DSS05.04 + DSS05.05 + DSS05.07 + MEA01.01 + MEA01.02 + MEA01.03 + MEA01.04 + MEA01.05 + MEA02.01 + 3.1.7 + CCI-000172 + CCI-000130 + CCI-000169 + CCI-002884 + 164.308(a)(1)(ii)(D) + 164.308(a)(3)(ii)(A) + 164.308(a)(5)(ii)(C) + 164.312(a)(2)(i) + 164.312(b) + 164.312(d) + 164.312(e) + 4.3.2.6.7 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.4.4.7 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.8 + SR 2.9 + SR 6.1 + SR 6.2 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.14.2.7 + A.15.2.1 + A.15.2.2 + AU-2(d) + AU-12(c) + AC-6(9) + CM-6(a) + DE.CM-1 + DE.CM-3 + DE.CM-7 + ID.SC-4 + PR.PT-1 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-APP-000029-CTR-000085 + OL09-00-000705 + SV-271568r1092556_rule + Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. Auditing the use of privileged functions is one way to detect such misuse and identify the risk from insider and advanced persistent threats. - + + Privileged programs are subject to escalation-of-privilege attacks, which attempt to subvert their normal role of providing some necessary but limited capability. As such, motivation exists to monitor these programs for -unusual activity. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +unusual activity. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then ACTION_ARCH_FILTERS="-a always,exit" OTHER_FILTERS="-F path=/usr/bin/umount -F perm=x" @@ -107345,7 +182489,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -107361,7 +182504,7 @@ then if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -107453,7 +182596,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -107506,7 +182649,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -107600,7 +182742,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -107627,11 +182769,12 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-000705 - NIST-800-171-3.1.7 - NIST-800-53-AC-6(9) - NIST-800-53-AU-12(c) @@ -107706,6 +182849,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -107714,7 +182858,7 @@ fi line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/umount -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -107751,6 +182895,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -107759,13 +182904,14 @@ fi line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/umount -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-000705 - NIST-800-171-3.1.7 - NIST-800-53-AC-6(9) - NIST-800-53-AU-12(c) @@ -107777,137 +182923,141 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Ensure auditd Collects Information on the Use of Privileged Commands - unix_chkpwd - At a minimum, the audit system should collect the execution of + + + + + + + + + + Ensure auditd Collects Information on the Use of Privileged Commands - unix_chkpwd + At a minimum, the audit system should collect the execution of privileged commands for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add a line of the following form to a file with suffix .rules in the directory /etc/audit/rules.d: --a always,exit -F path=/usr/sbin/unix_chkpwd -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged +-a always,exit -F path=/sbin/unix_chkpwd -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add a line of the following form to /etc/audit/audit.rules: --a always,exit -F path=/usr/sbin/unix_chkpwd -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged - 1 - 12 - 13 - 14 - 15 - 16 - 2 - 3 - 5 - 6 - 7 - 8 - 9 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - BAI03.05 - DSS01.03 - DSS03.05 - DSS05.02 - DSS05.04 - DSS05.05 - DSS05.07 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.1.7 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-000172 - CCI-002884 - 164.308(a)(1)(ii)(D) - 164.308(a)(3)(ii)(A) - 164.308(a)(5)(ii)(C) - 164.312(a)(2)(i) - 164.312(b) - 164.312(d) - 164.312(e) - 4.3.2.6.7 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.4.4.7 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.8 - SR 2.9 - SR 6.1 - SR 6.2 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.14.2.7 - A.15.2.1 - A.15.2.2 - CIP-004-6 R2.2.2 - CIP-004-6 R2.2.3 - CIP-007-3 R.1.3 - CIP-007-3 R5 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.3 - CIP-007-3 R5.2.1 - CIP-007-3 R5.2.3 - CIP-007-3 R6.5 - AC-2(4) - AU-2(d) - AU-3 - AU-3.1 - AU-12(a) - AU-12(c) - AU-12.1(ii) - AU-12.1(iv) - AC-6(9) - CM-6(a) - MA-4(1)(a) - DE.CM-1 - DE.CM-3 - DE.CM-7 - ID.SC-4 - PR.PT-1 - FAU_GEN.1.1.c - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-APP-000029-CTR-000085 - Misuse of privileged functions, either intentionally or unintentionally by +-a always,exit -F path=/sbin/unix_chkpwd -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + + 1 + 12 + 13 + 14 + 15 + 16 + 2 + 3 + 5 + 6 + 7 + 8 + 9 + APO10.01 + APO10.03 + APO10.04 + APO10.05 + APO11.04 + BAI03.05 + DSS01.03 + DSS03.05 + DSS05.02 + DSS05.04 + DSS05.05 + DSS05.07 + MEA01.01 + MEA01.02 + MEA01.03 + MEA01.04 + MEA01.05 + MEA02.01 + 3.1.7 + CCI-000172 + CCI-000130 + CCI-000135 + CCI-000169 + CCI-002884 + 164.308(a)(1)(ii)(D) + 164.308(a)(3)(ii)(A) + 164.308(a)(5)(ii)(C) + 164.312(a)(2)(i) + 164.312(b) + 164.312(d) + 164.312(e) + 4.3.2.6.7 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.4.4.7 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.8 + SR 2.9 + SR 6.1 + SR 6.2 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.14.2.7 + A.15.2.1 + A.15.2.2 + CIP-004-6 R2.2.2 + CIP-004-6 R2.2.3 + CIP-007-3 R.1.3 + CIP-007-3 R5 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.3 + CIP-007-3 R5.2.1 + CIP-007-3 R5.2.3 + CIP-007-3 R6.5 + AC-2(4) + AU-2(d) + AU-3 + AU-3.1 + AU-12(a) + AU-12(c) + AU-12.1(ii) + AU-12.1(iv) + AC-6(9) + CM-6(a) + MA-4(1)(a) + DE.CM-1 + DE.CM-3 + DE.CM-7 + ID.SC-4 + PR.PT-1 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-APP-000029-CTR-000085 + SRG-APP-000495-CTR-001235 + OL09-00-000620 + SV-271551r1092522_rule + Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. Auditing the use of privileged functions is one way to detect such misuse and identify the risk from insider and advanced persistent threats. - + + Privileged programs are subject to escalation-of-privilege attacks, which attempt to subvert their normal role of providing some necessary but limited capability. As such, motivation exists to monitor these programs for -unusual activity. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +unusual activity. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then ACTION_ARCH_FILTERS="-a always,exit" OTHER_FILTERS="-F path=/usr/sbin/unix_chkpwd -F perm=x" @@ -107945,7 +183095,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -107961,7 +183110,7 @@ then if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -108053,7 +183202,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -108106,7 +183255,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -108200,7 +183348,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -108227,11 +183375,12 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-000620 - NIST-800-171-3.1.7 - NIST-800-53-AC-2(4) - NIST-800-53-AC-6(9) @@ -108313,6 +183462,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -108321,7 +183471,7 @@ fi line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/unix_chkpwd -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -108358,6 +183508,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -108366,13 +183517,14 @@ fi line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/unix_chkpwd -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-000620 - NIST-800-171-3.1.7 - NIST-800-53-AC-2(4) - NIST-800-53-AC-6(9) @@ -108391,17 +183543,17 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Ensure auditd Collects Information on the Use of Privileged Commands - unix_update - At a minimum, the audit system should collect the execution of + + + + + + + + + + Ensure auditd Collects Information on the Use of Privileged Commands - unix_update + At a minimum, the audit system should collect the execution of privileged commands for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add a line of the following form to a file with @@ -108410,31 +183562,36 @@ suffix .rules in the directory /etc/audit/rule If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add a line of the following form to /etc/audit/audit.rules: --a always,exit -F path=/usr/sbin/unix_update -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged - CCI-000130 - CCI-000135 - CCI-000169 - CCI-000172 - CCI-002884 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000064-GPOS-00033 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - Misuse of privileged functions, either intentionally or unintentionally by +-a always,exit -F path=/usr/sbin/unix_update -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + + CCI-000172 + CCI-000130 + CCI-000135 + CCI-000169 + CCI-002884 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000064-GPOS-00033 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-APP-000495-CTR-001235 + OL09-00-000535 + SV-271534r1092488_rule + Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. Auditing the use of privileged functions is one way to detect such misuse and identify the risk from insider and advanced persistent threats. - + + Privileged programs are subject to escalation-of-privilege attacks, which attempt to subvert their normal role of providing some necessary but limited capability. As such, motivation exists to monitor these programs for -unusual activity. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +unusual activity. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then ACTION_ARCH_FILTERS="-a always,exit" OTHER_FILTERS="-F path=/usr/sbin/unix_update -F perm=x" @@ -108472,7 +183629,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -108488,7 +183644,7 @@ then if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -108580,7 +183736,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -108633,7 +183789,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -108727,7 +183882,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -108754,11 +183909,12 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-000535 - audit_rules_privileged_commands_unix_update - low_complexity - low_disruption @@ -108828,6 +183984,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -108836,7 +183993,7 @@ fi line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/unix_update -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -108873,6 +184030,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -108881,30 +184039,31 @@ fi line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/unix_update -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-000535 - audit_rules_privileged_commands_unix_update - low_complexity - low_disruption - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Ensure auditd Collects Information on the Use of Privileged Commands - userhelper - At a minimum, the audit system should collect the execution of + + + + + + + + + + Ensure auditd Collects Information on the Use of Privileged Commands - userhelper + At a minimum, the audit system should collect the execution of privileged commands for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add a line of the following form to a file with @@ -108913,100 +184072,105 @@ suffix .rules in the directory /etc/audit/rule If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add a line of the following form to /etc/audit/audit.rules: --a always,exit -F path=/usr/sbin/userhelper -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged - 1 - 12 - 13 - 14 - 15 - 16 - 2 - 3 - 5 - 6 - 7 - 8 - 9 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - BAI03.05 - DSS01.03 - DSS03.05 - DSS05.02 - DSS05.04 - DSS05.05 - DSS05.07 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.1.7 - CCI-000135 - CCI-000169 - CCI-000172 - CCI-002884 - 164.308(a)(1)(ii)(D) - 164.308(a)(3)(ii)(A) - 164.308(a)(5)(ii)(C) - 164.312(a)(2)(i) - 164.312(b) - 164.312(d) - 164.312(e) - 4.3.2.6.7 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.4.4.7 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.8 - SR 2.9 - SR 6.1 - SR 6.2 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.14.2.7 - A.15.2.1 - A.15.2.2 - AU-2(d) - AU-12(c) - AC-6(9) - CM-6(a) - DE.CM-1 - DE.CM-3 - DE.CM-7 - ID.SC-4 - PR.PT-1 - FAU_GEN.1.1.c - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - Misuse of privileged functions, either intentionally or unintentionally by +-a always,exit -F path=/usr/sbin/userhelper -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + + 1 + 12 + 13 + 14 + 15 + 16 + 2 + 3 + 5 + 6 + 7 + 8 + 9 + APO10.01 + APO10.03 + APO10.04 + APO10.05 + APO11.04 + BAI03.05 + DSS01.03 + DSS03.05 + DSS05.02 + DSS05.04 + DSS05.05 + DSS05.07 + MEA01.01 + MEA01.02 + MEA01.03 + MEA01.04 + MEA01.05 + MEA02.01 + 3.1.7 + CCI-000172 + CCI-000130 + CCI-000135 + CCI-000169 + CCI-002884 + 164.308(a)(1)(ii)(D) + 164.308(a)(3)(ii)(A) + 164.308(a)(5)(ii)(C) + 164.312(a)(2)(i) + 164.312(b) + 164.312(d) + 164.312(e) + 4.3.2.6.7 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.4.4.7 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.8 + SR 2.9 + SR 6.1 + SR 6.2 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.14.2.7 + A.15.2.1 + A.15.2.2 + AU-2(d) + AU-12(c) + AC-6(9) + CM-6(a) + DE.CM-1 + DE.CM-3 + DE.CM-7 + ID.SC-4 + PR.PT-1 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-APP-000495-CTR-001235 + OL09-00-000625 + SV-271552r1092524_rule + Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. Auditing the use of privileged functions is one way to detect such misuse and identify the risk from insider and advanced persistent threats. - + + Privileged programs are subject to escalation-of-privilege attacks, which attempt to subvert their normal role of providing some necessary but limited capability. As such, motivation exists to monitor these programs for -unusual activity. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +unusual activity. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then ACTION_ARCH_FILTERS="-a always,exit" OTHER_FILTERS="-F path=/usr/sbin/userhelper -F perm=x" @@ -109044,7 +184208,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -109060,7 +184223,7 @@ then if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -109152,7 +184315,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -109205,7 +184368,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -109299,7 +184461,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -109326,11 +184488,12 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-000625 - NIST-800-171-3.1.7 - NIST-800-53-AC-6(9) - NIST-800-53-AU-12(c) @@ -109405,6 +184568,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -109413,7 +184577,7 @@ fi line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/userhelper -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -109450,6 +184614,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -109458,13 +184623,14 @@ fi line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/userhelper -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-000625 - NIST-800-171-3.1.7 - NIST-800-53-AC-6(9) - NIST-800-53-AU-12(c) @@ -109476,17 +184642,17 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Ensure auditd Collects Information on the Use of Privileged Commands - usermod - At a minimum, the audit system should collect the execution of + + + + + + + + + + Ensure auditd Collects Information on the Use of Privileged Commands - usermod + At a minimum, the audit system should collect the execution of privileged commands for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add a line of the following form to a file with @@ -109495,31 +184661,37 @@ suffix .rules in the directory /etc/audit/rule If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add a line of the following form to /etc/audit/audit.rules: --a always,exit -F path=/usr/sbin/usermod -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged - CCI-000130 - CCI-000135 - CCI-000169 - CCI-000172 - CCI-002884 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-OS-000466-GPOS-00210 - Misuse of privileged functions, either intentionally or unintentionally by +-a always,exit -F path=/usr/sbin/usermod -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + + CCI-000172 + CCI-000130 + CCI-000135 + CCI-000169 + CCI-002884 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-OS-000466-GPOS-00210 + SRG-APP-000495-CTR-001235 + SRG-APP-000499-CTR-001255 + OL09-00-000675 + SV-271562r1092544_rule + Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. Auditing the use of privileged functions is one way to detect such misuse and identify the risk from insider and advanced persistent threats. - + + Privileged programs are subject to escalation-of-privilege attacks, which attempt to subvert their normal role of providing some necessary but limited capability. As such, motivation exists to monitor these programs for -unusual activity. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +unusual activity. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then ACTION_ARCH_FILTERS="-a always,exit" OTHER_FILTERS="-F path=/usr/sbin/usermod -F perm=x" @@ -109557,7 +184729,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -109573,7 +184744,7 @@ then if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -109665,7 +184836,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -109718,7 +184889,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -109812,7 +184982,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -109839,11 +185009,12 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-000675 - audit_rules_privileged_commands_usermod - low_complexity - low_disruption @@ -109913,6 +185084,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -109921,7 +185093,7 @@ fi line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/usermod -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -109958,6 +185130,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -109966,30 +185139,31 @@ fi line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/usermod -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-000675 - audit_rules_privileged_commands_usermod - low_complexity - low_disruption - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Ensure auditd Collects Information on the Use of Privileged Commands - usernetctl - At a minimum, the audit system should collect the execution of + + + + + + + + + + Ensure auditd Collects Information on the Use of Privileged Commands - usernetctl + At a minimum, the audit system should collect the execution of privileged commands for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add a line of the following form to a file with @@ -109998,34 +185172,35 @@ suffix .rules in the directory /etc/audit/rule If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add a line of the following form to /etc/audit/audit.rules: --a always,exit -F path=/usr/sbin/usernetctl -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged - CCI-000172 - CIP-004-6 R2.2.2 - CIP-004-6 R2.2.3 - CIP-007-3 R.1.3 - CIP-007-3 R5 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.3 - CIP-007-3 R5.2.1 - CIP-007-3 R5.2.3 - AC-2(4) - AU-2(d) - AU-12(c) - AC-6(9) - CM-6(a) - FAU_GEN.1.1.c - Misuse of privileged functions, either intentionally or unintentionally by +-a always,exit -F path=/usr/sbin/usernetctl -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + + CCI-000172 + CIP-004-6 R2.2.2 + CIP-004-6 R2.2.3 + CIP-007-3 R.1.3 + CIP-007-3 R5 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.3 + CIP-007-3 R5.2.1 + CIP-007-3 R5.2.3 + AC-2(4) + AU-2(d) + AU-12(c) + AC-6(9) + CM-6(a) + Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. Auditing the use of privileged functions is one way to detect such misuse and identify the risk from insider and advanced persistent threats. - + + Privileged programs are subject to escalation-of-privilege attacks, which attempt to subvert their normal role of providing some necessary but limited capability. As such, motivation exists to monitor these programs for -unusual activity. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +unusual activity. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then ACTION_ARCH_FILTERS="-a always,exit" OTHER_FILTERS="-F path=/usr/sbin/usernetctl -F perm=x" @@ -110063,7 +185238,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -110079,7 +185253,7 @@ then if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -110171,7 +185345,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -110224,7 +185398,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -110318,7 +185491,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -110345,8 +185518,8 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: @@ -110424,6 +185597,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -110432,7 +185606,7 @@ fi line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/usernetctl -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -110469,6 +185643,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -110477,12 +185652,12 @@ fi line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/usernetctl -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AC-2(4) - NIST-800-53-AC-6(9) @@ -110495,24 +185670,24 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - - Records Events that Modify Date and Time Information - Arbitrary changes to the system time can be used to obfuscate + + + + + + + + + + + Records Events that Modify Date and Time Information + Arbitrary changes to the system time can be used to obfuscate nefarious activities in log files, as well as to confuse network services that are highly dependent upon an accurate system time. All changes to the system -time should be audited. - - Record attempts to alter time through adjtimex - If the auditd daemon is configured to use the +time should be audited. + + Record attempts to alter time through adjtimex + If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following line to a file with suffix .rules in the directory /etc/audit/rules.d: @@ -110529,133 +185704,135 @@ The -k option allows for the specification of a key in string form that can be used for better reporting capability through ausearch and aureport. Multiple system calls can be defined on the same line to save space if desired, but is not required. See an example of multiple combined syscalls: --a always,exit -F arch=b64 -S adjtimex,settimeofday -F key=audit_time_rules - BP28(R73) - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 19 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 5.4.1.1 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - APO12.06 - APO13.01 - BAI03.05 - BAI08.02 - DSS01.03 - DSS01.04 - DSS02.02 - DSS02.04 - DSS02.07 - DSS03.01 - DSS03.05 - DSS05.02 - DSS05.03 - DSS05.04 - DSS05.05 - DSS05.07 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.1.7 - CCI-001487 - CCI-000169 - 164.308(a)(1)(ii)(D) - 164.308(a)(3)(ii)(A) - 164.308(a)(5)(ii)(C) - 164.312(a)(2)(i) - 164.312(b) - 164.312(d) - 164.312(e) - 4.2.3.10 - 4.3.2.6.7 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.3.6.6 - 4.3.4.4.7 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 1.13 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.6 - SR 2.8 - SR 2.9 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 6.1 - SR 6.2 - SR 7.1 - SR 7.6 - A.11.2.6 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.14.2.7 - A.15.2.1 - A.15.2.2 - A.16.1.4 - A.16.1.5 - A.16.1.7 - A.6.2.1 - A.6.2.2 - AU-2(d) - AU-12(c) - AC-6(9) - CM-6(a) - DE.AE-3 - DE.AE-5 - DE.CM-1 - DE.CM-3 - DE.CM-7 - ID.SC-4 - PR.AC-3 - PR.PT-1 - PR.PT-4 - RS.AN-1 - RS.AN-4 - Req-10.4.2.b - 10.6.3 - Arbitrary changes to the system time can be used to obfuscate +-a always,exit -F arch=b64 -S adjtimex,settimeofday -F key=audit_time_rules + + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 19 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 5.4.1.1 + APO10.01 + APO10.03 + APO10.04 + APO10.05 + APO11.04 + APO12.06 + APO13.01 + BAI03.05 + BAI08.02 + DSS01.03 + DSS01.04 + DSS02.02 + DSS02.04 + DSS02.07 + DSS03.01 + DSS03.05 + DSS05.02 + DSS05.03 + DSS05.04 + DSS05.05 + DSS05.07 + MEA01.01 + MEA01.02 + MEA01.03 + MEA01.04 + MEA01.05 + MEA02.01 + 3.1.7 + CCI-001487 + CCI-000169 + 164.308(a)(1)(ii)(D) + 164.308(a)(3)(ii)(A) + 164.308(a)(5)(ii)(C) + 164.312(a)(2)(i) + 164.312(b) + 164.312(d) + 164.312(e) + 4.2.3.10 + 4.3.2.6.7 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.3.6.6 + 4.3.4.4.7 + 4.3.4.5.6 + 4.3.4.5.7 + 4.3.4.5.8 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 1.13 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.6 + SR 2.8 + SR 2.9 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 6.1 + SR 6.2 + SR 7.1 + SR 7.6 + A.11.2.6 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.13.1.1 + A.13.2.1 + A.14.1.3 + A.14.2.7 + A.15.2.1 + A.15.2.2 + A.16.1.4 + A.16.1.5 + A.16.1.7 + A.6.2.1 + A.6.2.2 + AU-2(d) + AU-12(c) + AC-6(9) + CM-6(a) + DE.AE-3 + DE.AE-5 + DE.CM-1 + DE.CM-3 + DE.CM-7 + ID.SC-4 + PR.AC-3 + PR.PT-1 + PR.PT-4 + RS.AN-1 + RS.AN-4 + Req-10.4.2.b + R73 + 10.6.3 + 10.6 + Arbitrary changes to the system time can be used to obfuscate nefarious activities in log files, as well as to confuse network services that are highly dependent upon an accurate system time (such as sshd). All changes -to the system time should be audited. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +to the system time should be audited. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then # Retrieve hardware architecture of the underlying system [ "$(getconf LONG_BIT)" = "32" ] && RULE_ARCHS=("b32") || RULE_ARCHS=("b32" "b64") @@ -110711,7 +185888,6 @@ do # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -110727,7 +185903,7 @@ do if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -110819,7 +185995,7 @@ do auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -110872,7 +186048,6 @@ do files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -110966,7 +186141,7 @@ do auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -110994,8 +186169,8 @@ done else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: @@ -111006,6 +186181,7 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.4.2.b + - PCI-DSSv4-10.6 - PCI-DSSv4-10.6.3 - audit_rules_time_adjtimex - low_complexity @@ -111019,7 +186195,7 @@ fi audit_arch: b64 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - ansible_architecture == "aarch64" or ansible_architecture == "ppc64" or ansible_architecture == "ppc64le" or ansible_architecture == "s390x" or ansible_architecture == "x86_64" tags: @@ -111030,6 +186206,7 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.4.2.b + - PCI-DSSv4-10.6 - PCI-DSSv4-10.6.3 - audit_rules_time_adjtimex - low_complexity @@ -111103,6 +186280,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -111110,7 +186288,7 @@ fi path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F key=audit_time_rules create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -111150,6 +186328,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -111157,12 +186336,12 @@ fi path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F key=audit_time_rules create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.4.1.1 - NIST-800-171-3.1.7 @@ -111171,6 +186350,7 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.4.2.b + - PCI-DSSv4-10.6 - PCI-DSSv4-10.6.3 - audit_rules_time_adjtimex - low_complexity @@ -111243,6 +186423,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -111250,7 +186431,7 @@ fi path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F key=audit_time_rules create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -111290,6 +186471,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -111297,12 +186479,12 @@ fi path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F key=audit_time_rules create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - audit_arch == "b64" tags: - CJIS-5.4.1.1 @@ -111312,6 +186494,7 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.4.2.b + - PCI-DSSv4-10.6 - PCI-DSSv4-10.6.3 - audit_rules_time_adjtimex - low_complexity @@ -111319,17 +186502,17 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Record Attempts to Alter Time Through clock_settime - If the auditd daemon is configured to use the + + + + + + + + + + Record Attempts to Alter Time Through clock_settime + If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following line to a file with suffix .rules in the directory /etc/audit/rules.d: @@ -111346,133 +186529,135 @@ The -k option allows for the specification of a key in string form that can be used for better reporting capability through ausearch and aureport. Multiple system calls can be defined on the same line to save space if desired, but is not required. See an example of multiple combined syscalls: --a always,exit -F arch=b64 -S adjtimex,settimeofday -F key=audit_time_rules - BP28(R73) - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 19 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 5.4.1.1 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - APO12.06 - APO13.01 - BAI03.05 - BAI08.02 - DSS01.03 - DSS01.04 - DSS02.02 - DSS02.04 - DSS02.07 - DSS03.01 - DSS03.05 - DSS05.02 - DSS05.03 - DSS05.04 - DSS05.05 - DSS05.07 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.1.7 - CCI-001487 - CCI-000169 - 164.308(a)(1)(ii)(D) - 164.308(a)(3)(ii)(A) - 164.308(a)(5)(ii)(C) - 164.312(a)(2)(i) - 164.312(b) - 164.312(d) - 164.312(e) - 4.2.3.10 - 4.3.2.6.7 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.3.6.6 - 4.3.4.4.7 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 1.13 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.6 - SR 2.8 - SR 2.9 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 6.1 - SR 6.2 - SR 7.1 - SR 7.6 - A.11.2.6 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.14.2.7 - A.15.2.1 - A.15.2.2 - A.16.1.4 - A.16.1.5 - A.16.1.7 - A.6.2.1 - A.6.2.2 - AU-2(d) - AU-12(c) - AC-6(9) - CM-6(a) - DE.AE-3 - DE.AE-5 - DE.CM-1 - DE.CM-3 - DE.CM-7 - ID.SC-4 - PR.AC-3 - PR.PT-1 - PR.PT-4 - RS.AN-1 - RS.AN-4 - Req-10.4.2.b - 10.6.3 - Arbitrary changes to the system time can be used to obfuscate +-a always,exit -F arch=b64 -S adjtimex,settimeofday -F key=audit_time_rules + + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 19 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 5.4.1.1 + APO10.01 + APO10.03 + APO10.04 + APO10.05 + APO11.04 + APO12.06 + APO13.01 + BAI03.05 + BAI08.02 + DSS01.03 + DSS01.04 + DSS02.02 + DSS02.04 + DSS02.07 + DSS03.01 + DSS03.05 + DSS05.02 + DSS05.03 + DSS05.04 + DSS05.05 + DSS05.07 + MEA01.01 + MEA01.02 + MEA01.03 + MEA01.04 + MEA01.05 + MEA02.01 + 3.1.7 + CCI-001487 + CCI-000169 + 164.308(a)(1)(ii)(D) + 164.308(a)(3)(ii)(A) + 164.308(a)(5)(ii)(C) + 164.312(a)(2)(i) + 164.312(b) + 164.312(d) + 164.312(e) + 4.2.3.10 + 4.3.2.6.7 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.3.6.6 + 4.3.4.4.7 + 4.3.4.5.6 + 4.3.4.5.7 + 4.3.4.5.8 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 1.13 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.6 + SR 2.8 + SR 2.9 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 6.1 + SR 6.2 + SR 7.1 + SR 7.6 + A.11.2.6 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.13.1.1 + A.13.2.1 + A.14.1.3 + A.14.2.7 + A.15.2.1 + A.15.2.2 + A.16.1.4 + A.16.1.5 + A.16.1.7 + A.6.2.1 + A.6.2.2 + AU-2(d) + AU-12(c) + AC-6(9) + CM-6(a) + DE.AE-3 + DE.AE-5 + DE.CM-1 + DE.CM-3 + DE.CM-7 + ID.SC-4 + PR.AC-3 + PR.PT-1 + PR.PT-4 + RS.AN-1 + RS.AN-4 + Req-10.4.2.b + R73 + 10.6.3 + 10.6 + Arbitrary changes to the system time can be used to obfuscate nefarious activities in log files, as well as to confuse network services that are highly dependent upon an accurate system time (such as sshd). All changes -to the system time should be audited. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +to the system time should be audited. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then # First perform the remediation of the syscall rule # Retrieve hardware architecture of the underlying system @@ -111516,7 +186701,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -111532,7 +186716,7 @@ then if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -111624,7 +186808,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -111677,7 +186861,6 @@ read -a syscall_grouping <<< $SYSCALL_GROUPING files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -111771,7 +186954,7 @@ if [ "$skip" -ne 0 ]; then auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -111799,8 +186982,8 @@ done else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: @@ -111811,6 +186994,7 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.4.2.b + - PCI-DSSv4-10.6 - PCI-DSSv4-10.6.3 - audit_rules_time_clock_settime - low_complexity @@ -111824,7 +187008,7 @@ fi audit_arch: b64 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - ansible_architecture == "aarch64" or ansible_architecture == "ppc64" or ansible_architecture == "ppc64le" or ansible_architecture == "s390x" or ansible_architecture == "x86_64" tags: @@ -111835,6 +187019,7 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.4.2.b + - PCI-DSSv4-10.6 - PCI-DSSv4-10.6.3 - audit_rules_time_clock_settime - low_complexity @@ -111905,6 +187090,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -111913,7 +187099,7 @@ fi line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F a0=0x0 -F key=time-change create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -111950,6 +187136,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -111958,12 +187145,12 @@ fi line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F a0=0x0 -F key=time-change create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.4.1.1 - NIST-800-171-3.1.7 @@ -111972,6 +187159,7 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.4.2.b + - PCI-DSSv4-10.6 - PCI-DSSv4-10.6.3 - audit_rules_time_clock_settime - low_complexity @@ -112042,6 +187230,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -112050,7 +187239,7 @@ fi line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F a0=0x0 -F key=time-change create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -112087,6 +187276,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -112095,12 +187285,12 @@ fi line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F a0=0x0 -F key=time-change create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - audit_arch == "b64" tags: - CJIS-5.4.1.1 @@ -112110,6 +187300,7 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.4.2.b + - PCI-DSSv4-10.6 - PCI-DSSv4-10.6.3 - audit_rules_time_clock_settime - low_complexity @@ -112117,17 +187308,17 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Record attempts to alter time through settimeofday - If the auditd daemon is configured to use the + + + + + + + + + + Record attempts to alter time through settimeofday + If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following line to a file with suffix .rules in the directory /etc/audit/rules.d: @@ -112144,132 +187335,134 @@ The -k option allows for the specification of a key in string form that can be used for better reporting capability through ausearch and aureport. Multiple system calls can be defined on the same line to save space if desired, but is not required. See an example of multiple combined syscalls: --a always,exit -F arch=b64 -S adjtimex,settimeofday -F key=audit_time_rules - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 19 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 5.4.1.1 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - APO12.06 - APO13.01 - BAI03.05 - BAI08.02 - DSS01.03 - DSS01.04 - DSS02.02 - DSS02.04 - DSS02.07 - DSS03.01 - DSS03.05 - DSS05.02 - DSS05.03 - DSS05.04 - DSS05.05 - DSS05.07 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.1.7 - CCI-001487 - CCI-000169 - 164.308(a)(1)(ii)(D) - 164.308(a)(3)(ii)(A) - 164.308(a)(5)(ii)(C) - 164.312(a)(2)(i) - 164.312(b) - 164.312(d) - 164.312(e) - 4.2.3.10 - 4.3.2.6.7 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.3.6.6 - 4.3.4.4.7 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 1.13 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.6 - SR 2.8 - SR 2.9 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 6.1 - SR 6.2 - SR 7.1 - SR 7.6 - A.11.2.6 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.14.2.7 - A.15.2.1 - A.15.2.2 - A.16.1.4 - A.16.1.5 - A.16.1.7 - A.6.2.1 - A.6.2.2 - AU-2(d) - AU-12(c) - AC-6(9) - CM-6(a) - DE.AE-3 - DE.AE-5 - DE.CM-1 - DE.CM-3 - DE.CM-7 - ID.SC-4 - PR.AC-3 - PR.PT-1 - PR.PT-4 - RS.AN-1 - RS.AN-4 - Req-10.4.2.b - 10.6.3 - Arbitrary changes to the system time can be used to obfuscate +-a always,exit -F arch=b64 -S adjtimex,settimeofday -F key=audit_time_rules + + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 19 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 5.4.1.1 + APO10.01 + APO10.03 + APO10.04 + APO10.05 + APO11.04 + APO12.06 + APO13.01 + BAI03.05 + BAI08.02 + DSS01.03 + DSS01.04 + DSS02.02 + DSS02.04 + DSS02.07 + DSS03.01 + DSS03.05 + DSS05.02 + DSS05.03 + DSS05.04 + DSS05.05 + DSS05.07 + MEA01.01 + MEA01.02 + MEA01.03 + MEA01.04 + MEA01.05 + MEA02.01 + 3.1.7 + CCI-001487 + CCI-000169 + 164.308(a)(1)(ii)(D) + 164.308(a)(3)(ii)(A) + 164.308(a)(5)(ii)(C) + 164.312(a)(2)(i) + 164.312(b) + 164.312(d) + 164.312(e) + 4.2.3.10 + 4.3.2.6.7 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.3.6.6 + 4.3.4.4.7 + 4.3.4.5.6 + 4.3.4.5.7 + 4.3.4.5.8 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 1.13 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.6 + SR 2.8 + SR 2.9 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 6.1 + SR 6.2 + SR 7.1 + SR 7.6 + A.11.2.6 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.13.1.1 + A.13.2.1 + A.14.1.3 + A.14.2.7 + A.15.2.1 + A.15.2.2 + A.16.1.4 + A.16.1.5 + A.16.1.7 + A.6.2.1 + A.6.2.2 + AU-2(d) + AU-12(c) + AC-6(9) + CM-6(a) + DE.AE-3 + DE.AE-5 + DE.CM-1 + DE.CM-3 + DE.CM-7 + ID.SC-4 + PR.AC-3 + PR.PT-1 + PR.PT-4 + RS.AN-1 + RS.AN-4 + Req-10.4.2.b + 10.6.3 + 10.6 + Arbitrary changes to the system time can be used to obfuscate nefarious activities in log files, as well as to confuse network services that are highly dependent upon an accurate system time (such as sshd). All changes -to the system time should be audited. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +to the system time should be audited. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then # Retrieve hardware architecture of the underlying system [ "$(getconf LONG_BIT)" = "32" ] && RULE_ARCHS=("b32") || RULE_ARCHS=("b32" "b64") @@ -112325,7 +187518,6 @@ do # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -112341,7 +187533,7 @@ do if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -112433,7 +187625,7 @@ do auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -112486,7 +187678,6 @@ do files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -112580,7 +187771,7 @@ do auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -112608,8 +187799,8 @@ done else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: @@ -112620,6 +187811,7 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.4.2.b + - PCI-DSSv4-10.6 - PCI-DSSv4-10.6.3 - audit_rules_time_settimeofday - low_complexity @@ -112633,7 +187825,7 @@ fi audit_arch: b64 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - ansible_architecture == "aarch64" or ansible_architecture == "ppc64" or ansible_architecture == "ppc64le" or ansible_architecture == "s390x" or ansible_architecture == "x86_64" tags: @@ -112644,6 +187836,7 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.4.2.b + - PCI-DSSv4-10.6 - PCI-DSSv4-10.6.3 - audit_rules_time_settimeofday - low_complexity @@ -112717,6 +187910,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -112724,7 +187918,7 @@ fi path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F key=audit_time_rules create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -112764,6 +187958,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -112771,12 +187966,12 @@ fi path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F key=audit_time_rules create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.4.1.1 - NIST-800-171-3.1.7 @@ -112785,6 +187980,7 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.4.2.b + - PCI-DSSv4-10.6 - PCI-DSSv4-10.6.3 - audit_rules_time_settimeofday - low_complexity @@ -112858,6 +188054,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -112865,7 +188062,7 @@ fi path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F key=audit_time_rules create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -112905,6 +188102,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -112912,12 +188110,12 @@ fi path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F key=audit_time_rules create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - audit_arch == "b64" tags: - CJIS-5.4.1.1 @@ -112927,6 +188125,7 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.4.2.b + - PCI-DSSv4-10.6 - PCI-DSSv4-10.6.3 - audit_rules_time_settimeofday - low_complexity @@ -112934,17 +188133,17 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Record Attempts to Alter Time Through stime - If the auditd daemon is configured to use the + + + + + + + + + + Record Attempts to Alter Time Through stime + If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following line to a file with suffix .rules in the directory /etc/audit/rules.d for both 32 bit and 64 bit systems: @@ -112965,133 +188164,136 @@ allows for the specification of a key in string form that can be used for better reporting capability through ausearch and aureport. Multiple system calls can be defined on the same line to save space if desired, but is not required. See an example of multiple combined system calls: --a always,exit -F arch=b64 -S adjtimex,settimeofday -F key=audit_time_rules - BP28(R73) - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 19 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 5.4.1.1 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - APO12.06 - APO13.01 - BAI03.05 - BAI08.02 - DSS01.03 - DSS01.04 - DSS02.02 - DSS02.04 - DSS02.07 - DSS03.01 - DSS03.05 - DSS05.02 - DSS05.03 - DSS05.04 - DSS05.05 - DSS05.07 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.1.7 - CCI-001487 - CCI-000169 - 164.308(a)(1)(ii)(D) - 164.308(a)(3)(ii)(A) - 164.308(a)(5)(ii)(C) - 164.312(a)(2)(i) - 164.312(b) - 164.312(d) - 164.312(e) - 4.2.3.10 - 4.3.2.6.7 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.3.6.6 - 4.3.4.4.7 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 1.13 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.6 - SR 2.8 - SR 2.9 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 6.1 - SR 6.2 - SR 7.1 - SR 7.6 - A.11.2.6 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.14.2.7 - A.15.2.1 - A.15.2.2 - A.16.1.4 - A.16.1.5 - A.16.1.7 - A.6.2.1 - A.6.2.2 - AU-2(d) - AU-12(c) - AC-6(9) - CM-6(a) - DE.AE-3 - DE.AE-5 - DE.CM-1 - DE.CM-3 - DE.CM-7 - ID.SC-4 - PR.AC-3 - PR.PT-1 - PR.PT-4 - RS.AN-1 - RS.AN-4 - Req-10.4.2.b - 10.6.3 - Arbitrary changes to the system time can be used to obfuscate +-a always,exit -F arch=b64 -S adjtimex,settimeofday -F key=audit_time_rules + + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 19 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 5.4.1.1 + APO10.01 + APO10.03 + APO10.04 + APO10.05 + APO11.04 + APO12.06 + APO13.01 + BAI03.05 + BAI08.02 + DSS01.03 + DSS01.04 + DSS02.02 + DSS02.04 + DSS02.07 + DSS03.01 + DSS03.05 + DSS05.02 + DSS05.03 + DSS05.04 + DSS05.05 + DSS05.07 + MEA01.01 + MEA01.02 + MEA01.03 + MEA01.04 + MEA01.05 + MEA02.01 + 3.1.7 + CCI-001487 + CCI-000169 + 164.308(a)(1)(ii)(D) + 164.308(a)(3)(ii)(A) + 164.308(a)(5)(ii)(C) + 164.312(a)(2)(i) + 164.312(b) + 164.312(d) + 164.312(e) + 4.2.3.10 + 4.3.2.6.7 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.3.6.6 + 4.3.4.4.7 + 4.3.4.5.6 + 4.3.4.5.7 + 4.3.4.5.8 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 1.13 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.6 + SR 2.8 + SR 2.9 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 6.1 + SR 6.2 + SR 7.1 + SR 7.6 + A.11.2.6 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.13.1.1 + A.13.2.1 + A.14.1.3 + A.14.2.7 + A.15.2.1 + A.15.2.2 + A.16.1.4 + A.16.1.5 + A.16.1.7 + A.6.2.1 + A.6.2.2 + AU-2(d) + AU-12(c) + AC-6(9) + CM-6(a) + DE.AE-3 + DE.AE-5 + DE.CM-1 + DE.CM-3 + DE.CM-7 + ID.SC-4 + PR.AC-3 + PR.PT-1 + PR.PT-4 + RS.AN-1 + RS.AN-4 + Req-10.4.2.b + R73 + 10.6.3 + 10.6 + Arbitrary changes to the system time can be used to obfuscate nefarious activities in log files, as well as to confuse network services that are highly dependent upon an accurate system time (such as sshd). All changes -to the system time should be audited. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +to the system time should be audited. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { ( ! ( ( grep -sqE "^.*\.aarch64$" /proc/sys/kernel/osrelease || grep -sqE "^aarch64$" /proc/sys/kernel/arch; ) ) && ! ( ( grep -sqE "^.*\.s390x$" /proc/sys/kernel/osrelease || grep -sqE "^s390x$" /proc/sys/kernel/arch; ) ) ); }; then # Retrieve hardware architecture of the underlying system [ "$(getconf LONG_BIT)" = "32" ] && RULE_ARCHS=("b32") || RULE_ARCHS=("b32" "b64") @@ -113147,7 +188349,6 @@ do # files_to_inspect=() - # If audit tool is 'augenrules', then check if the audit rule is defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection # If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection @@ -113163,7 +188364,7 @@ do if [ ! -e "$file_to_inspect" ] then touch "$file_to_inspect" - chmod 0640 "$file_to_inspect" + chmod 0600 "$file_to_inspect" fi fi @@ -113255,7 +188456,7 @@ do auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -113308,7 +188509,6 @@ do files_to_inspect=() - # If audit tool is 'auditctl', then add '/etc/audit/audit.rules' # file to the list of files to be inspected default_file="/etc/audit/audit.rules" @@ -113402,7 +188602,7 @@ do auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true echo "$full_rule" >> "$default_file" - chmod o-rwx ${default_file} + chmod 0600 ${default_file} else # Check if the syscalls are declared as a comma separated list or # as multiple -S parameters @@ -113430,8 +188630,8 @@ done else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: @@ -113442,6 +188642,7 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.4.2.b + - PCI-DSSv4-10.6 - PCI-DSSv4-10.6.3 - audit_rules_time_stime - low_complexity @@ -113515,6 +188716,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -113522,7 +188724,7 @@ fi path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F key=audit_time_rules create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 @@ -113562,6 +188764,7 @@ fi line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present + mode: g-rwx,o-rwx when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} @@ -113569,12 +188772,14 @@ fi path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F key=audit_time_rules create: true - mode: o-rwx + mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - ( not ( ansible_architecture == "aarch64" ) and not ( ansible_architecture == + "s390x" ) ) tags: - CJIS-5.4.1.1 - NIST-800-171-3.1.7 @@ -113583,6 +188788,7 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.4.2.b + - PCI-DSSv4-10.6 - PCI-DSSv4-10.6.3 - audit_rules_time_stime - low_complexity @@ -113590,17 +188796,17 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Record Attempts to Alter the localtime File - If the auditd daemon is configured to use the + + + + + + + + + + Record Attempts to Alter the localtime File + If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following line to a file with suffix .rules in the directory /etc/audit/rules.d: @@ -113611,134 +188817,134 @@ utility to read audit rules during daemon startup, add the following line to -w /etc/localtime -p wa -k audit_time_rules The -k option allows for the specification of a key in string form that can be used for better reporting capability through ausearch and aureport and -should always be used. - BP28(R73) - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 19 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 5.4.1.1 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - APO12.06 - APO13.01 - BAI03.05 - BAI08.02 - DSS01.03 - DSS01.04 - DSS02.02 - DSS02.04 - DSS02.07 - DSS03.01 - DSS03.05 - DSS05.02 - DSS05.03 - DSS05.04 - DSS05.05 - DSS05.07 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.1.7 - CCI-001487 - CCI-000169 - 164.308(a)(1)(ii)(D) - 164.308(a)(3)(ii)(A) - 164.308(a)(5)(ii)(C) - 164.312(a)(2)(i) - 164.312(b) - 164.312(d) - 164.312(e) - 4.2.3.10 - 4.3.2.6.7 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.3.6.6 - 4.3.4.4.7 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 1.13 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.6 - SR 2.8 - SR 2.9 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 6.1 - SR 6.2 - SR 7.1 - SR 7.6 - A.11.2.6 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.14.2.7 - A.15.2.1 - A.15.2.2 - A.16.1.4 - A.16.1.5 - A.16.1.7 - A.6.2.1 - A.6.2.2 - AU-2(d) - AU-12(c) - AC-6(9) - CM-6(a) - DE.AE-3 - DE.AE-5 - DE.CM-1 - DE.CM-3 - DE.CM-7 - ID.SC-4 - PR.AC-3 - PR.PT-1 - PR.PT-4 - RS.AN-1 - RS.AN-4 - Req-10.4.2.b - 10.6.3 - 10.6.3 - Arbitrary changes to the system time can be used to obfuscate +should always be used. + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 19 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 5.4.1.1 + APO10.01 + APO10.03 + APO10.04 + APO10.05 + APO11.04 + APO12.06 + APO13.01 + BAI03.05 + BAI08.02 + DSS01.03 + DSS01.04 + DSS02.02 + DSS02.04 + DSS02.07 + DSS03.01 + DSS03.05 + DSS05.02 + DSS05.03 + DSS05.04 + DSS05.05 + DSS05.07 + MEA01.01 + MEA01.02 + MEA01.03 + MEA01.04 + MEA01.05 + MEA02.01 + 3.1.7 + CCI-001487 + CCI-000169 + 164.308(a)(1)(ii)(D) + 164.308(a)(3)(ii)(A) + 164.308(a)(5)(ii)(C) + 164.312(a)(2)(i) + 164.312(b) + 164.312(d) + 164.312(e) + 4.2.3.10 + 4.3.2.6.7 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.3.6.6 + 4.3.4.4.7 + 4.3.4.5.6 + 4.3.4.5.7 + 4.3.4.5.8 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 1.13 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.6 + SR 2.8 + SR 2.9 + SR 3.1 + SR 3.5 + SR 3.8 + SR 4.1 + SR 4.3 + SR 5.1 + SR 5.2 + SR 5.3 + SR 6.1 + SR 6.2 + SR 7.1 + SR 7.6 + A.11.2.6 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.13.1.1 + A.13.2.1 + A.14.1.3 + A.14.2.7 + A.15.2.1 + A.15.2.2 + A.16.1.4 + A.16.1.5 + A.16.1.7 + A.6.2.1 + A.6.2.2 + AU-2(d) + AU-12(c) + AC-6(9) + CM-6(a) + DE.AE-3 + DE.AE-5 + DE.CM-1 + DE.CM-3 + DE.CM-7 + ID.SC-4 + PR.AC-3 + PR.PT-1 + PR.PT-4 + RS.AN-1 + RS.AN-4 + Req-10.4.2.b + R73 + 10.6.3 + 10.6 + Arbitrary changes to the system time can be used to obfuscate nefarious activities in log files, as well as to confuse network services that are highly dependent upon an accurate system time (such as sshd). All changes -to the system time should be audited. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +to the system time should be audited. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' # Create a list of audit *.rules files that should be inspected for presence and correctness @@ -113831,7 +189037,7 @@ then if [ ! -e "$key_rule_file" ] then touch "$key_rule_file" - chmod 0640 "$key_rule_file" + chmod 0600 "$key_rule_file" fi files_to_inspect+=("$key_rule_file") fi @@ -113877,8 +189083,8 @@ done else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: @@ -113889,7 +189095,7 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.4.2.b - - PCI-DSSv4-10.6.3 + - PCI-DSSv4-10.6 - PCI-DSSv4-10.6.3 - audit_rules_time_watch_localtime - low_complexity @@ -113906,7 +189112,7 @@ fi register: find_existing_watch_rules_d when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.4.1.1 - NIST-800-171-3.1.7 @@ -113915,7 +189121,7 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.4.2.b - - PCI-DSSv4-10.6.3 + - PCI-DSSv4-10.6 - PCI-DSSv4-10.6.3 - audit_rules_time_watch_localtime - low_complexity @@ -113932,7 +189138,7 @@ fi register: find_watch_key when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: @@ -113943,7 +189149,7 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.4.2.b - - PCI-DSSv4-10.6.3 + - PCI-DSSv4-10.6 - PCI-DSSv4-10.6.3 - audit_rules_time_watch_localtime - low_complexity @@ -113958,7 +189164,7 @@ fi - /etc/audit/rules.d/audit_time_rules.rules when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_watch_key.matched is defined and find_watch_key.matched == 0 and find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: @@ -113969,7 +189175,7 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.4.2.b - - PCI-DSSv4-10.6.3 + - PCI-DSSv4-10.6 - PCI-DSSv4-10.6.3 - audit_rules_time_watch_localtime - low_complexity @@ -113984,7 +189190,7 @@ fi - '{{ find_watch_key.files | map(attribute=''path'') | list | first }}' when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_watch_key.matched is defined and find_watch_key.matched > 0 and find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: @@ -113995,7 +189201,7 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.4.2.b - - PCI-DSSv4-10.6.3 + - PCI-DSSv4-10.6 - PCI-DSSv4-10.6.3 - audit_rules_time_watch_localtime - low_complexity @@ -114009,10 +189215,10 @@ fi path: '{{ all_files[0] }}' line: -w /etc/localtime -p wa -k audit_time_rules create: true - mode: '0640' + mode: '0600' when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: @@ -114023,7 +189229,7 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.4.2.b - - PCI-DSSv4-10.6.3 + - PCI-DSSv4-10.6 - PCI-DSSv4-10.6.3 - audit_rules_time_watch_localtime - low_complexity @@ -114040,7 +189246,7 @@ fi register: find_existing_watch_audit_rules when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.4.1.1 - NIST-800-171-3.1.7 @@ -114049,7 +189255,7 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.4.2.b - - PCI-DSSv4-10.6.3 + - PCI-DSSv4-10.6 - PCI-DSSv4-10.6.3 - audit_rules_time_watch_localtime - low_complexity @@ -114064,10 +189270,10 @@ fi state: present dest: /etc/audit/audit.rules create: true - mode: '0640' + mode: '0600' when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - find_existing_watch_audit_rules.matched is defined and find_existing_watch_audit_rules.matched == 0 tags: @@ -114078,7 +189284,7 @@ fi - NIST-800-53-AU-2(d) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.4.2.b - - PCI-DSSv4-10.6.3 + - PCI-DSSv4-10.6 - PCI-DSSv4-10.6.3 - audit_rules_time_watch_localtime - low_complexity @@ -114086,19 +189292,19 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - - - Configure auditd Data Retention - The audit system writes data to /var/log/audit/audit.log. By default, + + + + + + + + + + + + Configure auditd Data Retention + The audit system writes data to /var/log/audit/audit.log. By default, auditd rotates 5 logs by size (6MB), retaining a maximum of 30MB of data in total, and refuses to write entries when the disk is too full. This minimizes the risk of audit data filling its partition @@ -114113,7 +189319,8 @@ for data retention may be of events are being audited. First configure auditing to log all the events of interest. Then monitor the log size manually for awhile to determine what file size will allow you to keep the required data for the correct time period. - + + Using a dedicated partition for /var/log/audit prevents the auditd logs from disrupting system functionality if they fill, and, more importantly, prevents other activity in /var from filling the @@ -114129,199 +189336,159 @@ rotated away before they can be viewed. sure this can never happen under normal circumstances! Ensure that /var/log/audit is on its own partition, and that this partition is larger than the maximum amount of data auditd will retain -normally. - - - Action for audispd to take when disk is full - The setting for disk_full_action in /etc/audisp/audisp-remote.conf - single - exec - halt - single - suspend - syslog - warn_once - stop - - - Action for audispd to take when network fails - The setting for network_failure_action in /etc/audisp/audisp-remote.conf - single - exec - halt - single - suspend - syslog - warn_once - stop - ignore - - - Remote server for audispd to send audit records - -The setting for remote_server in /etc/audisp/audisp-remote.conf - logcollector - - - Account for auditd to send email when actions occurs - The setting for action_mail_acct in /etc/audit/auditd.conf - admin - root - root - - - Action for auditd to take when disk space is low - The setting for admin_space_left_action in /etc/audit/auditd.conf - single - email - exec - halt - single - suspend - syslog - rotate - ignore - - - The percentage remaining in disk space before prompting admin_space_left_action - The setting for admin_space_left as a percentage in /etc/audit/auditd.conf - 5 - 25 - 50 - 75 - 5 - - - Action for auditd to take when disk errors - 'The setting for disk_error_action in /etc/audit/auditd.conf, if multiple +normally. + + + + Account for auditd to send email when actions occurs + The setting for action_mail_acct in /etc/audit/auditd.conf + admin + root + root + + + Action for auditd to take when disk space is low + The setting for admin_space_left_action in /etc/audit/auditd.conf + single + email + exec + halt + single + suspend + syslog + rotate + ignore + single|halt + single|halt + + + Action for auditd to take when disk errors + 'The setting for disk_error_action in /etc/audit/auditd.conf, if multiple values are allowed write them separated by pipes as in "syslog|single|halt", -for remediations the first value will be taken' - single - exec - halt - single - suspend - syslog - ignore - syslog|single|halt - syslog|single|halt - - - Action for auditd to take when disk is full - 'The setting for disk_full_action in /etc/audit/auditd.conf, if multiple +for remediations the first value will be taken' + single + exec + halt + single + suspend + syslog + ignore + syslog|single|halt + syslog|single|halt + syslog|single|halt + syslog|single|halt + syslog|single|halt + + + Action for auditd to take when disk is full + 'The setting for disk_full_action in /etc/audit/auditd.conf, if multiple values are allowed write them separated by pipes as in "syslog|single|halt", -for remediations the first value will be taken' - single - exec - halt - single - suspend - syslog - ignore - rotate - syslog|single|halt - syslog|single|halt - - - Auditd priority for flushing data to disk - The setting for flush in /etc/audit/auditd.conf - data - data - incremental - incremental_async - none - sync - - - Number of Record to Retain Before Flushing to Disk - The setting for freq in /etc/audit/auditd.conf - 50 - 100 - 50 - - - Maximum audit log file size for auditd - The setting for max_log_file in /etc/audit/auditd.conf - 1 - 10 - 20 - 5 - 6 - 6 - - - Action for auditd to take when log files reach their maximum size - The setting for max_log_file_action in /etc/audit/auditd.conf. The following options are available: -ignore - audit daemon does nothing. -syslog - audit daemon will issue a warning to syslog. -suspend - audit daemon will stop writing records to the disk. -rotate - audit daemon will rotate logs in the same convention used by logrotate. -keep_logs - similar to rotate but prevents audit logs to be overwritten. May trigger space_left_action if volume is full. - rotate - keep_logs - rotate - suspend - syslog - ignore - - - Number of log files for auditd to retain - The setting for num_logs in /etc/audit/auditd.conf - 0 - 1 - 2 - 3 - 4 - 5 - 10 - 20 - 50 - 100 - 5 - - - Size remaining in disk space before prompting space_left_action - The setting for space_left (MB) in /etc/audit/auditd.conf - 1000 - 100 - 250 - 500 - 750 - 100 - - - Action for auditd to take when disk space just starts to run low - The setting for space_left_action in /etc/audit/auditd.conf - email - email - exec - halt - single - suspend - syslog - rotate - ignore - - - The percentage remaining in disk space before prompting space_left_action - The setting for space_left as a percentage in /etc/audit/auditd.conf - 25 - 50 - 75 - 25 - - - Configure a Sufficiently Large Partition for Audit Logs - The Oracle Linux 9 operating system must allocate audit record storage +for remediations the first value will be taken' + single + exec + halt + single + suspend + syslog + ignore + rotate + syslog|single|halt + syslog|single|halt + syslog|single|halt + halt|single + halt|single + + + Auditd priority for flushing data to disk + The setting for flush in /etc/audit/auditd.conf + data + data + incremental + incremental_async + none + sync + + + Number of Record to Retain Before Flushing to Disk + The setting for freq in /etc/audit/auditd.conf + 50 + 100 + 50 + + + Action for auditd to take when log files reach their maximum size + The setting for max_log_file_action in /etc/audit/auditd.conf. The following options are available: +ignore - audit daemon does nothing. +syslog - audit daemon will issue a warning to syslog. +suspend - audit daemon will stop writing records to the disk. +rotate - audit daemon will rotate logs in the same convention used by logrotate. +keep_logs - similar to rotate but prevents audit logs to be overwritten. May trigger space_left_action if volume is full. + rotate + keep_logs + rotate + suspend + syslog + ignore + + + Type of hostname to record the audit event + Type of hostname to record the audit event + hostname + hostname + fqd + numeric + user + none + hostname|fqd|numeric + + + Size remaining in disk space before prompting space_left_action + The setting for space_left (MB) in /etc/audit/auditd.conf + 1000 + 100 + 250 + 500 + 750 + 100 + + + Action for auditd to take when disk space just starts to run low + The setting for space_left_action in /etc/audit/auditd.conf + email + email + exec + halt + single + suspend + syslog + rotate + ignore + email|exec|single|halt + email|exec|single|halt + + + The percentage remaining in disk space before prompting space_left_action + The setting for space_left as a percentage in /etc/audit/auditd.conf + 25 + 50 + 75 + 25 + + + Configure a Sufficiently Large Partition for Audit Logs + The Oracle Linux 9 operating system must allocate audit record storage capacity to store at least one weeks worth of audit records when audit records are not immediately sent to a central audit record storage facility. The partition size needed to capture a week's worth of audit records is based on the activity level of the system and the total storage capacity -available. In normal circumstances, 10.0 GB of storage space for audit +available. + +In normal circumstances, 10.0 GB of storage space for audit records will be sufficient. + Determine which partition the audit records are being written to with the following command: @@ -114332,104 +189499,110 @@ Check the size of the partition that audit records are written to with the following command: $ sudo df -h /var/log/audit/ -/dev/sda2 24G 10.4G 13.6G 43% /var/log/audit - CCI-001849 - SRG-OS-000341-GPOS-00132 - SRG-OS-000342-GPOS-00133 - Information stored in one location is vulnerable to accidental or incidental +/dev/sda2 24G 10.4G 13.6G 43% /var/log/audit + + CCI-001849 + CCI-001851 + SRG-OS-000341-GPOS-00132 + SRG-OS-000342-GPOS-00133 + OL09-00-000850 + SV-271596r1091500_rule + Information stored in one location is vulnerable to accidental or incidental deletion or alteration. Off-loading is a common process in information -systems with limited audit storage capacity. - - - - - - - Configure auditd to use audispd's syslog plugin - To configure the auditd service to use the +systems with limited audit storage capacity. + + + + + + Configure auditd to use audispd's syslog plugin + To configure the auditd service to use the syslog plug-in of the audispd audit event multiplexor, set the active line in /etc/audit/plugins.d/syslog.conf to yes. Restart the auditd service: -$ sudo service auditd restart - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 19 - 3 - 4 - 5 - 6 - 7 - 8 - 5.4.1.1 - APO11.04 - APO12.06 - BAI03.05 - BAI08.02 - DSS02.02 - DSS02.04 - DSS02.07 - DSS03.01 - DSS05.04 - DSS05.07 - MEA02.01 - 3.3.1 - CCI-000136 - 164.308(a)(1)(ii)(D) - 164.308(a)(5)(ii)(B) - 164.308(a)(5)(ii)(C) - 164.308(a)(6)(ii) - 164.308(a)(8) - 164.310(d)(2)(iii) - 164.312(b) - 164.314(a)(2)(i)(C) - 164.314(a)(2)(iii) - 4.2.3.10 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.4.4.7 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.8 - SR 2.9 - SR 6.1 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.16.1.4 - A.16.1.5 - A.16.1.7 - AU-4(1) - CM-6(a) - DE.AE-3 - DE.AE-5 - PR.PT-1 - RS.AN-1 - RS.AN-4 - FAU_GEN.1.1.c - Req-10.5.3 - 10.3.3 - SRG-OS-000479-GPOS-00224 - SRG-OS-000342-GPOS-00133 - The auditd service does not include the ability to send audit +$ sudo service auditd restart + + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 19 + 3 + 4 + 5 + 6 + 7 + 8 + 5.4.1.1 + APO11.04 + APO12.06 + BAI03.05 + BAI08.02 + DSS02.02 + DSS02.04 + DSS02.07 + DSS03.01 + DSS05.04 + DSS05.07 + MEA02.01 + 3.3.1 + CCI-001851 + 164.308(a)(1)(ii)(D) + 164.308(a)(5)(ii)(B) + 164.308(a)(5)(ii)(C) + 164.308(a)(6)(ii) + 164.308(a)(8) + 164.310(d)(2)(iii) + 164.312(b) + 164.314(a)(2)(i)(C) + 164.314(a)(2)(iii) + 4.2.3.10 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.4.4.7 + 4.3.4.5.6 + 4.3.4.5.7 + 4.3.4.5.8 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.8 + SR 2.9 + SR 6.1 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.16.1.4 + A.16.1.5 + A.16.1.7 + AU-4(1) + CM-6(a) + DE.AE-3 + DE.AE-5 + PR.PT-1 + RS.AN-1 + RS.AN-4 + Req-10.5.3 + SRG-OS-000479-GPOS-00224 + SRG-OS-000342-GPOS-00133 + 10.3.3 + 10.3 + OL09-00-000855 + SV-271597r1092586_rule + The auditd service does not include the ability to send audit records to a centralized server for management directly. It does, however, include a plug-in for audit event multiplexor (audispd) to pass audit records -to the local syslog server. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +to the local syslog server. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then var_syslog_active="yes" @@ -114458,16 +189631,18 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000855 - NIST-800-171-3.3.1 - NIST-800-53-AU-4(1) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.3 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.3 - auditd_audispd_syslog_plugin_activated - configure_strategy @@ -114484,13 +189659,15 @@ fi create: true when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000855 - NIST-800-171-3.3.1 - NIST-800-53-AU-4(1) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.5.3 + - PCI-DSSv4-10.3 - PCI-DSSv4-10.3.3 - auditd_audispd_syslog_plugin_activated - configure_strategy @@ -114498,102 +189675,113 @@ fi - low_disruption - medium_severity - no_reboot_needed - - - - - - - - - - Configure auditd Disk Error Action on Disk Error - The auditd service can be configured to take an action + + + + + + + + + + Configure auditd Disk Error Action on Disk Error + The auditd service can be configured to take an action when there is a disk error. Edit the file /etc/audit/auditd.conf. Add or modify the following line, substituting ACTION appropriately: -disk_error_action = ACTION +disk_error_action = ACTION + Set this value to single to cause the system to switch to single-user -mode for corrective action. Acceptable values also include syslog, -exec, single, and halt. For certain systems, the need for availability +mode for corrective action. Acceptable values also include + +syslog, exec, single, and halt + +For certain systems, the need for availability outweighs the need to log all actions, and a different setting should be determined. Details regarding all possible values for ACTION are described in the -auditd.conf man page. - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 19 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - APO11.04 - APO12.06 - APO13.01 - BAI03.05 - BAI04.04 - BAI08.02 - DSS02.02 - DSS02.04 - DSS02.07 - DSS03.01 - DSS05.04 - DSS05.07 - MEA02.01 - CCI-000140 - 4.2.3.10 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.4.4.7 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.8 - SR 2.9 - SR 6.1 - SR 7.1 - SR 7.2 - A.12.1.3 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.16.1.4 - A.16.1.5 - A.16.1.7 - A.17.2.1 - AU-5(b) - AU-5(2) - AU-5(1) - AU-5(4) - CM-6(a) - DE.AE-3 - DE.AE-5 - PR.DS-4 - PR.PT-1 - RS.AN-1 - RS.AN-4 - SRG-OS-000047-GPOS-00023 - Taking appropriate action in case of disk errors will minimize the possibility of -losing audit records. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +auditd.conf man page. + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 19 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + APO11.04 + APO12.06 + APO13.01 + BAI03.05 + BAI04.04 + BAI08.02 + DSS02.02 + DSS02.04 + DSS02.07 + DSS03.01 + DSS05.04 + DSS05.07 + MEA02.01 + CCI-000140 + 4.2.3.10 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.4.4.7 + 4.3.4.5.6 + 4.3.4.5.7 + 4.3.4.5.8 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.8 + SR 2.9 + SR 6.1 + SR 7.1 + SR 7.2 + A.12.1.3 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.16.1.4 + A.16.1.5 + A.16.1.7 + A.17.2.1 + AU-5(b) + AU-5(2) + AU-5(1) + AU-5(4) + CM-6(a) + DE.AE-3 + DE.AE-5 + PR.DS-4 + PR.PT-1 + RS.AN-1 + RS.AN-4 + SRG-OS-000047-GPOS-00023 + SRG-APP-000098-CTR-000185 + SRG-APP-000099-CTR-000190 + SRG-APP-000100-CTR-000195 + SRG-APP-000100-CTR-000200 + SRG-APP-000109-CTR-000215 + SRG-APP-000290-CTR-000670 + SRG-APP-000357-CTR-000800 + Taking appropriate action in case of disk errors will minimize the possibility of +losing audit records. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -var_auditd_disk_error_action='' +var_auditd_disk_error_action='' # @@ -114626,8 +189814,8 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: @@ -114644,7 +189832,7 @@ fi - restrict_strategy - name: XCCDF Value var_auditd_disk_error_action # promote to variable set_fact: - var_auditd_disk_error_action: !!str + var_auditd_disk_error_action: !!str tags: - always @@ -114657,7 +189845,7 @@ fi create: true when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AU-5(1) - NIST-800-53-AU-5(2) @@ -114670,103 +189858,106 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - - Configure auditd Disk Error Action on Disk Error - The auditd service can be configured to take an action + + + + + + + + + + + Configure auditd Disk Error Action on Disk Error + The auditd service can be configured to take an action when there is a disk error. Edit the file /etc/audit/auditd.conf. Add or modify the following line, substituting ACTION appropriately: -disk_error_action = ACTION +disk_error_action = ACTION + Set this value to single to cause the system to switch to single-user mode for corrective action. Acceptable values also include syslog, exec, single, and halt. For certain systems, the need for availability outweighs the need to log all actions, and a different setting should be determined. Details regarding all possible values for ACTION are described in the -auditd.conf man page. - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 19 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - APO11.04 - APO12.06 - APO13.01 - BAI03.05 - BAI04.04 - BAI08.02 - DSS02.02 - DSS02.04 - DSS02.07 - DSS03.01 - DSS05.04 - DSS05.07 - MEA02.01 - CCI-000140 - 4.2.3.10 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.4.4.7 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.8 - SR 2.9 - SR 6.1 - SR 7.1 - SR 7.2 - A.12.1.3 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.16.1.4 - A.16.1.5 - A.16.1.7 - A.17.2.1 - AU-5(b) - AU-5(2) - AU-5(1) - AU-5(4) - CM-6(a) - DE.AE-3 - DE.AE-5 - PR.DS-4 - PR.PT-1 - RS.AN-1 - RS.AN-4 - SRG-OS-000047-GPOS-00023 - Taking appropriate action in case of disk errors will minimize the possibility of -losing audit records. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +auditd.conf man page. + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 19 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + APO11.04 + APO12.06 + APO13.01 + BAI03.05 + BAI04.04 + BAI08.02 + DSS02.02 + DSS02.04 + DSS02.07 + DSS03.01 + DSS05.04 + DSS05.07 + MEA02.01 + CCI-000140 + 4.2.3.10 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.4.4.7 + 4.3.4.5.6 + 4.3.4.5.7 + 4.3.4.5.8 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.8 + SR 2.9 + SR 6.1 + SR 7.1 + SR 7.2 + A.12.1.3 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.16.1.4 + A.16.1.5 + A.16.1.7 + A.17.2.1 + AU-5(b) + AU-5(2) + AU-5(1) + AU-5(4) + CM-6(a) + DE.AE-3 + DE.AE-5 + PR.DS-4 + PR.PT-1 + RS.AN-1 + RS.AN-4 + SRG-OS-000047-GPOS-00023 + OL09-00-000760 + SV-271579r1091449_rule + Taking appropriate action in case of disk errors will minimize the possibility of +losing audit records. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -var_auditd_disk_error_action='' +var_auditd_disk_error_action='' # Strip any search characters in the key arg so that the key can be replaced without @@ -114792,11 +189983,12 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-000760 - NIST-800-53-AU-5(1) - NIST-800-53-AU-5(2) - NIST-800-53-AU-5(4) @@ -114810,7 +190002,7 @@ fi - restrict_strategy - name: XCCDF Value var_auditd_disk_error_action # promote to variable set_fact: - var_auditd_disk_error_action: !!str + var_auditd_disk_error_action: !!str tags: - always @@ -114823,8 +190015,9 @@ fi create: true when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-000760 - NIST-800-53-AU-5(1) - NIST-800-53-AU-5(2) - NIST-800-53-AU-5(4) @@ -114836,105 +190029,106 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Configure auditd Disk Full Action when Disk Space Is Full - The auditd service can be configured to take an action + + + + + + + + + + Configure auditd Disk Full Action when Disk Space Is Full + The auditd service can be configured to take an action when disk space is running low but prior to running out of space completely. Edit the file /etc/audit/auditd.conf. Add or modify the following line, substituting ACTION appropriately: -disk_full_action = ACTION +disk_full_action = ACTION + Set this value to single to cause the system to switch to single-user -mode for corrective action. Acceptable values also include syslog, +mode for corrective action. Acceptable values also include -exec, +syslog, exec, single, and halt -single, and halt. For certain systems, the need for availability +For certain systems, the need for availability outweighs the need to log all actions, and a different setting should be determined. Details regarding all possible values for ACTION are described in the -auditd.conf man page. - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 19 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - APO11.04 - APO12.06 - APO13.01 - BAI03.05 - BAI04.04 - BAI08.02 - DSS02.02 - DSS02.04 - DSS02.07 - DSS03.01 - DSS05.04 - DSS05.07 - MEA02.01 - CCI-000140 - 4.2.3.10 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.4.4.7 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.8 - SR 2.9 - SR 6.1 - SR 7.1 - SR 7.2 - A.12.1.3 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.16.1.4 - A.16.1.5 - A.16.1.7 - A.17.2.1 - AU-5(b) - AU-5(2) - AU-5(1) - AU-5(4) - CM-6(a) - DE.AE-3 - DE.AE-5 - PR.DS-4 - PR.PT-1 - RS.AN-1 - RS.AN-4 - SRG-OS-000047-GPOS-00023 - Taking appropriate action in case of a filled audit storage volume will minimize -the possibility of losing audit records. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +auditd.conf man page. + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 19 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + APO11.04 + APO12.06 + APO13.01 + BAI03.05 + BAI04.04 + BAI08.02 + DSS02.02 + DSS02.04 + DSS02.07 + DSS03.01 + DSS05.04 + DSS05.07 + MEA02.01 + CCI-000140 + 4.2.3.10 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.4.4.7 + 4.3.4.5.6 + 4.3.4.5.7 + 4.3.4.5.8 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.8 + SR 2.9 + SR 6.1 + SR 7.1 + SR 7.2 + A.12.1.3 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.16.1.4 + A.16.1.5 + A.16.1.7 + A.17.2.1 + AU-5(b) + AU-5(2) + AU-5(1) + AU-5(4) + CM-6(a) + DE.AE-3 + DE.AE-5 + PR.DS-4 + PR.PT-1 + RS.AN-1 + RS.AN-4 + SRG-OS-000047-GPOS-00023 + Taking appropriate action in case of a filled audit storage volume will minimize +the possibility of losing audit records. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -var_auditd_disk_full_action='' +var_auditd_disk_full_action='' var_auditd_disk_full_action="$(echo $var_auditd_disk_full_action | cut -d \| -f 1)" @@ -114962,8 +190156,8 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: @@ -114980,7 +190174,7 @@ fi - restrict_strategy - name: XCCDF Value var_auditd_disk_full_action # promote to variable set_fact: - var_auditd_disk_full_action: !!str + var_auditd_disk_full_action: !!str tags: - always @@ -114993,7 +190187,7 @@ fi create: true when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AU-5(1) - NIST-800-53-AU-5(2) @@ -115006,103 +190200,106 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - - Configure auditd Disk Full Action when Disk Space Is Full - The auditd service can be configured to take an action + + + + + + + + + + + Configure auditd Disk Full Action when Disk Space Is Full + The auditd service can be configured to take an action when disk space is running low but prior to running out of space completely. Edit the file /etc/audit/auditd.conf. Add or modify the following line, substituting ACTION appropriately: -disk_full_action = ACTION +disk_full_action = ACTION + Set this value to single to cause the system to switch to single-user mode for corrective action. Acceptable values also include syslog, single, and halt. For certain systems, the need for availability outweighs the need to log all actions, and a different setting should be determined. Details regarding all possible values for ACTION are described in the -auditd.conf man page. - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 19 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - APO11.04 - APO12.06 - APO13.01 - BAI03.05 - BAI04.04 - BAI08.02 - DSS02.02 - DSS02.04 - DSS02.07 - DSS03.01 - DSS05.04 - DSS05.07 - MEA02.01 - CCI-000140 - 4.2.3.10 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.4.4.7 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.8 - SR 2.9 - SR 6.1 - SR 7.1 - SR 7.2 - A.12.1.3 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.16.1.4 - A.16.1.5 - A.16.1.7 - A.17.2.1 - AU-5(b) - AU-5(2) - AU-5(1) - AU-5(4) - CM-6(a) - DE.AE-3 - DE.AE-5 - PR.DS-4 - PR.PT-1 - RS.AN-1 - RS.AN-4 - SRG-OS-000047-GPOS-00023 - Taking appropriate action in case of a filled audit storage volume will minimize -the possibility of losing audit records. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +auditd.conf man page. + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 19 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + APO11.04 + APO12.06 + APO13.01 + BAI03.05 + BAI04.04 + BAI08.02 + DSS02.02 + DSS02.04 + DSS02.07 + DSS03.01 + DSS05.04 + DSS05.07 + MEA02.01 + CCI-000140 + 4.2.3.10 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.4.4.7 + 4.3.4.5.6 + 4.3.4.5.7 + 4.3.4.5.8 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.8 + SR 2.9 + SR 6.1 + SR 7.1 + SR 7.2 + A.12.1.3 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.16.1.4 + A.16.1.5 + A.16.1.7 + A.17.2.1 + AU-5(b) + AU-5(2) + AU-5(1) + AU-5(4) + CM-6(a) + DE.AE-3 + DE.AE-5 + PR.DS-4 + PR.PT-1 + RS.AN-1 + RS.AN-4 + SRG-OS-000047-GPOS-00023 + OL09-00-000765 + SV-271580r1091452_rule + Taking appropriate action in case of a filled audit storage volume will minimize +the possibility of losing audit records. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -var_auditd_disk_full_action='' +var_auditd_disk_full_action='' # Strip any search characters in the key arg so that the key can be replaced without @@ -115128,11 +190325,12 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-000765 - NIST-800-53-AU-5(1) - NIST-800-53-AU-5(2) - NIST-800-53-AU-5(4) @@ -115146,7 +190344,7 @@ fi - restrict_strategy - name: XCCDF Value var_auditd_disk_full_action # promote to variable set_fact: - var_auditd_disk_full_action: !!str + var_auditd_disk_full_action: !!str tags: - always @@ -115159,8 +190357,9 @@ fi create: true when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-000765 - NIST-800-53-AU-5(1) - NIST-800-53-AU-5(2) - NIST-800-53-AU-5(4) @@ -115172,117 +190371,120 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Configure auditd mail_acct Action on Low Disk Space - The auditd service can be configured to send email to + + + + + + + + + + Configure auditd mail_acct Action on Low Disk Space + The auditd service can be configured to send email to a designated account in certain situations. Add or correct the following line in /etc/audit/auditd.conf to ensure that administrators are notified via email for those situations: -action_mail_acct = - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 19 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 5.4.1.1 - APO11.04 - APO12.06 - APO13.01 - BAI03.05 - BAI04.04 - BAI08.02 - DSS02.02 - DSS02.04 - DSS02.07 - DSS03.01 - DSS05.04 - DSS05.07 - MEA02.01 - 3.3.1 - CCI-000139 - CCI-001855 - 164.312(a)(2)(ii) - 4.2.3.10 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.4.4.7 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.8 - SR 2.9 - SR 6.1 - SR 7.1 - SR 7.2 - A.12.1.3 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.16.1.4 - A.16.1.5 - A.16.1.7 - A.17.2.1 - CIP-003-8 R1.3 - CIP-003-8 R3 - CIP-003-8 R3.1 - CIP-003-8 R3.2 - CIP-003-8 R3.3 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.2.3 - CIP-004-6 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.2 - CIP-007-3 R5.2 - CIP-007-3 R5.3.1 - CIP-007-3 R5.3.2 - CIP-007-3 R5.3.3 - IA-5(1) - AU-5(a) - AU-5(2) - CM-6(a) - DE.AE-3 - DE.AE-5 - PR.DS-4 - PR.PT-1 - RS.AN-1 - RS.AN-4 - Req-10.7.a - 10.5.1 - SRG-OS-000046-GPOS-00022 - SRG-OS-000343-GPOS-00134 - Email sent to the root account is typically aliased to the -administrators of the system, who can take appropriate action. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +action_mail_acct = + + + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 19 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 5.4.1.1 + APO11.04 + APO12.06 + APO13.01 + BAI03.05 + BAI04.04 + BAI08.02 + DSS02.02 + DSS02.04 + DSS02.07 + DSS03.01 + DSS05.04 + DSS05.07 + MEA02.01 + 3.3.1 + CCI-001855 + CCI-000139 + 164.312(a)(2)(ii) + 4.2.3.10 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.4.4.7 + 4.3.4.5.6 + 4.3.4.5.7 + 4.3.4.5.8 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.8 + SR 2.9 + SR 6.1 + SR 7.1 + SR 7.2 + A.12.1.3 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.16.1.4 + A.16.1.5 + A.16.1.7 + A.17.2.1 + CIP-003-8 R1.3 + CIP-003-8 R3 + CIP-003-8 R3.1 + CIP-003-8 R3.2 + CIP-003-8 R3.3 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.2.3 + CIP-004-6 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.2 + CIP-007-3 R5.2 + CIP-007-3 R5.3.1 + CIP-007-3 R5.3.2 + CIP-007-3 R5.3.3 + IA-5(1) + AU-5(a) + AU-5(2) + CM-6(a) + DE.AE-3 + DE.AE-5 + PR.DS-4 + PR.PT-1 + RS.AN-1 + RS.AN-4 + Req-10.7.a + SRG-OS-000046-GPOS-00022 + SRG-OS-000343-GPOS-00134 + OL09-00-000825 + SV-271591r1092578_rule + Email sent to the root account is typically aliased to the +administrators of the system, who can take appropriate action. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -var_auditd_action_mail_acct='' +var_auditd_action_mail_acct='' AUDITCONFIG=/etc/audit/auditd.conf @@ -115310,19 +190512,19 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000825 - NIST-800-171-3.3.1 - NIST-800-53-AU-5(2) - NIST-800-53-AU-5(a) - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(1) - PCI-DSS-Req-10.7.a - - PCI-DSSv4-10.5.1 - auditd_data_retention_action_mail_acct - low_complexity - low_disruption @@ -115331,7 +190533,7 @@ fi - restrict_strategy - name: XCCDF Value var_auditd_action_mail_acct # promote to variable set_fact: - var_auditd_action_mail_acct: !!str + var_auditd_action_mail_acct: !!str tags: - always @@ -115343,129 +190545,135 @@ fi create: true when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000825 - NIST-800-171-3.3.1 - NIST-800-53-AU-5(2) - NIST-800-53-AU-5(a) - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(1) - PCI-DSS-Req-10.7.a - - PCI-DSSv4-10.5.1 - auditd_data_retention_action_mail_acct - low_complexity - low_disruption - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - - Configure auditd admin_space_left Action on Low Disk Space - The auditd service can be configured to take an action + + + + + + + + + + + Configure auditd admin_space_left Action on Low Disk Space + The auditd service can be configured to take an action when disk space is running low but prior to running out of space completely. Edit the file /etc/audit/auditd.conf. Add or modify the following line, substituting ACTION appropriately: -admin_space_left_action = ACTION +admin_space_left_action = ACTION + Set this value to single to cause the system to switch to single user mode for corrective action. Acceptable values also include suspend and halt. For certain systems, the need for availability outweighs the need to log all actions, and a different setting should be determined. Details regarding all possible values for ACTION are described in the -auditd.conf man page. - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 19 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 5.4.1.1 - APO11.04 - APO12.06 - APO13.01 - BAI03.05 - BAI04.04 - BAI08.02 - DSS02.02 - DSS02.04 - DSS02.07 - DSS03.01 - DSS05.04 - DSS05.07 - MEA02.01 - 3.3.1 - CCI-000140 - CCI-001343 - CCI-001855 - 164.312(a)(2)(ii) - 4.2.3.10 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.4.4.7 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.8 - SR 2.9 - SR 6.1 - SR 7.1 - SR 7.2 - A.12.1.3 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.16.1.4 - A.16.1.5 - A.16.1.7 - A.17.2.1 - AU-5(b) - AU-5(2) - AU-5(1) - AU-5(4) - CM-6(a) - DE.AE-3 - DE.AE-5 - PR.DS-4 - PR.PT-1 - RS.AN-1 - RS.AN-4 - Req-10.7 - 10.5.1 - SRG-OS-000343-GPOS-00134 - Administrators should be made aware of an inability to record +auditd.conf man page. + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 19 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 5.4.1.1 + APO11.04 + APO12.06 + APO13.01 + BAI03.05 + BAI04.04 + BAI08.02 + DSS02.02 + DSS02.04 + DSS02.07 + DSS03.01 + DSS05.04 + DSS05.07 + MEA02.01 + 3.3.1 + CCI-001855 + 164.312(a)(2)(ii) + 4.2.3.10 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.4.4.7 + 4.3.4.5.6 + 4.3.4.5.7 + 4.3.4.5.8 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.8 + SR 2.9 + SR 6.1 + SR 7.1 + SR 7.2 + A.12.1.3 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.16.1.4 + A.16.1.5 + A.16.1.7 + A.17.2.1 + AU-5(b) + AU-5(2) + AU-5(1) + AU-5(4) + CM-6(a) + DE.AE-3 + DE.AE-5 + PR.DS-4 + PR.PT-1 + RS.AN-1 + RS.AN-4 + Req-10.7 + SRG-OS-000343-GPOS-00134 + 10.5.1 + 10.5 + OL09-00-000875 + OL09-00-000885 + SV-271601r1091515_rule + SV-271603r1092592_rule + Administrators should be made aware of an inability to record audit records. If a separate partition or logical volume of adequate size -is used, running low on space for audit records should never occur. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +is used, running low on space for audit records should never occur. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -var_auditd_admin_space_left_action='' +var_auditd_admin_space_left_action='' +var_auditd_admin_space_left_action="$(echo $var_auditd_admin_space_left_action | cut -d \| -f 1)" + AUDITCONFIG=/etc/audit/auditd.conf # Strip any search characters in the key arg so that the key can be replaced without @@ -115491,12 +190699,14 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000875 + - DISA-STIG-OL09-00-000885 - NIST-800-171-3.3.1 - NIST-800-53-AU-5(1) - NIST-800-53-AU-5(2) @@ -115504,6 +190714,7 @@ fi - NIST-800-53-AU-5(b) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.7 + - PCI-DSSv4-10.5 - PCI-DSSv4-10.5.1 - auditd_data_retention_admin_space_left_action - low_complexity @@ -115513,22 +190724,25 @@ fi - restrict_strategy - name: XCCDF Value var_auditd_admin_space_left_action # promote to variable set_fact: - var_auditd_admin_space_left_action: !!str + var_auditd_admin_space_left_action: !!str tags: - always - name: Configure auditd admin_space_left Action on Low Disk Space lineinfile: dest: /etc/audit/auditd.conf - line: admin_space_left_action = {{ var_auditd_admin_space_left_action }} + line: admin_space_left_action = {{ var_auditd_admin_space_left_action .split('|')[0] + }} regexp: ^\s*admin_space_left_action\s*=\s*.*$ state: present create: true when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000875 + - DISA-STIG-OL09-00-000885 - NIST-800-171-3.3.1 - NIST-800-53-AU-5(1) - NIST-800-53-AU-5(2) @@ -115536,6 +190750,7 @@ fi - NIST-800-53-AU-5(b) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.7 + - PCI-DSSv4-10.5 - PCI-DSSv4-10.5.1 - auditd_data_retention_admin_space_left_action - low_complexity @@ -115543,255 +190758,109 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - - Configure auditd admin_space_left on Low Disk Space - The auditd service can be configured to take an action -when disk space is running low but prior to running out of space completely. -Edit the file /etc/audit/auditd.conf. Add or modify the following line, -substituting PERCENTAGE appropriately: -admin_space_left = PERCENTAGE% -Set this value to -to cause the system to perform an action. - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 19 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - APO11.04 - APO12.06 - APO13.01 - BAI03.05 - BAI04.04 - BAI08.02 - DSS02.02 - DSS02.04 - DSS02.07 - DSS03.01 - DSS05.04 - DSS05.07 - MEA02.01 - CCI-001855 - 4.2.3.10 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.4.4.7 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.8 - SR 2.9 - SR 6.1 - SR 7.1 - SR 7.2 - A.12.1.3 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.16.1.4 - A.16.1.5 - A.16.1.7 - A.17.2.1 - AU-5(b) - AU-5(2) - AU-5(1) - AU-5(4) - CM-6(a) - DE.AE-3 - DE.AE-5 - PR.DS-4 - PR.PT-1 - RS.AN-1 - RS.AN-4 - Req-10.7 - SRG-OS-000343-GPOS-00134 - Notifying administrators of an impending disk space problem may allow them to -take corrective action prior to any disruption. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then - -var_auditd_admin_space_left_percentage='' - - -grep -q "^admin_space_left[[:space:]]*=.*$" /etc/audit/auditd.conf && \ - sed -i "s/^admin_space_left[[:space:]]*=.*$/admin_space_left = $var_auditd_admin_space_left_percentage%/g" /etc/audit/auditd.conf || \ - echo "admin_space_left = $var_auditd_admin_space_left_percentage%" >> /etc/audit/auditd.conf - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Gather the package facts - package_facts: - manager: auto - tags: - - NIST-800-53-AU-5(1) - - NIST-800-53-AU-5(2) - - NIST-800-53-AU-5(4) - - NIST-800-53-AU-5(b) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.7 - - auditd_data_retention_admin_space_left_percentage - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy -- name: XCCDF Value var_auditd_admin_space_left_percentage # promote to variable - set_fact: - var_auditd_admin_space_left_percentage: !!str - tags: - - always - -- name: Configure auditd admin_space_left on Low Disk Space - lineinfile: - dest: /etc/audit/auditd.conf - line: admin_space_left = {{ var_auditd_admin_space_left_percentage }}% - regexp: ^\s*admin_space_left\s*=\s*.*$ - state: present - create: true - when: - - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AU-5(1) - - NIST-800-53-AU-5(2) - - NIST-800-53-AU-5(4) - - NIST-800-53-AU-5(b) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.7 - - auditd_data_retention_admin_space_left_percentage - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - - - - - - - - - - Configure auditd flush priority - The auditd service can be configured to + + + + + + + + + + + Configure auditd flush priority + The auditd service can be configured to synchronously write audit event data to disk. Add or correct the following line in /etc/audit/auditd.conf to ensure that audit event data is fully synchronized with the log files on the disk: -flush = - 1 - 12 - 13 - 14 - 15 - 16 - 2 - 3 - 5 - 6 - 7 - 8 - 9 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - BAI03.05 - DSS01.03 - DSS03.05 - DSS05.02 - DSS05.04 - DSS05.05 - DSS05.07 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.3.1 - CCI-001576 - 164.308(a)(1)(ii)(D) - 164.308(a)(3)(ii)(A) - 164.308(a)(5)(ii)(C) - 164.312(a)(2)(i) - 164.312(b) - 164.312(d) - 164.312(e) - 4.3.2.6.7 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.4.4.7 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.8 - SR 2.9 - SR 6.1 - SR 6.2 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.14.2.7 - A.15.2.1 - A.15.2.2 - CIP-004-6 R2.2.3 - CIP-004-6 R3.3 - CIP-007-3 R5.2 - CIP-007-3 R5.3.1 - CIP-007-3 R5.3.2 - CIP-007-3 R5.3.3 - CIP-007-3 R6.5 - AU-11 - CM-6(a) - DE.CM-1 - DE.CM-3 - DE.CM-7 - ID.SC-4 - PR.PT-1 - SRG-OS-000480-GPOS-00227 - Audit data should be synchronously written to disk to ensure +flush = + + + 1 + 12 + 13 + 14 + 15 + 16 + 2 + 3 + 5 + 6 + 7 + 8 + 9 + APO10.01 + APO10.03 + APO10.04 + APO10.05 + APO11.04 + BAI03.05 + DSS01.03 + DSS03.05 + DSS05.02 + DSS05.04 + DSS05.05 + DSS05.07 + MEA01.01 + MEA01.02 + MEA01.03 + MEA01.04 + MEA01.05 + MEA02.01 + 3.3.1 + CCI-001576 + 164.308(a)(1)(ii)(D) + 164.308(a)(3)(ii)(A) + 164.308(a)(5)(ii)(C) + 164.312(a)(2)(i) + 164.312(b) + 164.312(d) + 164.312(e) + 4.3.2.6.7 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.4.4.7 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.8 + SR 2.9 + SR 6.1 + SR 6.2 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.14.2.7 + A.15.2.1 + A.15.2.2 + CIP-004-6 R2.2.3 + CIP-004-6 R3.3 + CIP-007-3 R5.2 + CIP-007-3 R5.3.1 + CIP-007-3 R5.3.2 + CIP-007-3 R5.3.3 + CIP-007-3 R6.5 + AU-11 + CM-6(a) + DE.CM-1 + DE.CM-3 + DE.CM-7 + ID.SC-4 + PR.PT-1 + FAU_GEN.1 + SRG-OS-000480-GPOS-00227 + Audit data should be synchronously written to disk to ensure log integrity. These parameters assure that all audit event data is fully -synchronized with the log files on the disk. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +synchronized with the log files on the disk. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -var_auditd_flush='' +var_auditd_flush='' AUDITCONFIG=/etc/audit/auditd.conf @@ -115824,8 +190893,8 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: @@ -115840,7 +190909,7 @@ fi - restrict_strategy - name: XCCDF Value var_auditd_flush # promote to variable set_fact: - var_auditd_flush: !!str + var_auditd_flush: !!str tags: - always @@ -115853,7 +190922,7 @@ fi create: true when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-171-3.3.1 - NIST-800-53-AU-11 @@ -115864,271 +190933,109 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - - Configure auditd Max Log File Size - Determine the amount of audit data (in megabytes) -which should be retained in each log file. Edit the file -/etc/audit/auditd.conf. Add or modify the following line, substituting -the correct value of for STOREMB: -max_log_file = STOREMB -Set the value to 6 (MB) or higher for general-purpose systems. -Larger values, of course, -support retention of even more audit data. - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 19 - 3 - 4 - 5 - 6 - 7 - 8 - 5.4.1.1 - APO11.04 - APO12.06 - BAI03.05 - BAI08.02 - DSS02.02 - DSS02.04 - DSS02.07 - DSS03.01 - DSS05.04 - DSS05.07 - MEA02.01 - 4.2.3.10 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.4.4.7 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.8 - SR 2.9 - SR 6.1 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.16.1.4 - A.16.1.5 - A.16.1.7 - CIP-004-6 R2.2.3 - CIP-004-6 R3.3 - CIP-007-3 R5.2 - CIP-007-3 R5.3.1 - CIP-007-3 R5.3.2 - CIP-007-3 R5.3.3 - CIP-007-3 R6.5 - AU-11 - CM-6(a) - DE.AE-3 - DE.AE-5 - PR.PT-1 - RS.AN-1 - RS.AN-4 - Req-10.7 - 10.5.1 - The total storage for audit log files must be large enough to retain -log information over the period required. This is a function of the maximum -log file size and the number of logs retained. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then - -var_auditd_max_log_file='' - - -AUDITCONFIG=/etc/audit/auditd.conf - -# Strip any search characters in the key arg so that the key can be replaced without -# adding any search characters to the config file. -stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^max_log_file") - -# shellcheck disable=SC2059 -printf -v formatted_output "%s = %s" "$stripped_key" "$var_auditd_max_log_file" - -# If the key exists, change it. Otherwise, add it to the config_file. -# We search for the key string followed by a word boundary (matched by \>), -# so if we search for 'setting', 'setting2' won't match. -if LC_ALL=C grep -q -m 1 -i -e "^max_log_file\\>" "$AUDITCONFIG"; then - escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") - LC_ALL=C sed -i --follow-symlinks "s/^max_log_file\\>.*/$escaped_formatted_output/gi" "$AUDITCONFIG" -else - if [[ -s "$AUDITCONFIG" ]] && [[ -n "$(tail -c 1 -- "$AUDITCONFIG" || true)" ]]; then - LC_ALL=C sed -i --follow-symlinks '$a'\\ "$AUDITCONFIG" - fi - printf '%s\n' "$formatted_output" >> "$AUDITCONFIG" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Gather the package facts - package_facts: - manager: auto - tags: - - CJIS-5.4.1.1 - - NIST-800-53-AU-11 - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.7 - - PCI-DSSv4-10.5.1 - - auditd_data_retention_max_log_file - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy -- name: XCCDF Value var_auditd_max_log_file # promote to variable - set_fact: - var_auditd_max_log_file: !!str - tags: - - always - -- name: Configure auditd Max Log File Size - lineinfile: - dest: /etc/audit/auditd.conf - regexp: ^\s*max_log_file\s*=\s*.*$ - line: max_log_file = {{ var_auditd_max_log_file }} - state: present - create: true - when: - - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - CJIS-5.4.1.1 - - NIST-800-53-AU-11 - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.7 - - PCI-DSSv4-10.5.1 - - auditd_data_retention_max_log_file - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - - - - - - - - - - Configure auditd max_log_file_action Upon Reaching Maximum Log Size - The default action to take when the logs reach their maximum size + + + + + + + + + + + Configure auditd max_log_file_action Upon Reaching Maximum Log Size + The default action to take when the logs reach their maximum size is to rotate the log files, discarding the oldest one. To configure the action taken by auditd, add or correct the line in /etc/audit/auditd.conf: -max_log_file_action = ACTION +max_log_file_action = ACTION + Possible values for ACTION are described in the auditd.conf man page. These include: ignoresyslogsuspendrotatekeep_logs -Set the ACTION to rotate to ensure log rotation -occurs. This is the default. The setting is case-insensitive. - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 19 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 5.4.1.1 - APO11.04 - APO12.06 - APO13.01 - BAI03.05 - BAI04.04 - BAI08.02 - DSS02.02 - DSS02.04 - DSS02.07 - DSS03.01 - DSS05.04 - DSS05.07 - MEA02.01 - CCI-000140 - 164.312(a)(2)(ii) - 4.2.3.10 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.4.4.7 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.8 - SR 2.9 - SR 6.1 - SR 7.1 - SR 7.2 - A.12.1.3 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.16.1.4 - A.16.1.5 - A.16.1.7 - A.17.2.1 - AU-5(b) - AU-5(2) - AU-5(1) - AU-5(4) - CM-6(a) - DE.AE-3 - DE.AE-5 - PR.DS-4 - PR.PT-1 - RS.AN-1 - RS.AN-4 - Req-10.7 - 10.5.1 - SRG-OS-000047-GPOS-00023 - Automatically rotating logs (by setting this to rotate) +Set the ACTION to . +The setting is case-insensitive. + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 19 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 5.4.1.1 + APO11.04 + APO12.06 + APO13.01 + BAI03.05 + BAI04.04 + BAI08.02 + DSS02.02 + DSS02.04 + DSS02.07 + DSS03.01 + DSS05.04 + DSS05.07 + MEA02.01 + CCI-000140 + 164.312(a)(2)(ii) + 4.2.3.10 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.4.4.7 + 4.3.4.5.6 + 4.3.4.5.7 + 4.3.4.5.8 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.8 + SR 2.9 + SR 6.1 + SR 7.1 + SR 7.2 + A.12.1.3 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.16.1.4 + A.16.1.5 + A.16.1.7 + A.17.2.1 + AU-5(b) + AU-5(2) + AU-5(1) + AU-5(4) + CM-6(a) + DE.AE-3 + DE.AE-5 + PR.DS-4 + PR.PT-1 + RS.AN-1 + RS.AN-4 + Req-10.7 + SRG-OS-000047-GPOS-00023 + A.3.SEC-OL6 + Automatically rotating logs (by setting this to rotate) minimizes the chances of the system unexpectedly running out of disk space by being overwhelmed with log data. However, for systems that must never discard log data, or which use external processes to transfer it and reclaim space, -keep_logs can be employed. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +keep_logs can be employed. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -var_auditd_max_log_file_action='' +var_auditd_max_log_file_action='' AUDITCONFIG=/etc/audit/auditd.conf @@ -116156,8 +191063,8 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: @@ -116168,7 +191075,6 @@ fi - NIST-800-53-AU-5(b) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.7 - - PCI-DSSv4-10.5.1 - auditd_data_retention_max_log_file_action - low_complexity - low_disruption @@ -116177,7 +191083,7 @@ fi - restrict_strategy - name: XCCDF Value var_auditd_max_log_file_action # promote to variable set_fact: - var_auditd_max_log_file_action: !!str + var_auditd_max_log_file_action: !!str tags: - always @@ -116190,7 +191096,7 @@ fi create: true when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.4.1.1 - NIST-800-53-AU-5(1) @@ -116199,114 +191105,122 @@ fi - NIST-800-53-AU-5(b) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.7 - - PCI-DSSv4-10.5.1 - auditd_data_retention_max_log_file_action - low_complexity - low_disruption - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - - Configure auditd max_log_file_action Upon Reaching Maximum Log Size - The default action to take when the logs reach their maximum size + + + + + + + + + + + Configure auditd max_log_file_action Upon Reaching Maximum Log Size + The default action to take when the logs reach their maximum size is to rotate the log files, discarding the oldest one. To configure the action taken by auditd, add or correct the line in /etc/audit/auditd.conf: -max_log_file_action = ACTION +max_log_file_action = ACTION + Possible values for ACTION are described in the auditd.conf man page. These include: ignoresyslogsuspendrotatekeep_logs Set the ACTION to rotate to ensure log rotation -occurs. This is the default. The setting is case-insensitive. - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 19 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - APO11.04 - APO12.06 - APO13.01 - BAI03.05 - BAI04.04 - BAI08.02 - DSS02.02 - DSS02.04 - DSS02.07 - DSS03.01 - DSS05.04 - DSS05.07 - MEA02.01 - CCI-000140 - 164.312(a)(2)(ii) - 4.2.3.10 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.4.4.7 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.8 - SR 2.9 - SR 6.1 - SR 7.1 - SR 7.2 - A.12.1.3 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.16.1.4 - A.16.1.5 - A.16.1.7 - A.17.2.1 - AU-5(b) - AU-5(2) - AU-5(1) - AU-5(4) - CM-6(a) - DE.AE-3 - DE.AE-5 - PR.DS-4 - PR.PT-1 - RS.AN-1 - RS.AN-4 - Req-10.7 - 10.5.1 - SRG-OS-000047-GPOS-00023 - Automatically rotating logs (by setting this to rotate) +occurs. This is the default. The setting is case-insensitive. + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 19 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + APO11.04 + APO12.06 + APO13.01 + BAI03.05 + BAI04.04 + BAI08.02 + DSS02.02 + DSS02.04 + DSS02.07 + DSS03.01 + DSS05.04 + DSS05.07 + MEA02.01 + CCI-000140 + 164.312(a)(2)(ii) + 4.2.3.10 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.4.4.7 + 4.3.4.5.6 + 4.3.4.5.7 + 4.3.4.5.8 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.8 + SR 2.9 + SR 6.1 + SR 7.1 + SR 7.2 + A.12.1.3 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.16.1.4 + A.16.1.5 + A.16.1.7 + A.17.2.1 + AU-5(b) + AU-5(2) + AU-5(1) + AU-5(4) + CM-6(a) + DE.AE-3 + DE.AE-5 + PR.DS-4 + PR.PT-1 + RS.AN-1 + RS.AN-4 + Req-10.7 + SRG-OS-000047-GPOS-00023 + SRG-APP-000098-CTR-000185 + SRG-APP-000099-CTR-000190 + SRG-APP-000100-CTR-000195 + SRG-APP-000100-CTR-000200 + SRG-APP-000109-CTR-000215 + SRG-APP-000290-CTR-000670 + SRG-APP-000357-CTR-000800 + OL09-00-000770 + SV-271581r1091455_rule + Automatically rotating logs (by setting this to rotate) minimizes the chances of the system unexpectedly running out of disk space by being overwhelmed with log data. However, for systems that must never discard log data, or which use external processes to transfer it and reclaim space, -keep_logs can be employed. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +keep_logs can be employed. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -var_auditd_max_log_file_action='' +var_auditd_max_log_file_action='' # Strip any search characters in the key arg so that the key can be replaced without @@ -116332,18 +191246,18 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-000770 - NIST-800-53-AU-5(1) - NIST-800-53-AU-5(2) - NIST-800-53-AU-5(4) - NIST-800-53-AU-5(b) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.7 - - PCI-DSSv4-10.5.1 - auditd_data_retention_max_log_file_action_stig - low_complexity - low_disruption @@ -116352,7 +191266,7 @@ fi - restrict_strategy - name: XCCDF Value var_auditd_max_log_file_action # promote to variable set_fact: - var_auditd_max_log_file_action: !!str + var_auditd_max_log_file_action: !!str tags: - always @@ -116365,7 +191279,130 @@ fi create: true when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-000770 + - NIST-800-53-AU-5(1) + - NIST-800-53-AU-5(2) + - NIST-800-53-AU-5(4) + - NIST-800-53-AU-5(b) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-10.7 + - auditd_data_retention_max_log_file_action_stig + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + + + + + + + + + + Configure auditd space_left on Low Disk Space + The auditd service can be configured to take an action +when disk space is running low but prior to running out of space completely. +Edit the file /etc/audit/auditd.conf. Add or modify the following line, +substituting SIZE_in_MB appropriately: +space_left = SIZE_in_MB + +Set this value to the appropriate size in Megabytes cause the system to +notify the user of an issue. + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 19 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + APO11.04 + APO12.06 + APO13.01 + BAI03.05 + BAI04.04 + BAI08.02 + DSS02.02 + DSS02.04 + DSS02.07 + DSS03.01 + DSS05.04 + DSS05.07 + MEA02.01 + CCI-001855 + 4.2.3.10 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.4.4.7 + 4.3.4.5.6 + 4.3.4.5.7 + 4.3.4.5.8 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.8 + SR 2.9 + SR 6.1 + SR 7.1 + SR 7.2 + A.12.1.3 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.16.1.4 + A.16.1.5 + A.16.1.7 + A.17.2.1 + AU-5(b) + AU-5(2) + AU-5(1) + AU-5(4) + CM-6(a) + DE.AE-3 + DE.AE-5 + PR.DS-4 + PR.PT-1 + RS.AN-1 + RS.AN-4 + Req-10.7 + SRG-OS-000343-GPOS-00134 + 10.5.1 + 10.5 + Notifying administrators of an impending disk space problem may allow them to +take corrective action prior to any disruption. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +var_auditd_space_left='' + + +grep -q "^space_left[[:space:]]*=.*$" /etc/audit/auditd.conf && \ + sed -i "s/^space_left[[:space:]]*=.*$/space_left = $var_auditd_space_left/g" /etc/audit/auditd.conf || \ + echo "space_left = $var_auditd_space_left" >> /etc/audit/auditd.conf + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto tags: - NIST-800-53-AU-5(1) - NIST-800-53-AU-5(2) @@ -116373,281 +191410,154 @@ fi - NIST-800-53-AU-5(b) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.7 + - PCI-DSSv4-10.5 - PCI-DSSv4-10.5.1 - - auditd_data_retention_max_log_file_action_stig + - auditd_data_retention_space_left - low_complexity - low_disruption - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Configure auditd Number of Logs Retained - Determine how many log files -auditd should retain when it rotates logs. -Edit the file /etc/audit/auditd.conf. Add or modify the following -line, substituting NUMLOGS with the correct value of : -num_logs = NUMLOGS -Set the value to 5 for general-purpose systems. -Note that values less than 2 result in no log rotation. - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 19 - 3 - 4 - 5 - 6 - 7 - 8 - 5.4.1.1 - APO11.04 - APO12.06 - BAI03.05 - BAI08.02 - DSS02.02 - DSS02.04 - DSS02.07 - DSS03.01 - DSS05.04 - DSS05.07 - MEA02.01 - 3.3.1 - 4.2.3.10 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.4.4.7 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.8 - SR 2.9 - SR 6.1 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.16.1.4 - A.16.1.5 - A.16.1.7 - CIP-004-6 R2.2.3 - CIP-004-6 R3.3 - CIP-007-3 R5.2 - CIP-007-3 R5.3.1 - CIP-007-3 R5.3.2 - CIP-007-3 R5.3.3 - CIP-007-3 R6.5 - AU-11 - CM-6(a) - DE.AE-3 - DE.AE-5 - PR.PT-1 - RS.AN-1 - RS.AN-4 - Req-10.7 - 10.5.1 - The total storage for audit log files must be large enough to retain -log information over the period required. This is a function of the maximum log -file size and the number of logs retained. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then - -var_auditd_num_logs='' - - -AUDITCONFIG=/etc/audit/auditd.conf - -# Strip any search characters in the key arg so that the key can be replaced without -# adding any search characters to the config file. -stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^num_logs") - -# shellcheck disable=SC2059 -printf -v formatted_output "%s = %s" "$stripped_key" "$var_auditd_num_logs" - -# If the key exists, change it. Otherwise, add it to the config_file. -# We search for the key string followed by a word boundary (matched by \>), -# so if we search for 'setting', 'setting2' won't match. -if LC_ALL=C grep -q -m 1 -i -e "^num_logs\\>" "$AUDITCONFIG"; then - escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") - LC_ALL=C sed -i --follow-symlinks "s/^num_logs\\>.*/$escaped_formatted_output/gi" "$AUDITCONFIG" -else - if [[ -s "$AUDITCONFIG" ]] && [[ -n "$(tail -c 1 -- "$AUDITCONFIG" || true)" ]]; then - LC_ALL=C sed -i --follow-symlinks '$a'\\ "$AUDITCONFIG" - fi - printf '%s\n' "$formatted_output" >> "$AUDITCONFIG" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Gather the package facts - package_facts: - manager: auto - tags: - - CJIS-5.4.1.1 - - NIST-800-171-3.3.1 - - NIST-800-53-AU-11 - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.7 - - PCI-DSSv4-10.5.1 - - auditd_data_retention_num_logs - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy -- name: XCCDF Value var_auditd_num_logs # promote to variable +- name: XCCDF Value var_auditd_space_left # promote to variable set_fact: - var_auditd_num_logs: !!str + var_auditd_space_left: !!str tags: - always -- name: Configure auditd Number of Logs Retained +- name: Configure auditd space_left on Low Disk Space lineinfile: dest: /etc/audit/auditd.conf - line: num_logs = {{ var_auditd_num_logs }} - regexp: ^\s*num_logs\s*=\s*.*$ + line: space_left = {{ var_auditd_space_left }} + regexp: ^\s*space_left\s*=\s*.*$ state: present create: true when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - - CJIS-5.4.1.1 - - NIST-800-171-3.3.1 - - NIST-800-53-AU-11 + - NIST-800-53-AU-5(1) + - NIST-800-53-AU-5(2) + - NIST-800-53-AU-5(4) + - NIST-800-53-AU-5(b) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.7 + - PCI-DSSv4-10.5 - PCI-DSSv4-10.5.1 - - auditd_data_retention_num_logs + - auditd_data_retention_space_left - low_complexity - low_disruption - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - - Configure auditd space_left Action on Low Disk Space - The auditd service can be configured to take an action + + + + + + + + + + + Configure auditd space_left Action on Low Disk Space + The auditd service can be configured to take an action when disk space starts to run low. Edit the file /etc/audit/auditd.conf. Modify the following line, substituting ACTION appropriately: -space_left_action = ACTION +space_left_action = ACTION + Possible values for ACTION are described in the auditd.conf man page. These include: syslogemailexecsuspendsinglehalt Set this to email (instead of the default, which is suspend) as it is more likely to get prompt attention. Acceptable values -also include suspend, single, and halt. - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 19 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 5.4.1.1 - APO11.04 - APO12.06 - APO13.01 - BAI03.05 - BAI04.04 - BAI08.02 - DSS02.02 - DSS02.04 - DSS02.07 - DSS03.01 - DSS05.04 - DSS05.07 - MEA02.01 - 3.3.1 - CCI-001855 - 164.312(a)(2)(ii) - 4.2.3.10 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.4.4.7 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.8 - SR 2.9 - SR 6.1 - SR 7.1 - SR 7.2 - A.12.1.3 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.16.1.4 - A.16.1.5 - A.16.1.7 - A.17.2.1 - AU-5(b) - AU-5(2) - AU-5(1) - AU-5(4) - CM-6(a) - DE.AE-3 - DE.AE-5 - PR.DS-4 - PR.PT-1 - RS.AN-1 - RS.AN-4 - Req-10.7 - 10.5.1 - SRG-OS-000343-GPOS-00134 - Notifying administrators of an impending disk space problem may -allow them to take corrective action prior to any disruption. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +also include suspend, single, and halt. + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 19 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 5.4.1.1 + APO11.04 + APO12.06 + APO13.01 + BAI03.05 + BAI04.04 + BAI08.02 + DSS02.02 + DSS02.04 + DSS02.07 + DSS03.01 + DSS05.04 + DSS05.07 + MEA02.01 + 3.3.1 + CCI-001855 + 164.312(a)(2)(ii) + 4.2.3.10 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.4.4.7 + 4.3.4.5.6 + 4.3.4.5.7 + 4.3.4.5.8 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.8 + SR 2.9 + SR 6.1 + SR 7.1 + SR 7.2 + A.12.1.3 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.16.1.4 + A.16.1.5 + A.16.1.7 + A.17.2.1 + AU-5(b) + AU-5(2) + AU-5(1) + AU-5(4) + CM-6(a) + DE.AE-3 + DE.AE-5 + PR.DS-4 + PR.PT-1 + RS.AN-1 + RS.AN-4 + Req-10.7 + SRG-OS-000343-GPOS-00134 + 10.5.1 + 10.5 + OL09-00-000870 + SV-271600r1091512_rule + Notifying administrators of an impending disk space problem may +allow them to take corrective action prior to any disruption. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -var_auditd_space_left_action='' +var_auditd_space_left_action='' +var_auditd_space_left_action="$(echo $var_auditd_space_left_action | cut -d \| -f 1)" # # If space_left_action present in /etc/audit/auditd.conf, change value # to var_auditd_space_left_action, else @@ -116679,12 +191589,13 @@ fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000870 - NIST-800-171-3.3.1 - NIST-800-53-AU-5(1) - NIST-800-53-AU-5(2) @@ -116692,6 +191603,7 @@ fi - NIST-800-53-AU-5(b) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.7 + - PCI-DSSv4-10.5 - PCI-DSSv4-10.5.1 - auditd_data_retention_space_left_action - low_complexity @@ -116701,22 +191613,23 @@ fi - restrict_strategy - name: XCCDF Value var_auditd_space_left_action # promote to variable set_fact: - var_auditd_space_left_action: !!str + var_auditd_space_left_action: !!str tags: - always - name: Configure auditd space_left Action on Low Disk Space lineinfile: dest: /etc/audit/auditd.conf - line: space_left_action = {{ var_auditd_space_left_action }} + line: space_left_action = {{ var_auditd_space_left_action.split('|')[0] }} regexp: ^\s*space_left_action\s*=\s*.*$ state: present create: true when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000870 - NIST-800-171-3.3.1 - NIST-800-53-AU-5(1) - NIST-800-53-AU-5(2) @@ -116724,6 +191637,7 @@ fi - NIST-800-53-AU-5(b) - NIST-800-53-CM-6(a) - PCI-DSS-Req-10.7 + - PCI-DSSv4-10.5 - PCI-DSSv4-10.5.1 - auditd_data_retention_space_left_action - low_complexity @@ -116731,100 +191645,102 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - - Configure auditd space_left on Low Disk Space - The auditd service can be configured to take an action + + + + + + + + + + + Configure auditd space_left on Low Disk Space + The auditd service can be configured to take an action when disk space is running low but prior to running out of space completely. Edit the file /etc/audit/auditd.conf. Add or modify the following line, substituting PERCENTAGE appropriately: space_left = PERCENTAGE% Set this value to at least 25 to cause the system to -notify the user of an issue. - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 19 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - APO11.04 - APO12.06 - APO13.01 - BAI03.05 - BAI04.04 - BAI08.02 - DSS02.02 - DSS02.04 - DSS02.07 - DSS03.01 - DSS05.04 - DSS05.07 - MEA02.01 - CCI-001855 - 4.2.3.10 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.4.4.7 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.8 - SR 2.9 - SR 6.1 - SR 7.1 - SR 7.2 - A.12.1.3 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.16.1.4 - A.16.1.5 - A.16.1.7 - A.17.2.1 - AU-5(b) - AU-5(2) - AU-5(1) - AU-5(4) - CM-6(a) - DE.AE-3 - DE.AE-5 - PR.DS-4 - PR.PT-1 - RS.AN-1 - RS.AN-4 - Req-10.7 - SRG-OS-000343-GPOS-00134 - Notifying administrators of an impending disk space problem may allow them to -take corrective action prior to any disruption. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +notify the user of an issue. + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 19 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + APO11.04 + APO12.06 + APO13.01 + BAI03.05 + BAI04.04 + BAI08.02 + DSS02.02 + DSS02.04 + DSS02.07 + DSS03.01 + DSS05.04 + DSS05.07 + MEA02.01 + CCI-001855 + 4.2.3.10 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.4.4.7 + 4.3.4.5.6 + 4.3.4.5.7 + 4.3.4.5.8 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.8 + SR 2.9 + SR 6.1 + SR 7.1 + SR 7.2 + A.12.1.3 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.16.1.4 + A.16.1.5 + A.16.1.7 + A.17.2.1 + AU-5(b) + AU-5(2) + AU-5(1) + AU-5(4) + CM-6(a) + DE.AE-3 + DE.AE-5 + PR.DS-4 + PR.PT-1 + RS.AN-1 + RS.AN-4 + Req-10.7 + SRG-OS-000343-GPOS-00134 + OL09-00-000865 + SV-271599r1091509_rule + Notifying administrators of an impending disk space problem may allow them to +take corrective action prior to any disruption. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -var_auditd_space_left_percentage='' +var_auditd_space_left_percentage='' grep -q "^space_left[[:space:]]*=.*$" /etc/audit/auditd.conf && \ @@ -116834,11 +191750,12 @@ grep -q "^space_left[[:space:]]*=.*$" /etc/audit/auditd.conf && \ else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-000865 - NIST-800-53-AU-5(1) - NIST-800-53-AU-5(2) - NIST-800-53-AU-5(4) @@ -116853,7 +191770,7 @@ fi - restrict_strategy - name: XCCDF Value var_auditd_space_left_percentage # promote to variable set_fact: - var_auditd_space_left_percentage: !!str + var_auditd_space_left_percentage: !!str tags: - always @@ -116866,8 +191783,9 @@ fi create: true when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-000865 - NIST-800-53-AU-5(1) - NIST-800-53-AU-5(2) - NIST-800-53-AU-5(4) @@ -116880,28 +191798,31 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - - Set number of records to cause an explicit flush to audit logs - To configure Audit daemon to issue an explicit flush to disk command -after writing records, set freq to -in /etc/audit/auditd.conf. - CM-6 - FAU_GEN.1 - SRG-OS-000051-GPOS-00024 - If option freq isn't set to , the flush to disk + + + + + + + + + + + Set number of records to cause an explicit flush to audit logs + To configure Audit daemon to issue an explicit flush to disk command +after writing records, set freq to +in /etc/audit/auditd.conf. + CCI-000154 + CM-6 + FAU_GEN.1 + SRG-OS-000051-GPOS-00024 + OL09-00-000775 + SV-271582r1092574_rule + If option freq isn't set to , the flush to disk may happen after higher number of records, increasing the danger -of audit loss. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +of audit loss. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then if [ -e "/etc/audit/auditd.conf" ] ; then @@ -116921,11 +191842,12 @@ rm "/etc/audit/auditd.conf.bak" else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-000775 - NIST-800-53-CM-6 - auditd_freq - low_complexity @@ -116940,8 +191862,8 @@ fi - name: Check for duplicate values lineinfile: path: /etc/audit/auditd.conf - create: false - regexp: (?i)^\s*freq\s*=\s* + create: true + regexp: (?i)(?i)^\s*freq\s*=\s* state: absent check_mode: true changed_when: false @@ -116950,8 +191872,8 @@ fi - name: Deduplicate values from /etc/audit/auditd.conf lineinfile: path: /etc/audit/auditd.conf - create: false - regexp: (?i)^\s*freq\s*=\s* + create: true + regexp: (?i)(?i)^\s*freq\s*=\s* state: absent when: dupes.found is defined and dupes.found > 1 @@ -116959,13 +191881,14 @@ fi lineinfile: path: /etc/audit/auditd.conf create: true - regexp: (?i)^\s*freq\s*=\s* + regexp: (?i)(?i)^\s*freq\s*=\s* line: freq = 50 state: present when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-000775 - NIST-800-53-CM-6 - auditd_freq - low_complexity @@ -116973,28 +191896,30 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Include Local Events in Audit Logs - To configure Audit daemon to include local events in Audit logs, set + + + + + + + + + + Include Local Events in Audit Logs + To configure Audit daemon to include local events in Audit logs, set local_events to yes in /etc/audit/auditd.conf. -This is the default setting. - CCI-000366 - CM-6 - FAU_GEN.1 - SRG-OS-000062-GPOS-00031 - SRG-OS-000480-GPOS-00227 - If option local_events isn't set to yes only events from -network will be aggregated. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +This is the default setting. + CCI-000366 + CCI-000169 + CM-6 + SRG-OS-000062-GPOS-00031 + SRG-OS-000480-GPOS-00227 + OL09-00-000800 + SV-271586r1092576_rule + If option local_events isn't set to yes only events from +network will be aggregated. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then if [ -e "/etc/audit/auditd.conf" ] ; then @@ -117014,11 +191939,12 @@ rm "/etc/audit/auditd.conf.bak" else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-000800 - NIST-800-53-CM-6 - auditd_local_events - low_complexity @@ -117033,8 +191959,8 @@ fi - name: Check for duplicate values lineinfile: path: /etc/audit/auditd.conf - create: false - regexp: (?i)^\s*local_events\s*=\s* + create: true + regexp: (?i)(?i)^\s*local_events\s*=\s* state: absent check_mode: true changed_when: false @@ -117043,8 +191969,8 @@ fi - name: Deduplicate values from /etc/audit/auditd.conf lineinfile: path: /etc/audit/auditd.conf - create: false - regexp: (?i)^\s*local_events\s*=\s* + create: true + regexp: (?i)(?i)^\s*local_events\s*=\s* state: absent when: dupes.found is defined and dupes.found > 1 @@ -117052,13 +191978,14 @@ fi lineinfile: path: /etc/audit/auditd.conf create: true - regexp: (?i)^\s*local_events\s*=\s* + regexp: (?i)(?i)^\s*local_events\s*=\s* line: local_events = yes state: present when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-000800 - NIST-800-53-CM-6 - auditd_local_events - low_complexity @@ -117066,30 +191993,42 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Resolve information before writing to audit logs - To configure Audit daemon to resolve all uid, gid, syscall, + + + + + + + + + + Resolve information before writing to audit logs + To configure Audit daemon to resolve all uid, gid, syscall, architecture, and socket address information before writing the events to disk, set log_format to ENRICHED -in /etc/audit/auditd.conf. - CCI-000366 - CM-6 - AU-3 - FAU_GEN.1.2 - SRG-OS-000255-GPOS-00096 - SRG-OS-000480-GPOS-00227 - If option log_format isn't set to ENRICHED, the -audit records will be stored in a format exactly as the kernel sends them. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +in /etc/audit/auditd.conf. + CCI-000366 + CCI-001487 + CM-6 + AU-3 + FAU_GEN.1.2 + SRG-OS-000255-GPOS-00096 + SRG-OS-000480-GPOS-00227 + SRG-APP-000096-CTR-000175 + SRG-APP-000097-CTR-000180 + SRG-APP-000098-CTR-000185 + SRG-APP-000099-CTR-000190 + SRG-APP-000100-CTR-000195 + SRG-APP-000100-CTR-000200 + SRG-APP-000109-CTR-000215 + SRG-APP-000290-CTR-000670 + SRG-APP-000357-CTR-000800 + OL09-00-000835 + SV-271593r1092580_rule + If option log_format isn't set to ENRICHED, the +audit records will be stored in a format exactly as the kernel sends them. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then if [ -e "/etc/audit/auditd.conf" ] ; then @@ -117109,11 +192048,12 @@ rm "/etc/audit/auditd.conf.bak" else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-000835 - NIST-800-53-AU-3 - NIST-800-53-CM-6 - auditd_log_format @@ -117129,8 +192069,8 @@ fi - name: Check for duplicate values lineinfile: path: /etc/audit/auditd.conf - create: false - regexp: (?i)^\s*log_format\s*=\s* + create: true + regexp: (?i)(?i)^\s*log_format\s*=\s* state: absent check_mode: true changed_when: false @@ -117139,8 +192079,8 @@ fi - name: Deduplicate values from /etc/audit/auditd.conf lineinfile: path: /etc/audit/auditd.conf - create: false - regexp: (?i)^\s*log_format\s*=\s* + create: true + regexp: (?i)(?i)^\s*log_format\s*=\s* state: absent when: dupes.found is defined and dupes.found > 1 @@ -117148,13 +192088,14 @@ fi lineinfile: path: /etc/audit/auditd.conf create: true - regexp: (?i)^\s*log_format\s*=\s* + regexp: (?i)(?i)^\s*log_format\s*=\s* line: log_format = ENRICHED state: present when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-000835 - NIST-800-53-AU-3 - NIST-800-53-CM-6 - auditd_log_format @@ -117163,32 +192104,44 @@ fi - low_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Set hostname as computer node name in audit logs - To configure Audit daemon to use value returned by gethostname -syscall as computer node name in the audit events, -set name_format to hostname -in /etc/audit/auditd.conf. - CCI-001851 - CM-6 - AU-3 - FAU_GEN.1.2 - SRG-OS-000039-GPOS-00017 - SRG-OS-000342-GPOS-00133 - SRG-OS-000479-GPOS-00224 - If option name_format is left at its default value of + + + + + + + + + + Set type of computer node name logging in audit logs + To configure Audit daemon to use a unique identifier +as computer node name in the audit events, +set name_format to +in /etc/audit/auditd.conf. + Whenever the variable var_auditd_name_format uses a multiple value option, for example +A|B|C, the first value will be used when remediating this rule. + CCI-000132 + CCI-001851 + CM-6 + AU-3 + FAU_GEN.1.2 + SRG-OS-000039-GPOS-00017 + SRG-OS-000342-GPOS-00133 + SRG-OS-000479-GPOS-00224 + 10.2.2 + 10.2 + OL09-00-000755 + SV-271578r1092572_rule + If option name_format is left at its default value of none, audit events from different computers may be hard -to distinguish. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +to distinguish. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +var_auditd_name_format='' + + +var_auditd_name_format="$(echo $var_auditd_name_format | cut -d \| -f 1)" if [ -e "/etc/audit/auditd.conf" ] ; then @@ -117201,20 +192154,48 @@ sed -i -e '$a\' "/etc/audit/auditd.conf" cp "/etc/audit/auditd.conf" "/etc/audit/auditd.conf.bak" # Insert at the end of the file -printf '%s\n' "name_format = hostname" >> "/etc/audit/auditd.conf" +printf '%s\n' "name_format = $var_auditd_name_format" >> "/etc/audit/auditd.conf" # Clean up after ourselves. rm "/etc/audit/auditd.conf.bak" else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-000755 - NIST-800-53-AU-3 - NIST-800-53-CM-6 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.2 + - auditd_name_format + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy +- name: XCCDF Value var_auditd_name_format # promote to variable + set_fact: + var_auditd_name_format: !!str + tags: + - always + +- name: Set type of computer node name logging in audit logs - Define Value to Be + Used in the Remediation + ansible.builtin.set_fact: auditd_name_format_split="{{ var_auditd_name_format.split('|')[0] + }}" + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-000755 + - NIST-800-53-AU-3 + - NIST-800-53-CM-6 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.2 - auditd_name_format - low_complexity - low_disruption @@ -117222,14 +192203,14 @@ fi - no_reboot_needed - restrict_strategy -- name: Set hostname as computer node name in audit logs +- name: Set type of computer node name logging in audit logs block: - name: Check for duplicate values lineinfile: path: /etc/audit/auditd.conf - create: false - regexp: (?i)^\s*name_format\s*=\s* + create: true + regexp: (?i)(?i)^\s*name_format\s*=\s* state: absent check_mode: true changed_when: false @@ -117238,8 +192219,8 @@ fi - name: Deduplicate values from /etc/audit/auditd.conf lineinfile: path: /etc/audit/auditd.conf - create: false - regexp: (?i)^\s*name_format\s*=\s* + create: true + regexp: (?i)(?i)^\s*name_format\s*=\s* state: absent when: dupes.found is defined and dupes.found > 1 @@ -117247,42 +192228,48 @@ fi lineinfile: path: /etc/audit/auditd.conf create: true - regexp: (?i)^\s*name_format\s*=\s* - line: name_format = hostname + regexp: (?i)(?i)^\s*name_format\s*=\s* + line: name_format = {{ auditd_name_format_split }} state: present when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-000755 - NIST-800-53-AU-3 - NIST-800-53-CM-6 + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.2 - auditd_name_format - low_complexity - low_disruption - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Appropriate Action Must be Setup When the Internal Audit Event Queue is Full - The audit system should have an action setup in the event the internal event queue becomes full. + + + + + + + + + + + Appropriate Action Must be Setup When the Internal Audit Event Queue is Full + The audit system should have an action setup in the event the internal event queue becomes full. To setup an overflow action edit /etc/audit/auditd.conf. Set overflow_action -to one of the following values: syslog, single, halt. - CCI-001851 - AU-4(1) - SRG-OS-000342-GPOS-00133 - SRG-OS-000479-GPOS-00224 - The audit system should have an action setup in the event the internal event queue becomes full -so that no data is lost. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +to one of the following values: syslog, single, halt. + CCI-001851 + AU-4(1) + SRG-OS-000342-GPOS-00133 + SRG-OS-000479-GPOS-00224 + OL09-00-000860 + SV-271598r1092588_rule + The audit system should have an action setup in the event the internal event queue becomes full +so that no data is lost. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then if [ -e "/etc/audit/auditd.conf" ] ; then @@ -117302,11 +192289,12 @@ rm "/etc/audit/auditd.conf.bak" else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-000860 - NIST-800-53-AU-4(1) - auditd_overflow_action - low_complexity @@ -117321,8 +192309,8 @@ fi - name: Check for duplicate values lineinfile: path: /etc/audit/auditd.conf - create: false - regexp: (?i)^\s*overflow_action\s*=\s* + create: true + regexp: (?i)(?i)^\s*overflow_action\s*=\s* state: absent check_mode: true changed_when: false @@ -117331,8 +192319,8 @@ fi - name: Deduplicate values from /etc/audit/auditd.conf lineinfile: path: /etc/audit/auditd.conf - create: false - regexp: (?i)^\s*overflow_action\s*=\s* + create: true + regexp: (?i)(?i)^\s*overflow_action\s*=\s* state: absent when: dupes.found is defined and dupes.found > 1 @@ -117340,13 +192328,14 @@ fi lineinfile: path: /etc/audit/auditd.conf create: true - regexp: (?i)^\s*overflow_action\s*=\s* + regexp: (?i)(?i)^\s*overflow_action\s*=\s* line: overflow_action = syslog state: present when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-000860 - NIST-800-53-AU-4(1) - auditd_overflow_action - low_complexity @@ -117354,26 +192343,28 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Write Audit Logs to the Disk - To configure Audit daemon to write Audit logs to the disk, set + + + + + + + + + + Write Audit Logs to the Disk + To configure Audit daemon to write Audit logs to the disk, set write_logs to yes in /etc/audit/auditd.conf. -This is the default setting. - CM-6 - FAU_STG.1 - SRG-OS-000480-GPOS-00227 - If write_logs isn't set to yes, the Audit logs will -not be written to the disk. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then +This is the default setting. + CCI-000366 + CM-6 + SRG-OS-000480-GPOS-00227 + OL09-00-000880 + SV-271602r1092590_rule + If write_logs isn't set to yes, the Audit logs will +not be written to the disk. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then if [ -e "/etc/audit/auditd.conf" ] ; then @@ -117393,11 +192384,12 @@ rm "/etc/audit/auditd.conf.bak" else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Gather the package facts + + - name: Gather the package facts package_facts: manager: auto tags: + - DISA-STIG-OL09-00-000880 - NIST-800-53-CM-6 - auditd_write_logs - low_complexity @@ -117412,8 +192404,8 @@ fi - name: Check for duplicate values lineinfile: path: /etc/audit/auditd.conf - create: false - regexp: (?i)^\s*write_logs\s*=\s* + create: true + regexp: (?i)(?i)^\s*write_logs\s*=\s* state: absent check_mode: true changed_when: false @@ -117422,8 +192414,8 @@ fi - name: Deduplicate values from /etc/audit/auditd.conf lineinfile: path: /etc/audit/auditd.conf - create: false - regexp: (?i)^\s*write_logs\s*=\s* + create: true + regexp: (?i)(?i)^\s*write_logs\s*=\s* state: absent when: dupes.found is defined and dupes.found > 1 @@ -117431,13 +192423,14 @@ fi lineinfile: path: /etc/audit/auditd.conf create: true - regexp: (?i)^\s*write_logs\s*=\s* + regexp: (?i)(?i)^\s*write_logs\s*=\s* line: write_logs = yes state: present when: - '"audit" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-000880 - NIST-800-53-CM-6 - auditd_write_logs - low_complexity @@ -117445,25 +192438,190 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - - System Accounting with auditd - The auditd program can perform comprehensive + + + + + + + + + + + System Accounting with auditd + The audit service provides substantial capabilities +for recording system activities. This section +deals with permissions of auditd related files. + + Verify Permissions on /etc/audit/auditd.conf + +To properly set the permissions of /etc/audit/auditd.conf, run the command: +$ sudo chmod 0640 /etc/audit/auditd.conf + + CCI-000171 + AU-12(b) + SRG-OS-000063-GPOS-00032 + OL09-00-000810 + SV-271588r1091476_rule + Without the capability to restrict the roles and individuals that can select which events +are audited, unauthorized personnel may be able to prevent the auditing of critical +events. Misconfigured audits may degrade the system's performance by overwhelming +the audit log. Misconfigured audits may also make it more difficult to establish, +correlate, and investigate the events relating to an incident or identify +those responsible for one. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +chmod u-xs,g-xws,o-xwrt /etc/audit/auditd.conf + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-000810 + - NIST-800-53-AU-12(b) + - configure_strategy + - file_permissions_etc_audit_auditd + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /etc/audit/auditd.conf + stat: + path: /etc/audit/auditd.conf + register: file_exists + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-000810 + - NIST-800-53-AU-12(b) + - configure_strategy + - file_permissions_etc_audit_auditd + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure permission u-xs,g-xws,o-xwrt on /etc/audit/auditd.conf + file: + path: /etc/audit/auditd.conf + mode: u-xs,g-xws,o-xwrt + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - file_exists.stat is defined and file_exists.stat.exists + tags: + - DISA-STIG-OL09-00-000810 + - NIST-800-53-AU-12(b) + - configure_strategy + - file_permissions_etc_audit_auditd + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + Verify Permissions on /etc/audit/rules.d/*.rules + +To properly set the permissions of /etc/audit/rules.d/*.rules, run the command: +$ sudo chmod 0600 /etc/audit/rules.d/*.rules + + CCI-000171 + AU-12(b) + SRG-OS-000063-GPOS-00032 + OL09-00-000805 + SV-271587r1091473_rule + Without the capability to restrict the roles and individuals that can select which events +are audited, unauthorized personnel may be able to prevent the auditing of critical +events. Misconfigured audits may degrade the system's performance by overwhelming +the audit log. Misconfigured audits may also make it more difficult to establish, +correlate, and investigate the events relating to an incident or identify +those responsible for one. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +find -L /etc/audit/rules.d/ -maxdepth 1 -perm /u+xs,g+xwrs,o+xwrt -type f -regextype posix-extended -regex '^.*rules$' -exec chmod u-xs,g-xwrs,o-xwrt {} \; + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-000805 + - NIST-800-53-AU-12(b) + - configure_strategy + - file_permissions_etc_audit_rulesd + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Find /etc/audit/rules.d/ file(s) + command: find -H /etc/audit/rules.d/ -maxdepth 1 -perm /u+xs,g+xwrs,o+xwrt -type + f -regextype posix-extended -regex "^.*rules$" + register: files_found + changed_when: false + failed_when: false + check_mode: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-000805 + - NIST-800-53-AU-12(b) + - configure_strategy + - file_permissions_etc_audit_rulesd + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Set permissions for /etc/audit/rules.d/ file(s) + file: + path: '{{ item }}' + mode: u-xs,g-xwrs,o-xwrt + state: file + with_items: + - '{{ files_found.stdout_lines }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-000805 + - NIST-800-53-AU-12(b) + - configure_strategy + - file_permissions_etc_audit_rulesd + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + + + + System Accounting with auditd + The auditd program can perform comprehensive monitoring of system activity. This section makes use of recommended configuration settings for specific policies or use cases. -The rules in this section make use of rules defined in /usr/share/doc/audit-VERSION/rules. - - - Configure auditing of unsuccessful file accesses - Ensure that unsuccessful attempts to access a file are audited. +The rules in this section make use of rules defined in /usr/share/doc/audit-VERSION/rules. + + Configure auditing of unsuccessful file accesses + Ensure that unsuccessful attempts to access a file are audited. The following rules configure audit as described above: ## Unsuccessful file access (any other opens) This has to go last. @@ -117475,24 +192633,30 @@ The following rules configure audit as described above: Load new Audit rules into kernel by running: augenrules --load -Note: This rule uses a special set of Audit rules to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are alligned with your needs. - 0582 - 0584 - 05885 - 0586 - 0846 - 0957 - AU-2(a) - FAU_GEN.1.1.c - SRG-OS-000458-GPOS-00203 - SRG-OS-000474-GPOS-00219 - SRG-OS-000475-GPOS-00220 - SRG-OS-000463-GPOS-00207 - SRG-OS-000465-GPOS-00209 - SRG-OS-000461-GPOS-00205 - Unsuccessful attempts to access a file might be signs of malicious activity happening within the system. Auditing of such activities helps in their monitoring and investigation. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then +Note: This rule uses a special set of Audit rules to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are alligned with your needs. + 0582 + 0584 + 05885 + 0586 + 0846 + 0957 + AU-2(a) + FAU_GEN.1.1.c + SRG-OS-000458-GPOS-00203 + SRG-OS-000474-GPOS-00219 + SRG-OS-000475-GPOS-00220 + SRG-OS-000463-GPOS-00207 + SRG-OS-000465-GPOS-00209 + SRG-OS-000461-GPOS-00205 + SRG-APP-000091-CTR-000160 + SRG-APP-000492-CTR-001220 + SRG-APP-000493-CTR-001225 + SRG-APP-000494-CTR-001230 + SRG-APP-000500-CTR-001260 + SRG-APP-000507-CTR-001295 + Unsuccessful attempts to access a file might be signs of malicious activity happening within the system. Auditing of such activities helps in their monitoring and investigation. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then cat << 'EOF' > /etc/audit/rules.d/30-ospp-v42-3-access-failed.rules ## Unsuccessful file access (any other opens) This has to go last. @@ -117509,8 +192673,20 @@ augenrules --load else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Put contents into /etc/audit/rules.d/30-ospp-v42-3-access-failed.rules according + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-53-AU-2(a) + - audit_access_failed + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Put contents into /etc/audit/rules.d/30-ospp-v42-3-access-failed.rules according to policy copy: dest: /etc/audit/rules.d/30-ospp-v42-3-access-failed.rules @@ -117521,7 +192697,7 @@ fi -a always,exit -F arch=b32 -S open,openat,openat2,open_by_handle_at -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-access -a always,exit -F arch=b64 -S open,openat,openat2,open_by_handle_at -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-access force: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AU-2(a) - audit_access_failed @@ -117531,11 +192707,12 @@ fi - no_reboot_needed - restrict_strategy -- name: Remove any permissions from other group - file: +- name: Configure auditing of unsuccessful file accesses - Remove any permissions + from group and other + ansible.builtin.file: path: /etc/audit/rules.d/30-ospp-v42-3-access-failed.rules - mode: o-rwx - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + mode: g-rwx,o-rwx + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AU-2(a) - audit_access_failed @@ -117544,17 +192721,17 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Configure auditing of successful file accesses - Ensure that successful attempts to access a file are audited. + + + + + + + + + + Configure auditing of successful file accesses + Ensure that successful attempts to access a file are audited. The following rules configure audit as described above: ## Successful file access (any other opens) This has to go last. @@ -117565,24 +192742,24 @@ The following rules configure audit as described above: Load new Audit rules into kernel by running: augenrules --load -Note: This rule uses a special set of Audit rules to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are alligned with your needs. - 0582 - 0584 - 05885 - 0586 - 0846 - 0957 - AU-2(a) - FAU_GEN.1.1.c - SRG-OS-000458-GPOS-00203 - SRG-OS-000474-GPOS-00219 - SRG-OS-000475-GPOS-00220 - SRG-OS-000463-GPOS-00207 - SRG-OS-000465-GPOS-00209 - SRG-OS-000461-GPOS-00205 - Auditing of successful attempts to access a file helps in investigation of activities performed on the system. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then +Note: This rule uses a special set of Audit rules to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are alligned with your needs. + 0582 + 0584 + 05885 + 0586 + 0846 + 0957 + AU-2(a) + FAU_GEN.1.1.c + SRG-OS-000458-GPOS-00203 + SRG-OS-000474-GPOS-00219 + SRG-OS-000475-GPOS-00220 + SRG-OS-000463-GPOS-00207 + SRG-OS-000465-GPOS-00209 + SRG-OS-000461-GPOS-00205 + Auditing of successful attempts to access a file helps in investigation of activities performed on the system. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then cat << 'EOF' > /etc/audit/rules.d/30-ospp-v42-3-access-success.rules ## Successful file access (any other opens) This has to go last. @@ -117598,18 +192775,10 @@ augenrules --load else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Put contents into /etc/audit/rules.d/30-ospp-v42-3-access-success.rules according - to policy - copy: - dest: /etc/audit/rules.d/30-ospp-v42-3-access-success.rules - content: | - ## Successful file access (any other opens) This has to go last. - ## These next two are likely to result in a whole lot of events - -a always,exit -F arch=b32 -S open,openat,openat2,open_by_handle_at -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-access - -a always,exit -F arch=b64 -S open,openat,openat2,open_by_handle_at -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-access - force: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + + - name: Gather the package facts + package_facts: + manager: auto tags: - NIST-800-53-AU-2(a) - audit_access_success @@ -117619,11 +192788,17 @@ fi - no_reboot_needed - restrict_strategy -- name: Remove any permissions from other group - file: - path: /etc/audit/rules.d/30-ospp-v42-3-access-success.rules - mode: o-rwx - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] +- name: Put contents into /etc/audit/rules.d/30-ospp-v42-3-access-success.rules according + to policy + copy: + dest: /etc/audit/rules.d/30-ospp-v42-3-access-success.rules + content: | + ## Successful file access (any other opens) This has to go last. + ## These next two are likely to result in a whole lot of events + -a always,exit -F arch=b32 -S open,openat,openat2,open_by_handle_at -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-access + -a always,exit -F arch=b64 -S open,openat,openat2,open_by_handle_at -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-access + force: true + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AU-2(a) - audit_access_success @@ -117632,17 +192807,32 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Configure basic parameters of Audit system - Perform basic configuration of Audit system. + +- name: Configure auditing of successful file accesses - Remove any permissions from + group and other + ansible.builtin.file: + path: /etc/audit/rules.d/30-ospp-v42-3-access-success.rules + mode: g-rwx,o-rwx + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-AU-2(a) + - audit_access_success + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + + + + + + + + + + Configure basic parameters of Audit system + Perform basic configuration of Audit system. Make sure that any previously defined rules are cleared, the auditing system is configured to handle sudden bursts of events, and in cases of failure, messages are configured to be directed to system log. The following rules configure audit as described above: @@ -117660,15 +192850,16 @@ The following rules configure audit as described above: -f 1 Load new Audit rules into kernel by running: -augenrules --load - It might happen that Audit buffer configured by this rule is not large enough for certain use cases. If that is the case, the buffer size can be overridden by placing -b larger_buffer_size into a file within /etc/audit/rules.d directory, replacing larger_file_size with the desired value. The file name should start with a number higher than 10 and lower than 99. - AU-2(a) - FAU_GEN.1 - SRG-OS-000365-GPOS-00152 - SRG-OS-000475-GPOS-00220 - Without basic configurations, audit may not perform as expected. It may not be able to correctly handle events under stressful conditions, or log events in case of failure. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then +augenrules --load + + It might happen that Audit buffer configured by this rule is not large enough for certain use cases. If that is the case, the buffer size can be overridden by placing -b larger_buffer_size into a file within /etc/audit/rules.d directory, replacing larger_file_size with the desired value. The file name should start with a number higher than 10 and lower than 99. + AU-2(a) + FAU_GEN.1 + SRG-OS-000365-GPOS-00152 + SRG-OS-000475-GPOS-00220 + Without basic configurations, audit may not perform as expected. It may not be able to correctly handle events under stressful conditions, or log events in case of failure. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then cat << 'EOF' > /etc/audit/rules.d/10-base-config.rules ## First rule - delete all @@ -117693,8 +192884,20 @@ augenrules --load else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Put contents into /etc/audit/rules.d/10-base-config.rules according to policy + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-53-AU-2(a) + - audit_basic_configuration + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Put contents into /etc/audit/rules.d/10-base-config.rules according to policy copy: dest: /etc/audit/rules.d/10-base-config.rules content: |+ @@ -117712,7 +192915,7 @@ fi -f 1 force: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AU-2(a) - audit_basic_configuration @@ -117722,11 +192925,12 @@ fi - no_reboot_needed - restrict_strategy -- name: Remove any permissions from other group - file: +- name: Configure basic parameters of Audit system - Remove any permissions from group + and other + ansible.builtin.file: path: /etc/audit/rules.d/10-base-config.rules - mode: o-rwx - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + mode: g-rwx,o-rwx + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AU-2(a) - audit_basic_configuration @@ -117735,17 +192939,17 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Configure auditing of unsuccessful file creations - Ensure that unsuccessful attempts to create a file are audited. + + + + + + + + + + Configure auditing of unsuccessful file creations + Ensure that unsuccessful attempts to create a file are audited. The following rules configure audit as described above: ## Unsuccessful file creation (open with O_CREAT) @@ -117765,18 +192969,24 @@ The following rules configure audit as described above: Load new Audit rules into kernel by running: augenrules --load -Note: This rule uses a special set of Audit rules to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are alligned with your needs. - AU-2(a) - FAU_GEN.1.1.c - SRG-OS-000458-GPOS-00203 - SRG-OS-000474-GPOS-00219 - SRG-OS-000475-GPOS-00220 - SRG-OS-000463-GPOS-00207 - SRG-OS-000465-GPOS-00209 - SRG-OS-000461-GPOS-00205 - Unsuccessful file creations might be a sign of a malicious action being performed on the system. Keeping log of such events helps in monitoring and investigation of such actions. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then +Note: This rule uses a special set of Audit rules to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are alligned with your needs. + AU-2(a) + FAU_GEN.1.1.c + SRG-OS-000458-GPOS-00203 + SRG-OS-000474-GPOS-00219 + SRG-OS-000475-GPOS-00220 + SRG-OS-000463-GPOS-00207 + SRG-OS-000465-GPOS-00209 + SRG-OS-000461-GPOS-00205 + SRG-APP-000091-CTR-000160 + SRG-APP-000492-CTR-001220 + SRG-APP-000493-CTR-001225 + SRG-APP-000494-CTR-001230 + SRG-APP-000500-CTR-001260 + SRG-APP-000507-CTR-001295 + Unsuccessful file creations might be a sign of a malicious action being performed on the system. Keeping log of such events helps in monitoring and investigation of such actions. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then cat << 'EOF' > /etc/audit/rules.d/30-ospp-v42-1-create-failed.rules ## Unsuccessful file creation (open with O_CREAT) @@ -117801,8 +193011,20 @@ augenrules --load else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Put contents into /etc/audit/rules.d/30-ospp-v42-1-create-failed.rules according + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-53-AU-2(a) + - audit_create_failed + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Put contents into /etc/audit/rules.d/30-ospp-v42-1-create-failed.rules according to policy copy: dest: /etc/audit/rules.d/30-ospp-v42-1-create-failed.rules @@ -117821,7 +193043,7 @@ fi -a always,exit -F arch=b32 -S creat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-create -a always,exit -F arch=b64 -S creat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-create force: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AU-2(a) - audit_create_failed @@ -117831,11 +193053,12 @@ fi - no_reboot_needed - restrict_strategy -- name: Remove any permissions from other group - file: +- name: Configure auditing of unsuccessful file creations - Remove any permissions + from group and other + ansible.builtin.file: path: /etc/audit/rules.d/30-ospp-v42-1-create-failed.rules - mode: o-rwx - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + mode: g-rwx,o-rwx + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AU-2(a) - audit_create_failed @@ -117844,17 +193067,17 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Configure auditing of successful file creations - Ensure that successful attempts to create a file are audited. + + + + + + + + + + Configure auditing of successful file creations + Ensure that successful attempts to create a file are audited. The following rules configure audit as described above: ## Successful file creation (open with O_CREAT) @@ -117868,18 +193091,18 @@ The following rules configure audit as described above: Load new Audit rules into kernel by running: augenrules --load -Note: This rule uses a special set of Audit rules to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are alligned with your needs. - AU-2(a) - FAU_GEN.1.1.c - SRG-OS-000458-GPOS-00203 - SRG-OS-000474-GPOS-00219 - SRG-OS-000475-GPOS-00220 - SRG-OS-000463-GPOS-00207 - SRG-OS-000465-GPOS-00209 - SRG-OS-000461-GPOS-00205 - Auditing of successful attempts to create a file helps in investigation of actions which happened on the system. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then +Note: This rule uses a special set of Audit rules to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are alligned with your needs. + AU-2(a) + FAU_GEN.1.1.c + SRG-OS-000458-GPOS-00203 + SRG-OS-000474-GPOS-00219 + SRG-OS-000475-GPOS-00220 + SRG-OS-000463-GPOS-00207 + SRG-OS-000465-GPOS-00209 + SRG-OS-000461-GPOS-00205 + Auditing of successful attempts to create a file helps in investigation of actions which happened on the system. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then cat << 'EOF' > /etc/audit/rules.d/30-ospp-v42-1-create-success.rules ## Successful file creation (open with O_CREAT) @@ -117898,8 +193121,20 @@ augenrules --load else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Put contents into /etc/audit/rules.d/30-ospp-v42-1-create-success.rules according + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-53-AU-2(a) + - audit_create_success + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Put contents into /etc/audit/rules.d/30-ospp-v42-1-create-success.rules according to policy copy: dest: /etc/audit/rules.d/30-ospp-v42-1-create-success.rules @@ -117912,7 +193147,7 @@ fi -a always,exit -F arch=b32 -S creat -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-create -a always,exit -F arch=b64 -S creat -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-create force: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AU-2(a) - audit_create_success @@ -117922,11 +193157,12 @@ fi - no_reboot_needed - restrict_strategy -- name: Remove any permissions from other group - file: +- name: Configure auditing of successful file creations - Remove any permissions from + group and other + ansible.builtin.file: path: /etc/audit/rules.d/30-ospp-v42-1-create-success.rules - mode: o-rwx - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + mode: g-rwx,o-rwx + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AU-2(a) - audit_create_success @@ -117935,17 +193171,17 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Configure auditing of unsuccessful file deletions - Ensure that unsuccessful attempts to delete a file are audited. + + + + + + + + + + Configure auditing of unsuccessful file deletions + Ensure that unsuccessful attempts to delete a file are audited. The following rules configure audit as described above: ## Unsuccessful file delete @@ -117957,19 +193193,21 @@ The following rules configure audit as described above: Load new Audit rules into kernel by running: augenrules --load -Note: This rule uses a special set of Audit rules to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are alligned with your needs. - AU-2(a) - FAU_GEN.1.1.c - SRG-OS-000458-GPOS-00203 - SRG-OS-000474-GPOS-00219 - SRG-OS-000475-GPOS-00220 - SRG-OS-000463-GPOS-00207 - SRG-OS-000465-GPOS-00209 - SRG-OS-000461-GPOS-00205 - SRG-OS-000468-GPOS-00212 - Unsuccessful attempts to delete a file might be signs of malicious activities. Auditing of such events help in monitoring and investigating of such activities. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then +Note: This rule uses a special set of Audit rules to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are alligned with your needs. + AU-2(a) + FAU_GEN.1.1.c + SRG-OS-000458-GPOS-00203 + SRG-OS-000474-GPOS-00219 + SRG-OS-000475-GPOS-00220 + SRG-OS-000463-GPOS-00207 + SRG-OS-000465-GPOS-00209 + SRG-OS-000461-GPOS-00205 + SRG-OS-000468-GPOS-00212 + SRG-APP-000501-CTR-001265 + SRG-APP-000502-CTR-001270 + Unsuccessful attempts to delete a file might be signs of malicious activities. Auditing of such events help in monitoring and investigating of such activities. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then cat << 'EOF' > /etc/audit/rules.d/30-ospp-v42-4-delete-failed.rules ## Unsuccessful file delete @@ -117986,8 +193224,20 @@ augenrules --load else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Put contents into /etc/audit/rules.d/30-ospp-v42-4-delete-failed.rules according + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-53-AU-2(a) + - audit_delete_failed + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Put contents into /etc/audit/rules.d/30-ospp-v42-4-delete-failed.rules according to policy copy: dest: /etc/audit/rules.d/30-ospp-v42-4-delete-failed.rules @@ -117998,7 +193248,7 @@ fi -a always,exit -F arch=b32 -S unlink,unlinkat,rename,renameat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-delete -a always,exit -F arch=b64 -S unlink,unlinkat,rename,renameat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-delete force: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AU-2(a) - audit_delete_failed @@ -118008,11 +193258,12 @@ fi - no_reboot_needed - restrict_strategy -- name: Remove any permissions from other group - file: +- name: Configure auditing of unsuccessful file deletions - Remove any permissions + from group and other + ansible.builtin.file: path: /etc/audit/rules.d/30-ospp-v42-4-delete-failed.rules - mode: o-rwx - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + mode: g-rwx,o-rwx + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AU-2(a) - audit_delete_failed @@ -118021,17 +193272,17 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Configure auditing of successful file deletions - Ensure that successful attempts to delete a file are audited. + + + + + + + + + + Configure auditing of successful file deletions + Ensure that successful attempts to delete a file are audited. The following rules configure audit as described above: ## Successful file delete @@ -118041,19 +193292,19 @@ The following rules configure audit as described above: Load new Audit rules into kernel by running: augenrules --load -Note: This rule uses a special set of Audit rules to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are alligned with your needs. - AU-2(a) - FAU_GEN.1.1.c - SRG-OS-000458-GPOS-00203 - SRG-OS-000474-GPOS-00219 - SRG-OS-000475-GPOS-00220 - SRG-OS-000463-GPOS-00207 - SRG-OS-000465-GPOS-00209 - SRG-OS-000461-GPOS-00205 - SRG-OS-000468-GPOS-00212 - Auditing of successful attempts to delete a file may help in monitoring and investigation of activities performed on the system. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then +Note: This rule uses a special set of Audit rules to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are alligned with your needs. + AU-2(a) + FAU_GEN.1.1.c + SRG-OS-000458-GPOS-00203 + SRG-OS-000474-GPOS-00219 + SRG-OS-000475-GPOS-00220 + SRG-OS-000463-GPOS-00207 + SRG-OS-000465-GPOS-00209 + SRG-OS-000461-GPOS-00205 + SRG-OS-000468-GPOS-00212 + Auditing of successful attempts to delete a file may help in monitoring and investigation of activities performed on the system. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then cat << 'EOF' > /etc/audit/rules.d/30-ospp-v42-4-delete-success.rules ## Successful file delete @@ -118068,8 +193319,20 @@ augenrules --load else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Put contents into /etc/audit/rules.d/30-ospp-v42-4-delete-success.rules according + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-53-AU-2(a) + - audit_delete_success + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Put contents into /etc/audit/rules.d/30-ospp-v42-4-delete-success.rules according to policy copy: dest: /etc/audit/rules.d/30-ospp-v42-4-delete-success.rules @@ -118078,7 +193341,7 @@ fi -a always,exit -F arch=b32 -S unlink,unlinkat,rename,renameat -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-delete -a always,exit -F arch=b64 -S unlink,unlinkat,rename,renameat -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-delete force: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AU-2(a) - audit_delete_success @@ -118088,11 +193351,12 @@ fi - no_reboot_needed - restrict_strategy -- name: Remove any permissions from other group - file: +- name: Configure auditing of successful file deletions - Remove any permissions from + group and other + ansible.builtin.file: path: /etc/audit/rules.d/30-ospp-v42-4-delete-success.rules - mode: o-rwx - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + mode: g-rwx,o-rwx + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AU-2(a) - audit_delete_success @@ -118101,17 +193365,17 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Configure immutable Audit login UIDs - Configure kernel to prevent modification of login UIDs once they are set. + + + + + + + + + + Configure immutable Audit login UIDs + Configure kernel to prevent modification of login UIDs once they are set. Changing login UIDs while this configuration is enforced requires special capabilities which are not available to unprivileged users. @@ -118120,21 +193384,24 @@ The following rules configure audit as described above: --loginuid-immutable Load new Audit rules into kernel by running: -augenrules --load - CCI-000162 - CCI-000163 - CCI-000164 - AU-2(a) - FAU_GEN.1.2 - SRG-OS-000462-GPOS-00206 - SRG-OS-000475-GPOS-00220 - SRG-OS-000057-GPOS-00027 - SRG-OS-000058-GPOS-00028 - SRG-OS-000059-GPOS-00029 - If modification of login UIDs is not prevented, they can be changed by unprivileged users and -make auditing complicated or impossible. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then +augenrules --load + + CCI-000162 + CCI-000163 + CCI-000164 + AU-2(a) + FAU_GEN.1.2 + SRG-OS-000462-GPOS-00206 + SRG-OS-000475-GPOS-00220 + SRG-OS-000057-GPOS-00027 + SRG-OS-000058-GPOS-00028 + SRG-OS-000059-GPOS-00029 + SRG-APP-000121-CTR-000255 + SRG-APP-000495-CTR-001235 + If modification of login UIDs is not prevented, they can be changed by unprivileged users and +make auditing complicated or impossible. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then cat << 'EOF' > /etc/audit/rules.d/11-loginuid.rules ## Make the loginuid immutable. This prevents tampering with the auid. @@ -118149,8 +193416,20 @@ augenrules --load else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Put contents into /etc/audit/rules.d/11-loginuid.rules according to policy + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-53-AU-2(a) + - audit_immutable_login_uids + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Put contents into /etc/audit/rules.d/11-loginuid.rules according to policy copy: dest: /etc/audit/rules.d/11-loginuid.rules content: |+ @@ -118158,7 +193437,7 @@ fi --loginuid-immutable force: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AU-2(a) - audit_immutable_login_uids @@ -118168,11 +193447,12 @@ fi - no_reboot_needed - restrict_strategy -- name: Remove any permissions from other group - file: +- name: Configure immutable Audit login UIDs - Remove any permissions from group and + other + ansible.builtin.file: path: /etc/audit/rules.d/11-loginuid.rules - mode: o-rwx - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + mode: g-rwx,o-rwx + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AU-2(a) - audit_immutable_login_uids @@ -118181,17 +193461,17 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Configure auditing of unsuccessful file modifications - Ensure that unsuccessful attempts to modify a file are audited. + + + + + + + + + + Configure auditing of unsuccessful file modifications + Ensure that unsuccessful attempts to modify a file are audited. The following rules configure audit as described above: ## Unsuccessful file modifications (open for write or truncate) @@ -118211,18 +193491,24 @@ The following rules configure audit as described above: Load new Audit rules into kernel by running: augenrules --load -Note: This rule uses a special set of Audit rules to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are alligned with your needs. - AU-2(a) - FAU_GEN.1.1.c - SRG-OS-000458-GPOS-00203 - SRG-OS-000474-GPOS-00219 - SRG-OS-000475-GPOS-00220 - SRG-OS-000463-GPOS-00207 - SRG-OS-000465-GPOS-00209 - SRG-OS-000461-GPOS-00205 - Unsuccessful file modifications might be a sign of a malicious action being performed on the system. Auditing of such events helps in detection and investigation of such actions. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then +Note: This rule uses a special set of Audit rules to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are alligned with your needs. + AU-2(a) + FAU_GEN.1.1.c + SRG-OS-000458-GPOS-00203 + SRG-OS-000474-GPOS-00219 + SRG-OS-000475-GPOS-00220 + SRG-OS-000463-GPOS-00207 + SRG-OS-000465-GPOS-00209 + SRG-OS-000461-GPOS-00205 + SRG-APP-000091-CTR-000160 + SRG-APP-000492-CTR-001220 + SRG-APP-000493-CTR-001225 + SRG-APP-000494-CTR-001230 + SRG-APP-000500-CTR-001260 + SRG-APP-000507-CTR-001295 + Unsuccessful file modifications might be a sign of a malicious action being performed on the system. Auditing of such events helps in detection and investigation of such actions. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then cat << 'EOF' > /etc/audit/rules.d/30-ospp-v42-2-modify-failed.rules ## Unsuccessful file modifications (open for write or truncate) @@ -118247,8 +193533,20 @@ augenrules --load else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Put contents into /etc/audit/rules.d/30-ospp-v42-2-modify-failed.rules according + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-53-AU-2(a) + - audit_modify_failed + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Put contents into /etc/audit/rules.d/30-ospp-v42-2-modify-failed.rules according to policy copy: dest: /etc/audit/rules.d/30-ospp-v42-2-modify-failed.rules @@ -118267,7 +193565,7 @@ fi -a always,exit -F arch=b32 -S truncate,ftruncate -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-modification -a always,exit -F arch=b64 -S truncate,ftruncate -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-modification force: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AU-2(a) - audit_modify_failed @@ -118277,11 +193575,12 @@ fi - no_reboot_needed - restrict_strategy -- name: Remove any permissions from other group - file: +- name: Configure auditing of unsuccessful file modifications - Remove any permissions + from group and other + ansible.builtin.file: path: /etc/audit/rules.d/30-ospp-v42-2-modify-failed.rules - mode: o-rwx - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + mode: g-rwx,o-rwx + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AU-2(a) - audit_modify_failed @@ -118290,17 +193589,17 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Configure auditing of successful file modifications - Ensure that successful attempts to modify a file are audited. + + + + + + + + + + Configure auditing of successful file modifications + Ensure that successful attempts to modify a file are audited. The following rules configure audit as described above: ## Successful file modifications (open for write or truncate) @@ -118314,18 +193613,18 @@ The following rules configure audit as described above: Load new Audit rules into kernel by running: augenrules --load -Note: This rule uses a special set of Audit rules to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are alligned with your needs. - AU-2(a) - FAU_GEN.1.1.c - SRG-OS-000458-GPOS-00203 - SRG-OS-000474-GPOS-00219 - SRG-OS-000475-GPOS-00220 - SRG-OS-000463-GPOS-00207 - SRG-OS-000465-GPOS-00209 - SRG-OS-000461-GPOS-00205 - Auditing of successful attempts to modify a file helps in investigation of actions which happened on the system. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then +Note: This rule uses a special set of Audit rules to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are alligned with your needs. + AU-2(a) + FAU_GEN.1.1.c + SRG-OS-000458-GPOS-00203 + SRG-OS-000474-GPOS-00219 + SRG-OS-000475-GPOS-00220 + SRG-OS-000463-GPOS-00207 + SRG-OS-000465-GPOS-00209 + SRG-OS-000461-GPOS-00205 + Auditing of successful attempts to modify a file helps in investigation of actions which happened on the system. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then cat << 'EOF' > /etc/audit/rules.d/30-ospp-v42-2-modify-success.rules ## Successful file modifications (open for write or truncate) @@ -118344,8 +193643,20 @@ augenrules --load else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Put contents into /etc/audit/rules.d/30-ospp-v42-2-modify-success.rules according + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-53-AU-2(a) + - audit_modify_success + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Put contents into /etc/audit/rules.d/30-ospp-v42-2-modify-success.rules according to policy copy: dest: /etc/audit/rules.d/30-ospp-v42-2-modify-success.rules @@ -118358,7 +193669,7 @@ fi -a always,exit -F arch=b32 -S truncate,ftruncate -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-modification -a always,exit -F arch=b64 -S truncate,ftruncate -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-modification force: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AU-2(a) - audit_modify_success @@ -118368,11 +193679,12 @@ fi - no_reboot_needed - restrict_strategy -- name: Remove any permissions from other group - file: +- name: Configure auditing of successful file modifications - Remove any permissions + from group and other + ansible.builtin.file: path: /etc/audit/rules.d/30-ospp-v42-2-modify-success.rules - mode: o-rwx - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + mode: g-rwx,o-rwx + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AU-2(a) - audit_modify_success @@ -118381,17 +193693,17 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Configure auditing of loading and unloading of kernel modules - Ensure that loading and unloading of kernel modules is audited. + + + + + + + + + + Configure auditing of loading and unloading of kernel modules + Ensure that loading and unloading of kernel modules is audited. The following rules configure audit as described above: ## These rules watch for kernel module insertion. By monitoring @@ -118402,15 +193714,16 @@ The following rules configure audit as described above: -a always,exit -F arch=b64 -S delete_module -F key=module-unload Load new Audit rules into kernel by running: -augenrules --load - AU-2(a) - FAU_GEN.1.1.c - SRG-OS-000471-GPOS-00216 - SRG-OS-000477-GPOS-00222 - SRG-OS-000475-GPOS-00220 - Loading of a malicious kernel module introduces a risk to the system, as the module has access to sensitive data and perform actions at the operating system kernel level. Having such events audited helps in monitoring and investigating of malicious activities. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then +augenrules --load + + AU-2(a) + FAU_GEN.1.1.c + SRG-OS-000471-GPOS-00216 + SRG-OS-000477-GPOS-00222 + SRG-OS-000475-GPOS-00220 + Loading of a malicious kernel module introduces a risk to the system, as the module has access to sensitive data and perform actions at the operating system kernel level. Having such events audited helps in monitoring and investigating of malicious activities. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then cat << 'EOF' > /etc/audit/rules.d/43-module-load.rules ## These rules watch for kernel module insertion. By monitoring @@ -118428,8 +193741,20 @@ augenrules --load else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Put contents into /etc/audit/rules.d/43-module-load.rules according to policy + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-53-AU-2(a) + - audit_module_load + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Put contents into /etc/audit/rules.d/43-module-load.rules according to policy copy: dest: /etc/audit/rules.d/43-module-load.rules content: | @@ -118440,7 +193765,7 @@ fi -a always,exit -F arch=b32 -S delete_module -F key=module-unload -a always,exit -F arch=b64 -S delete_module -F key=module-unload force: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AU-2(a) - audit_module_load @@ -118450,11 +193775,12 @@ fi - no_reboot_needed - restrict_strategy -- name: Remove any permissions from other group - file: +- name: Configure auditing of loading and unloading of kernel modules - Remove any + permissions from group and other + ansible.builtin.file: path: /etc/audit/rules.d/43-module-load.rules - mode: o-rwx - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + mode: g-rwx,o-rwx + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AU-2(a) - audit_module_load @@ -118463,17 +193789,17 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Perform general configuration of Audit for OSPP - Configure some basic Audit parameters specific for OSPP profile. + + + + + + + + + + Perform general configuration of Audit for OSPP + Configure some basic Audit parameters specific for OSPP profile. In particular, configure Audit to watch for direct modification of files storing system user and group information, and usage of applications with special rights which can change system configuration. Further audited events include access to audit log it self, attempts to Alter Process and Session Initiation Information, and attempts to modify MAC controls. @@ -118491,9 +193817,6 @@ The following rules configure audit as described above: ## 30-ospp-v42-5-perm-change-success.rules, ## 30-ospp-v42-6-owner-change-failed.rules, ## 30-ospp-v42-6-owner-change-success.rules -## -## original copies may be found in /usr/share/audit/sample-rules/ - ## User add delete modify. This is covered by pam. However, someone could ## open a file and directly create or modify a user, so we'll watch passwd and @@ -118512,44 +193835,77 @@ The following rules configure audit as described above: ## Group add delete modify. This is covered by pam. However, someone could ## open a file and directly create or modify a user, so we'll watch group and ## gshadow for writes --a always,exit -F path=/etc/passwd -F perm=wa -F auid>=1000 -F auid!=unset -F key=user-modify --a always,exit -F path=/etc/shadow -F perm=wa -F auid>=1000 -F auid!=unset -F key=user-modify --a always,exit -F path=/etc/group -F perm=wa -F auid>=1000 -F auid!=unset -F key=group-modify --a always,exit -F path=/etc/gshadow -F perm=wa -F auid>=1000 -F auid!=unset -F key=group-modify +-a always,exit -F arch=b32 -F path=/etc/passwd -F perm=wa -F auid>=1000 -F auid!=unset -F key=user-modify +-a always,exit -F arch=b64 -F path=/etc/passwd -F perm=wa -F auid>=1000 -F auid!=unset -F key=user-modify +-a always,exit -F arch=b32 -F path=/etc/shadow -F perm=wa -F auid>=1000 -F auid!=unset -F key=user-modify +-a always,exit -F arch=b64 -F path=/etc/shadow -F perm=wa -F auid>=1000 -F auid!=unset -F key=user-modify +-a always,exit -F arch=b32 -F path=/etc/group -F perm=wa -F auid>=1000 -F auid!=unset -F key=group-modify +-a always,exit -F arch=b64 -F path=/etc/group -F perm=wa -F auid>=1000 -F auid!=unset -F key=group-modify +-a always,exit -F arch=b32 -F path=/etc/gshadow -F perm=wa -F auid>=1000 -F auid!=unset -F key=group-modify +-a always,exit -F arch=b64 -F path=/etc/gshadow -F perm=wa -F auid>=1000 -F auid!=unset -F key=group-modify ## Use of special rights for config changes. This would be use of setuid ## programs that relate to user accts. This is not all setuid apps because ## requirements are only for ones that affect system configuration. --a always,exit -F path=/usr/sbin/unix_chkpwd -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes --a always,exit -F path=/usr/sbin/usernetctl -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes --a always,exit -F path=/usr/sbin/userhelper -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes --a always,exit -F path=/usr/sbin/seunshare -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes --a always,exit -F path=/usr/bin/mount -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes --a always,exit -F path=/usr/bin/newgrp -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes --a always,exit -F path=/usr/bin/newuidmap -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes --a always,exit -F path=/usr/bin/gpasswd -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes --a always,exit -F path=/usr/bin/newgidmap -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes --a always,exit -F path=/usr/bin/umount -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes --a always,exit -F path=/usr/bin/passwd -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes --a always,exit -F path=/usr/bin/crontab -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes --a always,exit -F path=/usr/bin/at -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b32 -F path=/usr/sbin/unix_chkpwd -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b64 -F path=/usr/sbin/unix_chkpwd -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b32 -F path=/usr/sbin/usernetctl -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b64 -F path=/usr/sbin/usernetctl -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b32 -F path=/usr/sbin/userhelper -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b64 -F path=/usr/sbin/userhelper -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b32 -F path=/usr/sbin/seunshare -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b64 -F path=/usr/sbin/seunshare -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b32 -F path=/usr/bin/mount -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b64 -F path=/usr/bin/mount -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b32 -F path=/usr/bin/newgrp -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b64 -F path=/usr/bin/newgrp -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b32 -F path=/usr/bin/newuidmap -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b64 -F path=/usr/bin/newuidmap -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b32 -F path=/usr/bin/gpasswd -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b64 -F path=/usr/bin/gpasswd -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b32 -F path=/usr/bin/newgidmap -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b64 -F path=/usr/bin/newgidmap -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b32 -F path=/usr/bin/umount -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b64 -F path=/usr/bin/umount -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b32 -F path=/usr/bin/passwd -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b64 -F path=/usr/bin/passwd -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b32 -F path=/usr/bin/crontab -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b64 -F path=/usr/bin/crontab -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b32 -F path=/usr/bin/at -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b64 -F path=/usr/bin/at -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b32 -F path=/usr/sbin/grub2-set-bootflag -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b64 -F path=/usr/sbin/grub2-set-bootflag -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes ## Privilege escalation via su or sudo. This is entirely handled by pam. +## Special case for systemd-run. It is not audit aware, specifically watch it +-a always,exit -F arch=b32 -F path=/usr/bin/systemd-run -F perm=x -F auid!=unset -F key=maybe-escalation +-a always,exit -F arch=b64 -F path=/usr/bin/systemd-run -F perm=x -F auid!=unset -F key=maybe-escalation +## Special case for pkexec. It is not audit aware, specifically watch it +-a always,exit -F arch=b32 -F path=/usr/bin/pkexec -F perm=x -F key=maybe-escalation +-a always,exit -F arch=b64 -F path=/usr/bin/pkexec -F perm=x -F key=maybe-escalation + ## Watch for configuration changes to privilege escalation. --a always,exit -F path=/etc/sudoers -F perm=wa -F key=special-config-changes --a always,exit -F dir=/etc/sudoers.d/ -F perm=wa -F key=special-config-changes +-a always,exit -F arch=b32 -F path=/etc/sudoers -F perm=wa -F key=special-config-changes +-a always,exit -F arch=b64 -F path=/etc/sudoers -F perm=wa -F key=special-config-changes +-a always,exit -F arch=b32 -F dir=/etc/sudoers.d/ -F perm=wa -F key=special-config-changes +-a always,exit -F arch=b64 -F dir=/etc/sudoers.d/ -F perm=wa -F key=special-config-changes ## Audit log access --a always,exit -F dir=/var/log/audit/ -F perm=r -F auid>=1000 -F auid!=unset -F key=access-audit-trail +-a always,exit -F arch=b32 -F dir=/var/log/audit/ -F perm=r -F auid>=1000 -F auid!=unset -F key=access-audit-trail +-a always,exit -F arch=b64 -F dir=/var/log/audit/ -F perm=r -F auid>=1000 -F auid!=unset -F key=access-audit-trail ## Attempts to Alter Process and Session Initiation Information --a always,exit -F path=/var/run/utmp -F perm=wa -F auid>=1000 -F auid!=unset -F key=session --a always,exit -F path=/var/log/btmp -F perm=wa -F auid>=1000 -F auid!=unset -F key=session --a always,exit -F path=/var/log/wtmp -F perm=wa -F auid>=1000 -F auid!=unset -F key=session +-a always,exit -F arch=b32 -F path=/var/run/utmp -F perm=wa -F auid>=1000 -F auid!=unset -F key=session +-a always,exit -F arch=b64 -F path=/var/run/utmp -F perm=wa -F auid>=1000 -F auid!=unset -F key=session +-a always,exit -F arch=b32 -F path=/var/log/btmp -F perm=wa -F auid>=1000 -F auid!=unset -F key=session +-a always,exit -F arch=b64 -F path=/var/log/btmp -F perm=wa -F auid>=1000 -F auid!=unset -F key=session +-a always,exit -F arch=b32 -F path=/var/log/wtmp -F perm=wa -F auid>=1000 -F auid!=unset -F key=session +-a always,exit -F arch=b64 -F path=/var/log/wtmp -F perm=wa -F auid>=1000 -F auid!=unset -F key=session ## Attempts to modify MAC controls --a always,exit -F dir=/etc/selinux/ -F perm=wa -F auid>=1000 -F auid!=unset -F key=MAC-policy +-a always,exit -F arch=b32 -F dir=/etc/selinux/ -F perm=wa -F auid>=1000 -F auid!=unset -F key=MAC-policy +-a always,exit -F arch=b64 -F dir=/etc/selinux/ -F perm=wa -F auid>=1000 -F auid!=unset -F key=MAC-policy ## Software updates. This is entirely handled by rpm. @@ -118565,22 +193921,22 @@ The following rules configure audit as described above: Load new Audit rules into kernel by running: augenrules --load -Note: This rule uses a special set of Audit rules to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are alligned with your needs. - AU-2(a) - FAU_GEN.1.1.c - SRG-OS-000004-GPOS-00004 - SRG-OS-000241-GPOS-00091 - SRG-OS-000476-GPOS-00221 - SRG-OS-000327-GPOS-00127 - SRG-OS-000475-GPOS-00220 - SRG-OS-000239-GPOS-00089 - SRG-OS-000274-GPOS-00104 - SRG-OS-000275-GPOS-00105 - SRG-OS-000303-GPOS-00120 - SRG-OS-000304-GPOS-00121 - Auditing of events listed in the description provides data for monitoring and investigation of potentially malicious events e.g. tampering with Audit logs, malicious access to files storing information about system users and groups etc. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then +Note: This rule uses a special set of Audit rules to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are alligned with your needs. + AU-2(a) + FAU_GEN.1.1.c + SRG-OS-000004-GPOS-00004 + SRG-OS-000241-GPOS-00091 + SRG-OS-000476-GPOS-00221 + SRG-OS-000327-GPOS-00127 + SRG-OS-000475-GPOS-00220 + SRG-OS-000239-GPOS-00089 + SRG-OS-000274-GPOS-00104 + SRG-OS-000275-GPOS-00105 + SRG-OS-000303-GPOS-00120 + SRG-OS-000304-GPOS-00121 + Auditing of events listed in the description provides data for monitoring and investigation of potentially malicious events e.g. tampering with Audit logs, malicious access to files storing information about system users and groups etc. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then cat << 'EOF' > /etc/audit/rules.d/30-ospp-v42.rules ## The purpose of these rules is to meet the requirements for Operating @@ -118596,9 +193952,6 @@ cat << 'EOF' > /etc/audit/rules.d/30-ospp-v42.rules ## 30-ospp-v42-5-perm-change-success.rules, ## 30-ospp-v42-6-owner-change-failed.rules, ## 30-ospp-v42-6-owner-change-success.rules -## -## original copies may be found in /usr/share/audit/sample-rules/ - ## User add delete modify. This is covered by pam. However, someone could ## open a file and directly create or modify a user, so we'll watch passwd and @@ -118617,44 +193970,77 @@ cat << 'EOF' > /etc/audit/rules.d/30-ospp-v42.rules ## Group add delete modify. This is covered by pam. However, someone could ## open a file and directly create or modify a user, so we'll watch group and ## gshadow for writes --a always,exit -F path=/etc/passwd -F perm=wa -F auid>=1000 -F auid!=unset -F key=user-modify --a always,exit -F path=/etc/shadow -F perm=wa -F auid>=1000 -F auid!=unset -F key=user-modify --a always,exit -F path=/etc/group -F perm=wa -F auid>=1000 -F auid!=unset -F key=group-modify --a always,exit -F path=/etc/gshadow -F perm=wa -F auid>=1000 -F auid!=unset -F key=group-modify +-a always,exit -F arch=b32 -F path=/etc/passwd -F perm=wa -F auid>=1000 -F auid!=unset -F key=user-modify +-a always,exit -F arch=b64 -F path=/etc/passwd -F perm=wa -F auid>=1000 -F auid!=unset -F key=user-modify +-a always,exit -F arch=b32 -F path=/etc/shadow -F perm=wa -F auid>=1000 -F auid!=unset -F key=user-modify +-a always,exit -F arch=b64 -F path=/etc/shadow -F perm=wa -F auid>=1000 -F auid!=unset -F key=user-modify +-a always,exit -F arch=b32 -F path=/etc/group -F perm=wa -F auid>=1000 -F auid!=unset -F key=group-modify +-a always,exit -F arch=b64 -F path=/etc/group -F perm=wa -F auid>=1000 -F auid!=unset -F key=group-modify +-a always,exit -F arch=b32 -F path=/etc/gshadow -F perm=wa -F auid>=1000 -F auid!=unset -F key=group-modify +-a always,exit -F arch=b64 -F path=/etc/gshadow -F perm=wa -F auid>=1000 -F auid!=unset -F key=group-modify ## Use of special rights for config changes. This would be use of setuid ## programs that relate to user accts. This is not all setuid apps because ## requirements are only for ones that affect system configuration. --a always,exit -F path=/usr/sbin/unix_chkpwd -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes --a always,exit -F path=/usr/sbin/usernetctl -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes --a always,exit -F path=/usr/sbin/userhelper -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes --a always,exit -F path=/usr/sbin/seunshare -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes --a always,exit -F path=/usr/bin/mount -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes --a always,exit -F path=/usr/bin/newgrp -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes --a always,exit -F path=/usr/bin/newuidmap -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes --a always,exit -F path=/usr/bin/gpasswd -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes --a always,exit -F path=/usr/bin/newgidmap -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes --a always,exit -F path=/usr/bin/umount -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes --a always,exit -F path=/usr/bin/passwd -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes --a always,exit -F path=/usr/bin/crontab -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes --a always,exit -F path=/usr/bin/at -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b32 -F path=/usr/sbin/unix_chkpwd -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b64 -F path=/usr/sbin/unix_chkpwd -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b32 -F path=/usr/sbin/usernetctl -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b64 -F path=/usr/sbin/usernetctl -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b32 -F path=/usr/sbin/userhelper -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b64 -F path=/usr/sbin/userhelper -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b32 -F path=/usr/sbin/seunshare -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b64 -F path=/usr/sbin/seunshare -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b32 -F path=/usr/bin/mount -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b64 -F path=/usr/bin/mount -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b32 -F path=/usr/bin/newgrp -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b64 -F path=/usr/bin/newgrp -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b32 -F path=/usr/bin/newuidmap -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b64 -F path=/usr/bin/newuidmap -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b32 -F path=/usr/bin/gpasswd -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b64 -F path=/usr/bin/gpasswd -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b32 -F path=/usr/bin/newgidmap -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b64 -F path=/usr/bin/newgidmap -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b32 -F path=/usr/bin/umount -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b64 -F path=/usr/bin/umount -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b32 -F path=/usr/bin/passwd -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b64 -F path=/usr/bin/passwd -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b32 -F path=/usr/bin/crontab -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b64 -F path=/usr/bin/crontab -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b32 -F path=/usr/bin/at -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b64 -F path=/usr/bin/at -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b32 -F path=/usr/sbin/grub2-set-bootflag -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b64 -F path=/usr/sbin/grub2-set-bootflag -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes ## Privilege escalation via su or sudo. This is entirely handled by pam. +## Special case for systemd-run. It is not audit aware, specifically watch it +-a always,exit -F arch=b32 -F path=/usr/bin/systemd-run -F perm=x -F auid!=unset -F key=maybe-escalation +-a always,exit -F arch=b64 -F path=/usr/bin/systemd-run -F perm=x -F auid!=unset -F key=maybe-escalation +## Special case for pkexec. It is not audit aware, specifically watch it +-a always,exit -F arch=b32 -F path=/usr/bin/pkexec -F perm=x -F key=maybe-escalation +-a always,exit -F arch=b64 -F path=/usr/bin/pkexec -F perm=x -F key=maybe-escalation + ## Watch for configuration changes to privilege escalation. --a always,exit -F path=/etc/sudoers -F perm=wa -F key=special-config-changes --a always,exit -F dir=/etc/sudoers.d/ -F perm=wa -F key=special-config-changes +-a always,exit -F arch=b32 -F path=/etc/sudoers -F perm=wa -F key=special-config-changes +-a always,exit -F arch=b64 -F path=/etc/sudoers -F perm=wa -F key=special-config-changes +-a always,exit -F arch=b32 -F dir=/etc/sudoers.d/ -F perm=wa -F key=special-config-changes +-a always,exit -F arch=b64 -F dir=/etc/sudoers.d/ -F perm=wa -F key=special-config-changes ## Audit log access --a always,exit -F dir=/var/log/audit/ -F perm=r -F auid>=1000 -F auid!=unset -F key=access-audit-trail +-a always,exit -F arch=b32 -F dir=/var/log/audit/ -F perm=r -F auid>=1000 -F auid!=unset -F key=access-audit-trail +-a always,exit -F arch=b64 -F dir=/var/log/audit/ -F perm=r -F auid>=1000 -F auid!=unset -F key=access-audit-trail ## Attempts to Alter Process and Session Initiation Information --a always,exit -F path=/var/run/utmp -F perm=wa -F auid>=1000 -F auid!=unset -F key=session --a always,exit -F path=/var/log/btmp -F perm=wa -F auid>=1000 -F auid!=unset -F key=session --a always,exit -F path=/var/log/wtmp -F perm=wa -F auid>=1000 -F auid!=unset -F key=session +-a always,exit -F arch=b32 -F path=/var/run/utmp -F perm=wa -F auid>=1000 -F auid!=unset -F key=session +-a always,exit -F arch=b64 -F path=/var/run/utmp -F perm=wa -F auid>=1000 -F auid!=unset -F key=session +-a always,exit -F arch=b32 -F path=/var/log/btmp -F perm=wa -F auid>=1000 -F auid!=unset -F key=session +-a always,exit -F arch=b64 -F path=/var/log/btmp -F perm=wa -F auid>=1000 -F auid!=unset -F key=session +-a always,exit -F arch=b32 -F path=/var/log/wtmp -F perm=wa -F auid>=1000 -F auid!=unset -F key=session +-a always,exit -F arch=b64 -F path=/var/log/wtmp -F perm=wa -F auid>=1000 -F auid!=unset -F key=session ## Attempts to modify MAC controls --a always,exit -F dir=/etc/selinux/ -F perm=wa -F auid>=1000 -F auid!=unset -F key=MAC-policy +-a always,exit -F arch=b32 -F dir=/etc/selinux/ -F perm=wa -F auid>=1000 -F auid!=unset -F key=MAC-policy +-a always,exit -F arch=b64 -F dir=/etc/selinux/ -F perm=wa -F auid>=1000 -F auid!=unset -F key=MAC-policy ## Software updates. This is entirely handled by rpm. @@ -118676,8 +194062,20 @@ augenrules --load else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Put contents into /etc/audit/rules.d/30-ospp-v42.rules according to policy + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-53-AU-2(a) + - audit_ospp_general + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Put contents into /etc/audit/rules.d/30-ospp-v42.rules according to policy copy: dest: /etc/audit/rules.d/30-ospp-v42.rules content: |+ @@ -118694,9 +194092,6 @@ fi ## 30-ospp-v42-5-perm-change-success.rules, ## 30-ospp-v42-6-owner-change-failed.rules, ## 30-ospp-v42-6-owner-change-success.rules - ## - ## original copies may be found in /usr/share/audit/sample-rules/ - ## User add delete modify. This is covered by pam. However, someone could ## open a file and directly create or modify a user, so we'll watch passwd and @@ -118715,44 +194110,77 @@ fi ## Group add delete modify. This is covered by pam. However, someone could ## open a file and directly create or modify a user, so we'll watch group and ## gshadow for writes - -a always,exit -F path=/etc/passwd -F perm=wa -F auid>=1000 -F auid!=unset -F key=user-modify - -a always,exit -F path=/etc/shadow -F perm=wa -F auid>=1000 -F auid!=unset -F key=user-modify - -a always,exit -F path=/etc/group -F perm=wa -F auid>=1000 -F auid!=unset -F key=group-modify - -a always,exit -F path=/etc/gshadow -F perm=wa -F auid>=1000 -F auid!=unset -F key=group-modify + -a always,exit -F arch=b32 -F path=/etc/passwd -F perm=wa -F auid>=1000 -F auid!=unset -F key=user-modify + -a always,exit -F arch=b64 -F path=/etc/passwd -F perm=wa -F auid>=1000 -F auid!=unset -F key=user-modify + -a always,exit -F arch=b32 -F path=/etc/shadow -F perm=wa -F auid>=1000 -F auid!=unset -F key=user-modify + -a always,exit -F arch=b64 -F path=/etc/shadow -F perm=wa -F auid>=1000 -F auid!=unset -F key=user-modify + -a always,exit -F arch=b32 -F path=/etc/group -F perm=wa -F auid>=1000 -F auid!=unset -F key=group-modify + -a always,exit -F arch=b64 -F path=/etc/group -F perm=wa -F auid>=1000 -F auid!=unset -F key=group-modify + -a always,exit -F arch=b32 -F path=/etc/gshadow -F perm=wa -F auid>=1000 -F auid!=unset -F key=group-modify + -a always,exit -F arch=b64 -F path=/etc/gshadow -F perm=wa -F auid>=1000 -F auid!=unset -F key=group-modify ## Use of special rights for config changes. This would be use of setuid ## programs that relate to user accts. This is not all setuid apps because ## requirements are only for ones that affect system configuration. - -a always,exit -F path=/usr/sbin/unix_chkpwd -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes - -a always,exit -F path=/usr/sbin/usernetctl -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes - -a always,exit -F path=/usr/sbin/userhelper -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes - -a always,exit -F path=/usr/sbin/seunshare -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes - -a always,exit -F path=/usr/bin/mount -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes - -a always,exit -F path=/usr/bin/newgrp -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes - -a always,exit -F path=/usr/bin/newuidmap -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes - -a always,exit -F path=/usr/bin/gpasswd -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes - -a always,exit -F path=/usr/bin/newgidmap -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes - -a always,exit -F path=/usr/bin/umount -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes - -a always,exit -F path=/usr/bin/passwd -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes - -a always,exit -F path=/usr/bin/crontab -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes - -a always,exit -F path=/usr/bin/at -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes + -a always,exit -F arch=b32 -F path=/usr/sbin/unix_chkpwd -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes + -a always,exit -F arch=b64 -F path=/usr/sbin/unix_chkpwd -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes + -a always,exit -F arch=b32 -F path=/usr/sbin/usernetctl -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes + -a always,exit -F arch=b64 -F path=/usr/sbin/usernetctl -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes + -a always,exit -F arch=b32 -F path=/usr/sbin/userhelper -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes + -a always,exit -F arch=b64 -F path=/usr/sbin/userhelper -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes + -a always,exit -F arch=b32 -F path=/usr/sbin/seunshare -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes + -a always,exit -F arch=b64 -F path=/usr/sbin/seunshare -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes + -a always,exit -F arch=b32 -F path=/usr/bin/mount -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes + -a always,exit -F arch=b64 -F path=/usr/bin/mount -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes + -a always,exit -F arch=b32 -F path=/usr/bin/newgrp -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes + -a always,exit -F arch=b64 -F path=/usr/bin/newgrp -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes + -a always,exit -F arch=b32 -F path=/usr/bin/newuidmap -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes + -a always,exit -F arch=b64 -F path=/usr/bin/newuidmap -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes + -a always,exit -F arch=b32 -F path=/usr/bin/gpasswd -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes + -a always,exit -F arch=b64 -F path=/usr/bin/gpasswd -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes + -a always,exit -F arch=b32 -F path=/usr/bin/newgidmap -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes + -a always,exit -F arch=b64 -F path=/usr/bin/newgidmap -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes + -a always,exit -F arch=b32 -F path=/usr/bin/umount -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes + -a always,exit -F arch=b64 -F path=/usr/bin/umount -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes + -a always,exit -F arch=b32 -F path=/usr/bin/passwd -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes + -a always,exit -F arch=b64 -F path=/usr/bin/passwd -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes + -a always,exit -F arch=b32 -F path=/usr/bin/crontab -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes + -a always,exit -F arch=b64 -F path=/usr/bin/crontab -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes + -a always,exit -F arch=b32 -F path=/usr/bin/at -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes + -a always,exit -F arch=b64 -F path=/usr/bin/at -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes + -a always,exit -F arch=b32 -F path=/usr/sbin/grub2-set-bootflag -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes + -a always,exit -F arch=b64 -F path=/usr/sbin/grub2-set-bootflag -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes ## Privilege escalation via su or sudo. This is entirely handled by pam. + ## Special case for systemd-run. It is not audit aware, specifically watch it + -a always,exit -F arch=b32 -F path=/usr/bin/systemd-run -F perm=x -F auid!=unset -F key=maybe-escalation + -a always,exit -F arch=b64 -F path=/usr/bin/systemd-run -F perm=x -F auid!=unset -F key=maybe-escalation + ## Special case for pkexec. It is not audit aware, specifically watch it + -a always,exit -F arch=b32 -F path=/usr/bin/pkexec -F perm=x -F key=maybe-escalation + -a always,exit -F arch=b64 -F path=/usr/bin/pkexec -F perm=x -F key=maybe-escalation + ## Watch for configuration changes to privilege escalation. - -a always,exit -F path=/etc/sudoers -F perm=wa -F key=special-config-changes - -a always,exit -F dir=/etc/sudoers.d/ -F perm=wa -F key=special-config-changes + -a always,exit -F arch=b32 -F path=/etc/sudoers -F perm=wa -F key=special-config-changes + -a always,exit -F arch=b64 -F path=/etc/sudoers -F perm=wa -F key=special-config-changes + -a always,exit -F arch=b32 -F dir=/etc/sudoers.d/ -F perm=wa -F key=special-config-changes + -a always,exit -F arch=b64 -F dir=/etc/sudoers.d/ -F perm=wa -F key=special-config-changes ## Audit log access - -a always,exit -F dir=/var/log/audit/ -F perm=r -F auid>=1000 -F auid!=unset -F key=access-audit-trail + -a always,exit -F arch=b32 -F dir=/var/log/audit/ -F perm=r -F auid>=1000 -F auid!=unset -F key=access-audit-trail + -a always,exit -F arch=b64 -F dir=/var/log/audit/ -F perm=r -F auid>=1000 -F auid!=unset -F key=access-audit-trail ## Attempts to Alter Process and Session Initiation Information - -a always,exit -F path=/var/run/utmp -F perm=wa -F auid>=1000 -F auid!=unset -F key=session - -a always,exit -F path=/var/log/btmp -F perm=wa -F auid>=1000 -F auid!=unset -F key=session - -a always,exit -F path=/var/log/wtmp -F perm=wa -F auid>=1000 -F auid!=unset -F key=session + -a always,exit -F arch=b32 -F path=/var/run/utmp -F perm=wa -F auid>=1000 -F auid!=unset -F key=session + -a always,exit -F arch=b64 -F path=/var/run/utmp -F perm=wa -F auid>=1000 -F auid!=unset -F key=session + -a always,exit -F arch=b32 -F path=/var/log/btmp -F perm=wa -F auid>=1000 -F auid!=unset -F key=session + -a always,exit -F arch=b64 -F path=/var/log/btmp -F perm=wa -F auid>=1000 -F auid!=unset -F key=session + -a always,exit -F arch=b32 -F path=/var/log/wtmp -F perm=wa -F auid>=1000 -F auid!=unset -F key=session + -a always,exit -F arch=b64 -F path=/var/log/wtmp -F perm=wa -F auid>=1000 -F auid!=unset -F key=session ## Attempts to modify MAC controls - -a always,exit -F dir=/etc/selinux/ -F perm=wa -F auid>=1000 -F auid!=unset -F key=MAC-policy + -a always,exit -F arch=b32 -F dir=/etc/selinux/ -F perm=wa -F auid>=1000 -F auid!=unset -F key=MAC-policy + -a always,exit -F arch=b64 -F dir=/etc/selinux/ -F perm=wa -F auid>=1000 -F auid!=unset -F key=MAC-policy ## Software updates. This is entirely handled by rpm. @@ -118766,7 +194194,7 @@ fi ## that daemon. force: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AU-2(a) - audit_ospp_general @@ -118776,11 +194204,12 @@ fi - no_reboot_needed - restrict_strategy -- name: Remove any permissions from other group - file: +- name: Perform general configuration of Audit for OSPP - Remove any permissions from + group and other + ansible.builtin.file: path: /etc/audit/rules.d/30-ospp-v42.rules - mode: o-rwx - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + mode: g-rwx,o-rwx + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AU-2(a) - audit_ospp_general @@ -118789,17 +194218,17 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Configure auditing of unsuccessful ownership changes - Ensure that unsuccessful attempts to change an ownership of files or directories are audited. + + + + + + + + + + Configure auditing of unsuccessful ownership changes + Ensure that unsuccessful attempts to change an ownership of files or directories are audited. The following rules configure audit as described above: ## Unsuccessful ownership change @@ -118811,19 +194240,19 @@ The following rules configure audit as described above: Load new Audit rules into kernel by running: augenrules --load -Note: This rule uses a special set of Audit rules to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are alligned with your needs. - AU-2(a) - FAU_GEN.1.1.c - SRG-OS-000462-GPOS-00206 - SRG-OS-000463-GPOS-00207 - SRG-OS-000465-GPOS-00209 - SRG-OS-000474-GPOS-00219 - SRG-OS-000475-GPOS-00220 - SRG-OS-000466-GPOS-00210 - SRG-OS-000064-GPOS-00033 - Unsuccessful attempts to change an ownership of files or directories might be signs of a malicious activity. Having such events audited helps in monitoring and investigation of such activities. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then +Note: This rule uses a special set of Audit rules to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are alligned with your needs. + AU-2(a) + FAU_GEN.1.1.c + SRG-OS-000462-GPOS-00206 + SRG-OS-000463-GPOS-00207 + SRG-OS-000465-GPOS-00209 + SRG-OS-000474-GPOS-00219 + SRG-OS-000475-GPOS-00220 + SRG-OS-000466-GPOS-00210 + SRG-OS-000064-GPOS-00033 + Unsuccessful attempts to change an ownership of files or directories might be signs of a malicious activity. Having such events audited helps in monitoring and investigation of such activities. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then cat << 'EOF' > /etc/audit/rules.d/30-ospp-v42-6-owner-change-failed.rules ## Unsuccessful ownership change @@ -118840,8 +194269,20 @@ augenrules --load else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Put contents into /etc/audit/rules.d/30-ospp-v42-6-owner-change-failed.rules + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-53-AU-2(a) + - audit_owner_change_failed + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Put contents into /etc/audit/rules.d/30-ospp-v42-6-owner-change-failed.rules according to policy copy: dest: /etc/audit/rules.d/30-ospp-v42-6-owner-change-failed.rules @@ -118852,7 +194293,7 @@ fi -a always,exit -F arch=b32 -S lchown,fchown,chown,fchownat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-owner-change -a always,exit -F arch=b64 -S lchown,fchown,chown,fchownat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-owner-change force: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AU-2(a) - audit_owner_change_failed @@ -118862,11 +194303,12 @@ fi - no_reboot_needed - restrict_strategy -- name: Remove any permissions from other group - file: +- name: Configure auditing of unsuccessful ownership changes - Remove any permissions + from group and other + ansible.builtin.file: path: /etc/audit/rules.d/30-ospp-v42-6-owner-change-failed.rules - mode: o-rwx - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + mode: g-rwx,o-rwx + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AU-2(a) - audit_owner_change_failed @@ -118875,17 +194317,17 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Configure auditing of successful ownership changes - Ensure that successful attempts to change an ownership of files or directories are audited. + + + + + + + + + + Configure auditing of successful ownership changes + Ensure that successful attempts to change an ownership of files or directories are audited. The following rules configure audit as described above: ## Successful ownership change @@ -118895,19 +194337,19 @@ The following rules configure audit as described above: Load new Audit rules into kernel by running: augenrules --load -Note: This rule uses a special set of Audit rules to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are alligned with your needs. - AU-2(a) - FAU_GEN.1.1.c - SRG-OS-000462-GPOS-00206 - SRG-OS-000463-GPOS-00207 - SRG-OS-000465-GPOS-00209 - SRG-OS-000474-GPOS-00219 - SRG-OS-000475-GPOS-00220 - SRG-OS-000466-GPOS-00210 - SRG-OS-000064-GPOS-00033 - Auditing of successful ownership changes of files or directories helps in monitoring or investingating of activities performed on the system. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then +Note: This rule uses a special set of Audit rules to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are alligned with your needs. + AU-2(a) + FAU_GEN.1.1.c + SRG-OS-000462-GPOS-00206 + SRG-OS-000463-GPOS-00207 + SRG-OS-000465-GPOS-00209 + SRG-OS-000474-GPOS-00219 + SRG-OS-000475-GPOS-00220 + SRG-OS-000466-GPOS-00210 + SRG-OS-000064-GPOS-00033 + Auditing of successful ownership changes of files or directories helps in monitoring or investingating of activities performed on the system. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then cat << 'EOF' > /etc/audit/rules.d/30-ospp-v42-6-owner-change-success.rules ## Successful ownership change @@ -118922,17 +194364,10 @@ augenrules --load else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Put contents into /etc/audit/rules.d/30-ospp-v42-6-owner-change-success.rules - according to policy - copy: - dest: /etc/audit/rules.d/30-ospp-v42-6-owner-change-success.rules - content: | - ## Successful ownership change - -a always,exit -F arch=b32 -S lchown,fchown,chown,fchownat -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-owner-change - -a always,exit -F arch=b64 -S lchown,fchown,chown,fchownat -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-owner-change - force: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + + - name: Gather the package facts + package_facts: + manager: auto tags: - NIST-800-53-AU-2(a) - audit_owner_change_success @@ -118942,11 +194377,16 @@ fi - no_reboot_needed - restrict_strategy -- name: Remove any permissions from other group - file: - path: /etc/audit/rules.d/30-ospp-v42-6-owner-change-success.rules - mode: o-rwx - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] +- name: Put contents into /etc/audit/rules.d/30-ospp-v42-6-owner-change-success.rules + according to policy + copy: + dest: /etc/audit/rules.d/30-ospp-v42-6-owner-change-success.rules + content: | + ## Successful ownership change + -a always,exit -F arch=b32 -S lchown,fchown,chown,fchownat -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-owner-change + -a always,exit -F arch=b64 -S lchown,fchown,chown,fchownat -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-owner-change + force: true + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AU-2(a) - audit_owner_change_success @@ -118955,17 +194395,32 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Configure auditing of unsuccessful permission changes - Ensure that unsuccessful attempts to change file or directory permissions are audited. + +- name: Configure auditing of successful ownership changes - Remove any permissions + from group and other + ansible.builtin.file: + path: /etc/audit/rules.d/30-ospp-v42-6-owner-change-success.rules + mode: g-rwx,o-rwx + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-AU-2(a) + - audit_owner_change_success + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + + + + + + + + + + Configure auditing of unsuccessful permission changes + Ensure that unsuccessful attempts to change file or directory permissions are audited. The following rules configure audit as described above: ## Unsuccessful permission change @@ -118977,19 +194432,19 @@ The following rules configure audit as described above: Load new Audit rules into kernel by running: augenrules --load -Note: This rule uses a special set of Audit rules to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are alligned with your needs. - AU-2(a) - FAU_GEN.1.1.c - SRG-OS-000462-GPOS-00206 - SRG-OS-000463-GPOS-00207 - SRG-OS-000465-GPOS-00209 - SRG-OS-000474-GPOS-00219 - SRG-OS-000475-GPOS-00220 - SRG-OS-000466-GPOS-00210 - SRG-OS-000064-GPOS-00033 - Unsuccessful attempts to change permissions of files or directories might be signs of malicious activity. Having such events audited helps in monitoring and investigation of such activities. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then +Note: This rule uses a special set of Audit rules to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are alligned with your needs. + AU-2(a) + FAU_GEN.1.1.c + SRG-OS-000462-GPOS-00206 + SRG-OS-000463-GPOS-00207 + SRG-OS-000465-GPOS-00209 + SRG-OS-000474-GPOS-00219 + SRG-OS-000475-GPOS-00220 + SRG-OS-000466-GPOS-00210 + SRG-OS-000064-GPOS-00033 + Unsuccessful attempts to change permissions of files or directories might be signs of malicious activity. Having such events audited helps in monitoring and investigation of such activities. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then cat << 'EOF' > /etc/audit/rules.d/30-ospp-v42-5-perm-change-failed.rules ## Unsuccessful permission change @@ -119006,8 +194461,20 @@ augenrules --load else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Put contents into /etc/audit/rules.d/30-ospp-v42-5-perm-change-failed.rules + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-53-AU-2(a) + - audit_perm_change_failed + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Put contents into /etc/audit/rules.d/30-ospp-v42-5-perm-change-failed.rules according to policy copy: dest: /etc/audit/rules.d/30-ospp-v42-5-perm-change-failed.rules @@ -119018,7 +194485,7 @@ fi -a always,exit -F arch=b32 -S chmod,fchmod,fchmodat,setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-perm-change -a always,exit -F arch=b64 -S chmod,fchmod,fchmodat,setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-perm-change force: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AU-2(a) - audit_perm_change_failed @@ -119028,11 +194495,12 @@ fi - no_reboot_needed - restrict_strategy -- name: Remove any permissions from other group - file: +- name: Configure auditing of unsuccessful permission changes - Remove any permissions + from group and other + ansible.builtin.file: path: /etc/audit/rules.d/30-ospp-v42-5-perm-change-failed.rules - mode: o-rwx - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + mode: g-rwx,o-rwx + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AU-2(a) - audit_perm_change_failed @@ -119041,17 +194509,17 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - Configure auditing of successful permission changes - Ensure that successful attempts to modify permissions of files or directories are audited. + + + + + + + + + + Configure auditing of successful permission changes + Ensure that successful attempts to modify permissions of files or directories are audited. The following rules configure audit as described above: ## Successful permission change @@ -119061,19 +194529,19 @@ The following rules configure audit as described above: Load new Audit rules into kernel by running: augenrules --load -Note: This rule uses a special set of Audit rules to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are alligned with your needs. - AU-2(a) - FAU_GEN.1.1.c - SRG-OS-000462-GPOS-00206 - SRG-OS-000463-GPOS-00207 - SRG-OS-000465-GPOS-00209 - SRG-OS-000474-GPOS-00219 - SRG-OS-000475-GPOS-00220 - SRG-OS-000466-GPOS-00210 - SRG-OS-000064-GPOS-00033 - Auditing successful file or directory permission changes helps in monitoring and investigating of activities performed on the system. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then +Note: This rule uses a special set of Audit rules to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are alligned with your needs. + AU-2(a) + FAU_GEN.1.1.c + SRG-OS-000462-GPOS-00206 + SRG-OS-000463-GPOS-00207 + SRG-OS-000465-GPOS-00209 + SRG-OS-000474-GPOS-00219 + SRG-OS-000475-GPOS-00220 + SRG-OS-000466-GPOS-00210 + SRG-OS-000064-GPOS-00033 + Auditing successful file or directory permission changes helps in monitoring and investigating of activities performed on the system. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then cat << 'EOF' > /etc/audit/rules.d/30-ospp-v42-5-perm-change-success.rules ## Successful permission change @@ -119088,8 +194556,20 @@ augenrules --load else >&2 echo 'Remediation is not applicable, nothing was done' fi - - - name: Put contents into /etc/audit/rules.d/30-ospp-v42-5-perm-change-success.rules + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-53-AU-2(a) + - audit_perm_change_success + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Put contents into /etc/audit/rules.d/30-ospp-v42-5-perm-change-success.rules according to policy copy: dest: /etc/audit/rules.d/30-ospp-v42-5-perm-change-success.rules @@ -119098,7 +194578,7 @@ fi -a always,exit -F arch=b32 -S chmod,fchmod,fchmodat,setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-perm-change -a always,exit -F arch=b64 -S chmod,fchmod,fchmodat,setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-perm-change force: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AU-2(a) - audit_perm_change_success @@ -119108,11 +194588,12 @@ fi - no_reboot_needed - restrict_strategy -- name: Remove any permissions from other group - file: +- name: Configure auditing of successful permission changes - Remove any permissions + from group and other + ansible.builtin.file: path: /etc/audit/rules.d/30-ospp-v42-5-perm-change-success.rules - mode: o-rwx - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + mode: g-rwx,o-rwx + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AU-2(a) - audit_perm_change_success @@ -119121,98528 +194602,39604 @@ fi - medium_severity - no_reboot_needed - restrict_strategy - - - - - - - - - - - - AppArmor - Many security vulnerabilities result from bugs in trusted programs. A trusted -program runs with privileges that attackers want to possess. The program fails -to keep that trust if there is a bug in the program that allows the attacker to -acquire said privilege. - -AppArmor® is an application security solution designed specifically to apply -privilege confinement to suspect programs. AppArmor allows the administrator to -specify the domain of activities the program can perform by developing a -security profile. A security profile is a listing of files that the program may -access and the operations the program may perform. AppArmor secures -applications by enforcing good application behavior without relying on attack -signatures, so it can prevent attacks even if previously unknown -vulnerabilities are being exploited. - - - AppArmor profiles mode - enforce - Set all AppArmor profiles to enforce mode -complain - Set all AppArmor profiles to complain mode - enforce - complain - enforce - - - - GRUB2 bootloader configuration - During the boot process, the boot loader is -responsible for starting the execution of the kernel and passing -options to it. The boot loader allows for the selection of -different kernels - possibly on different partitions or media. -The default Oracle Linux 9 boot loader for x86 systems is called GRUB2. -Options it can pass to the kernel include single-user mode, which -provides root access without any authentication, and the ability to -disable SELinux. To prevent local users from modifying the boot -parameters and endangering security, protect the boot loader configuration -with a password and ensure its configuration file's permissions -are set properly. - - - L1TF vulnerability mitigation - Defines the L1TF vulneratility mitigations to employ. - flush - full - full,force - flush - flush,nosmt - flush,nowarn - - - MDS vulnerability mitigation - Defines the MDS vulneratility mitigation to employ. - full - full - full,nosmt - - - Confidence level on Hardware Random Number Generator - Defines the level of trust on the hardware random number generators available in the -system and the percentage of entropy to credit. - 500 - 500 - 512 - 1000 - - - Spec Store Bypass Mitigation - This controls how the Speculative Store Bypass (SSB) vulnerability is mitigated. - prctl - on - auto - prctl - seccomp - - - Disable Recovery Booting - Oracle Linux 9 systems support an "recovery boot" option that can be used -to prevent services from being started. The GRUB_DISABLE_RECOVERY -configuration option in /etc/default/grub should be set to -true to disable the generation of recovery mode menu entries. It is -also required to change the runtime configuration, run: -$ sudo grubby --update-kernel=ALL - FIA_UAU.1 - Using recovery boot, the console user could disable auditing, firewalls, -or other services, weakening system security. - - # Remediation is applicable only in certain platforms -if rpm --quiet -q grub2-common; then - -if grep -q '^GRUB_DISABLE_RECOVERY=.*' '/etc/default/grub' ; then - sed -i 's/GRUB_DISABLE_RECOVERY=.*/GRUB_DISABLE_RECOVERY=true/' "/etc/default/grub" -else - echo "GRUB_DISABLE_RECOVERY=true" >> '/etc/default/grub' -fi - -grubby --update-kernel=ALL - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Gather the package facts - package_facts: - manager: auto - tags: - - grub2_disable_recovery - - low_complexity - - low_disruption - - medium_severity - - reboot_required - - restrict_strategy - -- name: Verify GRUB_DISABLE_RECOVERY=true - lineinfile: - path: /etc/default/grub - regexp: ^GRUB_DISABLE_RECOVERY=.* - line: GRUB_DISABLE_RECOVERY=true - state: present - when: '"grub2-common" in ansible_facts.packages' - tags: - - grub2_disable_recovery - - low_complexity - - low_disruption - - medium_severity - - reboot_required - - restrict_strategy - -- name: Update grub defaults and the bootloader menu - command: /sbin/grubby --update-kernel=ALL - when: '"grub2-common" in ansible_facts.packages' - tags: - - grub2_disable_recovery - - low_complexity - - low_disruption - - medium_severity - - reboot_required - - restrict_strategy - - - - - - - - - - IOMMU configuration directive - On x86 architecture supporting VT-d, the IOMMU manages the access control policy between the hardware devices and some - of the system critical units such as the memory. -To ensure that iommu=force is added as a kernel command line -argument to newly installed kernels, add iommu=force to the -default Grub2 command line for Linux operating systems. Modify the line within -/etc/default/grub as shown below: -GRUB_CMDLINE_LINUX="... iommu=force ..." -Run the following command to update command line for already installed kernels:# grubby --update-kernel=ALL --args="iommu=force" - Depending on the hardware, devices and operating system used, enabling IOMMU can cause hardware instabilities. Proper function and stability should be assessed before applying remediation to production systems. - BP28(R11) - On x86 architectures, activating the I/OMMU prevents the system from arbitrary accesses potentially made by - hardware devices. - - # Remediation is applicable only in certain platforms -if rpm --quiet -q grub2-common && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then - -grubby --update-kernel=ALL --args=iommu=force - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Gather the package facts - package_facts: - manager: auto - tags: - - grub2_enable_iommu_force - - low_disruption - - medium_complexity - - reboot_required - - restrict_strategy - - unknown_severity - -- name: Update grub defaults and the bootloader menu - command: /sbin/grubby --update-kernel=ALL --args="iommu=force" - when: - - '"grub2-common" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - grub2_enable_iommu_force - - low_disruption - - medium_complexity - - reboot_required - - restrict_strategy - - unknown_severity - - [customizations.kernel] -append = "iommu=force" - - - - - - - - - - Configure kernel to zero out memory before allocation - To configure the kernel to zero out memory before allocating it, add the -init_on_alloc=1 argument to the default GRUB 2 command line. -To ensure that init_on_alloc=1 is added as a kernel command line -argument to newly installed kernels, add init_on_alloc=1 to the -default Grub2 command line for Linux operating systems. Modify the line within -/etc/default/grub as shown below: -GRUB_CMDLINE_LINUX="... init_on_alloc=1 ..." -Run the following command to update command line for already installed kernels:# grubby --update-kernel=ALL --args="init_on_alloc=1" - When the kernel configuration option init_on_alloc is enabled, -all page allocator and slab allocator memory will be zeroed when allocated, -eliminating many kinds of "uninitialized heap memory" flaws, effectively -preventing data leaks. - - # Remediation is applicable only in certain platforms -if rpm --quiet -q grub2-common && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then - -grubby --update-kernel=ALL --args=init_on_alloc=1 - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Gather the package facts - package_facts: - manager: auto - tags: - - grub2_init_on_alloc_argument - - low_disruption - - medium_complexity - - medium_severity - - reboot_required - - restrict_strategy - -- name: Update grub defaults and the bootloader menu - command: /sbin/grubby --update-kernel=ALL --args="init_on_alloc=1" - when: - - '"grub2-common" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - grub2_init_on_alloc_argument - - low_disruption - - medium_complexity - - medium_severity - - reboot_required - - restrict_strategy - - [customizations.kernel] -append = "init_on_alloc=1" - - - - - - - - - - Configure L1 Terminal Fault mitigations - L1 Terminal Fault (L1TF) is a hardware vulnerability which allows unprivileged -speculative access to data which is available in the Level 1 Data Cache when -the page table entry isn't present. - -Select the appropriate mitigation by adding the argument -l1tf= to the default -GRUB 2 command line for the Linux operating system. -To ensure that l1tf= is added as a kernel command line -argument to newly installed kernels, add l1tf= to the -default Grub2 command line for Linux operating systems. Modify the line within -/etc/default/grub as shown below: -GRUB_CMDLINE_LINUX="... l1tf= ..." -Run the following command to update command line for already installed kernels:# grubby --update-kernel=ALL --args="l1tf=" - -Since Linux Kernel 4.19 you can check the L1TF vulnerability state with the -following command: -cat /sys/devices/system/cpu/vulnerabilities/l1tf - Enabling L1TF mitigations may impact performance of the system. - BP28(R8) - The L1TF vulnerability allows an attacker to bypass memory access security controls imposed -by the system or hypervisor. The L1TF vulnerability allows read access to any physical memory -location that is cached in the L1 Data Cache. - - # Remediation is applicable only in certain platforms -if rpm --quiet -q grub2-common && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then - -var_l1tf_options='' - - - -grubby --update-kernel=ALL --args=l1tf=$var_l1tf_options - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Gather the package facts - package_facts: - manager: auto - tags: - - grub2_l1tf_argument - - high_severity - - low_disruption - - medium_complexity - - reboot_required - - restrict_strategy -- name: XCCDF Value var_l1tf_options # promote to variable - set_fact: - var_l1tf_options: !!str - tags: - - always - -- name: Update grub defaults and the bootloader menu - command: /sbin/grubby --update-kernel=ALL --args="l1tf={{ var_l1tf_options }}" - when: - - '"grub2-common" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - grub2_l1tf_argument - - high_severity - - low_disruption - - medium_complexity - - reboot_required - - restrict_strategy - - [customizations.kernel] -append = "l1tf=" - - - - - - - - - - - Force kernel panic on uncorrected MCEs - A Machine Check Exception is an error generated by the CPU itdetects an error -in itself, memory or I/O devices. -These errors may be corrected and generate a check log entry, if an error -cannot be corrected the kernel may panic or SIGBUS. - -To force the kernel to panic on any uncorrected error reported by Machine Check -set the MCE tolerance to zero by adding mce=0 -to the default GRUB 2 command line for the Linux operating system. -To ensure that mce=0 is added as a kernel command line -argument to newly installed kernels, add mce=0 to the -default Grub2 command line for Linux operating systems. Modify the line within -/etc/default/grub as shown below: -GRUB_CMDLINE_LINUX="... mce=0 ..." -Run the following command to update command line for already installed kernels:# grubby --update-kernel=ALL --args="mce=0" - BP28(R8) - Allowing uncorrected errors to result on a SIGBUS may allow an attacker to continue -trying to exploit a vulnerability such as Rowhammer. - - # Remediation is applicable only in certain platforms -if rpm --quiet -q grub2-common && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then - -grubby --update-kernel=ALL --args=mce=0 - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Gather the package facts - package_facts: - manager: auto - tags: - - grub2_mce_argument - - low_disruption - - medium_complexity - - medium_severity - - reboot_required - - restrict_strategy - -- name: Update grub defaults and the bootloader menu - command: /sbin/grubby --update-kernel=ALL --args="mce=0" - when: - - '"grub2-common" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - grub2_mce_argument - - low_disruption - - medium_complexity - - medium_severity - - reboot_required - - restrict_strategy - - [customizations.kernel] -append = "mce=0" - - - - - - - - - - Ensure SMAP is not disabled during boot - The SMAP is used to prevent the supervisor mode from unintentionally reading/writing into -memory pages in the user space, it is enabled by default since Linux kernel 3.7. -But it could be disabled through kernel boot parameters. - -Ensure that Supervisor Mode Access Prevention (SMAP) is not disabled by -the nosmap boot paramenter option. - -Check that the line GRUB_CMDLINE_LINUX="..." within /etc/default/grub -doesn't contain the argument nosmap. -Run the following command to update command line for already installed kernels: -# grubby --update-kernel=ALL --remove-args="nosmap" - BP28(R1) - Disabling SMAP can facilitate exploitation of vulnerabilities caused by unintended access and -manipulation of data in the user space. - - # Remediation is applicable only in certain platforms -if rpm --quiet -q grub2-common && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then - -grubby --update-kernel=ALL --remove-args=nosmap - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Gather the package facts - package_facts: - manager: auto - tags: - - grub2_nosmap_argument_absent - - low_disruption - - medium_complexity - - medium_severity - - reboot_required - - restrict_strategy - -- name: Update grub defaults and the bootloader menu - command: /sbin/grubby --update-kernel=ALL --remove-args="nosmap" - when: - - '"grub2-common" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - grub2_nosmap_argument_absent - - low_disruption - - medium_complexity - - medium_severity - - reboot_required - - restrict_strategy - - - - - - - - - - Ensure SMEP is not disabled during boot - The SMEP is used to prevent the supervisor mode from executing user space code, -it is enabled by default since Linux kernel 3.0. But it could be disabled through -kernel boot parameters. - -Ensure that Supervisor Mode Execution Prevention (SMEP) is not disabled by -the nosmep boot paramenter option. - -Check that the line GRUB_CMDLINE_LINUX="..." within /etc/default/grub -doesn't contain the argument nosmep. -Run the following command to update command line for already installed kernels: -# grubby --update-kernel=ALL --remove-args="nosmep" - BP28(R1) - Disabling SMEP can facilitate exploitation of certain vulnerabilities because it allows -the kernel to unintentionally execute code in less privileged memory space. - - # Remediation is applicable only in certain platforms -if rpm --quiet -q grub2-common && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then - -grubby --update-kernel=ALL --remove-args=nosmep - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Gather the package facts - package_facts: - manager: auto - tags: - - grub2_nosmep_argument_absent - - low_disruption - - medium_complexity - - medium_severity - - reboot_required - - restrict_strategy - -- name: Update grub defaults and the bootloader menu - command: /sbin/grubby --update-kernel=ALL --remove-args="nosmep" - when: - - '"grub2-common" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - grub2_nosmep_argument_absent - - low_disruption - - medium_complexity - - medium_severity - - reboot_required - - restrict_strategy - - - - - - - - - - Enable randomization of the page allocator - To enable randomization of the page allocator in the kernel, add the -page_alloc.shuffle=1 argument to the default GRUB 2 command line. -To ensure that page_alloc.shuffle=1 is added as a kernel command line -argument to newly installed kernels, add page_alloc.shuffle=1 to the -default Grub2 command line for Linux operating systems. Modify the line within -/etc/default/grub as shown below: -GRUB_CMDLINE_LINUX="... page_alloc.shuffle=1 ..." -Run the following command to update command line for already installed kernels:# grubby --update-kernel=ALL --args="page_alloc.shuffle=1" - The CONFIG_SHUFFLE_PAGE_ALLOCATOR config option is primarily -focused on improving the average utilization of a direct-mapped -memory-side-cache. Aside of this performance effect, it also reduces -predictability of page allocations in situations when the bad actor can -crash the system and somehow leverage knowledge of (page) allocation order -right after a fresh reboot, or can control the timing between a -hot-pluggable memory node (as in NUMA node) and applications allocating -memory ouf of that node. The page_alloc.shuffle=1 kernel command -line parameter then forces this functionality irrespectively of memory cache -architecture. - - # Remediation is applicable only in certain platforms -if rpm --quiet -q grub2-common && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then - -grubby --update-kernel=ALL --args=page_alloc.shuffle=1 - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Gather the package facts - package_facts: - manager: auto - tags: - - grub2_page_alloc_shuffle_argument - - low_disruption - - medium_complexity - - medium_severity - - reboot_required - - restrict_strategy - -- name: Update grub defaults and the bootloader menu - command: /sbin/grubby --update-kernel=ALL --args="page_alloc.shuffle=1" - when: - - '"grub2-common" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - grub2_page_alloc_shuffle_argument - - low_disruption - - medium_complexity - - medium_severity - - reboot_required - - restrict_strategy - - [customizations.kernel] -append = "page_alloc.shuffle=1" - - - - - - - - - - Enable Kernel Page-Table Isolation (KPTI) - To enable Kernel page-table isolation, -add the argument pti=on to the default -GRUB 2 command line for the Linux operating system. -To ensure that pti=on is added as a kernel command line -argument to newly installed kernels, add pti=on to the -default Grub2 command line for Linux operating systems. Modify the line within -/etc/default/grub as shown below: -GRUB_CMDLINE_LINUX="... pti=on ..." -Run the following command to update command line for already installed kernels:# grubby --update-kernel=ALL --args="pti=on" - BP28(R8) - CCI-000381 - SI-16 - SRG-OS-000433-GPOS-00193 - SRG-OS-000095-GPOS-00049 - Kernel page-table isolation is a kernel feature that mitigates -the Meltdown security vulnerability and hardens the kernel -against attempts to bypass kernel address space layout -randomization (KASLR). - - # Remediation is applicable only in certain platforms -if rpm --quiet -q grub2-common && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then - -grubby --update-kernel=ALL --args=pti=on - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Gather the package facts - package_facts: - manager: auto - tags: - - NIST-800-53-SI-16 - - grub2_pti_argument - - low_disruption - - low_severity - - medium_complexity - - reboot_required - - restrict_strategy - -- name: Update grub defaults and the bootloader menu - command: /sbin/grubby --update-kernel=ALL --args="pti=on" - when: - - '"grub2-common" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-SI-16 - - grub2_pti_argument - - low_disruption - - low_severity - - medium_complexity - - reboot_required - - restrict_strategy - - [customizations.kernel] -append = "pti=on" - - - - - - - - - - Configure the confidence in TPM for entropy - The TPM security chip that is available in most modern systems has a hardware RNG. -It is also used to feed the entropy pool, but generally not credited entropy. - -Use rng_core.default_quality in the kernel command line to set the trust -level on the hardware generators. The trust level defines the amount of entropy to credit. -A value of 0 tells the system not to trust the hardware random number generators -available, and doesn't credit any entropy to the pool. -A value of 1000 assigns full confidence in the generators, and credits all the -entropy it provides to the pool. - -Note that the value of rng_core.default_quality is global, affecting the trust -on all hardware random number generators. - -Select the appropriate confidence by adding the argument -rng_core.default_quality= to the default -GRUB 2 command line for the Linux operating system. -To ensure that rng_core.default_quality= is added as a kernel command line -argument to newly installed kernels, add rng_core.default_quality= to the -default Grub2 command line for Linux operating systems. Modify the line within -/etc/default/grub as shown below: -GRUB_CMDLINE_LINUX="... rng_core.default_quality= ..." -Run the following command to update command line for already installed kernels:# grubby --update-kernel=ALL --args="rng_core.default_quality=" - BP28(R8) - A system may struggle to initialize its entropy pool and end up starving. Crediting entropy -from the hardware number generators available in the system helps fill up the entropy pool. - - # Remediation is applicable only in certain platforms -if rpm --quiet -q grub2-common && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then - -var_rng_core_default_quality='' - - - -grubby --update-kernel=ALL --args=rng_core.default_quality=$var_rng_core_default_quality - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Gather the package facts - package_facts: - manager: auto - tags: - - grub2_rng_core_default_quality_argument - - low_disruption - - low_severity - - medium_complexity - - reboot_required - - restrict_strategy -- name: XCCDF Value var_rng_core_default_quality # promote to variable - set_fact: - var_rng_core_default_quality: !!str - tags: - - always - -- name: Update grub defaults and the bootloader menu - command: /sbin/grubby --update-kernel=ALL --args="rng_core.default_quality={{ var_rng_core_default_quality - }}" - when: - - '"grub2-common" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - grub2_rng_core_default_quality_argument - - low_disruption - - low_severity - - medium_complexity - - reboot_required - - restrict_strategy - - [customizations.kernel] -append = "rng_core.default_quality=" - - - - - - - - - - - Disable merging of slabs with similar size - The kernel may merge similar slabs together to reduce overhead and increase -cache hotness of objects. -Disabling merging of slabs keeps the slabs separate and reduces the risk of -kernel heap overflows overwriting objects in merged caches. - -To disable merging of slabs in the Kernel add the argument slab_nomerge=yes -to the default GRUB 2 command line for the Linux operating system. -To ensure that slab_nomerge=yes is added as a kernel command line -argument to newly installed kernels, add slab_nomerge=yes to the -default Grub2 command line for Linux operating systems. Modify the line within -/etc/default/grub as shown below: -GRUB_CMDLINE_LINUX="... slab_nomerge=yes ..." -Run the following command to update command line for already installed kernels:# grubby --update-kernel=ALL --args="slab_nomerge=yes" - Disabling merge of slabs will slightly increase kernel memory utilization. - BP28(R8) - Disabling the merge of slabs of similar sizes prevents the kernel from -merging a seemingly useless but vulnerable slab with a useful and valuable slab. -This increase the risk that a heap overflow could overwrite objects from merged caches, -with unmerged caches the heap overflow would only affect the objects in the same cache. -Overall, this reduces the kernel attack surface area by isolating slabs from each other. - - # Remediation is applicable only in certain platforms -if rpm --quiet -q grub2-common && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then - -grubby --update-kernel=ALL --args=slab_nomerge=yes - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Gather the package facts - package_facts: - manager: auto - tags: - - grub2_slab_nomerge_argument - - low_disruption - - medium_complexity - - medium_severity - - reboot_required - - restrict_strategy - -- name: Update grub defaults and the bootloader menu - command: /sbin/grubby --update-kernel=ALL --args="slab_nomerge=yes" - when: - - '"grub2-common" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - grub2_slab_nomerge_argument - - low_disruption - - medium_complexity - - medium_severity - - reboot_required - - restrict_strategy - - [customizations.kernel] -append = "slab_nomerge=yes" - - - - - - - - - - Configure Speculative Store Bypass Mitigation - Certain CPUs are vulnerable to an exploit against a common wide industry wide performance -optimization known as Speculative Store Bypass (SSB). - -In such cases, recent stores to the same memory location cannot always be observed by later -loads during speculative execution. However, such stores are unlikely and thus they can be -detected prior to instruction retirement at the end of a particular speculation execution -window. - -Since Linux Kernel 4.17 you can check the SSB mitigation state with the following command: -cat /sys/devices/system/cpu/vulnerabilities/spec_store_bypass - -Select the appropriate SSB state by adding the argument -spec_store_bypass_disable= to the default -GRUB 2 command line for the Linux operating system. -To ensure that spec_store_bypass_disable= is added as a kernel command line -argument to newly installed kernels, add spec_store_bypass_disable= to the -default Grub2 command line for Linux operating systems. Modify the line within -/etc/default/grub as shown below: -GRUB_CMDLINE_LINUX="... spec_store_bypass_disable= ..." -Run the following command to update command line for already installed kernels:# grubby --update-kernel=ALL --args="spec_store_bypass_disable=" - Disabling Speculative Store Bypass may impact performance of the system. - BP28(R8) - In vulnerable processsors, the speculatively forwarded store can be used in a cache side channel -attack. An example of this is reading memory to which the attacker does not directly have access, -for example inside the sandboxed code. - - # Remediation is applicable only in certain platforms -if rpm --quiet -q grub2-common && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then - -var_spec_store_bypass_disable_options='' - - - -grubby --update-kernel=ALL --args=spec_store_bypass_disable=$var_spec_store_bypass_disable_options - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Gather the package facts - package_facts: - manager: auto - tags: - - grub2_spec_store_bypass_disable_argument - - low_disruption - - medium_complexity - - medium_severity - - reboot_required - - restrict_strategy -- name: XCCDF Value var_spec_store_bypass_disable_options # promote to variable - set_fact: - var_spec_store_bypass_disable_options: !!str - tags: - - always - -- name: Update grub defaults and the bootloader menu - command: /sbin/grubby --update-kernel=ALL --args="spec_store_bypass_disable={{ var_spec_store_bypass_disable_options - }}" - when: - - '"grub2-common" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - grub2_spec_store_bypass_disable_argument - - low_disruption - - medium_complexity - - medium_severity - - reboot_required - - restrict_strategy - - [customizations.kernel] -append = "spec_store_bypass_disable=" - - - - - - - - - - - Enforce Spectre v2 mitigation - Spectre V2 is an indirect branch poisoning attack that can lead to data leakage. -An exploit for Spectre V2 tricks the indirect branch predictor into executing -code from a future indirect branch chosen by the attacker, even if the privilege -level is different. - -Since Linux Kernel 4.15 you can check the Spectre V2 mitigation state with the following command: -cat /sys/devices/system/cpu/vulnerabilities/spectre_v2 - -Enforce the Spectre V2 mitigation by adding the argument -spectre_v2=on to the default -GRUB 2 command line for the Linux operating system. -To ensure that spectre_v2=on) is added as a kernel command line -argument to newly installed kernels, add spectre_v2=on) to the -default Grub2 command line for Linux operating systems. Modify the line within -/etc/default/grub as shown below: -GRUB_CMDLINE_LINUX="... spectre_v2=on) ..." -Run the following command to update command line for already installed kernels:# grubby --update-kernel=ALL --args="spectre_v2=on)" - BP28(R8) - The Spectre V2 vulnerability allows an attacker to read memory that he should not have -access to. - - # Remediation is applicable only in certain platforms -if rpm --quiet -q grub2-common && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then - -grubby --update-kernel=ALL --args=spectre_v2=on - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Gather the package facts - package_facts: - manager: auto - tags: - - grub2_spectre_v2_argument - - high_severity - - low_disruption - - medium_complexity - - reboot_required - - restrict_strategy - -- name: Update grub defaults and the bootloader menu - command: /sbin/grubby --update-kernel=ALL --args="spectre_v2=on" - when: - - '"grub2-common" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - grub2_spectre_v2_argument - - high_severity - - low_disruption - - medium_complexity - - reboot_required - - restrict_strategy - - [customizations.kernel] -append = "spectre_v2=on" - - - - - - - - - - Ensure debug-shell service is not enabled during boot - systemd's debug-shell service is intended to -diagnose systemd related boot issues with various systemctl -commands. Once enabled and following a system reboot, the root shell -will be available on tty9 which is access by pressing -CTRL-ALT-F9. The debug-shell service should only be used -for systemd related issues and should otherwise be disabled. - -By default, the debug-shell systemd service is already disabled. - -Ensure the debug-shell is not enabled by the systemd.debug-shel=1 -boot paramenter option. - -Check that the line GRUB_CMDLINE_LINUX="..." within /etc/default/grub -doesn't contain the argument systemd.debug-shell=1. -Run the following command to update command line for already installed kernels: -# grubby --update-kernel=ALL --remove-args="systemd.debug-shell" - FIA_UAU.1 - This prevents attackers with physical access from trivially bypassing security -on the machine through valid troubleshooting configurations and gaining root -access when the system is rebooted. - - # Remediation is applicable only in certain platforms -if rpm --quiet -q grub2-common && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then - -grubby --update-kernel=ALL --remove-args=systemd.debug-shell - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Gather the package facts - package_facts: - manager: auto - tags: - - grub2_systemd_debug-shell_argument_absent - - low_disruption - - medium_complexity - - medium_severity - - reboot_required - - restrict_strategy - -- name: Update grub defaults and the bootloader menu - command: /sbin/grubby --update-kernel=ALL --remove-args="systemd.debug-shell" - when: - - '"grub2-common" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - grub2_systemd_debug-shell_argument_absent - - low_disruption - - medium_complexity - - medium_severity - - reboot_required - - restrict_strategy - - - - - - - - - - Disable vsyscalls - To disable use of virtual syscalls, -add the argument vsyscall=none to the default -GRUB 2 command line for the Linux operating system. -To ensure that vsyscall=none is added as a kernel command line -argument to newly installed kernels, add vsyscall=none to the -default Grub2 command line for Linux operating systems. Modify the line within -/etc/default/grub as shown below: -GRUB_CMDLINE_LINUX="... vsyscall=none ..." -Run the following command to update command line for already installed kernels:# grubby --update-kernel=ALL --args="vsyscall=none" - CCI-001084 - CM-7(a) - FPT_ASLR_EXT.1 - SRG-OS-000480-GPOS-00227 - SRG-OS-000134-GPOS-00068 - Virtual Syscalls provide an opportunity of attack for a user who has control -of the return instruction pointer. - - # Remediation is applicable only in certain platforms -if rpm --quiet -q grub2-common && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then - -grubby --update-kernel=ALL --args=vsyscall=none - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Gather the package facts - package_facts: - manager: auto - tags: - - NIST-800-53-CM-7(a) - - grub2_vsyscall_argument - - low_disruption - - medium_complexity - - medium_severity - - reboot_required - - restrict_strategy - -- name: Update grub defaults and the bootloader menu - command: /sbin/grubby --update-kernel=ALL --args="vsyscall=none" - when: - - '"grub2-common" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-CM-7(a) - - grub2_vsyscall_argument - - low_disruption - - medium_complexity - - medium_severity - - reboot_required - - restrict_strategy - - [customizations.kernel] -append = "vsyscall=none" - - - - - - - - - - Non-UEFI GRUB2 bootloader configuration - Non-UEFI GRUB2 bootloader configuration - - - Verify /boot/grub2/grub.cfg Group Ownership - The file /boot/grub2/grub.cfg should -be group-owned by the root group to prevent -destruction or modification of the file. - -To properly set the group owner of /boot/grub2/grub.cfg, run the command: -$ sudo chgrp root /boot/grub2/grub.cfg - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - 5.5.2.2 - APO01.06 - DSS05.04 - DSS05.07 - DSS06.02 - 3.4.5 - CCI-000225 - 164.308(a)(1)(ii)(B) - 164.308(a)(7)(i) - 164.308(a)(7)(ii)(A) - 164.310(a)(1) - 164.310(a)(2)(i) - 164.310(a)(2)(ii) - 164.310(a)(2)(iii) - 164.310(b) - 164.310(c) - 164.310(d)(1) - 164.310(d)(2)(iii) - 4.3.3.7.3 - SR 2.1 - SR 5.2 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CM-6(a) - AC-6(1) - PR.AC-4 - PR.DS-5 - Req-7.1 - 2.2.6 - SRG-OS-000480-GPOS-00227 - The root group is a highly-privileged group. Furthermore, the group-owner of this -file should not have any access privileges anyway. - - # Remediation is applicable only in certain platforms -if [ ! -d /sys/firmware/efi ] && rpm --quiet -q grub2-common && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then - -chgrp 0 /boot/grub2/grub.cfg - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Gather the package facts - package_facts: - manager: auto - tags: - - CJIS-5.5.2.2 - - NIST-800-171-3.4.5 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-7.1 - - PCI-DSSv4-2.2.6 - - configure_strategy - - file_groupowner_grub2_cfg - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Test for existence /boot/grub2/grub.cfg - stat: - path: /boot/grub2/grub.cfg - register: file_exists - when: - - '"/boot/efi" not in ansible_mounts | map(attribute="mount") | list' - - '"grub2-common" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - CJIS-5.5.2.2 - - NIST-800-171-3.4.5 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-7.1 - - PCI-DSSv4-2.2.6 - - configure_strategy - - file_groupowner_grub2_cfg - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Ensure group owner 0 on /boot/grub2/grub.cfg - file: - path: /boot/grub2/grub.cfg - group: '0' - when: - - '"/boot/efi" not in ansible_mounts | map(attribute="mount") | list' - - '"grub2-common" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - file_exists.stat is defined and file_exists.stat.exists - tags: - - CJIS-5.5.2.2 - - NIST-800-171-3.4.5 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-7.1 - - PCI-DSSv4-2.2.6 - - configure_strategy - - file_groupowner_grub2_cfg - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Verify /boot/grub2/user.cfg Group Ownership - The file /boot/grub2/user.cfg should be group-owned by the root -group to prevent reading or modification of the file. - -To properly set the group owner of /boot/grub2/user.cfg, run the command: -$ sudo chgrp root /boot/grub2/user.cfg - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - 5.5.2.2 - APO01.06 - DSS05.04 - DSS05.07 - DSS06.02 - 3.4.5 - CCI-000225 - 164.308(a)(1)(ii)(B) - 164.308(a)(7)(i) - 164.308(a)(7)(ii)(A) - 164.310(a)(1) - 164.310(a)(2)(i) - 164.310(a)(2)(ii) - 164.310(a)(2)(iii) - 164.310(b) - 164.310(c) - 164.310(d)(1) - 164.310(d)(2)(iii) - 4.3.3.7.3 - SR 2.1 - SR 5.2 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CM-6(a) - AC-6(1) - PR.AC-4 - PR.DS-5 - Req-7.1 - SRG-OS-000480-GPOS-00227 - The root group is a highly-privileged group. Furthermore, the group-owner of this -file should not have any access privileges anyway. Non-root users who read the boot parameters -may be able to identify weaknesses in security upon boot and be able to exploit them. - - # Remediation is applicable only in certain platforms -if [ ! -d /sys/firmware/efi ] && rpm --quiet -q grub2-common && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then - -chgrp 0 /boot/grub2/user.cfg - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Gather the package facts - package_facts: - manager: auto - tags: - - CJIS-5.5.2.2 - - NIST-800-171-3.4.5 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-7.1 - - configure_strategy - - file_groupowner_user_cfg - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Test for existence /boot/grub2/user.cfg - stat: - path: /boot/grub2/user.cfg - register: file_exists - when: - - '"/boot/efi" not in ansible_mounts | map(attribute="mount") | list' - - '"grub2-common" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - CJIS-5.5.2.2 - - NIST-800-171-3.4.5 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-7.1 - - configure_strategy - - file_groupowner_user_cfg - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Ensure group owner 0 on /boot/grub2/user.cfg - file: - path: /boot/grub2/user.cfg - group: '0' - when: - - '"/boot/efi" not in ansible_mounts | map(attribute="mount") | list' - - '"grub2-common" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - file_exists.stat is defined and file_exists.stat.exists - tags: - - CJIS-5.5.2.2 - - NIST-800-171-3.4.5 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-7.1 - - configure_strategy - - file_groupowner_user_cfg - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Verify /boot/grub2/grub.cfg User Ownership - The file /boot/grub2/grub.cfg should -be owned by the root user to prevent destruction -or modification of the file. - -To properly set the owner of /boot/grub2/grub.cfg, run the command: -$ sudo chown root /boot/grub2/grub.cfg - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - 5.5.2.2 - APO01.06 - DSS05.04 - DSS05.07 - DSS06.02 - 3.4.5 - CCI-000225 - 164.308(a)(1)(ii)(B) - 164.308(a)(7)(i) - 164.308(a)(7)(ii)(A) - 164.310(a)(1) - 164.310(a)(2)(i) - 164.310(a)(2)(ii) - 164.310(a)(2)(iii) - 164.310(b) - 164.310(c) - 164.310(d)(1) - 164.310(d)(2)(iii) - 4.3.3.7.3 - SR 2.1 - SR 5.2 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CM-6(a) - AC-6(1) - PR.AC-4 - PR.DS-5 - Req-7.1 - 2.2.6 - Only root should be able to modify important boot parameters. - - # Remediation is applicable only in certain platforms -if [ ! -d /sys/firmware/efi ] && rpm --quiet -q grub2-common && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then - -chown 0 /boot/grub2/grub.cfg - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Gather the package facts - package_facts: - manager: auto - tags: - - CJIS-5.5.2.2 - - NIST-800-171-3.4.5 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-7.1 - - PCI-DSSv4-2.2.6 - - configure_strategy - - file_owner_grub2_cfg - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Test for existence /boot/grub2/grub.cfg - stat: - path: /boot/grub2/grub.cfg - register: file_exists - when: - - '"/boot/efi" not in ansible_mounts | map(attribute="mount") | list' - - '"grub2-common" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - CJIS-5.5.2.2 - - NIST-800-171-3.4.5 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-7.1 - - PCI-DSSv4-2.2.6 - - configure_strategy - - file_owner_grub2_cfg - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Ensure owner 0 on /boot/grub2/grub.cfg - file: - path: /boot/grub2/grub.cfg - owner: '0' - when: - - '"/boot/efi" not in ansible_mounts | map(attribute="mount") | list' - - '"grub2-common" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - file_exists.stat is defined and file_exists.stat.exists - tags: - - CJIS-5.5.2.2 - - NIST-800-171-3.4.5 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-7.1 - - PCI-DSSv4-2.2.6 - - configure_strategy - - file_owner_grub2_cfg - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Verify /boot/grub2/user.cfg User Ownership - The file /boot/grub2/user.cfg should be owned by the root -user to prevent reading or modification of the file. - -To properly set the owner of /boot/grub2/user.cfg, run the command: -$ sudo chown root /boot/grub2/user.cfg - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - 5.5.2.2 - APO01.06 - DSS05.04 - DSS05.07 - DSS06.02 - 3.4.5 - CCI-000225 - 164.308(a)(1)(ii)(B) - 164.308(a)(7)(i) - 164.308(a)(7)(ii)(A) - 164.310(a)(1) - 164.310(a)(2)(i) - 164.310(a)(2)(ii) - 164.310(a)(2)(iii) - 164.310(b) - 164.310(c) - 164.310(d)(1) - 164.310(d)(2)(iii) - 4.3.3.7.3 - SR 2.1 - SR 5.2 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CM-6(a) - AC-6(1) - PR.AC-4 - PR.DS-5 - Req-7.1 - Only root should be able to modify important boot parameters. Also, non-root users who read -the boot parameters may be able to identify weaknesses in security upon boot and be able to -exploit them. - - # Remediation is applicable only in certain platforms -if [ ! -d /sys/firmware/efi ] && rpm --quiet -q grub2-common && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then - -chown 0 /boot/grub2/user.cfg - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Gather the package facts - package_facts: - manager: auto - tags: - - CJIS-5.5.2.2 - - NIST-800-171-3.4.5 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-7.1 - - configure_strategy - - file_owner_user_cfg - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Test for existence /boot/grub2/user.cfg - stat: - path: /boot/grub2/user.cfg - register: file_exists - when: - - '"/boot/efi" not in ansible_mounts | map(attribute="mount") | list' - - '"grub2-common" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - CJIS-5.5.2.2 - - NIST-800-171-3.4.5 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-7.1 - - configure_strategy - - file_owner_user_cfg - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Ensure owner 0 on /boot/grub2/user.cfg - file: - path: /boot/grub2/user.cfg - owner: '0' - when: - - '"/boot/efi" not in ansible_mounts | map(attribute="mount") | list' - - '"grub2-common" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - file_exists.stat is defined and file_exists.stat.exists - tags: - - CJIS-5.5.2.2 - - NIST-800-171-3.4.5 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-7.1 - - configure_strategy - - file_owner_user_cfg - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Set the Boot Loader Admin Username to a Non-Default Value - The grub2 boot loader should have a superuser account and password -protection enabled to protect boot-time settings. - -To maximize the protection, select a password-protected superuser account with unique name, and modify the -/etc/grub.d/01_users configuration file to reflect the account name change. - -Do not to use common administrator account names like root, -admin, or administrator for the grub2 superuser account. - -Change the superuser to a different username (The default is 'root'). -$ sed -i 's/\(set superusers=\).*/\1"<unique user ID>"/g' /etc/grub.d/01_users - -Once the superuser account has been added, -update the -grub.cfg file by running: -grubby --update-kernel=ALL - To prevent hard-coded admin usernames, automatic remediation of this control is not available. Remediation -must be automated as a component of machine provisioning, or followed manually as outlined above. - -Also, do NOT manually add the superuser account and password to the -grub.cfg file as the grub2-mkconfig command overwrites this file. - BP28(R17) - 1 - 11 - 12 - 14 - 15 - 16 - 18 - 3 - 5 - DSS05.02 - DSS05.04 - DSS05.05 - DSS05.07 - DSS05.10 - DSS06.03 - DSS06.06 - DSS06.10 - 3.4.5 - CCI-000213 - 164.308(a)(1)(ii)(B) - 164.308(a)(7)(i) - 164.308(a)(7)(ii)(A) - 164.310(a)(1) - 164.310(a)(2)(i) - 164.310(a)(2)(ii) - 164.310(a)(2)(iii) - 164.310(b) - 164.310(c) - 164.310(d)(1) - 164.310(d)(2)(iii) - 4.3.3.2.2 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - A.18.1.4 - A.6.1.2 - A.7.1.1 - A.9.1.2 - A.9.2.1 - A.9.2.2 - A.9.2.3 - A.9.2.4 - A.9.2.6 - A.9.3.1 - A.9.4.1 - A.9.4.2 - A.9.4.3 - A.9.4.4 - A.9.4.5 - CM-6(a) - PR.AC-1 - PR.AC-4 - PR.AC-6 - PR.AC-7 - PR.PT-3 - FIA_UAU.1 - SRG-OS-000080-GPOS-00048 - Having a non-default grub superuser username makes password-guessing attacks less effective. - - - - - - - - - - Set Boot Loader Password in grub2 - The grub2 boot loader should have a superuser account and password -protection enabled to protect boot-time settings. - -Since plaintext passwords are a security risk, generate a hash for the password -by running the following command: - -# grub2-setpassword - -When prompted, enter the password that was selected. - - To prevent hard-coded passwords, automatic remediation of this control is not available. Remediation -must be automated as a component of machine provisioning, or followed manually as outlined above. - -Also, do NOT manually add the superuser account and password to the -grub.cfg file as the grub2-mkconfig command overwrites this file. - BP28(R17) - 1 - 11 - 12 - 14 - 15 - 16 - 18 - 3 - 5 - DSS05.02 - DSS05.04 - DSS05.05 - DSS05.07 - DSS05.10 - DSS06.03 - DSS06.06 - DSS06.10 - 3.4.5 - CCI-000213 - 164.308(a)(1)(ii)(B) - 164.308(a)(7)(i) - 164.308(a)(7)(ii)(A) - 164.310(a)(1) - 164.310(a)(2)(i) - 164.310(a)(2)(ii) - 164.310(a)(2)(iii) - 164.310(b) - 164.310(c) - 164.310(d)(1) - 164.310(d)(2)(iii) - 4.3.3.2.2 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - A.18.1.4 - A.6.1.2 - A.7.1.1 - A.9.1.2 - A.9.2.1 - A.9.2.2 - A.9.2.3 - A.9.2.4 - A.9.2.6 - A.9.3.1 - A.9.4.1 - A.9.4.2 - A.9.4.3 - A.9.4.4 - A.9.4.5 - CM-6(a) - PR.AC-1 - PR.AC-4 - PR.AC-6 - PR.AC-7 - PR.PT-3 - FIA_UAU.1 - SRG-OS-000080-GPOS-00048 - Password protection on the boot loader configuration ensures -users with physical access cannot trivially alter -important bootloader settings. These include which kernel to use, -and whether to enter single-user mode. - - - - - - - - - - - UEFI GRUB2 bootloader configuration - UEFI GRUB2 bootloader configuration - UEFI generally uses vfat file systems, which does not support Unix-style permissions -managed by chmod command. In this case, in order to change file permissions for files -within /boot/efi it is necessary to update the mount options in /etc/fstab file and -reboot the system. - - - Verify /boot/grub2/user.cfg Group Ownership - The file /boot/grub2/user.cfg should be group-owned by the -root group to prevent reading or modification of the file. - -To properly set the group owner of /boot/grub2/user.cfg, run the command: -$ sudo chgrp root /boot/grub2/user.cfg - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - 5.5.2.2 - APO01.06 - DSS05.04 - DSS05.07 - DSS06.02 - 3.4.5 - CCI-000225 - 4.3.3.7.3 - SR 2.1 - SR 5.2 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CM-6(a) - AC-6(1) - PR.AC-4 - PR.DS-5 - Req-7.1 - The root group is a highly-privileged group. Furthermore, the group-owner of this -file should not have any access privileges anyway. Non-root users who read the boot parameters -may be able to identify weaknesses in security upon boot and be able to exploit them. - - # Remediation is applicable only in certain platforms -if [ -d /sys/firmware/efi ] && rpm --quiet -q grub2-common && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then - -chgrp 0 /boot/grub2/user.cfg - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Gather the package facts - package_facts: - manager: auto - tags: - - CJIS-5.5.2.2 - - NIST-800-171-3.4.5 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-7.1 - - configure_strategy - - file_groupowner_efi_user_cfg - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Test for existence /boot/grub2/user.cfg - stat: - path: /boot/grub2/user.cfg - register: file_exists - when: - - '"/boot/efi" in ansible_mounts | map(attribute="mount") | list' - - '"grub2-common" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - CJIS-5.5.2.2 - - NIST-800-171-3.4.5 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-7.1 - - configure_strategy - - file_groupowner_efi_user_cfg - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Ensure group owner 0 on /boot/grub2/user.cfg - file: - path: /boot/grub2/user.cfg - group: '0' - when: - - '"/boot/efi" in ansible_mounts | map(attribute="mount") | list' - - '"grub2-common" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - file_exists.stat is defined and file_exists.stat.exists - tags: - - CJIS-5.5.2.2 - - NIST-800-171-3.4.5 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-7.1 - - configure_strategy - - file_groupowner_efi_user_cfg - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Set the UEFI Boot Loader Admin Username to a Non-Default Value - The grub2 boot loader should have a superuser account and password -protection enabled to protect boot-time settings. - -To maximize the protection, select a password-protected superuser account with unique name, and modify the -/etc/grub.d/01_users configuration file to reflect the account name change. - -It is highly suggested not to use common administrator account names like root, -admin, or administrator for the grub2 superuser account. - -Change the superuser to a different username (The default is 'root'). -$ sed -i 's/\(set superusers=\).*/\1"<unique user ID>"/g' /etc/grub.d/01_users - -Once the superuser account has been added, -update the -grub.cfg file by running: -grubby --update-kernel=ALL - To prevent hard-coded admin usernames, automatic remediation of this control is not available. Remediation -must be automated as a component of machine provisioning, or followed manually as outlined above. - -Also, do NOT manually add the superuser account and password to the -grub.cfg file as the grub2-mkconfig command overwrites this file. - BP28(R17) - 11 - 12 - 14 - 15 - 16 - 18 - 3 - 5 - DSS05.02 - DSS05.04 - DSS05.05 - DSS05.07 - DSS06.03 - DSS06.06 - 3.4.5 - CCI-000213 - 164.308(a)(1)(ii)(B) - 164.308(a)(7)(i) - 164.308(a)(7)(ii)(A) - 164.310(a)(1) - 164.310(a)(2)(i) - 164.310(a)(2)(ii) - 164.310(a)(2)(iii) - 164.310(b) - 164.310(c) - 164.310(d)(1) - 164.310(d)(2)(iii) - 4.3.3.2.2 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - A.6.1.2 - A.7.1.1 - A.9.1.2 - A.9.2.1 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CM-6(a) - PR.AC-4 - PR.AC-6 - PR.PT-3 - FIA_UAU.1 - SRG-OS-000080-GPOS-00048 - Having a non-default grub superuser username makes password-guessing attacks less effective. - - - - - - - - - - Set the UEFI Boot Loader Password - The grub2 boot loader should have a superuser account and password -protection enabled to protect boot-time settings. - -Since plaintext passwords are a security risk, generate a hash for the password -by running the following command: - -# grub2-setpassword - -When prompted, enter the password that was selected. - - To prevent hard-coded passwords, automatic remediation of this control is not available. Remediation -must be automated as a component of machine provisioning, or followed manually as outlined above. - -Also, do NOT manually add the superuser account and password to the -grub.cfg file as the grub2-mkconfig command overwrites this file. - BP28(R17) - 11 - 12 - 14 - 15 - 16 - 18 - 3 - 5 - DSS05.02 - DSS05.04 - DSS05.05 - DSS05.07 - DSS06.03 - DSS06.06 - 3.4.5 - CCI-000213 - 164.308(a)(1)(ii)(B) - 164.308(a)(7)(i) - 164.308(a)(7)(ii)(A) - 164.310(a)(1) - 164.310(a)(2)(i) - 164.310(a)(2)(ii) - 164.310(a)(2)(iii) - 164.310(b) - 164.310(c) - 164.310(d)(1) - 164.310(d)(2)(iii) - 4.3.3.2.2 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - A.6.1.2 - A.7.1.1 - A.9.1.2 - A.9.2.1 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CM-6(a) - PR.AC-4 - PR.AC-6 - PR.PT-3 - FIA_UAU.1 - SRG-OS-000080-GPOS-00048 - Password protection on the boot loader configuration ensures -users with physical access cannot trivially alter -important bootloader settings. These include which kernel to use, -and whether to enter single-user mode. - - - - - - - - - - - - zIPL bootloader configuration - During the boot process, the bootloader is -responsible for starting the execution of the kernel and passing -options to it. -The default Oracle Linux 9 boot loader for s390x systems is called zIPL. - - - - Protect Random-Number Entropy Pool - The I/O operations of the Linux kernel block layer due to their inherently -unpredictable execution times have been traditionally considered as a reliable -source to contribute to random-number entropy pool of the Linux kernel. This -has changed with introduction of solid-state storage devices (SSDs) though. - - - Ensure Solid State Drives Do Not Contribute To Random-Number Entropy Pool - For each solid-state drive on the system, run: - # echo 0 > /sys/block/DRIVE/queue/add_random - In contrast to traditional electromechanical magnetic disks, containing -spinning disks and / or movable read / write heads, the solid-state storage -devices (SSDs) do not contain moving / mechanical components. Therefore the -I/O operation completion times are much more predictable for them. - - - - Kernel Configuration - Contains rules that check the kernel configuration that was used to build it. - - - Hash function for kernel module signing - The hash function to use when signing modules during kernel build process. - sha512 - sha1 - sha224 - sha256 - sha384 - sha512 - - - Key and certificate for kernel module signing - The private key and certificate to use when signing modules during kernel build process. -On systems where the OpenSSL ENGINE_pkcs11 is functional — a PKCS#11 URI as defined by RFC7512 -In the latter case, the PKCS#11 URI should reference both a certificate and a private key. - certs/signing_key.pem - certs/signing_key.pem - - - Kernel panic timeout - The time, in seconds, to wait until a reboot occurs. -If the value is 0 the system never reboots. -If the value is less than 0 the system reboots immediately. - 0 - 0 - 300 - 60 - -1 - - - Do not allow ACPI methods to be inserted/replaced at run time - This debug facility allows ACPI AML methods to be inserted and/or replaced without rebooting -the system. -This configuration is available from kernel 3.0. - -The configuration that was used to build kernel is available at /boot/config-*. - To check the configuration value for CONFIG_ACPI_CUSTOM_METHOD, run the following command: - grep CONFIG_ACPI_CUSTOM_METHOD /boot/config-* - - Configs with value 'n' are not explicitly set in the file, so either commented lines or no - lines should be returned. - - There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. - BP28(R15) - Enabling this feature allows arbitrary kernel memory to be written to by root (uid=0) users, -allowing them to bypass certain security measures - - - - - - - - - Disable kernel support for MISC binaries - Enabling CONFIG_BINFMT_MISC makes it possible to plug wrapper-driven binary formats -into the kernel. This is specially useful for programs that need an interpreter to run like -Java, Python and DOS emulators. Once you have registered such a binary class with the kernel, -you can start one of those programs simply by typing in its name at a shell prompt. - -The configuration that was used to build kernel is available at /boot/config-*. - To check the configuration value for CONFIG_BINFMT_MISC, run the following command: - grep CONFIG_BINFMT_MISC /boot/config-* - - Configs with value 'n' are not explicitly set in the file, so either commented lines or no - lines should be returned. - - There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. - BP28(R23) - This disables arbitrary binary format support and helps reduce attack surface. - - - - - - - - - Enable support for BUG() - Disabling this option eliminates support for BUG and WARN, reducing the size of your kernel -image and potentially quietly ignoring numerous fatal conditions. You should only consider -disabling this option for embedded systems with no facilities for reporting errors. - -The configuration that was used to build kernel is available at /boot/config-*. - To check the configuration value for CONFIG_BUG, run the following command: - grep CONFIG_BUG /boot/config-* - - For each kernel installed, a line with value "y" should be returned. - - There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. - BP28(R19) - Not setting this variable may hide a number of critical errors. - - - - - - - - - Disable compatibility with brk() - Enabling compatiliby with brk() allows legacy binaries to run (i.e. those linked -against libc5). But this compatibility comes at the cost of not being able to randomize -the heap placement (ASLR). - -Unless legacy binaries need to run on the system, set CONFIG_COMPAT_BRK to "n". - -The configuration that was used to build kernel is available at /boot/config-*. - To check the configuration value for CONFIG_COMPAT_BRK, run the following command: - grep CONFIG_COMPAT_BRK /boot/config-* - - Configs with value 'n' are not explicitly set in the file, so either commented lines or no - lines should be returned. - - There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. - BP28(R17) - Enabling compatibility with brk() disables support for ASLR. - - - - - - - - - Disable the 32-bit vDSO - Certain buggy versions of glibc (2.3.3) will crash if they are presented with a 32-bit vDSO -that is not mapped at the address indicated in its segment table. -Setting CONFIG_COMPAT_VDSO to y turns off the 32-bit VDSO and works -aroud the glibc bug. - -The configuration that was used to build kernel is available at /boot/config-*. - To check the configuration value for CONFIG_COMPAT_VDSO, run the following command: - grep CONFIG_COMPAT_VDSO /boot/config-* - - Configs with value 'n' are not explicitly set in the file, so either commented lines or no - lines should be returned. - - There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. - BP28(R15) - Enabling VDSO compatibility hurts performance and disables ASLR. - - - - - - - - - Enable checks on credential management - Enable this to turn on some debug checking for credential management. The additional code keeps -track of the number of pointers from task_structs to any given cred struct, and checks to see -that this number never exceeds the usage count of the cred struct. - -Furthermore, if SELinux is enabled, this also checks that the security pointer in the cred -struct is never seen to be invalid. - -The configuration that was used to build kernel is available at /boot/config-*. - To check the configuration value for CONFIG_DEBUG_CREDENTIALS, run the following command: - grep CONFIG_DEBUG_CREDENTIALS /boot/config-* - - For each kernel installed, a line with value "y" should be returned. - - There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. - BP28(R16) - This adds sanity checks and validations to credential data structures. - - - - - - - - - Disable kernel debugfs - debugfs is a virtual file system that kernel developers use to put debugging files -into. Enable this option to be able to read and write to these files. - -The configuration that was used to build kernel is available at /boot/config-*. - To check the configuration value for CONFIG_DEBUG_FS, run the following command: - grep CONFIG_DEBUG_FS /boot/config-* - - Configs with value 'n' are not explicitly set in the file, so either commented lines or no - lines should be returned. - - There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. - BP28(R15) - To reduce the attack surface, this file system should be disabled if not in use. - - - - - - - - - Enable checks on linked list manipulation - Enable this to turn on extended checks in the linked-list walking routines. - -The configuration that was used to build kernel is available at /boot/config-*. - To check the configuration value for CONFIG_DEBUG_LIST, run the following command: - grep CONFIG_DEBUG_LIST /boot/config-* - - For each kernel installed, a line with value "y" should be returned. - - There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. - BP28(R16) - This add sanity checks to manipulation of linked lists structures in the kernel and may -prevent exploits such as CVE-2017-1661, where a race condition and simultaneos operations -caused a list to corrupt. - - - - - - - - - Enable checks on notifier call chains - Enable this to turn on sanity checking for notifier call chains. This is most useful for kernel -developers to make sure that modules properly unregister themselves from notifier chains. - -The configuration that was used to build kernel is available at /boot/config-*. - To check the configuration value for CONFIG_DEBUG_NOTIFIERS, run the following command: - grep CONFIG_DEBUG_NOTIFIERS /boot/config-* - - For each kernel installed, a line with value "y" should be returned. - - There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. - BP28(R16) - This provides validation of notifier chains, it checks whether the notifiers are from the -kernel or a module that is still loaded prior to being invoked. - - - - - - - - - Enable checks on scatter-gather (SG) table operations - Scatter-gather tables are mechanism used for high performance I/O on DMA devices. -Enable this to turn on checks on scatter-gather tables. - -The configuration that was used to build kernel is available at /boot/config-*. - To check the configuration value for CONFIG_DEBUG_SG, run the following command: - grep CONFIG_DEBUG_SG /boot/config-* - - For each kernel installed, a line with value "y" should be returned. - - There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. - BP28(R16) - This can help find problems with drivers that do not properly initialize their SG tables. - - - - - - - - - Configure low address space to protect from user allocation - This is the portion of low virtual memory which should be protected from userspace allocation. -This configuration is available from kernel 3.14, but may be available if backported -by distros. - -The configuration that was used to build kernel is available at /boot/config-*. - To check the configuration value for CONFIG_DEFAULT_MMAP_MIN_ADDR, run the following command: - grep CONFIG_DEFAULT_MMAP_MIN_ADDR /boot/config-* - - For each kernel installed, a line with value "65536" should be returned. - - There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. - BP28(R25) - Keeping a user from writing to low pages can help reduce the impact of kernel NULL pointer bugs. - - - - - - - - - Disable /dev/kmem virtual device support - Disable support for the /dev/kmem device. - -The configuration that was used to build kernel is available at /boot/config-*. - To check the configuration value for CONFIG_DEVKMEM, run the following command: - grep CONFIG_DEVKMEM /boot/config-* - - Configs with value 'n' are not explicitly set in the file, so either commented lines or no - lines should be returned. - - There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. - BP28(R15) - The /dev/kmem device is rarely used, but can be used for certain kind of kernel debugging -operations. - - - - - - - - - Disable hibernation - Enable the suspend to disk (STD) functionality, which is usually called "hibernation" in user -interfaces. STD checkpoints the system and powers it off; and restores that checkpoint on -reboot. - -The configuration that was used to build kernel is available at /boot/config-*. - To check the configuration value for CONFIG_HIBERNATION, run the following command: - grep CONFIG_HIBERNATION /boot/config-* - - Configs with value 'n' are not explicitly set in the file, so either commented lines or no - lines should be returned. - - There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. - BP28(R23) - Suspending to disk allows one to replace the running kernel. - - - - - - - - - Disable IA32 emulation - Disables support for legacy 32-bit programs under a 64-bit kernel. - -The configuration that was used to build kernel is available at /boot/config-*. - To check the configuration value for CONFIG_IA32_EMULATION, run the following command: - grep CONFIG_IA32_EMULATION /boot/config-* - - Configs with value 'n' are not explicitly set in the file, so either commented lines or no - lines should be returned. - - There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. - Only disable support for 32-bit programs if you are sure you don't need any 32-bit program. - BP28(R25) - Disabling 32-bit backwards compatibility helps reduce the attack surface. - - - - - - - - - Disable the IPv6 protocol - Disable support for IP version 6 (IPv6). - -The configuration that was used to build kernel is available at /boot/config-*. - To check the configuration value for CONFIG_IPV6, run the following command: - grep CONFIG_IPV6 /boot/config-* - - Configs with value 'n' are not explicitly set in the file, so either commented lines or no - lines should be returned. - - There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. - BP28(R22) - Any unnecessary network stacks, including IPv6, should be disabled to reduce -the vulnerability to exploitation. - - - - - - - - - Disable kexec system call - kexec is a system call that implements the ability to shutdown your current kernel, -and to start another kernel. It is like a reboot but it is independent of the system firmware. -And like a reboot you can start any kernel with it, not just Linux. - -The configuration that was used to build kernel is available at /boot/config-*. - To check the configuration value for CONFIG_KEXEC, run the following command: - grep CONFIG_KEXEC /boot/config-* - - Configs with value 'n' are not explicitly set in the file, so either commented lines or no - lines should be returned. - - There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. - BP28(R23) - Prohibits the execution of a new kernel image after reboot. - - - - - - - - - Disable legacy (BSD) PTY support - Disable the Linux traditional BSD-like terminal names /dev/ptyxx for masters and /dev/ttyxx for -slaves of pseudo terminals, and use only the modern ptys (devpts) interface. - -The configuration that was used to build kernel is available at /boot/config-*. - To check the configuration value for CONFIG_LEGACY_PTYS, run the following command: - grep CONFIG_LEGACY_PTYS /boot/config-* - - Configs with value 'n' are not explicitly set in the file, so either commented lines or no - lines should be returned. - - There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. - BP28(R23) - The legacy scheme has a number of security problems. - - - - - - - - - Enable module signature verification - Check modules for valid signatures upon load. -Note that this option adds the OpenSSL development packages as a kernel build dependency so -that the signing tool can use its crypto library. - -The configuration that was used to build kernel is available at /boot/config-*. - To check the configuration value for CONFIG_MODULE_SIG, run the following command: - grep CONFIG_MODULE_SIG /boot/config-* - - For each kernel installed, a line with value "y" should be returned. - - There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. - BP28(R18) - Loaded modules must be signed. - - - - - - - - - Enable automatic signing of all modules - Sign all modules during make modules_install. Without this option, modules must be signed -manually, using the scripts/sign-file tool. - -The configuration that was used to build kernel is available at /boot/config-*. - To check the configuration value for CONFIG_MODULE_SIG_ALL, run the following command: - grep CONFIG_MODULE_SIG_ALL /boot/config-* - - For each kernel installed, a line with value "y" should be returned. - - There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. - BP28(R18) - This ensures the modules are signed during install process. - - - - - - - - - Require modules to be validly signed - Reject unsigned modules or signed modules with an unknown key. - -The configuration that was used to build kernel is available at /boot/config-*. - To check the configuration value for CONFIG_MODULE_SIG_FORCE, run the following command: - grep CONFIG_MODULE_SIG_FORCE /boot/config-* - - For each kernel installed, a line with value "y" should be returned. - - There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. - BP28(R18) - Prevent loading modules that are unsigned or signed with an unknown key. - - - - - - - - - Specify the hash to use when signing modules - This configures the kernel to build and sign modules using - as the hash function. - -The configuration that was used to build kernel is available at /boot/config-*. - To check the configuration value for CONFIG_MODULE_SIG_HASH, run the following command: - grep CONFIG_MODULE_SIG_HASH /boot/config-* - - For each kernel installed, a line with value "" should be returned. - - There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. - BP28(R18) - Use of strong hash function is important to secure the module against counterfeit signatures. - - - - - - - - - - Specify module signing key to use - Setting this option to something other than its default of certs/signing_key.pem will -disable the autogeneration of signing keys and allow the kernel modules to be signed with a key -of your choosing. - -The string provided should identify a file containing both a private key and -its corresponding X.509 certificate in PEM form, or — on systems where the OpenSSL ENGINE_pkcs11 -is functional — a PKCS#11 URI as defined by RFC7512. In the latter case, the PKCS#11 URI should -reference both a certificate and a private key. - -The configuration that was used to build kernel is available at /boot/config-*. - To check the configuration value for CONFIG_MODULE_SIG_KEY, run the following command: - grep CONFIG_MODULE_SIG_KEY /boot/config-* - - For each kernel installed, a line with value "" should be returned. - - There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. - BP28(R18) - A key and certificate is required to sign the built modules. - - - - - - - - - - Sign kernel modules with SHA-512 - This configures the kernel to build and sign modules using SHA512 as the hash function. - -The configuration that was used to build kernel is available at /boot/config-*. - To check the configuration value for CONFIG_MODULE_SIG_SHA512, run the following command: - grep CONFIG_MODULE_SIG_SHA512 /boot/config-* - - For each kernel installed, a line with value "y" should be returned. - - There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. - BP28(R18) - Use of strong hash function is important to secure the module against counterfeit signatures. - - - - - - - - - Enable poison without sanity check - Skip the sanity checking on alloc, only fill the pages with poison on free. This reduces some -of the overhead of the poisoning feature. -This configuration is available from kernel 4.6. - -The configuration that was used to build kernel is available at /boot/config-*. - To check the configuration value for CONFIG_PAGE_POISONING_NO_SANITY, run the following command: - grep CONFIG_PAGE_POISONING_NO_SANITY /boot/config-* - - For each kernel installed, a line with value "y" should be returned. - - There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. - BP28(R17) - This configuration helps alleviates the performance impact of poisonining. - - - - - - - - - Use zero for poisoning instead of debugging value - Instead of using the existing poison value, fill the pages with zeros. This makes it harder to -detect when errors are occurring due to sanitization but the zeroing at free means that it is -no longer necessary to write zeros when GFP_ZERO is used on allocation. -This configuration is available from kernel 4.19. - -The configuration that was used to build kernel is available at /boot/config-*. - To check the configuration value for CONFIG_PAGE_POISONING_ZERO, run the following command: - grep CONFIG_PAGE_POISONING_ZERO /boot/config-* - - For each kernel installed, a line with value "y" should be returned. - - There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. - BP28(R17) - This configuration helps alleviates the performance impact of poisonining. - - - - - - - - - Remove the kernel mapping in user mode - This feature reduces the number of hardware side channels by ensuring that the majority of -kernel addresses are not mapped into userspace. -This configuration is available from kernel 4.15, but may be available if backported -by distros. - -The configuration that was used to build kernel is available at /boot/config-*. - To check the configuration value for CONFIG_PAGE_TABLE_ISOLATION, run the following command: - grep CONFIG_PAGE_TABLE_ISOLATION /boot/config-* - - For each kernel installed, a line with value "y" should be returned. - - There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. - BP28(R25) - This is a countermeasure to the Meltdown attack. - - - - - - - - - Kernel panic oops - Enable the kernel to panic when it oopses. -This has the same effect as setting oops=panic on the kernel command line. - -The configuration that was used to build kernel is available at /boot/config-*. - To check the configuration value for CONFIG_PANIC_ON_OOPS, run the following command: - grep CONFIG_PANIC_ON_OOPS /boot/config-* - - For each kernel installed, a line with value "y" should be returned. - - There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. - BP28(R19) - This feature ensures that the kernel does not do anything erroneous after an oops which -could result in data corruption or other issues. - - - - - - - - - Kernel panic timeout - Set the timeout value (in seconds) until a reboot occurs when the kernel panics. -A timeout of 0 configures the system to wait forever. With a timeout value greater than 0, -the system will wait the specified amount of seconds before rebooting. While a timeout value -less than 0 makes the system reboot immediately. - -The configuration that was used to build kernel is available at /boot/config-*. - To check the configuration value for CONFIG_PANIC_TIMEOUT, run the following command: - grep CONFIG_PANIC_TIMEOUT /boot/config-* - - For each kernel installed, a line with value "" should be returned. - - There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. - BP28(R19) - This is required to enable protection against Spectre v2. - - - - - - - - - - Disable support for /proc/kkcore - Provides a virtual ELF core file of the live kernel. - -The configuration that was used to build kernel is available at /boot/config-*. - To check the configuration value for CONFIG_PROC_KCORE, run the following command: - grep CONFIG_PROC_KCORE /boot/config-* - - Configs with value 'n' are not explicitly set in the file, so either commented lines or no - lines should be returned. - - There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. - BP28(R15) - This feature exposes the memory to the userspace and can assist an attacker in discovering -attack vectors. - - - - - - - - - Randomize the address of the kernel image (KASLR) - In support of Kernel Address Space Layout Randomization (KASLR), this randomizes the physical -address at which the kernel image is decompressed and the virtual address where the kernel -image is mapped. - -The configuration that was used to build kernel is available at /boot/config-*. - To check the configuration value for CONFIG_RANDOMIZE_BASE, run the following command: - grep CONFIG_RANDOMIZE_BASE /boot/config-* - - For each kernel installed, a line with value "y" should be returned. - - There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. - BP28(R25) - BP28(R27) - An unpredictable kernel address makes it more difficult to succeed with exploits that rely on -knowledge of the location of kernel code internals. - - - - - - - - - Randomize the kernel memory sections - Randomizes the base virtual address of kernel memory sections (physical memory mapping, -vmalloc & vmemmap). -This configuration is available from kernel 4.8, but may be available if backported -by distros. - -The configuration that was used to build kernel is available at /boot/config-*. - To check the configuration value for CONFIG_RANDOMIZE_MEMORY, run the following command: - grep CONFIG_RANDOMIZE_MEMORY /boot/config-* - - For each kernel installed, a line with value "y" should be returned. - - There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. - BP28(R25) - This security feature makes exploits relying on predictable memory locations less reliable. - - - - - - - - - Avoid speculative indirect branches in kernel - Compile kernel with the retpoline compiler options to guard against kernel-to-user data leaks -by avoiding speculative indirect branches. -Requires a compiler with -mindirect-branch=thunk-extern support for full protection. -The kernel may run slower. - -The configuration that was used to build kernel is available at /boot/config-*. - To check the configuration value for CONFIG_RETPOLINE, run the following command: - grep CONFIG_RETPOLINE /boot/config-* - - For each kernel installed, a line with value "y" should be returned. - - There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. - BP28(R15) - This is required to enable protection against Spectre v2. - - - - - - - - - Enable seccomp to safely compute untrusted bytecode - This kernel feature is useful for number crunching applications that may need to compute -untrusted bytecode during their execution. By using pipes or other transports made available -to the process as file descriptors supporting the read/write syscalls, it's possible to isolate -those applications in their own address space using seccomp. - -The configuration that was used to build kernel is available at /boot/config-*. - To check the configuration value for CONFIG_SECCOMP, run the following command: - grep CONFIG_SECCOMP /boot/config-* - - For each kernel installed, a line with value "y" should be returned. - - There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. - BP28(R20) - seccomp enables the ability to filter system calls made by an application, effectively -isolating the system's resources from it. - - - - - - - - - Enable use of Berkeley Packet Filter with seccomp - Enable tasks to build secure computing environments defined in terms of Berkeley Packet Filter -programs which implement task-defined system call filtering polices. - -The configuration that was used to build kernel is available at /boot/config-*. - To check the configuration value for CONFIG_SECCOMP_FILTER, run the following command: - grep CONFIG_SECCOMP_FILTER /boot/config-* - - For each kernel installed, a line with value "y" should be returned. - - There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. - BP28(R20) - Use of BPF filters allows for expressive filtering of system calls using a filter program -language with a long history of being exposed to userland. - - - - - - - - - Enable different security models - This allows you to choose different security modules to be configured into your kernel. - -The configuration that was used to build kernel is available at /boot/config-*. - To check the configuration value for CONFIG_SECURITY, run the following command: - grep CONFIG_SECURITY /boot/config-* - - For each kernel installed, a line with value "y" should be returned. - - There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. - BP28(R20) - This is enables kernel security primitives required by the LSM framework. - - - - - - - - - Restrict unprivileged access to the kernel syslog - Enforce restrictions on unprivileged users reading the kernel syslog via dmesg(8). - -The configuration that was used to build kernel is available at /boot/config-*. - To check the configuration value for CONFIG_SECURITY_DMESG_RESTRICT, run the following command: - grep CONFIG_SECURITY_DMESG_RESTRICT /boot/config-* - - Configs with value 'n' are not explicitly set in the file, so either commented lines or no - lines should be returned. - - There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. - BP28(R15) - Prevents unprivileged users from retrieving kernel addresses with dmesg. - - - - - - - - - Disable mutable hooks - Ensure kernel structures associated with LSMs are always mapped as read-only after system boot. - -The configuration that was used to build kernel is available at /boot/config-*. - To check the configuration value for CONFIG_SECURITY_WRITABLE_HOOKS, run the following command: - grep CONFIG_SECURITY_WRITABLE_HOOKS /boot/config-* - - For each kernel installed, a line with value "y" should be returned. - - There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. - BP28(R20) - If CONFIG_SECURITY_WRITABLE_HOOKS is enabled, then hooks can be loaded at runtime and -being able to manipulate hooks is a way to bypass all LSMs. - - - - - - - - - Enable Yama support - This enables support for LSM module Yama, which extends DAC support with additional system-wide -security settings beyond regular Linux discretionary access controls. The module will limit the -use of the system call ptrace(). - -The configuration that was used to build kernel is available at /boot/config-*. - To check the configuration value for CONFIG_SECURITY_YAMA, run the following command: - grep CONFIG_SECURITY_YAMA /boot/config-* - - For each kernel installed, a line with value "y" should be returned. - - There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. - BP28(R20) - Unrestricted usage of ptrace allows compromised binaries to run ptrace -on another processes of the user. - - - - - - - - - Enable SLUB debugging support - SLUB has extensive debug support features and this allows the allocator validation checking to -be enabled. - -The configuration that was used to build kernel is available at /boot/config-*. - To check the configuration value for CONFIG_SLUB_DEBUG, run the following command: - grep CONFIG_SLUB_DEBUG /boot/config-* - - For each kernel installed, a line with value "y" should be returned. - - There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. - BP28(R17) - This activates the checking of the memory allocator structures and resets to zero the zones -allocated when they are released. - - - - - - - - - Enable TCP/IP syncookie support - Normal TCP/IP networking is open to an attack known as SYN flooding. -It is denial-of-service attack that prevents legitimate remote users from being able to connect -to your computer during an ongoing attack. - -When enabled the TCP/IP stack will use a cryptographic challenge protocol known as SYN cookies -to enable legitimate users to continue to connect, even when your machine is under attack. - -The configuration that was used to build kernel is available at /boot/config-*. - To check the configuration value for CONFIG_SYN_COOKIES, run the following command: - grep CONFIG_SYN_COOKIES /boot/config-* - - For each kernel installed, a line with value "y" should be returned. - - There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. - BP28(R22) - SYN cookies provide protection against SYN flooding attacks. - - - - - - - - - Unmap kernel when running in userspace (aka KAISER) - Speculation attacks against some high-performance processors can be used to bypass MMU -permission checks and leak kernel data to userspace. This can be defended against by unmapping -the kernel when running in userspace, mapping it back in on exception entry via a trampoline -page in the vector table. -This configuration is available from kernel 4.16, but may be available if backported -by distros. -The configuration that was used to build kernel is available at /boot/config-*. - To check the configuration value for CONFIG_UNMAP_KERNEL_AT_EL0, run the following command: - grep CONFIG_UNMAP_KERNEL_AT_EL0 /boot/config-* - - For each kernel installed, a line with value "y" should be returned. - - There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. - BP28(R27) - This is a countermeasure to the Meltdown attack. - - - - - - - - - - Disable x86 vsyscall emulation - Disabling it is roughly equivalent to booting with vsyscall=none, except that it will also -disable the helpful warning if a program tries to use a vsyscall. With this option set to N, -offending programs will just segfault, citing addresses of the form 0xffffffffff600?00. -This configuration is available from kernel 3.19. - -The configuration that was used to build kernel is available at /boot/config-*. - To check the configuration value for CONFIG_X86_VSYSCALL_EMULATION, run the following command: - grep CONFIG_X86_VSYSCALL_EMULATION /boot/config-* - - Configs with value 'n' are not explicitly set in the file, so either commented lines or no - lines should be returned. - - There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. - BP28(R15) - The vsyscall table is no longer required and is a potential source of ROP gadgets. - - - - - - - - - Kernel GCC plugin configuration - Contains rules that check the configuration of GCC plugins used by the compiler - - - - - Configure Syslog - The syslog service has been the default Unix logging mechanism for -many years. It has a number of downsides, including inconsistent log format, -lack of authentication for received messages, and lack of authentication, -encryption, or reliable transport for messages sent over a network. However, -due to its long history, syslog is a de facto standard which is supported by -almost all Unix applications. - - -In Oracle Linux 9, rsyslog has replaced ksyslogd as the -syslog daemon of choice, and it includes some additional security features -such as reliable, connection-oriented (i.e. TCP) transmission of logs, the -option to log to database formats, and the encryption of log data en route to -a central logging server. -This section discusses how to configure rsyslog for -best effect, and how to use tools provided with the system to maintain and -monitor logs. - - - Ensure rsyslog-gnutls is installed - TLS protocol support for rsyslog is installed. - -The rsyslog-gnutls package can be installed with the following command: - -$ sudo yum install rsyslog-gnutls - BP28(R43) - CCI-000366 - FTP_ITC_EXT.1.1 - SRG-OS-000480-GPOS-00227 - SRG-OS-000120-GPOS-00061 - The rsyslog-gnutls package provides Transport Layer Security (TLS) support -for the rsyslog daemon, which enables secure remote logging. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -if ! rpm -q --quiet "rsyslog-gnutls" ; then - yum install -y "rsyslog-gnutls" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Ensure rsyslog-gnutls is installed - package: - name: rsyslog-gnutls - state: present - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - enable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - package_rsyslog-gnutls_installed - - include install_rsyslog-gnutls - -class install_rsyslog-gnutls { - package { 'rsyslog-gnutls': - ensure => 'installed', - } -} - - -package --add=rsyslog-gnutls - - -[[packages]] -name = "rsyslog-gnutls" -version = "*" - - - - - - - - - - Ensure rsyslog is Installed - Rsyslog is installed by default. The rsyslog package can be installed with the following command: $ sudo yum install rsyslog - 1 - 14 - 15 - 16 - 3 - 5 - 6 - APO11.04 - BAI03.05 - DSS05.04 - DSS05.07 - MEA02.01 - CCI-001311 - CCI-001312 - CCI-000366 - 164.312(a)(2)(ii) - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.4.4.7 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.8 - SR 2.9 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - CM-6(a) - PR.PT-1 - FTP_ITC_EXT.1.1 - SRG-OS-000479-GPOS-00224 - SRG-OS-000051-GPOS-00024 - SRG-OS-000480-GPOS-00227 - The rsyslog package provides the rsyslog daemon, which provides -system logging services. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -if ! rpm -q --quiet "rsyslog" ; then - yum install -y "rsyslog" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Ensure rsyslog is installed - package: - name: rsyslog - state: present - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-CM-6(a) - - enable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - package_rsyslog_installed - - include install_rsyslog - -class install_rsyslog { - package { 'rsyslog': - ensure => 'installed', - } -} - - -package --add=rsyslog - - -[[packages]] -name = "rsyslog" -version = "*" - - - - - - - - - - Enable rsyslog Service - The rsyslog service provides syslog-style logging by default on Oracle Linux 9. - -The rsyslog service can be enabled with the following command: -$ sudo systemctl enable rsyslog.service - 1 - 12 - 13 - 14 - 15 - 16 - 2 - 3 - 5 - 6 - 7 - 8 - 9 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - APO13.01 - BAI03.05 - BAI04.04 - DSS01.03 - DSS03.05 - DSS05.02 - DSS05.04 - DSS05.05 - DSS05.07 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - CCI-001311 - CCI-001312 - CCI-001557 - CCI-001851 - CCI-000366 - 164.312(a)(2)(ii) - 4.3.2.6.7 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.4.4.7 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.8 - SR 2.9 - SR 6.1 - SR 6.2 - SR 7.1 - SR 7.2 - A.12.1.3 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.14.2.7 - A.15.2.1 - A.15.2.2 - A.17.2.1 - CM-6(a) - AU-4(1) - DE.CM-1 - DE.CM-3 - DE.CM-7 - ID.SC-4 - PR.DS-4 - PR.PT-1 - SRG-OS-000480-GPOS-00227 - The rsyslog service must be running in order to provide -logging services, which are essential to system administration. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -SYSTEMCTL_EXEC='/usr/bin/systemctl' -"$SYSTEMCTL_EXEC" unmask 'rsyslog.service' -"$SYSTEMCTL_EXEC" start 'rsyslog.service' -"$SYSTEMCTL_EXEC" enable 'rsyslog.service' - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Enable service rsyslog - block: - - - name: Gather the package facts - package_facts: - manager: auto - - - name: Enable service rsyslog - systemd: - name: rsyslog - enabled: 'yes' - state: started - masked: 'no' - when: - - '"rsyslog" in ansible_facts.packages' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AU-4(1) - - NIST-800-53-CM-6(a) - - enable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_rsyslog_enabled - - include enable_rsyslog - -class enable_rsyslog { - service {'rsyslog': - enable => true, - ensure => 'running', - } -} - - -[customizations.services] -enabled = ["rsyslog"] - - - - - - - - - - Configure Logwatch on the Central Log Server - Is this system the central log server? If so, edit the file /etc/logwatch/conf/logwatch.conf as shown below. - - - Ensure Proper Configuration of Log Files - The file /etc/rsyslog.conf controls where log message are written. -These are controlled by lines called rules, which consist of a -selector and an action. -These rules are often customized depending on the role of the system, the -requirements of the environment, and whatever may enable -the administrator to most effectively make use of log data. -The default rules in Oracle Linux 9 are: -*.info;mail.none;authpriv.none;cron.none /var/log/messages -authpriv.* /var/log/secure -mail.* -/var/log/maillog -cron.* /var/log/cron -*.emerg * -uucp,news.crit /var/log/spooler -local7.* /var/log/boot.log -See the man page rsyslog.conf(5) for more information. -Note that the rsyslog daemon can be configured to use a timestamp format that -some log processing programs may not understand. If this occurs, -edit the file /etc/rsyslog.conf and add or edit the following line: -$ ActionFileDefaultTemplate RSYSLOG_TraditionalFileFormat - - User who owns log files - Specify user owner of all logfiles specified in -/etc/rsyslog.conf. - root - adm - root - syslog - - - Ensure cron Is Logging To Rsyslog - Cron logging must be implemented to spot intrusions or trace -cron job status. If cron is not logging to rsyslog, it -can be implemented by adding the following to the RULES section of -/etc/rsyslog.conf: -cron.* /var/log/cron - 1 - 14 - 15 - 16 - 3 - 5 - 6 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - BAI03.05 - DSS05.04 - DSS05.07 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - CCI-000366 - 4.3.2.6.7 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.4.4.7 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.8 - SR 2.9 - SR 6.1 - 0988 - 1405 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.15.2.1 - A.15.2.2 - CM-6(a) - ID.SC-4 - PR.PT-1 - FAU_GEN.1.1.c - SRG-OS-000480-GPOS-00227 - Cron logging can be used to trace the successful or unsuccessful execution -of cron jobs. It can also be used to spot intrusions into the use of the cron -facility by unauthorized and malicious users. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -if ! grep -s "^\s*cron\.\*\s*/var/log/cron$" /etc/rsyslog.conf /etc/rsyslog.d/*.conf; then - mkdir -p /etc/rsyslog.d - echo "cron.* /var/log/cron" >> /etc/rsyslog.d/cron.conf -fi - -systemctl restart rsyslog.service - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - - - - - - - - Ensure Rsyslog Authenticates Off-Loaded Audit Records - Rsyslogd is a system utility providing support for message logging. Support -for both internet and UNIX domain sockets enables this utility to support both local -and remote logging. Couple this utility with gnutls (which is a secure communications -library implementing the SSL, TLS and DTLS protocols), and you have a method to securely -encrypt and off-load auditing. - -When using rsyslogd to off-load logs the remote system must be authenticated. - CCI-001851 - AU-4(1) - SRG-OS-000342-GPOS-00133 - SRG-OS-000479-GPOS-00224 - The audit records generated by Rsyslog contain valuable information regarding system -configuration, user authentication, and other such information. Audit records should be -protected from unauthorized access. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -sed -i '/^.*\$ActionSendStreamDriverAuthMode.*/d' /etc/rsyslog.conf /etc/rsyslog.d/*.conf 2> /dev/null - -if [ -e "/etc/rsyslog.d/stream_driver_auth.conf" ] ; then - - LC_ALL=C sed -i "/^\s*\$ActionSendStreamDriverAuthMode /Id" "/etc/rsyslog.d/stream_driver_auth.conf" -else - touch "/etc/rsyslog.d/stream_driver_auth.conf" -fi -# make sure file has newline at the end -sed -i -e '$a\' "/etc/rsyslog.d/stream_driver_auth.conf" - -cp "/etc/rsyslog.d/stream_driver_auth.conf" "/etc/rsyslog.d/stream_driver_auth.conf.bak" -# Insert at the end of the file -printf '%s\n' "\$ActionSendStreamDriverAuthMode x509/name" >> "/etc/rsyslog.d/stream_driver_auth.conf" -# Clean up after ourselves. -rm "/etc/rsyslog.d/stream_driver_auth.conf.bak" - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Ensure Rsyslog Authenticates Off-Loaded Audit Records - block: - - - name: Deduplicate values from /etc/rsyslog.conf - lineinfile: - path: /etc/rsyslog.conf - create: false - regexp: ^\s*{{ "$ActionSendStreamDriverAuthMode"| regex_escape }}\s - state: absent - - - name: Check if /etc/rsyslog.d exists - stat: - path: /etc/rsyslog.d - register: _etc_rsyslog_d_exists - - - name: Check if the parameter $ActionSendStreamDriverAuthMode is present in /etc/rsyslog.d - find: - paths: /etc/rsyslog.d - recurse: 'yes' - follow: 'no' - contains: ^\s*{{ "$ActionSendStreamDriverAuthMode"| regex_escape }}\s - register: _etc_rsyslog_d_has_parameter - when: _etc_rsyslog_d_exists.stat.isdir is defined and _etc_rsyslog_d_exists.stat.isdir - - - name: Remove parameter from files in /etc/rsyslog.d - lineinfile: - path: '{{ item.path }}' - create: false - regexp: ^\s*{{ "$ActionSendStreamDriverAuthMode"| regex_escape }}\s - state: absent - with_items: '{{ _etc_rsyslog_d_has_parameter.files }}' - when: _etc_rsyslog_d_has_parameter.matched - - - name: Insert correct line to /etc/rsyslog.conf - lineinfile: - path: /etc/rsyslog.conf - create: true - regexp: ^\s*{{ "$ActionSendStreamDriverAuthMode"| regex_escape }}\s - line: $ActionSendStreamDriverAuthMode x509/name - state: present - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AU-4(1) - - configure_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - rsyslog_encrypt_offload_actionsendstreamdriverauthmode - - - - - - - - - - Ensure Rsyslog Encrypts Off-Loaded Audit Records - Rsyslogd is a system utility providing support for message logging. Support -for both internet and UNIX domain sockets enables this utility to support both local -and remote logging. Couple this utility with gnutls (which is a secure communications -library implementing the SSL, TLS and DTLS protocols), and you have a method to securely -encrypt and off-load auditing. - -When using rsyslogd to off-load logs off a encrpytion system must be used. - CCI-001851 - AU-4(1) - SRG-OS-000342-GPOS-00133 - SRG-OS-000479-GPOS-00224 - The audit records generated by Rsyslog contain valuable information regarding system -configuration, user authentication, and other such information. Audit records should be -protected from unauthorized access. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -if [ -e "/etc/rsyslog.d/encrypt.conf" ] ; then - - LC_ALL=C sed -i "/^\s*\$ActionSendStreamDriverMode /Id" "/etc/rsyslog.d/encrypt.conf" -else - touch "/etc/rsyslog.d/encrypt.conf" -fi -# make sure file has newline at the end -sed -i -e '$a\' "/etc/rsyslog.d/encrypt.conf" - -cp "/etc/rsyslog.d/encrypt.conf" "/etc/rsyslog.d/encrypt.conf.bak" -# Insert at the end of the file -printf '%s\n' "\$ActionSendStreamDriverMode 1" >> "/etc/rsyslog.d/encrypt.conf" -# Clean up after ourselves. -rm "/etc/rsyslog.d/encrypt.conf.bak" - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Ensure Rsyslog Encrypts Off-Loaded Audit Records - block: - - - name: Deduplicate values from /etc/rsyslog.conf - lineinfile: - path: /etc/rsyslog.conf - create: false - regexp: '^\s*{{ "$ActionSendStreamDriverMode"| regex_escape }} ' - state: absent - - - name: Check if /etc/rsyslog.d exists - stat: - path: /etc/rsyslog.d - register: _etc_rsyslog_d_exists - - - name: Check if the parameter $ActionSendStreamDriverMode is present in /etc/rsyslog.d - find: - paths: /etc/rsyslog.d - recurse: 'yes' - follow: 'no' - contains: '^\s*{{ "$ActionSendStreamDriverMode"| regex_escape }} ' - register: _etc_rsyslog_d_has_parameter - when: _etc_rsyslog_d_exists.stat.isdir is defined and _etc_rsyslog_d_exists.stat.isdir - - - name: Remove parameter from files in /etc/rsyslog.d - lineinfile: - path: '{{ item.path }}' - create: false - regexp: '^\s*{{ "$ActionSendStreamDriverMode"| regex_escape }} ' - state: absent - with_items: '{{ _etc_rsyslog_d_has_parameter.files }}' - when: _etc_rsyslog_d_has_parameter.matched - - - name: Insert correct line to /etc/rsyslog.conf - lineinfile: - path: /etc/rsyslog.conf - create: true - regexp: '^\s*{{ "$ActionSendStreamDriverMode"| regex_escape }} ' - line: $ActionSendStreamDriverMode 1 - state: present - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AU-4(1) - - configure_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - rsyslog_encrypt_offload_actionsendstreamdrivermode - - - - - - - - - - Ensure Rsyslog Encrypts Off-Loaded Audit Records - Rsyslogd is a system utility providing support for message logging. Support -for both internet and UNIX domain sockets enables this utility to support both local -and remote logging. Couple this utility with gnutls (which is a secure communications -library implementing the SSL, TLS and DTLS protocols), and you have a method to securely -encrypt and off-load auditing. - -When using rsyslogd to off-load logs off an encryption system must be used. - CCI-001851 - AU-4(1) - SRG-OS-000342-GPOS-00133 - SRG-OS-000479-GPOS-00224 - The audit records generated by Rsyslog contain valuable information regarding system -configuration, user authentication, and other such information. Audit records should be -protected from unauthorized access. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -if [ -e "/etc/rsyslog.d/encrypt.conf" ] ; then - - LC_ALL=C sed -i "/^\s*\$DefaultNetstreamDriver /Id" "/etc/rsyslog.d/encrypt.conf" -else - touch "/etc/rsyslog.d/encrypt.conf" -fi -# make sure file has newline at the end -sed -i -e '$a\' "/etc/rsyslog.d/encrypt.conf" - -cp "/etc/rsyslog.d/encrypt.conf" "/etc/rsyslog.d/encrypt.conf.bak" -# Insert at the end of the file -printf '%s\n' "\$DefaultNetstreamDriver gtls" >> "/etc/rsyslog.d/encrypt.conf" -# Clean up after ourselves. -rm "/etc/rsyslog.d/encrypt.conf.bak" - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Ensure Rsyslog Encrypts Off-Loaded Audit Records - block: - - - name: Deduplicate values from /etc/rsyslog.conf - lineinfile: - path: /etc/rsyslog.conf - create: false - regexp: '^\s*{{ "$DefaultNetstreamDriver"| regex_escape }} ' - state: absent - - - name: Check if /etc/rsyslog.d exists - stat: - path: /etc/rsyslog.d - register: _etc_rsyslog_d_exists - - - name: Check if the parameter $DefaultNetstreamDriver is present in /etc/rsyslog.d - find: - paths: /etc/rsyslog.d - recurse: 'yes' - follow: 'no' - contains: '^\s*{{ "$DefaultNetstreamDriver"| regex_escape }} ' - register: _etc_rsyslog_d_has_parameter - when: _etc_rsyslog_d_exists.stat.isdir is defined and _etc_rsyslog_d_exists.stat.isdir - - - name: Remove parameter from files in /etc/rsyslog.d - lineinfile: - path: '{{ item.path }}' - create: false - regexp: '^\s*{{ "$DefaultNetstreamDriver"| regex_escape }} ' - state: absent - with_items: '{{ _etc_rsyslog_d_has_parameter.files }}' - when: _etc_rsyslog_d_has_parameter.matched - - - name: Insert correct line to /etc/rsyslog.conf - lineinfile: - path: /etc/rsyslog.conf - create: true - regexp: '^\s*{{ "$DefaultNetstreamDriver"| regex_escape }} ' - line: $DefaultNetstreamDriver gtls - state: present - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AU-4(1) - - configure_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - rsyslog_encrypt_offload_defaultnetstreamdriver - - - - - - - - - - Ensure Log Files Are Owned By Appropriate Group - The group-owner of all log files written by -rsyslog should be - -root. - -These log files are determined by the second part of each Rule line in -/etc/rsyslog.conf and typically all appear in /var/log. -For each log file LOGFILE referenced in /etc/rsyslog.conf, -run the following command to inspect the file's group owner: -$ ls -l LOGFILE -If the owner is not - -root, - -run the following command to -correct this: - -$ sudo chgrp root LOGFILE - BP28(R46) - BP28(R5) - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - APO01.06 - DSS05.04 - DSS05.07 - DSS06.02 - CCI-001314 - 4.3.3.7.3 - SR 2.1 - SR 5.2 - 0988 - 1405 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 - CM-6(a) - AC-6(1) - PR.AC-4 - PR.DS-5 - Req-10.5.1 - Req-10.5.2 - 10.3.1 - 10.3.2 - The log files generated by rsyslog contain valuable information regarding system -configuration, user authentication, and other such information. Log files should be -protected from unauthorized access. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# List of log file paths to be inspected for correct permissions -# * Primarily inspect log file paths listed in /etc/rsyslog.conf -RSYSLOG_ETC_CONFIG="/etc/rsyslog.conf" -# * And also the log file paths listed after rsyslog's $IncludeConfig directive -# (store the result into array for the case there's shell glob used as value of IncludeConfig) -readarray -t OLD_INC < <(grep -e "\$IncludeConfig[[:space:]]\+[^[:space:];]\+" /etc/rsyslog.conf | cut -d ' ' -f 2) -readarray -t RSYSLOG_INCLUDE_CONFIG < <(for INCPATH in "${OLD_INC[@]}"; do eval printf '%s\\n' "${INCPATH}"; done) -readarray -t NEW_INC < <(awk '/)/{f=0} /include\(/{f=1} f{nf=gensub("^(include\\(|\\s*)file=\"(\\S+)\".*","\\2",1); if($0!=nf){print nf}}' /etc/rsyslog.conf) -readarray -t RSYSLOG_INCLUDE < <(for INCPATH in "${NEW_INC[@]}"; do eval printf '%s\\n' "${INCPATH}"; done) - -# Declare an array to hold the final list of different log file paths -declare -a LOG_FILE_PATHS - -# Array to hold all rsyslog config entries -RSYSLOG_CONFIGS=() -RSYSLOG_CONFIGS=("${RSYSLOG_ETC_CONFIG}" "${RSYSLOG_INCLUDE_CONFIG[@]}" "${RSYSLOG_INCLUDE[@]}") - -# Get full list of files to be checked -# RSYSLOG_CONFIGS may contain globs such as -# /etc/rsyslog.d/*.conf /etc/rsyslog.d/*.frule -# So, loop over the entries in RSYSLOG_CONFIGS and use find to get the list of included files. -RSYSLOG_CONFIG_FILES=() -for ENTRY in "${RSYSLOG_CONFIGS[@]}" -do - # If directory, rsyslog will search for config files in recursively. - # However, files in hidden sub-directories or hidden files will be ignored. - if [ -d "${ENTRY}" ] - then - readarray -t FINDOUT < <(find "${ENTRY}" -not -path '*/.*' -type f) - RSYSLOG_CONFIG_FILES+=("${FINDOUT[@]}") - elif [ -f "${ENTRY}" ] - then - RSYSLOG_CONFIG_FILES+=("${ENTRY}") - else - echo "Invalid include object: ${ENTRY}" - fi -done - -# Browse each file selected above as containing paths of log files -# ('/etc/rsyslog.conf' and '/etc/rsyslog.d/*.conf' in the default configuration) -for LOG_FILE in "${RSYSLOG_CONFIG_FILES[@]}" -do - # From each of these files extract just particular log file path(s), thus: - # * Ignore lines starting with space (' '), comment ('#"), or variable syntax ('$') characters, - # * Ignore empty lines, - # * Strip quotes and closing brackets from paths. - # * Ignore paths that match /dev|/etc.*\.conf, as those are paths, but likely not log files - # * From the remaining valid rows select only fields constituting a log file path - # Text file column is understood to represent a log file path if and only if all of the - # following are met: - # * it contains at least one slash '/' character, - # * it is preceded by space - # * it doesn't contain space (' '), colon (':'), and semicolon (';') characters - # Search log file for path(s) only in case it exists! - if [[ -f "${LOG_FILE}" ]] - then - NORMALIZED_CONFIG_FILE_LINES=$(sed -e "/^[#|$]/d" "${LOG_FILE}") - LINES_WITH_PATHS=$(grep '[^/]*\s\+\S*/\S\+$' <<< "${NORMALIZED_CONFIG_FILE_LINES}") - FILTERED_PATHS=$(awk '{if(NF>=2&&($NF~/^\//||$NF~/^-\//)){sub(/^-\//,"/",$NF);print $NF}}' <<< "${LINES_WITH_PATHS}") - CLEANED_PATHS=$(sed -e "s/[\"')]//g; /\\/etc.*\.conf/d; /\\/dev\\//d" <<< "${FILTERED_PATHS}") - MATCHED_ITEMS=$(sed -e "/^$/d" <<< "${CLEANED_PATHS}") - # Since above sed command might return more than one item (delimited by newline), split - # the particular matches entries into new array specific for this log file - readarray -t ARRAY_FOR_LOG_FILE <<< "$MATCHED_ITEMS" - # Concatenate the two arrays - previous content of $LOG_FILE_PATHS array with - # items from newly created array for this log file - LOG_FILE_PATHS+=("${ARRAY_FOR_LOG_FILE[@]}") - # Delete the temporary array - unset ARRAY_FOR_LOG_FILE - fi -done - -# Check for RainerScript action log format which might be also multiline so grep regex is a bit -# curly: -# extract possibly multiline action omfile expressions -# extract File="logfile" expression -# match only "logfile" expression -for LOG_FILE in "${RSYSLOG_CONFIG_FILES[@]}" -do - ACTION_OMFILE_LINES=$(grep -ozP "action\s*\(\s*type\s*=\s*\"omfile\"[^\)]*\)" "${LOG_FILE}") - OMFILE_LINES=$(echo "${ACTION_OMFILE_LINES}"| grep -aoP "File\s*=\s*\"([/[:alnum:][:punct:]]*)\"\s*\)") - LOG_FILE_PATHS+=("$(echo "${OMFILE_LINES}"| grep -oE "\"([/[:alnum:][:punct:]]*)\""|tr -d "\"")") -done - -# Ensure the correct attribute if file exists -FILE_CMD="chgrp" -for LOG_FILE_PATH in "${LOG_FILE_PATHS[@]}" -do - # Sanity check - if particular $LOG_FILE_PATH is empty string, skip it from further processing - if [ -z "$LOG_FILE_PATH" ] - then - continue - fi - $FILE_CMD "0" "$LOG_FILE_PATH" -done - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Ensure Log Files Are Owned By Appropriate Group - Set rsyslog logfile configuration - facts - ansible.builtin.set_fact: - rsyslog_etc_config: /etc/rsyslog.conf - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.5.1 - - PCI-DSS-Req-10.5.2 - - PCI-DSSv4-10.3.1 - - PCI-DSSv4-10.3.2 - - configure_strategy - - low_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - - rsyslog_files_groupownership - -- name: Ensure Log Files Are Owned By Appropriate Group - Get IncludeConfig directive - ansible.builtin.shell: | - set -o pipefail - grep -e '$IncludeConfig' {{ rsyslog_etc_config }} | cut -d ' ' -f 2 || true - register: rsyslog_old_inc - changed_when: false - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.5.1 - - PCI-DSS-Req-10.5.2 - - PCI-DSSv4-10.3.1 - - PCI-DSSv4-10.3.2 - - configure_strategy - - low_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - - rsyslog_files_groupownership - -- name: Ensure Log Files Are Owned By Appropriate Group - Get include files directives - ansible.builtin.shell: | - set -o pipefail - awk '/)/{f=0} /include\(/{f=1} f{nf=gensub("^(include\\(|\\s*)file=\"(\\S+)\".*","\\2",1); if($0!=nf){print nf}}' {{ rsyslog_etc_config }} || true - register: rsyslog_new_inc - changed_when: false - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.5.1 - - PCI-DSS-Req-10.5.2 - - PCI-DSSv4-10.3.1 - - PCI-DSSv4-10.3.2 - - configure_strategy - - low_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - - rsyslog_files_groupownership - -- name: Ensure Log Files Are Owned By Appropriate Group - Aggregate rsyslog includes - ansible.builtin.set_fact: - include_config_output: '{{ rsyslog_old_inc.stdout_lines + rsyslog_new_inc.stdout_lines - }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.5.1 - - PCI-DSS-Req-10.5.2 - - PCI-DSSv4-10.3.1 - - PCI-DSSv4-10.3.2 - - configure_strategy - - low_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - - rsyslog_files_groupownership - -- name: Ensure Log Files Are Owned By Appropriate Group - List all config files - ansible.builtin.find: - paths: '{{ item | dirname }}' - patterns: '{{ item | basename }}' - hidden: false - follow: true - loop: '{{ include_config_output | list + [rsyslog_etc_config] }}' - register: rsyslog_config_files - failed_when: false - changed_when: false - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.5.1 - - PCI-DSS-Req-10.5.2 - - PCI-DSSv4-10.3.1 - - PCI-DSSv4-10.3.2 - - configure_strategy - - low_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - - rsyslog_files_groupownership - -- name: Ensure Log Files Are Owned By Appropriate Group - Extract log files old format - ansible.builtin.shell: | - set -o pipefail - grep -oP '^[^(\s|#|\$)]+[\s]+.*[\s]+-?(/+[^:;\s]+);*\.*$' {{ item.1.path }} | \ - awk '{print $NF}' | \ - sed -e 's/^-//' || true - loop: '{{ rsyslog_config_files.results | subelements(''files'') }}' - register: log_files_old - changed_when: false - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.5.1 - - PCI-DSS-Req-10.5.2 - - PCI-DSSv4-10.3.1 - - PCI-DSSv4-10.3.2 - - configure_strategy - - low_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - - rsyslog_files_groupownership - -- name: Ensure Log Files Are Owned By Appropriate Group - Extract log files new format - ansible.builtin.shell: | - set -o pipefail - grep -ozP "action\s*\(\s*type\s*=\s*\"omfile\"[^\)]*\)" {{ item.1.path }} | \ - grep -aoP "File\s*=\s*\"([/[:alnum:][:punct:]]*)\"\s*\)" | \ - grep -oE "\"([/[:alnum:][:punct:]]*)\"" | \ - tr -d "\""|| true - loop: '{{ rsyslog_config_files.results | subelements(''files'') }}' - register: log_files_new - changed_when: false - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.5.1 - - PCI-DSS-Req-10.5.2 - - PCI-DSSv4-10.3.1 - - PCI-DSSv4-10.3.2 - - configure_strategy - - low_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - - rsyslog_files_groupownership - -- name: Ensure Log Files Are Owned By Appropriate Group - Sum all log files found - ansible.builtin.set_fact: - log_files: '{{ log_files_new.results | map(attribute=''stdout_lines'') | list - | flatten | unique + log_files_old.results | map(attribute=''stdout_lines'') - | list | flatten | unique }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.5.1 - - PCI-DSS-Req-10.5.2 - - PCI-DSSv4-10.3.1 - - PCI-DSSv4-10.3.2 - - configure_strategy - - low_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - - rsyslog_files_groupownership - -- name: Ensure Log Files Are Owned By Appropriate Group -Setup log files attribute - ansible.builtin.file: - path: '{{ item }}' - group: '0' - state: file - loop: '{{ log_files | list | flatten | unique }}' - failed_when: false - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.5.1 - - PCI-DSS-Req-10.5.2 - - PCI-DSSv4-10.3.1 - - PCI-DSSv4-10.3.2 - - configure_strategy - - low_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - - rsyslog_files_groupownership - - - - - - - - - - Ensure Log Files Are Owned By Appropriate User - The owner of all log files written by -rsyslog should be - -root. - -These log files are determined by the second part of each Rule line in -/etc/rsyslog.conf and typically all appear in /var/log. -For each log file LOGFILE referenced in /etc/rsyslog.conf, -run the following command to inspect the file's owner: -$ ls -l LOGFILE -If the owner is not - -root, - -run the following command to -correct this: - -$ sudo chown root LOGFILE - BP28(R46) - BP28(R5) - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - APO01.06 - DSS05.04 - DSS05.07 - DSS06.02 - CCI-001314 - 4.3.3.7.3 - SR 2.1 - SR 5.2 - 0988 - 1405 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 - CM-6(a) - AC-6(1) - PR.AC-4 - PR.DS-5 - Req-10.5.1 - Req-10.5.2 - 10.3.1 - 10.3.2 - The log files generated by rsyslog contain valuable information regarding system -configuration, user authentication, and other such information. Log files should be -protected from unauthorized access. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# List of log file paths to be inspected for correct permissions -# * Primarily inspect log file paths listed in /etc/rsyslog.conf -RSYSLOG_ETC_CONFIG="/etc/rsyslog.conf" -# * And also the log file paths listed after rsyslog's $IncludeConfig directive -# (store the result into array for the case there's shell glob used as value of IncludeConfig) -readarray -t OLD_INC < <(grep -e "\$IncludeConfig[[:space:]]\+[^[:space:];]\+" /etc/rsyslog.conf | cut -d ' ' -f 2) -readarray -t RSYSLOG_INCLUDE_CONFIG < <(for INCPATH in "${OLD_INC[@]}"; do eval printf '%s\\n' "${INCPATH}"; done) -readarray -t NEW_INC < <(awk '/)/{f=0} /include\(/{f=1} f{nf=gensub("^(include\\(|\\s*)file=\"(\\S+)\".*","\\2",1); if($0!=nf){print nf}}' /etc/rsyslog.conf) -readarray -t RSYSLOG_INCLUDE < <(for INCPATH in "${NEW_INC[@]}"; do eval printf '%s\\n' "${INCPATH}"; done) - -# Declare an array to hold the final list of different log file paths -declare -a LOG_FILE_PATHS - -# Array to hold all rsyslog config entries -RSYSLOG_CONFIGS=() -RSYSLOG_CONFIGS=("${RSYSLOG_ETC_CONFIG}" "${RSYSLOG_INCLUDE_CONFIG[@]}" "${RSYSLOG_INCLUDE[@]}") - -# Get full list of files to be checked -# RSYSLOG_CONFIGS may contain globs such as -# /etc/rsyslog.d/*.conf /etc/rsyslog.d/*.frule -# So, loop over the entries in RSYSLOG_CONFIGS and use find to get the list of included files. -RSYSLOG_CONFIG_FILES=() -for ENTRY in "${RSYSLOG_CONFIGS[@]}" -do - # If directory, rsyslog will search for config files in recursively. - # However, files in hidden sub-directories or hidden files will be ignored. - if [ -d "${ENTRY}" ] - then - readarray -t FINDOUT < <(find "${ENTRY}" -not -path '*/.*' -type f) - RSYSLOG_CONFIG_FILES+=("${FINDOUT[@]}") - elif [ -f "${ENTRY}" ] - then - RSYSLOG_CONFIG_FILES+=("${ENTRY}") - else - echo "Invalid include object: ${ENTRY}" - fi -done - -# Browse each file selected above as containing paths of log files -# ('/etc/rsyslog.conf' and '/etc/rsyslog.d/*.conf' in the default configuration) -for LOG_FILE in "${RSYSLOG_CONFIG_FILES[@]}" -do - # From each of these files extract just particular log file path(s), thus: - # * Ignore lines starting with space (' '), comment ('#"), or variable syntax ('$') characters, - # * Ignore empty lines, - # * Strip quotes and closing brackets from paths. - # * Ignore paths that match /dev|/etc.*\.conf, as those are paths, but likely not log files - # * From the remaining valid rows select only fields constituting a log file path - # Text file column is understood to represent a log file path if and only if all of the - # following are met: - # * it contains at least one slash '/' character, - # * it is preceded by space - # * it doesn't contain space (' '), colon (':'), and semicolon (';') characters - # Search log file for path(s) only in case it exists! - if [[ -f "${LOG_FILE}" ]] - then - NORMALIZED_CONFIG_FILE_LINES=$(sed -e "/^[#|$]/d" "${LOG_FILE}") - LINES_WITH_PATHS=$(grep '[^/]*\s\+\S*/\S\+$' <<< "${NORMALIZED_CONFIG_FILE_LINES}") - FILTERED_PATHS=$(awk '{if(NF>=2&&($NF~/^\//||$NF~/^-\//)){sub(/^-\//,"/",$NF);print $NF}}' <<< "${LINES_WITH_PATHS}") - CLEANED_PATHS=$(sed -e "s/[\"')]//g; /\\/etc.*\.conf/d; /\\/dev\\//d" <<< "${FILTERED_PATHS}") - MATCHED_ITEMS=$(sed -e "/^$/d" <<< "${CLEANED_PATHS}") - # Since above sed command might return more than one item (delimited by newline), split - # the particular matches entries into new array specific for this log file - readarray -t ARRAY_FOR_LOG_FILE <<< "$MATCHED_ITEMS" - # Concatenate the two arrays - previous content of $LOG_FILE_PATHS array with - # items from newly created array for this log file - LOG_FILE_PATHS+=("${ARRAY_FOR_LOG_FILE[@]}") - # Delete the temporary array - unset ARRAY_FOR_LOG_FILE - fi -done - -# Check for RainerScript action log format which might be also multiline so grep regex is a bit -# curly: -# extract possibly multiline action omfile expressions -# extract File="logfile" expression -# match only "logfile" expression -for LOG_FILE in "${RSYSLOG_CONFIG_FILES[@]}" -do - ACTION_OMFILE_LINES=$(grep -ozP "action\s*\(\s*type\s*=\s*\"omfile\"[^\)]*\)" "${LOG_FILE}") - OMFILE_LINES=$(echo "${ACTION_OMFILE_LINES}"| grep -aoP "File\s*=\s*\"([/[:alnum:][:punct:]]*)\"\s*\)") - LOG_FILE_PATHS+=("$(echo "${OMFILE_LINES}"| grep -oE "\"([/[:alnum:][:punct:]]*)\""|tr -d "\"")") -done - -# Ensure the correct attribute if file exists -FILE_CMD="chown" -for LOG_FILE_PATH in "${LOG_FILE_PATHS[@]}" -do - # Sanity check - if particular $LOG_FILE_PATH is empty string, skip it from further processing - if [ -z "$LOG_FILE_PATH" ] - then - continue - fi - $FILE_CMD "0" "$LOG_FILE_PATH" -done - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Ensure Log Files Are Owned By Appropriate User - Set rsyslog logfile configuration - facts - ansible.builtin.set_fact: - rsyslog_etc_config: /etc/rsyslog.conf - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.5.1 - - PCI-DSS-Req-10.5.2 - - PCI-DSSv4-10.3.1 - - PCI-DSSv4-10.3.2 - - configure_strategy - - low_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - - rsyslog_files_ownership - -- name: Ensure Log Files Are Owned By Appropriate User - Get IncludeConfig directive - ansible.builtin.shell: | - set -o pipefail - grep -e '$IncludeConfig' {{ rsyslog_etc_config }} | cut -d ' ' -f 2 || true - register: rsyslog_old_inc - changed_when: false - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.5.1 - - PCI-DSS-Req-10.5.2 - - PCI-DSSv4-10.3.1 - - PCI-DSSv4-10.3.2 - - configure_strategy - - low_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - - rsyslog_files_ownership - -- name: Ensure Log Files Are Owned By Appropriate User - Get include files directives - ansible.builtin.shell: | - set -o pipefail - awk '/)/{f=0} /include\(/{f=1} f{nf=gensub("^(include\\(|\\s*)file=\"(\\S+)\".*","\\2",1); if($0!=nf){print nf}}' {{ rsyslog_etc_config }} || true - register: rsyslog_new_inc - changed_when: false - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.5.1 - - PCI-DSS-Req-10.5.2 - - PCI-DSSv4-10.3.1 - - PCI-DSSv4-10.3.2 - - configure_strategy - - low_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - - rsyslog_files_ownership - -- name: Ensure Log Files Are Owned By Appropriate User - Aggregate rsyslog includes - ansible.builtin.set_fact: - include_config_output: '{{ rsyslog_old_inc.stdout_lines + rsyslog_new_inc.stdout_lines - }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.5.1 - - PCI-DSS-Req-10.5.2 - - PCI-DSSv4-10.3.1 - - PCI-DSSv4-10.3.2 - - configure_strategy - - low_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - - rsyslog_files_ownership - -- name: Ensure Log Files Are Owned By Appropriate User - List all config files - ansible.builtin.find: - paths: '{{ item | dirname }}' - patterns: '{{ item | basename }}' - hidden: false - follow: true - loop: '{{ include_config_output | list + [rsyslog_etc_config] }}' - register: rsyslog_config_files - failed_when: false - changed_when: false - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.5.1 - - PCI-DSS-Req-10.5.2 - - PCI-DSSv4-10.3.1 - - PCI-DSSv4-10.3.2 - - configure_strategy - - low_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - - rsyslog_files_ownership - -- name: Ensure Log Files Are Owned By Appropriate User - Extract log files old format - ansible.builtin.shell: | - set -o pipefail - grep -oP '^[^(\s|#|\$)]+[\s]+.*[\s]+-?(/+[^:;\s]+);*\.*$' {{ item.1.path }} | \ - awk '{print $NF}' | \ - sed -e 's/^-//' || true - loop: '{{ rsyslog_config_files.results | subelements(''files'') }}' - register: log_files_old - changed_when: false - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.5.1 - - PCI-DSS-Req-10.5.2 - - PCI-DSSv4-10.3.1 - - PCI-DSSv4-10.3.2 - - configure_strategy - - low_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - - rsyslog_files_ownership - -- name: Ensure Log Files Are Owned By Appropriate User - Extract log files new format - ansible.builtin.shell: | - set -o pipefail - grep -ozP "action\s*\(\s*type\s*=\s*\"omfile\"[^\)]*\)" {{ item.1.path }} | \ - grep -aoP "File\s*=\s*\"([/[:alnum:][:punct:]]*)\"\s*\)" | \ - grep -oE "\"([/[:alnum:][:punct:]]*)\"" | \ - tr -d "\""|| true - loop: '{{ rsyslog_config_files.results | subelements(''files'') }}' - register: log_files_new - changed_when: false - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.5.1 - - PCI-DSS-Req-10.5.2 - - PCI-DSSv4-10.3.1 - - PCI-DSSv4-10.3.2 - - configure_strategy - - low_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - - rsyslog_files_ownership - -- name: Ensure Log Files Are Owned By Appropriate User - Sum all log files found - ansible.builtin.set_fact: - log_files: '{{ log_files_new.results | map(attribute=''stdout_lines'') | list - | flatten | unique + log_files_old.results | map(attribute=''stdout_lines'') - | list | flatten | unique }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.5.1 - - PCI-DSS-Req-10.5.2 - - PCI-DSSv4-10.3.1 - - PCI-DSSv4-10.3.2 - - configure_strategy - - low_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - - rsyslog_files_ownership - -- name: Ensure Log Files Are Owned By Appropriate User -Setup log files attribute - ansible.builtin.file: - path: '{{ item }}' - owner: '0' - state: file - loop: '{{ log_files | list | flatten | unique }}' - failed_when: false - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.5.1 - - PCI-DSS-Req-10.5.2 - - PCI-DSSv4-10.3.1 - - PCI-DSSv4-10.3.2 - - configure_strategy - - low_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - - rsyslog_files_ownership - - - - - - - - - - Ensure System Log Files Have Correct Permissions - The file permissions for all log files written by rsyslog should -be set to 640, or more restrictive. These log files are determined by the -second part of each Rule line in /etc/rsyslog.conf and typically -all appear in /var/log. For each log file LOGFILE -referenced in /etc/rsyslog.conf, run the following command to -inspect the file's permissions: -$ ls -l LOGFILE -If the permissions are not 640 or more restrictive, run the following -command to correct this: -$ sudo chmod 640 LOGFILE" - BP28(R36) - CCI-001314 - 0988 - 1405 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 - CM-6(a) - AC-6(1) - Req-10.5.1 - Req-10.5.2 - 10.3.1 - 10.3.2 - Log files can contain valuable information regarding system -configuration. If the system log files are not protected unauthorized -users could change the logged data, eliminating their forensic value. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# List of log file paths to be inspected for correct permissions -# * Primarily inspect log file paths listed in /etc/rsyslog.conf -RSYSLOG_ETC_CONFIG="/etc/rsyslog.conf" -# * And also the log file paths listed after rsyslog's $IncludeConfig directive -# (store the result into array for the case there's shell glob used as value of IncludeConfig) -readarray -t OLD_INC < <(grep -e "\$IncludeConfig[[:space:]]\+[^[:space:];]\+" /etc/rsyslog.conf | cut -d ' ' -f 2) -readarray -t RSYSLOG_INCLUDE_CONFIG < <(for INCPATH in "${OLD_INC[@]}"; do eval printf '%s\\n' "${INCPATH}"; done) -readarray -t NEW_INC < <(awk '/)/{f=0} /include\(/{f=1} f{nf=gensub("^(include\\(|\\s*)file=\"(\\S+)\".*","\\2",1); if($0!=nf){print nf}}' /etc/rsyslog.conf) -readarray -t RSYSLOG_INCLUDE < <(for INCPATH in "${NEW_INC[@]}"; do eval printf '%s\\n' "${INCPATH}"; done) - -# Declare an array to hold the final list of different log file paths -declare -a LOG_FILE_PATHS - -# Array to hold all rsyslog config entries -RSYSLOG_CONFIGS=() -RSYSLOG_CONFIGS=("${RSYSLOG_ETC_CONFIG}" "${RSYSLOG_INCLUDE_CONFIG[@]}" "${RSYSLOG_INCLUDE[@]}") - -# Get full list of files to be checked -# RSYSLOG_CONFIGS may contain globs such as -# /etc/rsyslog.d/*.conf /etc/rsyslog.d/*.frule -# So, loop over the entries in RSYSLOG_CONFIGS and use find to get the list of included files. -RSYSLOG_CONFIG_FILES=() -for ENTRY in "${RSYSLOG_CONFIGS[@]}" -do - # If directory, rsyslog will search for config files in recursively. - # However, files in hidden sub-directories or hidden files will be ignored. - if [ -d "${ENTRY}" ] - then - readarray -t FINDOUT < <(find "${ENTRY}" -not -path '*/.*' -type f) - RSYSLOG_CONFIG_FILES+=("${FINDOUT[@]}") - elif [ -f "${ENTRY}" ] - then - RSYSLOG_CONFIG_FILES+=("${ENTRY}") - else - echo "Invalid include object: ${ENTRY}" - fi -done - -# Browse each file selected above as containing paths of log files -# ('/etc/rsyslog.conf' and '/etc/rsyslog.d/*.conf' in the default configuration) -for LOG_FILE in "${RSYSLOG_CONFIG_FILES[@]}" -do - # From each of these files extract just particular log file path(s), thus: - # * Ignore lines starting with space (' '), comment ('#"), or variable syntax ('$') characters, - # * Ignore empty lines, - # * Strip quotes and closing brackets from paths. - # * Ignore paths that match /dev|/etc.*\.conf, as those are paths, but likely not log files - # * From the remaining valid rows select only fields constituting a log file path - # Text file column is understood to represent a log file path if and only if all of the - # following are met: - # * it contains at least one slash '/' character, - # * it is preceded by space - # * it doesn't contain space (' '), colon (':'), and semicolon (';') characters - # Search log file for path(s) only in case it exists! - if [[ -f "${LOG_FILE}" ]] - then - NORMALIZED_CONFIG_FILE_LINES=$(sed -e "/^[#|$]/d" "${LOG_FILE}") - LINES_WITH_PATHS=$(grep '[^/]*\s\+\S*/\S\+$' <<< "${NORMALIZED_CONFIG_FILE_LINES}") - FILTERED_PATHS=$(awk '{if(NF>=2&&($NF~/^\//||$NF~/^-\//)){sub(/^-\//,"/",$NF);print $NF}}' <<< "${LINES_WITH_PATHS}") - CLEANED_PATHS=$(sed -e "s/[\"')]//g; /\\/etc.*\.conf/d; /\\/dev\\//d" <<< "${FILTERED_PATHS}") - MATCHED_ITEMS=$(sed -e "/^$/d" <<< "${CLEANED_PATHS}") - # Since above sed command might return more than one item (delimited by newline), split - # the particular matches entries into new array specific for this log file - readarray -t ARRAY_FOR_LOG_FILE <<< "$MATCHED_ITEMS" - # Concatenate the two arrays - previous content of $LOG_FILE_PATHS array with - # items from newly created array for this log file - LOG_FILE_PATHS+=("${ARRAY_FOR_LOG_FILE[@]}") - # Delete the temporary array - unset ARRAY_FOR_LOG_FILE - fi -done - -# Check for RainerScript action log format which might be also multiline so grep regex is a bit -# curly: -# extract possibly multiline action omfile expressions -# extract File="logfile" expression -# match only "logfile" expression -for LOG_FILE in "${RSYSLOG_CONFIG_FILES[@]}" -do - ACTION_OMFILE_LINES=$(grep -ozP "action\s*\(\s*type\s*=\s*\"omfile\"[^\)]*\)" "${LOG_FILE}") - OMFILE_LINES=$(echo "${ACTION_OMFILE_LINES}"| grep -aoP "File\s*=\s*\"([/[:alnum:][:punct:]]*)\"\s*\)") - LOG_FILE_PATHS+=("$(echo "${OMFILE_LINES}"| grep -oE "\"([/[:alnum:][:punct:]]*)\""|tr -d "\"")") -done - -# Ensure the correct attribute if file exists -FILE_CMD="chmod" -for LOG_FILE_PATH in "${LOG_FILE_PATHS[@]}" -do - # Sanity check - if particular $LOG_FILE_PATH is empty string, skip it from further processing - if [ -z "$LOG_FILE_PATH" ] - then - continue - fi - $FILE_CMD "0640" "$LOG_FILE_PATH" -done - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Ensure System Log Files Have Correct Permissions - Set rsyslog logfile configuration - facts - ansible.builtin.set_fact: - rsyslog_etc_config: /etc/rsyslog.conf - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.5.1 - - PCI-DSS-Req-10.5.2 - - PCI-DSSv4-10.3.1 - - PCI-DSSv4-10.3.2 - - configure_strategy - - low_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - - rsyslog_files_permissions - -- name: Ensure System Log Files Have Correct Permissions - Get IncludeConfig directive - ansible.builtin.shell: | - set -o pipefail - grep -e '$IncludeConfig' {{ rsyslog_etc_config }} | cut -d ' ' -f 2 || true - register: rsyslog_old_inc - changed_when: false - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.5.1 - - PCI-DSS-Req-10.5.2 - - PCI-DSSv4-10.3.1 - - PCI-DSSv4-10.3.2 - - configure_strategy - - low_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - - rsyslog_files_permissions - -- name: Ensure System Log Files Have Correct Permissions - Get include files directives - ansible.builtin.shell: | - set -o pipefail - awk '/)/{f=0} /include\(/{f=1} f{nf=gensub("^(include\\(|\\s*)file=\"(\\S+)\".*","\\2",1); if($0!=nf){print nf}}' {{ rsyslog_etc_config }} || true - register: rsyslog_new_inc - changed_when: false - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.5.1 - - PCI-DSS-Req-10.5.2 - - PCI-DSSv4-10.3.1 - - PCI-DSSv4-10.3.2 - - configure_strategy - - low_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - - rsyslog_files_permissions - -- name: Ensure System Log Files Have Correct Permissions - Aggregate rsyslog includes - ansible.builtin.set_fact: - include_config_output: '{{ rsyslog_old_inc.stdout_lines + rsyslog_new_inc.stdout_lines - }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.5.1 - - PCI-DSS-Req-10.5.2 - - PCI-DSSv4-10.3.1 - - PCI-DSSv4-10.3.2 - - configure_strategy - - low_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - - rsyslog_files_permissions - -- name: Ensure System Log Files Have Correct Permissions - List all config files - ansible.builtin.find: - paths: '{{ item | dirname }}' - patterns: '{{ item | basename }}' - hidden: false - follow: true - loop: '{{ include_config_output | list + [rsyslog_etc_config] }}' - register: rsyslog_config_files - failed_when: false - changed_when: false - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.5.1 - - PCI-DSS-Req-10.5.2 - - PCI-DSSv4-10.3.1 - - PCI-DSSv4-10.3.2 - - configure_strategy - - low_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - - rsyslog_files_permissions - -- name: Ensure System Log Files Have Correct Permissions - Extract log files old format - ansible.builtin.shell: | - set -o pipefail - grep -oP '^[^(\s|#|\$)]+[\s]+.*[\s]+-?(/+[^:;\s]+);*\.*$' {{ item.1.path }} | \ - awk '{print $NF}' | \ - sed -e 's/^-//' || true - loop: '{{ rsyslog_config_files.results | subelements(''files'') }}' - register: log_files_old - changed_when: false - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.5.1 - - PCI-DSS-Req-10.5.2 - - PCI-DSSv4-10.3.1 - - PCI-DSSv4-10.3.2 - - configure_strategy - - low_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - - rsyslog_files_permissions - -- name: Ensure System Log Files Have Correct Permissions - Extract log files new format - ansible.builtin.shell: | - set -o pipefail - grep -ozP "action\s*\(\s*type\s*=\s*\"omfile\"[^\)]*\)" {{ item.1.path }} | \ - grep -aoP "File\s*=\s*\"([/[:alnum:][:punct:]]*)\"\s*\)" | \ - grep -oE "\"([/[:alnum:][:punct:]]*)\"" | \ - tr -d "\""|| true - loop: '{{ rsyslog_config_files.results | subelements(''files'') }}' - register: log_files_new - changed_when: false - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.5.1 - - PCI-DSS-Req-10.5.2 - - PCI-DSSv4-10.3.1 - - PCI-DSSv4-10.3.2 - - configure_strategy - - low_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - - rsyslog_files_permissions - -- name: Ensure System Log Files Have Correct Permissions - Sum all log files found - ansible.builtin.set_fact: - log_files: '{{ log_files_new.results | map(attribute=''stdout_lines'') | list - | flatten | unique + log_files_old.results | map(attribute=''stdout_lines'') - | list | flatten | unique }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.5.1 - - PCI-DSS-Req-10.5.2 - - PCI-DSSv4-10.3.1 - - PCI-DSSv4-10.3.2 - - configure_strategy - - low_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - - rsyslog_files_permissions - -- name: Ensure System Log Files Have Correct Permissions -Setup log files attribute - ansible.builtin.file: - path: '{{ item }}' - mode: '0640' - state: file - loop: '{{ log_files | list | flatten | unique }}' - failed_when: false - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.5.1 - - PCI-DSS-Req-10.5.2 - - PCI-DSSv4-10.3.1 - - PCI-DSSv4-10.3.2 - - configure_strategy - - low_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - - rsyslog_files_permissions - - - - - - - - - - Ensure remote access methods are monitored in Rsyslog - Logging of remote access methods must be implemented to help identify cyber -attacks and ensure ongoing compliance with remote access policies are being -audited and upheld. An examples of a remote access method is the use of the -Remote Desktop Protocol (RDP) from an external, non-organization controlled -network. The /etc/rsyslog.conf or -/etc/rsyslog.d/*.conf file should contain a match for the following -selectors: auth.*, authpriv.*, and daemon.*. If -not, use the following as an example configuration: -auth.*;authpriv.*;daemon.* /var/log/secure - CCI-000067 - AC-17(1) - SRG-OS-000032-GPOS-00013 - Logging remote access methods can be used to trace the decrease the risks -associated with remote user access management. It can also be used to spot -cyber attacks and ensure ongoing compliance with organizational policies -surrounding the use of remote access methods. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -declare -A REMOTE_METHODS=( ['auth.*']='^[^#]*auth\.\*.*$' ['authpriv.*']='^[^#]*authpriv\.\*.*$' ['daemon.*']='^[^#]*daemon\.\*.*$' ) - -if [[ ! -f /etc/rsyslog.conf ]]; then - # Something is not right, create the file - touch /etc/rsyslog.conf -fi - -APPEND_LINE=$(sed -rn '/^\S+\s+\/var\/log\/secure$/p' /etc/rsyslog.conf) - -# Loop through the remote methods associative array -for K in "${!REMOTE_METHODS[@]}" -do - # Check to see if selector/value exists - if ! grep -rq "${REMOTE_METHODS[$K]}" /etc/rsyslog.*; then - # Make sure we have a line to insert after, otherwise append to end - if [[ ! -z ${APPEND_LINE} ]]; then - # Add selector to file - sed -r -i "0,/^(\S+\s+\/var\/log\/secure$)/s//\1\n${K} \/var\/log\/secure/" /etc/rsyslog.conf - else - echo "${K} /var/log/secure" >> /etc/rsyslog.conf - fi - fi -done - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: 'Ensure remote access methods are monitored in Rsyslog: Set facts' - set_fact: - conf_files: - - /etc/rsyslog.conf - remote_methods: - - selector: auth.* - regexp: ^.*auth\.\*.*$ - - selector: authpriv.* - regexp: ^.*authpriv\.\*.*$ - - selector: daemon.* - regexp: ^.*daemon\.\*.*$ - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-17(1) - - configure_strategy - - low_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - - rsyslog_remote_access_monitoring - -- name: 'Ensure remote access methods are monitored in Rsyslog: Ensure rsyslog.conf - exists' - file: - path: '{{ conf_files.0 }}' - state: touch - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-17(1) - - configure_strategy - - low_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - - rsyslog_remote_access_monitoring - -- name: 'Ensure remote access methods are monitored in Rsyslog: Gather conf.d files' - find: - patterns: - - '*.conf' - paths: - - /etc/rsyslog.d - register: rsyslogd - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-17(1) - - configure_strategy - - low_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - - rsyslog_remote_access_monitoring - -- name: 'Ensure remote access methods are monitored in Rsyslog: Set conf file(s)' - set_fact: - conf_files: '{{ conf_files + [item.path] }}' - loop: '{{ rsyslogd.files }}' - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - rsyslogd.matched > 0 - tags: - - NIST-800-53-AC-17(1) - - configure_strategy - - low_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - - rsyslog_remote_access_monitoring - -- name: 'Ensure remote access methods are monitored in Rsyslog: Check for existing - values' - lineinfile: - path: '{{ item.1 }}' - regexp: '{{ item.0.regexp }}' - state: absent - check_mode: true - changed_when: false - register: remote_method_values - loop: '{{ remote_methods|product(conf_files)|list }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-17(1) - - configure_strategy - - low_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - - rsyslog_remote_access_monitoring - -- name: 'Ensure remote access methods are monitored in Rsyslog: Configure' - lineinfile: - path: /etc/rsyslog.conf - line: '{{ item.item.0.selector }} /var/log/secure' - insertafter: ^.*\/var\/log\/secure.*$ - create: true - loop: '{{ remote_method_values.results }}' - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - item.found == 0 - tags: - - NIST-800-53-AC-17(1) - - configure_strategy - - low_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - - rsyslog_remote_access_monitoring - - - - - - - - - - - systemd-journald - systemd-journald is a system service that collects and stores -logging data. It creates and maintains structured, indexed -journals based on logging information that is received from a -variety of sources. - -For more information on systemd-journald and additional systemd-journald configuration options, see -https://systemd.io/. - - Enable systemd-journald Service - The systemd-journald service is an essential component of -systemd. - -The systemd-journald service can be enabled with the following command: -$ sudo systemctl enable systemd-journald.service - CCI-001665 - SC-24 - SRG-OS-000269-GPOS-00103 - In the event of a system failure, Oracle Linux 9 must preserve any information necessary to determine cause of failure and any information necessary to return to operations with least disruption to system processes. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -SYSTEMCTL_EXEC='/usr/bin/systemctl' -"$SYSTEMCTL_EXEC" unmask 'systemd-journald.service' -"$SYSTEMCTL_EXEC" start 'systemd-journald.service' -"$SYSTEMCTL_EXEC" enable 'systemd-journald.service' - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Enable service systemd-journald - block: - - - name: Gather the package facts - package_facts: - manager: auto - - - name: Enable service systemd-journald - systemd: - name: systemd-journald - enabled: 'yes' - state: started - masked: 'no' - when: - - '"systemd" in ansible_facts.packages' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-SC-24 - - enable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_systemd-journald_enabled - - include enable_systemd-journald - -class enable_systemd-journald { - service {'systemd-journald': - enable => true, - ensure => 'running', - } -} - - -[customizations.services] -enabled = ["systemd-journald"] - - - - - - - - - - - Ensure All Logs are Rotated by logrotate - -Edit the file /etc/logrotate.d/syslog. Find the first - -line, which should look like this (wrapped for clarity): -/var/log/messages /var/log/secure /var/log/maillog /var/log/spooler \ - /var/log/boot.log /var/log/cron { -Edit this line so that it contains a one-space-separated -listing of each log file referenced in /etc/rsyslog.conf. - -All logs in use on a system must be rotated regularly, or the -log files will consume disk space over time, eventually interfering -with system operation. The file /etc/logrotate.d/syslog is the -configuration file used by the logrotate program to maintain all -log files written by syslog. By default, it rotates logs weekly and -stores four archival copies of each log. These settings can be -modified by editing /etc/logrotate.conf, but the defaults are -sufficient for purposes of this guide. - -Note that logrotate is run nightly by the cron job -/etc/cron.daily/logrotate. If particularly active logs need to be -rotated more often than once a day, some other mechanism must be -used. - - Ensure logrotate is Installed - logrotate is installed by default. The logrotate package can be installed with the following command: $ sudo yum install logrotate - BP28(R43) - NT12(R18) - 1 - 14 - 15 - 16 - 3 - 5 - 6 - APO11.04 - BAI03.05 - DSS05.04 - DSS05.07 - MEA02.01 - CCI-000366 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.4.4.7 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.8 - SR 2.9 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - CM-6(a) - PR.PT-1 - Req-10.7 - The logrotate package provides the logrotate services. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -if ! rpm -q --quiet "logrotate" ; then - yum install -y "logrotate" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Ensure logrotate is installed - package: - name: logrotate - state: present - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.7 - - enable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - package_logrotate_installed - - include install_logrotate - -class install_logrotate { - package { 'logrotate': - ensure => 'installed', - } -} - - -package --add=logrotate - - -[[packages]] -name = "logrotate" -version = "*" - - - - - - - - - - Ensure Logrotate Runs Periodically - The logrotate utility allows for the automatic rotation of -log files. The frequency of rotation is specified in /etc/logrotate.conf, -which triggers a cron task or a timer. To configure logrotate to run daily, add or correct -the following line in /etc/logrotate.conf: -# rotate log files frequency -daily - BP28(R43) - NT12(R18) - 1 - 14 - 15 - 16 - 3 - 5 - 6 - APO11.04 - BAI03.05 - DSS05.04 - DSS05.07 - MEA02.01 - CCI-000366 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.4.4.7 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.8 - SR 2.9 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - CM-6(a) - PR.PT-1 - Req-10.7 - 10.5.1 - Log files that are not properly rotated run the risk of growing so large -that they fill up the /var/log partition. Valuable logging information could be lost -if the /var/log partition becomes full. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -LOGROTATE_CONF_FILE="/etc/logrotate.conf" - -CRON_DAILY_LOGROTATE_FILE="/etc/cron.daily/logrotate" - - -# daily rotation is configured -grep -q "^daily$" $LOGROTATE_CONF_FILE|| echo "daily" >> $LOGROTATE_CONF_FILE - -# remove any line configuring weekly, monthly or yearly rotation -sed -i '/^\s*\(weekly\|monthly\|yearly\).*$/d' $LOGROTATE_CONF_FILE - - -# configure cron.daily if not already -if ! grep -q "^[[:space:]]*/usr/sbin/logrotate[[:alnum:][:blank:][:punct:]]*$LOGROTATE_CONF_FILE$" $CRON_DAILY_LOGROTATE_FILE; then - echo '#!/bin/sh' > $CRON_DAILY_LOGROTATE_FILE - echo "/usr/sbin/logrotate $LOGROTATE_CONF_FILE" >> $CRON_DAILY_LOGROTATE_FILE -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Configure daily log rotation in /etc/logrotate.conf - lineinfile: - create: true - dest: /etc/logrotate.conf - regexp: ^daily$ - line: daily - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.7 - - PCI-DSSv4-10.5.1 - - configure_strategy - - ensure_logrotate_activated - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Make sure daily log rotation setting is not overriden in /etc/logrotate.conf - lineinfile: - create: false - dest: /etc/logrotate.conf - regexp: ^[\s]*(weekly|monthly|yearly)$ - state: absent - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.7 - - PCI-DSSv4-10.5.1 - - configure_strategy - - ensure_logrotate_activated - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Configure cron.daily if not already - block: - - - name: Add shebang - lineinfile: - path: /etc/cron.daily/logrotate - line: '#!/bin/sh' - insertbefore: BOF - create: true - - - name: Add logrotate call - lineinfile: - path: /etc/cron.daily/logrotate - line: /usr/sbin/logrotate /etc/logrotate.conf - regexp: ^[\s]*/usr/sbin/logrotate[\s\S]*/etc/logrotate.conf$ - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.7 - - PCI-DSSv4-10.5.1 - - configure_strategy - - ensure_logrotate_activated - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Enable logrotate Timer - -The logrotate timer can be enabled with the following command: -$ sudo systemctl enable logrotate.timer - BP28(R43) - NT12(R18) - 1 - 14 - 15 - 16 - 3 - 5 - 6 - APO11.04 - BAI03.05 - DSS05.04 - DSS05.07 - MEA02.01 - CCI-000366 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.4.4.7 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.8 - SR 2.9 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - CM-6(a) - PR.PT-1 - Req-10.7 - Log files that are not properly rotated run the risk of growing so large -that they fill up the /var/log partition. Valuable logging information could be lost -if the /var/log partition becomes full. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -SYSTEMCTL_EXEC='/usr/bin/systemctl' -"$SYSTEMCTL_EXEC" start 'logrotate.timer' -"$SYSTEMCTL_EXEC" enable 'logrotate.timer' - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Enable timer logrotate - block: - - - name: Gather the package facts - package_facts: - manager: auto - - - name: Enable timer logrotate - systemd: - name: logrotate.timer - enabled: 'yes' - state: started - when: - - '"logrotate" in ansible_facts.packages' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.7 - - enable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - timer_logrotate_enabled - - - - - - - - - - - Configure rsyslogd to Accept Remote Messages If Acting as a Log Server - By default, rsyslog does not listen over the network -for log messages. If needed, modules can be enabled to allow -the rsyslog daemon to receive messages from other systems and for the system -thus to act as a log server. -If the system is not a log server, then lines concerning these modules -should remain commented out. - - - Ensure syslog-ng is Installed - syslog-ng can be installed in replacement of rsyslog. -The syslog-ng-core package can be installed with the following command: - -$ sudo yum install syslog-ng-core - BP28(R46) - BP28(R5) - 1 - 14 - 15 - 16 - 3 - 5 - 6 - APO11.04 - BAI03.05 - DSS05.04 - DSS05.07 - MEA02.01 - CCI-001311 - CCI-001312 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.4.4.7 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.8 - SR 2.9 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - CM-6(a) - PR.PT-1 - The syslog-ng-core package provides the syslog-ng daemon, which provides -system logging services. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -if ! rpm -q --quiet "syslog-ng" ; then - yum install -y "syslog-ng" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Ensure syslog-ng is installed - package: - name: syslog-ng - state: present - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-CM-6(a) - - enable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - package_syslogng_installed - - include install_syslog-ng - -class install_syslog-ng { - package { 'syslog-ng': - ensure => 'installed', - } -} - - -package --add=syslog-ng - - -[[packages]] -name = "syslog-ng" -version = "*" - - - - - - - - - - Enable syslog-ng Service - The syslog-ng service (in replacement of rsyslog) provides syslog-style logging by default on Debian. - -The syslog-ng service can be enabled with the following command: -$ sudo systemctl enable syslog-ng.service - BP28(R46) - BP28(R5) - 1 - 12 - 13 - 14 - 15 - 16 - 2 - 3 - 5 - 6 - 7 - 8 - 9 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - APO13.01 - BAI03.05 - BAI04.04 - DSS01.03 - DSS03.05 - DSS05.02 - DSS05.04 - DSS05.05 - DSS05.07 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - CCI-001311 - CCI-001312 - CCI-001557 - CCI-001851 - 4.3.2.6.7 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.4.4.7 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.8 - SR 2.9 - SR 6.1 - SR 6.2 - SR 7.1 - SR 7.2 - A.12.1.3 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.14.2.7 - A.15.2.1 - A.15.2.2 - A.17.2.1 - CM-6(a) - AU-4(1) - DE.CM-1 - DE.CM-3 - DE.CM-7 - ID.SC-4 - PR.DS-4 - PR.PT-1 - The syslog-ng service must be running in order to provide -logging services, which are essential to system administration. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -SYSTEMCTL_EXEC='/usr/bin/systemctl' -"$SYSTEMCTL_EXEC" unmask 'syslog-ng.service' -"$SYSTEMCTL_EXEC" start 'syslog-ng.service' -"$SYSTEMCTL_EXEC" enable 'syslog-ng.service' - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Enable service syslog-ng - block: - - - name: Gather the package facts - package_facts: - manager: auto - - - name: Enable service syslog-ng - systemd: - name: syslog-ng - enabled: 'yes' - state: started - masked: 'no' - when: - - '"syslog-ng" in ansible_facts.packages' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AU-4(1) - - NIST-800-53-CM-6(a) - - enable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_syslogng_enabled - - include enable_syslog-ng - -class enable_syslog-ng { - service {'syslog-ng': - enable => true, - ensure => 'running', - } -} - - -[customizations.services] -enabled = ["syslog-ng"] - - - - - - - - - - Enable rsyslog to Accept Messages via TCP, if Acting As Log Server - The rsyslog daemon should not accept remote messages -unless the system acts as a log server. -If the system needs to act as a central log server, add the following lines to -/etc/rsyslog.conf to enable reception of messages over TCP: -$ModLoad imtcp -$InputTCPServerRun 514 - 1 - 14 - 15 - 16 - 3 - 5 - 6 - APO11.04 - BAI03.05 - DSS05.04 - DSS05.07 - MEA02.01 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.4.4.7 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.8 - SR 2.9 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - CIP-004-6 R2.2.2 - CIP-004-6 R3.3 - CIP-007-3 R.1.3 - CIP-007-3 R5 - CIP-007-3 R5.1.1 - CIP-007-3 R6.5 - CM-6(a) - AU-6(3) - AU-6(4) - PR.PT-1 - If the system needs to act as a log server, this ensures that it can receive -messages over a reliable TCP connection. - - - Enable rsyslog to Accept Messages via UDP, if Acting As Log Server - The rsyslog daemon should not accept remote messages -unless the system acts as a log server. -If the system needs to act as a central log server, add the following lines to -/etc/rsyslog.conf to enable reception of messages over UDP: -$ModLoad imudp -$UDPServerRun 514 - 1 - 14 - 15 - 16 - 3 - 5 - 6 - APO11.04 - BAI03.05 - DSS05.04 - DSS05.07 - MEA02.01 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.4.4.7 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.8 - SR 2.9 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - CIP-004-6 R2.2.2 - CIP-004-6 R3.3 - CIP-007-3 R.1.3 - CIP-007-3 R5 - CIP-007-3 R5.1.1 - CIP-007-3 R6.5 - CM-6(a) - AU-6(3) - AU-6(4) - PR.PT-1 - Many devices, such as switches, routers, and other Unix-like systems, may only support -the traditional syslog transmission over UDP. If the system must act as a log server, -this enables it to receive their messages as well. - - - Ensure rsyslog Does Not Accept Remote Messages Unless Acting As Log Server - The rsyslog daemon should not accept remote messages unless the system acts as a log -server. To ensure that it is not listening on the network, ensure any of the following lines -are not found in rsyslog configuration files. - -If using legacy syntax: -$ModLoad imtcp -$InputTCPServerRun port -$ModLoad imudp -$UDPServerRun port -$ModLoad imrelp -$InputRELPServerRun port - -If using RainerScript syntax: -module(load="imtcp") -module(load="imudp") -input(type="imtcp" port="514") -input(type="imudp" port="514") - - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 4 - 5 - 6 - 8 - 9 - APO01.06 - APO11.04 - APO13.01 - BAI03.05 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS01.05 - DSS03.01 - DSS05.02 - DSS05.04 - DSS05.07 - DSS06.02 - MEA02.01 - CCI-000318 - CCI-000366 - CCI-000368 - CCI-001812 - CCI-001813 - CCI-001814 - 4.2.3.4 - 4.3.3.3.9 - 4.3.3.4 - 4.3.3.5.8 - 4.3.4.3.2 - 4.3.4.3.3 - 4.3.4.4.7 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - 4.4.3.3 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.8 - SR 2.9 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 7.1 - SR 7.6 - 0988 - 1405 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.12.1.1 - A.12.1.2 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.5.1 - A.12.6.2 - A.12.7.1 - A.13.1.1 - A.13.1.2 - A.13.1.3 - A.13.2.1 - A.13.2.2 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CM-7(a) - CM-7(b) - CM-6(a) - DE.AE-1 - ID.AM-3 - PR.AC-5 - PR.DS-5 - PR.IP-1 - PR.PT-1 - PR.PT-4 - SRG-OS-000480-GPOS-00227 - Any process which receives messages from the network incurs some risk of receiving malicious -messages. This risk can be eliminated for rsyslog by configuring it not to listen on the -network. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -legacy_regex='^\s*\$(((Input(TCP|RELP)|UDP)ServerRun)|ModLoad\s+(imtcp|imudp|imrelp))' -rainer_regex='^\s*(module|input)\((load|type)="(imtcp|imudp)".*$' - -readarray -t legacy_targets < <(grep -l -E -r "${legacy_regex[@]}" /etc/rsyslog.conf /etc/rsyslog.d/) -readarray -t rainer_targets < <(grep -l -E -r "${rainer_regex[@]}" /etc/rsyslog.conf /etc/rsyslog.d/) - -config_changed=false -if [ ${#legacy_targets[@]} -gt 0 ]; then - for target in "${legacy_targets[@]}"; do - sed -E -i "/$legacy_regex/ s/^/# /" "$target" - done - config_changed=true -fi - -if [ ${#rainer_targets[@]} -gt 0 ]; then - for target in "${rainer_targets[@]}"; do - sed -E -i "/$rainer_regex/ s/^/# /" "$target" - done - config_changed=true -fi - -if $config_changed; then - systemctl restart rsyslog.service -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Ensure rsyslog Does Not Accept Remote Messages Unless Acting As Log Server - - Define Rsyslog Config Lines Regex in Legacy Syntax - ansible.builtin.set_fact: - rsyslog_listen_legacy_regex: ^\s*\$(((Input(TCP|RELP)|UDP)ServerRun)|ModLoad\s+(imtcp|imudp|imrelp)) - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - configure_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - rsyslog_nolisten - -- name: Ensure rsyslog Does Not Accept Remote Messages Unless Acting As Log Server - - Search for Legacy Config Lines in Rsyslog Main Config File - ansible.builtin.find: - paths: /etc - pattern: rsyslog.conf - contains: '{{ rsyslog_listen_legacy_regex }}' - register: rsyslog_listen_legacy_main_file - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - configure_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - rsyslog_nolisten - -- name: Ensure rsyslog Does Not Accept Remote Messages Unless Acting As Log Server - - Search for Legacy Config Lines in Rsyslog Include Files - ansible.builtin.find: - paths: /etc/rsyslog.d/ - pattern: '*.conf' - contains: '{{ rsyslog_listen_legacy_regex }}' - register: rsyslog_listen_legacy_include_files - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - configure_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - rsyslog_nolisten - -- name: Ensure rsyslog Does Not Accept Remote Messages Unless Acting As Log Server - - Assemble List of Config Files With Listen Lines in Legacy Syntax - ansible.builtin.set_fact: - rsyslog_legacy_remote_listen_files: '{{ rsyslog_listen_legacy_main_file.files - | map(attribute=''path'') | list + rsyslog_listen_legacy_include_files.files - | map(attribute=''path'') | list }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - configure_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - rsyslog_nolisten - -- name: Ensure rsyslog Does Not Accept Remote Messages Unless Acting As Log Server - - Comment Listen Config Lines Wherever Defined Using Legacy Syntax - ansible.builtin.replace: - path: '{{ item }}' - regexp: '{{ rsyslog_listen_legacy_regex }}' - replace: '# \1' - loop: '{{ rsyslog_legacy_remote_listen_files }}' - register: rsyslog_listen_legacy_comment - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - rsyslog_legacy_remote_listen_files | length > 0 - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - configure_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - rsyslog_nolisten - -- name: Ensure rsyslog Does Not Accept Remote Messages Unless Acting As Log Server - - Define Rsyslog Config Lines Regex in RainerScript Syntax - ansible.builtin.set_fact: - rsyslog_listen_rainer_regex: ^\s*(module|input)\((load|type)="(imtcp|imudp)".*$ - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - configure_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - rsyslog_nolisten - -- name: Ensure rsyslog Does Not Accept Remote Messages Unless Acting As Log Server - - Search for RainerScript Config Lines in Rsyslog Main Config File - ansible.builtin.find: - paths: /etc - pattern: rsyslog.conf - contains: '{{ rsyslog_listen_rainer_regex }}' - register: rsyslog_rainer_remote_main_file - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - configure_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - rsyslog_nolisten - -- name: Ensure rsyslog Does Not Accept Remote Messages Unless Acting As Log Server - - Search for RainerScript Config Lines in Rsyslog Include Files - ansible.builtin.find: - paths: /etc/rsyslog.d/ - pattern: '*.conf' - contains: '{{ rsyslog_listen_rainer_regex }}' - register: rsyslog_rainer_remote_include_files - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - configure_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - rsyslog_nolisten - -- name: Ensure rsyslog Does Not Accept Remote Messages Unless Acting As Log Server - - Assemble List of Config Files With Listen Lines in RainerScript - ansible.builtin.set_fact: - rsyslog_rainer_remote_listen_files: '{{ rsyslog_rainer_remote_main_file.files - | map(attribute=''path'') | list + rsyslog_rainer_remote_include_files.files - | map(attribute=''path'') | list }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - configure_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - rsyslog_nolisten - -- name: Ensure rsyslog Does Not Accept Remote Messages Unless Acting As Log Server - - Comment Listen Config Lines Wherever Defined Using RainerScript - ansible.builtin.replace: - path: '{{ item }}' - regexp: '{{ rsyslog_listen_rainer_regex }}' - replace: '# \1' - loop: '{{ rsyslog_rainer_remote_listen_files }}' - register: rsyslog_listen_rainer_comment - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - rsyslog_rainer_remote_listen_files | length > 0 - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - configure_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - rsyslog_nolisten - -- name: Ensure rsyslog Does Not Accept Remote Messages Unless Acting As Log Server - - Restart Rsyslog if Any Line Were Commented Out - ansible.builtin.service: - name: rsyslog - state: restarted - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - rsyslog_listen_legacy_comment is changed or rsyslog_listen_rainer_comment is changed - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - configure_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - rsyslog_nolisten - - - - - - - - - - - Rsyslog Logs Sent To Remote Host - If system logs are to be useful in detecting malicious -activities, it is necessary to send logs to a remote server. An -intruder who has compromised the root account on a system may -delete the log entries which indicate that the system was attacked -before they are seen by an administrator. - -However, it is recommended that logs be stored on the local -host in addition to being sent to the loghost, especially if -rsyslog has been configured to use the UDP protocol to send -messages over a network. UDP does not guarantee reliable delivery, -and moderately busy sites will lose log messages occasionally, -especially in periods of high traffic which may be the result of an -attack. In addition, remote rsyslog messages are not -authenticated in any way by default, so it is easy for an attacker to -introduce spurious messages to the central log server. Also, some -problems cause loss of network connectivity, which will prevent the -sending of messages to the central server. For all of these reasons, it is -better to store log messages both centrally and on each host, so -that they can be correlated if necessary. - - Remote Log Server - Specify an URI or IP address of a remote host where the log messages will be sent and stored. - logcollector - - - Ensure Logs Sent To Remote Host - To configure rsyslog to send logs to a remote log server, -open /etc/rsyslog.conf and read and understand the last section of the file, -which describes the multiple directives necessary to activate remote -logging. -Along with these other directives, the system can be configured -to forward its logs to a particular log server by -adding or correcting one of the following lines, -substituting appropriately. -The choice of protocol depends on the environment of the system; -although TCP and RELP provide more reliable message delivery, -they may not be supported in all environments. - -To use UDP for log message delivery: -*.* @ - -To use TCP for log message delivery: -*.* @@ - -To use RELP for log message delivery: -*.* :omrelp: - -There must be a resolvable DNS CNAME or Alias record set to "" for logs to be sent correctly to the centralized logging utility. - It is important to configure queues in case the client is sending log -messages to a remote server. If queues are not configured, -the system will stop functioning when the connection -to the remote server is not available. Please consult Rsyslog -documentation for more information about configuration of queues. The -example configuration which should go into /etc/rsyslog.conf -can look like the following lines: - -$ActionQueueType LinkedList -$ActionQueueFileName queuefilename -$ActionQueueMaxDiskSpace 1g -$ActionQueueSaveOnShutdown on -$ActionResumeRetryCount -1 - - BP28(R7) - NT28(R43) - NT12(R5) - 1 - 13 - 14 - 15 - 16 - 2 - 3 - 5 - 6 - APO11.04 - APO13.01 - BAI03.05 - BAI04.04 - DSS05.04 - DSS05.07 - MEA02.01 - CCI-000366 - CCI-001348 - CCI-000136 - CCI-001851 - 164.308(a)(1)(ii)(D) - 164.308(a)(5)(ii)(B) - 164.308(a)(5)(ii)(C) - 164.308(a)(6)(ii) - 164.308(a)(8) - 164.310(d)(2)(iii) - 164.312(b) - 164.314(a)(2)(i)(C) - 164.314(a)(2)(iii) - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.4.4.7 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.8 - SR 2.9 - SR 7.1 - SR 7.2 - 0988 - 1405 - A.12.1.3 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.17.2.1 - CIP-003-8 R5.2 - CIP-004-6 R3.3 - CM-6(a) - AU-4(1) - AU-9(2) - PR.DS-4 - PR.PT-1 - FAU_GEN.1.1.c - SRG-OS-000479-GPOS-00224 - SRG-OS-000480-GPOS-00227 - SRG-OS-000342-GPOS-00133 - A log server (loghost) receives syslog messages from one or more -systems. This data can be used as an additional log source in the event a -system is compromised and its local logs are suspect. Forwarding log messages -to a remote loghost also provides system administrators with a centralized -place to view the status of multiple hosts within the enterprise. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -rsyslog_remote_loghost_address='' - - -# Strip any search characters in the key arg so that the key can be replaced without -# adding any search characters to the config file. -stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^\*\.\*") - -# shellcheck disable=SC2059 -printf -v formatted_output "%s %s" "$stripped_key" "@@$rsyslog_remote_loghost_address" - -# If the key exists, change it. Otherwise, add it to the config_file. -# We search for the key string followed by a word boundary (matched by \>), -# so if we search for 'setting', 'setting2' won't match. -if LC_ALL=C grep -q -m 1 -i -e "^\*\.\*\\>" "/etc/rsyslog.conf"; then - escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") - LC_ALL=C sed -i --follow-symlinks "s/^\*\.\*\\>.*/$escaped_formatted_output/gi" "/etc/rsyslog.conf" -else - if [[ -s "/etc/rsyslog.conf" ]] && [[ -n "$(tail -c 1 -- "/etc/rsyslog.conf" || true)" ]]; then - LC_ALL=C sed -i --follow-symlinks '$a'\\ "/etc/rsyslog.conf" - fi - printf '%s\n' "$formatted_output" >> "/etc/rsyslog.conf" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: XCCDF Value rsyslog_remote_loghost_address # promote to variable - set_fact: - rsyslog_remote_loghost_address: !!str - tags: - - always - -- name: Set rsyslog remote loghost - lineinfile: - dest: /etc/rsyslog.conf - regexp: ^\*\.\* - line: '*.* @@{{ rsyslog_remote_loghost_address }}' - create: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AU-4(1) - - NIST-800-53-AU-9(2) - - NIST-800-53-CM-6(a) - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - rsyslog_remote_loghost - - - - - - - - - - Configure TLS for rsyslog remote logging - Configure rsyslog to use Transport Layer -Security (TLS) support for logging to remote server -for the Forwarding Output Module in /etc/rsyslog.conf -using action. You can use the following command: -echo 'action(type="omfwd" protocol="tcp" Target="<remote system>" port="6514" - StreamDriver="gtls" StreamDriverMode="1" StreamDriverAuthMode="x509/name" streamdriver.CheckExtendedKeyPurpose="on")' >> /etc/rsyslog.conf - -Replace the <remote system> in the above command with an IP address or a host name of the remote logging server. - BP28(R43) - 0988 - 1405 - AU-9(3) - CM-6(a) - FCS_TLSC_EXT.1 - FTP_ITC_EXT.1.1 - FIA_X509_EXT.1.1 - FMT_SMF_EXT.1.1 - SRG-OS-000480-GPOS-00227 - SRG-OS-000120-GPOS-00061 - For protection of data being logged, the connection to the -remote logging server needs to be authenticated and encrypted. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -rsyslog_remote_loghost_address='' - -params_to_add_if_missing=("protocol" "target" "port" "StreamDriver" "StreamDriverMode" "StreamDriverAuthMode" "streamdriver.CheckExtendedKeyPurpose") -values_to_add_if_missing=("tcp" "$rsyslog_remote_loghost_address" "6514" "gtls" "1" "x509/name" "on") -params_to_replace_if_wrong_value=("protocol" "StreamDriver" "StreamDriverMode" "StreamDriverAuthMode" "streamdriver.CheckExtendedKeyPurpose") -values_to_replace_if_wrong_value=("tcp" "gtls" "1" "x509/name" "on") - -files_containing_omfwd=("$(grep -ilE '^[^#]*\s*action\s*\(\s*type\s*=\s*"omfwd".*' /etc/rsyslog.conf /etc/rsyslog.d/*.conf)") -if [ -n "${files_containing_omfwd[*]}" ]; then - for file in "${files_containing_omfwd[@]}"; do - for ((i=0; i<${#params_to_replace_if_wrong_value[@]}; i++)); do - sed -i -E -e 'H;$!d;x;s/^\n//' -e "s|(\s*action\s*\(\s*type\s*=\s*[\"]omfwd[\"].*?)${params_to_replace_if_wrong_value[$i]}\s*=\s*[\"]\S*[\"](.*\))|\1${params_to_replace_if_wrong_value[$i]}=\"${values_to_replace_if_wrong_value[$i]}\"\2|gI" "$file" - done - for ((i=0; i<${#params_to_add_if_missing[@]}; i++)); do - if ! grep -qPzi "(?s)\s*action\s*\(\s*type\s*=\s*[\"]omfwd[\"].*?${params_to_add_if_missing[$i]}.*?\).*" "$file"; then - sed -i -E -e 'H;$!d;x;s/^\n//' -e "s|(\s*action\s*\(\s*type\s*=\s*[\"]omfwd[\"])|\1\n${params_to_add_if_missing[$i]}=\"${values_to_add_if_missing[$i]}\"|gI" "$file" - fi - done - done -else - echo "action(type=\"omfwd\" protocol=\"tcp\" Target=\"$rsyslog_remote_loghost_address\" port=\"6514\" StreamDriver=\"gtls\" StreamDriverMode=\"1\" StreamDriverAuthMode=\"x509/name\" streamdriver.CheckExtendedKeyPurpose=\"on\")" >> /etc/rsyslog.conf -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: XCCDF Value rsyslog_remote_loghost_address # promote to variable - set_fact: - rsyslog_remote_loghost_address: !!str - tags: - - always - -- name: 'Configure TLS for rsyslog remote logging: search for omfwd action directive - in rsyslog include files' - ansible.builtin.find: - paths: /etc/rsyslog.d/ - pattern: '*.conf' - contains: ^\s*action\s*\(\s*type\s*=\s*"omfwd".* - register: rsyslog_includes_with_directive - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AU-9(3) - - NIST-800-53-CM-6(a) - - configure_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - rsyslog_remote_tls - -- name: 'Configure TLS for rsyslog remote logging: search for omfwd action directive - in rsyslog main config file' - ansible.builtin.find: - paths: /etc - pattern: rsyslog.conf - contains: ^\s*action\s*\(\s*type\s*=\s*"omfwd".* - register: rsyslog_main_file_with_directive - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AU-9(3) - - NIST-800-53-CM-6(a) - - configure_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - rsyslog_remote_tls - -- name: 'Configure TLS for rsyslog remote logging: declare Rsyslog option parameters - to be inserted if entirely missing' - ansible.builtin.set_fact: - rsyslog_parameters_to_add_if_missing: - - protocol - - target - - port - - StreamDriver - - StreamDriverMode - - StreamDriverAuthMode - - streamdriver.CheckExtendedKeyPurpose - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AU-9(3) - - NIST-800-53-CM-6(a) - - configure_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - rsyslog_remote_tls - -- name: 'Configure TLS for rsyslog remote logging: declare Rsyslog option values to - be inserted if entirely missing' - ansible.builtin.set_fact: - rsyslog_values_to_add_if_missing: - - tcp - - '{{ rsyslog_remote_loghost_address }}' - - '6514' - - gtls - - '1' - - x509/name - - 'on' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AU-9(3) - - NIST-800-53-CM-6(a) - - configure_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - rsyslog_remote_tls - -- name: 'Configure TLS for rsyslog remote logging: declare Rsyslog option parameters - to be replaced if defined with wrong values' - ansible.builtin.set_fact: - rsyslog_parameters_to_replace_if_wrong_value: - - protocol - - StreamDriver - - StreamDriverMode - - StreamDriverAuthMode - - streamdriver.CheckExtendedKeyPurpose - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AU-9(3) - - NIST-800-53-CM-6(a) - - configure_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - rsyslog_remote_tls - -- name: 'Configure TLS for rsyslog remote logging: declare Rsyslog option values to - be replaced when having wrong value' - ansible.builtin.set_fact: - rsyslog_values_to_replace_if_wrong_value: - - tcp - - gtls - - '1' - - x509/name - - 'on' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AU-9(3) - - NIST-800-53-CM-6(a) - - configure_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - rsyslog_remote_tls - -- name: 'Configure TLS for rsyslog remote logging: assemble list of files with existing - directives' - ansible.builtin.set_fact: - rsyslog_files: '{{ rsyslog_includes_with_directive.files | map(attribute=''path'') - | list + rsyslog_main_file_with_directive.files | map(attribute=''path'') | - list }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AU-9(3) - - NIST-800-53-CM-6(a) - - configure_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - rsyslog_remote_tls - -- name: 'Configure TLS for rsyslog remote logging: try to fix existing directives' - block: - - - name: 'Configure TLS for rsyslog remote logging: Fix existing omfwd directives - by adjusting the value' - ansible.builtin.replace: - path: '{{ item[0] }}' - regexp: (?i)^(\s*action\s*\(\s*type\s*=\s*"omfwd"[\s\S]*)({{ item[1][0] | regex_escape() - }}\s*=\s*"\S*")([\s\S]*\))$ - replace: \1{{ item[1][0] }}="{{ item[1][1] }}"\3 - loop: '{{ rsyslog_files | product (rsyslog_parameters_to_replace_if_wrong_value - | zip(rsyslog_values_to_replace_if_wrong_value)) | list }}' - - - name: 'Configure TLS for rsyslog remote logging: Fix existing omfwd directives - by adding parameter and value' - ansible.builtin.replace: - path: '{{ item[0] }}' - regexp: (?i)^(\s*action\s*\(\s*type\s*=\s*"omfwd"(?:[\s\S](?!{{ item[1][0] | - regex_escape() }}))*.)(\))$ - replace: \1 {{ item[1][0] }}="{{ item[1][1] }}" \2 - loop: '{{ rsyslog_files | product (rsyslog_parameters_to_add_if_missing | zip(rsyslog_values_to_add_if_missing)) - | list }}' - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - rsyslog_includes_with_directive.matched or rsyslog_main_file_with_directive.matched - tags: - - NIST-800-53-AU-9(3) - - NIST-800-53-CM-6(a) - - configure_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - rsyslog_remote_tls - -- name: 'Configure TLS for rsyslog remote logging: Add missing rsyslog directive' - ansible.builtin.lineinfile: - dest: /etc/rsyslog.conf - line: action(type="omfwd" protocol="tcp" Target="{{ rsyslog_remote_loghost_address - }}" port="6514" StreamDriver="gtls" StreamDriverMode="1" StreamDriverAuthMode="x509/name" - streamdriver.CheckExtendedKeyPurpose="on") - create: true - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - not rsyslog_includes_with_directive.matched and not rsyslog_main_file_with_directive.matched - tags: - - NIST-800-53-AU-9(3) - - NIST-800-53-CM-6(a) - - configure_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - rsyslog_remote_tls - - - - - - - - - - Configure CA certificate for rsyslog remote logging - Configure CA certificate for rsyslog logging -to remote server using Transport Layer Security (TLS) -using correct path for the DefaultNetstreamDriverCAFile -global option in /etc/rsyslog.conf, for example with the following command: -echo 'global(DefaultNetstreamDriverCAFile="/etc/pki/tls/cert.pem")' >> /etc/rsyslog.conf -Replace the /etc/pki/tls/cert.pem in the above command with the path to the file with CA certificate generated for the purpose of remote logging. - Automatic remediation is not available as each organization has unique requirements. - BP28(R43) - 0988 - 1405 - FCS_TLSC_EXT.1 - SRG-OS-000480-GPOS-00227 - The CA certificate needs to be set or rsyslog.service -fails to start with -error: ca certificate is not set, cannot continue - - - - - - - - - - - Network Configuration and Firewalls - Most systems must be connected to a network of some -sort, and this brings with it the substantial risk of network -attack. This section discusses the security impact of decisions -about networking which must be made when configuring a system. - -This section also discusses firewalls, network access -controls, and other network security frameworks, which allow -system-level rules to be written that can limit an attackers' ability -to connect to your system. These rules can specify that network -traffic should be allowed or denied from certain IP addresses, -hosts, and networks. The rules can also specify which of the -system's network services are available to particular hosts or -networks. - - Configure Multiple DNS Servers in /etc/resolv.conf - -Determine whether the system is using local or DNS name resolution with the -following command: -$ sudo grep hosts /etc/nsswitch.conf -hosts: files dns -If the DNS entry is missing from the host's line in the "/etc/nsswitch.conf" -file, the "/etc/resolv.conf" file must be empty. -Verify the "/etc/resolv.conf" file is empty with the following command: -$ sudo ls -al /etc/resolv.conf --rw-r--r-- 1 root root 0 Aug 19 08:31 resolv.conf -If the DNS entry is found on the host's line of the "/etc/nsswitch.conf" file, -then verify the following: - -Multiple Domain Name System (DNS) Servers should be configured -in /etc/resolv.conf. This provides redundant name resolution services -in the event that a domain server crashes. To configure the system to contain -as least 2 DNS servers, add a corresponding nameserver -ip_address entry in /etc/resolv.conf for each DNS -server where ip_address is the IP address of a valid DNS server. -For example: -search example.com -nameserver 192.168.0.1 -nameserver 192.168.0.2 - 12 - 15 - 8 - APO13.01 - DSS05.02 - CCI-000366 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 7.1 - SR 7.6 - A.13.1.1 - A.13.2.1 - A.14.1.3 - SC-20(a) - CM-6(a) - PR.PT-4 - SRG-OS-000480-GPOS-00227 - To provide availability for name resolution services, multiple redundant -name servers are mandated. A failure in name resolution could lead to the -failure of security functions requiring name resolution, which may include -time synchronization, centralized authentication, and remote system logging. - - - - - - - - - Ensure System is Not Acting as a Network Sniffer - The system should not be acting as a network sniffer, which can -capture all traffic on the network to which it is connected. Run the following -to determine if any interface is running in promiscuous mode: -$ ip link | grep PROMISC -Promiscuous mode of an interface can be disabled with the following command: -$ sudo ip link set dev device_name multicast off promisc off - 1 - 11 - 14 - 3 - 9 - APO11.06 - APO12.06 - BAI03.10 - BAI09.01 - BAI09.02 - BAI09.03 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS01.05 - DSS04.05 - DSS05.02 - DSS05.05 - DSS06.06 - CCI-000366 - 4.2.3.4 - 4.3.3.3.7 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - 4.4.3.4 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 7.6 - SR 7.8 - A.11.1.2 - A.11.2.4 - A.11.2.5 - A.11.2.6 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.16.1.6 - A.8.1.1 - A.8.1.2 - A.9.1.2 - CM-7(a) - CM-7(b) - CM-6(a) - CM-7(2) - MA-3 - DE.DP-5 - ID.AM-1 - PR.IP-1 - PR.MA-1 - PR.PT-3 - SRG-OS-000480-GPOS-00227 - Network interfaces in promiscuous mode allow for the capture of all network traffic -visible to the system. If unauthorized individuals can access these applications, it -may allow them to collect information such as logon IDs, passwords, and key exchanges -between systems. - -If the system is being used to perform a network troubleshooting function, the use of these -tools must be documented with the Information Systems Security Manager (ISSM) and restricted -to only authorized personnel. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -for interface in $(ip link show | grep -E '^[0-9]' | cut -d ":" -f 2); do - ip link set dev $interface multicast off promisc off -done - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Ensure System is Not Acting as a Network Sniffer - Gather network interfaces - ansible.builtin.command: - cmd: ip link show - register: network_interfaces - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(2) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MA-3 - - low_complexity - - low_disruption - - medium_severity - - network_sniffer_disabled - - no_reboot_needed - - restrict_strategy - -- name: Ensure System is Not Acting as a Network Sniffer - Disable promiscuous mode - ansible.builtin.command: - cmd: ip link set dev {{ item.split(':')[1] }} multicast off promisc off - loop: '{{ network_interfaces.stdout_lines }}' - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - item.split(':') | length == 3 - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(2) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MA-3 - - low_complexity - - low_disruption - - medium_severity - - network_sniffer_disabled - - no_reboot_needed - - restrict_strategy - - - - - - - - - - firewalld - The dynamic firewall daemon firewalld provides a -dynamically managed firewall with support for network “zones” to assign -a level of trust to a network and its associated connections and interfaces. -It has support for IPv4 and IPv6 firewall settings. It supports Ethernet -bridges and has a separation of runtime and permanent configuration options. -It also has an interface for services or applications to add firewall rules -directly. - -A graphical configuration tool, firewall-config, is used to configure -firewalld, which in turn uses iptables tool to communicate -with Netfilter in the kernel which implements packet filtering. - -The firewall service provided by firewalld is dynamic rather than -static because changes to the configuration can be made at anytime and are -immediately implemented. There is no need to save or apply the changes. No -unintended disruption of existing network connections occurs as no part of -the firewall has to be reloaded. - - - Configure Firewalld to Use the Nftables Backend - Firewalld can be configured with many backends, such as nftables. - CCI-002385 - SC-5 - SRG-OS-000420-GPOS-00186 - Nftables is modern kernel module for controling network connections coming into a system. -Utilizing the limit statement in "nftables" can help to mitigate DoS attacks. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && { rpm --quiet -q firewalld; }; then - -if [ -e "/etc/firewalld/firewalld.conf" ] ; then - - LC_ALL=C sed -i "/^\s*FirewallBackend\s*=\s*/d" "/etc/firewalld/firewalld.conf" -else - touch "/etc/firewalld/firewalld.conf" -fi -# make sure file has newline at the end -sed -i -e '$a\' "/etc/firewalld/firewalld.conf" - -cp "/etc/firewalld/firewalld.conf" "/etc/firewalld/firewalld.conf.bak" -# Insert before the line matching the regex '^#\s*FirewallBackend'. -line_number="$(LC_ALL=C grep -n "^#\s*FirewallBackend" "/etc/firewalld/firewalld.conf.bak" | LC_ALL=C sed 's/:.*//g')" -if [ -z "$line_number" ]; then - # There was no match of '^#\s*FirewallBackend', insert at - # the end of the file. - printf '%s\n' "FirewallBackend=nftables" >> "/etc/firewalld/firewalld.conf" -else - head -n "$(( line_number - 1 ))" "/etc/firewalld/firewalld.conf.bak" > "/etc/firewalld/firewalld.conf" - printf '%s\n' "FirewallBackend=nftables" >> "/etc/firewalld/firewalld.conf" - tail -n "+$(( line_number ))" "/etc/firewalld/firewalld.conf.bak" >> "/etc/firewalld/firewalld.conf" -fi -# Clean up after ourselves. -rm "/etc/firewalld/firewalld.conf.bak" - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Gather the package facts - package_facts: - manager: auto - tags: - - NIST-800-53-SC-5 - - firewalld-backend - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - -- name: Setting unquoted shell-style assignment of 'FirewallBackend' to 'nftables' - in '/etc/firewalld/firewalld.conf' - block: - - - name: Check for duplicate values - lineinfile: - path: /etc/firewalld/firewalld.conf - create: false - regexp: ^\s*FirewallBackend= - state: absent - check_mode: true - changed_when: false - register: dupes - - - name: Deduplicate values from /etc/firewalld/firewalld.conf - lineinfile: - path: /etc/firewalld/firewalld.conf - create: false - regexp: ^\s*FirewallBackend= - state: absent - when: dupes.found is defined and dupes.found > 1 - - - name: Insert correct line to /etc/firewalld/firewalld.conf - lineinfile: - path: /etc/firewalld/firewalld.conf - create: true - regexp: ^\s*FirewallBackend= - line: FirewallBackend=nftables - state: present - insertbefore: ^# FirewallBackend - validate: /usr/bin/bash -n %s - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - '"firewalld" in ansible_facts.packages' - tags: - - NIST-800-53-SC-5 - - firewalld-backend - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - - - - - - - - - Inspect and Activate Default firewalld Rules - Firewalls can be used to separate networks into different zones -based on the level of trust the user has decided to place on the devices and -traffic within that network. NetworkManager informs firewalld to which -zone an interface belongs. An interface's assigned zone can be changed by -NetworkManager or via the firewall-config tool. - -The zone settings in /etc/firewalld/ are a range of preset settings -which can be quickly applied to a network interface. These are the zones -provided by firewalld sorted according to the default trust level of the -zones from untrusted to trusted: -dropAny incoming network packets are dropped, there is no -reply. Only outgoing network connections are possible.blockAny incoming network connections are rejected with an -icmp-host-prohibited message for IPv4 and icmp6-adm-prohibited -for IPv6. Only network connections initiated from within the system are -possible.publicFor use in public areas. You do not trust the other -computers on the network to not harm your computer. Only selected incoming -connections are accepted.externalFor use on external networks with masquerading enabled -especially for routers. You do not trust the other computers on the network to -not harm your computer. Only selected incoming connections are accepted.dmzFor computers in your demilitarized zone that are -publicly-accessible with limited access to your internal network. Only selected -incoming connections are accepted.workFor use in work areas. You mostly trust the other computers -on networks to not harm your computer. Only selected incoming connections are -accepted.homeFor use in home areas. You mostly trust the other computers -on networks to not harm your computer. Only selected incoming connections are -accepted.internalFor use on internal networks. You mostly trust the -other computers on the networks to not harm your computer. Only selected -incoming connections are accepted.trustedAll network connections are accepted. - -It is possible to designate one of these zones to be the default zone. When -interface connections are added to NetworkManager, they are assigned -to the default zone. On installation, the default zone in firewalld is set to -be the public zone. - -To find out all the settings of a zone, for example the public zone, -enter the following command as root: -# firewall-cmd --zone=public --list-all -Example output of this command might look like the following: - -# firewall-cmd --zone=public --list-all -public - interfaces: - services: mdns dhcpv6-client ssh - ports: - forward-ports: - icmp-blocks: source-quench - -To view the network zones currently active, enter the following command as root: -# firewall-cmd --get-service -The following listing displays the result of this command -on common Oracle Linux 9 system: - -# firewall-cmd --get-service -amanda-client bacula bacula-client dhcp dhcpv6 dhcpv6-client dns ftp -high-availability http https imaps ipp ipp-client ipsec kerberos kpasswd -ldap ldaps libvirt libvirt-tls mdns mountd ms-wbt mysql nfs ntp openvpn -pmcd pmproxy pmwebapi pmwebapis pop3s postgresql proxy-dhcp radius rpc-bind -samba samba-client smtp ssh telnet tftp tftp-client transmission-client -vnc-server wbem-https - -Finally to view the network zones that will be active after the next firewalld -service reload, enter the following command as root: -# firewall-cmd --get-service --permanent - - Install firewalld Package - The firewalld package can be installed with the following command: - -$ sudo yum install firewalld - CCI-002314 - CM-6(a) - FMT_SMF_EXT.1 - SRG-OS-000096-GPOS-00050 - SRG-OS-000297-GPOS-00115 - SRG-OS-000298-GPOS-00116 - SRG-OS-000480-GPOS-00227 - SRG-OS-000480-GPOS-00232 - "Firewalld" provides an easy and effective way to block/limit remote access to the system via ports, services, and protocols. - -Remote access services, such as those providing remote access to network devices and information systems, which lack automated control capabilities, increase risk and make remote user access management difficult at best. - -Remote access is access to DoD nonpublic information systems by an authorized user (or an information system) communicating through an external, non-organization-controlled network. Remote access methods include, for example, dial-up, broadband, and wireless. - -Oracle Linux 9 functionality (e.g., SSH) must be capable of taking enforcement action if the audit reveals unauthorized activity. -Automated control of remote access sessions allows organizations to ensure ongoing compliance with remote access policies by enforcing connection rules of remote access applications on a variety of information system components (e.g., servers, workstations, notebook computers, smartphones, and tablets)." - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -if ! rpm -q --quiet "firewalld" ; then - yum install -y "firewalld" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Ensure firewalld is installed - package: - name: firewalld - state: present - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-CM-6(a) - - enable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - package_firewalld_installed - - include install_firewalld - -class install_firewalld { - package { 'firewalld': - ensure => 'installed', - } -} - - -package --add=firewalld - - -[[packages]] -name = "firewalld" -version = "*" - - - - - - - - - - Verify firewalld Enabled - -The firewalld service can be enabled with the following command: -$ sudo systemctl enable firewalld.service - 11 - 3 - 9 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - 3.1.3 - 3.4.7 - CCI-000366 - CCI-000382 - CCI-002314 - 4.3.4.3.2 - 4.3.4.3.3 - SR 7.6 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.14.2.2 - A.14.2.3 - A.14.2.4 - CIP-003-8 R4 - CIP-003-8 R5 - CIP-004-6 R3 - AC-4 - CM-7(b) - CA-3(5) - SC-7(21) - CM-6(a) - PR.IP-1 - FMT_SMF_EXT.1 - SRG-OS-000096-GPOS-00050 - SRG-OS-000297-GPOS-00115 - SRG-OS-000480-GPOS-00227 - SRG-OS-000480-GPOS-00231 - SRG-OS-000480-GPOS-00232 - Access control methods provide the ability to enhance system security posture -by restricting services and known good IP addresses and address ranges. This -prevents connections from unknown hosts and protocols. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && { rpm --quiet -q firewalld; }; then - -SYSTEMCTL_EXEC='/usr/bin/systemctl' -"$SYSTEMCTL_EXEC" unmask 'firewalld.service' -"$SYSTEMCTL_EXEC" start 'firewalld.service' -"$SYSTEMCTL_EXEC" enable 'firewalld.service' - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Gather the package facts - package_facts: - manager: auto - tags: - - NIST-800-171-3.1.3 - - NIST-800-171-3.4.7 - - NIST-800-53-AC-4 - - NIST-800-53-CA-3(5) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-SC-7(21) - - enable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_firewalld_enabled - -- name: Enable service firewalld - block: - - - name: Gather the package facts - package_facts: - manager: auto - - - name: Enable service firewalld - systemd: - name: firewalld - enabled: 'yes' - state: started - masked: 'no' - when: - - '"firewalld" in ansible_facts.packages' - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - '"firewalld" in ansible_facts.packages' - tags: - - NIST-800-171-3.1.3 - - NIST-800-171-3.4.7 - - NIST-800-53-AC-4 - - NIST-800-53-CA-3(5) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-SC-7(21) - - enable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_firewalld_enabled - - include enable_firewalld - -class enable_firewalld { - service {'firewalld': - enable => true, - ensure => 'running', - } -} - - -[customizations.services] -enabled = ["firewalld"] - - - - - - - - - - - Strengthen the Default Ruleset - The default rules can be strengthened. The system -scripts that activate the firewall rules expect them to be defined -in configuration files under the /etc/firewalld/services -and /etc/firewalld/zones directories. - -The following recommendations describe how to strengthen the -default ruleset configuration file. An alternative to editing this -configuration file is to create a shell script that makes calls to -the firewall-cmd program to load in rules under the /etc/firewalld/services -and /etc/firewalld/zones directories. - -Instructions apply to both unless otherwise noted. Language and address -conventions for regular firewalld rules are used throughout this section. - The program firewall-config -allows additional services to penetrate the default firewall rules -and automatically adjusts the firewalld ruleset(s). - - Configure the Firewalld Ports - Configure the firewalld ports to allow approved services to have access to the system. -To configure firewalld to open ports, run the following command: -firewall-cmd --permanent --add-port=port_number/tcp -To configure firewalld to allow access for pre-defined services, run the following -command: -firewall-cmd --permanent --add-service=service_name - 11 - 12 - 14 - 15 - 3 - 8 - 9 - APO13.01 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS01.04 - DSS05.02 - DSS05.03 - DSS05.05 - DSS06.06 - CCI-000382 - CCI-002314 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 7.1 - SR 7.6 - 1416 - A.11.2.6 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.6.2.1 - A.6.2.2 - A.9.1.2 - AC-4 - CM-7(b) - CA-3(5) - SC-7(21) - CM-6(a) - PR.AC-3 - PR.IP-1 - PR.PT-3 - PR.PT-4 - SRG-OS-000096-GPOS-00050 - SRG-OS-000297-GPOS-00115 - In order to prevent unauthorized connection of devices, unauthorized transfer of information, -or unauthorized tunneling (i.e., embedding of data types within data types), organizations must -disable or restrict unused or unnecessary physical and logical ports/protocols on information -systems. - -Operating systems are capable of providing a wide variety of functions and services. -Some of the functions and services provided by default may not be necessary to support -essential organizational operations. -Additionally, it is sometimes convenient to provide multiple services from a single component -(e.g., VPN and IPS); however, doing so increases risk over limiting the services provided by -one component. - -To support the requirements and principles of least functionality, the operating system must -support the organizational requirements, providing only essential capabilities and limiting the -use of ports, protocols, and/or services to only those required, authorized, and approved to -conduct official business. - - - - - - Firewalld Must Employ a Deny-all, Allow-by-exception Policy for Allowing Connections to Other Systems - Oracle Linux 9 incorporates the "firewalld" daemon, which allows for many different configurations. One of these configurations is zones. -Zones can be utilized to a deny-all, allow-by-exception approach. -The default "drop" zone will drop all incoming network packets unless it is explicitly allowed by the configuration file or is related to an outgoing network connection. - CCI-002314 - AC-17 (1) - SRG-OS-000297-GPOS-00115 - Failure to restrict network connectivity only to authorized systems permits inbound connections from malicious systems. -It also permits outbound connections that may facilitate exfiltration of data. - - - - - - Set Default firewalld Zone for Incoming Packets - To set the default zone to drop for -the built-in default zone which processes incoming IPv4 and IPv6 packets, -modify the following line in -/etc/firewalld/firewalld.conf to be: -DefaultZone=drop - To prevent denying any access to the system, automatic remediation -of this control is not available. Remediation must be automated as -a component of machine provisioning, or followed manually as outlined -above. - 11 - 14 - 3 - 9 - 5.10.1 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS05.02 - DSS05.05 - DSS06.06 - 3.1.3 - 3.4.7 - 3.13.6 - CCI-000366 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 7.6 - 1416 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.9.1.2 - CA-3(5) - CM-7(b) - SC-7(23) - CM-6(a) - PR.IP-1 - PR.PT-3 - FMT_MOF_EXT.1 - Req-1.4 - 1.5.1 - SRG-OS-000480-GPOS-00227 - In firewalld the default zone is applied only after all -the applicable rules in the table are examined for a match. Setting the -default zone to drop implements proper design for a firewall, i.e. -any packets which are not explicitly permitted should not be -accepted. - - - - - - - - - - - - IPSec Support - Support for Internet Protocol Security (IPsec) -is provided with Libreswan. - - Install libreswan Package - The libreswan package provides an implementation of IPsec -and IKE, which permits the creation of secure tunnels over -untrusted networks. The libreswan package can be installed with the following command: - -$ sudo yum install libreswan - 12 - 15 - 3 - 5 - 8 - APO13.01 - DSS01.04 - DSS05.02 - DSS05.03 - DSS05.04 - CCI-001130 - CCI-001131 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - SR 1.13 - SR 2.6 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 7.1 - SR 7.6 - A.11.2.4 - A.11.2.6 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.15.1.1 - A.15.2.1 - A.6.2.1 - A.6.2.2 - CM-6(a) - PR.AC-3 - PR.MA-2 - PR.PT-4 - Req-4.1 - 4.2.1 - SRG-OS-000480-GPOS-00227 - SRG-OS-000120-GPOS-00061 - Providing the ability for remote users or systems -to initiate a secure VPN connection protects information when it is -transmitted over a wide area network. - -if ! rpm -q --quiet "libreswan" ; then - yum install -y "libreswan" -fi - - - name: Ensure libreswan is installed - package: - name: libreswan - state: present - tags: - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-4.1 - - PCI-DSSv4-4.2.1 - - enable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - package_libreswan_installed - - include install_libreswan - -class install_libreswan { - package { 'libreswan': - ensure => 'installed', - } -} - - -package --add=libreswan - - -[[packages]] -name = "libreswan" -version = "*" - - - - - - - - - - Verify Any Configured IPSec Tunnel Connections - Libreswan provides an implementation of IPsec -and IKE, which permits the creation of secure tunnels over -untrusted networks. As such, IPsec can be used to circumvent certain -network requirements such as filtering. Verify that if any IPsec connection -(conn) configured in /etc/ipsec.conf and /etc/ipsec.d -exists is an approved organizational connection. - Automatic remediation of this control is not available due to the unique -requirements of each system. - 1 - 12 - 13 - 14 - 15 - 16 - 18 - 4 - 6 - 8 - 9 - APO01.06 - APO13.01 - DSS01.05 - DSS03.01 - DSS05.02 - DSS05.04 - DSS05.07 - DSS06.02 - CCI-000336 - 164.308(a)(4)(i) - 164.308(b)(1) - 164.308(b)(3) - 164.310(b) - 164.312(e)(1) - 164.312(e)(2)(ii) - 4.2.3.4 - 4.3.3.4 - 4.4.3.3 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 7.1 - SR 7.6 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.12.1.1 - A.12.1.2 - A.13.1.1 - A.13.1.2 - A.13.1.3 - A.13.2.1 - A.13.2.2 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - AC-17(a) - MA-4(6) - CM-6(a) - AC-4 - SC-8 - DE.AE-1 - ID.AM-3 - PR.AC-5 - PR.DS-5 - PR.PT-4 - SRG-OS-000480-GPOS-00227 - IP tunneling mechanisms can be used to bypass network filtering. - - - - - - - iptables and ip6tables - A host-based firewall called netfilter is included as -part of the Linux kernel distributed with the system. It is -activated by default. This firewall is controlled by the program -iptables, and the entire capability is frequently referred to by -this name. An analogous program called ip6tables handles filtering -for IPv6. - -Unlike TCP Wrappers, which depends on the network server -program to support and respect the rules written, netfilter -filtering occurs at the kernel level, before a program can even -process the data from the network packet. As such, any program on -the system is affected by the rules written. - -This section provides basic information about strengthening -the iptables and ip6tables configurations included with the system. -For more complete information that may allow the construction of a -sophisticated ruleset tailored to your environment, please consult -the references at the end of this section. - - Inspect and Activate Default Rules - View the currently-enforced iptables rules by running -the command: -$ sudo iptables -nL --line-numbers -The command is analogous for ip6tables. - -If the firewall does not appear to be active (i.e., no rules -appear), activate it and ensure that it starts at boot by issuing -the following commands (and analogously for ip6tables): -$ sudo service iptables restart -The default iptables rules are: -Chain INPUT (policy ACCEPT) -num target prot opt source destination -1 ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED -2 ACCEPT icmp -- 0.0.0.0/0 0.0.0.0/0 -3 ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 -4 ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 state NEW tcp dpt:22 -5 REJECT all -- 0.0.0.0/0 0.0.0.0/0 reject-with icmp-host-prohibited - -Chain FORWARD (policy ACCEPT) -num target prot opt source destination -1 REJECT all -- 0.0.0.0/0 0.0.0.0/0 reject-with icmp-host-prohibited - -Chain OUTPUT (policy ACCEPT) -num target prot opt source destination -The ip6tables default rules are essentially the same. - - Verify ip6tables Enabled if Using IPv6 - -The ip6tables service can be enabled with the following command: -$ sudo systemctl enable ip6tables.service - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 4 - 6 - 8 - 9 - APO01.06 - APO13.01 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS01.05 - DSS03.01 - DSS05.02 - DSS05.04 - DSS05.05 - DSS05.07 - DSS06.02 - DSS06.06 - 4.2.3.4 - 4.3.3.4 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - 4.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 7.1 - SR 7.6 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.12.1.1 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.13.1.1 - A.13.1.2 - A.13.1.3 - A.13.2.1 - A.13.2.2 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CIP-003-8 R4 - CIP-003-8 R5 - CIP-004-6 R3 - AC-4 - CM-7(b) - CA-3(5) - SC-7(21) - CM-6(a) - DE.AE-1 - ID.AM-3 - PR.AC-5 - PR.DS-5 - PR.IP-1 - PR.PT-3 - PR.PT-4 - The ip6tables service provides the system's host-based firewalling -capability for IPv6 and ICMPv6. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -SYSTEMCTL_EXEC='/usr/bin/systemctl' -"$SYSTEMCTL_EXEC" unmask 'ip6tables.service' -"$SYSTEMCTL_EXEC" start 'ip6tables.service' -"$SYSTEMCTL_EXEC" enable 'ip6tables.service' - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Enable service ip6tables - block: - - - name: Gather the package facts - package_facts: - manager: auto - - - name: Enable service ip6tables - systemd: - name: ip6tables - enabled: 'yes' - state: started - masked: 'no' - when: - - '"iptables-ipv6" in ansible_facts.packages' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-4 - - NIST-800-53-CA-3(5) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-SC-7(21) - - enable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_ip6tables_enabled - - include enable_ip6tables - -class enable_ip6tables { - service {'ip6tables': - enable => true, - ensure => 'running', - } -} - - -[customizations.services] -enabled = ["ip6tables"] - - - - - - - - - - Verify iptables Enabled - -The iptables service can be enabled with the following command: -$ sudo systemctl enable iptables.service - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 4 - 6 - 8 - 9 - APO01.06 - APO13.01 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS01.05 - DSS03.01 - DSS05.02 - DSS05.04 - DSS05.05 - DSS05.07 - DSS06.02 - DSS06.06 - 4.2.3.4 - 4.3.3.4 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - 4.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 7.1 - SR 7.6 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.12.1.1 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.13.1.1 - A.13.1.2 - A.13.1.3 - A.13.2.1 - A.13.2.2 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CIP-003-8 R4 - CIP-003-8 R5 - CIP-004-6 R3 - AC-4 - CM-7(b) - CA-3(5) - SC-7(21) - CM-6(a) - DE.AE-1 - ID.AM-3 - PR.AC-5 - PR.DS-5 - PR.IP-1 - PR.PT-3 - PR.PT-4 - The iptables service provides the system's host-based firewalling -capability for IPv4 and ICMP. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -SYSTEMCTL_EXEC='/usr/bin/systemctl' -"$SYSTEMCTL_EXEC" unmask 'iptables.service' -"$SYSTEMCTL_EXEC" start 'iptables.service' -"$SYSTEMCTL_EXEC" enable 'iptables.service' - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Enable service iptables - block: - - - name: Gather the package facts - package_facts: - manager: auto - - - name: Enable service iptables - systemd: - name: iptables - enabled: 'yes' - state: started - masked: 'no' - when: - - '"iptables" in ansible_facts.packages' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-4 - - NIST-800-53-CA-3(5) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-SC-7(21) - - enable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_iptables_enabled - - include enable_iptables - -class enable_iptables { - service {'iptables': - enable => true, - ensure => 'running', - } -} - - -[customizations.services] -enabled = ["iptables"] - - - - - - - - - - Set Default ip6tables Policy for Incoming Packets - To set the default policy to DROP (instead of ACCEPT) for -the built-in INPUT chain which processes incoming packets, -add or correct the following line in -/etc/sysconfig/ip6tables: -:INPUT DROP [0:0] -If changes were required, reload the ip6tables rules: -$ sudo service ip6tables reload - 11 - 14 - 3 - 9 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS05.02 - DSS05.05 - DSS06.06 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 7.6 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.9.1.2 - CIP-003-8 R4 - CIP-003-8 R5 - CIP-004-6 R3 - AC-4 - CM-7(b) - CA-3(5) - SC-7(21) - CM-6(a) - PR.IP-1 - PR.PT-3 - 1.4.1 - In ip6tables, the default policy is applied only after all -the applicable rules in the table are examined for a match. Setting the -default policy to DROP implements proper design for a firewall, i.e. -any packets which are not explicitly permitted should not be -accepted. - - # Remediation is applicable only in certain platforms -if ( ! ( rpm --quiet -q nftables ) && ! ( rpm --quiet -q ufw ) && rpm --quiet -q iptables ); then - -sed -i 's/^:INPUT ACCEPT.*/:INPUT DROP [0:0]/g' /etc/sysconfig/ip6tables - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - - - - - Set configuration for IPv6 loopback traffic - Configure the loopback interface to accept traffic. -Configure all other interfaces to deny traffic to the loopback -network. - Changing firewall settings while connected over network can -result in being locked out of the system. - Req-1.3 - 1.4.1 - Loopback traffic is generated between processes on machine and is -typically critical to operation of the system. The loopback interface -is the only place that loopback network traffic should be seen, -all other interfaces should ignore traffic on this network as an -anti-spoofing measure. - - - - - - - Set configuration for loopback traffic - Configure the loopback interface to accept traffic. -Configure all other interfaces to deny traffic to the loopback -network. - Changing firewall settings while connected over network can -result in being locked out of the system. - Req-1.3 - 1.4.1 - Loopback traffic is generated between processes on machine and is -typically critical to operation of the system. The loopback interface -is the only place that loopback network traffic should be seen, all -other interfaces should ignore traffic on this network as an -anti-spoofing measure. - - - - - - - - Strengthen the Default Ruleset - The default rules can be strengthened. The system -scripts that activate the firewall rules expect them to be defined -in the configuration files iptables and ip6tables in the directory -/etc/sysconfig. Many of the lines in these files are similar -to the command line arguments that would be provided to the programs -/sbin/iptables or /sbin/ip6tables - but some are quite -different. - -The following recommendations describe how to strengthen the -default ruleset configuration file. An alternative to editing this -configuration file is to create a shell script that makes calls to -the iptables program to load in rules, and then invokes service -iptables save to write those loaded rules to -/etc/sysconfig/iptables. - -The following alterations can be made directly to -/etc/sysconfig/iptables and /etc/sysconfig/ip6tables. -Instructions apply to both unless otherwise noted. Language and address -conventions for regular iptables are used throughout this section; -configuration for ip6tables will be either analogous or explicitly -covered. - The program system-config-securitylevel -allows additional services to penetrate the default firewall rules -and automatically adjusts /etc/sysconfig/iptables. This program -is only useful if the default ruleset meets your security -requirements. Otherwise, this program should not be used to make -changes to the firewall configuration because it re-writes the -saved configuration file. - - Set Default iptables Policy for Incoming Packets - To set the default policy to DROP (instead of ACCEPT) for -the built-in INPUT chain which processes incoming packets, -add or correct the following line in -/etc/sysconfig/iptables: -:INPUT DROP [0:0] - 11 - 14 - 3 - 9 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS05.02 - DSS05.05 - DSS06.06 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 7.6 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.9.1.2 - CA-3(5) - CM-7(b) - SC-7(23) - CM-6(a) - PR.IP-1 - PR.PT-3 - In iptables the default policy is applied only after all -the applicable rules in the table are examined for a match. Setting the -default policy to DROP implements proper design for a firewall, i.e. -any packets which are not explicitly permitted should not be -accepted. - - # Remediation is applicable only in certain platforms -if ( ! ( rpm --quiet -q nftables ) && ! ( rpm --quiet -q ufw ) ); then - -sed -i 's/^:INPUT ACCEPT.*/:INPUT DROP [0:0]/g' /etc/sysconfig/iptables - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - - - - - Set Default iptables Policy for Forwarded Packets - To set the default policy to DROP (instead of ACCEPT) for -the built-in FORWARD chain which processes packets that will be forwarded from -one interface to another, -add or correct the following line in -/etc/sysconfig/iptables: -:FORWARD DROP [0:0] - 11 - 14 - 3 - 9 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS05.02 - DSS05.05 - DSS06.06 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 7.6 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.9.1.2 - CA-3(5) - CM-7(b) - SC-7(23) - CM-6(a) - PR.IP-1 - PR.PT-3 - In iptables, the default policy is applied only after all -the applicable rules in the table are examined for a match. Setting the -default policy to DROP implements proper design for a firewall, i.e. -any packets which are not explicitly permitted should not be -accepted. - sed -i 's/^:FORWARD ACCEPT.*/:FORWARD DROP [0:0]/g' /etc/sysconfig/iptables - - - - - - - Restrict ICMP Message Types - In /etc/sysconfig/iptables, the accepted ICMP messages -types can be restricted. To accept only ICMP echo reply, destination -unreachable, and time exceeded messages, remove the line: --A INPUT -p icmp --icmp-type any -j ACCEPT -and insert the lines: --A INPUT -p icmp --icmp-type echo-reply -j ACCEPT --A INPUT -p icmp --icmp-type destination-unreachable -j ACCEPT --A INPUT -p icmp --icmp-type time-exceeded -j ACCEPT -To allow the system to respond to pings, also insert the following line: --A INPUT -p icmp --icmp-type echo-request -j ACCEPT -Ping responses can also be limited to certain networks or hosts by using the -s -option in the previous rule. Because IPv6 depends so heavily on ICMPv6, it is -preferable to deny the ICMPv6 packets you know you don't need (e.g. ping -requests) in /etc/sysconfig/ip6tables, while letting everything else -through: --A INPUT -p icmpv6 --icmpv6-type echo-request -j DROP -If you are going to statically configure the system's address, it should -ignore Router Advertisements which could add another IPv6 address to the -interface or alter important network settings: --A INPUT -p icmpv6 --icmpv6-type router-advertisement -j DROP -Restricting ICMPv6 message types in /etc/sysconfig/ip6tables is not -recommended because the operation of IPv6 depends heavily on ICMPv6. Thus, great -care must be taken if any other ICMPv6 types are blocked. - - - Log and Drop Packets with Suspicious Source Addresses - Packets with non-routable source addresses should be rejected, as they may indicate spoofing. Because the -modified policy will reject non-matching packets, you only need to add these rules if you are interested in also -logging these spoofing or suspicious attempts before they are dropped. If you do choose to log various suspicious -traffic, add identical rules with a target of DROP after each LOG. -To log and then drop these IPv4 packets, insert the following rules in /etc/sysconfig/iptables (excepting -any that are intentionally used): --A INPUT -s 10.0.0.0/8 -j LOG --log-prefix "IP DROP SPOOF A: " --A INPUT -s 172.16.0.0/12 -j LOG --log-prefix "IP DROP SPOOF B: " --A INPUT -s 192.168.0.0/16 -j LOG --log-prefix "IP DROP SPOOF C: " --A INPUT -s 224.0.0.0/4 -j LOG --log-prefix "IP DROP MULTICAST D: " --A INPUT -s 240.0.0.0/5 -j LOG --log-prefix "IP DROP SPOOF E: " --A INPUT -d 127.0.0.0/8 -j LOG --log-prefix "IP DROP LOOPBACK: " -Similarly, you might wish to log packets containing some IPv6 reserved addresses if they are not expected -on your network: --A INPUT -i eth0 -s ::1 -j LOG --log-prefix "IPv6 DROP LOOPBACK: " --A INPUT -s 2002:E000::/20 -j LOG --log-prefix "IPv6 6to4 TRAFFIC: " --A INPUT -s 2002:7F00::/24 -j LOG --log-prefix "IPv6 6to4 TRAFFIC: " --A INPUT -s 2002:0000::/24 -j LOG --log-prefix "IPv6 6to4 TRAFFIC: " --A INPUT -s 2002:FF00::/24 -j LOG --log-prefix "IPv6 6to4 TRAFFIC: " --A INPUT -s 2002:0A00::/24 -j LOG --log-prefix "IPv6 6to4 TRAFFIC: " --A INPUT -s 2002:AC10::/28 -j LOG --log-prefix "IPv6 6to4 TRAFFIC: " --A INPUT -s 2002:C0A8::/32 -j LOG --log-prefix "IPv6 6to4 TRAFFIC: " -If you are not expecting to see site-local multicast or auto-tunneled traffic, you can log those: --A INPUT -s FF05::/16 -j LOG --log-prefix "IPv6 SITE-LOCAL MULTICAST: " --A INPUT -s ::0.0.0.0/96 -j LOG --log-prefix "IPv4 COMPATIBLE IPv6 ADDR: " -If you wish to block multicasts to all link-local nodes (e.g. if you are not using router auto-configuration and -do not plan to have any services that multicast to the entire local network), you can block the link-local -all-nodes multicast address (before accepting incoming ICMPv6): --A INPUT -d FF02::1 -j LOG --log-prefix "Link-local All-Nodes Multicast: " -However, if you're going to allow IPv4 compatible IPv6 addresses (of the form ::0.0.0.0/96), you should -then consider logging the non-routable IPv4-compatible addresses: --A INPUT -s ::0.0.0.0/104 -j LOG --log-prefix "IP NON-ROUTABLE ADDR: " --A INPUT -s ::127.0.0.0/104 -j LOG --log-prefix "IP DROP LOOPBACK: " --A INPUT -s ::224.0.0.0.0/100 -j LOG --log-prefix "IP DROP MULTICAST D: " --A INPUT -s ::255.0.0.0/104 -j LOG --log-prefix "IP BROADCAST: " -If you are not expecting to see any IPv4 (or IPv4-compatible) traffic on your network, consider logging it before it gets dropped: --A INPUT -s ::FFFF:0.0.0.0/96 -j LOG --log-prefix "IPv4 MAPPED IPv6 ADDR: " --A INPUT -s 2002::/16 -j LOG --log-prefix "IPv6 6to4 ADDR: " -The following rule will log all traffic originating from a site-local address, which is deprecated address space: --A INPUT -s FEC0::/10 -j LOG --log-prefix "SITE-LOCAL ADDRESS TRAFFIC: " - - - - - IPv6 - The system includes support for Internet Protocol -version 6. A major and often-mentioned improvement over IPv4 is its -enormous increase in the number of available addresses. Another -important feature is its support for automatic configuration of -many network settings. - - Disable Support for IPv6 Unless Needed - Despite configuration that suggests support for IPv6 has -been disabled, link-local IPv6 address auto-configuration occurs -even when only an IPv4 address is assigned. The only way to -effectively prevent execution of the IPv6 networking stack is to -instruct the system not to activate the IPv6 kernel module. - - Disable IPv6 Networking Support Automatic Loading - To prevent the IPv6 kernel module (ipv6) from binding to the -IPv6 networking stack, add the following line to -/etc/modprobe.d/disabled.conf (or another file in -/etc/modprobe.d): -options ipv6 disable=1 -This permits the IPv6 module to be loaded (and thus satisfy other modules that -depend on it), while disabling support for the IPv6 protocol. - 11 - 14 - 3 - 9 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS05.02 - DSS05.05 - DSS06.06 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 7.6 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.9.1.2 - CM-7(a) - CM-7(b) - CM-6(a) - PR.IP-1 - PR.PT-3 - Any unnecessary network stacks - including IPv6 - should be disabled, to reduce -the vulnerability to exploitation. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Prevent the IPv6 kernel module (ipv6) from loading the IPv6 networking stack -echo "options ipv6 disable=1" > /etc/modprobe.d/ipv6.conf - -# Since according to: https://access.redhat.com/solutions/72733 -# "ipv6 disable=1" options doesn't always disable the IPv6 networking stack from -# loading, instruct also sysctl configuration to disable IPv6 according to: -# https://access.redhat.com/solutions/8709#rhel6disable - -declare -a IPV6_SETTINGS=("net.ipv6.conf.all.disable_ipv6" "net.ipv6.conf.default.disable_ipv6") - -for setting in "${IPV6_SETTINGS[@]}" -do - # Set runtime =1 for setting - /sbin/sysctl -q -n -w "$setting=1" - - # If setting is present in /etc/sysctl.conf, change value to "1" - # else, add "$setting = 1" to /etc/sysctl.conf - if grep -q ^"$setting" /etc/sysctl.conf ; then - sed -i "s/^$setting.*/$setting = 1/g" /etc/sysctl.conf - else - echo "" >> /etc/sysctl.conf - echo "# Set $setting = 1 per security requirements" >> /etc/sysctl.conf - echo "$setting = 1" >> /etc/sysctl.conf - fi -done - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Disable IPv6 Networking kernel module - lineinfile: - create: true - dest: /etc/modprobe.d/ipv6.conf - regexp: ^options\s+ipv6\s+disable=\d - line: options ipv6 disable=1 - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - kernel_module_ipv6_option_disabled - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - -- name: Ensure disable_ipv6 (all and default) is set to 1 - sysctl: - name: '{{ item }}' - value: '1' - state: present - reload: true - with_items: - - net.ipv6.conf.all.disable_ipv6 - - net.ipv6.conf.default.disable_ipv6 - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - kernel_module_ipv6_option_disabled - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - - - - - - - - - Disable IPv6 Addressing on All IPv6 Interfaces - To disable support for (ipv6) addressing on all interface add the following line to -/etc/sysctl.d/ipv6.conf (or another file in /etc/sysctl.d): -net.ipv6.conf.all.disable_ipv6 = 1 -This disables IPv6 on all network interfaces as other services and system -functionality require the IPv6 stack loaded to work. - BP28(R13) - 11 - 14 - 3 - 9 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS05.02 - DSS05.05 - DSS06.06 - 3.1.20 - CCI-001551 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 7.6 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.9.1.2 - CM-7(a) - CM-7(b) - CM-6(a) - PR.IP-1 - PR.PT-3 - Any unnecessary network stacks - including IPv6 - should be disabled, to reduce -the vulnerability to exploitation. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Comment out any occurrences of net.ipv6.conf.all.disable_ipv6 from /etc/sysctl.d/*.conf files - -for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do - - matching_list=$(grep -P '^(?!#).*[\s]*net.ipv6.conf.all.disable_ipv6.*$' $f | uniq ) - if ! test -z "$matching_list"; then - while IFS= read -r entry; do - escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") - # comment out "net.ipv6.conf.all.disable_ipv6" matches to preserve user data - sed -i "s/^${escaped_entry}$/# &/g" $f - done <<< "$matching_list" - fi -done - -# -# Set sysctl config file which to save the desired value -# - -SYSCONFIG_FILE="/etc/sysctl.conf" - - -# -# Set runtime for net.ipv6.conf.all.disable_ipv6 -# -/sbin/sysctl -q -n -w net.ipv6.conf.all.disable_ipv6="1" - -# -# If net.ipv6.conf.all.disable_ipv6 present in /etc/sysctl.conf, change value to "1" -# else, add "net.ipv6.conf.all.disable_ipv6 = 1" to /etc/sysctl.conf -# - -# Strip any search characters in the key arg so that the key can be replaced without -# adding any search characters to the config file. -stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv6.conf.all.disable_ipv6") - -# shellcheck disable=SC2059 -printf -v formatted_output "%s = %s" "$stripped_key" "1" - -# If the key exists, change it. Otherwise, add it to the config_file. -# We search for the key string followed by a word boundary (matched by \>), -# so if we search for 'setting', 'setting2' won't match. -if LC_ALL=C grep -q -m 1 -i -e "^net.ipv6.conf.all.disable_ipv6\\>" "${SYSCONFIG_FILE}"; then - escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") - LC_ALL=C sed -i --follow-symlinks "s/^net.ipv6.conf.all.disable_ipv6\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" -else - if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then - LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" - fi - printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: List /etc/sysctl.d/*.conf files - find: - paths: - - /etc/sysctl.d/ - - /run/sysctl.d/ - - /usr/local/lib/sysctl.d/ - contains: ^[\s]*net.ipv6.conf.all.disable_ipv6.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.20 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv6_conf_all_disable_ipv6 - -- name: Comment out any occurrences of net.ipv6.conf.all.disable_ipv6 from config - files - replace: - path: '{{ item.path }}' - regexp: ^[\s]*net.ipv6.conf.all.disable_ipv6 - replace: '#net.ipv6.conf.all.disable_ipv6' - loop: '{{ find_sysctl_d.files }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.20 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv6_conf_all_disable_ipv6 - -- name: Ensure sysctl net.ipv6.conf.all.disable_ipv6 is set to 1 - sysctl: - name: net.ipv6.conf.all.disable_ipv6 - value: '1' - sysctl_file: /etc/sysctl.conf - state: present - reload: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.20 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv6_conf_all_disable_ipv6 - - - - - - - - - - Disable IPv6 Addressing on IPv6 Interfaces by Default - To disable support for (ipv6) addressing on interfaces by default add the following line to -/etc/sysctl.d/ipv6.conf (or another file in /etc/sysctl.d): -net.ipv6.conf.default.disable_ipv6 = 1 -This disables IPv6 on network interfaces by default as other services and system -functionality require the IPv6 stack loaded to work. - BP28(R13) - 11 - 14 - 3 - 9 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS05.02 - DSS05.05 - DSS06.06 - 3.1.20 - CCI-001551 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 7.6 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.9.1.2 - CM-7(a) - CM-7(b) - CM-6(a) - PR.IP-1 - PR.PT-3 - Any unnecessary network stacks - including IPv6 - should be disabled, to reduce -the vulnerability to exploitation. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Comment out any occurrences of net.ipv6.conf.default.disable_ipv6 from /etc/sysctl.d/*.conf files - -for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do - - matching_list=$(grep -P '^(?!#).*[\s]*net.ipv6.conf.default.disable_ipv6.*$' $f | uniq ) - if ! test -z "$matching_list"; then - while IFS= read -r entry; do - escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") - # comment out "net.ipv6.conf.default.disable_ipv6" matches to preserve user data - sed -i "s/^${escaped_entry}$/# &/g" $f - done <<< "$matching_list" - fi -done - -# -# Set sysctl config file which to save the desired value -# - -SYSCONFIG_FILE="/etc/sysctl.conf" - - -# -# Set runtime for net.ipv6.conf.default.disable_ipv6 -# -/sbin/sysctl -q -n -w net.ipv6.conf.default.disable_ipv6="1" - -# -# If net.ipv6.conf.default.disable_ipv6 present in /etc/sysctl.conf, change value to "1" -# else, add "net.ipv6.conf.default.disable_ipv6 = 1" to /etc/sysctl.conf -# - -# Strip any search characters in the key arg so that the key can be replaced without -# adding any search characters to the config file. -stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv6.conf.default.disable_ipv6") - -# shellcheck disable=SC2059 -printf -v formatted_output "%s = %s" "$stripped_key" "1" - -# If the key exists, change it. Otherwise, add it to the config_file. -# We search for the key string followed by a word boundary (matched by \>), -# so if we search for 'setting', 'setting2' won't match. -if LC_ALL=C grep -q -m 1 -i -e "^net.ipv6.conf.default.disable_ipv6\\>" "${SYSCONFIG_FILE}"; then - escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") - LC_ALL=C sed -i --follow-symlinks "s/^net.ipv6.conf.default.disable_ipv6\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" -else - if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then - LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" - fi - printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: List /etc/sysctl.d/*.conf files - find: - paths: - - /etc/sysctl.d/ - - /run/sysctl.d/ - - /usr/local/lib/sysctl.d/ - contains: ^[\s]*net.ipv6.conf.default.disable_ipv6.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.20 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv6_conf_default_disable_ipv6 - -- name: Comment out any occurrences of net.ipv6.conf.default.disable_ipv6 from config - files - replace: - path: '{{ item.path }}' - regexp: ^[\s]*net.ipv6.conf.default.disable_ipv6 - replace: '#net.ipv6.conf.default.disable_ipv6' - loop: '{{ find_sysctl_d.files }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.20 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv6_conf_default_disable_ipv6 - -- name: Ensure sysctl net.ipv6.conf.default.disable_ipv6 is set to 1 - sysctl: - name: net.ipv6.conf.default.disable_ipv6 - value: '1' - sysctl_file: /etc/sysctl.conf - state: present - reload: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.20 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv6_conf_default_disable_ipv6 - - - - - - - - - - - Configure IPv6 Settings if Necessary - A major feature of IPv6 is the extent to which systems -implementing it can automatically configure their networking -devices using information from the network. From a security -perspective, manually configuring important configuration -information is preferable to accepting it from the network -in an unauthenticated fashion. - - - IPV6_AUTOCONF - Toggle global IPv6 auto-configuration (only, if global -forwarding is disabled) - no - no - yes - - - net.ipv6.conf.all.accept_ra_defrtr - Accept default router in router advertisements? - 0 - 0 - 1 - - - net.ipv6.conf.all.accept_ra_pinfo - Accept prefix information in router advertisements? - 0 - 0 - 1 - - - net.ipv6.conf.all.accept_ra_rtr_pref - Accept router preference in router advertisements? - 0 - 0 - 1 - - - net.ipv6.conf.all.accept_ra - Accept all router advertisements? - 0 - 0 - 1 - - - net.ipv6.conf.all.accept_redirects - Toggle ICMP Redirect Acceptance - 0 - 0 - 1 - - - net.ipv6.conf.all.accept_source_route - Trackers could be using source-routed packets to -generate traffic that seems to be intra-net, but actually was -created outside and has been redirected. - 0 - 0 - 1 - - - net.ipv6.conf.all.autoconf - Enable auto configuration on IPv6 interfaces - 0 - 0 - 1 - - - net.ipv6.conf.all.forwarding - Toggle IPv6 Forwarding - 0 - 0 - 1 - - - net.ipv6.conf.all.max_addresses - Maximum number of autoconfigured IPv6 addresses - 1 - - - net.ipv6.conf.all.router_solicitations - Accept all router solicitations? - 0 - 0 - 1 - - - net.ipv6.conf.default.accept_ra_defrtr - Accept default router in router advertisements? - 0 - 0 - 1 - - - net.ipv6.conf.default.accept_ra_pinfo - Accept prefix information in router advertisements? - 0 - 0 - 1 - - - net.ipv6.conf.default.accept_ra_rtr_pref - Accept router preference in router advertisements? - 0 - 0 - 1 - - - net.ipv6.conf.default.accept_ra - Accept default router advertisements by default? - 0 - 0 - 1 - - - net.ipv6.conf.default.accept_redirects - Toggle ICMP Redirect Acceptance By Default - 0 - 0 - 1 - - - net.ipv6.conf.default.accept_source_route - Trackers could be using source-routed packets to -generate traffic that seems to be intra-net, but actually was -created outside and has been redirected. - 0 - 0 - 1 - - - net.ipv6.conf.default.autoconf - Enable auto configuration on IPv6 interfaces - 0 - 0 - 1 - - - net.ipv6.conf.default.forwarding - Toggle IPv6 default Forwarding - 0 - 0 - 1 - - - net.ipv6.conf.default.max_addresses - Maximum number of autoconfigured IPv6 addresses - 1 - - - net.ipv6.conf.default.router_solicitations - Accept all router solicitations by default? - 0 - 0 - 1 - - - Configure Accepting Router Advertisements on All IPv6 Interfaces - To set the runtime status of the net.ipv6.conf.all.accept_ra kernel parameter, run the following command: $ sudo sysctl -w net.ipv6.conf.all.accept_ra=0 -To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv6.conf.all.accept_ra = 0 - 11 - 14 - 3 - 9 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS05.02 - DSS05.05 - DSS06.06 - 3.1.20 - CCI-000366 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 7.6 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.9.1.2 - CM-7(a) - CM-7(b) - CM-6(a) - PR.IP-1 - PR.PT-3 - SRG-OS-000480-GPOS-00227 - An illicit router advertisement message could result in a man-in-the-middle attack. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Comment out any occurrences of net.ipv6.conf.all.accept_ra from /etc/sysctl.d/*.conf files - -for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do - - matching_list=$(grep -P '^(?!#).*[\s]*net.ipv6.conf.all.accept_ra.*$' $f | uniq ) - if ! test -z "$matching_list"; then - while IFS= read -r entry; do - escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") - # comment out "net.ipv6.conf.all.accept_ra" matches to preserve user data - sed -i "s/^${escaped_entry}$/# &/g" $f - done <<< "$matching_list" - fi -done - -# -# Set sysctl config file which to save the desired value -# - -SYSCONFIG_FILE="/etc/sysctl.conf" - -sysctl_net_ipv6_conf_all_accept_ra_value='' - - -# -# Set runtime for net.ipv6.conf.all.accept_ra -# -/sbin/sysctl -q -n -w net.ipv6.conf.all.accept_ra="$sysctl_net_ipv6_conf_all_accept_ra_value" - -# -# If net.ipv6.conf.all.accept_ra present in /etc/sysctl.conf, change value to appropriate value -# else, add "net.ipv6.conf.all.accept_ra = value" to /etc/sysctl.conf -# - -# Strip any search characters in the key arg so that the key can be replaced without -# adding any search characters to the config file. -stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv6.conf.all.accept_ra") - -# shellcheck disable=SC2059 -printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv6_conf_all_accept_ra_value" - -# If the key exists, change it. Otherwise, add it to the config_file. -# We search for the key string followed by a word boundary (matched by \>), -# so if we search for 'setting', 'setting2' won't match. -if LC_ALL=C grep -q -m 1 -i -e "^net.ipv6.conf.all.accept_ra\\>" "${SYSCONFIG_FILE}"; then - escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") - LC_ALL=C sed -i --follow-symlinks "s/^net.ipv6.conf.all.accept_ra\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" -else - if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then - LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" - fi - printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: List /etc/sysctl.d/*.conf files - find: - paths: - - /etc/sysctl.d/ - - /run/sysctl.d/ - - /usr/local/lib/sysctl.d/ - contains: ^[\s]*net.ipv6.conf.all.accept_ra.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.20 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv6_conf_all_accept_ra - -- name: Comment out any occurrences of net.ipv6.conf.all.accept_ra from config files - replace: - path: '{{ item.path }}' - regexp: ^[\s]*net.ipv6.conf.all.accept_ra - replace: '#net.ipv6.conf.all.accept_ra' - loop: '{{ find_sysctl_d.files }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.20 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv6_conf_all_accept_ra -- name: XCCDF Value sysctl_net_ipv6_conf_all_accept_ra_value # promote to variable - set_fact: - sysctl_net_ipv6_conf_all_accept_ra_value: !!str - tags: - - always - -- name: Ensure sysctl net.ipv6.conf.all.accept_ra is set - sysctl: - name: net.ipv6.conf.all.accept_ra - value: '{{ sysctl_net_ipv6_conf_all_accept_ra_value }}' - sysctl_file: /etc/sysctl.conf - state: present - reload: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.20 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv6_conf_all_accept_ra - - - - - - - - - - - Configure Accepting Default Router in Router Advertisements on All IPv6 Interfaces - To set the runtime status of the net.ipv6.conf.all.accept_ra_defrtr kernel parameter, run the following command: $ sudo sysctl -w net.ipv6.conf.all.accept_ra_defrtr=0 -To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv6.conf.all.accept_ra_defrtr = 0 - BP28(R22) - An illicit router advertisement message could result in a man-in-the-middle attack. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Comment out any occurrences of net.ipv6.conf.all.accept_ra_defrtr from /etc/sysctl.d/*.conf files - -for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do - - matching_list=$(grep -P '^(?!#).*[\s]*net.ipv6.conf.all.accept_ra_defrtr.*$' $f | uniq ) - if ! test -z "$matching_list"; then - while IFS= read -r entry; do - escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") - # comment out "net.ipv6.conf.all.accept_ra_defrtr" matches to preserve user data - sed -i "s/^${escaped_entry}$/# &/g" $f - done <<< "$matching_list" - fi -done - -# -# Set sysctl config file which to save the desired value -# - -SYSCONFIG_FILE="/etc/sysctl.conf" - -sysctl_net_ipv6_conf_all_accept_ra_defrtr_value='' - - -# -# Set runtime for net.ipv6.conf.all.accept_ra_defrtr -# -/sbin/sysctl -q -n -w net.ipv6.conf.all.accept_ra_defrtr="$sysctl_net_ipv6_conf_all_accept_ra_defrtr_value" - -# -# If net.ipv6.conf.all.accept_ra_defrtr present in /etc/sysctl.conf, change value to appropriate value -# else, add "net.ipv6.conf.all.accept_ra_defrtr = value" to /etc/sysctl.conf -# - -# Strip any search characters in the key arg so that the key can be replaced without -# adding any search characters to the config file. -stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv6.conf.all.accept_ra_defrtr") - -# shellcheck disable=SC2059 -printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv6_conf_all_accept_ra_defrtr_value" - -# If the key exists, change it. Otherwise, add it to the config_file. -# We search for the key string followed by a word boundary (matched by \>), -# so if we search for 'setting', 'setting2' won't match. -if LC_ALL=C grep -q -m 1 -i -e "^net.ipv6.conf.all.accept_ra_defrtr\\>" "${SYSCONFIG_FILE}"; then - escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") - LC_ALL=C sed -i --follow-symlinks "s/^net.ipv6.conf.all.accept_ra_defrtr\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" -else - if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then - LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" - fi - printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: List /etc/sysctl.d/*.conf files - find: - paths: - - /etc/sysctl.d/ - - /run/sysctl.d/ - - /usr/local/lib/sysctl.d/ - contains: ^[\s]*net.ipv6.conf.all.accept_ra_defrtr.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - reboot_required - - sysctl_net_ipv6_conf_all_accept_ra_defrtr - - unknown_severity - -- name: Comment out any occurrences of net.ipv6.conf.all.accept_ra_defrtr from config - files - replace: - path: '{{ item.path }}' - regexp: ^[\s]*net.ipv6.conf.all.accept_ra_defrtr - replace: '#net.ipv6.conf.all.accept_ra_defrtr' - loop: '{{ find_sysctl_d.files }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - reboot_required - - sysctl_net_ipv6_conf_all_accept_ra_defrtr - - unknown_severity -- name: XCCDF Value sysctl_net_ipv6_conf_all_accept_ra_defrtr_value # promote to variable - set_fact: - sysctl_net_ipv6_conf_all_accept_ra_defrtr_value: !!str - tags: - - always - -- name: Ensure sysctl net.ipv6.conf.all.accept_ra_defrtr is set - sysctl: - name: net.ipv6.conf.all.accept_ra_defrtr - value: '{{ sysctl_net_ipv6_conf_all_accept_ra_defrtr_value }}' - sysctl_file: /etc/sysctl.conf - state: present - reload: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - reboot_required - - sysctl_net_ipv6_conf_all_accept_ra_defrtr - - unknown_severity - - - - - - - - - - - Configure Accepting Prefix Information in Router Advertisements on All IPv6 Interfaces - To set the runtime status of the net.ipv6.conf.all.accept_ra_pinfo kernel parameter, run the following command: $ sudo sysctl -w net.ipv6.conf.all.accept_ra_pinfo=0 -To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv6.conf.all.accept_ra_pinfo = 0 - BP28(R22) - An illicit router advertisement message could result in a man-in-the-middle attack. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Comment out any occurrences of net.ipv6.conf.all.accept_ra_pinfo from /etc/sysctl.d/*.conf files - -for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do - - matching_list=$(grep -P '^(?!#).*[\s]*net.ipv6.conf.all.accept_ra_pinfo.*$' $f | uniq ) - if ! test -z "$matching_list"; then - while IFS= read -r entry; do - escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") - # comment out "net.ipv6.conf.all.accept_ra_pinfo" matches to preserve user data - sed -i "s/^${escaped_entry}$/# &/g" $f - done <<< "$matching_list" - fi -done - -# -# Set sysctl config file which to save the desired value -# - -SYSCONFIG_FILE="/etc/sysctl.conf" - -sysctl_net_ipv6_conf_all_accept_ra_pinfo_value='' - - -# -# Set runtime for net.ipv6.conf.all.accept_ra_pinfo -# -/sbin/sysctl -q -n -w net.ipv6.conf.all.accept_ra_pinfo="$sysctl_net_ipv6_conf_all_accept_ra_pinfo_value" - -# -# If net.ipv6.conf.all.accept_ra_pinfo present in /etc/sysctl.conf, change value to appropriate value -# else, add "net.ipv6.conf.all.accept_ra_pinfo = value" to /etc/sysctl.conf -# - -# Strip any search characters in the key arg so that the key can be replaced without -# adding any search characters to the config file. -stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv6.conf.all.accept_ra_pinfo") - -# shellcheck disable=SC2059 -printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv6_conf_all_accept_ra_pinfo_value" - -# If the key exists, change it. Otherwise, add it to the config_file. -# We search for the key string followed by a word boundary (matched by \>), -# so if we search for 'setting', 'setting2' won't match. -if LC_ALL=C grep -q -m 1 -i -e "^net.ipv6.conf.all.accept_ra_pinfo\\>" "${SYSCONFIG_FILE}"; then - escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") - LC_ALL=C sed -i --follow-symlinks "s/^net.ipv6.conf.all.accept_ra_pinfo\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" -else - if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then - LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" - fi - printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: List /etc/sysctl.d/*.conf files - find: - paths: - - /etc/sysctl.d/ - - /run/sysctl.d/ - - /usr/local/lib/sysctl.d/ - contains: ^[\s]*net.ipv6.conf.all.accept_ra_pinfo.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - reboot_required - - sysctl_net_ipv6_conf_all_accept_ra_pinfo - - unknown_severity - -- name: Comment out any occurrences of net.ipv6.conf.all.accept_ra_pinfo from config - files - replace: - path: '{{ item.path }}' - regexp: ^[\s]*net.ipv6.conf.all.accept_ra_pinfo - replace: '#net.ipv6.conf.all.accept_ra_pinfo' - loop: '{{ find_sysctl_d.files }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - reboot_required - - sysctl_net_ipv6_conf_all_accept_ra_pinfo - - unknown_severity -- name: XCCDF Value sysctl_net_ipv6_conf_all_accept_ra_pinfo_value # promote to variable - set_fact: - sysctl_net_ipv6_conf_all_accept_ra_pinfo_value: !!str - tags: - - always - -- name: Ensure sysctl net.ipv6.conf.all.accept_ra_pinfo is set - sysctl: - name: net.ipv6.conf.all.accept_ra_pinfo - value: '{{ sysctl_net_ipv6_conf_all_accept_ra_pinfo_value }}' - sysctl_file: /etc/sysctl.conf - state: present - reload: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - reboot_required - - sysctl_net_ipv6_conf_all_accept_ra_pinfo - - unknown_severity - - - - - - - - - - - Configure Accepting Router Preference in Router Advertisements on All IPv6 Interfaces - To set the runtime status of the net.ipv6.conf.all.accept_ra_rtr_pref kernel parameter, run the following command: $ sudo sysctl -w net.ipv6.conf.all.accept_ra_rtr_pref=0 -To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv6.conf.all.accept_ra_rtr_pref = 0 - BP28(R22) - An illicit router advertisement message could result in a man-in-the-middle attack. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Comment out any occurrences of net.ipv6.conf.all.accept_ra_rtr_pref from /etc/sysctl.d/*.conf files - -for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do - - matching_list=$(grep -P '^(?!#).*[\s]*net.ipv6.conf.all.accept_ra_rtr_pref.*$' $f | uniq ) - if ! test -z "$matching_list"; then - while IFS= read -r entry; do - escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") - # comment out "net.ipv6.conf.all.accept_ra_rtr_pref" matches to preserve user data - sed -i "s/^${escaped_entry}$/# &/g" $f - done <<< "$matching_list" - fi -done - -# -# Set sysctl config file which to save the desired value -# - -SYSCONFIG_FILE="/etc/sysctl.conf" - -sysctl_net_ipv6_conf_all_accept_ra_rtr_pref_value='' - - -# -# Set runtime for net.ipv6.conf.all.accept_ra_rtr_pref -# -/sbin/sysctl -q -n -w net.ipv6.conf.all.accept_ra_rtr_pref="$sysctl_net_ipv6_conf_all_accept_ra_rtr_pref_value" - -# -# If net.ipv6.conf.all.accept_ra_rtr_pref present in /etc/sysctl.conf, change value to appropriate value -# else, add "net.ipv6.conf.all.accept_ra_rtr_pref = value" to /etc/sysctl.conf -# - -# Strip any search characters in the key arg so that the key can be replaced without -# adding any search characters to the config file. -stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv6.conf.all.accept_ra_rtr_pref") - -# shellcheck disable=SC2059 -printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv6_conf_all_accept_ra_rtr_pref_value" - -# If the key exists, change it. Otherwise, add it to the config_file. -# We search for the key string followed by a word boundary (matched by \>), -# so if we search for 'setting', 'setting2' won't match. -if LC_ALL=C grep -q -m 1 -i -e "^net.ipv6.conf.all.accept_ra_rtr_pref\\>" "${SYSCONFIG_FILE}"; then - escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") - LC_ALL=C sed -i --follow-symlinks "s/^net.ipv6.conf.all.accept_ra_rtr_pref\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" -else - if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then - LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" - fi - printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: List /etc/sysctl.d/*.conf files - find: - paths: - - /etc/sysctl.d/ - - /run/sysctl.d/ - - /usr/local/lib/sysctl.d/ - contains: ^[\s]*net.ipv6.conf.all.accept_ra_rtr_pref.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - reboot_required - - sysctl_net_ipv6_conf_all_accept_ra_rtr_pref - - unknown_severity - -- name: Comment out any occurrences of net.ipv6.conf.all.accept_ra_rtr_pref from config - files - replace: - path: '{{ item.path }}' - regexp: ^[\s]*net.ipv6.conf.all.accept_ra_rtr_pref - replace: '#net.ipv6.conf.all.accept_ra_rtr_pref' - loop: '{{ find_sysctl_d.files }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - reboot_required - - sysctl_net_ipv6_conf_all_accept_ra_rtr_pref - - unknown_severity -- name: XCCDF Value sysctl_net_ipv6_conf_all_accept_ra_rtr_pref_value # promote to variable - set_fact: - sysctl_net_ipv6_conf_all_accept_ra_rtr_pref_value: !!str - tags: - - always - -- name: Ensure sysctl net.ipv6.conf.all.accept_ra_rtr_pref is set - sysctl: - name: net.ipv6.conf.all.accept_ra_rtr_pref - value: '{{ sysctl_net_ipv6_conf_all_accept_ra_rtr_pref_value }}' - sysctl_file: /etc/sysctl.conf - state: present - reload: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - reboot_required - - sysctl_net_ipv6_conf_all_accept_ra_rtr_pref - - unknown_severity - - - - - - - - - - - Disable Accepting ICMP Redirects for All IPv6 Interfaces - To set the runtime status of the net.ipv6.conf.all.accept_redirects kernel parameter, run the following command: $ sudo sysctl -w net.ipv6.conf.all.accept_redirects=0 -To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv6.conf.all.accept_redirects = 0 - BP28(R22) - 11 - 14 - 3 - 9 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS05.02 - DSS05.05 - DSS06.06 - 3.1.20 - CCI-000366 - CCI-001551 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 7.6 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.9.1.2 - CM-7(a) - CM-7(b) - CM-6(a) - CM-6(b) - CM-6.1(iv) - PR.IP-1 - PR.PT-3 - SRG-OS-000480-GPOS-00227 - An illicit ICMP redirect message could result in a man-in-the-middle attack. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Comment out any occurrences of net.ipv6.conf.all.accept_redirects from /etc/sysctl.d/*.conf files - -for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do - - matching_list=$(grep -P '^(?!#).*[\s]*net.ipv6.conf.all.accept_redirects.*$' $f | uniq ) - if ! test -z "$matching_list"; then - while IFS= read -r entry; do - escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") - # comment out "net.ipv6.conf.all.accept_redirects" matches to preserve user data - sed -i "s/^${escaped_entry}$/# &/g" $f - done <<< "$matching_list" - fi -done - -# -# Set sysctl config file which to save the desired value -# - -SYSCONFIG_FILE="/etc/sysctl.conf" - -sysctl_net_ipv6_conf_all_accept_redirects_value='' - - -# -# Set runtime for net.ipv6.conf.all.accept_redirects -# -/sbin/sysctl -q -n -w net.ipv6.conf.all.accept_redirects="$sysctl_net_ipv6_conf_all_accept_redirects_value" - -# -# If net.ipv6.conf.all.accept_redirects present in /etc/sysctl.conf, change value to appropriate value -# else, add "net.ipv6.conf.all.accept_redirects = value" to /etc/sysctl.conf -# - -# Strip any search characters in the key arg so that the key can be replaced without -# adding any search characters to the config file. -stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv6.conf.all.accept_redirects") - -# shellcheck disable=SC2059 -printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv6_conf_all_accept_redirects_value" - -# If the key exists, change it. Otherwise, add it to the config_file. -# We search for the key string followed by a word boundary (matched by \>), -# so if we search for 'setting', 'setting2' won't match. -if LC_ALL=C grep -q -m 1 -i -e "^net.ipv6.conf.all.accept_redirects\\>" "${SYSCONFIG_FILE}"; then - escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") - LC_ALL=C sed -i --follow-symlinks "s/^net.ipv6.conf.all.accept_redirects\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" -else - if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then - LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" - fi - printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: List /etc/sysctl.d/*.conf files - find: - paths: - - /etc/sysctl.d/ - - /run/sysctl.d/ - - /usr/local/lib/sysctl.d/ - contains: ^[\s]*net.ipv6.conf.all.accept_redirects.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.20 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-6(b) - - NIST-800-53-CM-6.1(iv) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv6_conf_all_accept_redirects - -- name: Comment out any occurrences of net.ipv6.conf.all.accept_redirects from config - files - replace: - path: '{{ item.path }}' - regexp: ^[\s]*net.ipv6.conf.all.accept_redirects - replace: '#net.ipv6.conf.all.accept_redirects' - loop: '{{ find_sysctl_d.files }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.20 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-6(b) - - NIST-800-53-CM-6.1(iv) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv6_conf_all_accept_redirects -- name: XCCDF Value sysctl_net_ipv6_conf_all_accept_redirects_value # promote to variable - set_fact: - sysctl_net_ipv6_conf_all_accept_redirects_value: !!str - tags: - - always - -- name: Ensure sysctl net.ipv6.conf.all.accept_redirects is set - sysctl: - name: net.ipv6.conf.all.accept_redirects - value: '{{ sysctl_net_ipv6_conf_all_accept_redirects_value }}' - sysctl_file: /etc/sysctl.conf - state: present - reload: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.20 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-6(b) - - NIST-800-53-CM-6.1(iv) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv6_conf_all_accept_redirects - - - - - - - - - - - Disable Kernel Parameter for Accepting Source-Routed Packets on all IPv6 Interfaces - To set the runtime status of the net.ipv6.conf.all.accept_source_route kernel parameter, run the following command: $ sudo sysctl -w net.ipv6.conf.all.accept_source_route=0 -To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv6.conf.all.accept_source_route = 0 - BP28(R22) - 1 - 12 - 13 - 14 - 15 - 16 - 18 - 4 - 6 - 8 - 9 - APO01.06 - APO13.01 - DSS01.05 - DSS03.01 - DSS05.02 - DSS05.04 - DSS05.07 - DSS06.02 - 3.1.20 - CCI-000366 - 4.2.3.4 - 4.3.3.4 - 4.4.3.3 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 7.1 - SR 7.6 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.12.1.1 - A.12.1.2 - A.13.1.1 - A.13.1.2 - A.13.1.3 - A.13.2.1 - A.13.2.2 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CM-7(a) - CM-7(b) - CM-6(a) - DE.AE-1 - ID.AM-3 - PR.AC-5 - PR.DS-5 - PR.PT-4 - SRG-OS-000480-GPOS-00227 - Source-routed packets allow the source of the packet to suggest routers -forward the packet along a different path than configured on the router, which can -be used to bypass network security measures. This requirement applies only to the -forwarding of source-routerd traffic, such as when IPv6 forwarding is enabled and -the system is functioning as a router. - -Accepting source-routed packets in the IPv6 protocol has few legitimate -uses. It should be disabled unless it is absolutely required. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Comment out any occurrences of net.ipv6.conf.all.accept_source_route from /etc/sysctl.d/*.conf files - -for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do - - matching_list=$(grep -P '^(?!#).*[\s]*net.ipv6.conf.all.accept_source_route.*$' $f | uniq ) - if ! test -z "$matching_list"; then - while IFS= read -r entry; do - escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") - # comment out "net.ipv6.conf.all.accept_source_route" matches to preserve user data - sed -i "s/^${escaped_entry}$/# &/g" $f - done <<< "$matching_list" - fi -done - -# -# Set sysctl config file which to save the desired value -# - -SYSCONFIG_FILE="/etc/sysctl.conf" - -sysctl_net_ipv6_conf_all_accept_source_route_value='' - - -# -# Set runtime for net.ipv6.conf.all.accept_source_route -# -/sbin/sysctl -q -n -w net.ipv6.conf.all.accept_source_route="$sysctl_net_ipv6_conf_all_accept_source_route_value" - -# -# If net.ipv6.conf.all.accept_source_route present in /etc/sysctl.conf, change value to appropriate value -# else, add "net.ipv6.conf.all.accept_source_route = value" to /etc/sysctl.conf -# - -# Strip any search characters in the key arg so that the key can be replaced without -# adding any search characters to the config file. -stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv6.conf.all.accept_source_route") - -# shellcheck disable=SC2059 -printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv6_conf_all_accept_source_route_value" - -# If the key exists, change it. Otherwise, add it to the config_file. -# We search for the key string followed by a word boundary (matched by \>), -# so if we search for 'setting', 'setting2' won't match. -if LC_ALL=C grep -q -m 1 -i -e "^net.ipv6.conf.all.accept_source_route\\>" "${SYSCONFIG_FILE}"; then - escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") - LC_ALL=C sed -i --follow-symlinks "s/^net.ipv6.conf.all.accept_source_route\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" -else - if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then - LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" - fi - printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: List /etc/sysctl.d/*.conf files - find: - paths: - - /etc/sysctl.d/ - - /run/sysctl.d/ - - /usr/local/lib/sysctl.d/ - contains: ^[\s]*net.ipv6.conf.all.accept_source_route.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.20 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv6_conf_all_accept_source_route - -- name: Comment out any occurrences of net.ipv6.conf.all.accept_source_route from - config files - replace: - path: '{{ item.path }}' - regexp: ^[\s]*net.ipv6.conf.all.accept_source_route - replace: '#net.ipv6.conf.all.accept_source_route' - loop: '{{ find_sysctl_d.files }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.20 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv6_conf_all_accept_source_route -- name: XCCDF Value sysctl_net_ipv6_conf_all_accept_source_route_value # promote to variable - set_fact: - sysctl_net_ipv6_conf_all_accept_source_route_value: !!str - tags: - - always - -- name: Ensure sysctl net.ipv6.conf.all.accept_source_route is set - sysctl: - name: net.ipv6.conf.all.accept_source_route - value: '{{ sysctl_net_ipv6_conf_all_accept_source_route_value }}' - sysctl_file: /etc/sysctl.conf - state: present - reload: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.20 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv6_conf_all_accept_source_route - - - - - - - - - - - Configure Auto Configuration on All IPv6 Interfaces - To set the runtime status of the net.ipv6.conf.all.autoconf kernel parameter, run the following command: $ sudo sysctl -w net.ipv6.conf.all.autoconf=0 -To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv6.conf.all.autoconf = 0 - BP28(R22) - An illicit router advertisement message could result in a man-in-the-middle attack. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Comment out any occurrences of net.ipv6.conf.all.autoconf from /etc/sysctl.d/*.conf files - -for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do - - matching_list=$(grep -P '^(?!#).*[\s]*net.ipv6.conf.all.autoconf.*$' $f | uniq ) - if ! test -z "$matching_list"; then - while IFS= read -r entry; do - escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") - # comment out "net.ipv6.conf.all.autoconf" matches to preserve user data - sed -i "s/^${escaped_entry}$/# &/g" $f - done <<< "$matching_list" - fi -done - -# -# Set sysctl config file which to save the desired value -# - -SYSCONFIG_FILE="/etc/sysctl.conf" - -sysctl_net_ipv6_conf_all_autoconf_value='' - - -# -# Set runtime for net.ipv6.conf.all.autoconf -# -/sbin/sysctl -q -n -w net.ipv6.conf.all.autoconf="$sysctl_net_ipv6_conf_all_autoconf_value" - -# -# If net.ipv6.conf.all.autoconf present in /etc/sysctl.conf, change value to appropriate value -# else, add "net.ipv6.conf.all.autoconf = value" to /etc/sysctl.conf -# - -# Strip any search characters in the key arg so that the key can be replaced without -# adding any search characters to the config file. -stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv6.conf.all.autoconf") - -# shellcheck disable=SC2059 -printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv6_conf_all_autoconf_value" - -# If the key exists, change it. Otherwise, add it to the config_file. -# We search for the key string followed by a word boundary (matched by \>), -# so if we search for 'setting', 'setting2' won't match. -if LC_ALL=C grep -q -m 1 -i -e "^net.ipv6.conf.all.autoconf\\>" "${SYSCONFIG_FILE}"; then - escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") - LC_ALL=C sed -i --follow-symlinks "s/^net.ipv6.conf.all.autoconf\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" -else - if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then - LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" - fi - printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: List /etc/sysctl.d/*.conf files - find: - paths: - - /etc/sysctl.d/ - - /run/sysctl.d/ - - /usr/local/lib/sysctl.d/ - contains: ^[\s]*net.ipv6.conf.all.autoconf.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - reboot_required - - sysctl_net_ipv6_conf_all_autoconf - - unknown_severity - -- name: Comment out any occurrences of net.ipv6.conf.all.autoconf from config files - replace: - path: '{{ item.path }}' - regexp: ^[\s]*net.ipv6.conf.all.autoconf - replace: '#net.ipv6.conf.all.autoconf' - loop: '{{ find_sysctl_d.files }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - reboot_required - - sysctl_net_ipv6_conf_all_autoconf - - unknown_severity -- name: XCCDF Value sysctl_net_ipv6_conf_all_autoconf_value # promote to variable - set_fact: - sysctl_net_ipv6_conf_all_autoconf_value: !!str - tags: - - always - -- name: Ensure sysctl net.ipv6.conf.all.autoconf is set - sysctl: - name: net.ipv6.conf.all.autoconf - value: '{{ sysctl_net_ipv6_conf_all_autoconf_value }}' - sysctl_file: /etc/sysctl.conf - state: present - reload: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - reboot_required - - sysctl_net_ipv6_conf_all_autoconf - - unknown_severity - - - - - - - - - - - Disable Kernel Parameter for IPv6 Forwarding - To set the runtime status of the net.ipv6.conf.all.forwarding kernel parameter, run the following command: $ sudo sysctl -w net.ipv6.conf.all.forwarding=0 -To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv6.conf.all.forwarding = 0 - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 2 - 3 - 7 - 8 - 9 - APO13.01 - BAI04.04 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS01.03 - DSS03.05 - DSS05.02 - DSS05.05 - DSS05.07 - DSS06.06 - CCI-000366 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 6.2 - SR 7.1 - SR 7.2 - SR 7.6 - A.12.1.2 - A.12.1.3 - A.12.5.1 - A.12.6.2 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.17.2.1 - A.9.1.2 - CM-7(a) - CM-7(b) - CM-6(a) - CM-6(b) - CM-6.1(iv) - DE.CM-1 - PR.DS-4 - PR.IP-1 - PR.PT-3 - SRG-OS-000480-GPOS-00227 - IP forwarding permits the kernel to forward packets from one network -interface to another. The ability to forward packets between two networks is -only appropriate for systems acting as routers. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Comment out any occurrences of net.ipv6.conf.all.forwarding from /etc/sysctl.d/*.conf files - -for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do - - matching_list=$(grep -P '^(?!#).*[\s]*net.ipv6.conf.all.forwarding.*$' $f | uniq ) - if ! test -z "$matching_list"; then - while IFS= read -r entry; do - escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") - # comment out "net.ipv6.conf.all.forwarding" matches to preserve user data - sed -i "s/^${escaped_entry}$/# &/g" $f - done <<< "$matching_list" - fi -done - -# -# Set sysctl config file which to save the desired value -# - -SYSCONFIG_FILE="/etc/sysctl.conf" - -sysctl_net_ipv6_conf_all_forwarding_value='' - - -# -# Set runtime for net.ipv6.conf.all.forwarding -# -/sbin/sysctl -q -n -w net.ipv6.conf.all.forwarding="$sysctl_net_ipv6_conf_all_forwarding_value" - -# -# If net.ipv6.conf.all.forwarding present in /etc/sysctl.conf, change value to appropriate value -# else, add "net.ipv6.conf.all.forwarding = value" to /etc/sysctl.conf -# - -# Strip any search characters in the key arg so that the key can be replaced without -# adding any search characters to the config file. -stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv6.conf.all.forwarding") - -# shellcheck disable=SC2059 -printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv6_conf_all_forwarding_value" - -# If the key exists, change it. Otherwise, add it to the config_file. -# We search for the key string followed by a word boundary (matched by \>), -# so if we search for 'setting', 'setting2' won't match. -if LC_ALL=C grep -q -m 1 -i -e "^net.ipv6.conf.all.forwarding\\>" "${SYSCONFIG_FILE}"; then - escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") - LC_ALL=C sed -i --follow-symlinks "s/^net.ipv6.conf.all.forwarding\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" -else - if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then - LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" - fi - printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: List /etc/sysctl.d/*.conf files - find: - paths: - - /etc/sysctl.d/ - - /run/sysctl.d/ - - /usr/local/lib/sysctl.d/ - contains: ^[\s]*net.ipv6.conf.all.forwarding.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-6(b) - - NIST-800-53-CM-6.1(iv) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv6_conf_all_forwarding - -- name: Comment out any occurrences of net.ipv6.conf.all.forwarding from config files - replace: - path: '{{ item.path }}' - regexp: ^[\s]*net.ipv6.conf.all.forwarding - replace: '#net.ipv6.conf.all.forwarding' - loop: '{{ find_sysctl_d.files }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-6(b) - - NIST-800-53-CM-6.1(iv) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv6_conf_all_forwarding -- name: XCCDF Value sysctl_net_ipv6_conf_all_forwarding_value # promote to variable - set_fact: - sysctl_net_ipv6_conf_all_forwarding_value: !!str - tags: - - always - -- name: Ensure sysctl net.ipv6.conf.all.forwarding is set - sysctl: - name: net.ipv6.conf.all.forwarding - value: '{{ sysctl_net_ipv6_conf_all_forwarding_value }}' - sysctl_file: /etc/sysctl.conf - state: present - reload: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-6(b) - - NIST-800-53-CM-6.1(iv) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv6_conf_all_forwarding - - - - - - - - - - - Configure Maximum Number of Autoconfigured Addresses on All IPv6 Interfaces - To set the runtime status of the net.ipv6.conf.all.max_addresses kernel parameter, run the following command: $ sudo sysctl -w net.ipv6.conf.all.max_addresses=1 -To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv6.conf.all.max_addresses = 1 - BP28(R22) - The number of global unicast IPv6 addresses for each interface should be limited exactly to the number of statically configured addresses. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Comment out any occurrences of net.ipv6.conf.all.max_addresses from /etc/sysctl.d/*.conf files - -for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do - - matching_list=$(grep -P '^(?!#).*[\s]*net.ipv6.conf.all.max_addresses.*$' $f | uniq ) - if ! test -z "$matching_list"; then - while IFS= read -r entry; do - escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") - # comment out "net.ipv6.conf.all.max_addresses" matches to preserve user data - sed -i "s/^${escaped_entry}$/# &/g" $f - done <<< "$matching_list" - fi -done - -# -# Set sysctl config file which to save the desired value -# - -SYSCONFIG_FILE="/etc/sysctl.conf" - -sysctl_net_ipv6_conf_all_max_addresses_value='' - - -# -# Set runtime for net.ipv6.conf.all.max_addresses -# -/sbin/sysctl -q -n -w net.ipv6.conf.all.max_addresses="$sysctl_net_ipv6_conf_all_max_addresses_value" - -# -# If net.ipv6.conf.all.max_addresses present in /etc/sysctl.conf, change value to appropriate value -# else, add "net.ipv6.conf.all.max_addresses = value" to /etc/sysctl.conf -# - -# Strip any search characters in the key arg so that the key can be replaced without -# adding any search characters to the config file. -stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv6.conf.all.max_addresses") - -# shellcheck disable=SC2059 -printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv6_conf_all_max_addresses_value" - -# If the key exists, change it. Otherwise, add it to the config_file. -# We search for the key string followed by a word boundary (matched by \>), -# so if we search for 'setting', 'setting2' won't match. -if LC_ALL=C grep -q -m 1 -i -e "^net.ipv6.conf.all.max_addresses\\>" "${SYSCONFIG_FILE}"; then - escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") - LC_ALL=C sed -i --follow-symlinks "s/^net.ipv6.conf.all.max_addresses\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" -else - if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then - LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" - fi - printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: List /etc/sysctl.d/*.conf files - find: - paths: - - /etc/sysctl.d/ - - /run/sysctl.d/ - - /usr/local/lib/sysctl.d/ - contains: ^[\s]*net.ipv6.conf.all.max_addresses.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - reboot_required - - sysctl_net_ipv6_conf_all_max_addresses - - unknown_severity - -- name: Comment out any occurrences of net.ipv6.conf.all.max_addresses from config - files - replace: - path: '{{ item.path }}' - regexp: ^[\s]*net.ipv6.conf.all.max_addresses - replace: '#net.ipv6.conf.all.max_addresses' - loop: '{{ find_sysctl_d.files }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - reboot_required - - sysctl_net_ipv6_conf_all_max_addresses - - unknown_severity -- name: XCCDF Value sysctl_net_ipv6_conf_all_max_addresses_value # promote to variable - set_fact: - sysctl_net_ipv6_conf_all_max_addresses_value: !!str - tags: - - always - -- name: Ensure sysctl net.ipv6.conf.all.max_addresses is set - sysctl: - name: net.ipv6.conf.all.max_addresses - value: '{{ sysctl_net_ipv6_conf_all_max_addresses_value }}' - sysctl_file: /etc/sysctl.conf - state: present - reload: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - reboot_required - - sysctl_net_ipv6_conf_all_max_addresses - - unknown_severity - - - - - - - - - - - Configure Denying Router Solicitations on All IPv6 Interfaces - To set the runtime status of the net.ipv6.conf.all.router_solicitations kernel parameter, run the following command: $ sudo sysctl -w net.ipv6.conf.all.router_solicitations=0 -To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv6.conf.all.router_solicitations = 0 - BP28(R22) - To prevent discovery of the system by other systems, router solicitation requests should be denied. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Comment out any occurrences of net.ipv6.conf.all.router_solicitations from /etc/sysctl.d/*.conf files - -for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do - - matching_list=$(grep -P '^(?!#).*[\s]*net.ipv6.conf.all.router_solicitations.*$' $f | uniq ) - if ! test -z "$matching_list"; then - while IFS= read -r entry; do - escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") - # comment out "net.ipv6.conf.all.router_solicitations" matches to preserve user data - sed -i "s/^${escaped_entry}$/# &/g" $f - done <<< "$matching_list" - fi -done - -# -# Set sysctl config file which to save the desired value -# - -SYSCONFIG_FILE="/etc/sysctl.conf" - -sysctl_net_ipv6_conf_all_router_solicitations_value='' - - -# -# Set runtime for net.ipv6.conf.all.router_solicitations -# -/sbin/sysctl -q -n -w net.ipv6.conf.all.router_solicitations="$sysctl_net_ipv6_conf_all_router_solicitations_value" - -# -# If net.ipv6.conf.all.router_solicitations present in /etc/sysctl.conf, change value to appropriate value -# else, add "net.ipv6.conf.all.router_solicitations = value" to /etc/sysctl.conf -# - -# Strip any search characters in the key arg so that the key can be replaced without -# adding any search characters to the config file. -stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv6.conf.all.router_solicitations") - -# shellcheck disable=SC2059 -printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv6_conf_all_router_solicitations_value" - -# If the key exists, change it. Otherwise, add it to the config_file. -# We search for the key string followed by a word boundary (matched by \>), -# so if we search for 'setting', 'setting2' won't match. -if LC_ALL=C grep -q -m 1 -i -e "^net.ipv6.conf.all.router_solicitations\\>" "${SYSCONFIG_FILE}"; then - escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") - LC_ALL=C sed -i --follow-symlinks "s/^net.ipv6.conf.all.router_solicitations\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" -else - if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then - LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" - fi - printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: List /etc/sysctl.d/*.conf files - find: - paths: - - /etc/sysctl.d/ - - /run/sysctl.d/ - - /usr/local/lib/sysctl.d/ - contains: ^[\s]*net.ipv6.conf.all.router_solicitations.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - reboot_required - - sysctl_net_ipv6_conf_all_router_solicitations - - unknown_severity - -- name: Comment out any occurrences of net.ipv6.conf.all.router_solicitations from - config files - replace: - path: '{{ item.path }}' - regexp: ^[\s]*net.ipv6.conf.all.router_solicitations - replace: '#net.ipv6.conf.all.router_solicitations' - loop: '{{ find_sysctl_d.files }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - reboot_required - - sysctl_net_ipv6_conf_all_router_solicitations - - unknown_severity -- name: XCCDF Value sysctl_net_ipv6_conf_all_router_solicitations_value # promote to variable - set_fact: - sysctl_net_ipv6_conf_all_router_solicitations_value: !!str - tags: - - always - -- name: Ensure sysctl net.ipv6.conf.all.router_solicitations is set - sysctl: - name: net.ipv6.conf.all.router_solicitations - value: '{{ sysctl_net_ipv6_conf_all_router_solicitations_value }}' - sysctl_file: /etc/sysctl.conf - state: present - reload: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - reboot_required - - sysctl_net_ipv6_conf_all_router_solicitations - - unknown_severity - - - - - - - - - - - Disable Accepting Router Advertisements on all IPv6 Interfaces by Default - To set the runtime status of the net.ipv6.conf.default.accept_ra kernel parameter, run the following command: $ sudo sysctl -w net.ipv6.conf.default.accept_ra=0 -To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv6.conf.default.accept_ra = 0 - 11 - 14 - 3 - 9 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS05.02 - DSS05.05 - DSS06.06 - 3.1.20 - CCI-000366 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 7.6 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.9.1.2 - CM-7(a) - CM-7(b) - CM-6(a) - PR.IP-1 - PR.PT-3 - SRG-OS-000480-GPOS-00227 - An illicit router advertisement message could result in a man-in-the-middle attack. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Comment out any occurrences of net.ipv6.conf.default.accept_ra from /etc/sysctl.d/*.conf files - -for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do - - matching_list=$(grep -P '^(?!#).*[\s]*net.ipv6.conf.default.accept_ra.*$' $f | uniq ) - if ! test -z "$matching_list"; then - while IFS= read -r entry; do - escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") - # comment out "net.ipv6.conf.default.accept_ra" matches to preserve user data - sed -i "s/^${escaped_entry}$/# &/g" $f - done <<< "$matching_list" - fi -done - -# -# Set sysctl config file which to save the desired value -# - -SYSCONFIG_FILE="/etc/sysctl.conf" - -sysctl_net_ipv6_conf_default_accept_ra_value='' - - -# -# Set runtime for net.ipv6.conf.default.accept_ra -# -/sbin/sysctl -q -n -w net.ipv6.conf.default.accept_ra="$sysctl_net_ipv6_conf_default_accept_ra_value" - -# -# If net.ipv6.conf.default.accept_ra present in /etc/sysctl.conf, change value to appropriate value -# else, add "net.ipv6.conf.default.accept_ra = value" to /etc/sysctl.conf -# - -# Strip any search characters in the key arg so that the key can be replaced without -# adding any search characters to the config file. -stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv6.conf.default.accept_ra") - -# shellcheck disable=SC2059 -printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv6_conf_default_accept_ra_value" - -# If the key exists, change it. Otherwise, add it to the config_file. -# We search for the key string followed by a word boundary (matched by \>), -# so if we search for 'setting', 'setting2' won't match. -if LC_ALL=C grep -q -m 1 -i -e "^net.ipv6.conf.default.accept_ra\\>" "${SYSCONFIG_FILE}"; then - escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") - LC_ALL=C sed -i --follow-symlinks "s/^net.ipv6.conf.default.accept_ra\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" -else - if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then - LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" - fi - printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: List /etc/sysctl.d/*.conf files - find: - paths: - - /etc/sysctl.d/ - - /run/sysctl.d/ - - /usr/local/lib/sysctl.d/ - contains: ^[\s]*net.ipv6.conf.default.accept_ra.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.20 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv6_conf_default_accept_ra - -- name: Comment out any occurrences of net.ipv6.conf.default.accept_ra from config - files - replace: - path: '{{ item.path }}' - regexp: ^[\s]*net.ipv6.conf.default.accept_ra - replace: '#net.ipv6.conf.default.accept_ra' - loop: '{{ find_sysctl_d.files }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.20 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv6_conf_default_accept_ra -- name: XCCDF Value sysctl_net_ipv6_conf_default_accept_ra_value # promote to variable - set_fact: - sysctl_net_ipv6_conf_default_accept_ra_value: !!str - tags: - - always - -- name: Ensure sysctl net.ipv6.conf.default.accept_ra is set - sysctl: - name: net.ipv6.conf.default.accept_ra - value: '{{ sysctl_net_ipv6_conf_default_accept_ra_value }}' - sysctl_file: /etc/sysctl.conf - state: present - reload: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.20 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv6_conf_default_accept_ra - - - - - - - - - - - Configure Accepting Default Router in Router Advertisements on All IPv6 Interfaces By Default - To set the runtime status of the net.ipv6.conf.default.accept_ra_defrtr kernel parameter, run the following command: $ sudo sysctl -w net.ipv6.conf.default.accept_ra_defrtr=0 -To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv6.conf.default.accept_ra_defrtr = 0 - BP28(R22) - An illicit router advertisement message could result in a man-in-the-middle attack. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Comment out any occurrences of net.ipv6.conf.default.accept_ra_defrtr from /etc/sysctl.d/*.conf files - -for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do - - matching_list=$(grep -P '^(?!#).*[\s]*net.ipv6.conf.default.accept_ra_defrtr.*$' $f | uniq ) - if ! test -z "$matching_list"; then - while IFS= read -r entry; do - escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") - # comment out "net.ipv6.conf.default.accept_ra_defrtr" matches to preserve user data - sed -i "s/^${escaped_entry}$/# &/g" $f - done <<< "$matching_list" - fi -done - -# -# Set sysctl config file which to save the desired value -# - -SYSCONFIG_FILE="/etc/sysctl.conf" - -sysctl_net_ipv6_conf_default_accept_ra_defrtr_value='' - - -# -# Set runtime for net.ipv6.conf.default.accept_ra_defrtr -# -/sbin/sysctl -q -n -w net.ipv6.conf.default.accept_ra_defrtr="$sysctl_net_ipv6_conf_default_accept_ra_defrtr_value" - -# -# If net.ipv6.conf.default.accept_ra_defrtr present in /etc/sysctl.conf, change value to appropriate value -# else, add "net.ipv6.conf.default.accept_ra_defrtr = value" to /etc/sysctl.conf -# - -# Strip any search characters in the key arg so that the key can be replaced without -# adding any search characters to the config file. -stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv6.conf.default.accept_ra_defrtr") - -# shellcheck disable=SC2059 -printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv6_conf_default_accept_ra_defrtr_value" - -# If the key exists, change it. Otherwise, add it to the config_file. -# We search for the key string followed by a word boundary (matched by \>), -# so if we search for 'setting', 'setting2' won't match. -if LC_ALL=C grep -q -m 1 -i -e "^net.ipv6.conf.default.accept_ra_defrtr\\>" "${SYSCONFIG_FILE}"; then - escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") - LC_ALL=C sed -i --follow-symlinks "s/^net.ipv6.conf.default.accept_ra_defrtr\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" -else - if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then - LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" - fi - printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: List /etc/sysctl.d/*.conf files - find: - paths: - - /etc/sysctl.d/ - - /run/sysctl.d/ - - /usr/local/lib/sysctl.d/ - contains: ^[\s]*net.ipv6.conf.default.accept_ra_defrtr.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - reboot_required - - sysctl_net_ipv6_conf_default_accept_ra_defrtr - - unknown_severity - -- name: Comment out any occurrences of net.ipv6.conf.default.accept_ra_defrtr from - config files - replace: - path: '{{ item.path }}' - regexp: ^[\s]*net.ipv6.conf.default.accept_ra_defrtr - replace: '#net.ipv6.conf.default.accept_ra_defrtr' - loop: '{{ find_sysctl_d.files }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - reboot_required - - sysctl_net_ipv6_conf_default_accept_ra_defrtr - - unknown_severity -- name: XCCDF Value sysctl_net_ipv6_conf_default_accept_ra_defrtr_value # promote to variable - set_fact: - sysctl_net_ipv6_conf_default_accept_ra_defrtr_value: !!str - tags: - - always - -- name: Ensure sysctl net.ipv6.conf.default.accept_ra_defrtr is set - sysctl: - name: net.ipv6.conf.default.accept_ra_defrtr - value: '{{ sysctl_net_ipv6_conf_default_accept_ra_defrtr_value }}' - sysctl_file: /etc/sysctl.conf - state: present - reload: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - reboot_required - - sysctl_net_ipv6_conf_default_accept_ra_defrtr - - unknown_severity - - - - - - - - - - - Configure Accepting Prefix Information in Router Advertisements on All IPv6 Interfaces By Default - To set the runtime status of the net.ipv6.conf.default.accept_ra_pinfo kernel parameter, run the following command: $ sudo sysctl -w net.ipv6.conf.default.accept_ra_pinfo=0 -To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv6.conf.default.accept_ra_pinfo = 0 - BP28(R22) - An illicit router advertisement message could result in a man-in-the-middle attack. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Comment out any occurrences of net.ipv6.conf.default.accept_ra_pinfo from /etc/sysctl.d/*.conf files - -for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do - - matching_list=$(grep -P '^(?!#).*[\s]*net.ipv6.conf.default.accept_ra_pinfo.*$' $f | uniq ) - if ! test -z "$matching_list"; then - while IFS= read -r entry; do - escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") - # comment out "net.ipv6.conf.default.accept_ra_pinfo" matches to preserve user data - sed -i "s/^${escaped_entry}$/# &/g" $f - done <<< "$matching_list" - fi -done - -# -# Set sysctl config file which to save the desired value -# - -SYSCONFIG_FILE="/etc/sysctl.conf" - -sysctl_net_ipv6_conf_default_accept_ra_pinfo_value='' - - -# -# Set runtime for net.ipv6.conf.default.accept_ra_pinfo -# -/sbin/sysctl -q -n -w net.ipv6.conf.default.accept_ra_pinfo="$sysctl_net_ipv6_conf_default_accept_ra_pinfo_value" - -# -# If net.ipv6.conf.default.accept_ra_pinfo present in /etc/sysctl.conf, change value to appropriate value -# else, add "net.ipv6.conf.default.accept_ra_pinfo = value" to /etc/sysctl.conf -# - -# Strip any search characters in the key arg so that the key can be replaced without -# adding any search characters to the config file. -stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv6.conf.default.accept_ra_pinfo") - -# shellcheck disable=SC2059 -printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv6_conf_default_accept_ra_pinfo_value" - -# If the key exists, change it. Otherwise, add it to the config_file. -# We search for the key string followed by a word boundary (matched by \>), -# so if we search for 'setting', 'setting2' won't match. -if LC_ALL=C grep -q -m 1 -i -e "^net.ipv6.conf.default.accept_ra_pinfo\\>" "${SYSCONFIG_FILE}"; then - escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") - LC_ALL=C sed -i --follow-symlinks "s/^net.ipv6.conf.default.accept_ra_pinfo\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" -else - if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then - LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" - fi - printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: List /etc/sysctl.d/*.conf files - find: - paths: - - /etc/sysctl.d/ - - /run/sysctl.d/ - - /usr/local/lib/sysctl.d/ - contains: ^[\s]*net.ipv6.conf.default.accept_ra_pinfo.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - reboot_required - - sysctl_net_ipv6_conf_default_accept_ra_pinfo - - unknown_severity - -- name: Comment out any occurrences of net.ipv6.conf.default.accept_ra_pinfo from - config files - replace: - path: '{{ item.path }}' - regexp: ^[\s]*net.ipv6.conf.default.accept_ra_pinfo - replace: '#net.ipv6.conf.default.accept_ra_pinfo' - loop: '{{ find_sysctl_d.files }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - reboot_required - - sysctl_net_ipv6_conf_default_accept_ra_pinfo - - unknown_severity -- name: XCCDF Value sysctl_net_ipv6_conf_default_accept_ra_pinfo_value # promote to variable - set_fact: - sysctl_net_ipv6_conf_default_accept_ra_pinfo_value: !!str - tags: - - always - -- name: Ensure sysctl net.ipv6.conf.default.accept_ra_pinfo is set - sysctl: - name: net.ipv6.conf.default.accept_ra_pinfo - value: '{{ sysctl_net_ipv6_conf_default_accept_ra_pinfo_value }}' - sysctl_file: /etc/sysctl.conf - state: present - reload: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - reboot_required - - sysctl_net_ipv6_conf_default_accept_ra_pinfo - - unknown_severity - - - - - - - - - - - Configure Accepting Router Preference in Router Advertisements on All IPv6 Interfaces By Default - To set the runtime status of the net.ipv6.conf.default.accept_ra_rtr_pref kernel parameter, run the following command: $ sudo sysctl -w net.ipv6.conf.default.accept_ra_rtr_pref=0 -To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv6.conf.default.accept_ra_rtr_pref = 0 - BP28(R22) - An illicit router advertisement message could result in a man-in-the-middle attack. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Comment out any occurrences of net.ipv6.conf.default.accept_ra_rtr_pref from /etc/sysctl.d/*.conf files - -for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do - - matching_list=$(grep -P '^(?!#).*[\s]*net.ipv6.conf.default.accept_ra_rtr_pref.*$' $f | uniq ) - if ! test -z "$matching_list"; then - while IFS= read -r entry; do - escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") - # comment out "net.ipv6.conf.default.accept_ra_rtr_pref" matches to preserve user data - sed -i "s/^${escaped_entry}$/# &/g" $f - done <<< "$matching_list" - fi -done - -# -# Set sysctl config file which to save the desired value -# - -SYSCONFIG_FILE="/etc/sysctl.conf" - -sysctl_net_ipv6_conf_default_accept_ra_rtr_pref_value='' - - -# -# Set runtime for net.ipv6.conf.default.accept_ra_rtr_pref -# -/sbin/sysctl -q -n -w net.ipv6.conf.default.accept_ra_rtr_pref="$sysctl_net_ipv6_conf_default_accept_ra_rtr_pref_value" - -# -# If net.ipv6.conf.default.accept_ra_rtr_pref present in /etc/sysctl.conf, change value to appropriate value -# else, add "net.ipv6.conf.default.accept_ra_rtr_pref = value" to /etc/sysctl.conf -# - -# Strip any search characters in the key arg so that the key can be replaced without -# adding any search characters to the config file. -stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv6.conf.default.accept_ra_rtr_pref") - -# shellcheck disable=SC2059 -printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv6_conf_default_accept_ra_rtr_pref_value" - -# If the key exists, change it. Otherwise, add it to the config_file. -# We search for the key string followed by a word boundary (matched by \>), -# so if we search for 'setting', 'setting2' won't match. -if LC_ALL=C grep -q -m 1 -i -e "^net.ipv6.conf.default.accept_ra_rtr_pref\\>" "${SYSCONFIG_FILE}"; then - escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") - LC_ALL=C sed -i --follow-symlinks "s/^net.ipv6.conf.default.accept_ra_rtr_pref\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" -else - if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then - LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" - fi - printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: List /etc/sysctl.d/*.conf files - find: - paths: - - /etc/sysctl.d/ - - /run/sysctl.d/ - - /usr/local/lib/sysctl.d/ - contains: ^[\s]*net.ipv6.conf.default.accept_ra_rtr_pref.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - reboot_required - - sysctl_net_ipv6_conf_default_accept_ra_rtr_pref - - unknown_severity - -- name: Comment out any occurrences of net.ipv6.conf.default.accept_ra_rtr_pref from - config files - replace: - path: '{{ item.path }}' - regexp: ^[\s]*net.ipv6.conf.default.accept_ra_rtr_pref - replace: '#net.ipv6.conf.default.accept_ra_rtr_pref' - loop: '{{ find_sysctl_d.files }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - reboot_required - - sysctl_net_ipv6_conf_default_accept_ra_rtr_pref - - unknown_severity -- name: XCCDF Value sysctl_net_ipv6_conf_default_accept_ra_rtr_pref_value # promote to variable - set_fact: - sysctl_net_ipv6_conf_default_accept_ra_rtr_pref_value: !!str - tags: - - always - -- name: Ensure sysctl net.ipv6.conf.default.accept_ra_rtr_pref is set - sysctl: - name: net.ipv6.conf.default.accept_ra_rtr_pref - value: '{{ sysctl_net_ipv6_conf_default_accept_ra_rtr_pref_value }}' - sysctl_file: /etc/sysctl.conf - state: present - reload: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - reboot_required - - sysctl_net_ipv6_conf_default_accept_ra_rtr_pref - - unknown_severity - - - - - - - - - - - Disable Kernel Parameter for Accepting ICMP Redirects by Default on IPv6 Interfaces - To set the runtime status of the net.ipv6.conf.default.accept_redirects kernel parameter, run the following command: $ sudo sysctl -w net.ipv6.conf.default.accept_redirects=0 -To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv6.conf.default.accept_redirects = 0 - BP28(R22) - 11 - 14 - 3 - 9 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS05.02 - DSS05.05 - DSS06.06 - 3.1.20 - CCI-000366 - CCI-001551 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 7.6 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.9.1.2 - CM-7(a) - CM-7(b) - CM-6(a) - PR.IP-1 - PR.PT-3 - SRG-OS-000480-GPOS-00227 - An illicit ICMP redirect message could result in a man-in-the-middle attack. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Comment out any occurrences of net.ipv6.conf.default.accept_redirects from /etc/sysctl.d/*.conf files - -for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do - - matching_list=$(grep -P '^(?!#).*[\s]*net.ipv6.conf.default.accept_redirects.*$' $f | uniq ) - if ! test -z "$matching_list"; then - while IFS= read -r entry; do - escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") - # comment out "net.ipv6.conf.default.accept_redirects" matches to preserve user data - sed -i "s/^${escaped_entry}$/# &/g" $f - done <<< "$matching_list" - fi -done - -# -# Set sysctl config file which to save the desired value -# - -SYSCONFIG_FILE="/etc/sysctl.conf" - -sysctl_net_ipv6_conf_default_accept_redirects_value='' - - -# -# Set runtime for net.ipv6.conf.default.accept_redirects -# -/sbin/sysctl -q -n -w net.ipv6.conf.default.accept_redirects="$sysctl_net_ipv6_conf_default_accept_redirects_value" - -# -# If net.ipv6.conf.default.accept_redirects present in /etc/sysctl.conf, change value to appropriate value -# else, add "net.ipv6.conf.default.accept_redirects = value" to /etc/sysctl.conf -# - -# Strip any search characters in the key arg so that the key can be replaced without -# adding any search characters to the config file. -stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv6.conf.default.accept_redirects") - -# shellcheck disable=SC2059 -printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv6_conf_default_accept_redirects_value" - -# If the key exists, change it. Otherwise, add it to the config_file. -# We search for the key string followed by a word boundary (matched by \>), -# so if we search for 'setting', 'setting2' won't match. -if LC_ALL=C grep -q -m 1 -i -e "^net.ipv6.conf.default.accept_redirects\\>" "${SYSCONFIG_FILE}"; then - escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") - LC_ALL=C sed -i --follow-symlinks "s/^net.ipv6.conf.default.accept_redirects\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" -else - if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then - LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" - fi - printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: List /etc/sysctl.d/*.conf files - find: - paths: - - /etc/sysctl.d/ - - /run/sysctl.d/ - - /usr/local/lib/sysctl.d/ - contains: ^[\s]*net.ipv6.conf.default.accept_redirects.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.20 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv6_conf_default_accept_redirects - -- name: Comment out any occurrences of net.ipv6.conf.default.accept_redirects from - config files - replace: - path: '{{ item.path }}' - regexp: ^[\s]*net.ipv6.conf.default.accept_redirects - replace: '#net.ipv6.conf.default.accept_redirects' - loop: '{{ find_sysctl_d.files }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.20 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv6_conf_default_accept_redirects -- name: XCCDF Value sysctl_net_ipv6_conf_default_accept_redirects_value # promote to variable - set_fact: - sysctl_net_ipv6_conf_default_accept_redirects_value: !!str - tags: - - always - -- name: Ensure sysctl net.ipv6.conf.default.accept_redirects is set - sysctl: - name: net.ipv6.conf.default.accept_redirects - value: '{{ sysctl_net_ipv6_conf_default_accept_redirects_value }}' - sysctl_file: /etc/sysctl.conf - state: present - reload: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.20 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv6_conf_default_accept_redirects - - - - - - - - - - - Disable Kernel Parameter for Accepting Source-Routed Packets on IPv6 Interfaces by Default - To set the runtime status of the net.ipv6.conf.default.accept_source_route kernel parameter, run the following command: $ sudo sysctl -w net.ipv6.conf.default.accept_source_route=0 -To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv6.conf.default.accept_source_route = 0 - BP28(R22) - 1 - 12 - 13 - 14 - 15 - 16 - 18 - 4 - 6 - 8 - 9 - APO01.06 - APO13.01 - DSS01.05 - DSS03.01 - DSS05.02 - DSS05.04 - DSS05.07 - DSS06.02 - 3.1.20 - CCI-000366 - 4.2.3.4 - 4.3.3.4 - 4.4.3.3 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 7.1 - SR 7.6 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.12.1.1 - A.12.1.2 - A.13.1.1 - A.13.1.2 - A.13.1.3 - A.13.2.1 - A.13.2.2 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CM-7(a) - CM-7(b) - CM-6(a) - CM-6(b) - CM-6.1(iv) - DE.AE-1 - ID.AM-3 - PR.AC-5 - PR.DS-5 - PR.PT-4 - Req-1.4.3 - SRG-OS-000480-GPOS-00227 - Source-routed packets allow the source of the packet to suggest routers -forward the packet along a different path than configured on the router, which can -be used to bypass network security measures. This requirement applies only to the -forwarding of source-routerd traffic, such as when IPv6 forwarding is enabled and -the system is functioning as a router. - -Accepting source-routed packets in the IPv6 protocol has few legitimate -uses. It should be disabled unless it is absolutely required. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Comment out any occurrences of net.ipv6.conf.default.accept_source_route from /etc/sysctl.d/*.conf files - -for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do - - matching_list=$(grep -P '^(?!#).*[\s]*net.ipv6.conf.default.accept_source_route.*$' $f | uniq ) - if ! test -z "$matching_list"; then - while IFS= read -r entry; do - escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") - # comment out "net.ipv6.conf.default.accept_source_route" matches to preserve user data - sed -i "s/^${escaped_entry}$/# &/g" $f - done <<< "$matching_list" - fi -done - -# -# Set sysctl config file which to save the desired value -# - -SYSCONFIG_FILE="/etc/sysctl.conf" - -sysctl_net_ipv6_conf_default_accept_source_route_value='' - - -# -# Set runtime for net.ipv6.conf.default.accept_source_route -# -/sbin/sysctl -q -n -w net.ipv6.conf.default.accept_source_route="$sysctl_net_ipv6_conf_default_accept_source_route_value" - -# -# If net.ipv6.conf.default.accept_source_route present in /etc/sysctl.conf, change value to appropriate value -# else, add "net.ipv6.conf.default.accept_source_route = value" to /etc/sysctl.conf -# - -# Strip any search characters in the key arg so that the key can be replaced without -# adding any search characters to the config file. -stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv6.conf.default.accept_source_route") - -# shellcheck disable=SC2059 -printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv6_conf_default_accept_source_route_value" - -# If the key exists, change it. Otherwise, add it to the config_file. -# We search for the key string followed by a word boundary (matched by \>), -# so if we search for 'setting', 'setting2' won't match. -if LC_ALL=C grep -q -m 1 -i -e "^net.ipv6.conf.default.accept_source_route\\>" "${SYSCONFIG_FILE}"; then - escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") - LC_ALL=C sed -i --follow-symlinks "s/^net.ipv6.conf.default.accept_source_route\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" -else - if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then - LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" - fi - printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: List /etc/sysctl.d/*.conf files - find: - paths: - - /etc/sysctl.d/ - - /run/sysctl.d/ - - /usr/local/lib/sysctl.d/ - contains: ^[\s]*net.ipv6.conf.default.accept_source_route.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.20 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-6(b) - - NIST-800-53-CM-6.1(iv) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - PCI-DSS-Req-1.4.3 - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv6_conf_default_accept_source_route - -- name: Comment out any occurrences of net.ipv6.conf.default.accept_source_route from - config files - replace: - path: '{{ item.path }}' - regexp: ^[\s]*net.ipv6.conf.default.accept_source_route - replace: '#net.ipv6.conf.default.accept_source_route' - loop: '{{ find_sysctl_d.files }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.20 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-6(b) - - NIST-800-53-CM-6.1(iv) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - PCI-DSS-Req-1.4.3 - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv6_conf_default_accept_source_route -- name: XCCDF Value sysctl_net_ipv6_conf_default_accept_source_route_value # promote to variable - set_fact: - sysctl_net_ipv6_conf_default_accept_source_route_value: !!str - tags: - - always - -- name: Ensure sysctl net.ipv6.conf.default.accept_source_route is set - sysctl: - name: net.ipv6.conf.default.accept_source_route - value: '{{ sysctl_net_ipv6_conf_default_accept_source_route_value }}' - sysctl_file: /etc/sysctl.conf - state: present - reload: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.20 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-6(b) - - NIST-800-53-CM-6.1(iv) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - PCI-DSS-Req-1.4.3 - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv6_conf_default_accept_source_route - - - - - - - - - - - Configure Auto Configuration on All IPv6 Interfaces By Default - To set the runtime status of the net.ipv6.conf.default.autoconf kernel parameter, run the following command: $ sudo sysctl -w net.ipv6.conf.default.autoconf=0 -To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv6.conf.default.autoconf = 0 - BP28(R22) - An illicit router advertisement message could result in a man-in-the-middle attack. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Comment out any occurrences of net.ipv6.conf.default.autoconf from /etc/sysctl.d/*.conf files - -for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do - - matching_list=$(grep -P '^(?!#).*[\s]*net.ipv6.conf.default.autoconf.*$' $f | uniq ) - if ! test -z "$matching_list"; then - while IFS= read -r entry; do - escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") - # comment out "net.ipv6.conf.default.autoconf" matches to preserve user data - sed -i "s/^${escaped_entry}$/# &/g" $f - done <<< "$matching_list" - fi -done - -# -# Set sysctl config file which to save the desired value -# - -SYSCONFIG_FILE="/etc/sysctl.conf" - -sysctl_net_ipv6_conf_default_autoconf_value='' - - -# -# Set runtime for net.ipv6.conf.default.autoconf -# -/sbin/sysctl -q -n -w net.ipv6.conf.default.autoconf="$sysctl_net_ipv6_conf_default_autoconf_value" - -# -# If net.ipv6.conf.default.autoconf present in /etc/sysctl.conf, change value to appropriate value -# else, add "net.ipv6.conf.default.autoconf = value" to /etc/sysctl.conf -# - -# Strip any search characters in the key arg so that the key can be replaced without -# adding any search characters to the config file. -stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv6.conf.default.autoconf") - -# shellcheck disable=SC2059 -printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv6_conf_default_autoconf_value" - -# If the key exists, change it. Otherwise, add it to the config_file. -# We search for the key string followed by a word boundary (matched by \>), -# so if we search for 'setting', 'setting2' won't match. -if LC_ALL=C grep -q -m 1 -i -e "^net.ipv6.conf.default.autoconf\\>" "${SYSCONFIG_FILE}"; then - escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") - LC_ALL=C sed -i --follow-symlinks "s/^net.ipv6.conf.default.autoconf\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" -else - if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then - LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" - fi - printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: List /etc/sysctl.d/*.conf files - find: - paths: - - /etc/sysctl.d/ - - /run/sysctl.d/ - - /usr/local/lib/sysctl.d/ - contains: ^[\s]*net.ipv6.conf.default.autoconf.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - reboot_required - - sysctl_net_ipv6_conf_default_autoconf - - unknown_severity - -- name: Comment out any occurrences of net.ipv6.conf.default.autoconf from config - files - replace: - path: '{{ item.path }}' - regexp: ^[\s]*net.ipv6.conf.default.autoconf - replace: '#net.ipv6.conf.default.autoconf' - loop: '{{ find_sysctl_d.files }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - reboot_required - - sysctl_net_ipv6_conf_default_autoconf - - unknown_severity -- name: XCCDF Value sysctl_net_ipv6_conf_default_autoconf_value # promote to variable - set_fact: - sysctl_net_ipv6_conf_default_autoconf_value: !!str - tags: - - always - -- name: Ensure sysctl net.ipv6.conf.default.autoconf is set - sysctl: - name: net.ipv6.conf.default.autoconf - value: '{{ sysctl_net_ipv6_conf_default_autoconf_value }}' - sysctl_file: /etc/sysctl.conf - state: present - reload: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - reboot_required - - sysctl_net_ipv6_conf_default_autoconf - - unknown_severity - - - - - - - - - - - Configure Maximum Number of Autoconfigured Addresses on All IPv6 Interfaces By Default - To set the runtime status of the net.ipv6.conf.default.max_addresses kernel parameter, run the following command: $ sudo sysctl -w net.ipv6.conf.default.max_addresses=1 -To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv6.conf.default.max_addresses = 1 - BP28(R22) - The number of global unicast IPv6 addresses for each interface should be limited exactly to the number of statically configured addresses. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Comment out any occurrences of net.ipv6.conf.default.max_addresses from /etc/sysctl.d/*.conf files - -for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do - - matching_list=$(grep -P '^(?!#).*[\s]*net.ipv6.conf.default.max_addresses.*$' $f | uniq ) - if ! test -z "$matching_list"; then - while IFS= read -r entry; do - escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") - # comment out "net.ipv6.conf.default.max_addresses" matches to preserve user data - sed -i "s/^${escaped_entry}$/# &/g" $f - done <<< "$matching_list" - fi -done - -# -# Set sysctl config file which to save the desired value -# - -SYSCONFIG_FILE="/etc/sysctl.conf" - -sysctl_net_ipv6_conf_default_max_addresses_value='' - - -# -# Set runtime for net.ipv6.conf.default.max_addresses -# -/sbin/sysctl -q -n -w net.ipv6.conf.default.max_addresses="$sysctl_net_ipv6_conf_default_max_addresses_value" - -# -# If net.ipv6.conf.default.max_addresses present in /etc/sysctl.conf, change value to appropriate value -# else, add "net.ipv6.conf.default.max_addresses = value" to /etc/sysctl.conf -# - -# Strip any search characters in the key arg so that the key can be replaced without -# adding any search characters to the config file. -stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv6.conf.default.max_addresses") - -# shellcheck disable=SC2059 -printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv6_conf_default_max_addresses_value" - -# If the key exists, change it. Otherwise, add it to the config_file. -# We search for the key string followed by a word boundary (matched by \>), -# so if we search for 'setting', 'setting2' won't match. -if LC_ALL=C grep -q -m 1 -i -e "^net.ipv6.conf.default.max_addresses\\>" "${SYSCONFIG_FILE}"; then - escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") - LC_ALL=C sed -i --follow-symlinks "s/^net.ipv6.conf.default.max_addresses\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" -else - if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then - LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" - fi - printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: List /etc/sysctl.d/*.conf files - find: - paths: - - /etc/sysctl.d/ - - /run/sysctl.d/ - - /usr/local/lib/sysctl.d/ - contains: ^[\s]*net.ipv6.conf.default.max_addresses.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - reboot_required - - sysctl_net_ipv6_conf_default_max_addresses - - unknown_severity - -- name: Comment out any occurrences of net.ipv6.conf.default.max_addresses from config - files - replace: - path: '{{ item.path }}' - regexp: ^[\s]*net.ipv6.conf.default.max_addresses - replace: '#net.ipv6.conf.default.max_addresses' - loop: '{{ find_sysctl_d.files }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - reboot_required - - sysctl_net_ipv6_conf_default_max_addresses - - unknown_severity -- name: XCCDF Value sysctl_net_ipv6_conf_default_max_addresses_value # promote to variable - set_fact: - sysctl_net_ipv6_conf_default_max_addresses_value: !!str - tags: - - always - -- name: Ensure sysctl net.ipv6.conf.default.max_addresses is set - sysctl: - name: net.ipv6.conf.default.max_addresses - value: '{{ sysctl_net_ipv6_conf_default_max_addresses_value }}' - sysctl_file: /etc/sysctl.conf - state: present - reload: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - reboot_required - - sysctl_net_ipv6_conf_default_max_addresses - - unknown_severity - - - - - - - - - - - Configure Denying Router Solicitations on All IPv6 Interfaces By Default - To set the runtime status of the net.ipv6.conf.default.router_solicitations kernel parameter, run the following command: $ sudo sysctl -w net.ipv6.conf.default.router_solicitations=0 -To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv6.conf.default.router_solicitations = 0 - BP28(R22) - To prevent discovery of the system by other systems, router solicitation requests should be denied. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Comment out any occurrences of net.ipv6.conf.default.router_solicitations from /etc/sysctl.d/*.conf files - -for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do - - matching_list=$(grep -P '^(?!#).*[\s]*net.ipv6.conf.default.router_solicitations.*$' $f | uniq ) - if ! test -z "$matching_list"; then - while IFS= read -r entry; do - escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") - # comment out "net.ipv6.conf.default.router_solicitations" matches to preserve user data - sed -i "s/^${escaped_entry}$/# &/g" $f - done <<< "$matching_list" - fi -done - -# -# Set sysctl config file which to save the desired value -# - -SYSCONFIG_FILE="/etc/sysctl.conf" - -sysctl_net_ipv6_conf_default_router_solicitations_value='' - - -# -# Set runtime for net.ipv6.conf.default.router_solicitations -# -/sbin/sysctl -q -n -w net.ipv6.conf.default.router_solicitations="$sysctl_net_ipv6_conf_default_router_solicitations_value" - -# -# If net.ipv6.conf.default.router_solicitations present in /etc/sysctl.conf, change value to appropriate value -# else, add "net.ipv6.conf.default.router_solicitations = value" to /etc/sysctl.conf -# - -# Strip any search characters in the key arg so that the key can be replaced without -# adding any search characters to the config file. -stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv6.conf.default.router_solicitations") - -# shellcheck disable=SC2059 -printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv6_conf_default_router_solicitations_value" - -# If the key exists, change it. Otherwise, add it to the config_file. -# We search for the key string followed by a word boundary (matched by \>), -# so if we search for 'setting', 'setting2' won't match. -if LC_ALL=C grep -q -m 1 -i -e "^net.ipv6.conf.default.router_solicitations\\>" "${SYSCONFIG_FILE}"; then - escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") - LC_ALL=C sed -i --follow-symlinks "s/^net.ipv6.conf.default.router_solicitations\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" -else - if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then - LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" - fi - printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: List /etc/sysctl.d/*.conf files - find: - paths: - - /etc/sysctl.d/ - - /run/sysctl.d/ - - /usr/local/lib/sysctl.d/ - contains: ^[\s]*net.ipv6.conf.default.router_solicitations.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - reboot_required - - sysctl_net_ipv6_conf_default_router_solicitations - - unknown_severity - -- name: Comment out any occurrences of net.ipv6.conf.default.router_solicitations - from config files - replace: - path: '{{ item.path }}' - regexp: ^[\s]*net.ipv6.conf.default.router_solicitations - replace: '#net.ipv6.conf.default.router_solicitations' - loop: '{{ find_sysctl_d.files }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - reboot_required - - sysctl_net_ipv6_conf_default_router_solicitations - - unknown_severity -- name: XCCDF Value sysctl_net_ipv6_conf_default_router_solicitations_value # promote to variable - set_fact: - sysctl_net_ipv6_conf_default_router_solicitations_value: !!str - tags: - - always - -- name: Ensure sysctl net.ipv6.conf.default.router_solicitations is set - sysctl: - name: net.ipv6.conf.default.router_solicitations - value: '{{ sysctl_net_ipv6_conf_default_router_solicitations_value }}' - sysctl_file: /etc/sysctl.conf - state: present - reload: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - reboot_required - - sysctl_net_ipv6_conf_default_router_solicitations - - unknown_severity - - - - - - - - - - - Limit Network-Transmitted Configuration if Using Static IPv6 Addresses - To limit the configuration information requested from other -systems and accepted from the network on a system that uses -statically-configured IPv6 addresses, add the following lines to -/etc/sysctl.conf: -net.ipv6.conf.default.router_solicitations = 0 -net.ipv6.conf.default.accept_ra_rtr_pref = 0 -net.ipv6.conf.default.accept_ra_pinfo = 0 -net.ipv6.conf.default.accept_ra_defrtr = 0 -net.ipv6.conf.default.autoconf = 0 -net.ipv6.conf.default.dad_transmits = 0 -net.ipv6.conf.default.max_addresses = 1 -The router_solicitations setting determines how many router -solicitations are sent when bringing up the interface. If addresses are -statically assigned, there is no need to send any solicitations. - -The accept_ra_pinfo setting controls whether the system will accept -prefix info from the router. - -The accept_ra_defrtr setting controls whether the system will accept -Hop Limit settings from a router advertisement. Setting it to 0 prevents a -router from changing your default IPv6 Hop Limit for outgoing packets. - -The autoconf setting controls whether router advertisements can cause -the system to assign a global unicast address to an interface. - -The dad_transmits setting determines how many neighbor solicitations -to send out per address (global and link-local) when bringing up an interface -to ensure the desired address is unique on the network. - -The max_addresses setting determines how many global unicast IPv6 -addresses can be assigned to each interface. The default is 16, but it should -be set to exactly the number of statically configured global addresses -required. - - - - - Kernel Parameters Which Affect Networking - The sysctl utility is used to set -parameters which affect the operation of the Linux kernel. Kernel parameters -which affect networking and have security implications are described here. - - Network Related Kernel Runtime Parameters for Hosts and Routers - Certain kernel parameters should be set for systems which are -acting as either hosts or routers to improve the system's ability defend -against certain types of IPv4 protocol attacks. - - - net.ipv4.conf.all.accept_redirects - Disable ICMP Redirect Acceptance - 0 - 0 - 1 - - - net.ipv4.conf.all.accept_source_route - Trackers could be using source-routed packets to -generate traffic that seems to be intra-net, but actually was -created outside and has been redirected. - 0 - 0 - 1 - - - net.ipv4.conf.default.arp_filter - Controls whether the ARP filter is enabled or not. - -1 - Allows you to have multiple network interfaces on the same subnet, and have the ARPs for each -interface be answered based on whether or not the kernel would route a packet from the ARP’d IP out that interface. -In other words it allows control of which cards (usually 1) will respond to an ARP request. - -0 - (default) The kernel can respond to arp requests with addresses from other interfaces. -This may seem wrong but it usually makes sense, because it increases the chance of successful communication. -IP addresses are owned by the complete host on Linux, not by particular interfaces. - 0 - 0 - 1 - - - net.ipv4.conf.default.arp_ignore - Control the response modes for ARP queries that resolve local target IP addresses: - -0 - (default): reply for any local target IP address, configured on any interface -1 - reply only if the target IP address is local address configured on the incoming interface -2 - reply only if the target IP address is local address configured on the incoming interface and both with the sender’s IP address are part from same subnet on this interface -3 - do not reply for local addresses configured with scope host, only resolutions for global and link addresses are replied -4-7 - reserved -8 - do not reply for all local addresses - 0 - 0 - 1 - 2 - 3 - 8 - - - net.ipv4.conf.all.forwarding - Toggle IPv4 Forwarding - 0 - 0 - 1 - - - net.ipv4.conf.all.log_martians - Disable so you don't Log Spoofed Packets, Source -Routed Packets, Redirect Packets - 1 - 0 - 1 - - - net.ipv4.conf.all.rp_filter - Enable to enforce sanity checking, also called ingress -filtering or egress filtering. The point is to drop a packet if the -source and destination IP addresses in the IP header do not make -sense when considered in light of the physical interface on which -it arrived. - 1 - 1 - 2 - - - net.ipv4.conf.all.secure_redirects - Enable to prevent hijacking of routing path by only -allowing redirects from gateways known in routing -table. Disable to refuse acceptance of secure ICMP redirected packets on all interfaces. - 0 - 0 - 1 - - - net.ipv4.conf.all.shared_media - Controls whether the system can send (router) or accept (host) RFC1620 shared media redirects. -shared_media for the interface will be enabled if at least one of conf/{all,interface}/shared_media -is set to TRUE, it will be disabled otherwise. - 0 - 0 - 1 - - - net.ipv4.conf.default.accept_redirects - Disable ICMP Redirect Acceptance? - 0 - 0 - 1 - - - net.ipv4.conf.default.accept_source_route - Disable IP source routing? - 0 - 0 - 1 - - - net.ipv4.conf.default.log_martians - Disable so you don't Log Spoofed Packets, Source -Routed Packets, Redirect Packets - 1 - 0 - 1 - - - net.ipv4.conf.default.rp_filter - Enables source route verification - 1 - 0 - 1 - - - net.ipv4.conf.default.secure_redirects - Enable to prevent hijacking of routing path by only -allowing redirects from gateways known in routing -table. Disable to refuse acceptance of secure ICMP redirected packages by default. - 0 - 0 - 1 - - - net.ipv4.conf.default.shared_media - Controls whether the system can send(router) or accept(host) RFC1620 shared media redirects. -shared_media for the interface will be enabled if at least one of conf/{all,interface}/shared_media -is set to TRUE, it will be disabled otherwise. - 0 - 0 - 1 - - - net.ipv4.icmp_echo_ignore_broadcasts - Ignore all ICMP ECHO and TIMESTAMP requests sent to it -via broadcast/multicast - 1 - 0 - 1 - - - net.ipv4.icmp_ignore_bogus_error_responses - Enable to prevent unnecessary logging - 1 - 0 - 1 - - - net.ipv4.tcp_invalid_ratelimit - Configure the maximal rate for sending duplicate acknowledgments in -response to incoming invalid TCP packets. - 500 - 1000 - 500 - 250 - 100 - - - net.ipv4.tcp_rfc1337 - Enable to enable TCP behavior conformant with RFC 1337 - 1 - 0 - 1 - - - net.ipv4.tcp_syncookies - Enable to turn on TCP SYN Cookie -Protection - 1 - 0 - 1 - - - Disable Accepting Packets Routed Between Local Interfaces - To set the runtime status of the net.ipv4.conf.all.accept_local kernel parameter, run the following command: $ sudo sysctl -w net.ipv4.conf.all.accept_local=0 -To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv4.conf.all.accept_local = 0 - BP28(R12) - Configure net.ipv4.conf.all.accept_local=0 to consider as invalid the packets -received from outside whose source is the 127.0.0.0/8 address block. -In combination with suitable routing, this can be used to direct packets between two -local interfaces over the wire and have them accepted properly. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Comment out any occurrences of net.ipv4.conf.all.accept_local from /etc/sysctl.d/*.conf files - -for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do - - matching_list=$(grep -P '^(?!#).*[\s]*net.ipv4.conf.all.accept_local.*$' $f | uniq ) - if ! test -z "$matching_list"; then - while IFS= read -r entry; do - escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") - # comment out "net.ipv4.conf.all.accept_local" matches to preserve user data - sed -i "s/^${escaped_entry}$/# &/g" $f - done <<< "$matching_list" - fi -done - -# -# Set sysctl config file which to save the desired value -# - -SYSCONFIG_FILE="/etc/sysctl.conf" - - -# -# Set runtime for net.ipv4.conf.all.accept_local -# -/sbin/sysctl -q -n -w net.ipv4.conf.all.accept_local="0" - -# -# If net.ipv4.conf.all.accept_local present in /etc/sysctl.conf, change value to "0" -# else, add "net.ipv4.conf.all.accept_local = 0" to /etc/sysctl.conf -# - -# Strip any search characters in the key arg so that the key can be replaced without -# adding any search characters to the config file. -stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv4.conf.all.accept_local") - -# shellcheck disable=SC2059 -printf -v formatted_output "%s = %s" "$stripped_key" "0" - -# If the key exists, change it. Otherwise, add it to the config_file. -# We search for the key string followed by a word boundary (matched by \>), -# so if we search for 'setting', 'setting2' won't match. -if LC_ALL=C grep -q -m 1 -i -e "^net.ipv4.conf.all.accept_local\\>" "${SYSCONFIG_FILE}"; then - escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") - LC_ALL=C sed -i --follow-symlinks "s/^net.ipv4.conf.all.accept_local\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" -else - if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then - LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" - fi - printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: List /etc/sysctl.d/*.conf files - find: - paths: - - /etc/sysctl.d/ - - /run/sysctl.d/ - - /usr/local/lib/sysctl.d/ - contains: ^[\s]*net.ipv4.conf.all.accept_local.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv4_conf_all_accept_local - -- name: Comment out any occurrences of net.ipv4.conf.all.accept_local from config - files - replace: - path: '{{ item.path }}' - regexp: ^[\s]*net.ipv4.conf.all.accept_local - replace: '#net.ipv4.conf.all.accept_local' - loop: '{{ find_sysctl_d.files }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv4_conf_all_accept_local - -- name: Ensure sysctl net.ipv4.conf.all.accept_local is set to 0 - sysctl: - name: net.ipv4.conf.all.accept_local - value: '0' - sysctl_file: /etc/sysctl.conf - state: present - reload: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv4_conf_all_accept_local - - - - - - - - - - Disable Accepting ICMP Redirects for All IPv4 Interfaces - To set the runtime status of the net.ipv4.conf.all.accept_redirects kernel parameter, run the following command: $ sudo sysctl -w net.ipv4.conf.all.accept_redirects=0 -To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv4.conf.all.accept_redirects = 0 - BP28(R22) - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 2 - 3 - 7 - 8 - 9 - 5.10.1.1 - APO13.01 - BAI04.04 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS01.03 - DSS03.05 - DSS05.02 - DSS05.05 - DSS05.07 - DSS06.06 - 3.1.20 - CCI-000366 - CCI-001503 - CCI-001551 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 6.2 - SR 7.1 - SR 7.2 - SR 7.6 - A.12.1.2 - A.12.1.3 - A.12.5.1 - A.12.6.2 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.17.2.1 - A.9.1.2 - CM-7(a) - CM-7(b) - CM-6(a) - SC-7(a) - DE.CM-1 - PR.DS-4 - PR.IP-1 - PR.PT-3 - SRG-OS-000480-GPOS-00227 - ICMP redirect messages are used by routers to inform hosts that a more -direct route exists for a particular destination. These messages modify the -host's route table and are unauthenticated. An illicit ICMP redirect -message could result in a man-in-the-middle attack. - -This feature of the IPv4 protocol has few legitimate uses. It should be -disabled unless absolutely required." - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Comment out any occurrences of net.ipv4.conf.all.accept_redirects from /etc/sysctl.d/*.conf files - -for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do - - matching_list=$(grep -P '^(?!#).*[\s]*net.ipv4.conf.all.accept_redirects.*$' $f | uniq ) - if ! test -z "$matching_list"; then - while IFS= read -r entry; do - escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") - # comment out "net.ipv4.conf.all.accept_redirects" matches to preserve user data - sed -i "s/^${escaped_entry}$/# &/g" $f - done <<< "$matching_list" - fi -done - -# -# Set sysctl config file which to save the desired value -# - -SYSCONFIG_FILE="/etc/sysctl.conf" - -sysctl_net_ipv4_conf_all_accept_redirects_value='' - - -# -# Set runtime for net.ipv4.conf.all.accept_redirects -# -/sbin/sysctl -q -n -w net.ipv4.conf.all.accept_redirects="$sysctl_net_ipv4_conf_all_accept_redirects_value" - -# -# If net.ipv4.conf.all.accept_redirects present in /etc/sysctl.conf, change value to appropriate value -# else, add "net.ipv4.conf.all.accept_redirects = value" to /etc/sysctl.conf -# - -# Strip any search characters in the key arg so that the key can be replaced without -# adding any search characters to the config file. -stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv4.conf.all.accept_redirects") - -# shellcheck disable=SC2059 -printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv4_conf_all_accept_redirects_value" - -# If the key exists, change it. Otherwise, add it to the config_file. -# We search for the key string followed by a word boundary (matched by \>), -# so if we search for 'setting', 'setting2' won't match. -if LC_ALL=C grep -q -m 1 -i -e "^net.ipv4.conf.all.accept_redirects\\>" "${SYSCONFIG_FILE}"; then - escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") - LC_ALL=C sed -i --follow-symlinks "s/^net.ipv4.conf.all.accept_redirects\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" -else - if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then - LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" - fi - printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: List /etc/sysctl.d/*.conf files - find: - paths: - - /etc/sysctl.d/ - - /run/sysctl.d/ - - /usr/local/lib/sysctl.d/ - contains: ^[\s]*net.ipv4.conf.all.accept_redirects.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - CJIS-5.10.1.1 - - NIST-800-171-3.1.20 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-SC-7(a) - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv4_conf_all_accept_redirects - -- name: Comment out any occurrences of net.ipv4.conf.all.accept_redirects from config - files - replace: - path: '{{ item.path }}' - regexp: ^[\s]*net.ipv4.conf.all.accept_redirects - replace: '#net.ipv4.conf.all.accept_redirects' - loop: '{{ find_sysctl_d.files }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - CJIS-5.10.1.1 - - NIST-800-171-3.1.20 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-SC-7(a) - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv4_conf_all_accept_redirects -- name: XCCDF Value sysctl_net_ipv4_conf_all_accept_redirects_value # promote to variable - set_fact: - sysctl_net_ipv4_conf_all_accept_redirects_value: !!str - tags: - - always - -- name: Ensure sysctl net.ipv4.conf.all.accept_redirects is set - sysctl: - name: net.ipv4.conf.all.accept_redirects - value: '{{ sysctl_net_ipv4_conf_all_accept_redirects_value }}' - sysctl_file: /etc/sysctl.conf - state: present - reload: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - CJIS-5.10.1.1 - - NIST-800-171-3.1.20 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-SC-7(a) - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv4_conf_all_accept_redirects - - - - - - - - - - - Disable Kernel Parameter for Accepting Source-Routed Packets on all IPv4 Interfaces - To set the runtime status of the net.ipv4.conf.all.accept_source_route kernel parameter, run the following command: $ sudo sysctl -w net.ipv4.conf.all.accept_source_route=0 -To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv4.conf.all.accept_source_route = 0 - BP28(R22) - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 18 - 2 - 3 - 4 - 6 - 7 - 8 - 9 - APO01.06 - APO13.01 - BAI04.04 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS01.03 - DSS01.05 - DSS03.01 - DSS03.05 - DSS05.02 - DSS05.04 - DSS05.05 - DSS05.07 - DSS06.02 - DSS06.06 - 3.1.20 - CCI-000366 - 4.2.3.4 - 4.3.3.4 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - 4.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 6.2 - SR 7.1 - SR 7.2 - SR 7.6 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.12.1.1 - A.12.1.2 - A.12.1.3 - A.12.5.1 - A.12.6.2 - A.13.1.1 - A.13.1.2 - A.13.1.3 - A.13.2.1 - A.13.2.2 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.17.2.1 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CIP-007-3 R4 - CIP-007-3 R4.1 - CIP-007-3 R4.2 - CIP-007-3 R5.1 - CM-7(a) - CM-7(b) - SC-5 - CM-6(a) - SC-7(a) - DE.AE-1 - DE.CM-1 - ID.AM-3 - PR.AC-5 - PR.DS-4 - PR.DS-5 - PR.IP-1 - PR.PT-3 - PR.PT-4 - SRG-OS-000480-GPOS-00227 - Source-routed packets allow the source of the packet to suggest routers -forward the packet along a different path than configured on the router, -which can be used to bypass network security measures. This requirement -applies only to the forwarding of source-routerd traffic, such as when IPv4 -forwarding is enabled and the system is functioning as a router. - -Accepting source-routed packets in the IPv4 protocol has few legitimate -uses. It should be disabled unless it is absolutely required. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Comment out any occurrences of net.ipv4.conf.all.accept_source_route from /etc/sysctl.d/*.conf files - -for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do - - matching_list=$(grep -P '^(?!#).*[\s]*net.ipv4.conf.all.accept_source_route.*$' $f | uniq ) - if ! test -z "$matching_list"; then - while IFS= read -r entry; do - escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") - # comment out "net.ipv4.conf.all.accept_source_route" matches to preserve user data - sed -i "s/^${escaped_entry}$/# &/g" $f - done <<< "$matching_list" - fi -done - -# -# Set sysctl config file which to save the desired value -# - -SYSCONFIG_FILE="/etc/sysctl.conf" - -sysctl_net_ipv4_conf_all_accept_source_route_value='' - - -# -# Set runtime for net.ipv4.conf.all.accept_source_route -# -/sbin/sysctl -q -n -w net.ipv4.conf.all.accept_source_route="$sysctl_net_ipv4_conf_all_accept_source_route_value" - -# -# If net.ipv4.conf.all.accept_source_route present in /etc/sysctl.conf, change value to appropriate value -# else, add "net.ipv4.conf.all.accept_source_route = value" to /etc/sysctl.conf -# - -# Strip any search characters in the key arg so that the key can be replaced without -# adding any search characters to the config file. -stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv4.conf.all.accept_source_route") - -# shellcheck disable=SC2059 -printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv4_conf_all_accept_source_route_value" - -# If the key exists, change it. Otherwise, add it to the config_file. -# We search for the key string followed by a word boundary (matched by \>), -# so if we search for 'setting', 'setting2' won't match. -if LC_ALL=C grep -q -m 1 -i -e "^net.ipv4.conf.all.accept_source_route\\>" "${SYSCONFIG_FILE}"; then - escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") - LC_ALL=C sed -i --follow-symlinks "s/^net.ipv4.conf.all.accept_source_route\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" -else - if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then - LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" - fi - printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: List /etc/sysctl.d/*.conf files - find: - paths: - - /etc/sysctl.d/ - - /run/sysctl.d/ - - /usr/local/lib/sysctl.d/ - contains: ^[\s]*net.ipv4.conf.all.accept_source_route.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.20 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-SC-5 - - NIST-800-53-SC-7(a) - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv4_conf_all_accept_source_route - -- name: Comment out any occurrences of net.ipv4.conf.all.accept_source_route from - config files - replace: - path: '{{ item.path }}' - regexp: ^[\s]*net.ipv4.conf.all.accept_source_route - replace: '#net.ipv4.conf.all.accept_source_route' - loop: '{{ find_sysctl_d.files }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.20 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-SC-5 - - NIST-800-53-SC-7(a) - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv4_conf_all_accept_source_route -- name: XCCDF Value sysctl_net_ipv4_conf_all_accept_source_route_value # promote to variable - set_fact: - sysctl_net_ipv4_conf_all_accept_source_route_value: !!str - tags: - - always - -- name: Ensure sysctl net.ipv4.conf.all.accept_source_route is set - sysctl: - name: net.ipv4.conf.all.accept_source_route - value: '{{ sysctl_net_ipv4_conf_all_accept_source_route_value }}' - sysctl_file: /etc/sysctl.conf - state: present - reload: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.20 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-SC-5 - - NIST-800-53-SC-7(a) - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv4_conf_all_accept_source_route - - - - - - - - - - - Configure ARP filtering for All IPv4 Interfaces - To set the runtime status of the net.ipv4.conf.all.arp_filter kernel parameter, run the following command: $ sudo sysctl -w net.ipv4.conf.all.arp_filter= -To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv4.conf.all.arp_filter = - This behaviour may cause problems to system on a high availability or load balancing configuration. - BP28(R12) - Prevents the Linux Kernel from handling the ARP table globally. -By default, the kernel may respond to an ARP request from a certain interface with information -from another interface. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Comment out any occurrences of net.ipv4.conf.all.arp_filter from /etc/sysctl.d/*.conf files - -for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do - - matching_list=$(grep -P '^(?!#).*[\s]*net.ipv4.conf.all.arp_filter.*$' $f | uniq ) - if ! test -z "$matching_list"; then - while IFS= read -r entry; do - escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") - # comment out "net.ipv4.conf.all.arp_filter" matches to preserve user data - sed -i "s/^${escaped_entry}$/# &/g" $f - done <<< "$matching_list" - fi -done - -# -# Set sysctl config file which to save the desired value -# - -SYSCONFIG_FILE="/etc/sysctl.conf" - -sysctl_net_ipv4_conf_all_arp_filter_value='' - - -# -# Set runtime for net.ipv4.conf.all.arp_filter -# -/sbin/sysctl -q -n -w net.ipv4.conf.all.arp_filter="$sysctl_net_ipv4_conf_all_arp_filter_value" - -# -# If net.ipv4.conf.all.arp_filter present in /etc/sysctl.conf, change value to appropriate value -# else, add "net.ipv4.conf.all.arp_filter = value" to /etc/sysctl.conf -# - -# Strip any search characters in the key arg so that the key can be replaced without -# adding any search characters to the config file. -stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv4.conf.all.arp_filter") - -# shellcheck disable=SC2059 -printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv4_conf_all_arp_filter_value" - -# If the key exists, change it. Otherwise, add it to the config_file. -# We search for the key string followed by a word boundary (matched by \>), -# so if we search for 'setting', 'setting2' won't match. -if LC_ALL=C grep -q -m 1 -i -e "^net.ipv4.conf.all.arp_filter\\>" "${SYSCONFIG_FILE}"; then - escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") - LC_ALL=C sed -i --follow-symlinks "s/^net.ipv4.conf.all.arp_filter\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" -else - if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then - LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" - fi - printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: List /etc/sysctl.d/*.conf files - find: - paths: - - /etc/sysctl.d/ - - /run/sysctl.d/ - - /usr/local/lib/sysctl.d/ - contains: ^[\s]*net.ipv4.conf.all.arp_filter.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv4_conf_all_arp_filter - -- name: Comment out any occurrences of net.ipv4.conf.all.arp_filter from config files - replace: - path: '{{ item.path }}' - regexp: ^[\s]*net.ipv4.conf.all.arp_filter - replace: '#net.ipv4.conf.all.arp_filter' - loop: '{{ find_sysctl_d.files }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv4_conf_all_arp_filter -- name: XCCDF Value sysctl_net_ipv4_conf_all_arp_filter_value # promote to variable - set_fact: - sysctl_net_ipv4_conf_all_arp_filter_value: !!str - tags: - - always - -- name: Ensure sysctl net.ipv4.conf.all.arp_filter is set - sysctl: - name: net.ipv4.conf.all.arp_filter - value: '{{ sysctl_net_ipv4_conf_all_arp_filter_value }}' - sysctl_file: /etc/sysctl.conf - state: present - reload: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv4_conf_all_arp_filter - - - - - - - - - - - Configure Response Mode of ARP Requests for All IPv4 Interfaces - To set the runtime status of the net.ipv4.conf.all.arp_ignore kernel parameter, run the following command: $ sudo sysctl -w net.ipv4.conf.all.arp_ignore= -To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv4.conf.all.arp_ignore = - The ARP response mode may impact behaviour of workloads and firewalls on the system. - BP28(R12) - Avoids ARP Flux on system that have more than one interface on the same subnet. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Comment out any occurrences of net.ipv4.conf.all.arp_ignore from /etc/sysctl.d/*.conf files - -for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do - - matching_list=$(grep -P '^(?!#).*[\s]*net.ipv4.conf.all.arp_ignore.*$' $f | uniq ) - if ! test -z "$matching_list"; then - while IFS= read -r entry; do - escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") - # comment out "net.ipv4.conf.all.arp_ignore" matches to preserve user data - sed -i "s/^${escaped_entry}$/# &/g" $f - done <<< "$matching_list" - fi -done - -# -# Set sysctl config file which to save the desired value -# - -SYSCONFIG_FILE="/etc/sysctl.conf" - -sysctl_net_ipv4_conf_all_arp_ignore_value='' - - -# -# Set runtime for net.ipv4.conf.all.arp_ignore -# -/sbin/sysctl -q -n -w net.ipv4.conf.all.arp_ignore="$sysctl_net_ipv4_conf_all_arp_ignore_value" - -# -# If net.ipv4.conf.all.arp_ignore present in /etc/sysctl.conf, change value to appropriate value -# else, add "net.ipv4.conf.all.arp_ignore = value" to /etc/sysctl.conf -# - -# Strip any search characters in the key arg so that the key can be replaced without -# adding any search characters to the config file. -stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv4.conf.all.arp_ignore") - -# shellcheck disable=SC2059 -printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv4_conf_all_arp_ignore_value" - -# If the key exists, change it. Otherwise, add it to the config_file. -# We search for the key string followed by a word boundary (matched by \>), -# so if we search for 'setting', 'setting2' won't match. -if LC_ALL=C grep -q -m 1 -i -e "^net.ipv4.conf.all.arp_ignore\\>" "${SYSCONFIG_FILE}"; then - escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") - LC_ALL=C sed -i --follow-symlinks "s/^net.ipv4.conf.all.arp_ignore\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" -else - if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then - LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" - fi - printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: List /etc/sysctl.d/*.conf files - find: - paths: - - /etc/sysctl.d/ - - /run/sysctl.d/ - - /usr/local/lib/sysctl.d/ - contains: ^[\s]*net.ipv4.conf.all.arp_ignore.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv4_conf_all_arp_ignore - -- name: Comment out any occurrences of net.ipv4.conf.all.arp_ignore from config files - replace: - path: '{{ item.path }}' - regexp: ^[\s]*net.ipv4.conf.all.arp_ignore - replace: '#net.ipv4.conf.all.arp_ignore' - loop: '{{ find_sysctl_d.files }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv4_conf_all_arp_ignore -- name: XCCDF Value sysctl_net_ipv4_conf_all_arp_ignore_value # promote to variable - set_fact: - sysctl_net_ipv4_conf_all_arp_ignore_value: !!str - tags: - - always - -- name: Ensure sysctl net.ipv4.conf.all.arp_ignore is set - sysctl: - name: net.ipv4.conf.all.arp_ignore - value: '{{ sysctl_net_ipv4_conf_all_arp_ignore_value }}' - sysctl_file: /etc/sysctl.conf - state: present - reload: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv4_conf_all_arp_ignore - - - - - - - - - - - Drop Gratuitious ARP frames on All IPv4 Interfaces - To set the runtime status of the net.ipv4.conf.all.drop_gratuitous_arp kernel parameter, run the following command: $ sudo sysctl -w net.ipv4.conf.all.drop_gratuitous_arp=1 -To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv4.conf.all.drop_gratuitous_arp = 1 - This can cause problems if ARP proxies are used in the network. - BP28(R12) - Drop Gratuitous ARP frames to prevent ARP poisoning. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Comment out any occurrences of net.ipv4.conf.all.drop_gratuitous_arp from /etc/sysctl.d/*.conf files - -for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do - - matching_list=$(grep -P '^(?!#).*[\s]*net.ipv4.conf.all.drop_gratuitous_arp.*$' $f | uniq ) - if ! test -z "$matching_list"; then - while IFS= read -r entry; do - escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") - # comment out "net.ipv4.conf.all.drop_gratuitous_arp" matches to preserve user data - sed -i "s/^${escaped_entry}$/# &/g" $f - done <<< "$matching_list" - fi -done - -# -# Set sysctl config file which to save the desired value -# - -SYSCONFIG_FILE="/etc/sysctl.conf" - - -# -# Set runtime for net.ipv4.conf.all.drop_gratuitous_arp -# -/sbin/sysctl -q -n -w net.ipv4.conf.all.drop_gratuitous_arp="1" - -# -# If net.ipv4.conf.all.drop_gratuitous_arp present in /etc/sysctl.conf, change value to "1" -# else, add "net.ipv4.conf.all.drop_gratuitous_arp = 1" to /etc/sysctl.conf -# - -# Strip any search characters in the key arg so that the key can be replaced without -# adding any search characters to the config file. -stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv4.conf.all.drop_gratuitous_arp") - -# shellcheck disable=SC2059 -printf -v formatted_output "%s = %s" "$stripped_key" "1" - -# If the key exists, change it. Otherwise, add it to the config_file. -# We search for the key string followed by a word boundary (matched by \>), -# so if we search for 'setting', 'setting2' won't match. -if LC_ALL=C grep -q -m 1 -i -e "^net.ipv4.conf.all.drop_gratuitous_arp\\>" "${SYSCONFIG_FILE}"; then - escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") - LC_ALL=C sed -i --follow-symlinks "s/^net.ipv4.conf.all.drop_gratuitous_arp\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" -else - if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then - LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" - fi - printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: List /etc/sysctl.d/*.conf files - find: - paths: - - /etc/sysctl.d/ - - /run/sysctl.d/ - - /usr/local/lib/sysctl.d/ - contains: ^[\s]*net.ipv4.conf.all.drop_gratuitous_arp.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv4_conf_all_drop_gratuitous_arp - -- name: Comment out any occurrences of net.ipv4.conf.all.drop_gratuitous_arp from - config files - replace: - path: '{{ item.path }}' - regexp: ^[\s]*net.ipv4.conf.all.drop_gratuitous_arp - replace: '#net.ipv4.conf.all.drop_gratuitous_arp' - loop: '{{ find_sysctl_d.files }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv4_conf_all_drop_gratuitous_arp - -- name: Ensure sysctl net.ipv4.conf.all.drop_gratuitous_arp is set to 1 - sysctl: - name: net.ipv4.conf.all.drop_gratuitous_arp - value: '1' - sysctl_file: /etc/sysctl.conf - state: present - reload: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv4_conf_all_drop_gratuitous_arp - - - - - - - - - - Enable Kernel Parameter to Log Martian Packets on all IPv4 Interfaces - To set the runtime status of the net.ipv4.conf.all.log_martians kernel parameter, run the following command: $ sudo sysctl -w net.ipv4.conf.all.log_martians=1 -To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv4.conf.all.log_martians = 1 - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 2 - 3 - 7 - 8 - 9 - APO13.01 - BAI04.04 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS01.03 - DSS01.04 - DSS03.05 - DSS05.02 - DSS05.03 - DSS05.05 - DSS05.07 - DSS06.06 - 3.1.20 - CCI-000126 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 6.2 - SR 7.1 - SR 7.2 - SR 7.6 - A.11.2.6 - A.12.1.2 - A.12.1.3 - A.12.5.1 - A.12.6.2 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.17.2.1 - A.6.2.1 - A.6.2.2 - A.9.1.2 - CM-7(a) - CM-7(b) - SC-5(3)(a) - DE.CM-1 - PR.AC-3 - PR.DS-4 - PR.IP-1 - PR.PT-3 - PR.PT-4 - SRG-OS-000480-GPOS-00227 - The presence of "martian" packets (which have impossible addresses) -as well as spoofed packets, source-routed packets, and redirects could be a -sign of nefarious network activity. Logging these packets enables this activity -to be detected. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Comment out any occurrences of net.ipv4.conf.all.log_martians from /etc/sysctl.d/*.conf files - -for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do - - matching_list=$(grep -P '^(?!#).*[\s]*net.ipv4.conf.all.log_martians.*$' $f | uniq ) - if ! test -z "$matching_list"; then - while IFS= read -r entry; do - escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") - # comment out "net.ipv4.conf.all.log_martians" matches to preserve user data - sed -i "s/^${escaped_entry}$/# &/g" $f - done <<< "$matching_list" - fi -done - -# -# Set sysctl config file which to save the desired value -# - -SYSCONFIG_FILE="/etc/sysctl.conf" - -sysctl_net_ipv4_conf_all_log_martians_value='' - - -# -# Set runtime for net.ipv4.conf.all.log_martians -# -/sbin/sysctl -q -n -w net.ipv4.conf.all.log_martians="$sysctl_net_ipv4_conf_all_log_martians_value" - -# -# If net.ipv4.conf.all.log_martians present in /etc/sysctl.conf, change value to appropriate value -# else, add "net.ipv4.conf.all.log_martians = value" to /etc/sysctl.conf -# - -# Strip any search characters in the key arg so that the key can be replaced without -# adding any search characters to the config file. -stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv4.conf.all.log_martians") - -# shellcheck disable=SC2059 -printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv4_conf_all_log_martians_value" - -# If the key exists, change it. Otherwise, add it to the config_file. -# We search for the key string followed by a word boundary (matched by \>), -# so if we search for 'setting', 'setting2' won't match. -if LC_ALL=C grep -q -m 1 -i -e "^net.ipv4.conf.all.log_martians\\>" "${SYSCONFIG_FILE}"; then - escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") - LC_ALL=C sed -i --follow-symlinks "s/^net.ipv4.conf.all.log_martians\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" -else - if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then - LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" - fi - printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: List /etc/sysctl.d/*.conf files - find: - paths: - - /etc/sysctl.d/ - - /run/sysctl.d/ - - /usr/local/lib/sysctl.d/ - contains: ^[\s]*net.ipv4.conf.all.log_martians.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.20 - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-SC-5(3)(a) - - disable_strategy - - low_complexity - - medium_disruption - - reboot_required - - sysctl_net_ipv4_conf_all_log_martians - - unknown_severity - -- name: Comment out any occurrences of net.ipv4.conf.all.log_martians from config - files - replace: - path: '{{ item.path }}' - regexp: ^[\s]*net.ipv4.conf.all.log_martians - replace: '#net.ipv4.conf.all.log_martians' - loop: '{{ find_sysctl_d.files }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.20 - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-SC-5(3)(a) - - disable_strategy - - low_complexity - - medium_disruption - - reboot_required - - sysctl_net_ipv4_conf_all_log_martians - - unknown_severity -- name: XCCDF Value sysctl_net_ipv4_conf_all_log_martians_value # promote to variable - set_fact: - sysctl_net_ipv4_conf_all_log_martians_value: !!str - tags: - - always - -- name: Ensure sysctl net.ipv4.conf.all.log_martians is set - sysctl: - name: net.ipv4.conf.all.log_martians - value: '{{ sysctl_net_ipv4_conf_all_log_martians_value }}' - sysctl_file: /etc/sysctl.conf - state: present - reload: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.20 - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-SC-5(3)(a) - - disable_strategy - - low_complexity - - medium_disruption - - reboot_required - - sysctl_net_ipv4_conf_all_log_martians - - unknown_severity - - - - - - - - - - - Prevent Routing External Traffic to Local Loopback on All IPv4 Interfaces - To set the runtime status of the net.ipv4.conf.all.route_localnet kernel parameter, run the following command: $ sudo sysctl -w net.ipv4.conf.all.route_localnet=0 -To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv4.conf.all.route_localnet = 0 - BP28(R12) - Refuse the routing of packets whose source or destination address is the local loopback. -This prohibits the use of network 127/8 for local routing purposes. -Enabling route_localnet can expose applications listening on localhost to external traffic. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Comment out any occurrences of net.ipv4.conf.all.route_localnet from /etc/sysctl.d/*.conf files - -for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do - - matching_list=$(grep -P '^(?!#).*[\s]*net.ipv4.conf.all.route_localnet.*$' $f | uniq ) - if ! test -z "$matching_list"; then - while IFS= read -r entry; do - escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") - # comment out "net.ipv4.conf.all.route_localnet" matches to preserve user data - sed -i "s/^${escaped_entry}$/# &/g" $f - done <<< "$matching_list" - fi -done - -# -# Set sysctl config file which to save the desired value -# - -SYSCONFIG_FILE="/etc/sysctl.conf" - - -# -# Set runtime for net.ipv4.conf.all.route_localnet -# -/sbin/sysctl -q -n -w net.ipv4.conf.all.route_localnet="0" - -# -# If net.ipv4.conf.all.route_localnet present in /etc/sysctl.conf, change value to "0" -# else, add "net.ipv4.conf.all.route_localnet = 0" to /etc/sysctl.conf -# - -# Strip any search characters in the key arg so that the key can be replaced without -# adding any search characters to the config file. -stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv4.conf.all.route_localnet") - -# shellcheck disable=SC2059 -printf -v formatted_output "%s = %s" "$stripped_key" "0" - -# If the key exists, change it. Otherwise, add it to the config_file. -# We search for the key string followed by a word boundary (matched by \>), -# so if we search for 'setting', 'setting2' won't match. -if LC_ALL=C grep -q -m 1 -i -e "^net.ipv4.conf.all.route_localnet\\>" "${SYSCONFIG_FILE}"; then - escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") - LC_ALL=C sed -i --follow-symlinks "s/^net.ipv4.conf.all.route_localnet\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" -else - if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then - LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" - fi - printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: List /etc/sysctl.d/*.conf files - find: - paths: - - /etc/sysctl.d/ - - /run/sysctl.d/ - - /usr/local/lib/sysctl.d/ - contains: ^[\s]*net.ipv4.conf.all.route_localnet.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv4_conf_all_route_localnet - -- name: Comment out any occurrences of net.ipv4.conf.all.route_localnet from config - files - replace: - path: '{{ item.path }}' - regexp: ^[\s]*net.ipv4.conf.all.route_localnet - replace: '#net.ipv4.conf.all.route_localnet' - loop: '{{ find_sysctl_d.files }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv4_conf_all_route_localnet - -- name: Ensure sysctl net.ipv4.conf.all.route_localnet is set to 0 - sysctl: - name: net.ipv4.conf.all.route_localnet - value: '0' - sysctl_file: /etc/sysctl.conf - state: present - reload: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv4_conf_all_route_localnet - - - - - - - - - - Enable Kernel Parameter to Use Reverse Path Filtering on all IPv4 Interfaces - To set the runtime status of the net.ipv4.conf.all.rp_filter kernel parameter, run the following command: $ sudo sysctl -w net.ipv4.conf.all.rp_filter=1 -To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv4.conf.all.rp_filter = 1 - BP28(R22) - 1 - 12 - 13 - 14 - 15 - 16 - 18 - 2 - 4 - 6 - 7 - 8 - 9 - APO01.06 - APO13.01 - BAI04.04 - DSS01.03 - DSS01.05 - DSS03.01 - DSS03.05 - DSS05.02 - DSS05.04 - DSS05.07 - DSS06.02 - 3.1.20 - CCI-000366 - CCI-001551 - 4.2.3.4 - 4.3.3.4 - 4.4.3.3 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 6.2 - SR 7.1 - SR 7.2 - SR 7.6 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.12.1.1 - A.12.1.2 - A.12.1.3 - A.13.1.1 - A.13.1.2 - A.13.1.3 - A.13.2.1 - A.13.2.2 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.17.2.1 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CM-7(a) - CM-7(b) - CM-6(a) - SC-7(a) - DE.AE-1 - DE.CM-1 - ID.AM-3 - PR.AC-5 - PR.DS-4 - PR.DS-5 - PR.PT-4 - Req-1.4.3 - SRG-OS-000480-GPOS-00227 - Enabling reverse path filtering drops packets with source addresses -that should not have been able to be received on the interface they were -received on. It should not be used on systems which are routers for -complicated networks, but is helpful for end hosts and routers serving small -networks. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Comment out any occurrences of net.ipv4.conf.all.rp_filter from /etc/sysctl.d/*.conf files - -for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do - - matching_list=$(grep -P '^(?!#).*[\s]*net.ipv4.conf.all.rp_filter.*$' $f | uniq ) - if ! test -z "$matching_list"; then - while IFS= read -r entry; do - escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") - # comment out "net.ipv4.conf.all.rp_filter" matches to preserve user data - sed -i "s/^${escaped_entry}$/# &/g" $f - done <<< "$matching_list" - fi -done - -# -# Set sysctl config file which to save the desired value -# - -SYSCONFIG_FILE="/etc/sysctl.conf" - -sysctl_net_ipv4_conf_all_rp_filter_value='' - - -# -# Set runtime for net.ipv4.conf.all.rp_filter -# -/sbin/sysctl -q -n -w net.ipv4.conf.all.rp_filter="$sysctl_net_ipv4_conf_all_rp_filter_value" - -# -# If net.ipv4.conf.all.rp_filter present in /etc/sysctl.conf, change value to appropriate value -# else, add "net.ipv4.conf.all.rp_filter = value" to /etc/sysctl.conf -# - -# Strip any search characters in the key arg so that the key can be replaced without -# adding any search characters to the config file. -stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv4.conf.all.rp_filter") - -# shellcheck disable=SC2059 -printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv4_conf_all_rp_filter_value" - -# If the key exists, change it. Otherwise, add it to the config_file. -# We search for the key string followed by a word boundary (matched by \>), -# so if we search for 'setting', 'setting2' won't match. -if LC_ALL=C grep -q -m 1 -i -e "^net.ipv4.conf.all.rp_filter\\>" "${SYSCONFIG_FILE}"; then - escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") - LC_ALL=C sed -i --follow-symlinks "s/^net.ipv4.conf.all.rp_filter\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" -else - if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then - LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" - fi - printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: List /etc/sysctl.d/*.conf files - find: - paths: - - /etc/sysctl.d/ - - /run/sysctl.d/ - - /usr/local/lib/sysctl.d/ - contains: ^[\s]*net.ipv4.conf.all.rp_filter.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.20 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-SC-7(a) - - PCI-DSS-Req-1.4.3 - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv4_conf_all_rp_filter - -- name: Comment out any occurrences of net.ipv4.conf.all.rp_filter from config files - replace: - path: '{{ item.path }}' - regexp: ^[\s]*net.ipv4.conf.all.rp_filter - replace: '#net.ipv4.conf.all.rp_filter' - loop: '{{ find_sysctl_d.files }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.20 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-SC-7(a) - - PCI-DSS-Req-1.4.3 - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv4_conf_all_rp_filter -- name: XCCDF Value sysctl_net_ipv4_conf_all_rp_filter_value # promote to variable - set_fact: - sysctl_net_ipv4_conf_all_rp_filter_value: !!str - tags: - - always - -- name: Ensure sysctl net.ipv4.conf.all.rp_filter is set - sysctl: - name: net.ipv4.conf.all.rp_filter - value: '{{ sysctl_net_ipv4_conf_all_rp_filter_value }}' - sysctl_file: /etc/sysctl.conf - state: present - reload: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.20 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-SC-7(a) - - PCI-DSS-Req-1.4.3 - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv4_conf_all_rp_filter - - - - - - - - - - Disable Kernel Parameter for Accepting Secure ICMP Redirects on all IPv4 Interfaces - To set the runtime status of the net.ipv4.conf.all.secure_redirects kernel parameter, run the following command: $ sudo sysctl -w net.ipv4.conf.all.secure_redirects=0 -To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv4.conf.all.secure_redirects = 0 - BP28(R22) - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 18 - 2 - 3 - 4 - 6 - 7 - 8 - 9 - APO01.06 - APO13.01 - BAI04.04 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS01.03 - DSS01.05 - DSS03.01 - DSS03.05 - DSS05.02 - DSS05.04 - DSS05.05 - DSS05.07 - DSS06.02 - DSS06.06 - 3.1.20 - CCI-001503 - CCI-001551 - 4.2.3.4 - 4.3.3.4 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - 4.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 6.2 - SR 7.1 - SR 7.2 - SR 7.6 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.12.1.1 - A.12.1.2 - A.12.1.3 - A.12.5.1 - A.12.6.2 - A.13.1.1 - A.13.1.2 - A.13.1.3 - A.13.2.1 - A.13.2.2 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.17.2.1 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CM-7(a) - CM-7(b) - CM-6(a) - SC-7(a) - DE.AE-1 - DE.CM-1 - ID.AM-3 - PR.AC-5 - PR.DS-4 - PR.DS-5 - PR.IP-1 - PR.PT-3 - PR.PT-4 - Req-1.4.3 - SRG-OS-000480-GPOS-00227 - Accepting "secure" ICMP redirects (from those gateways listed as -default gateways) has few legitimate uses. It should be disabled unless it is -absolutely required. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Comment out any occurrences of net.ipv4.conf.all.secure_redirects from /etc/sysctl.d/*.conf files - -for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do - - matching_list=$(grep -P '^(?!#).*[\s]*net.ipv4.conf.all.secure_redirects.*$' $f | uniq ) - if ! test -z "$matching_list"; then - while IFS= read -r entry; do - escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") - # comment out "net.ipv4.conf.all.secure_redirects" matches to preserve user data - sed -i "s/^${escaped_entry}$/# &/g" $f - done <<< "$matching_list" - fi -done - -# -# Set sysctl config file which to save the desired value -# - -SYSCONFIG_FILE="/etc/sysctl.conf" - -sysctl_net_ipv4_conf_all_secure_redirects_value='' - - -# -# Set runtime for net.ipv4.conf.all.secure_redirects -# -/sbin/sysctl -q -n -w net.ipv4.conf.all.secure_redirects="$sysctl_net_ipv4_conf_all_secure_redirects_value" - -# -# If net.ipv4.conf.all.secure_redirects present in /etc/sysctl.conf, change value to appropriate value -# else, add "net.ipv4.conf.all.secure_redirects = value" to /etc/sysctl.conf -# - -# Strip any search characters in the key arg so that the key can be replaced without -# adding any search characters to the config file. -stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv4.conf.all.secure_redirects") - -# shellcheck disable=SC2059 -printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv4_conf_all_secure_redirects_value" - -# If the key exists, change it. Otherwise, add it to the config_file. -# We search for the key string followed by a word boundary (matched by \>), -# so if we search for 'setting', 'setting2' won't match. -if LC_ALL=C grep -q -m 1 -i -e "^net.ipv4.conf.all.secure_redirects\\>" "${SYSCONFIG_FILE}"; then - escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") - LC_ALL=C sed -i --follow-symlinks "s/^net.ipv4.conf.all.secure_redirects\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" -else - if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then - LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" - fi - printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: List /etc/sysctl.d/*.conf files - find: - paths: - - /etc/sysctl.d/ - - /run/sysctl.d/ - - /usr/local/lib/sysctl.d/ - contains: ^[\s]*net.ipv4.conf.all.secure_redirects.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.20 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-SC-7(a) - - PCI-DSS-Req-1.4.3 - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv4_conf_all_secure_redirects - -- name: Comment out any occurrences of net.ipv4.conf.all.secure_redirects from config - files - replace: - path: '{{ item.path }}' - regexp: ^[\s]*net.ipv4.conf.all.secure_redirects - replace: '#net.ipv4.conf.all.secure_redirects' - loop: '{{ find_sysctl_d.files }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.20 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-SC-7(a) - - PCI-DSS-Req-1.4.3 - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv4_conf_all_secure_redirects -- name: XCCDF Value sysctl_net_ipv4_conf_all_secure_redirects_value # promote to variable - set_fact: - sysctl_net_ipv4_conf_all_secure_redirects_value: !!str - tags: - - always - -- name: Ensure sysctl net.ipv4.conf.all.secure_redirects is set - sysctl: - name: net.ipv4.conf.all.secure_redirects - value: '{{ sysctl_net_ipv4_conf_all_secure_redirects_value }}' - sysctl_file: /etc/sysctl.conf - state: present - reload: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.20 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-SC-7(a) - - PCI-DSS-Req-1.4.3 - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv4_conf_all_secure_redirects - - - - - - - - - - - Configure Sending and Accepting Shared Media Redirects for All IPv4 Interfaces - To set the runtime status of the net.ipv4.conf.all.shared_media kernel parameter, run the following command: $ sudo sysctl -w net.ipv4.conf.all.shared_media= -To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv4.conf.all.shared_media = - BP28(R12) - This setting should be aligned with net.ipv4.conf.all.secure_redirects because it overrides it. -If shared_media is enabled for an interface secure_redirects will be enabled too. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Comment out any occurrences of net.ipv4.conf.all.shared_media from /etc/sysctl.d/*.conf files - -for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do - - matching_list=$(grep -P '^(?!#).*[\s]*net.ipv4.conf.all.shared_media.*$' $f | uniq ) - if ! test -z "$matching_list"; then - while IFS= read -r entry; do - escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") - # comment out "net.ipv4.conf.all.shared_media" matches to preserve user data - sed -i "s/^${escaped_entry}$/# &/g" $f - done <<< "$matching_list" - fi -done - -# -# Set sysctl config file which to save the desired value -# - -SYSCONFIG_FILE="/etc/sysctl.conf" - -sysctl_net_ipv4_conf_all_shared_media_value='' - - -# -# Set runtime for net.ipv4.conf.all.shared_media -# -/sbin/sysctl -q -n -w net.ipv4.conf.all.shared_media="$sysctl_net_ipv4_conf_all_shared_media_value" - -# -# If net.ipv4.conf.all.shared_media present in /etc/sysctl.conf, change value to appropriate value -# else, add "net.ipv4.conf.all.shared_media = value" to /etc/sysctl.conf -# - -# Strip any search characters in the key arg so that the key can be replaced without -# adding any search characters to the config file. -stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv4.conf.all.shared_media") - -# shellcheck disable=SC2059 -printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv4_conf_all_shared_media_value" - -# If the key exists, change it. Otherwise, add it to the config_file. -# We search for the key string followed by a word boundary (matched by \>), -# so if we search for 'setting', 'setting2' won't match. -if LC_ALL=C grep -q -m 1 -i -e "^net.ipv4.conf.all.shared_media\\>" "${SYSCONFIG_FILE}"; then - escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") - LC_ALL=C sed -i --follow-symlinks "s/^net.ipv4.conf.all.shared_media\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" -else - if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then - LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" - fi - printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: List /etc/sysctl.d/*.conf files - find: - paths: - - /etc/sysctl.d/ - - /run/sysctl.d/ - - /usr/local/lib/sysctl.d/ - contains: ^[\s]*net.ipv4.conf.all.shared_media.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv4_conf_all_shared_media - -- name: Comment out any occurrences of net.ipv4.conf.all.shared_media from config - files - replace: - path: '{{ item.path }}' - regexp: ^[\s]*net.ipv4.conf.all.shared_media - replace: '#net.ipv4.conf.all.shared_media' - loop: '{{ find_sysctl_d.files }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv4_conf_all_shared_media -- name: XCCDF Value sysctl_net_ipv4_conf_all_shared_media_value # promote to variable - set_fact: - sysctl_net_ipv4_conf_all_shared_media_value: !!str - tags: - - always - -- name: Ensure sysctl net.ipv4.conf.all.shared_media is set - sysctl: - name: net.ipv4.conf.all.shared_media - value: '{{ sysctl_net_ipv4_conf_all_shared_media_value }}' - sysctl_file: /etc/sysctl.conf - state: present - reload: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv4_conf_all_shared_media - - - - - - - - - - - Disable Kernel Parameter for Accepting ICMP Redirects by Default on IPv4 Interfaces - To set the runtime status of the net.ipv4.conf.default.accept_redirects kernel parameter, run the following command: $ sudo sysctl -w net.ipv4.conf.default.accept_redirects=0 -To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv4.conf.default.accept_redirects = 0 - BP28(R22) - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 18 - 2 - 3 - 4 - 6 - 7 - 8 - 9 - 5.10.1.1 - APO01.06 - APO13.01 - BAI04.04 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS01.03 - DSS01.05 - DSS03.01 - DSS03.05 - DSS05.02 - DSS05.04 - DSS05.05 - DSS05.07 - DSS06.02 - DSS06.06 - 3.1.20 - CCI-000366 - CCI-001551 - 4.2.3.4 - 4.3.3.4 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - 4.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 6.2 - SR 7.1 - SR 7.2 - SR 7.6 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.12.1.1 - A.12.1.2 - A.12.1.3 - A.12.5.1 - A.12.6.2 - A.13.1.1 - A.13.1.2 - A.13.1.3 - A.13.2.1 - A.13.2.2 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.17.2.1 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CM-7(a) - CM-7(b) - CM-6(a) - SC-7(a) - DE.AE-1 - DE.CM-1 - ID.AM-3 - PR.AC-5 - PR.DS-4 - PR.DS-5 - PR.IP-1 - PR.PT-3 - PR.PT-4 - Req-1.4.3 - SRG-OS-000480-GPOS-00227 - ICMP redirect messages are used by routers to inform hosts that a more -direct route exists for a particular destination. These messages modify the -host's route table and are unauthenticated. An illicit ICMP redirect -message could result in a man-in-the-middle attack. -This feature of the IPv4 protocol has few legitimate uses. It should -be disabled unless absolutely required. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Comment out any occurrences of net.ipv4.conf.default.accept_redirects from /etc/sysctl.d/*.conf files - -for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do - - matching_list=$(grep -P '^(?!#).*[\s]*net.ipv4.conf.default.accept_redirects.*$' $f | uniq ) - if ! test -z "$matching_list"; then - while IFS= read -r entry; do - escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") - # comment out "net.ipv4.conf.default.accept_redirects" matches to preserve user data - sed -i "s/^${escaped_entry}$/# &/g" $f - done <<< "$matching_list" - fi -done - -# -# Set sysctl config file which to save the desired value -# - -SYSCONFIG_FILE="/etc/sysctl.conf" - -sysctl_net_ipv4_conf_default_accept_redirects_value='' - - -# -# Set runtime for net.ipv4.conf.default.accept_redirects -# -/sbin/sysctl -q -n -w net.ipv4.conf.default.accept_redirects="$sysctl_net_ipv4_conf_default_accept_redirects_value" - -# -# If net.ipv4.conf.default.accept_redirects present in /etc/sysctl.conf, change value to appropriate value -# else, add "net.ipv4.conf.default.accept_redirects = value" to /etc/sysctl.conf -# - -# Strip any search characters in the key arg so that the key can be replaced without -# adding any search characters to the config file. -stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv4.conf.default.accept_redirects") - -# shellcheck disable=SC2059 -printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv4_conf_default_accept_redirects_value" - -# If the key exists, change it. Otherwise, add it to the config_file. -# We search for the key string followed by a word boundary (matched by \>), -# so if we search for 'setting', 'setting2' won't match. -if LC_ALL=C grep -q -m 1 -i -e "^net.ipv4.conf.default.accept_redirects\\>" "${SYSCONFIG_FILE}"; then - escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") - LC_ALL=C sed -i --follow-symlinks "s/^net.ipv4.conf.default.accept_redirects\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" -else - if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then - LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" - fi - printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: List /etc/sysctl.d/*.conf files - find: - paths: - - /etc/sysctl.d/ - - /run/sysctl.d/ - - /usr/local/lib/sysctl.d/ - contains: ^[\s]*net.ipv4.conf.default.accept_redirects.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - CJIS-5.10.1.1 - - NIST-800-171-3.1.20 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-SC-7(a) - - PCI-DSS-Req-1.4.3 - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv4_conf_default_accept_redirects - -- name: Comment out any occurrences of net.ipv4.conf.default.accept_redirects from - config files - replace: - path: '{{ item.path }}' - regexp: ^[\s]*net.ipv4.conf.default.accept_redirects - replace: '#net.ipv4.conf.default.accept_redirects' - loop: '{{ find_sysctl_d.files }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - CJIS-5.10.1.1 - - NIST-800-171-3.1.20 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-SC-7(a) - - PCI-DSS-Req-1.4.3 - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv4_conf_default_accept_redirects -- name: XCCDF Value sysctl_net_ipv4_conf_default_accept_redirects_value # promote to variable - set_fact: - sysctl_net_ipv4_conf_default_accept_redirects_value: !!str - tags: - - always - -- name: Ensure sysctl net.ipv4.conf.default.accept_redirects is set - sysctl: - name: net.ipv4.conf.default.accept_redirects - value: '{{ sysctl_net_ipv4_conf_default_accept_redirects_value }}' - sysctl_file: /etc/sysctl.conf - state: present - reload: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - CJIS-5.10.1.1 - - NIST-800-171-3.1.20 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-SC-7(a) - - PCI-DSS-Req-1.4.3 - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv4_conf_default_accept_redirects - - - - - - - - - - - Disable Kernel Parameter for Accepting Source-Routed Packets on IPv4 Interfaces by Default - To set the runtime status of the net.ipv4.conf.default.accept_source_route kernel parameter, run the following command: $ sudo sysctl -w net.ipv4.conf.default.accept_source_route=0 -To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv4.conf.default.accept_source_route = 0 - BP28(R22) - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 18 - 2 - 3 - 4 - 6 - 7 - 8 - 9 - 5.10.1.1 - APO01.06 - APO13.01 - BAI04.04 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS01.03 - DSS01.05 - DSS03.01 - DSS03.05 - DSS05.02 - DSS05.04 - DSS05.05 - DSS05.07 - DSS06.02 - DSS06.06 - 3.1.20 - CCI-000366 - CCI-001551 - 4.2.3.4 - 4.3.3.4 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - 4.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 6.2 - SR 7.1 - SR 7.2 - SR 7.6 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.12.1.1 - A.12.1.2 - A.12.1.3 - A.12.5.1 - A.12.6.2 - A.13.1.1 - A.13.1.2 - A.13.1.3 - A.13.2.1 - A.13.2.2 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.17.2.1 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CIP-007-3 R4 - CIP-007-3 R4.1 - CIP-007-3 R4.2 - CIP-007-3 R5.1 - CM-7(a) - CM-7(b) - SC-5 - SC-7(a) - DE.AE-1 - DE.CM-1 - ID.AM-3 - PR.AC-5 - PR.DS-4 - PR.DS-5 - PR.IP-1 - PR.PT-3 - PR.PT-4 - SRG-OS-000480-GPOS-00227 - Source-routed packets allow the source of the packet to suggest routers -forward the packet along a different path than configured on the router, -which can be used to bypass network security measures. - -Accepting source-routed packets in the IPv4 protocol has few legitimate -uses. It should be disabled unless it is absolutely required, such as when -IPv4 forwarding is enabled and the system is legitimately functioning as a -router. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Comment out any occurrences of net.ipv4.conf.default.accept_source_route from /etc/sysctl.d/*.conf files - -for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do - - matching_list=$(grep -P '^(?!#).*[\s]*net.ipv4.conf.default.accept_source_route.*$' $f | uniq ) - if ! test -z "$matching_list"; then - while IFS= read -r entry; do - escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") - # comment out "net.ipv4.conf.default.accept_source_route" matches to preserve user data - sed -i "s/^${escaped_entry}$/# &/g" $f - done <<< "$matching_list" - fi -done - -# -# Set sysctl config file which to save the desired value -# - -SYSCONFIG_FILE="/etc/sysctl.conf" - -sysctl_net_ipv4_conf_default_accept_source_route_value='' - - -# -# Set runtime for net.ipv4.conf.default.accept_source_route -# -/sbin/sysctl -q -n -w net.ipv4.conf.default.accept_source_route="$sysctl_net_ipv4_conf_default_accept_source_route_value" - -# -# If net.ipv4.conf.default.accept_source_route present in /etc/sysctl.conf, change value to appropriate value -# else, add "net.ipv4.conf.default.accept_source_route = value" to /etc/sysctl.conf -# - -# Strip any search characters in the key arg so that the key can be replaced without -# adding any search characters to the config file. -stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv4.conf.default.accept_source_route") - -# shellcheck disable=SC2059 -printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv4_conf_default_accept_source_route_value" - -# If the key exists, change it. Otherwise, add it to the config_file. -# We search for the key string followed by a word boundary (matched by \>), -# so if we search for 'setting', 'setting2' won't match. -if LC_ALL=C grep -q -m 1 -i -e "^net.ipv4.conf.default.accept_source_route\\>" "${SYSCONFIG_FILE}"; then - escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") - LC_ALL=C sed -i --follow-symlinks "s/^net.ipv4.conf.default.accept_source_route\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" -else - if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then - LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" - fi - printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: List /etc/sysctl.d/*.conf files - find: - paths: - - /etc/sysctl.d/ - - /run/sysctl.d/ - - /usr/local/lib/sysctl.d/ - contains: ^[\s]*net.ipv4.conf.default.accept_source_route.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - CJIS-5.10.1.1 - - NIST-800-171-3.1.20 - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-SC-5 - - NIST-800-53-SC-7(a) - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv4_conf_default_accept_source_route - -- name: Comment out any occurrences of net.ipv4.conf.default.accept_source_route from - config files - replace: - path: '{{ item.path }}' - regexp: ^[\s]*net.ipv4.conf.default.accept_source_route - replace: '#net.ipv4.conf.default.accept_source_route' - loop: '{{ find_sysctl_d.files }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - CJIS-5.10.1.1 - - NIST-800-171-3.1.20 - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-SC-5 - - NIST-800-53-SC-7(a) - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv4_conf_default_accept_source_route -- name: XCCDF Value sysctl_net_ipv4_conf_default_accept_source_route_value # promote to variable - set_fact: - sysctl_net_ipv4_conf_default_accept_source_route_value: !!str - tags: - - always - -- name: Ensure sysctl net.ipv4.conf.default.accept_source_route is set - sysctl: - name: net.ipv4.conf.default.accept_source_route - value: '{{ sysctl_net_ipv4_conf_default_accept_source_route_value }}' - sysctl_file: /etc/sysctl.conf - state: present - reload: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - CJIS-5.10.1.1 - - NIST-800-171-3.1.20 - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-SC-5 - - NIST-800-53-SC-7(a) - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv4_conf_default_accept_source_route - - - - - - - - - - - Enable Kernel Paremeter to Log Martian Packets on all IPv4 Interfaces by Default - To set the runtime status of the net.ipv4.conf.default.log_martians kernel parameter, run the following command: $ sudo sysctl -w net.ipv4.conf.default.log_martians=1 -To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv4.conf.default.log_martians = 1 - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 2 - 3 - 7 - 8 - 9 - APO13.01 - BAI04.04 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS01.03 - DSS01.04 - DSS03.05 - DSS05.02 - DSS05.03 - DSS05.05 - DSS05.07 - DSS06.06 - 3.1.20 - CCI-000126 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 6.2 - SR 7.1 - SR 7.2 - SR 7.6 - A.11.2.6 - A.12.1.2 - A.12.1.3 - A.12.5.1 - A.12.6.2 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.17.2.1 - A.6.2.1 - A.6.2.2 - A.9.1.2 - CM-7(a) - CM-7(b) - SC-5(3)(a) - DE.CM-1 - PR.AC-3 - PR.DS-4 - PR.IP-1 - PR.PT-3 - PR.PT-4 - SRG-OS-000480-GPOS-00227 - The presence of "martian" packets (which have impossible addresses) -as well as spoofed packets, source-routed packets, and redirects could be a -sign of nefarious network activity. Logging these packets enables this activity -to be detected. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Comment out any occurrences of net.ipv4.conf.default.log_martians from /etc/sysctl.d/*.conf files - -for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do - - matching_list=$(grep -P '^(?!#).*[\s]*net.ipv4.conf.default.log_martians.*$' $f | uniq ) - if ! test -z "$matching_list"; then - while IFS= read -r entry; do - escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") - # comment out "net.ipv4.conf.default.log_martians" matches to preserve user data - sed -i "s/^${escaped_entry}$/# &/g" $f - done <<< "$matching_list" - fi -done - -# -# Set sysctl config file which to save the desired value -# - -SYSCONFIG_FILE="/etc/sysctl.conf" - -sysctl_net_ipv4_conf_default_log_martians_value='' - - -# -# Set runtime for net.ipv4.conf.default.log_martians -# -/sbin/sysctl -q -n -w net.ipv4.conf.default.log_martians="$sysctl_net_ipv4_conf_default_log_martians_value" - -# -# If net.ipv4.conf.default.log_martians present in /etc/sysctl.conf, change value to appropriate value -# else, add "net.ipv4.conf.default.log_martians = value" to /etc/sysctl.conf -# - -# Strip any search characters in the key arg so that the key can be replaced without -# adding any search characters to the config file. -stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv4.conf.default.log_martians") - -# shellcheck disable=SC2059 -printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv4_conf_default_log_martians_value" - -# If the key exists, change it. Otherwise, add it to the config_file. -# We search for the key string followed by a word boundary (matched by \>), -# so if we search for 'setting', 'setting2' won't match. -if LC_ALL=C grep -q -m 1 -i -e "^net.ipv4.conf.default.log_martians\\>" "${SYSCONFIG_FILE}"; then - escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") - LC_ALL=C sed -i --follow-symlinks "s/^net.ipv4.conf.default.log_martians\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" -else - if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then - LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" - fi - printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: List /etc/sysctl.d/*.conf files - find: - paths: - - /etc/sysctl.d/ - - /run/sysctl.d/ - - /usr/local/lib/sysctl.d/ - contains: ^[\s]*net.ipv4.conf.default.log_martians.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.20 - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-SC-5(3)(a) - - disable_strategy - - low_complexity - - medium_disruption - - reboot_required - - sysctl_net_ipv4_conf_default_log_martians - - unknown_severity - -- name: Comment out any occurrences of net.ipv4.conf.default.log_martians from config - files - replace: - path: '{{ item.path }}' - regexp: ^[\s]*net.ipv4.conf.default.log_martians - replace: '#net.ipv4.conf.default.log_martians' - loop: '{{ find_sysctl_d.files }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.20 - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-SC-5(3)(a) - - disable_strategy - - low_complexity - - medium_disruption - - reboot_required - - sysctl_net_ipv4_conf_default_log_martians - - unknown_severity -- name: XCCDF Value sysctl_net_ipv4_conf_default_log_martians_value # promote to variable - set_fact: - sysctl_net_ipv4_conf_default_log_martians_value: !!str - tags: - - always - -- name: Ensure sysctl net.ipv4.conf.default.log_martians is set - sysctl: - name: net.ipv4.conf.default.log_martians - value: '{{ sysctl_net_ipv4_conf_default_log_martians_value }}' - sysctl_file: /etc/sysctl.conf - state: present - reload: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.20 - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-SC-5(3)(a) - - disable_strategy - - low_complexity - - medium_disruption - - reboot_required - - sysctl_net_ipv4_conf_default_log_martians - - unknown_severity - - - - - - - - - - - Enable Kernel Parameter to Use Reverse Path Filtering on all IPv4 Interfaces by Default - To set the runtime status of the net.ipv4.conf.default.rp_filter kernel parameter, run the following command: $ sudo sysctl -w net.ipv4.conf.default.rp_filter=1 -To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv4.conf.default.rp_filter = 1 - BP28(R22) - 1 - 12 - 13 - 14 - 15 - 16 - 18 - 2 - 4 - 6 - 7 - 8 - 9 - APO01.06 - APO13.01 - BAI04.04 - DSS01.03 - DSS01.05 - DSS03.01 - DSS03.05 - DSS05.02 - DSS05.04 - DSS05.07 - DSS06.02 - 3.1.20 - CCI-000366 - 4.2.3.4 - 4.3.3.4 - 4.4.3.3 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 6.2 - SR 7.1 - SR 7.2 - SR 7.6 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.12.1.1 - A.12.1.2 - A.12.1.3 - A.13.1.1 - A.13.1.2 - A.13.1.3 - A.13.2.1 - A.13.2.2 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.17.2.1 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CM-7(a) - CM-7(b) - CM-6(a) - SC-7(a) - DE.AE-1 - DE.CM-1 - ID.AM-3 - PR.AC-5 - PR.DS-4 - PR.DS-5 - PR.PT-4 - SRG-OS-000480-GPOS-00227 - Enabling reverse path filtering drops packets with source addresses -that should not have been able to be received on the interface they were -received on. It should not be used on systems which are routers for -complicated networks, but is helpful for end hosts and routers serving small -networks. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Comment out any occurrences of net.ipv4.conf.default.rp_filter from /etc/sysctl.d/*.conf files - -for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do - - matching_list=$(grep -P '^(?!#).*[\s]*net.ipv4.conf.default.rp_filter.*$' $f | uniq ) - if ! test -z "$matching_list"; then - while IFS= read -r entry; do - escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") - # comment out "net.ipv4.conf.default.rp_filter" matches to preserve user data - sed -i "s/^${escaped_entry}$/# &/g" $f - done <<< "$matching_list" - fi -done - -# -# Set sysctl config file which to save the desired value -# - -SYSCONFIG_FILE="/etc/sysctl.conf" - -sysctl_net_ipv4_conf_default_rp_filter_value='' - - -# -# Set runtime for net.ipv4.conf.default.rp_filter -# -/sbin/sysctl -q -n -w net.ipv4.conf.default.rp_filter="$sysctl_net_ipv4_conf_default_rp_filter_value" - -# -# If net.ipv4.conf.default.rp_filter present in /etc/sysctl.conf, change value to appropriate value -# else, add "net.ipv4.conf.default.rp_filter = value" to /etc/sysctl.conf -# - -# Strip any search characters in the key arg so that the key can be replaced without -# adding any search characters to the config file. -stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv4.conf.default.rp_filter") - -# shellcheck disable=SC2059 -printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv4_conf_default_rp_filter_value" - -# If the key exists, change it. Otherwise, add it to the config_file. -# We search for the key string followed by a word boundary (matched by \>), -# so if we search for 'setting', 'setting2' won't match. -if LC_ALL=C grep -q -m 1 -i -e "^net.ipv4.conf.default.rp_filter\\>" "${SYSCONFIG_FILE}"; then - escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") - LC_ALL=C sed -i --follow-symlinks "s/^net.ipv4.conf.default.rp_filter\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" -else - if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then - LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" - fi - printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: List /etc/sysctl.d/*.conf files - find: - paths: - - /etc/sysctl.d/ - - /run/sysctl.d/ - - /usr/local/lib/sysctl.d/ - contains: ^[\s]*net.ipv4.conf.default.rp_filter.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.20 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-SC-7(a) - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv4_conf_default_rp_filter - -- name: Comment out any occurrences of net.ipv4.conf.default.rp_filter from config - files - replace: - path: '{{ item.path }}' - regexp: ^[\s]*net.ipv4.conf.default.rp_filter - replace: '#net.ipv4.conf.default.rp_filter' - loop: '{{ find_sysctl_d.files }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.20 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-SC-7(a) - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv4_conf_default_rp_filter -- name: XCCDF Value sysctl_net_ipv4_conf_default_rp_filter_value # promote to variable - set_fact: - sysctl_net_ipv4_conf_default_rp_filter_value: !!str - tags: - - always - -- name: Ensure sysctl net.ipv4.conf.default.rp_filter is set - sysctl: - name: net.ipv4.conf.default.rp_filter - value: '{{ sysctl_net_ipv4_conf_default_rp_filter_value }}' - sysctl_file: /etc/sysctl.conf - state: present - reload: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.20 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-SC-7(a) - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv4_conf_default_rp_filter - - - - - - - - - - - Configure Kernel Parameter for Accepting Secure Redirects By Default - To set the runtime status of the net.ipv4.conf.default.secure_redirects kernel parameter, run the following command: $ sudo sysctl -w net.ipv4.conf.default.secure_redirects=0 -To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv4.conf.default.secure_redirects = 0 - BP28(R22) - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 18 - 2 - 3 - 4 - 6 - 7 - 8 - 9 - APO01.06 - APO13.01 - BAI04.04 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS01.03 - DSS01.05 - DSS03.01 - DSS03.05 - DSS05.02 - DSS05.04 - DSS05.05 - DSS05.07 - DSS06.02 - DSS06.06 - 3.1.20 - CCI-001551 - 4.2.3.4 - 4.3.3.4 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - 4.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 6.2 - SR 7.1 - SR 7.2 - SR 7.6 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.12.1.1 - A.12.1.2 - A.12.1.3 - A.12.5.1 - A.12.6.2 - A.13.1.1 - A.13.1.2 - A.13.1.3 - A.13.2.1 - A.13.2.2 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.17.2.1 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CIP-007-3 R4 - CIP-007-3 R4.1 - CIP-007-3 R4.2 - CIP-007-3 R5.1 - CM-7(a) - CM-7(b) - SC-5 - SC-7(a) - DE.AE-1 - DE.CM-1 - ID.AM-3 - PR.AC-5 - PR.DS-4 - PR.DS-5 - PR.IP-1 - PR.PT-3 - PR.PT-4 - SRG-OS-000480-GPOS-00227 - Accepting "secure" ICMP redirects (from those gateways listed as -default gateways) has few legitimate uses. It should be disabled unless it is -absolutely required. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Comment out any occurrences of net.ipv4.conf.default.secure_redirects from /etc/sysctl.d/*.conf files - -for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do - - matching_list=$(grep -P '^(?!#).*[\s]*net.ipv4.conf.default.secure_redirects.*$' $f | uniq ) - if ! test -z "$matching_list"; then - while IFS= read -r entry; do - escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") - # comment out "net.ipv4.conf.default.secure_redirects" matches to preserve user data - sed -i "s/^${escaped_entry}$/# &/g" $f - done <<< "$matching_list" - fi -done - -# -# Set sysctl config file which to save the desired value -# - -SYSCONFIG_FILE="/etc/sysctl.conf" - -sysctl_net_ipv4_conf_default_secure_redirects_value='' - - -# -# Set runtime for net.ipv4.conf.default.secure_redirects -# -/sbin/sysctl -q -n -w net.ipv4.conf.default.secure_redirects="$sysctl_net_ipv4_conf_default_secure_redirects_value" - -# -# If net.ipv4.conf.default.secure_redirects present in /etc/sysctl.conf, change value to appropriate value -# else, add "net.ipv4.conf.default.secure_redirects = value" to /etc/sysctl.conf -# - -# Strip any search characters in the key arg so that the key can be replaced without -# adding any search characters to the config file. -stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv4.conf.default.secure_redirects") - -# shellcheck disable=SC2059 -printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv4_conf_default_secure_redirects_value" - -# If the key exists, change it. Otherwise, add it to the config_file. -# We search for the key string followed by a word boundary (matched by \>), -# so if we search for 'setting', 'setting2' won't match. -if LC_ALL=C grep -q -m 1 -i -e "^net.ipv4.conf.default.secure_redirects\\>" "${SYSCONFIG_FILE}"; then - escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") - LC_ALL=C sed -i --follow-symlinks "s/^net.ipv4.conf.default.secure_redirects\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" -else - if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then - LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" - fi - printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: List /etc/sysctl.d/*.conf files - find: - paths: - - /etc/sysctl.d/ - - /run/sysctl.d/ - - /usr/local/lib/sysctl.d/ - contains: ^[\s]*net.ipv4.conf.default.secure_redirects.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.20 - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-SC-5 - - NIST-800-53-SC-7(a) - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv4_conf_default_secure_redirects - -- name: Comment out any occurrences of net.ipv4.conf.default.secure_redirects from - config files - replace: - path: '{{ item.path }}' - regexp: ^[\s]*net.ipv4.conf.default.secure_redirects - replace: '#net.ipv4.conf.default.secure_redirects' - loop: '{{ find_sysctl_d.files }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.20 - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-SC-5 - - NIST-800-53-SC-7(a) - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv4_conf_default_secure_redirects -- name: XCCDF Value sysctl_net_ipv4_conf_default_secure_redirects_value # promote to variable - set_fact: - sysctl_net_ipv4_conf_default_secure_redirects_value: !!str - tags: - - always - -- name: Ensure sysctl net.ipv4.conf.default.secure_redirects is set - sysctl: - name: net.ipv4.conf.default.secure_redirects - value: '{{ sysctl_net_ipv4_conf_default_secure_redirects_value }}' - sysctl_file: /etc/sysctl.conf - state: present - reload: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.20 - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-SC-5 - - NIST-800-53-SC-7(a) - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv4_conf_default_secure_redirects - - - - - - - - - - - Configure Sending and Accepting Shared Media Redirects by Default - To set the runtime status of the net.ipv4.conf.default.shared_media kernel parameter, run the following command: $ sudo sysctl -w net.ipv4.conf.default.shared_media= -To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv4.conf.default.shared_media = - BP28(R12) - This setting should be aligned with net.ipv4.conf.default.secure_redirects because it overrides it. -If shared_media is enabled for an interface secure_redirects will be enabled too. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Comment out any occurrences of net.ipv4.conf.default.shared_media from /etc/sysctl.d/*.conf files - -for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do - - matching_list=$(grep -P '^(?!#).*[\s]*net.ipv4.conf.default.shared_media.*$' $f | uniq ) - if ! test -z "$matching_list"; then - while IFS= read -r entry; do - escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") - # comment out "net.ipv4.conf.default.shared_media" matches to preserve user data - sed -i "s/^${escaped_entry}$/# &/g" $f - done <<< "$matching_list" - fi -done - -# -# Set sysctl config file which to save the desired value -# - -SYSCONFIG_FILE="/etc/sysctl.conf" - -sysctl_net_ipv4_conf_default_shared_media_value='' - - -# -# Set runtime for net.ipv4.conf.default.shared_media -# -/sbin/sysctl -q -n -w net.ipv4.conf.default.shared_media="$sysctl_net_ipv4_conf_default_shared_media_value" - -# -# If net.ipv4.conf.default.shared_media present in /etc/sysctl.conf, change value to appropriate value -# else, add "net.ipv4.conf.default.shared_media = value" to /etc/sysctl.conf -# - -# Strip any search characters in the key arg so that the key can be replaced without -# adding any search characters to the config file. -stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv4.conf.default.shared_media") - -# shellcheck disable=SC2059 -printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv4_conf_default_shared_media_value" - -# If the key exists, change it. Otherwise, add it to the config_file. -# We search for the key string followed by a word boundary (matched by \>), -# so if we search for 'setting', 'setting2' won't match. -if LC_ALL=C grep -q -m 1 -i -e "^net.ipv4.conf.default.shared_media\\>" "${SYSCONFIG_FILE}"; then - escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") - LC_ALL=C sed -i --follow-symlinks "s/^net.ipv4.conf.default.shared_media\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" -else - if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then - LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" - fi - printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: List /etc/sysctl.d/*.conf files - find: - paths: - - /etc/sysctl.d/ - - /run/sysctl.d/ - - /usr/local/lib/sysctl.d/ - contains: ^[\s]*net.ipv4.conf.default.shared_media.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv4_conf_default_shared_media - -- name: Comment out any occurrences of net.ipv4.conf.default.shared_media from config - files - replace: - path: '{{ item.path }}' - regexp: ^[\s]*net.ipv4.conf.default.shared_media - replace: '#net.ipv4.conf.default.shared_media' - loop: '{{ find_sysctl_d.files }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv4_conf_default_shared_media -- name: XCCDF Value sysctl_net_ipv4_conf_default_shared_media_value # promote to variable - set_fact: - sysctl_net_ipv4_conf_default_shared_media_value: !!str - tags: - - always - -- name: Ensure sysctl net.ipv4.conf.default.shared_media is set - sysctl: - name: net.ipv4.conf.default.shared_media - value: '{{ sysctl_net_ipv4_conf_default_shared_media_value }}' - sysctl_file: /etc/sysctl.conf - state: present - reload: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv4_conf_default_shared_media - - - - - - - - - - - Enable Kernel Parameter to Ignore ICMP Broadcast Echo Requests on IPv4 Interfaces - To set the runtime status of the net.ipv4.icmp_echo_ignore_broadcasts kernel parameter, run the following command: $ sudo sysctl -w net.ipv4.icmp_echo_ignore_broadcasts=1 -To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv4.icmp_echo_ignore_broadcasts = 1 - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 18 - 2 - 3 - 4 - 6 - 7 - 8 - 9 - 5.10.1.1 - APO01.06 - APO13.01 - BAI04.04 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS01.03 - DSS01.05 - DSS03.01 - DSS03.05 - DSS05.02 - DSS05.04 - DSS05.05 - DSS05.07 - DSS06.02 - DSS06.06 - 3.1.20 - CCI-000366 - 4.2.3.4 - 4.3.3.4 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - 4.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 6.2 - SR 7.1 - SR 7.2 - SR 7.6 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.12.1.1 - A.12.1.2 - A.12.1.3 - A.12.5.1 - A.12.6.2 - A.13.1.1 - A.13.1.2 - A.13.1.3 - A.13.2.1 - A.13.2.2 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.17.2.1 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CIP-007-3 R4 - CIP-007-3 R4.1 - CIP-007-3 R4.2 - CIP-007-3 R5.1 - CM-7(a) - CM-7(b) - SC-5 - DE.AE-1 - DE.CM-1 - ID.AM-3 - PR.AC-5 - PR.DS-4 - PR.DS-5 - PR.IP-1 - PR.PT-3 - PR.PT-4 - Req-1.4.3 - SRG-OS-000480-GPOS-00227 - Responding to broadcast (ICMP) echoes facilitates network mapping -and provides a vector for amplification attacks. - -Ignoring ICMP echo requests (pings) sent to broadcast or multicast -addresses makes the system slightly more difficult to enumerate on the network. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Comment out any occurrences of net.ipv4.icmp_echo_ignore_broadcasts from /etc/sysctl.d/*.conf files - -for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do - - matching_list=$(grep -P '^(?!#).*[\s]*net.ipv4.icmp_echo_ignore_broadcasts.*$' $f | uniq ) - if ! test -z "$matching_list"; then - while IFS= read -r entry; do - escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") - # comment out "net.ipv4.icmp_echo_ignore_broadcasts" matches to preserve user data - sed -i "s/^${escaped_entry}$/# &/g" $f - done <<< "$matching_list" - fi -done - -# -# Set sysctl config file which to save the desired value -# - -SYSCONFIG_FILE="/etc/sysctl.conf" - -sysctl_net_ipv4_icmp_echo_ignore_broadcasts_value='' - - -# -# Set runtime for net.ipv4.icmp_echo_ignore_broadcasts -# -/sbin/sysctl -q -n -w net.ipv4.icmp_echo_ignore_broadcasts="$sysctl_net_ipv4_icmp_echo_ignore_broadcasts_value" - -# -# If net.ipv4.icmp_echo_ignore_broadcasts present in /etc/sysctl.conf, change value to appropriate value -# else, add "net.ipv4.icmp_echo_ignore_broadcasts = value" to /etc/sysctl.conf -# - -# Strip any search characters in the key arg so that the key can be replaced without -# adding any search characters to the config file. -stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv4.icmp_echo_ignore_broadcasts") - -# shellcheck disable=SC2059 -printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv4_icmp_echo_ignore_broadcasts_value" - -# If the key exists, change it. Otherwise, add it to the config_file. -# We search for the key string followed by a word boundary (matched by \>), -# so if we search for 'setting', 'setting2' won't match. -if LC_ALL=C grep -q -m 1 -i -e "^net.ipv4.icmp_echo_ignore_broadcasts\\>" "${SYSCONFIG_FILE}"; then - escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") - LC_ALL=C sed -i --follow-symlinks "s/^net.ipv4.icmp_echo_ignore_broadcasts\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" -else - if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then - LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" - fi - printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: List /etc/sysctl.d/*.conf files - find: - paths: - - /etc/sysctl.d/ - - /run/sysctl.d/ - - /usr/local/lib/sysctl.d/ - contains: ^[\s]*net.ipv4.icmp_echo_ignore_broadcasts.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - CJIS-5.10.1.1 - - NIST-800-171-3.1.20 - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-SC-5 - - PCI-DSS-Req-1.4.3 - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv4_icmp_echo_ignore_broadcasts - -- name: Comment out any occurrences of net.ipv4.icmp_echo_ignore_broadcasts from config - files - replace: - path: '{{ item.path }}' - regexp: ^[\s]*net.ipv4.icmp_echo_ignore_broadcasts - replace: '#net.ipv4.icmp_echo_ignore_broadcasts' - loop: '{{ find_sysctl_d.files }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - CJIS-5.10.1.1 - - NIST-800-171-3.1.20 - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-SC-5 - - PCI-DSS-Req-1.4.3 - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv4_icmp_echo_ignore_broadcasts -- name: XCCDF Value sysctl_net_ipv4_icmp_echo_ignore_broadcasts_value # promote to variable - set_fact: - sysctl_net_ipv4_icmp_echo_ignore_broadcasts_value: !!str - tags: - - always - -- name: Ensure sysctl net.ipv4.icmp_echo_ignore_broadcasts is set - sysctl: - name: net.ipv4.icmp_echo_ignore_broadcasts - value: '{{ sysctl_net_ipv4_icmp_echo_ignore_broadcasts_value }}' - sysctl_file: /etc/sysctl.conf - state: present - reload: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - CJIS-5.10.1.1 - - NIST-800-171-3.1.20 - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-SC-5 - - PCI-DSS-Req-1.4.3 - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv4_icmp_echo_ignore_broadcasts - - - - - - - - - - - Enable Kernel Parameter to Ignore Bogus ICMP Error Responses on IPv4 Interfaces - To set the runtime status of the net.ipv4.icmp_ignore_bogus_error_responses kernel parameter, run the following command: $ sudo sysctl -w net.ipv4.icmp_ignore_bogus_error_responses=1 -To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv4.icmp_ignore_bogus_error_responses = 1 - BP28(R22) - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 2 - 3 - 7 - 8 - 9 - APO13.01 - BAI04.04 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS01.03 - DSS03.05 - DSS05.02 - DSS05.05 - DSS05.07 - DSS06.06 - 3.1.20 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 6.2 - SR 7.1 - SR 7.2 - SR 7.6 - A.12.1.2 - A.12.1.3 - A.12.5.1 - A.12.6.2 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.17.2.1 - A.9.1.2 - CIP-007-3 R4 - CIP-007-3 R4.1 - CIP-007-3 R4.2 - CIP-007-3 R5.1 - CM-7(a) - CM-7(b) - SC-5 - DE.CM-1 - PR.DS-4 - PR.IP-1 - PR.PT-3 - Req-1.4.3 - SRG-OS-000480-GPOS-00227 - Ignoring bogus ICMP error responses reduces -log size, although some activity would not be logged. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Comment out any occurrences of net.ipv4.icmp_ignore_bogus_error_responses from /etc/sysctl.d/*.conf files - -for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do - - matching_list=$(grep -P '^(?!#).*[\s]*net.ipv4.icmp_ignore_bogus_error_responses.*$' $f | uniq ) - if ! test -z "$matching_list"; then - while IFS= read -r entry; do - escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") - # comment out "net.ipv4.icmp_ignore_bogus_error_responses" matches to preserve user data - sed -i "s/^${escaped_entry}$/# &/g" $f - done <<< "$matching_list" - fi -done - -# -# Set sysctl config file which to save the desired value -# - -SYSCONFIG_FILE="/etc/sysctl.conf" - -sysctl_net_ipv4_icmp_ignore_bogus_error_responses_value='' - - -# -# Set runtime for net.ipv4.icmp_ignore_bogus_error_responses -# -/sbin/sysctl -q -n -w net.ipv4.icmp_ignore_bogus_error_responses="$sysctl_net_ipv4_icmp_ignore_bogus_error_responses_value" - -# -# If net.ipv4.icmp_ignore_bogus_error_responses present in /etc/sysctl.conf, change value to appropriate value -# else, add "net.ipv4.icmp_ignore_bogus_error_responses = value" to /etc/sysctl.conf -# - -# Strip any search characters in the key arg so that the key can be replaced without -# adding any search characters to the config file. -stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv4.icmp_ignore_bogus_error_responses") - -# shellcheck disable=SC2059 -printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv4_icmp_ignore_bogus_error_responses_value" - -# If the key exists, change it. Otherwise, add it to the config_file. -# We search for the key string followed by a word boundary (matched by \>), -# so if we search for 'setting', 'setting2' won't match. -if LC_ALL=C grep -q -m 1 -i -e "^net.ipv4.icmp_ignore_bogus_error_responses\\>" "${SYSCONFIG_FILE}"; then - escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") - LC_ALL=C sed -i --follow-symlinks "s/^net.ipv4.icmp_ignore_bogus_error_responses\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" -else - if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then - LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" - fi - printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: List /etc/sysctl.d/*.conf files - find: - paths: - - /etc/sysctl.d/ - - /run/sysctl.d/ - - /usr/local/lib/sysctl.d/ - contains: ^[\s]*net.ipv4.icmp_ignore_bogus_error_responses.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.20 - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-SC-5 - - PCI-DSS-Req-1.4.3 - - disable_strategy - - low_complexity - - medium_disruption - - reboot_required - - sysctl_net_ipv4_icmp_ignore_bogus_error_responses - - unknown_severity - -- name: Comment out any occurrences of net.ipv4.icmp_ignore_bogus_error_responses - from config files - replace: - path: '{{ item.path }}' - regexp: ^[\s]*net.ipv4.icmp_ignore_bogus_error_responses - replace: '#net.ipv4.icmp_ignore_bogus_error_responses' - loop: '{{ find_sysctl_d.files }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.20 - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-SC-5 - - PCI-DSS-Req-1.4.3 - - disable_strategy - - low_complexity - - medium_disruption - - reboot_required - - sysctl_net_ipv4_icmp_ignore_bogus_error_responses - - unknown_severity -- name: XCCDF Value sysctl_net_ipv4_icmp_ignore_bogus_error_responses_value # promote to variable - set_fact: - sysctl_net_ipv4_icmp_ignore_bogus_error_responses_value: !!str - tags: - - always - -- name: Ensure sysctl net.ipv4.icmp_ignore_bogus_error_responses is set - sysctl: - name: net.ipv4.icmp_ignore_bogus_error_responses - value: '{{ sysctl_net_ipv4_icmp_ignore_bogus_error_responses_value }}' - sysctl_file: /etc/sysctl.conf - state: present - reload: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.20 - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-SC-5 - - PCI-DSS-Req-1.4.3 - - disable_strategy - - low_complexity - - medium_disruption - - reboot_required - - sysctl_net_ipv4_icmp_ignore_bogus_error_responses - - unknown_severity - - - - - - - - - - - Set Kernel Parameter to Increase Local Port Range - To set the runtime status of the net.ipv4.ip_local_port_range kernel parameter, run the following command: $ sudo sysctl -w net.ipv4.ip_local_port_range=32768 65535 -To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv4.ip_local_port_range = 32768 65535 - BP28(R22) - This setting defines the local port range that is used by TCP and UDP to -choose the local port. The first number is the first, the second the last -local port number. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Comment out any occurrences of net.ipv4.ip_local_port_range from /etc/sysctl.d/*.conf files - -for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do - - matching_list=$(grep -P '^(?!#).*[\s]*net.ipv4.ip_local_port_range.*$' $f | uniq ) - if ! test -z "$matching_list"; then - while IFS= read -r entry; do - escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") - # comment out "net.ipv4.ip_local_port_range" matches to preserve user data - sed -i "s/^${escaped_entry}$/# &/g" $f - done <<< "$matching_list" - fi -done - -# -# Set sysctl config file which to save the desired value -# - -SYSCONFIG_FILE="/etc/sysctl.conf" - - -# -# Set runtime for net.ipv4.ip_local_port_range -# -/sbin/sysctl -q -n -w net.ipv4.ip_local_port_range="32768 65535" - -# -# If net.ipv4.ip_local_port_range present in /etc/sysctl.conf, change value to "32768 65535" -# else, add "net.ipv4.ip_local_port_range = 32768 65535" to /etc/sysctl.conf -# - -# Strip any search characters in the key arg so that the key can be replaced without -# adding any search characters to the config file. -stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv4.ip_local_port_range") - -# shellcheck disable=SC2059 -printf -v formatted_output "%s = %s" "$stripped_key" "32768 65535" - -# If the key exists, change it. Otherwise, add it to the config_file. -# We search for the key string followed by a word boundary (matched by \>), -# so if we search for 'setting', 'setting2' won't match. -if LC_ALL=C grep -q -m 1 -i -e "^net.ipv4.ip_local_port_range\\>" "${SYSCONFIG_FILE}"; then - escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") - LC_ALL=C sed -i --follow-symlinks "s/^net.ipv4.ip_local_port_range\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" -else - if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then - LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" - fi - printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: List /etc/sysctl.d/*.conf files - find: - paths: - - /etc/sysctl.d/ - - /run/sysctl.d/ - - /usr/local/lib/sysctl.d/ - contains: ^[\s]*net.ipv4.ip_local_port_range.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv4_ip_local_port_range - -- name: Comment out any occurrences of net.ipv4.ip_local_port_range from config files - replace: - path: '{{ item.path }}' - regexp: ^[\s]*net.ipv4.ip_local_port_range - replace: '#net.ipv4.ip_local_port_range' - loop: '{{ find_sysctl_d.files }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv4_ip_local_port_range - -- name: Ensure sysctl net.ipv4.ip_local_port_range is set to 32768 65535 - sysctl: - name: net.ipv4.ip_local_port_range - value: 32768 65535 - sysctl_file: /etc/sysctl.conf - state: present - reload: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv4_ip_local_port_range - - - - - - - - - - Configure Kernel to Rate Limit Sending of Duplicate TCP Acknowledgments - Make sure that the system is configured to limit the maximal rate for sending -duplicate acknowledgments in response to incoming TCP packets that are for -an existing connection but that are invalid due to any of these reasons: - -(a) out-of-window sequence number, (b) out-of-window acknowledgment number, -or (c) PAWS (Protection Against Wrapped Sequence numbers) check failure -This measure protects against or limits effects of DoS attacks against the system. -Set the system to implement rate-limiting measures by adding the following line to -/etc/sysctl.conf or a configuration file in the /etc/sysctl.d/ directory -(or modify the line to have the required value): -net.ipv4.tcp_invalid_ratelimit = -Issue the following command to make the changes take effect: -# sysctl --system - CCI-002385 - CIP-007-3 R4 - CIP-007-3 R4.1 - CIP-007-3 R4.2 - CIP-007-3 R5.1 - SC-5 - SRG-OS-000420-GPOS-00186 - Denial of Service (DoS) is a condition when a resource is not available for legitimate users. When -this occurs, the organization either cannot accomplish its mission or must -operate at degraded capacity. - -This can help mitigate simple “ack loop” DoS attacks, wherein a buggy or -malicious middlebox or man-in-the-middle can rewrite TCP header fields in -manner that causes each endpoint to think that the other is sending invalid -TCP segments, thus causing each side to send an unterminating stream of -duplicate acknowledgments for invalid segments. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Comment out any occurrences of net.ipv4.tcp_invalid_ratelimit from /etc/sysctl.d/*.conf files - -for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do - - matching_list=$(grep -P '^(?!#).*[\s]*net.ipv4.tcp_invalid_ratelimit.*$' $f | uniq ) - if ! test -z "$matching_list"; then - while IFS= read -r entry; do - escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") - # comment out "net.ipv4.tcp_invalid_ratelimit" matches to preserve user data - sed -i "s/^${escaped_entry}$/# &/g" $f - done <<< "$matching_list" - fi -done - -# -# Set sysctl config file which to save the desired value -# - -SYSCONFIG_FILE="/etc/sysctl.conf" - -sysctl_net_ipv4_tcp_invalid_ratelimit_value='' - - -# -# Set runtime for net.ipv4.tcp_invalid_ratelimit -# -/sbin/sysctl -q -n -w net.ipv4.tcp_invalid_ratelimit="$sysctl_net_ipv4_tcp_invalid_ratelimit_value" - -# -# If net.ipv4.tcp_invalid_ratelimit present in /etc/sysctl.conf, change value to appropriate value -# else, add "net.ipv4.tcp_invalid_ratelimit = value" to /etc/sysctl.conf -# - -# Strip any search characters in the key arg so that the key can be replaced without -# adding any search characters to the config file. -stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv4.tcp_invalid_ratelimit") - -# shellcheck disable=SC2059 -printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv4_tcp_invalid_ratelimit_value" - -# If the key exists, change it. Otherwise, add it to the config_file. -# We search for the key string followed by a word boundary (matched by \>), -# so if we search for 'setting', 'setting2' won't match. -if LC_ALL=C grep -q -m 1 -i -e "^net.ipv4.tcp_invalid_ratelimit\\>" "${SYSCONFIG_FILE}"; then - escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") - LC_ALL=C sed -i --follow-symlinks "s/^net.ipv4.tcp_invalid_ratelimit\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" -else - if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then - LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" - fi - printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: List /etc/sysctl.d/*.conf files - find: - paths: - - /etc/sysctl.d/ - - /run/sysctl.d/ - - /usr/local/lib/sysctl.d/ - contains: ^[\s]*net.ipv4.tcp_invalid_ratelimit.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-SC-5 - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv4_tcp_invalid_ratelimit - -- name: Comment out any occurrences of net.ipv4.tcp_invalid_ratelimit from config - files - replace: - path: '{{ item.path }}' - regexp: ^[\s]*net.ipv4.tcp_invalid_ratelimit - replace: '#net.ipv4.tcp_invalid_ratelimit' - loop: '{{ find_sysctl_d.files }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-SC-5 - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv4_tcp_invalid_ratelimit -- name: XCCDF Value sysctl_net_ipv4_tcp_invalid_ratelimit_value # promote to variable - set_fact: - sysctl_net_ipv4_tcp_invalid_ratelimit_value: !!str - tags: - - always - -- name: Ensure sysctl net.ipv4.tcp_invalid_ratelimit is set - sysctl: - name: net.ipv4.tcp_invalid_ratelimit - value: '{{ sysctl_net_ipv4_tcp_invalid_ratelimit_value }}' - sysctl_file: /etc/sysctl.conf - state: present - reload: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-SC-5 - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv4_tcp_invalid_ratelimit - - - - - - - - - - - Enable Kernel Parameter to Use TCP RFC 1337 on IPv4 Interfaces - To set the runtime status of the net.ipv4.tcp_rfc1337 kernel parameter, run the following command: $ sudo sysctl -w net.ipv4.tcp_rfc1337=1 -To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv4.tcp_rfc1337 = 1 - BP28(R22) - Enable TCP behavior conformant with RFC 1337. When disabled, if a RST is -received in TIME_WAIT state, we close the socket immediately without waiting -for the end of the TIME_WAIT period. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Comment out any occurrences of net.ipv4.tcp_rfc1337 from /etc/sysctl.d/*.conf files - -for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do - - matching_list=$(grep -P '^(?!#).*[\s]*net.ipv4.tcp_rfc1337.*$' $f | uniq ) - if ! test -z "$matching_list"; then - while IFS= read -r entry; do - escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") - # comment out "net.ipv4.tcp_rfc1337" matches to preserve user data - sed -i "s/^${escaped_entry}$/# &/g" $f - done <<< "$matching_list" - fi -done - -# -# Set sysctl config file which to save the desired value -# - -SYSCONFIG_FILE="/etc/sysctl.conf" - -sysctl_net_ipv4_tcp_rfc1337_value='' - - -# -# Set runtime for net.ipv4.tcp_rfc1337 -# -/sbin/sysctl -q -n -w net.ipv4.tcp_rfc1337="$sysctl_net_ipv4_tcp_rfc1337_value" - -# -# If net.ipv4.tcp_rfc1337 present in /etc/sysctl.conf, change value to appropriate value -# else, add "net.ipv4.tcp_rfc1337 = value" to /etc/sysctl.conf -# - -# Strip any search characters in the key arg so that the key can be replaced without -# adding any search characters to the config file. -stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv4.tcp_rfc1337") - -# shellcheck disable=SC2059 -printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv4_tcp_rfc1337_value" - -# If the key exists, change it. Otherwise, add it to the config_file. -# We search for the key string followed by a word boundary (matched by \>), -# so if we search for 'setting', 'setting2' won't match. -if LC_ALL=C grep -q -m 1 -i -e "^net.ipv4.tcp_rfc1337\\>" "${SYSCONFIG_FILE}"; then - escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") - LC_ALL=C sed -i --follow-symlinks "s/^net.ipv4.tcp_rfc1337\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" -else - if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then - LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" - fi - printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: List /etc/sysctl.d/*.conf files - find: - paths: - - /etc/sysctl.d/ - - /run/sysctl.d/ - - /usr/local/lib/sysctl.d/ - contains: ^[\s]*net.ipv4.tcp_rfc1337.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv4_tcp_rfc1337 - -- name: Comment out any occurrences of net.ipv4.tcp_rfc1337 from config files - replace: - path: '{{ item.path }}' - regexp: ^[\s]*net.ipv4.tcp_rfc1337 - replace: '#net.ipv4.tcp_rfc1337' - loop: '{{ find_sysctl_d.files }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv4_tcp_rfc1337 -- name: XCCDF Value sysctl_net_ipv4_tcp_rfc1337_value # promote to variable - set_fact: - sysctl_net_ipv4_tcp_rfc1337_value: !!str - tags: - - always - -- name: Ensure sysctl net.ipv4.tcp_rfc1337 is set - sysctl: - name: net.ipv4.tcp_rfc1337 - value: '{{ sysctl_net_ipv4_tcp_rfc1337_value }}' - sysctl_file: /etc/sysctl.conf - state: present - reload: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv4_tcp_rfc1337 - - - - - - - - - - - Enable Kernel Parameter to Use TCP Syncookies on Network Interfaces - To set the runtime status of the net.ipv4.tcp_syncookies kernel parameter, run the following command: $ sudo sysctl -w net.ipv4.tcp_syncookies=1 -To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv4.tcp_syncookies = 1 - BP28(R22) - 1 - 12 - 13 - 14 - 15 - 16 - 18 - 2 - 4 - 6 - 7 - 8 - 9 - 5.10.1.1 - APO01.06 - APO13.01 - BAI04.04 - DSS01.03 - DSS01.05 - DSS03.01 - DSS03.05 - DSS05.02 - DSS05.04 - DSS05.07 - DSS06.02 - 3.1.20 - CCI-000366 - CCI-001095 - 4.2.3.4 - 4.3.3.4 - 4.4.3.3 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 6.2 - SR 7.1 - SR 7.2 - SR 7.6 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.12.1.1 - A.12.1.2 - A.12.1.3 - A.13.1.1 - A.13.1.2 - A.13.1.3 - A.13.2.1 - A.13.2.2 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.17.2.1 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CM-7(a) - CM-7(b) - SC-5(1) - SC-5(2) - SC-5(3)(a) - CM-6(a) - DE.AE-1 - DE.CM-1 - ID.AM-3 - PR.AC-5 - PR.DS-4 - PR.DS-5 - PR.PT-4 - Req-1.4.1 - SRG-OS-000480-GPOS-00227 - SRG-OS-000420-GPOS-00186 - SRG-OS-000142-GPOS-00071 - A TCP SYN flood attack can cause a denial of service by filling a -system's TCP connection table with connections in the SYN_RCVD state. -Syncookies can be used to track a connection when a subsequent ACK is received, -verifying the initiator is attempting a valid connection and is not a flood -source. This feature is activated when a flood condition is detected, and -enables the system to continue servicing valid connection requests. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Comment out any occurrences of net.ipv4.tcp_syncookies from /etc/sysctl.d/*.conf files - -for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do - - matching_list=$(grep -P '^(?!#).*[\s]*net.ipv4.tcp_syncookies.*$' $f | uniq ) - if ! test -z "$matching_list"; then - while IFS= read -r entry; do - escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") - # comment out "net.ipv4.tcp_syncookies" matches to preserve user data - sed -i "s/^${escaped_entry}$/# &/g" $f - done <<< "$matching_list" - fi -done - -# -# Set sysctl config file which to save the desired value -# - -SYSCONFIG_FILE="/etc/sysctl.conf" - -sysctl_net_ipv4_tcp_syncookies_value='' - - -# -# Set runtime for net.ipv4.tcp_syncookies -# -/sbin/sysctl -q -n -w net.ipv4.tcp_syncookies="$sysctl_net_ipv4_tcp_syncookies_value" - -# -# If net.ipv4.tcp_syncookies present in /etc/sysctl.conf, change value to appropriate value -# else, add "net.ipv4.tcp_syncookies = value" to /etc/sysctl.conf -# - -# Strip any search characters in the key arg so that the key can be replaced without -# adding any search characters to the config file. -stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv4.tcp_syncookies") - -# shellcheck disable=SC2059 -printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv4_tcp_syncookies_value" - -# If the key exists, change it. Otherwise, add it to the config_file. -# We search for the key string followed by a word boundary (matched by \>), -# so if we search for 'setting', 'setting2' won't match. -if LC_ALL=C grep -q -m 1 -i -e "^net.ipv4.tcp_syncookies\\>" "${SYSCONFIG_FILE}"; then - escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") - LC_ALL=C sed -i --follow-symlinks "s/^net.ipv4.tcp_syncookies\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" -else - if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then - LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" - fi - printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: List /etc/sysctl.d/*.conf files - find: - paths: - - /etc/sysctl.d/ - - /run/sysctl.d/ - - /usr/local/lib/sysctl.d/ - contains: ^[\s]*net.ipv4.tcp_syncookies.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - CJIS-5.10.1.1 - - NIST-800-171-3.1.20 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-SC-5(1) - - NIST-800-53-SC-5(2) - - NIST-800-53-SC-5(3)(a) - - PCI-DSS-Req-1.4.1 - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv4_tcp_syncookies - -- name: Comment out any occurrences of net.ipv4.tcp_syncookies from config files - replace: - path: '{{ item.path }}' - regexp: ^[\s]*net.ipv4.tcp_syncookies - replace: '#net.ipv4.tcp_syncookies' - loop: '{{ find_sysctl_d.files }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - CJIS-5.10.1.1 - - NIST-800-171-3.1.20 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-SC-5(1) - - NIST-800-53-SC-5(2) - - NIST-800-53-SC-5(3)(a) - - PCI-DSS-Req-1.4.1 - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv4_tcp_syncookies -- name: XCCDF Value sysctl_net_ipv4_tcp_syncookies_value # promote to variable - set_fact: - sysctl_net_ipv4_tcp_syncookies_value: !!str - tags: - - always - -- name: Ensure sysctl net.ipv4.tcp_syncookies is set - sysctl: - name: net.ipv4.tcp_syncookies - value: '{{ sysctl_net_ipv4_tcp_syncookies_value }}' - sysctl_file: /etc/sysctl.conf - state: present - reload: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - CJIS-5.10.1.1 - - NIST-800-171-3.1.20 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-SC-5(1) - - NIST-800-53-SC-5(2) - - NIST-800-53-SC-5(3)(a) - - PCI-DSS-Req-1.4.1 - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv4_tcp_syncookies - - - - - - - - - - - - Network Parameters for Hosts Only - If the system is not going to be used as a router, then setting certain -kernel parameters ensure that the host will not perform routing -of network traffic. - - - Disable Kernel Parameter for Sending ICMP Redirects on all IPv4 Interfaces - To set the runtime status of the net.ipv4.conf.all.send_redirects kernel parameter, run the following command: $ sudo sysctl -w net.ipv4.conf.all.send_redirects=0 -To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv4.conf.all.send_redirects = 0 - BP28(R22) - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 18 - 2 - 3 - 4 - 6 - 7 - 8 - 9 - 5.10.1.1 - APO01.06 - APO13.01 - BAI04.04 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS01.03 - DSS01.05 - DSS03.01 - DSS03.05 - DSS05.02 - DSS05.04 - DSS05.05 - DSS05.07 - DSS06.02 - DSS06.06 - 3.1.20 - CCI-000366 - 4.2.3.4 - 4.3.3.4 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - 4.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 6.2 - SR 7.1 - SR 7.2 - SR 7.6 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.12.1.1 - A.12.1.2 - A.12.1.3 - A.12.5.1 - A.12.6.2 - A.13.1.1 - A.13.1.2 - A.13.1.3 - A.13.2.1 - A.13.2.2 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.17.2.1 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CIP-007-3 R4 - CIP-007-3 R4.1 - CIP-007-3 R4.2 - CIP-007-3 R5.1 - CM-7(a) - CM-7(b) - SC-5 - CM-6(a) - SC-7(a) - DE.AE-1 - DE.CM-1 - ID.AM-3 - PR.AC-5 - PR.DS-4 - PR.DS-5 - PR.IP-1 - PR.PT-3 - PR.PT-4 - 1.4.2 - SRG-OS-000480-GPOS-00227 - ICMP redirect messages are used by routers to inform hosts that a more -direct route exists for a particular destination. These messages contain information -from the system's route table possibly revealing portions of the network topology. - -The ability to send ICMP redirects is only appropriate for systems acting as routers. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Comment out any occurrences of net.ipv4.conf.all.send_redirects from /etc/sysctl.d/*.conf files - -for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do - - matching_list=$(grep -P '^(?!#).*[\s]*net.ipv4.conf.all.send_redirects.*$' $f | uniq ) - if ! test -z "$matching_list"; then - while IFS= read -r entry; do - escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") - # comment out "net.ipv4.conf.all.send_redirects" matches to preserve user data - sed -i "s/^${escaped_entry}$/# &/g" $f - done <<< "$matching_list" - fi -done - -# -# Set sysctl config file which to save the desired value -# - -SYSCONFIG_FILE="/etc/sysctl.conf" - - -# -# Set runtime for net.ipv4.conf.all.send_redirects -# -/sbin/sysctl -q -n -w net.ipv4.conf.all.send_redirects="0" - -# -# If net.ipv4.conf.all.send_redirects present in /etc/sysctl.conf, change value to "0" -# else, add "net.ipv4.conf.all.send_redirects = 0" to /etc/sysctl.conf -# - -# Strip any search characters in the key arg so that the key can be replaced without -# adding any search characters to the config file. -stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv4.conf.all.send_redirects") - -# shellcheck disable=SC2059 -printf -v formatted_output "%s = %s" "$stripped_key" "0" - -# If the key exists, change it. Otherwise, add it to the config_file. -# We search for the key string followed by a word boundary (matched by \>), -# so if we search for 'setting', 'setting2' won't match. -if LC_ALL=C grep -q -m 1 -i -e "^net.ipv4.conf.all.send_redirects\\>" "${SYSCONFIG_FILE}"; then - escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") - LC_ALL=C sed -i --follow-symlinks "s/^net.ipv4.conf.all.send_redirects\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" -else - if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then - LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" - fi - printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: List /etc/sysctl.d/*.conf files - find: - paths: - - /etc/sysctl.d/ - - /run/sysctl.d/ - - /usr/local/lib/sysctl.d/ - contains: ^[\s]*net.ipv4.conf.all.send_redirects.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - CJIS-5.10.1.1 - - NIST-800-171-3.1.20 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-SC-5 - - NIST-800-53-SC-7(a) - - PCI-DSSv4-1.4.2 - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv4_conf_all_send_redirects - -- name: Comment out any occurrences of net.ipv4.conf.all.send_redirects from config - files - replace: - path: '{{ item.path }}' - regexp: ^[\s]*net.ipv4.conf.all.send_redirects - replace: '#net.ipv4.conf.all.send_redirects' - loop: '{{ find_sysctl_d.files }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - CJIS-5.10.1.1 - - NIST-800-171-3.1.20 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-SC-5 - - NIST-800-53-SC-7(a) - - PCI-DSSv4-1.4.2 - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv4_conf_all_send_redirects - -- name: Ensure sysctl net.ipv4.conf.all.send_redirects is set to 0 - sysctl: - name: net.ipv4.conf.all.send_redirects - value: '0' - sysctl_file: /etc/sysctl.conf - state: present - reload: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - CJIS-5.10.1.1 - - NIST-800-171-3.1.20 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-SC-5 - - NIST-800-53-SC-7(a) - - PCI-DSSv4-1.4.2 - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv4_conf_all_send_redirects - - - - - - - - - - Disable Kernel Parameter for Sending ICMP Redirects on all IPv4 Interfaces by Default - To set the runtime status of the net.ipv4.conf.default.send_redirects kernel parameter, run the following command: $ sudo sysctl -w net.ipv4.conf.default.send_redirects=0 -To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv4.conf.default.send_redirects = 0 - BP28(R22) - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 18 - 2 - 3 - 4 - 6 - 7 - 8 - 9 - 5.10.1.1 - APO01.06 - APO13.01 - BAI04.04 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS01.03 - DSS01.05 - DSS03.01 - DSS03.05 - DSS05.02 - DSS05.04 - DSS05.05 - DSS05.07 - DSS06.02 - DSS06.06 - 3.1.20 - CCI-000366 - 4.2.3.4 - 4.3.3.4 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - 4.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 6.2 - SR 7.1 - SR 7.2 - SR 7.6 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.12.1.1 - A.12.1.2 - A.12.1.3 - A.12.5.1 - A.12.6.2 - A.13.1.1 - A.13.1.2 - A.13.1.3 - A.13.2.1 - A.13.2.2 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.17.2.1 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CIP-007-3 R4 - CIP-007-3 R4.1 - CIP-007-3 R4.2 - CIP-007-3 R5.1 - CM-7(a) - CM-7(b) - SC-5 - CM-6(a) - SC-7(a) - DE.AE-1 - DE.CM-1 - ID.AM-3 - PR.AC-5 - PR.DS-4 - PR.DS-5 - PR.IP-1 - PR.PT-3 - PR.PT-4 - SRG-OS-000480-GPOS-00227 - ICMP redirect messages are used by routers to inform hosts that a more -direct route exists for a particular destination. These messages contain information -from the system's route table possibly revealing portions of the network topology. - -The ability to send ICMP redirects is only appropriate for systems acting as routers. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Comment out any occurrences of net.ipv4.conf.default.send_redirects from /etc/sysctl.d/*.conf files - -for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do - - matching_list=$(grep -P '^(?!#).*[\s]*net.ipv4.conf.default.send_redirects.*$' $f | uniq ) - if ! test -z "$matching_list"; then - while IFS= read -r entry; do - escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") - # comment out "net.ipv4.conf.default.send_redirects" matches to preserve user data - sed -i "s/^${escaped_entry}$/# &/g" $f - done <<< "$matching_list" - fi -done - -# -# Set sysctl config file which to save the desired value -# - -SYSCONFIG_FILE="/etc/sysctl.conf" - - -# -# Set runtime for net.ipv4.conf.default.send_redirects -# -/sbin/sysctl -q -n -w net.ipv4.conf.default.send_redirects="0" - -# -# If net.ipv4.conf.default.send_redirects present in /etc/sysctl.conf, change value to "0" -# else, add "net.ipv4.conf.default.send_redirects = 0" to /etc/sysctl.conf -# - -# Strip any search characters in the key arg so that the key can be replaced without -# adding any search characters to the config file. -stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv4.conf.default.send_redirects") - -# shellcheck disable=SC2059 -printf -v formatted_output "%s = %s" "$stripped_key" "0" - -# If the key exists, change it. Otherwise, add it to the config_file. -# We search for the key string followed by a word boundary (matched by \>), -# so if we search for 'setting', 'setting2' won't match. -if LC_ALL=C grep -q -m 1 -i -e "^net.ipv4.conf.default.send_redirects\\>" "${SYSCONFIG_FILE}"; then - escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") - LC_ALL=C sed -i --follow-symlinks "s/^net.ipv4.conf.default.send_redirects\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" -else - if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then - LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" - fi - printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: List /etc/sysctl.d/*.conf files - find: - paths: - - /etc/sysctl.d/ - - /run/sysctl.d/ - - /usr/local/lib/sysctl.d/ - contains: ^[\s]*net.ipv4.conf.default.send_redirects.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - CJIS-5.10.1.1 - - NIST-800-171-3.1.20 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-SC-5 - - NIST-800-53-SC-7(a) - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv4_conf_default_send_redirects - -- name: Comment out any occurrences of net.ipv4.conf.default.send_redirects from config - files - replace: - path: '{{ item.path }}' - regexp: ^[\s]*net.ipv4.conf.default.send_redirects - replace: '#net.ipv4.conf.default.send_redirects' - loop: '{{ find_sysctl_d.files }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - CJIS-5.10.1.1 - - NIST-800-171-3.1.20 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-SC-5 - - NIST-800-53-SC-7(a) - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv4_conf_default_send_redirects - -- name: Ensure sysctl net.ipv4.conf.default.send_redirects is set to 0 - sysctl: - name: net.ipv4.conf.default.send_redirects - value: '0' - sysctl_file: /etc/sysctl.conf - state: present - reload: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - CJIS-5.10.1.1 - - NIST-800-171-3.1.20 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-SC-5 - - NIST-800-53-SC-7(a) - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv4_conf_default_send_redirects - - - - - - - - - - Disable Kernel Parameter for IP Forwarding on IPv4 Interfaces - To set the runtime status of the net.ipv4.ip_forward kernel parameter, run the following command: $ sudo sysctl -w net.ipv4.ip_forward=0 -To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv4.ip_forward = 0 - Certain technologies such as virtual machines, containers, etc. rely on IPv4 forwarding to enable and use networking. -Disabling IPv4 forwarding would cause those technologies to stop working. Therefore, this rule should not be used in -profiles or benchmarks that target usage of IPv4 forwarding. - BP28(R22) - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 2 - 3 - 7 - 8 - 9 - APO13.01 - BAI04.04 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS01.03 - DSS03.05 - DSS05.02 - DSS05.05 - DSS05.07 - DSS06.06 - 3.1.20 - CCI-000366 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 6.2 - SR 7.1 - SR 7.2 - SR 7.6 - A.12.1.2 - A.12.1.3 - A.12.5.1 - A.12.6.2 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.17.2.1 - A.9.1.2 - CIP-007-3 R4 - CIP-007-3 R4.1 - CIP-007-3 R4.2 - CIP-007-3 R5.1 - CM-7(a) - CM-7(b) - SC-5 - CM-6(a) - SC-7(a) - DE.CM-1 - PR.DS-4 - PR.IP-1 - PR.PT-3 - PR.PT-4 - Req-1.3.1 - Req-1.3.2 - 1.4.2 - SRG-OS-000480-GPOS-00227 - Routing protocol daemons are typically used on routers to exchange -network topology information with other routers. If this capability is used when -not required, system network information may be unnecessarily transmitted across -the network. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Comment out any occurrences of net.ipv4.ip_forward from /etc/sysctl.d/*.conf files - -for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do - - matching_list=$(grep -P '^(?!#).*[\s]*net.ipv4.ip_forward.*$' $f | uniq ) - if ! test -z "$matching_list"; then - while IFS= read -r entry; do - escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") - # comment out "net.ipv4.ip_forward" matches to preserve user data - sed -i "s/^${escaped_entry}$/# &/g" $f - done <<< "$matching_list" - fi -done - -# -# Set sysctl config file which to save the desired value -# - -SYSCONFIG_FILE="/etc/sysctl.conf" - - -# -# Set runtime for net.ipv4.ip_forward -# -/sbin/sysctl -q -n -w net.ipv4.ip_forward="0" - -# -# If net.ipv4.ip_forward present in /etc/sysctl.conf, change value to "0" -# else, add "net.ipv4.ip_forward = 0" to /etc/sysctl.conf -# - -# Strip any search characters in the key arg so that the key can be replaced without -# adding any search characters to the config file. -stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv4.ip_forward") - -# shellcheck disable=SC2059 -printf -v formatted_output "%s = %s" "$stripped_key" "0" - -# If the key exists, change it. Otherwise, add it to the config_file. -# We search for the key string followed by a word boundary (matched by \>), -# so if we search for 'setting', 'setting2' won't match. -if LC_ALL=C grep -q -m 1 -i -e "^net.ipv4.ip_forward\\>" "${SYSCONFIG_FILE}"; then - escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") - LC_ALL=C sed -i --follow-symlinks "s/^net.ipv4.ip_forward\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" -else - if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then - LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" - fi - printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: List /etc/sysctl.d/*.conf files - find: - paths: - - /etc/sysctl.d/ - - /run/sysctl.d/ - - /usr/local/lib/sysctl.d/ - contains: ^[\s]*net.ipv4.ip_forward.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.20 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-SC-5 - - NIST-800-53-SC-7(a) - - PCI-DSS-Req-1.3.1 - - PCI-DSS-Req-1.3.2 - - PCI-DSSv4-1.4.2 - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv4_ip_forward - -- name: Comment out any occurrences of net.ipv4.ip_forward from config files - replace: - path: '{{ item.path }}' - regexp: ^[\s]*net.ipv4.ip_forward - replace: '#net.ipv4.ip_forward' - loop: '{{ find_sysctl_d.files }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.20 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-SC-5 - - NIST-800-53-SC-7(a) - - PCI-DSS-Req-1.3.1 - - PCI-DSS-Req-1.3.2 - - PCI-DSSv4-1.4.2 - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv4_ip_forward - -- name: Ensure sysctl net.ipv4.ip_forward is set to 0 - sysctl: - name: net.ipv4.ip_forward - value: '0' - sysctl_file: /etc/sysctl.conf - state: present - reload: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.20 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-SC-5 - - NIST-800-53-SC-7(a) - - PCI-DSS-Req-1.3.1 - - PCI-DSS-Req-1.3.2 - - PCI-DSSv4-1.4.2 - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_ipv4_ip_forward - - - - - - - - - - - - nftables - If firewalld or iptables are being used in your environment, please follow the guidance in their -respective section and pass-over the guidance in this section. -nftables is a subsystem of the Linux kernel providing filtering and classification of network -packets/datagrams/frames and is the successor to iptables. The biggest change with the -successor nftables is its simplicity. With iptables, we have to configure every single rule and -use the syntax which can be compared with normal commands. With nftables, the simpler -syntax, much like BPF (Berkely Packet Filter) means shorter lines and less repetition. -Support for nftables should also be compiled into the kernel, together with the related -nftables modules. - -It is available in Linux kernels >= 3.13. Please ensure that your kernel -supports nftables before choosing this option. - - Nftables Base Chain Hooks - The possible hooks which can be used to configure the base chain are: -ingress (only in netdev family since Linux kernel 4.2, and inet family since Linux kernel 5.10): -sees packets immediately after they are passed up from the NIC driver, before even prerouting. -prerouting sees all incoming packets, before any routing decision has been made. -Packets may be addressed to the local or remote systems. -input sees incoming packets that are addressed to and have now been routed -to the local system and processes running there. -forward sees incoming packets that are not addressed to the local system. -output sees packets that originated from processes in the local machine. -postrouting sees all packets after routing, just before they leave the -local system. - input,forward,output - ingress - prerouting - input - forward - output - postrouting - input,forward,output - - - Nftables Chain Names - The rules in nftables are attached to chains. Unlike in iptables, -there are no predefined chains like INPUT, OUTPUT, etc. Instead, -to filter packets at a particular processing step, a base chain with a -chosen name should be created, and attached it to the appropriate -Netfilter hook. - - input,forward,output - input - output - forward - input,forward,output - - - Nftables Base Chain Policies - This is the default verdict that will be applied to packets reaching the end of the chain -(i.e, no more rules to be evaluated against). -Currently there are 2 policies: -accept this verdict means that the packet will keep traversing the network stack. -drop this verdict means that the packet is discarded if the packet reaches the end -of the base chain. - accept,accept,accept - accept - drop - accept,accept,accept - - - Nftables Base Chain Priorities - Each nftables base chain is assigned a priority that defines its ordering -among other base chains, flowtables, and Netfilter internal operations at -the same hook. For example, a chain on the prerouting hook with priority --300 will be placed before connection tracking operations. -Netfilter Internal Priority for inet, ip, ip6: -NF_IP_PRI_RAW_BEFORE_DEFRAG Typical hooks: prerouting; nft Keyword: n/a; Description: n/a -NF_IP_PRI_CONNTRACK_DEFRAG Typical hooks: prerouting; nft Keyword: n/a; Description: Packet defragmentation / datagram reassembly -NF_IP_PRI_RAW Typical hooks: all; nft Keyword: raw; Description: Typical hooks: prerouting; nft Keyword: n/a; Description: Traditional priority of -the raw table placed before connection tracking operation -NF_IP_PRI_SELINUX_FIRST Typical hooks: n/a; nft Keyword: n/a; Description: SELinux operations -NF_IP_PRI_CONNTRACK Typical hooks: prerouting, output;nft Keyword: n/a; Description: Connection tracking processes run early in prerouting and -output hooks to associate packets with tracked connections. -NF_IP_PRI_MANGLE Typical hooks: all;nft Keyword: mangle; Description: Mangle operation -NF_IP_PRI_NAT_DST Typical hooks: prerouting;nft Keyword: dstnat; Description: Destination NAT -NF_IP_PRI_FILTER Typical hooks: all;nft Keyword: filter; Description: Filtering operation, the filter table -NF_IP_PRI_SECURITY Typical hooks: all;nft Keyword: security; Description: Place of security table, where secmark can be set for example -NF_IP_PRI_NAT_SRC Typical hooks: postrouting;nft Keyword: srcnat; Description: Source NAT -NF_IP_PRI_SELINUX_LAST Typical hooks: postrouting;nft Keyword: n/a; Description: SELinux at packet exit -NF_IP_PRI_CONNTRACK_HELPER Typical hooks: postrouting;nft Keyword: n/a; Description: Connection tracking helpers, which identify expected and -related packets. -NF_IP_PRI_CONNTRACK_CONFIRM Typical hooks: input,postrouting;nft Keyword: n/a; Description: Connection tracking adds new tracked connections -at final step in input and postrouting hooks. -Netfilter Internal Priority for bridge: -NF_BR_PRI_NAT_DST_BRIDGED Typical hooks: prerouting; nft Keyword: n/a; Description: n/a -NF_BR_PRI_FILTER_BRIDGED Typical hooks: all;nft Keyword: filter; Description: n/a -NF_BR_PRI_BRNF Typical hooks: n/a;nft Keyword: n/a; Description: n/a -NF_BR_PRI_NAT_DST_OTHER Typical hooks: output;nft Keyword: out; Description: n/a -NF_BR_PRI_FILTER_OTHER Typical hooks: n/a;nft Keyword: n/a; Description: n/a -NF_BR_PRI_NAT_SRC Typical hooks: postrouting;nft Keyword: srcnat; Description: n/a - 0,0,0 - -450 - -400 - -300 - -225 - -200 - -150 - -100 - 0 - 50 - 100 - 225 - 300 - 2147483647 - -300 - -200 - 0 - 100 - 200 - 300 - 0,0,0 - - - Nftables Base Chain Types - Base chains are those that are registered into the Netfilter hooks, -i.e. these chains see packets flowing through the Linux TCP/IP stack. -The possible chain types are: -filter, which is used to filter packets. This is supported by -the arp, bridge, ip, ip6 and inet table families. -route, which is used to reroute packets if any relevant IP -header field or the packet mark is modified. This chain type provides -equivalent semantics to the mangle table but only for the output hook -(for other hooks use type filter instead). This is supported by the -ip, ip6 and inet table families. -nat, which is used to perform Networking Address Translation (NAT). -Only the first packet of a given flow hits this chain; subsequent packets bypass it. -This chain should be never used for filtering. The nat chain type -is supported by the ip, ip6 and inet table families. - - filter,filter,filter - filter - route - nat - filter,filter,filter - - - Nftables Families - Netfilter enables filtering at multiple networking levels. With iptables there -is a separate tool for each level: iptables, ip6tables, arptables, ebtables. -With nftables the multiple networking levels are abstracted into families, -all of which are served by the single tool nft. -ipTables of this family see IPv4 traffic/packets. -ip6Tables of this family see IPv6 traffic/packets. -inetTables of this family see both IPv4 and IPv6 traffic/packets, -simplifying dual stack support. -arpTables of this family see ARP-level (i.e, L2) traffic, before -any L3 handling is done by the kernel. -bridgeTables of this family see traffic/packets traversing bridges -(i.e. switching). No assumptions are made about L3 protocols. -netdevThe netdev family is different from the others in that it -is used to create base chains attached to a single network interface. Such -base chains see all network traffic on the specified interface, with no -assumptions about L2 or L3 protocols. Therefore you can filter ARP traffic from here. - inet - ip - ip6 - inet - arp - bridge - netdev - - - Nftables Master configuration file - The file which contains top level configuration for nftables service, and with which, -the service is started. - /etc/sysconfig/nftables.conf - /etc/sysconfig/nftables.conf - /etc/nftables.conf - - - Nftables Tables - Tables in nftables hold chains. Each table only has one address family and only applies -to packets of this family. Tables can have one of six families. - - filter - filter - firewalld - - - - SuSEfirewall2 - The SuSEfirewall2 provides a managed firewall. - - - Uncomplicated Firewall (ufw) - The Linux kernel in Ubuntu provides a packet filtering system called -netfilter, and the traditional interface for manipulating netfilter are -the iptables suite of commands. iptables provide a complete firewall -solution that is both highly configurable and highly flexible. - -Becoming proficient in iptables takes time, and getting started with -netfilter firewalling using only iptables can be a daunting task. As a -result, many frontends for iptables have been created over the years, -each trying to achieve a different result and targeting a different -audience. - -The Uncomplicated Firewall (ufw) is a frontend for iptables and is -particularly well-suited for host-based firewalls. ufw provides a -framework for managing netfilter, as well as a command-line interface -for manipulating the firewall. ufw aims to provide an easy to use -interface for people unfamiliar with firewall concepts, while at the -same time simplifies complicated iptables commands to help an -administrator who knows what he or she is doing. ufw is an upstream -for other distributions and graphical frontends. - - - Verify ufw Enabled - -The ufw service can be enabled with the following command: -$ sudo systemctl enable ufw.service - CCI-002314 - SRG-OS-000297-GPOS-00115 - The ufw service must be enabled and running in order for ufw to protect the system - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && { ( [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q ufw ); }; then - -SYSTEMCTL_EXEC='/usr/bin/systemctl' -"$SYSTEMCTL_EXEC" unmask 'ufw.service' -"$SYSTEMCTL_EXEC" start 'ufw.service' -"$SYSTEMCTL_EXEC" enable 'ufw.service' - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Gather the package facts - package_facts: - manager: auto - tags: - - enable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_ufw_enabled - -- name: Enable service ufw - block: - - - name: Gather the package facts - package_facts: - manager: auto - - - name: Enable service ufw - systemd: - name: ufw - enabled: 'yes' - state: started - masked: 'no' - when: - - '"ufw" in ansible_facts.packages' - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - and "ufw" in ansible_facts.packages ) - tags: - - enable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_ufw_enabled - - include enable_ufw - -class enable_ufw { - service {'ufw': - enable => true, - ensure => 'running', - } -} - - -[customizations.services] -enabled = ["ufw"] - - - - - - - - - - - Uncommon Network Protocols - The system includes support for several network protocols which are not commonly used. -Although security vulnerabilities in kernel networking code are not frequently discovered, -the consequences can be dramatic. Ensuring uncommon network protocols are disabled -reduces the system's risk to attacks targeted at its implementation of those protocols. - Although these protocols are not commonly used, avoid disruption -in your network environment by ensuring they are not needed -prior to disabling them. - - - Disable ATM Support - The Asynchronous Transfer Mode (ATM) is a protocol operating on -network, data link, and physical layers, based on virtual circuits -and virtual paths. - -To configure the system to prevent the atm -kernel module from being loaded, add the following line to the file /etc/modprobe.d/atm.conf: -install atm /bin/true - -To configure the system to prevent the atm from being used, -add the following line to file /etc/modprobe.d/atm.conf: -blacklist atm - CCI-000381 - CCI-000366 - AC-18 - FMT_SMF_EXT.1 - SRG-OS-000095-GPOS-00049 - SRG-OS-000480-GPOS-00227 - Disabling ATM protects the system against exploitation of any -flaws in its implementation. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -if LC_ALL=C grep -q -m 1 "^install atm" /etc/modprobe.d/atm.conf ; then - - sed -i 's#^install atm.*#install atm /bin/true#g' /etc/modprobe.d/atm.conf -else - echo -e "\n# Disable per security requirements" >> /etc/modprobe.d/atm.conf - echo "install atm /bin/true" >> /etc/modprobe.d/atm.conf -fi - -if ! LC_ALL=C grep -q -m 1 "^blacklist atm$" /etc/modprobe.d/atm.conf ; then - echo "blacklist atm" >> /etc/modprobe.d/atm.conf -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Ensure kernel module 'atm' is disabled - lineinfile: - create: true - dest: /etc/modprobe.d/atm.conf - regexp: install\s+atm - line: install atm /bin/true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-18 - - disable_strategy - - kernel_module_atm_disabled - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - -- name: Ensure kernel module 'atm' is blacklisted - lineinfile: - create: true - dest: /etc/modprobe.d/atm.conf - regexp: ^blacklist atm$ - line: blacklist atm - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-18 - - disable_strategy - - kernel_module_atm_disabled - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - - - - - - - - - Disable CAN Support - The Controller Area Network (CAN) is a serial communications -protocol which was initially developed for automotive and -is now also used in marine, industrial, and medical applications. - -To configure the system to prevent the can -kernel module from being loaded, add the following line to the file /etc/modprobe.d/can.conf: -install can /bin/true - -To configure the system to prevent the can from being used, -add the following line to file /etc/modprobe.d/can.conf: -blacklist can - CCI-000381 - CCI-000366 - AC-18 - FMT_SMF_EXT.1 - SRG-OS-000095-GPOS-00049 - SRG-OS-000480-GPOS-00227 - Disabling CAN protects the system against exploitation of any -flaws in its implementation. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -if LC_ALL=C grep -q -m 1 "^install can" /etc/modprobe.d/can.conf ; then - - sed -i 's#^install can.*#install can /bin/true#g' /etc/modprobe.d/can.conf -else - echo -e "\n# Disable per security requirements" >> /etc/modprobe.d/can.conf - echo "install can /bin/true" >> /etc/modprobe.d/can.conf -fi - -if ! LC_ALL=C grep -q -m 1 "^blacklist can$" /etc/modprobe.d/can.conf ; then - echo "blacklist can" >> /etc/modprobe.d/can.conf -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Ensure kernel module 'can' is disabled - lineinfile: - create: true - dest: /etc/modprobe.d/can.conf - regexp: install\s+can - line: install can /bin/true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-18 - - disable_strategy - - kernel_module_can_disabled - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - -- name: Ensure kernel module 'can' is blacklisted - lineinfile: - create: true - dest: /etc/modprobe.d/can.conf - regexp: ^blacklist can$ - line: blacklist can - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-18 - - disable_strategy - - kernel_module_can_disabled - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - - - - - - - - - Disable IEEE 1394 (FireWire) Support - The IEEE 1394 (FireWire) is a serial bus standard for -high-speed real-time communication. - -To configure the system to prevent the firewire-core -kernel module from being loaded, add the following line to the file /etc/modprobe.d/firewire-core.conf: -install firewire-core /bin/true - -To configure the system to prevent the firewire-core from being used, -add the following line to file /etc/modprobe.d/firewire-core.conf: -blacklist firewire-core - CCI-000381 - AC-18 - FMT_SMF_EXT.1 - SRG-OS-000095-GPOS-00049 - Disabling FireWire protects the system against exploitation of any -flaws in its implementation. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -if LC_ALL=C grep -q -m 1 "^install firewire-core" /etc/modprobe.d/firewire-core.conf ; then - - sed -i 's#^install firewire-core.*#install firewire-core /bin/true#g' /etc/modprobe.d/firewire-core.conf -else - echo -e "\n# Disable per security requirements" >> /etc/modprobe.d/firewire-core.conf - echo "install firewire-core /bin/true" >> /etc/modprobe.d/firewire-core.conf -fi - -if ! LC_ALL=C grep -q -m 1 "^blacklist firewire-core$" /etc/modprobe.d/firewire-core.conf ; then - echo "blacklist firewire-core" >> /etc/modprobe.d/firewire-core.conf -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Ensure kernel module 'firewire-core' is disabled - lineinfile: - create: true - dest: /etc/modprobe.d/firewire-core.conf - regexp: install\s+firewire-core - line: install firewire-core /bin/true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-18 - - disable_strategy - - kernel_module_firewire-core_disabled - - low_complexity - - low_severity - - medium_disruption - - reboot_required - -- name: Ensure kernel module 'firewire-core' is blacklisted - lineinfile: - create: true - dest: /etc/modprobe.d/firewire-core.conf - regexp: ^blacklist firewire-core$ - line: blacklist firewire-core - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-18 - - disable_strategy - - kernel_module_firewire-core_disabled - - low_complexity - - low_severity - - medium_disruption - - reboot_required - - - - - - - - - - Disable RDS Support - The Reliable Datagram Sockets (RDS) protocol is a transport -layer protocol designed to provide reliable high-bandwidth, -low-latency communications between nodes in a cluster. - -To configure the system to prevent the rds -kernel module from being loaded, add the following line to the file /etc/modprobe.d/rds.conf: -install rds /bin/true - -To configure the system to prevent the rds from being used, -add the following line to file /etc/modprobe.d/rds.conf: -blacklist rds - 11 - 14 - 3 - 9 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS05.02 - DSS05.05 - DSS06.06 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 7.6 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.9.1.2 - CM-7(a) - CM-7(b) - CM-6(a) - PR.IP-1 - PR.PT-3 - Disabling RDS protects -the system against exploitation of any flaws in its implementation. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -if LC_ALL=C grep -q -m 1 "^install rds" /etc/modprobe.d/rds.conf ; then - - sed -i 's#^install rds.*#install rds /bin/true#g' /etc/modprobe.d/rds.conf -else - echo -e "\n# Disable per security requirements" >> /etc/modprobe.d/rds.conf - echo "install rds /bin/true" >> /etc/modprobe.d/rds.conf -fi - -if ! LC_ALL=C grep -q -m 1 "^blacklist rds$" /etc/modprobe.d/rds.conf ; then - echo "blacklist rds" >> /etc/modprobe.d/rds.conf -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Ensure kernel module 'rds' is disabled - lineinfile: - create: true - dest: /etc/modprobe.d/rds.conf - regexp: install\s+rds - line: install rds /bin/true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - kernel_module_rds_disabled - - low_complexity - - low_severity - - medium_disruption - - reboot_required - -- name: Ensure kernel module 'rds' is blacklisted - lineinfile: - create: true - dest: /etc/modprobe.d/rds.conf - regexp: ^blacklist rds$ - line: blacklist rds - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - kernel_module_rds_disabled - - low_complexity - - low_severity - - medium_disruption - - reboot_required - - - - - - - - - - Disable SCTP Support - The Stream Control Transmission Protocol (SCTP) is a -transport layer protocol, designed to support the idea of -message-oriented communication, with several streams of messages -within one connection. - -To configure the system to prevent the sctp -kernel module from being loaded, add the following line to the file /etc/modprobe.d/sctp.conf: -install sctp /bin/true - -To configure the system to prevent the sctp from being used, -add the following line to file /etc/modprobe.d/sctp.conf: -blacklist sctp - 11 - 14 - 3 - 9 - 5.10.1 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS05.02 - DSS05.05 - DSS06.06 - 3.4.6 - CCI-000381 - CCI-000366 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 7.6 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.9.1.2 - CM-7(a) - CM-7(b) - CM-6(a) - PR.IP-1 - PR.PT-3 - Req-1.4.2 - 1.4.2 - SRG-OS-000095-GPOS-00049 - SRG-OS-000480-GPOS-00227 - Disabling SCTP protects -the system against exploitation of any flaws in its implementation. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -if LC_ALL=C grep -q -m 1 "^install sctp" /etc/modprobe.d/sctp.conf ; then - - sed -i 's#^install sctp.*#install sctp /bin/true#g' /etc/modprobe.d/sctp.conf -else - echo -e "\n# Disable per security requirements" >> /etc/modprobe.d/sctp.conf - echo "install sctp /bin/true" >> /etc/modprobe.d/sctp.conf -fi - -if ! LC_ALL=C grep -q -m 1 "^blacklist sctp$" /etc/modprobe.d/sctp.conf ; then - echo "blacklist sctp" >> /etc/modprobe.d/sctp.conf -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Ensure kernel module 'sctp' is disabled - lineinfile: - create: true - dest: /etc/modprobe.d/sctp.conf - regexp: install\s+sctp - line: install sctp /bin/true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - CJIS-5.10.1 - - NIST-800-171-3.4.6 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - PCI-DSS-Req-1.4.2 - - PCI-DSSv4-1.4.2 - - disable_strategy - - kernel_module_sctp_disabled - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - -- name: Ensure kernel module 'sctp' is blacklisted - lineinfile: - create: true - dest: /etc/modprobe.d/sctp.conf - regexp: ^blacklist sctp$ - line: blacklist sctp - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - CJIS-5.10.1 - - NIST-800-171-3.4.6 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - PCI-DSS-Req-1.4.2 - - PCI-DSSv4-1.4.2 - - disable_strategy - - kernel_module_sctp_disabled - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - - - - - - - - - Disable TIPC Support - The Transparent Inter-Process Communication (TIPC) protocol -is designed to provide communications between nodes in a -cluster. - -To configure the system to prevent the tipc -kernel module from being loaded, add the following line to the file /etc/modprobe.d/tipc.conf: -install tipc /bin/true - -To configure the system to prevent the tipc from being used, -add the following line to file /etc/modprobe.d/tipc.conf: -blacklist tipc - This configuration baseline was created to deploy the base operating system for general purpose -workloads. When the operating system is configured for certain purposes, such as -a node in High Performance Computing cluster, it is expected that -the tipc kernel module will be loaded. - 11 - 14 - 3 - 9 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS05.02 - DSS05.05 - DSS06.06 - CCI-000381 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 7.6 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.9.1.2 - CM-7(a) - CM-7(b) - CM-6(a) - PR.IP-1 - PR.PT-3 - FMT_SMF_EXT.1 - SRG-OS-000095-GPOS-00049 - Disabling TIPC protects -the system against exploitation of any flaws in its implementation. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -if LC_ALL=C grep -q -m 1 "^install tipc" /etc/modprobe.d/tipc.conf ; then - - sed -i 's#^install tipc.*#install tipc /bin/true#g' /etc/modprobe.d/tipc.conf -else - echo -e "\n# Disable per security requirements" >> /etc/modprobe.d/tipc.conf - echo "install tipc /bin/true" >> /etc/modprobe.d/tipc.conf -fi - -if ! LC_ALL=C grep -q -m 1 "^blacklist tipc$" /etc/modprobe.d/tipc.conf ; then - echo "blacklist tipc" >> /etc/modprobe.d/tipc.conf -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Ensure kernel module 'tipc' is disabled - lineinfile: - create: true - dest: /etc/modprobe.d/tipc.conf - regexp: install\s+tipc - line: install tipc /bin/true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - kernel_module_tipc_disabled - - low_complexity - - low_severity - - medium_disruption - - reboot_required - -- name: Ensure kernel module 'tipc' is blacklisted - lineinfile: - create: true - dest: /etc/modprobe.d/tipc.conf - regexp: ^blacklist tipc$ - line: blacklist tipc - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - kernel_module_tipc_disabled - - low_complexity - - low_severity - - medium_disruption - - reboot_required - - - - - - - - - - - Wireless Networking - Wireless networking, such as 802.11 -(WiFi) and Bluetooth, can present a security risk to sensitive or -classified systems and networks. Wireless networking hardware is -much more likely to be included in laptop or portable systems than -in desktops or servers. - -Removal of hardware provides the greatest assurance that the wireless -capability remains disabled. Acquisition policies often include provisions to -prevent the purchase of equipment that will be used in sensitive spaces and -includes wireless capabilities. If it is impractical to remove the wireless -hardware, and policy permits the device to enter sensitive spaces as long -as wireless is disabled, efforts should instead focus on disabling wireless capability -via software. - - Disable Wireless Through Software Configuration - If it is impossible to remove the wireless hardware -from the device in question, disable as much of it as possible -through software. The following methods can disable software -support for wireless networking, but note that these methods do not -prevent malicious software or careless users from re-activating the -devices. - - Disable Bluetooth Kernel Module - The kernel's module loading system can be configured to prevent -loading of the Bluetooth module. Add the following to -the appropriate /etc/modprobe.d configuration file -to prevent the loading of the Bluetooth module: -install bluetooth /bin/true - 11 - 12 - 14 - 15 - 3 - 8 - 9 - 5.13.1.3 - APO13.01 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS01.04 - DSS05.02 - DSS05.03 - DSS05.05 - DSS06.06 - 3.1.16 - CCI-000085 - CCI-001443 - CCI-001444 - CCI-001551 - CCI-002418 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 7.1 - SR 7.6 - A.11.2.6 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.6.2.1 - A.6.2.2 - A.9.1.2 - AC-18(a) - AC-18(3) - CM-7(a) - CM-7(b) - CM-6(a) - MP-7 - PR.AC-3 - PR.IP-1 - PR.PT-3 - PR.PT-4 - SRG-OS-000095-GPOS-00049 - SRG-OS-000300-GPOS-00118 - If Bluetooth functionality must be disabled, preventing the kernel -from loading the kernel module provides an additional safeguard against its -activation. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -if LC_ALL=C grep -q -m 1 "^install bluetooth" /etc/modprobe.d/bluetooth.conf ; then - - sed -i 's#^install bluetooth.*#install bluetooth /bin/true#g' /etc/modprobe.d/bluetooth.conf -else - echo -e "\n# Disable per security requirements" >> /etc/modprobe.d/bluetooth.conf - echo "install bluetooth /bin/true" >> /etc/modprobe.d/bluetooth.conf -fi - -if ! LC_ALL=C grep -q -m 1 "^blacklist bluetooth$" /etc/modprobe.d/bluetooth.conf ; then - echo "blacklist bluetooth" >> /etc/modprobe.d/bluetooth.conf -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Ensure kernel module 'bluetooth' is disabled - lineinfile: - create: true - dest: /etc/modprobe.d/bluetooth.conf - regexp: install\s+bluetooth - line: install bluetooth /bin/true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - CJIS-5.13.1.3 - - NIST-800-171-3.1.16 - - NIST-800-53-AC-18(3) - - NIST-800-53-AC-18(a) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - disable_strategy - - kernel_module_bluetooth_disabled - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - -- name: Ensure kernel module 'bluetooth' is blacklisted - lineinfile: - create: true - dest: /etc/modprobe.d/bluetooth.conf - regexp: ^blacklist bluetooth$ - line: blacklist bluetooth - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - CJIS-5.13.1.3 - - NIST-800-171-3.1.16 - - NIST-800-53-AC-18(3) - - NIST-800-53-AC-18(a) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - disable_strategy - - kernel_module_bluetooth_disabled - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - - - - - - - - - Deactivate Wireless Network Interfaces - Deactivating wireless network interfaces should prevent normal usage of the wireless -capability. - - -Configure the system to disable all wireless network interfaces with the following command: -$ sudo nmcli radio all off - 11 - 12 - 14 - 15 - 3 - 8 - 9 - APO13.01 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS01.04 - DSS05.02 - DSS05.03 - DSS05.05 - DSS06.06 - 3.1.16 - CCI-000085 - CCI-002418 - CCI-002421 - CCI-001443 - CCI-001444 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 7.1 - SR 7.6 - 1315 - 1319 - A.11.2.6 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.6.2.1 - A.6.2.2 - A.9.1.2 - AC-18(a) - AC-18(3) - CM-7(a) - CM-7(b) - CM-6(a) - MP-7 - PR.AC-3 - PR.IP-1 - PR.PT-3 - PR.PT-4 - Req-1.3.3 - 1.4.3 - SRG-OS-000299-GPOS-00117 - SRG-OS-000300-GPOS-00118 - SRG-OS-000424-GPOS-00188 - SRG-OS-000481-GPOS-000481 - The use of wireless networking can introduce many different attack vectors into -the organization's network. Common attack vectors such as malicious association -and ad hoc networks will allow an attacker to spoof a wireless access point -(AP), allowing validated systems to connect to the malicious AP and enabling the -attacker to monitor and record network traffic. These malicious APs can also -serve to create a man-in-the-middle attack or be used to create a denial of -service to valid network resources. - - -if ! rpm -q --quiet "NetworkManager" ; then - yum install -y "NetworkManager" -fi - -nmcli radio all off - - - name: Gather the package facts - package_facts: - manager: auto - tags: - - NIST-800-171-3.1.16 - - NIST-800-53-AC-18(3) - - NIST-800-53-AC-18(a) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - PCI-DSS-Req-1.3.3 - - PCI-DSSv4-1.4.3 - - low_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - - unknown_strategy - - wireless_disable_interfaces - -- name: Ensure NetworkManager is installed - ansible.builtin.package: - name: '{{ item }}' - state: present - with_items: - - NetworkManager - tags: - - NIST-800-171-3.1.16 - - NIST-800-53-AC-18(3) - - NIST-800-53-AC-18(a) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - PCI-DSS-Req-1.3.3 - - PCI-DSSv4-1.4.3 - - low_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - - unknown_strategy - - wireless_disable_interfaces - -- name: Deactivate Wireless Network Interfaces - command: nmcli radio wifi off - when: '''NetworkManager'' in ansible_facts.packages' - tags: - - NIST-800-171-3.1.16 - - NIST-800-53-AC-18(3) - - NIST-800-53-AC-18(a) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - PCI-DSS-Req-1.3.3 - - PCI-DSSv4-1.4.3 - - low_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - - unknown_strategy - - wireless_disable_interfaces - - - - - - - - - - - - Disable Unused Interfaces - Network interfaces expand the attack surface of the -system. Unused interfaces are not monitored or controlled, and -should be disabled. - -If the system does not require network communications but still -needs to use the loopback interface, remove all files of the form -ifcfg-interface except for ifcfg-lo from -/etc/sysconfig/network-scripts: -$ sudo rm /etc/sysconfig/network-scripts/ifcfg-interface -If the system is a standalone machine with no need for network access or even -communication over the loopback device, then disable this service. - -The network service can be disabled with the following command: -$ sudo systemctl mask --now network.service - - - Transport Layer Security Support - Support for Transport Layer Security (TLS), and its predecessor, the Secure -Sockets Layer (SSL), is included in Red Hat Enterprise Linux in the OpenSSL software (RPM package -openssl). TLS provides encrypted and authenticated network -communications, and many network services include support for it. TLS or SSL -can be leveraged to avoid any plaintext transmission of sensitive data. - -For information on how to use OpenSSL, see -http://www.openssl.org/docs/. Information on FIPS validation -of OpenSSL is available at http://www.openssl.org/docs/fips.html -and http://csrc.nist.gov/groups/STM/cmvp/documents/140-1/140val-all.htm. - - - - File Permissions and Masks - Traditional Unix security relies heavily on file and -directory permissions to prevent unauthorized users from reading or -modifying files to which they should not have access. - -Several of the commands in this section search filesystems -for files or directories with certain characteristics, and are -intended to be run on every local partition on a given system. -When the variable PART appears in one of the commands below, -it means that the command is intended to be run repeatedly, with the -name of each local partition substituted for PART in turn. - -The following command prints a list of all xfs partitions on the local -system, which is the default filesystem for Oracle Linux 9 -installations: -$ mount -t xfs | awk '{print $3}' -For any systems that use a different -local filesystem type, modify this command as appropriate. - - Verify Permissions on Important Files and -Directories - Permissions for many files on a system must be set -restrictively to ensure sensitive information is properly protected. -This section discusses important -permission restrictions which can be verified -to ensure that no harmful discrepancies have -arisen. - - Ensure All World-Writable Directories Are Owned by root User - All directories in local partitions which are world-writable should be owned by root. -If any world-writable directories are not owned by root, this should be investigated. -Following this, the files should be deleted or assigned to root user. - BP28(R40) - CCI-000366 - SRG-OS-000480-GPOS-00227 - SRG-OS-000138-GPOS-00069 - Allowing a user account to own a world-writable directory is undesirable because it allows the -owner of that directory to remove or replace any files that may be placed in the directory by -other users. - -# At least under containerized env /proc can have files w/o possilibity to -# modify even as root. And touching /proc is not good idea anyways. -find / -path /proc -prune -o \ - -not -fstype afs -not -fstype ceph -not -fstype cifs -not -fstype smb3 -not -fstype smbfs \ - -not -fstype sshfs -not -fstype ncpfs -not -fstype ncp -not -fstype nfs -not -fstype nfs4 \ - -not -fstype gfs -not -fstype gfs2 -not -fstype glusterfs -not -fstype gpfs \ - -not -fstype pvfs2 -not -fstype ocfs2 -not -fstype lustre -not -fstype davfs \ - -not -fstype fuse.sshfs -type d -perm -0002 -uid +0 -exec chown root {} \; - - - name: Ensure All World-Writable Directories Are Owned by root User - Define Excluded - (Non-Local) File Systems and Paths - ansible.builtin.set_fact: - excluded_fstypes: - - afs - - ceph - - cifs - - smb3 - - smbfs - - sshfs - - ncpfs - - ncp - - nfs - - nfs4 - - gfs - - gfs2 - - glusterfs - - gpfs - - pvfs2 - - ocfs2 - - lustre - - davfs - - fuse.sshfs - excluded_paths: - - dev - - proc - - run - - sys - search_paths: [] - tags: - - dir_perms_world_writable_root_owned - - low_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - -- name: Ensure All World-Writable Directories Are Owned by root User - Find Relevant - Root Directories Ignoring Pre-Defined Excluded Paths - ansible.builtin.find: - paths: / - file_type: directory - excludes: '{{ excluded_paths }}' - hidden: true - recurse: false - register: result_relevant_root_dirs - tags: - - dir_perms_world_writable_root_owned - - low_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - -- name: Ensure All World-Writable Directories Are Owned by root User - Include Relevant - Root Directories in a List of Paths to be Searched - ansible.builtin.set_fact: - search_paths: '{{ search_paths | union([item.path]) }}' - loop: '{{ result_relevant_root_dirs.files }}' - tags: - - dir_perms_world_writable_root_owned - - low_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - -- name: Ensure All World-Writable Directories Are Owned by root User - Increment Search - Paths List with Local Partitions Mount Points - ansible.builtin.set_fact: - search_paths: '{{ search_paths | union([item.mount]) }}' - loop: '{{ ansible_mounts }}' - when: - - item.fstype not in excluded_fstypes - - item.mount != '/' - tags: - - dir_perms_world_writable_root_owned - - low_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - -- name: Ensure All World-Writable Directories Are Owned by root User - Increment Search - Paths List with Local NFS File System Targets - ansible.builtin.set_fact: - search_paths: '{{ search_paths | union([item.device.split('':'')[1]]) }}' - loop: '{{ ansible_mounts }}' - when: item.device is search("localhost:") - tags: - - dir_perms_world_writable_root_owned - - low_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - -- name: Ensure All World-Writable Directories Are Owned by root User - Define Rule - Specific Facts - ansible.builtin.set_fact: - world_writable_dirs: [] - tags: - - dir_perms_world_writable_root_owned - - low_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - -- name: Ensure All World-Writable Directories Are Owned by root User - Find All Uncompliant - Directories in Local File Systems - ansible.builtin.command: - cmd: find {{ item }} -xdev -type d -perm -0002 -uid +0 - loop: '{{ search_paths }}' - changed_when: false - register: result_found_dirs - tags: - - dir_perms_world_writable_root_owned - - low_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - -- name: Ensure All World-Writable Directories Are Owned by root User - Create List - of World Writable Directories Not Owned by root - ansible.builtin.set_fact: - world_writable_dirs: '{{ world_writable_dirs | union(item.stdout_lines) | list - }}' - loop: '{{ result_found_dirs.results }}' - tags: - - dir_perms_world_writable_root_owned - - low_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - -- name: Ensure All World-Writable Directories Are Owned by root User - Ensure root - Ownership on Local World Writable Directories - ansible.builtin.file: - path: '{{ item }}' - owner: root - loop: '{{ world_writable_dirs }}' - tags: - - dir_perms_world_writable_root_owned - - low_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - - - - - - - - - Verify that All World-Writable Directories Have Sticky Bits Set - When the so-called 'sticky bit' is set on a directory, -only the owner of a given file may remove that file from the -directory. Without the sticky bit, any user with write access to a -directory may remove any file in the directory. Setting the sticky -bit prevents users from removing each other's files. In cases where -there is no reason for a directory to be world-writable, a better -solution is to remove that permission rather than to set the sticky -bit. However, if a directory is used by a particular application, -consult that application's documentation instead of blindly -changing modes. - -To set the sticky bit on a world-writable directory DIR, run the -following command: -$ sudo chmod +t DIR - BP28(R40) - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - APO01.06 - DSS05.04 - DSS05.07 - DSS06.02 - CCI-001090 - 4.3.3.7.3 - SR 2.1 - SR 5.2 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 - CM-6(a) - AC-6(1) - PR.AC-4 - PR.DS-5 - SRG-OS-000138-GPOS-00069 - Failing to set the sticky bit on public directories allows unauthorized -users to delete files in the directory structure. - -The only authorized public directories are those temporary directories -supplied with the system, or those designed to be temporary file -repositories. The setting is normally reserved for directories used by the -system, by users for temporary file storage (such as /tmp), and -for directories requiring global read/write access. - df --local -P | awk '{if (NR!=1) print $6}' \ -| xargs -I '$6' find '$6' -xdev -type d \ -\( -perm -0002 -a ! -perm -1000 \) 2>/dev/null \ --exec chmod a+t {} + - - - name: Get all world-writable directories with no sticky bits set - shell: | - set -o pipefail - df --local -P | awk '{if (NR!=1) print $6}' | xargs -I '{}' find '{}' -xdev -type d \( -perm -0002 -a ! -perm -1000 \) 2>/dev/null - register: dir_output - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - dir_perms_world_writable_sticky_bits - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - -- name: Ensure sticky bit is set - file: - path: '{{ item }}' - mode: a+t - with_items: - - '{{ dir_output.stdout_lines }}' - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - dir_perms_world_writable_sticky_bits - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - - - - - - - - - Verify Permissions on /etc/audit/auditd.conf - -To properly set the permissions of /etc/audit/auditd.conf, run the command: -$ sudo chmod 0640 /etc/audit/auditd.conf - CCI-000171 - AU-12(b) - SRG-OS-000063-GPOS-00032 - Without the capability to restrict the roles and individuals that can select which events -are audited, unauthorized personnel may be able to prevent the auditing of critical -events. Misconfigured audits may degrade the system's performance by overwhelming -the audit log. Misconfigured audits may also make it more difficult to establish, -correlate, and investigate the events relating to an incident or identify -those responsible for one. - - - - - -chmod u-xs,g-xws,o-xwrt /etc/audit/auditd.conf - - - name: Test for existence /etc/audit/auditd.conf - stat: - path: /etc/audit/auditd.conf - register: file_exists - tags: - - NIST-800-53-AU-12(b) - - configure_strategy - - file_permissions_etc_audit_auditd - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Ensure permission u-xs,g-xws,o-xwrt on /etc/audit/auditd.conf - file: - path: /etc/audit/auditd.conf - mode: u-xs,g-xws,o-xwrt - when: file_exists.stat is defined and file_exists.stat.exists - tags: - - NIST-800-53-AU-12(b) - - configure_strategy - - file_permissions_etc_audit_auditd - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Verify Permissions on /etc/audit/rules.d/*.rules - -To properly set the permissions of /etc/audit/rules.d/*.rules, run the command: -$ sudo chmod 0640 /etc/audit/rules.d/*.rules - CCI-000171 - AU-12(b) - SRG-OS-000063-GPOS-00032 - Without the capability to restrict the roles and individuals that can select which events -are audited, unauthorized personnel may be able to prevent the auditing of critical -events. Misconfigured audits may degrade the system's performance by overwhelming -the audit log. Misconfigured audits may also make it more difficult to establish, -correlate, and investigate the events relating to an incident or identify -those responsible for one. - - - - - -find -H /etc/audit/rules.d/ -maxdepth 1 -perm /u+xs,g+xws,o+xwrt -type f -regex '^.*rules$' -exec chmod u-xs,g-xws,o-xwrt {} \; - - - name: Find /etc/audit/rules.d/ file(s) - command: find -H /etc/audit/rules.d/ -maxdepth 1 -perm /u+xs,g+xws,o+xwrt -type - f -regex "^.*rules$" - register: files_found - changed_when: false - failed_when: false - check_mode: false - tags: - - NIST-800-53-AU-12(b) - - configure_strategy - - file_permissions_etc_audit_rulesd - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Set permissions for /etc/audit/rules.d/ file(s) - file: - path: '{{ item }}' - mode: u-xs,g-xws,o-xwrt - state: file - with_items: - - '{{ files_found.stdout_lines }}' - tags: - - NIST-800-53-AU-12(b) - - configure_strategy - - file_permissions_etc_audit_rulesd - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Verify that local System.map file (if exists) is readable only by root - Files containing sensitive informations should be protected by restrictive - permissions. Most of the time, there is no need that these files need to be read by any non-root user - -To properly set the permissions of /boot/System.map-*, run the command: -$ sudo chmod 0600 /boot/System.map-* - BP28(R13) - The System.map file contains information about kernel symbols and - can give some hints to generate local exploitation. - - - - - - - - - Ensure All SGID Executables Are Authorized - The SGID (set group id) bit should be set only on files that were -installed via authorized means. A straightforward means of identifying -unauthorized SGID files is determine if any were not installed as part of an -RPM package, which is cryptographically verified. Investigate the origin -of any unpackaged SGID files. -This configuration check considers authorized SGID files which were installed via RPM. -It is assumed that when an individual has sudo access to install an RPM -and all packages are signed with an organizationally-recognized GPG key, -the software should be considered an approved package on the system. -Any SGID file not deployed through an RPM will be flagged for further review. - BP28(R37) - BP28(R38) - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - APO01.06 - DSS05.04 - DSS05.07 - DSS06.02 - 4.3.3.7.3 - SR 2.1 - SR 5.2 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CM-6(a) - AC-6(1) - PR.AC-4 - PR.DS-5 - Executable files with the SGID permission run with the privileges of -the owner of the file. SGID files of uncertain provenance could allow for -unprivileged users to elevate privileges. The presence of these files should be -strictly controlled on the system. - - - - - - - - - Ensure All SUID Executables Are Authorized - The SUID (set user id) bit should be set only on files that were -installed via authorized means. A straightforward means of identifying -unauthorized SUID files is determine if any were not installed as part of an -RPM package, which is cryptographically verified. Investigate the origin -of any unpackaged SUID files. -This configuration check considers authorized SUID files which were installed via RPM. -It is assumed that when an individual has sudo access to install an RPM -and all packages are signed with an organizationally-recognized GPG key, -the software should be considered an approved package on the system. -Any SUID file not deployed through an RPM will be flagged for further review. - BP28(R37) - BP28(R38) - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - APO01.06 - DSS05.04 - DSS05.07 - DSS06.02 - 4.3.3.7.3 - SR 2.1 - SR 5.2 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CM-6(a) - AC-6(1) - PR.AC-4 - PR.DS-5 - Executable files with the SUID permission run with the privileges of -the owner of the file. SUID files of uncertain provenance could allow for -unprivileged users to elevate privileges. The presence of these files should be -strictly controlled on the system. - - - - - - - - - Ensure No World-Writable Files Exist - It is generally a good idea to remove global (other) write -access to a file when it is discovered. However, check with -documentation for specific applications before making changes. -Also, monitor for recurring world-writable files, as these may be -symptoms of a misconfigured application or user account. Finally, -this applies to real files and not virtual files that are a part of -pseudo file systems such as sysfs or procfs. - BP28(R40) - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - APO01.06 - DSS05.04 - DSS05.07 - DSS06.02 - 4.3.3.7.3 - SR 2.1 - SR 5.2 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 - CM-6(a) - AC-6(1) - PR.AC-4 - PR.DS-5 - 2.2.6 - Data in world-writable files can be modified by any -user on the system. In almost all circumstances, files can be -configured using a combination of user and group permissions to -support whatever legitimate access is needed without the risk -caused by world-writable files. - -find / -xdev -type f -perm -002 -exec chmod o-w {} \; - - - - - - - - - - Ensure All Files Are Owned by a Group - If any files are not owned by a group, then the -cause of their lack of group-ownership should be investigated. -Following this, the files should be deleted or assigned to an -appropriate group. The following command will discover and print -any files on local partitions which do not belong to a valid group: -$ df --local -P | awk '{if (NR!=1) print $6}' | sudo xargs -I '{}' find '{}' -xdev -nogroup -To search all filesystems on a system including network mounted -filesystems the following command can be run manually for each partition: -$ sudo find PARTITION -xdev -nogroup - This rule only considers local groups. -If you have your groups defined outside /etc/group, the rule won't consider those. - BP28(R55) - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - APO01.06 - DSS05.02 - DSS05.04 - DSS05.05 - DSS05.07 - DSS05.10 - DSS06.02 - DSS06.03 - DSS06.06 - DSS06.10 - CCI-000366 - CCI-002165 - 4.3.3.2.2 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 5.2 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.18.1.4 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.1 - A.9.2.2 - A.9.2.3 - A.9.2.4 - A.9.2.6 - A.9.3.1 - A.9.4.1 - A.9.4.2 - A.9.4.3 - A.9.4.4 - A.9.4.5 - CM-6(a) - AC-6(1) - PR.AC-1 - PR.AC-4 - PR.AC-6 - PR.AC-7 - PR.DS-5 - PR.PT-3 - 2.2.6 - SRG-OS-000480-GPOS-00227 - Unowned files do not directly imply a security problem, but they are generally -a sign that something is amiss. They may -be caused by an intruder, by incorrect software installation or -draft software removal, or by failure to remove all files belonging -to a deleted account. The files should be repaired so they -will not cause problems when accounts are created in the future, -and the cause should be discovered and addressed. - - - - - - - - - Ensure All Files Are Owned by a User - If any files are not owned by a user, then the -cause of their lack of ownership should be investigated. -Following this, the files should be deleted or assigned to an -appropriate user. The following command will discover and print -any files on local partitions which do not belong to a valid user: -$ df --local -P | awk {'if (NR!=1) print $6'} | sudo xargs -I '{}' find '{}' -xdev -nouser -To search all filesystems on a system including network mounted -filesystems the following command can be run manually for each partition: -$ sudo find PARTITION -xdev -nouser - For this rule to evaluate centralized user accounts, getent must be working properly -so that running the command getent passwd returns a list of all users in your organization. -If using the System Security Services Daemon (SSSD), enumerate = true must be configured -in your organization's domain to return a complete list of users - Enabling this rule will result in slower scan times depending on the size of your organization -and number of centralized users. - BP28(R55) - 11 - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - 9 - APO01.06 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS05.02 - DSS05.04 - DSS05.05 - DSS05.07 - DSS06.02 - DSS06.03 - DSS06.06 - CCI-000366 - CCI-002165 - 4.3.3.2.2 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 5.2 - SR 7.6 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.1 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CM-6(a) - AC-6(1) - PR.AC-4 - PR.AC-6 - PR.DS-5 - PR.IP-1 - PR.PT-3 - 2.2.6 - SRG-OS-000480-GPOS-00227 - Unowned files do not directly imply a security problem, but they are generally -a sign that something is amiss. They may -be caused by an intruder, by incorrect software installation or -draft software removal, or by failure to remove all files belonging -to a deleted account. The files should be repaired so they -will not cause problems when accounts are created in the future, -and the cause should be discovered and addressed. - - - - - - - - - - Enable Kernel Parameter to Enforce DAC on Hardlinks - To set the runtime status of the fs.protected_hardlinks kernel parameter, run the following command: $ sudo sysctl -w fs.protected_hardlinks=1 -To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: fs.protected_hardlinks = 1 - BP28(R23) - CCI-002165 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 - CM-6(a) - AC-6(1) - SRG-OS-000312-GPOS-00122 - SRG-OS-000312-GPOS-00123 - SRG-OS-000324-GPOS-00125 - By enabling this kernel parameter, users can no longer create soft or hard links to -files which they do not own. Disallowing such hardlinks mitigate vulnerabilities -based on insecure file system accessed by privileged programs, avoiding an -exploitation vector exploiting unsafe use of open() or creat(). - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Comment out any occurrences of fs.protected_hardlinks from /etc/sysctl.d/*.conf files - -for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do - - matching_list=$(grep -P '^(?!#).*[\s]*fs.protected_hardlinks.*$' $f | uniq ) - if ! test -z "$matching_list"; then - while IFS= read -r entry; do - escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") - # comment out "fs.protected_hardlinks" matches to preserve user data - sed -i "s/^${escaped_entry}$/# &/g" $f - done <<< "$matching_list" - fi -done - -# -# Set sysctl config file which to save the desired value -# - -SYSCONFIG_FILE="/etc/sysctl.conf" - - -# -# Set runtime for fs.protected_hardlinks -# -/sbin/sysctl -q -n -w fs.protected_hardlinks="1" - -# -# If fs.protected_hardlinks present in /etc/sysctl.conf, change value to "1" -# else, add "fs.protected_hardlinks = 1" to /etc/sysctl.conf -# - -# Strip any search characters in the key arg so that the key can be replaced without -# adding any search characters to the config file. -stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^fs.protected_hardlinks") - -# shellcheck disable=SC2059 -printf -v formatted_output "%s = %s" "$stripped_key" "1" - -# If the key exists, change it. Otherwise, add it to the config_file. -# We search for the key string followed by a word boundary (matched by \>), -# so if we search for 'setting', 'setting2' won't match. -if LC_ALL=C grep -q -m 1 -i -e "^fs.protected_hardlinks\\>" "${SYSCONFIG_FILE}"; then - escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") - LC_ALL=C sed -i --follow-symlinks "s/^fs.protected_hardlinks\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" -else - if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then - LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" - fi - printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: List /etc/sysctl.d/*.conf files - find: - paths: - - /etc/sysctl.d/ - - /run/sysctl.d/ - - /usr/local/lib/sysctl.d/ - contains: ^[\s]*fs.protected_hardlinks.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_fs_protected_hardlinks - -- name: Comment out any occurrences of fs.protected_hardlinks from config files - replace: - path: '{{ item.path }}' - regexp: ^[\s]*fs.protected_hardlinks - replace: '#fs.protected_hardlinks' - loop: '{{ find_sysctl_d.files }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_fs_protected_hardlinks - -- name: Ensure sysctl fs.protected_hardlinks is set to 1 - sysctl: - name: fs.protected_hardlinks - value: '1' - sysctl_file: /etc/sysctl.conf - state: present - reload: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_fs_protected_hardlinks - - - - - - - - - - Enable Kernel Parameter to Enforce DAC on Symlinks - To set the runtime status of the fs.protected_symlinks kernel parameter, run the following command: $ sudo sysctl -w fs.protected_symlinks=1 -To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: fs.protected_symlinks = 1 - BP28(R23) - CCI-002165 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 - CM-6(a) - AC-6(1) - SRG-OS-000312-GPOS-00122 - SRG-OS-000312-GPOS-00123 - SRG-OS-000324-GPOS-00125 - By enabling this kernel parameter, symbolic links are permitted to be followed -only when outside a sticky world-writable directory, or when the UID of the -link and follower match, or when the directory owner matches the symlink's owner. -Disallowing such symlinks helps mitigate vulnerabilities based on insecure file system -accessed by privileged programs, avoiding an exploitation vector exploiting unsafe use of -open() or creat(). - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Comment out any occurrences of fs.protected_symlinks from /etc/sysctl.d/*.conf files - -for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do - - matching_list=$(grep -P '^(?!#).*[\s]*fs.protected_symlinks.*$' $f | uniq ) - if ! test -z "$matching_list"; then - while IFS= read -r entry; do - escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") - # comment out "fs.protected_symlinks" matches to preserve user data - sed -i "s/^${escaped_entry}$/# &/g" $f - done <<< "$matching_list" - fi -done - -# -# Set sysctl config file which to save the desired value -# - -SYSCONFIG_FILE="/etc/sysctl.conf" - - -# -# Set runtime for fs.protected_symlinks -# -/sbin/sysctl -q -n -w fs.protected_symlinks="1" - -# -# If fs.protected_symlinks present in /etc/sysctl.conf, change value to "1" -# else, add "fs.protected_symlinks = 1" to /etc/sysctl.conf -# - -# Strip any search characters in the key arg so that the key can be replaced without -# adding any search characters to the config file. -stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^fs.protected_symlinks") - -# shellcheck disable=SC2059 -printf -v formatted_output "%s = %s" "$stripped_key" "1" - -# If the key exists, change it. Otherwise, add it to the config_file. -# We search for the key string followed by a word boundary (matched by \>), -# so if we search for 'setting', 'setting2' won't match. -if LC_ALL=C grep -q -m 1 -i -e "^fs.protected_symlinks\\>" "${SYSCONFIG_FILE}"; then - escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") - LC_ALL=C sed -i --follow-symlinks "s/^fs.protected_symlinks\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" -else - if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then - LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" - fi - printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: List /etc/sysctl.d/*.conf files - find: - paths: - - /etc/sysctl.d/ - - /run/sysctl.d/ - - /usr/local/lib/sysctl.d/ - contains: ^[\s]*fs.protected_symlinks.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_fs_protected_symlinks - -- name: Comment out any occurrences of fs.protected_symlinks from config files - replace: - path: '{{ item.path }}' - regexp: ^[\s]*fs.protected_symlinks - replace: '#fs.protected_symlinks' - loop: '{{ find_sysctl_d.files }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_fs_protected_symlinks - -- name: Ensure sysctl fs.protected_symlinks is set to 1 - sysctl: - name: fs.protected_symlinks - value: '1' - sysctl_file: /etc/sysctl.conf - state: present - reload: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_fs_protected_symlinks - - - - - - - - - - Verify Permissions on Files with Local Account Information and Credentials - The default restrictive permissions for files which act as -important security databases such as passwd, shadow, -group, and gshadow files must be maintained. Many utilities -need read access to the passwd file in order to function properly, but -read access to the shadow file allows malicious attacks against system -passwords, and should never be enabled. - - Verify Group Who Owns Backup group File - To properly set the group owner of /etc/group-, run the command: $ sudo chgrp root /etc/group- - CCI-002223 - AC-6 (1) - Req-8.7 - 7.2.6 - SRG-OS-000480-GPOS-00227 - The /etc/group- file is a backup file of /etc/group, and as such, -it contains information regarding groups that are configured on the system. -Protection of this file is important for system security. - chgrp 0 /etc/group- - - - name: Test for existence /etc/group- - stat: - path: /etc/group- - register: file_exists - tags: - - NIST-800-53-AC-6 (1) - - PCI-DSS-Req-8.7 - - PCI-DSSv4-7.2.6 - - configure_strategy - - file_groupowner_backup_etc_group - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Ensure group owner 0 on /etc/group- - file: - path: /etc/group- - group: '0' - when: file_exists.stat is defined and file_exists.stat.exists - tags: - - NIST-800-53-AC-6 (1) - - PCI-DSS-Req-8.7 - - PCI-DSSv4-7.2.6 - - configure_strategy - - file_groupowner_backup_etc_group - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Verify Group Who Owns Backup gshadow File - To properly set the group owner of /etc/gshadow-, run the command: $ sudo chgrp root /etc/gshadow- - CCI-002223 - AC-6 (1) - Req-8.7 - 7.2.6 - SRG-OS-000480-GPOS-00227 - The /etc/gshadow- file is a backup of /etc/gshadow, and as such, -it contains group password hashes. Protection of this file is critical for system security. - chgrp 0 /etc/gshadow- - - - name: Test for existence /etc/gshadow- - stat: - path: /etc/gshadow- - register: file_exists - tags: - - NIST-800-53-AC-6 (1) - - PCI-DSS-Req-8.7 - - PCI-DSSv4-7.2.6 - - configure_strategy - - file_groupowner_backup_etc_gshadow - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Ensure group owner 0 on /etc/gshadow- - file: - path: /etc/gshadow- - group: '0' - when: file_exists.stat is defined and file_exists.stat.exists - tags: - - NIST-800-53-AC-6 (1) - - PCI-DSS-Req-8.7 - - PCI-DSSv4-7.2.6 - - configure_strategy - - file_groupowner_backup_etc_gshadow - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Verify Group Who Owns Backup passwd File - To properly set the group owner of /etc/passwd-, run the command: $ sudo chgrp root /etc/passwd- - CCI-002223 - AC-6 (1) - Req-8.7 - 7.2.6 - SRG-OS-000480-GPOS-00227 - The /etc/passwd- file is a backup file of /etc/passwd, and as such, -it contains information about the users that are configured on the system. -Protection of this file is critical for system security. - chgrp 0 /etc/passwd- - - - name: Test for existence /etc/passwd- - stat: - path: /etc/passwd- - register: file_exists - tags: - - NIST-800-53-AC-6 (1) - - PCI-DSS-Req-8.7 - - PCI-DSSv4-7.2.6 - - configure_strategy - - file_groupowner_backup_etc_passwd - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Ensure group owner 0 on /etc/passwd- - file: - path: /etc/passwd- - group: '0' - when: file_exists.stat is defined and file_exists.stat.exists - tags: - - NIST-800-53-AC-6 (1) - - PCI-DSS-Req-8.7 - - PCI-DSSv4-7.2.6 - - configure_strategy - - file_groupowner_backup_etc_passwd - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Verify User Who Owns Backup shadow File - To properly set the group owner of /etc/shadow-, run the command: $ sudo chgrp root /etc/shadow- - Req-8.7 - 7.2.6 - SRG-OS-000480-GPOS-00227 - The /etc/shadow- file is a backup file of /etc/shadow, and as such, -it contains the list of local system accounts and password hashes. -Protection of this file is critical for system security. - chgrp 0 /etc/shadow- - - - name: Test for existence /etc/shadow- - stat: - path: /etc/shadow- - register: file_exists - tags: - - PCI-DSS-Req-8.7 - - PCI-DSSv4-7.2.6 - - configure_strategy - - file_groupowner_backup_etc_shadow - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Ensure group owner 0 on /etc/shadow- - file: - path: /etc/shadow- - group: '0' - when: file_exists.stat is defined and file_exists.stat.exists - tags: - - PCI-DSS-Req-8.7 - - PCI-DSSv4-7.2.6 - - configure_strategy - - file_groupowner_backup_etc_shadow - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Verify Group Who Owns group File - To properly set the group owner of /etc/group, run the command: $ sudo chgrp root /etc/group - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - 5.5.2.2 - APO01.06 - DSS05.04 - DSS05.07 - DSS06.02 - 4.3.3.7.3 - SR 2.1 - SR 5.2 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 - CM-6(a) - AC-6(1) - PR.AC-4 - PR.DS-5 - Req-8.7.c - 7.2.6 - SRG-OS-000480-GPOS-00227 - The /etc/group file contains information regarding groups that are configured -on the system. Protection of this file is important for system security. - chgrp 0 /etc/group - - - name: Test for existence /etc/group - stat: - path: /etc/group - register: file_exists - tags: - - CJIS-5.5.2.2 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-8.7.c - - PCI-DSSv4-7.2.6 - - configure_strategy - - file_groupowner_etc_group - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Ensure group owner 0 on /etc/group - file: - path: /etc/group - group: '0' - when: file_exists.stat is defined and file_exists.stat.exists - tags: - - CJIS-5.5.2.2 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-8.7.c - - PCI-DSSv4-7.2.6 - - configure_strategy - - file_groupowner_etc_group - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Verify Group Who Owns gshadow File - To properly set the group owner of /etc/gshadow, run the command: $ sudo chgrp root /etc/gshadow - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - APO01.06 - DSS05.04 - DSS05.07 - DSS06.02 - 4.3.3.7.3 - SR 2.1 - SR 5.2 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 - CM-6(a) - AC-6(1) - PR.AC-4 - PR.DS-5 - SRG-OS-000480-GPOS-00227 - The /etc/gshadow file contains group password hashes. Protection of this file -is critical for system security. - chgrp 0 /etc/gshadow - - - name: Test for existence /etc/gshadow - stat: - path: /etc/gshadow - register: file_exists - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - configure_strategy - - file_groupowner_etc_gshadow - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Ensure group owner 0 on /etc/gshadow - file: - path: /etc/gshadow - group: '0' - when: file_exists.stat is defined and file_exists.stat.exists - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - configure_strategy - - file_groupowner_etc_gshadow - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Verify Group Who Owns passwd File - To properly set the group owner of /etc/passwd, run the command: $ sudo chgrp root /etc/passwd - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - 5.5.2.2 - APO01.06 - DSS05.04 - DSS05.07 - DSS06.02 - 4.3.3.7.3 - SR 2.1 - SR 5.2 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 - CM-6(a) - AC-6(1) - PR.AC-4 - PR.DS-5 - Req-8.7.c - 7.2.6 - SRG-OS-000480-GPOS-00227 - The /etc/passwd file contains information about the users that are configured on -the system. Protection of this file is critical for system security. - chgrp 0 /etc/passwd - - - name: Test for existence /etc/passwd - stat: - path: /etc/passwd - register: file_exists - tags: - - CJIS-5.5.2.2 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-8.7.c - - PCI-DSSv4-7.2.6 - - configure_strategy - - file_groupowner_etc_passwd - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Ensure group owner 0 on /etc/passwd - file: - path: /etc/passwd - group: '0' - when: file_exists.stat is defined and file_exists.stat.exists - tags: - - CJIS-5.5.2.2 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-8.7.c - - PCI-DSSv4-7.2.6 - - configure_strategy - - file_groupowner_etc_passwd - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Verify Group Who Owns shadow File - To properly set the group owner of /etc/shadow, run the command: $ sudo chgrp root /etc/shadow - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - 5.5.2.2 - APO01.06 - DSS05.04 - DSS05.07 - DSS06.02 - 4.3.3.7.3 - SR 2.1 - SR 5.2 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 - CM-6(a) - AC-6(1) - PR.AC-4 - PR.DS-5 - Req-8.7.c - 7.2.6 - SRG-OS-000480-GPOS-00227 - The /etc/shadow file stores password hashes. Protection of this file is -critical for system security. - chgrp 0 /etc/shadow - - - name: Test for existence /etc/shadow - stat: - path: /etc/shadow - register: file_exists - tags: - - CJIS-5.5.2.2 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-8.7.c - - PCI-DSSv4-7.2.6 - - configure_strategy - - file_groupowner_etc_shadow - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Ensure group owner 0 on /etc/shadow - file: - path: /etc/shadow - group: '0' - when: file_exists.stat is defined and file_exists.stat.exists - tags: - - CJIS-5.5.2.2 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-8.7.c - - PCI-DSSv4-7.2.6 - - configure_strategy - - file_groupowner_etc_shadow - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Verify User Who Owns Backup group File - To properly set the owner of /etc/group-, run the command: $ sudo chown root /etc/group- - CCI-002223 - AC-6 (1) - Req-8.7.c - 7.2.6 - SRG-OS-000480-GPOS-00227 - The /etc/group- file is a backup file of /etc/group, and as such, -it contains information regarding groups that are configured on the system. -Protection of this file is important for system security. - chown 0 /etc/group- - - - name: Test for existence /etc/group- - stat: - path: /etc/group- - register: file_exists - tags: - - NIST-800-53-AC-6 (1) - - PCI-DSS-Req-8.7.c - - PCI-DSSv4-7.2.6 - - configure_strategy - - file_owner_backup_etc_group - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Ensure owner 0 on /etc/group- - file: - path: /etc/group- - owner: '0' - when: file_exists.stat is defined and file_exists.stat.exists - tags: - - NIST-800-53-AC-6 (1) - - PCI-DSS-Req-8.7.c - - PCI-DSSv4-7.2.6 - - configure_strategy - - file_owner_backup_etc_group - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Verify User Who Owns Backup gshadow File - To properly set the owner of /etc/gshadow-, run the command: $ sudo chown root /etc/gshadow- - CCI-002223 - AC-6 (1) - Req-8.7 - 7.2.6 - SRG-OS-000480-GPOS-00227 - The /etc/gshadow- file is a backup of /etc/gshadow, and as such, -it contains group password hashes. Protection of this file is critical for system security. - chown 0 /etc/gshadow- - - - name: Test for existence /etc/gshadow- - stat: - path: /etc/gshadow- - register: file_exists - tags: - - NIST-800-53-AC-6 (1) - - PCI-DSS-Req-8.7 - - PCI-DSSv4-7.2.6 - - configure_strategy - - file_owner_backup_etc_gshadow - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Ensure owner 0 on /etc/gshadow- - file: - path: /etc/gshadow- - owner: '0' - when: file_exists.stat is defined and file_exists.stat.exists - tags: - - NIST-800-53-AC-6 (1) - - PCI-DSS-Req-8.7 - - PCI-DSSv4-7.2.6 - - configure_strategy - - file_owner_backup_etc_gshadow - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Verify User Who Owns Backup passwd File - To properly set the owner of /etc/passwd-, run the command: $ sudo chown root /etc/passwd- - CCI-002223 - AC-6 (1) - Req-8.7.c - 7.2.6 - SRG-OS-000480-GPOS-00227 - The /etc/passwd- file is a backup file of /etc/passwd, and as such, -it contains information about the users that are configured on the system. -Protection of this file is critical for system security. - chown 0 /etc/passwd- - - - name: Test for existence /etc/passwd- - stat: - path: /etc/passwd- - register: file_exists - tags: - - NIST-800-53-AC-6 (1) - - PCI-DSS-Req-8.7.c - - PCI-DSSv4-7.2.6 - - configure_strategy - - file_owner_backup_etc_passwd - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Ensure owner 0 on /etc/passwd- - file: - path: /etc/passwd- - owner: '0' - when: file_exists.stat is defined and file_exists.stat.exists - tags: - - NIST-800-53-AC-6 (1) - - PCI-DSS-Req-8.7.c - - PCI-DSSv4-7.2.6 - - configure_strategy - - file_owner_backup_etc_passwd - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Verify Group Who Owns Backup shadow File - To properly set the owner of /etc/shadow-, run the command: $ sudo chown root /etc/shadow- - CCI-002223 - AC-6 (1) - Req-8.7.c - 7.2.6 - SRG-OS-000480-GPOS-00227 - The /etc/shadow- file is a backup file of /etc/shadow, and as such, -it contains the list of local system accounts and password hashes. -Protection of this file is critical for system security. - chown 0 /etc/shadow- - - - name: Test for existence /etc/shadow- - stat: - path: /etc/shadow- - register: file_exists - tags: - - NIST-800-53-AC-6 (1) - - PCI-DSS-Req-8.7.c - - PCI-DSSv4-7.2.6 - - configure_strategy - - file_owner_backup_etc_shadow - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Ensure owner 0 on /etc/shadow- - file: - path: /etc/shadow- - owner: '0' - when: file_exists.stat is defined and file_exists.stat.exists - tags: - - NIST-800-53-AC-6 (1) - - PCI-DSS-Req-8.7.c - - PCI-DSSv4-7.2.6 - - configure_strategy - - file_owner_backup_etc_shadow - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Verify User Who Owns group File - To properly set the owner of /etc/group, run the command: $ sudo chown root /etc/group - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - 5.5.2.2 - APO01.06 - DSS05.04 - DSS05.07 - DSS06.02 - CCI-002223 - 4.3.3.7.3 - SR 2.1 - SR 5.2 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 - CM-6(a) - AC-6(1) - PR.AC-4 - PR.DS-5 - Req-8.7.c - 7.2.6 - SRG-OS-000480-GPOS-00227 - The /etc/group file contains information regarding groups that are configured -on the system. Protection of this file is important for system security. - chown 0 /etc/group - - - name: Test for existence /etc/group - stat: - path: /etc/group - register: file_exists - tags: - - CJIS-5.5.2.2 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-8.7.c - - PCI-DSSv4-7.2.6 - - configure_strategy - - file_owner_etc_group - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Ensure owner 0 on /etc/group - file: - path: /etc/group - owner: '0' - when: file_exists.stat is defined and file_exists.stat.exists - tags: - - CJIS-5.5.2.2 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-8.7.c - - PCI-DSSv4-7.2.6 - - configure_strategy - - file_owner_etc_group - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Verify User Who Owns gshadow File - To properly set the owner of /etc/gshadow, run the command: $ sudo chown root /etc/gshadow - BP28(R36) - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - APO01.06 - DSS05.04 - DSS05.07 - DSS06.02 - CCI-002223 - 4.3.3.7.3 - SR 2.1 - SR 5.2 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 - CM-6(a) - AC-6(1) - PR.AC-4 - PR.DS-5 - SRG-OS-000480-GPOS-00227 - The /etc/gshadow file contains group password hashes. Protection of this file -is critical for system security. - chown 0 /etc/gshadow - - - name: Test for existence /etc/gshadow - stat: - path: /etc/gshadow - register: file_exists - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - configure_strategy - - file_owner_etc_gshadow - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Ensure owner 0 on /etc/gshadow - file: - path: /etc/gshadow - owner: '0' - when: file_exists.stat is defined and file_exists.stat.exists - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - configure_strategy - - file_owner_etc_gshadow - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Verify User Who Owns passwd File - To properly set the owner of /etc/passwd, run the command: $ sudo chown root /etc/passwd - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - 5.5.2.2 - APO01.06 - DSS05.04 - DSS05.07 - DSS06.02 - CCI-002223 - 4.3.3.7.3 - SR 2.1 - SR 5.2 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 - CM-6(a) - AC-6(1) - PR.AC-4 - PR.DS-5 - Req-8.7.c - 7.2.6 - SRG-OS-000480-GPOS-00227 - The /etc/passwd file contains information about the users that are configured on -the system. Protection of this file is critical for system security. - chown 0 /etc/passwd - - - name: Test for existence /etc/passwd - stat: - path: /etc/passwd - register: file_exists - tags: - - CJIS-5.5.2.2 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-8.7.c - - PCI-DSSv4-7.2.6 - - configure_strategy - - file_owner_etc_passwd - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Ensure owner 0 on /etc/passwd - file: - path: /etc/passwd - owner: '0' - when: file_exists.stat is defined and file_exists.stat.exists - tags: - - CJIS-5.5.2.2 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-8.7.c - - PCI-DSSv4-7.2.6 - - configure_strategy - - file_owner_etc_passwd - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Verify User Who Owns shadow File - To properly set the owner of /etc/shadow, run the command: $ sudo chown root /etc/shadow - BP28(R36) - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - 5.5.2.2 - APO01.06 - DSS05.04 - DSS05.07 - DSS06.02 - CCI-002223 - 4.3.3.7.3 - SR 2.1 - SR 5.2 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 - CM-6(a) - AC-6(1) - PR.AC-4 - PR.DS-5 - Req-8.7.c - 7.2.6 - SRG-OS-000480-GPOS-00227 - The /etc/shadow file contains the list of local -system accounts and stores password hashes. Protection of this file is -critical for system security. Failure to give ownership of this file -to root provides the designated owner with access to sensitive information -which could weaken the system security posture. - chown 0 /etc/shadow - - - name: Test for existence /etc/shadow - stat: - path: /etc/shadow - register: file_exists - tags: - - CJIS-5.5.2.2 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-8.7.c - - PCI-DSSv4-7.2.6 - - configure_strategy - - file_owner_etc_shadow - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Ensure owner 0 on /etc/shadow - file: - path: /etc/shadow - owner: '0' - when: file_exists.stat is defined and file_exists.stat.exists - tags: - - CJIS-5.5.2.2 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-8.7.c - - PCI-DSSv4-7.2.6 - - configure_strategy - - file_owner_etc_shadow - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Verify Permissions on Backup group File - -To properly set the permissions of /etc/group-, run the command: -$ sudo chmod 0644 /etc/group- - CCI-002223 - AC-6 (1) - Req-8.7.c - 7.2.6 - SRG-OS-000480-GPOS-00227 - The /etc/group- file is a backup file of /etc/group, and as such, -it contains information regarding groups that are configured on the system. -Protection of this file is important for system security. - - - - - -chmod u-xs,g-xws,o-xwt /etc/group- - - - name: Test for existence /etc/group- - stat: - path: /etc/group- - register: file_exists - tags: - - NIST-800-53-AC-6 (1) - - PCI-DSS-Req-8.7.c - - PCI-DSSv4-7.2.6 - - configure_strategy - - file_permissions_backup_etc_group - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Ensure permission u-xs,g-xws,o-xwt on /etc/group- - file: - path: /etc/group- - mode: u-xs,g-xws,o-xwt - when: file_exists.stat is defined and file_exists.stat.exists - tags: - - NIST-800-53-AC-6 (1) - - PCI-DSS-Req-8.7.c - - PCI-DSSv4-7.2.6 - - configure_strategy - - file_permissions_backup_etc_group - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Verify Permissions on Backup gshadow File - -To properly set the permissions of /etc/gshadow-, run the command: -$ sudo chmod 0000 /etc/gshadow- - CCI-002223 - AC-6 (1) - SRG-OS-000480-GPOS-00227 - The /etc/gshadow- file is a backup of /etc/gshadow, and as such, -it contains group password hashes. Protection of this file is critical for system security. - - - - - -chmod u-xwrs,g-xwrs,o-xwrt /etc/gshadow- - - - name: Test for existence /etc/gshadow- - stat: - path: /etc/gshadow- - register: file_exists - tags: - - NIST-800-53-AC-6 (1) - - configure_strategy - - file_permissions_backup_etc_gshadow - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Ensure permission u-xwrs,g-xwrs,o-xwrt on /etc/gshadow- - file: - path: /etc/gshadow- - mode: u-xwrs,g-xwrs,o-xwrt - when: file_exists.stat is defined and file_exists.stat.exists - tags: - - NIST-800-53-AC-6 (1) - - configure_strategy - - file_permissions_backup_etc_gshadow - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Verify Permissions on Backup passwd File - -To properly set the permissions of /etc/passwd-, run the command: -$ sudo chmod 0644 /etc/passwd- - CCI-002223 - AC-6 (1) - Req-8.7.c - 7.2.6 - SRG-OS-000480-GPOS-00227 - The /etc/passwd- file is a backup file of /etc/passwd, and as such, -it contains information about the users that are configured on the system. -Protection of this file is critical for system security. - - - - - -chmod u-xs,g-xws,o-xwt /etc/passwd- - - - name: Test for existence /etc/passwd- - stat: - path: /etc/passwd- - register: file_exists - tags: - - NIST-800-53-AC-6 (1) - - PCI-DSS-Req-8.7.c - - PCI-DSSv4-7.2.6 - - configure_strategy - - file_permissions_backup_etc_passwd - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Ensure permission u-xs,g-xws,o-xwt on /etc/passwd- - file: - path: /etc/passwd- - mode: u-xs,g-xws,o-xwt - when: file_exists.stat is defined and file_exists.stat.exists - tags: - - NIST-800-53-AC-6 (1) - - PCI-DSS-Req-8.7.c - - PCI-DSSv4-7.2.6 - - configure_strategy - - file_permissions_backup_etc_passwd - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Verify Permissions on Backup shadow File - -To properly set the permissions of /etc/shadow-, run the command: -$ sudo chmod 0000 /etc/shadow- - CCI-002223 - AC-6 (1) - Req-8.7.c - 7.2.6 - SRG-OS-000480-GPOS-00227 - The /etc/shadow- file is a backup file of /etc/shadow, and as such, -it contains the list of local system accounts and password hashes. -Protection of this file is critical for system security. - - - - - -chmod u-xwrs,g-xwrs,o-xwrt /etc/shadow- - - - name: Test for existence /etc/shadow- - stat: - path: /etc/shadow- - register: file_exists - tags: - - NIST-800-53-AC-6 (1) - - PCI-DSS-Req-8.7.c - - PCI-DSSv4-7.2.6 - - configure_strategy - - file_permissions_backup_etc_shadow - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Ensure permission u-xwrs,g-xwrs,o-xwrt on /etc/shadow- - file: - path: /etc/shadow- - mode: u-xwrs,g-xwrs,o-xwrt - when: file_exists.stat is defined and file_exists.stat.exists - tags: - - NIST-800-53-AC-6 (1) - - PCI-DSS-Req-8.7.c - - PCI-DSSv4-7.2.6 - - configure_strategy - - file_permissions_backup_etc_shadow - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Verify Permissions on group File - -To properly set the permissions of /etc/passwd, run the command: -$ sudo chmod 0644 /etc/passwd - BP28(R36) - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - 5.5.2.2 - APO01.06 - DSS05.04 - DSS05.07 - DSS06.02 - CCI-002223 - 4.3.3.7.3 - SR 2.1 - SR 5.2 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 - CM-6(a) - AC-6(1) - PR.AC-4 - PR.DS-5 - Req-8.7.c - 7.2.6 - SRG-OS-000480-GPOS-00227 - The /etc/group file contains information regarding groups that are configured -on the system. Protection of this file is important for system security. - - - - - -chmod u-xs,g-xws,o-xwt /etc/group - - - name: Test for existence /etc/group - stat: - path: /etc/group - register: file_exists - tags: - - CJIS-5.5.2.2 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-8.7.c - - PCI-DSSv4-7.2.6 - - configure_strategy - - file_permissions_etc_group - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Ensure permission u-xs,g-xws,o-xwt on /etc/group - file: - path: /etc/group - mode: u-xs,g-xws,o-xwt - when: file_exists.stat is defined and file_exists.stat.exists - tags: - - CJIS-5.5.2.2 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-8.7.c - - PCI-DSSv4-7.2.6 - - configure_strategy - - file_permissions_etc_group - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Verify Permissions on gshadow File - -To properly set the permissions of /etc/gshadow, run the command: -$ sudo chmod 0000 /etc/gshadow - BP28(R36) - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - APO01.06 - DSS05.04 - DSS05.07 - DSS06.02 - CCI-002223 - 4.3.3.7.3 - SR 2.1 - SR 5.2 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 - CM-6(a) - AC-6(1) - PR.AC-4 - PR.DS-5 - SRG-OS-000480-GPOS-00227 - The /etc/gshadow file contains group password hashes. Protection of this file -is critical for system security. - - - - - -chmod u-xwrs,g-xwrs,o-xwrt /etc/gshadow - - - name: Test for existence /etc/gshadow - stat: - path: /etc/gshadow - register: file_exists - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - configure_strategy - - file_permissions_etc_gshadow - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Ensure permission u-xwrs,g-xwrs,o-xwrt on /etc/gshadow - file: - path: /etc/gshadow - mode: u-xwrs,g-xwrs,o-xwrt - when: file_exists.stat is defined and file_exists.stat.exists - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - configure_strategy - - file_permissions_etc_gshadow - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Verify Permissions on passwd File - -To properly set the permissions of /etc/passwd, run the command: -$ sudo chmod 0644 /etc/passwd - BP28(R36) - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - 5.5.2.2 - APO01.06 - DSS05.04 - DSS05.07 - DSS06.02 - CCI-002223 - 4.3.3.7.3 - SR 2.1 - SR 5.2 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 - CM-6(a) - AC-6(1) - PR.AC-4 - PR.DS-5 - Req-8.7.c - 7.2.6 - SRG-OS-000480-GPOS-00227 - If the /etc/passwd file is writable by a group-owner or the -world the risk of its compromise is increased. The file contains the list of -accounts on the system and associated information, and protection of this file -is critical for system security. - - - - - -chmod u-xs,g-xws,o-xwt /etc/passwd - - - name: Test for existence /etc/passwd - stat: - path: /etc/passwd - register: file_exists - tags: - - CJIS-5.5.2.2 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-8.7.c - - PCI-DSSv4-7.2.6 - - configure_strategy - - file_permissions_etc_passwd - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Ensure permission u-xs,g-xws,o-xwt on /etc/passwd - file: - path: /etc/passwd - mode: u-xs,g-xws,o-xwt - when: file_exists.stat is defined and file_exists.stat.exists - tags: - - CJIS-5.5.2.2 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-8.7.c - - PCI-DSSv4-7.2.6 - - configure_strategy - - file_permissions_etc_passwd - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Verify Permissions on shadow File - -To properly set the permissions of /etc/shadow, run the command: -$ sudo chmod 0000 /etc/shadow - BP28(R36) - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - 5.5.2.2 - APO01.06 - DSS05.04 - DSS05.07 - DSS06.02 - CCI-002223 - 4.3.3.7.3 - SR 2.1 - SR 5.2 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 - CM-6(a) - AC-6(1) - PR.AC-4 - PR.DS-5 - Req-8.7.c - 7.2.6 - SRG-OS-000480-GPOS-00227 - The /etc/shadow file contains the list of local -system accounts and stores password hashes. Protection of this file is -critical for system security. Failure to give ownership of this file -to root provides the designated owner with access to sensitive information -which could weaken the system security posture. - - - - - -chmod u-xwrs,g-xwrs,o-xwrt /etc/shadow - - - name: Test for existence /etc/shadow - stat: - path: /etc/shadow - register: file_exists - tags: - - CJIS-5.5.2.2 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-8.7.c - - PCI-DSSv4-7.2.6 - - configure_strategy - - file_permissions_etc_shadow - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Ensure permission u-xwrs,g-xwrs,o-xwrt on /etc/shadow - file: - path: /etc/shadow - mode: u-xwrs,g-xwrs,o-xwrt - when: file_exists.stat is defined and file_exists.stat.exists - tags: - - CJIS-5.5.2.2 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-8.7.c - - PCI-DSSv4-7.2.6 - - configure_strategy - - file_permissions_etc_shadow - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - - Verify Permissions on Files within /var/log Directory - The /var/log directory contains files with logs of error -messages in the system and should only be accessed by authorized -personnel. - - Verify Group Who Owns /var/log Directory - To properly set the group owner of /var/log, run the command: $ sudo chgrp root /var/log - CCI-001314 - SRG-OS-000206-GPOS-00084 - SRG-APP-000118-CTR-000240 - The /var/log directory contains files with logs of error -messages in the system and should only be accessed by authorized -personnel. - find -H /var/log/ -maxdepth 1 -type d -exec chgrp 0 {} \; - - - name: Ensure group owner on /var/log/ - file: - path: /var/log/ - state: directory - group: '0' - tags: - - configure_strategy - - file_groupowner_var_log - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Verify Group Who Owns /var/log/messages File - To properly set the group owner of /var/log/messages, run the command: $ sudo chgrp root /var/log/messages - CCI-001314 - SRG-OS-000206-GPOS-00084 - The /var/log/messages file contains logs of error messages in -the system and should only be accessed by authorized personnel. - chgrp 0 /var/log/messages - - - name: Test for existence /var/log/messages - stat: - path: /var/log/messages - register: file_exists - tags: - - configure_strategy - - file_groupowner_var_log_messages - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Ensure group owner 0 on /var/log/messages - file: - path: /var/log/messages - group: '0' - when: file_exists.stat is defined and file_exists.stat.exists - tags: - - configure_strategy - - file_groupowner_var_log_messages - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Verify Group Who Owns /var/log/syslog File - To properly set the group owner of /var/log/syslog, run the command: $ sudo chgrp adm /var/log/syslog - CCI-001314 - SRG-OS-000206-GPOS-00084 - The /var/log/syslog file contains logs of error messages in -the system and should only be accessed by authorized personnel. - chgrp 4 /var/log/syslog - - - name: Test for existence /var/log/syslog - stat: - path: /var/log/syslog - register: file_exists - tags: - - configure_strategy - - file_groupowner_var_log_syslog - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Ensure group owner 4 on /var/log/syslog - file: - path: /var/log/syslog - group: '4' - when: file_exists.stat is defined and file_exists.stat.exists - tags: - - configure_strategy - - file_groupowner_var_log_syslog - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Verify User Who Owns /var/log Directory - To properly set the owner of /var/log, run the command: $ sudo chown root /var/log - CCI-001314 - SRG-OS-000206-GPOS-00084 - SRG-APP-000118-CTR-000240 - The /var/log directory contains files with logs of error -messages in the system and should only be accessed by authorized -personnel. - find -H /var/log/ -maxdepth 1 -type d -exec chown 0 {} \; - - - name: Ensure owner on directory /var/log/ - file: - path: /var/log/ - state: directory - owner: '0' - tags: - - configure_strategy - - file_owner_var_log - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Verify User Who Owns /var/log/messages File - To properly set the owner of /var/log/messages, run the command: $ sudo chown root /var/log/messages - CCI-001314 - SRG-OS-000206-GPOS-00084 - The /var/log/messages file contains logs of error messages in -the system and should only be accessed by authorized personnel. - chown 0 /var/log/messages - - - name: Test for existence /var/log/messages - stat: - path: /var/log/messages - register: file_exists - tags: - - configure_strategy - - file_owner_var_log_messages - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Ensure owner 0 on /var/log/messages - file: - path: /var/log/messages - owner: '0' - when: file_exists.stat is defined and file_exists.stat.exists - tags: - - configure_strategy - - file_owner_var_log_messages - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Verify User Who Owns /var/log/syslog File - To properly set the owner of /var/log/syslog, run the command: $ sudo chown syslog /var/log/syslog - CCI-001314 - SRG-OS-000206-GPOS-00084 - The /var/log/syslog file contains logs of error messages in -the system and should only be accessed by authorized personnel. - chown 104 /var/log/syslog - - - name: Test for existence /var/log/syslog - stat: - path: /var/log/syslog - register: file_exists - tags: - - configure_strategy - - file_owner_var_log_syslog - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Ensure owner 104 on /var/log/syslog - file: - path: /var/log/syslog - owner: '104' - when: file_exists.stat is defined and file_exists.stat.exists - tags: - - configure_strategy - - file_owner_var_log_syslog - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Verify Permissions on /var/log Directory - -To properly set the permissions of /var/log, run the command: -$ sudo chmod 0755 /var/log - CCI-001314 - SRG-OS-000206-GPOS-00084 - SRG-APP-000118-CTR-000240 - The /var/log directory contains files with logs of error -messages in the system and should only be accessed by authorized -personnel. - - - - - -find -H /var/log/ -maxdepth 1 -perm /u+s,g+ws,o+wt -type d -exec chmod u-s,g-ws,o-wt {} \; - - - name: Set permissions for /var/log/ - file: - path: /var/log/ - state: directory - mode: u-s,g-ws,o-wt - tags: - - configure_strategy - - file_permissions_var_log - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Verify Permissions on /var/log/messages File - -To properly set the permissions of /var/log/messages, run the command: -$ sudo chmod 0640 /var/log/messages - CCI-001314 - SRG-OS-000206-GPOS-00084 - The /var/log/messages file contains logs of error messages in -the system and should only be accessed by authorized personnel. - - - - - -chmod u-xs,g-xws,o-xwrt /var/log/messages - - - name: Test for existence /var/log/messages - stat: - path: /var/log/messages - register: file_exists - tags: - - configure_strategy - - file_permissions_var_log_messages - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Ensure permission u-xs,g-xws,o-xwrt on /var/log/messages - file: - path: /var/log/messages - mode: u-xs,g-xws,o-xwrt - when: file_exists.stat is defined and file_exists.stat.exists - tags: - - configure_strategy - - file_permissions_var_log_messages - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Verify Permissions on /var/log/syslog File - -To properly set the permissions of /var/log/syslog, run the command: -$ sudo chmod 0640 /var/log/syslog - CCI-001314 - SRG-OS-000206-GPOS-00084 - The /var/log/syslog file contains logs of error messages in -the system and should only be accessed by authorized personnel. - - - - - -chmod u-xs,g-xws,o-xwrt /var/log/syslog - - - name: Test for existence /var/log/syslog - stat: - path: /var/log/syslog - register: file_exists - tags: - - configure_strategy - - file_permissions_var_log_syslog - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Ensure permission u-xs,g-xws,o-xwrt on /var/log/syslog - file: - path: /var/log/syslog - mode: u-xs,g-xws,o-xwrt - when: file_exists.stat is defined and file_exists.stat.exists - tags: - - configure_strategy - - file_permissions_var_log_syslog - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - - Verify File Permissions Within Some Important Directories - Some directories contain files whose confidentiality or integrity -is notably important and may also be susceptible to misconfiguration over time, particularly if -unpackaged software is installed. As such, -an argument exists to verify that files' permissions within these directories remain -configured correctly and restrictively. - - Verify that Shared Library Directories Have Root Group Ownership - System-wide shared library files, which are linked to executables -during process load time or run time, are stored in the following directories -by default: -/lib -/lib64 -/usr/lib -/usr/lib64 - -Kernel modules, which can be added to the kernel during runtime, are also -stored in /lib/modules. All files in these directories should be -group-owned by the root user. If the directories, is found to be owned -by a user other than root correct its -ownership with the following command: -$ sudo chgrp root DIR - CCI-001499 - CM-5(6) - CM-5(6).1 - SRG-OS-000259-GPOS-00100 - Files from shared library directories are loaded into the address -space of processes (including privileged ones) or of the kernel itself at -runtime. Proper ownership of library directories is necessary to protect -the integrity of the system. - find -H /lib/ -type d -exec chgrp 0 {} \; -find -H /lib64/ -type d -exec chgrp 0 {} \; -find -H /usr/lib/ -type d -exec chgrp 0 {} \; -find -H /usr/lib64/ -type d -exec chgrp 0 {} \; - - - name: Ensure group owner on /lib/ recursively - file: - path: /lib/ - state: directory - recurse: true - group: '0' - tags: - - NIST-800-53-CM-5(6) - - NIST-800-53-CM-5(6).1 - - configure_strategy - - dir_group_ownership_library_dirs - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Ensure group owner on /lib64/ recursively - file: - path: /lib64/ - state: directory - recurse: true - group: '0' - tags: - - NIST-800-53-CM-5(6) - - NIST-800-53-CM-5(6).1 - - configure_strategy - - dir_group_ownership_library_dirs - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Ensure group owner on /usr/lib/ recursively - file: - path: /usr/lib/ - state: directory - recurse: true - group: '0' - tags: - - NIST-800-53-CM-5(6) - - NIST-800-53-CM-5(6).1 - - configure_strategy - - dir_group_ownership_library_dirs - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Ensure group owner on /usr/lib64/ recursively - file: - path: /usr/lib64/ - state: directory - recurse: true - group: '0' - tags: - - NIST-800-53-CM-5(6) - - NIST-800-53-CM-5(6).1 - - configure_strategy - - dir_group_ownership_library_dirs - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Verify that System Executable Have Root Ownership - /bin -/sbin -/usr/bin -/usr/sbin -/usr/local/bin -/usr/local/sbin -All these directories should be owned by the root user. -If any directory DIR in these directories is found -to be owned by a user other than root, correct its ownership with the -following command: -$ sudo chown root DIR - CCI-001495 - SRG-OS-000258-GPOS-00099 - System binaries are executed by privileged users as well as system services, -and restrictive permissions are necessary to ensure that their -execution of these programs cannot be co-opted. - find -H /bin/ -type d -exec chown 0 {} \; -find -H /sbin/ -type d -exec chown 0 {} \; -find -H /usr/bin/ -type d -exec chown 0 {} \; -find -H /usr/sbin/ -type d -exec chown 0 {} \; -find -H /usr/local/bin/ -type d -exec chown 0 {} \; -find -H /usr/local/sbin/ -type d -exec chown 0 {} \; - - - name: Ensure owner on directory /bin/ recursively - file: - path: /bin/ - state: directory - recurse: true - owner: '0' - tags: - - configure_strategy - - dir_ownership_binary_dirs - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Ensure owner on directory /sbin/ recursively - file: - path: /sbin/ - state: directory - recurse: true - owner: '0' - tags: - - configure_strategy - - dir_ownership_binary_dirs - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Ensure owner on directory /usr/bin/ recursively - file: - path: /usr/bin/ - state: directory - recurse: true - owner: '0' - tags: - - configure_strategy - - dir_ownership_binary_dirs - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Ensure owner on directory /usr/sbin/ recursively - file: - path: /usr/sbin/ - state: directory - recurse: true - owner: '0' - tags: - - configure_strategy - - dir_ownership_binary_dirs - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Ensure owner on directory /usr/local/bin/ recursively - file: - path: /usr/local/bin/ - state: directory - recurse: true - owner: '0' - tags: - - configure_strategy - - dir_ownership_binary_dirs - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Ensure owner on directory /usr/local/sbin/ recursively - file: - path: /usr/local/sbin/ - state: directory - recurse: true - owner: '0' - tags: - - configure_strategy - - dir_ownership_binary_dirs - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Verify that Shared Library Directories Have Root Ownership - System-wide shared library files, which are linked to executables -during process load time or run time, are stored in the following directories -by default: -/lib -/lib64 -/usr/lib -/usr/lib64 - -Kernel modules, which can be added to the kernel during runtime, are also -stored in /lib/modules. All files in these directories should be -owned by the root user. If the directories, is found to be owned -by a user other than root correct its -ownership with the following command: -$ sudo chown root DIR - CCI-001499 - CM-5(6) - CM-5(6).1 - SRG-OS-000259-GPOS-00100 - Files from shared library directories are loaded into the address -space of processes (including privileged ones) or of the kernel itself at -runtime. Proper ownership of library directories is necessary to protect -the integrity of the system. - find -H /lib/ -type d -exec chown 0 {} \; -find -H /lib64/ -type d -exec chown 0 {} \; -find -H /usr/lib/ -type d -exec chown 0 {} \; -find -H /usr/lib64/ -type d -exec chown 0 {} \; - - - name: Ensure owner on directory /lib/ recursively - file: - path: /lib/ - state: directory - recurse: true - owner: '0' - tags: - - NIST-800-53-CM-5(6) - - NIST-800-53-CM-5(6).1 - - configure_strategy - - dir_ownership_library_dirs - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Ensure owner on directory /lib64/ recursively - file: - path: /lib64/ - state: directory - recurse: true - owner: '0' - tags: - - NIST-800-53-CM-5(6) - - NIST-800-53-CM-5(6).1 - - configure_strategy - - dir_ownership_library_dirs - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Ensure owner on directory /usr/lib/ recursively - file: - path: /usr/lib/ - state: directory - recurse: true - owner: '0' - tags: - - NIST-800-53-CM-5(6) - - NIST-800-53-CM-5(6).1 - - configure_strategy - - dir_ownership_library_dirs - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Ensure owner on directory /usr/lib64/ recursively - file: - path: /usr/lib64/ - state: directory - recurse: true - owner: '0' - tags: - - NIST-800-53-CM-5(6) - - NIST-800-53-CM-5(6).1 - - configure_strategy - - dir_ownership_library_dirs - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Verify that System Executable Directories Have Restrictive Permissions - System executables are stored in the following directories by default: -/bin -/sbin -/usr/bin -/usr/sbin -/usr/local/bin -/usr/local/sbin -These directories should not be group-writable or world-writable. -If any directory DIR in these directories is found to be -group-writable or world-writable, correct its permission with the -following command: -$ sudo chmod go-w DIR - CCI-001495 - SRG-OS-000258-GPOS-00099 - System binaries are executed by privileged users, as well as system services, -and restrictive permissions are necessary to ensure execution of these programs -cannot be co-opted. - - - - - -find -H /bin/ -perm /u+s,g+ws,o+wt -type d -exec chmod u-s,g-ws,o-wt {} \; - -find -H /sbin/ -perm /u+s,g+ws,o+wt -type d -exec chmod u-s,g-ws,o-wt {} \; - -find -H /usr/bin/ -perm /u+s,g+ws,o+wt -type d -exec chmod u-s,g-ws,o-wt {} \; - -find -H /usr/sbin/ -perm /u+s,g+ws,o+wt -type d -exec chmod u-s,g-ws,o-wt {} \; - -find -H /usr/local/bin/ -perm /u+s,g+ws,o+wt -type d -exec chmod u-s,g-ws,o-wt {} \; - -find -H /usr/local/sbin/ -perm /u+s,g+ws,o+wt -type d -exec chmod u-s,g-ws,o-wt {} \; - - - name: Set permissions for /bin/ recursively - file: - path: /bin/ - state: directory - recurse: true - mode: u-s,g-ws,o-wt - tags: - - configure_strategy - - dir_permissions_binary_dirs - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Set permissions for /sbin/ recursively - file: - path: /sbin/ - state: directory - recurse: true - mode: u-s,g-ws,o-wt - tags: - - configure_strategy - - dir_permissions_binary_dirs - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Set permissions for /usr/bin/ recursively - file: - path: /usr/bin/ - state: directory - recurse: true - mode: u-s,g-ws,o-wt - tags: - - configure_strategy - - dir_permissions_binary_dirs - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Set permissions for /usr/sbin/ recursively - file: - path: /usr/sbin/ - state: directory - recurse: true - mode: u-s,g-ws,o-wt - tags: - - configure_strategy - - dir_permissions_binary_dirs - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Set permissions for /usr/local/bin/ recursively - file: - path: /usr/local/bin/ - state: directory - recurse: true - mode: u-s,g-ws,o-wt - tags: - - configure_strategy - - dir_permissions_binary_dirs - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Set permissions for /usr/local/sbin/ recursively - file: - path: /usr/local/sbin/ - state: directory - recurse: true - mode: u-s,g-ws,o-wt - tags: - - configure_strategy - - dir_permissions_binary_dirs - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Verify that Shared Library Directories Have Restrictive Permissions - System-wide shared library directories, which contain are linked to executables -during process load time or run time, are stored in the following directories -by default: -/lib -/lib64 -/usr/lib -/usr/lib64 - -Kernel modules, which can be added to the kernel during runtime, are -stored in /lib/modules. All sub-directories in these directories -should not be group-writable or world-writable. If any file in these -directories is found to be group-writable or world-writable, correct -its permission with the following command: -$ sudo chmod go-w DIR - CCI-001499 - CIP-003-8 R6 - CM-5 - CM-5(6) - CM-5(6).1 - SRG-OS-000259-GPOS-00100 - If the operating system were to allow any user to make changes to software libraries, -then those changes might be implemented without undergoing the appropriate testing -and approvals that are part of a robust change management process. - -This requirement applies to operating systems with software libraries that are accessible -and configurable, as in the case of interpreted languages. Software libraries also include -privileged programs which execute with escalated privileges. Only qualified and authorized -individuals must be allowed to obtain access to information system components for purposes -of initiating changes, including upgrades and modifications. - - - - - -find -H /lib/ -perm /g+w,o+w -type d -exec chmod g-w,o-w {} \; - -find -H /lib64/ -perm /g+w,o+w -type d -exec chmod g-w,o-w {} \; - -find -H /usr/lib/ -perm /g+w,o+w -type d -exec chmod g-w,o-w {} \; - -find -H /usr/lib64/ -perm /g+w,o+w -type d -exec chmod g-w,o-w {} \; - - - name: Set permissions for /lib/ recursively - file: - path: /lib/ - state: directory - recurse: true - mode: g-w,o-w - tags: - - NIST-800-53-CM-5 - - NIST-800-53-CM-5(6) - - NIST-800-53-CM-5(6).1 - - configure_strategy - - dir_permissions_library_dirs - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Set permissions for /lib64/ recursively - file: - path: /lib64/ - state: directory - recurse: true - mode: g-w,o-w - tags: - - NIST-800-53-CM-5 - - NIST-800-53-CM-5(6) - - NIST-800-53-CM-5(6).1 - - configure_strategy - - dir_permissions_library_dirs - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Set permissions for /usr/lib/ recursively - file: - path: /usr/lib/ - state: directory - recurse: true - mode: g-w,o-w - tags: - - NIST-800-53-CM-5 - - NIST-800-53-CM-5(6) - - NIST-800-53-CM-5(6).1 - - configure_strategy - - dir_permissions_library_dirs - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Set permissions for /usr/lib64/ recursively - file: - path: /usr/lib64/ - state: directory - recurse: true - mode: g-w,o-w - tags: - - NIST-800-53-CM-5 - - NIST-800-53-CM-5(6) - - NIST-800-53-CM-5(6).1 - - configure_strategy - - dir_permissions_library_dirs - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Verify that system commands files are group owned by root or a system account - System commands files are stored in the following directories by default: -/bin -/sbin -/usr/bin -/usr/sbin -/usr/local/bin -/usr/local/sbin - -All files in these directories should be owned by the root group, -or a system account. -If the directory, or any file in these directories, is found to be owned -by a group other than root or a a system account correct its ownership -with the following command: -$ sudo chgrp root FILE - CCI-001499 - CM-5(6) - CM-5(6).1 - SRG-OS-000259-GPOS-00100 - If the operating system allows any user to make changes to software -libraries, then those changes might be implemented without undergoing the -appropriate testing and approvals that are part of a robust change management -process. -This requirement applies to operating systems with software libraries -that are accessible and configurable, as in the case of interpreted languages. -Software libraries also include privileged programs which execute with -escalated privileges. Only qualified and authorized individuals must be -allowed to obtain access to information system components for purposes -of initiating changes, including upgrades and modifications. - -for SYSCMDFILES in /bin /sbin /usr/bin /usr/sbin /usr/local/bin /usr/local/sbin -do - find -L $SYSCMDFILES \! -group root -type f -exec chgrp root '{}' \; -done - - - name: Retrieve the system command files and set their group ownership to root - command: find -L {{ item }} ! -group root -type f -exec chgrp root '{}' \; - with_items: - - /bin - - /sbin - - /usr/bin - - /usr/sbin - - /usr/local/bin - - /usr/local/sbin - changed_when: false - failed_when: false - check_mode: false - tags: - - NIST-800-53-CM-5(6) - - NIST-800-53-CM-5(6).1 - - file_groupownership_system_commands_dirs - - medium_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - - - - - - - - - Verify that System Executables Have Root Ownership - System executables are stored in the following directories by default: -/bin -/sbin -/usr/bin -/usr/libexec -/usr/local/bin -/usr/local/sbin -/usr/sbin -All files in these directories should be owned by the root user. -If any file FILE in these directories is found -to be owned by a user other than root, correct its ownership with the -following command: -$ sudo chown root FILE - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - APO01.06 - DSS05.04 - DSS05.07 - DSS06.02 - CCI-001499 - 4.3.3.7.3 - SR 2.1 - SR 5.2 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 - CM-5(6) - CM-5(6).1 - CM-6(a) - AC-6(1) - PR.AC-4 - PR.DS-5 - SRG-OS-000259-GPOS-00100 - System binaries are executed by privileged users as well as system services, -and restrictive permissions are necessary to ensure that their -execution of these programs cannot be co-opted. - find /bin/ \ -/usr/bin/ \ -/usr/local/bin/ \ -/sbin/ \ -/usr/sbin/ \ -/usr/local/sbin/ \ -/usr/libexec \ -\! -user root -execdir chown root {} \; - - - name: Read list of system executables without root ownership - command: find /bin/ /usr/bin/ /usr/local/bin/ /sbin/ /usr/sbin/ /usr/local/sbin/ - /usr/libexec \! -user root - register: no_root_system_executables - changed_when: false - failed_when: false - check_mode: false - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-5(6) - - NIST-800-53-CM-5(6).1 - - NIST-800-53-CM-6(a) - - file_ownership_binary_dirs - - medium_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - -- name: Set ownership to root of system executables - file: - path: '{{ item }}' - owner: root - with_items: '{{ no_root_system_executables.stdout_lines }}' - when: no_root_system_executables.stdout_lines | length > 0 - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-5(6) - - NIST-800-53-CM-5(6).1 - - NIST-800-53-CM-6(a) - - file_ownership_binary_dirs - - medium_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - - - - - - - - - Verify that Shared Library Files Have Root Ownership - System-wide shared library files, which are linked to executables -during process load time or run time, are stored in the following directories -by default: -/lib -/lib64 -/usr/lib -/usr/lib64 - -Kernel modules, which can be added to the kernel during runtime, are also -stored in /lib/modules. All files in these directories should be -owned by the root user. If the directory, or any file in these -directories, is found to be owned by a user other than root correct its -ownership with the following command: -$ sudo chown root FILE - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - APO01.06 - DSS05.04 - DSS05.07 - DSS06.02 - CCI-001499 - 4.3.3.7.3 - SR 2.1 - SR 5.2 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 - CM-5(6) - CM-5(6).1 - CM-6(a) - AC-6(1) - PR.AC-4 - PR.DS-5 - SRG-OS-000259-GPOS-00100 - Files from shared library directories are loaded into the address -space of processes (including privileged ones) or of the kernel itself at -runtime. Proper ownership is necessary to protect the integrity of the system. - -find /lib/ -type f ! -uid 0 -regex '^.*$' -exec chown 0 {} \; - -find /lib64/ -type f ! -uid 0 -regex '^.*$' -exec chown 0 {} \; - -find /usr/lib/ -type f ! -uid 0 -regex '^.*$' -exec chown 0 {} \; - -find /usr/lib64/ -type f ! -uid 0 -regex '^.*$' -exec chown 0 {} \; - - - name: Find /lib/ file(s) matching ^.*$ recursively - command: find -H /lib/ -type f ! -uid 0 -regex "^.*$" - register: files_found - changed_when: false - failed_when: false - check_mode: false - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-5(6) - - NIST-800-53-CM-5(6).1 - - NIST-800-53-CM-6(a) - - configure_strategy - - file_ownership_library_dirs - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Ensure owner on /lib/ file(s) matching ^.*$ - file: - path: '{{ item }}' - owner: '0' - state: file - with_items: - - '{{ files_found.stdout_lines }}' - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-5(6) - - NIST-800-53-CM-5(6).1 - - NIST-800-53-CM-6(a) - - configure_strategy - - file_ownership_library_dirs - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Find /lib64/ file(s) matching ^.*$ recursively - command: find -H /lib64/ -type f ! -uid 0 -regex "^.*$" - register: files_found - changed_when: false - failed_when: false - check_mode: false - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-5(6) - - NIST-800-53-CM-5(6).1 - - NIST-800-53-CM-6(a) - - configure_strategy - - file_ownership_library_dirs - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Ensure owner on /lib64/ file(s) matching ^.*$ - file: - path: '{{ item }}' - owner: '0' - state: file - with_items: - - '{{ files_found.stdout_lines }}' - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-5(6) - - NIST-800-53-CM-5(6).1 - - NIST-800-53-CM-6(a) - - configure_strategy - - file_ownership_library_dirs - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Find /usr/lib/ file(s) matching ^.*$ recursively - command: find -H /usr/lib/ -type f ! -uid 0 -regex "^.*$" - register: files_found - changed_when: false - failed_when: false - check_mode: false - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-5(6) - - NIST-800-53-CM-5(6).1 - - NIST-800-53-CM-6(a) - - configure_strategy - - file_ownership_library_dirs - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Ensure owner on /usr/lib/ file(s) matching ^.*$ - file: - path: '{{ item }}' - owner: '0' - state: file - with_items: - - '{{ files_found.stdout_lines }}' - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-5(6) - - NIST-800-53-CM-5(6).1 - - NIST-800-53-CM-6(a) - - configure_strategy - - file_ownership_library_dirs - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Find /usr/lib64/ file(s) matching ^.*$ recursively - command: find -H /usr/lib64/ -type f ! -uid 0 -regex "^.*$" - register: files_found - changed_when: false - failed_when: false - check_mode: false - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-5(6) - - NIST-800-53-CM-5(6).1 - - NIST-800-53-CM-6(a) - - configure_strategy - - file_ownership_library_dirs - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Ensure owner on /usr/lib64/ file(s) matching ^.*$ - file: - path: '{{ item }}' - owner: '0' - state: file - with_items: - - '{{ files_found.stdout_lines }}' - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-5(6) - - NIST-800-53-CM-5(6).1 - - NIST-800-53-CM-6(a) - - configure_strategy - - file_ownership_library_dirs - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Verify that System Executables Have Restrictive Permissions - System executables are stored in the following directories by default: -/bin -/sbin -/usr/bin -/usr/libexec -/usr/local/bin -/usr/local/sbin -/usr/sbin -All files in these directories should not be group-writable or world-writable. -If any file FILE in these directories is found -to be group-writable or world-writable, correct its permission with the -following command: -$ sudo chmod go-w FILE - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - APO01.06 - DSS05.04 - DSS05.07 - DSS06.02 - CCI-001499 - 4.3.3.7.3 - SR 2.1 - SR 5.2 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 - CM-5(6) - CM-5(6).1 - CM-6(a) - AC-6(1) - PR.AC-4 - PR.DS-5 - SRG-OS-000259-GPOS-00100 - System binaries are executed by privileged users, as well as system services, -and restrictive permissions are necessary to ensure execution of these programs -cannot be co-opted. - DIRS="/bin /usr/bin /usr/local/bin /sbin /usr/sbin /usr/local/sbin /usr/libexec" -for dirPath in $DIRS; do - find "$dirPath" -perm /022 -exec chmod go-w '{}' \; -done - - - name: Read list of world and group writable system executables - ansible.builtin.command: find /bin /usr/bin /usr/local/bin /sbin /usr/sbin /usr/local/sbin - /usr/libexec -perm /022 -type f - register: world_writable_library_files - changed_when: false - failed_when: false - check_mode: false - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-5(6) - - NIST-800-53-CM-5(6).1 - - NIST-800-53-CM-6(a) - - file_permissions_binary_dirs - - medium_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - -- name: Remove world/group writability of system executables - ansible.builtin.file: - path: '{{ item }}' - mode: go-w - state: file - with_items: '{{ world_writable_library_files.stdout_lines }}' - when: world_writable_library_files.stdout_lines | length > 0 - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-5(6) - - NIST-800-53-CM-5(6).1 - - NIST-800-53-CM-6(a) - - file_permissions_binary_dirs - - medium_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - - - - - - - - - Verify that Shared Library Files Have Restrictive Permissions - System-wide shared library files, which are linked to executables -during process load time or run time, are stored in the following directories -by default: -/lib -/lib64 -/usr/lib -/usr/lib64 - -Kernel modules, which can be added to the kernel during runtime, are -stored in /lib/modules. All files in these directories -should not be group-writable or world-writable. If any file in these -directories is found to be group-writable or world-writable, correct -its permission with the following command: -$ sudo chmod go-w FILE - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - APO01.06 - DSS05.04 - DSS05.07 - DSS06.02 - CCI-001499 - 4.3.3.7.3 - SR 2.1 - SR 5.2 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 - CM-6(a) - CM-5(6) - CM-5(6).1 - AC-6(1) - PR.AC-4 - PR.DS-5 - SRG-OS-000259-GPOS-00100 - Files from shared library directories are loaded into the address -space of processes (including privileged ones) or of the kernel itself at -runtime. Restrictive permissions are necessary to protect the integrity of the system. - - - - - -find -H /lib/ -perm /g+w,o+w -type f -regex '^.*$' -exec chmod g-w,o-w {} \; - -find -H /lib64/ -perm /g+w,o+w -type f -regex '^.*$' -exec chmod g-w,o-w {} \; - -find -H /usr/lib/ -perm /g+w,o+w -type f -regex '^.*$' -exec chmod g-w,o-w {} \; - -find -H /usr/lib64/ -perm /g+w,o+w -type f -regex '^.*$' -exec chmod g-w,o-w {} \; - - - name: Find /lib/ file(s) recursively - command: find -H /lib/ -perm /g+w,o+w -type f -regex "^.*$" - register: files_found - changed_when: false - failed_when: false - check_mode: false - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-5(6) - - NIST-800-53-CM-5(6).1 - - NIST-800-53-CM-6(a) - - configure_strategy - - file_permissions_library_dirs - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Set permissions for /lib/ file(s) - file: - path: '{{ item }}' - mode: g-w,o-w - state: file - with_items: - - '{{ files_found.stdout_lines }}' - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-5(6) - - NIST-800-53-CM-5(6).1 - - NIST-800-53-CM-6(a) - - configure_strategy - - file_permissions_library_dirs - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Find /lib64/ file(s) recursively - command: find -H /lib64/ -perm /g+w,o+w -type f -regex "^.*$" - register: files_found - changed_when: false - failed_when: false - check_mode: false - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-5(6) - - NIST-800-53-CM-5(6).1 - - NIST-800-53-CM-6(a) - - configure_strategy - - file_permissions_library_dirs - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Set permissions for /lib64/ file(s) - file: - path: '{{ item }}' - mode: g-w,o-w - state: file - with_items: - - '{{ files_found.stdout_lines }}' - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-5(6) - - NIST-800-53-CM-5(6).1 - - NIST-800-53-CM-6(a) - - configure_strategy - - file_permissions_library_dirs - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Find /usr/lib/ file(s) recursively - command: find -H /usr/lib/ -perm /g+w,o+w -type f -regex "^.*$" - register: files_found - changed_when: false - failed_when: false - check_mode: false - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-5(6) - - NIST-800-53-CM-5(6).1 - - NIST-800-53-CM-6(a) - - configure_strategy - - file_permissions_library_dirs - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Set permissions for /usr/lib/ file(s) - file: - path: '{{ item }}' - mode: g-w,o-w - state: file - with_items: - - '{{ files_found.stdout_lines }}' - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-5(6) - - NIST-800-53-CM-5(6).1 - - NIST-800-53-CM-6(a) - - configure_strategy - - file_permissions_library_dirs - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Find /usr/lib64/ file(s) recursively - command: find -H /usr/lib64/ -perm /g+w,o+w -type f -regex "^.*$" - register: files_found - changed_when: false - failed_when: false - check_mode: false - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-5(6) - - NIST-800-53-CM-5(6).1 - - NIST-800-53-CM-6(a) - - configure_strategy - - file_permissions_library_dirs - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Set permissions for /usr/lib64/ file(s) - file: - path: '{{ item }}' - mode: g-w,o-w - state: file - with_items: - - '{{ files_found.stdout_lines }}' - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-5(6) - - NIST-800-53-CM-5(6).1 - - NIST-800-53-CM-6(a) - - configure_strategy - - file_permissions_library_dirs - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Verify the system-wide library files in directories -"/lib", "/lib64", "/usr/lib/" and "/usr/lib64" are group-owned by root. - System-wide library files are stored in the following directories -by default: -/lib -/lib64 -/usr/lib -/usr/lib64 - -All system-wide shared library files should be protected from unauthorised -access. If any of these files is not group-owned by root, correct its group-owner with -the following command: -$ sudo chgrp root FILE - CCI-001499 - CM-5(6) - CM-5(6).1 - SRG-OS-000259-GPOS-00100 - If the operating system were to allow any user to make changes to software libraries, -then those changes might be implemented without undergoing the appropriate testing and -approvals that are part of a robust change management process. - -This requirement applies to operating systems with software libraries that are -accessible and configurable, as in the case of interpreted languages. Software libraries -also include privileged programs which execute with escalated privileges. Only qualified -and authorized individuals must be allowed to obtain access to information system components -for purposes of initiating changes, including upgrades and modifications. - -find /lib/ -type f ! -group 0 -regex '^.*$' -exec chgrp 0 {} \; - -find /lib64/ -type f ! -group 0 -regex '^.*$' -exec chgrp 0 {} \; - -find /usr/lib/ -type f ! -group 0 -regex '^.*$' -exec chgrp 0 {} \; - -find /usr/lib64/ -type f ! -group 0 -regex '^.*$' -exec chgrp 0 {} \; - - - name: Find /lib/ file(s) matching ^.*$ recursively - command: find -H /lib/ -type f ! -group 0 -regex "^.*$" - register: files_found - changed_when: false - failed_when: false - check_mode: false - tags: - - NIST-800-53-CM-5(6) - - NIST-800-53-CM-5(6).1 - - configure_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - root_permissions_syslibrary_files - -- name: Ensure group owner on /lib/ file(s) matching ^.*$ - file: - path: '{{ item }}' - group: '0' - state: file - with_items: - - '{{ files_found.stdout_lines }}' - tags: - - NIST-800-53-CM-5(6) - - NIST-800-53-CM-5(6).1 - - configure_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - root_permissions_syslibrary_files - -- name: Find /lib64/ file(s) matching ^.*$ recursively - command: find -H /lib64/ -type f ! -group 0 -regex "^.*$" - register: files_found - changed_when: false - failed_when: false - check_mode: false - tags: - - NIST-800-53-CM-5(6) - - NIST-800-53-CM-5(6).1 - - configure_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - root_permissions_syslibrary_files - -- name: Ensure group owner on /lib64/ file(s) matching ^.*$ - file: - path: '{{ item }}' - group: '0' - state: file - with_items: - - '{{ files_found.stdout_lines }}' - tags: - - NIST-800-53-CM-5(6) - - NIST-800-53-CM-5(6).1 - - configure_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - root_permissions_syslibrary_files - -- name: Find /usr/lib/ file(s) matching ^.*$ recursively - command: find -H /usr/lib/ -type f ! -group 0 -regex "^.*$" - register: files_found - changed_when: false - failed_when: false - check_mode: false - tags: - - NIST-800-53-CM-5(6) - - NIST-800-53-CM-5(6).1 - - configure_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - root_permissions_syslibrary_files - -- name: Ensure group owner on /usr/lib/ file(s) matching ^.*$ - file: - path: '{{ item }}' - group: '0' - state: file - with_items: - - '{{ files_found.stdout_lines }}' - tags: - - NIST-800-53-CM-5(6) - - NIST-800-53-CM-5(6).1 - - configure_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - root_permissions_syslibrary_files - -- name: Find /usr/lib64/ file(s) matching ^.*$ recursively - command: find -H /usr/lib64/ -type f ! -group 0 -regex "^.*$" - register: files_found - changed_when: false - failed_when: false - check_mode: false - tags: - - NIST-800-53-CM-5(6) - - NIST-800-53-CM-5(6).1 - - configure_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - root_permissions_syslibrary_files - -- name: Ensure group owner on /usr/lib64/ file(s) matching ^.*$ - file: - path: '{{ item }}' - group: '0' - state: file - with_items: - - '{{ files_found.stdout_lines }}' - tags: - - NIST-800-53-CM-5(6) - - NIST-800-53-CM-5(6).1 - - configure_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - root_permissions_syslibrary_files - - - - - - - - - - - - Restrict Dynamic Mounting and Unmounting of -Filesystems - Linux includes a number of facilities for the automated addition -and removal of filesystems on a running system. These facilities may be -necessary in many environments, but this capability also carries some risk -- whether direct -risk from allowing users to introduce arbitrary filesystems, -or risk that software flaws in the automated mount facility itself could -allow an attacker to compromise the system. - -This command can be used to list the types of filesystems that are -available to the currently executing kernel: -$ find /lib/modules/`uname -r`/kernel/fs -type f -name '*.ko' -If these filesystems are not required then they can be explicitly disabled -in a configuratio file in /etc/modprobe.d. - - Disable the Automounter - The autofs daemon mounts and unmounts filesystems, such as user -home directories shared via NFS, on demand. In addition, autofs can be used to handle -removable media, and the default configuration provides the cdrom device as /misc/cd. -However, this method of providing access to removable media is not common, so autofs -can almost always be disabled if NFS is not in use. Even if NFS is required, it may be -possible to configure filesystem mounts statically by editing /etc/fstab -rather than relying on the automounter. - - -The autofs service can be disabled with the following command: -$ sudo systemctl mask --now autofs.service - 1 - 12 - 15 - 16 - 5 - APO13.01 - DSS01.04 - DSS05.03 - DSS05.04 - DSS05.05 - DSS05.07 - DSS05.10 - DSS06.03 - DSS06.10 - 3.4.6 - CCI-000366 - CCI-000778 - CCI-001958 - 164.308(a)(3)(i) - 164.308(a)(3)(ii)(A) - 164.310(d)(1) - 164.310(d)(2) - 164.312(a)(1) - 164.312(a)(2)(iv) - 164.312(b) - 4.3.3.2.2 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.2 - 4.3.3.7.4 - SR 1.1 - SR 1.10 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.6 - A.11.2.6 - A.13.1.1 - A.13.2.1 - A.18.1.4 - A.6.2.1 - A.6.2.2 - A.7.1.1 - A.9.2.1 - A.9.2.2 - A.9.2.3 - A.9.2.4 - A.9.2.6 - A.9.3.1 - A.9.4.2 - A.9.4.3 - CM-7(a) - CM-7(b) - CM-6(a) - MP-7 - PR.AC-1 - PR.AC-3 - PR.AC-6 - PR.AC-7 - SRG-OS-000114-GPOS-00059 - SRG-OS-000378-GPOS-00163 - SRG-OS-000480-GPOS-00227 - Disabling the automounter permits the administrator to -statically control filesystem mounting through /etc/fstab. - -Additionally, automatically mounting filesystems permits easy introduction of -unknown devices, thereby facilitating malicious activity. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -SYSTEMCTL_EXEC='/usr/bin/systemctl' -"$SYSTEMCTL_EXEC" stop 'autofs.service' -"$SYSTEMCTL_EXEC" disable 'autofs.service' -"$SYSTEMCTL_EXEC" mask 'autofs.service' -# Disable socket activation if we have a unit file for it -if "$SYSTEMCTL_EXEC" -q list-unit-files autofs.socket; then - "$SYSTEMCTL_EXEC" stop 'autofs.socket' - "$SYSTEMCTL_EXEC" mask 'autofs.socket' -fi -# The service may not be running because it has been started and failed, -# so let's reset the state so OVAL checks pass. -# Service should be 'inactive', not 'failed' after reboot though. -"$SYSTEMCTL_EXEC" reset-failed 'autofs.service' || true - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Block Disable service autofs - block: - - - name: Disable service autofs - block: - - - name: Disable service autofs - systemd: - name: autofs.service - enabled: 'no' - state: stopped - masked: 'yes' - rescue: - - - name: Intentionally ignored previous 'Disable service autofs' failure, service - was already disabled - meta: noop - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.4.6 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_autofs_disabled - -- name: Unit Socket Exists - autofs.socket - command: systemctl -q list-unit-files autofs.socket - register: socket_file_exists - changed_when: false - failed_when: socket_file_exists.rc not in [0, 1] - check_mode: false - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.4.6 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_autofs_disabled - -- name: Disable socket autofs - systemd: - name: autofs.socket - enabled: 'no' - state: stopped - masked: 'yes' - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - socket_file_exists.stdout_lines is search("autofs.socket",multiline=True) - tags: - - NIST-800-171-3.4.6 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_autofs_disabled - - include disable_autofs - -class disable_autofs { - service {'autofs': - enable => false, - ensure => 'stopped', - } -} - - -[customizations.services] -disabled = ["autofs"] - - - - - - - - - - Disable Mounting of cramfs - -To configure the system to prevent the cramfs -kernel module from being loaded, add the following line to the file /etc/modprobe.d/cramfs.conf: -install cramfs /bin/true - -To configure the system to prevent the cramfs from being used, -add the following line to file /etc/modprobe.d/cramfs.conf: -blacklist cramfs - -This effectively prevents usage of this uncommon filesystem. - -The cramfs filesystem type is a compressed read-only -Linux filesystem embedded in small footprint systems. A -cramfs image can be used without having to first -decompress the image. - 11 - 14 - 3 - 9 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS05.02 - DSS05.05 - DSS06.06 - 3.4.6 - CCI-000381 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 7.6 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.9.1.2 - CM-7(a) - CM-7(b) - CM-6(a) - PR.IP-1 - PR.PT-3 - SRG-OS-000095-GPOS-00049 - Removing support for unneeded filesystem types reduces the local attack surface -of the server. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -if LC_ALL=C grep -q -m 1 "^install cramfs" /etc/modprobe.d/cramfs.conf ; then - - sed -i 's#^install cramfs.*#install cramfs /bin/true#g' /etc/modprobe.d/cramfs.conf -else - echo -e "\n# Disable per security requirements" >> /etc/modprobe.d/cramfs.conf - echo "install cramfs /bin/true" >> /etc/modprobe.d/cramfs.conf -fi - -if ! LC_ALL=C grep -q -m 1 "^blacklist cramfs$" /etc/modprobe.d/cramfs.conf ; then - echo "blacklist cramfs" >> /etc/modprobe.d/cramfs.conf -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Ensure kernel module 'cramfs' is disabled - lineinfile: - create: true - dest: /etc/modprobe.d/cramfs.conf - regexp: install\s+cramfs - line: install cramfs /bin/true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.4.6 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - kernel_module_cramfs_disabled - - low_complexity - - low_severity - - medium_disruption - - reboot_required - -- name: Ensure kernel module 'cramfs' is blacklisted - lineinfile: - create: true - dest: /etc/modprobe.d/cramfs.conf - regexp: ^blacklist cramfs$ - line: blacklist cramfs - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.4.6 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - kernel_module_cramfs_disabled - - low_complexity - - low_severity - - medium_disruption - - reboot_required - - - - - - - - - - Disable Modprobe Loading of USB Storage Driver - To prevent USB storage devices from being used, configure the kernel module loading system -to prevent automatic loading of the USB storage driver. - -To configure the system to prevent the usb-storage -kernel module from being loaded, add the following line to the file /etc/modprobe.d/usb-storage.conf: -install usb-storage /bin/true - -To configure the system to prevent the usb-storage from being used, -add the following line to file /etc/modprobe.d/usb-storage.conf: -blacklist usb-storage - -This will prevent the modprobe program from loading the usb-storage -module, but will not prevent an administrator (or another program) from using the -insmod program to load the module manually. - 1 - 12 - 15 - 16 - 5 - APO13.01 - DSS01.04 - DSS05.03 - DSS05.04 - DSS05.05 - DSS05.07 - DSS05.10 - DSS06.03 - DSS06.10 - 3.1.21 - CCI-000366 - CCI-000778 - CCI-001958 - 164.308(a)(3)(i) - 164.308(a)(3)(ii)(A) - 164.310(d)(1) - 164.310(d)(2) - 164.312(a)(1) - 164.312(a)(2)(iv) - 164.312(b) - 4.3.3.2.2 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.2 - 4.3.3.7.4 - SR 1.1 - SR 1.10 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.6 - A.11.2.6 - A.13.1.1 - A.13.2.1 - A.18.1.4 - A.6.2.1 - A.6.2.2 - A.7.1.1 - A.9.2.1 - A.9.2.2 - A.9.2.3 - A.9.2.4 - A.9.2.6 - A.9.3.1 - A.9.4.2 - A.9.4.3 - CM-7(a) - CM-7(b) - CM-6(a) - MP-7 - PR.AC-1 - PR.AC-3 - PR.AC-6 - PR.AC-7 - SRG-OS-000114-GPOS-00059 - SRG-OS-000378-GPOS-00163 - SRG-OS-000480-GPOS-00227 - USB storage devices such as thumb drives can be used to introduce -malicious software. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -if LC_ALL=C grep -q -m 1 "^install usb-storage" /etc/modprobe.d/usb-storage.conf ; then - - sed -i 's#^install usb-storage.*#install usb-storage /bin/true#g' /etc/modprobe.d/usb-storage.conf -else - echo -e "\n# Disable per security requirements" >> /etc/modprobe.d/usb-storage.conf - echo "install usb-storage /bin/true" >> /etc/modprobe.d/usb-storage.conf -fi - -if ! LC_ALL=C grep -q -m 1 "^blacklist usb-storage$" /etc/modprobe.d/usb-storage.conf ; then - echo "blacklist usb-storage" >> /etc/modprobe.d/usb-storage.conf -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Ensure kernel module 'usb-storage' is disabled - lineinfile: - create: true - dest: /etc/modprobe.d/usb-storage.conf - regexp: install\s+usb-storage - line: install usb-storage /bin/true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.21 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - disable_strategy - - kernel_module_usb-storage_disabled - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - -- name: Ensure kernel module 'usb-storage' is blacklisted - lineinfile: - create: true - dest: /etc/modprobe.d/usb-storage.conf - regexp: ^blacklist usb-storage$ - line: blacklist usb-storage - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.21 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - disable_strategy - - kernel_module_usb-storage_disabled - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - - - - - - - - - - Restrict Partition Mount Options - System partitions can be mounted with certain options -that limit what files on those partitions can do. These options -are set in the /etc/fstab configuration file, and can be -used to make certain types of malicious behavior more difficult. - - Value for hidepid option - The hidepid mount option is applicable to /proc and is used to control who can access -the information in /proc/[pid] directories. The option can have one of the following -values: -0: Everybody may access all /proc/[pid] directories. -1: Users may not access files and subdirectories inside any /proc/[pid] directories - but their own. The /proc/[pid] directories themselves remain visible. -2: Same as for mode 1, but in addition the /proc/[pid] directories belonging to other - users become invisible. - 0 - 1 - 2 - 2 - - - Removable Partition - This value is used by the checks mount_option_nodev_removable_partitions, mount_option_nodev_removable_partitions, -and mount_option_nodev_removable_partitions to ensure that the correct mount options are set on partitions mounted from -removable media such as CD-ROMs, USB keys, and floppy drives. This value should be modified to reflect any removable -partitions that are required on the local system. - /dev/cdrom - - - Add nodev Option to /boot - The nodev mount option can be used to prevent device files from -being created in /boot. -Legitimate character and block devices should exist only in -the /dev directory on the root partition or within chroot -jails built for system services. -Add the nodev option to the fourth column of -/etc/fstab for the line which controls mounting of -/boot. - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 - CM-7(a) - CM-7(b) - CM-6(a) - AC-6 - AC-6(1) - MP-7 - PR.IP-1 - PR.PT-2 - PR.PT-3 - SRG-OS-000368-GPOS-00154 - The only legitimate location for device files is the /dev directory -located on the root partition. The only exception to this is chroot jails. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -function perform_remediation { - - mount_point_match_regexp="$(printf "[^#].*[[:space:]]%s[[:space:]]" "/boot")" - - grep "$mount_point_match_regexp" -q /etc/fstab \ - || { echo "The mount point '/boot' is not even in /etc/fstab, so we can't set up mount options" >&2; - echo "Not remediating, because there is no record of /boot in /etc/fstab" >&2; return 1; } - - - - mount_point_match_regexp="$(printf "[^#].*[[:space:]]%s[[:space:]]" /boot)" - - # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab - if ! grep "$mount_point_match_regexp" /etc/fstab; then - # runtime opts without some automatic kernel/userspace-added defaults - previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 | awk '{print $4}' \ - | sed -E "s/(rw|defaults|seclabel|nodev)(,|$)//g;s/,$//") - [ "$previous_mount_opts" ] && previous_mount_opts+="," - # In iso9660 filesystems mtab could describe a "blocksize" value, this should be reflected in - # fstab as "block". The next variable is to satisfy shellcheck SC2050. - fs_type="" - if [ "$fs_type" == "iso9660" ] ; then - previous_mount_opts=$(sed 's/blocksize=/block=/' <<< "$previous_mount_opts") - fi - echo " /boot defaults,${previous_mount_opts}nodev 0 0" >> /etc/fstab - # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it - elif ! grep "$mount_point_match_regexp" /etc/fstab | grep "nodev"; then - previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}') - sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,nodev|" /etc/fstab - fi - - - if mkdir -p "/boot"; then - if mountpoint -q "/boot"; then - mount -o remount --target "/boot" - fi - fi -} - -perform_remediation - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: 'Add nodev Option to /boot: Check information associated to mountpoint' - command: findmnt --fstab '/boot' - register: device_name - failed_when: device_name.rc > 1 - changed_when: false - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_boot_nodev - - no_reboot_needed - -- name: 'Add nodev Option to /boot: Create mount_info dictionary variable' - set_fact: - mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' - with_together: - - '{{ device_name.stdout_lines[0].split() | list | lower }}' - - '{{ device_name.stdout_lines[1].split() | list }}' - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - device_name.stdout is defined and device_name.stdout_lines is defined - - (device_name.stdout | length > 0) - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_boot_nodev - - no_reboot_needed - -- name: 'Add nodev Option to /boot: If /boot not mounted, craft mount_info manually' - set_fact: - mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' - with_together: - - - target - - source - - fstype - - options - - - /boot - - '' - - '' - - defaults - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - ("--fstab" | length == 0) - - (device_name.stdout | length == 0) - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_boot_nodev - - no_reboot_needed - -- name: 'Add nodev Option to /boot: Make sure nodev option is part of the to /boot - options' - set_fact: - mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',nodev'' - }) }}' - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - mount_info is defined and "nodev" not in mount_info.options - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_boot_nodev - - no_reboot_needed - -- name: 'Add nodev Option to /boot: Ensure /boot is mounted with nodev option' - mount: - path: /boot - src: '{{ mount_info.source }}' - opts: '{{ mount_info.options }}' - state: mounted - fstype: '{{ mount_info.fstype }}' - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" - | length == 0) - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_boot_nodev - - no_reboot_needed - - -part /boot --mountoptions="nodev" - - - - - - - - - - Add noexec Option to /boot - The noexec mount option can be used to prevent binaries from being -executed out of /boot. -Add the noexec option to the fourth column of -/etc/fstab for the line which controls mounting of -/boot. - BP28(R12) - The /boot partition contains the kernel and the bootloader. No -binaries should be executed from this partition after the booting process -finishes. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -function perform_remediation { - - mount_point_match_regexp="$(printf "[^#].*[[:space:]]%s[[:space:]]" "/boot")" - - grep "$mount_point_match_regexp" -q /etc/fstab \ - || { echo "The mount point '/boot' is not even in /etc/fstab, so we can't set up mount options" >&2; - echo "Not remediating, because there is no record of /boot in /etc/fstab" >&2; return 1; } - - - - mount_point_match_regexp="$(printf "[^#].*[[:space:]]%s[[:space:]]" /boot)" - - # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab - if ! grep "$mount_point_match_regexp" /etc/fstab; then - # runtime opts without some automatic kernel/userspace-added defaults - previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 | awk '{print $4}' \ - | sed -E "s/(rw|defaults|seclabel|noexec)(,|$)//g;s/,$//") - [ "$previous_mount_opts" ] && previous_mount_opts+="," - # In iso9660 filesystems mtab could describe a "blocksize" value, this should be reflected in - # fstab as "block". The next variable is to satisfy shellcheck SC2050. - fs_type="" - if [ "$fs_type" == "iso9660" ] ; then - previous_mount_opts=$(sed 's/blocksize=/block=/' <<< "$previous_mount_opts") - fi - echo " /boot defaults,${previous_mount_opts}noexec 0 0" >> /etc/fstab - # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it - elif ! grep "$mount_point_match_regexp" /etc/fstab | grep "noexec"; then - previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}') - sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,noexec|" /etc/fstab - fi - - - if mkdir -p "/boot"; then - if mountpoint -q "/boot"; then - mount -o remount --target "/boot" - fi - fi -} - -perform_remediation - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: 'Add noexec Option to /boot: Check information associated to mountpoint' - command: findmnt --fstab '/boot' - register: device_name - failed_when: device_name.rc > 1 - changed_when: false - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_boot_noexec - - no_reboot_needed - -- name: 'Add noexec Option to /boot: Create mount_info dictionary variable' - set_fact: - mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' - with_together: - - '{{ device_name.stdout_lines[0].split() | list | lower }}' - - '{{ device_name.stdout_lines[1].split() | list }}' - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - device_name.stdout is defined and device_name.stdout_lines is defined - - (device_name.stdout | length > 0) - tags: - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_boot_noexec - - no_reboot_needed - -- name: 'Add noexec Option to /boot: If /boot not mounted, craft mount_info manually' - set_fact: - mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' - with_together: - - - target - - source - - fstype - - options - - - /boot - - '' - - '' - - defaults - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - ("--fstab" | length == 0) - - (device_name.stdout | length == 0) - tags: - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_boot_noexec - - no_reboot_needed - -- name: 'Add noexec Option to /boot: Make sure noexec option is part of the to /boot - options' - set_fact: - mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',noexec'' - }) }}' - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - mount_info is defined and "noexec" not in mount_info.options - tags: - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_boot_noexec - - no_reboot_needed - -- name: 'Add noexec Option to /boot: Ensure /boot is mounted with noexec option' - mount: - path: /boot - src: '{{ mount_info.source }}' - opts: '{{ mount_info.options }}' - state: mounted - fstype: '{{ mount_info.fstype }}' - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" - | length == 0) - tags: - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_boot_noexec - - no_reboot_needed - - -part /boot --mountoptions="noexec" - - - - - - - - - - Add nosuid Option to /boot - The nosuid mount option can be used to prevent -execution of setuid programs in /boot. The SUID and SGID permissions -should not be required on the boot partition. -Add the nosuid option to the fourth column of -/etc/fstab for the line which controls mounting of -/boot. - BP28(R12) - CCI-000366 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 - CM-7(a) - CM-7(b) - CM-6(a) - AC-6 - AC-6(1) - MP-7 - PR.IP-1 - PR.PT-2 - PR.PT-3 - SRG-OS-000368-GPOS-00154 - SRG-OS-000480-GPOS-00227 - The presence of SUID and SGID executables should be tightly controlled. Users -should not be able to execute SUID or SGID binaries from boot partitions. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -function perform_remediation { - - mount_point_match_regexp="$(printf "[^#].*[[:space:]]%s[[:space:]]" "/boot")" - - grep "$mount_point_match_regexp" -q /etc/fstab \ - || { echo "The mount point '/boot' is not even in /etc/fstab, so we can't set up mount options" >&2; - echo "Not remediating, because there is no record of /boot in /etc/fstab" >&2; return 1; } - - - - mount_point_match_regexp="$(printf "[^#].*[[:space:]]%s[[:space:]]" /boot)" - - # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab - if ! grep "$mount_point_match_regexp" /etc/fstab; then - # runtime opts without some automatic kernel/userspace-added defaults - previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 | awk '{print $4}' \ - | sed -E "s/(rw|defaults|seclabel|nosuid)(,|$)//g;s/,$//") - [ "$previous_mount_opts" ] && previous_mount_opts+="," - # In iso9660 filesystems mtab could describe a "blocksize" value, this should be reflected in - # fstab as "block". The next variable is to satisfy shellcheck SC2050. - fs_type="" - if [ "$fs_type" == "iso9660" ] ; then - previous_mount_opts=$(sed 's/blocksize=/block=/' <<< "$previous_mount_opts") - fi - echo " /boot defaults,${previous_mount_opts}nosuid 0 0" >> /etc/fstab - # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it - elif ! grep "$mount_point_match_regexp" /etc/fstab | grep "nosuid"; then - previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}') - sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,nosuid|" /etc/fstab - fi - - - if mkdir -p "/boot"; then - if mountpoint -q "/boot"; then - mount -o remount --target "/boot" - fi - fi -} - -perform_remediation - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: 'Add nosuid Option to /boot: Check information associated to mountpoint' - command: findmnt --fstab '/boot' - register: device_name - failed_when: device_name.rc > 1 - changed_when: false - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_boot_nosuid - - no_reboot_needed - -- name: 'Add nosuid Option to /boot: Create mount_info dictionary variable' - set_fact: - mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' - with_together: - - '{{ device_name.stdout_lines[0].split() | list | lower }}' - - '{{ device_name.stdout_lines[1].split() | list }}' - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - device_name.stdout is defined and device_name.stdout_lines is defined - - (device_name.stdout | length > 0) - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_boot_nosuid - - no_reboot_needed - -- name: 'Add nosuid Option to /boot: If /boot not mounted, craft mount_info manually' - set_fact: - mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' - with_together: - - - target - - source - - fstype - - options - - - /boot - - '' - - '' - - defaults - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - ("--fstab" | length == 0) - - (device_name.stdout | length == 0) - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_boot_nosuid - - no_reboot_needed - -- name: 'Add nosuid Option to /boot: Make sure nosuid option is part of the to /boot - options' - set_fact: - mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',nosuid'' - }) }}' - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - mount_info is defined and "nosuid" not in mount_info.options - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_boot_nosuid - - no_reboot_needed - -- name: 'Add nosuid Option to /boot: Ensure /boot is mounted with nosuid option' - mount: - path: /boot - src: '{{ mount_info.source }}' - opts: '{{ mount_info.options }}' - state: mounted - fstype: '{{ mount_info.fstype }}' - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" - | length == 0) - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_boot_nosuid - - no_reboot_needed - - -part /boot --mountoptions="nosuid" - - - - - - - - - - Add nodev Option to /dev/shm - The nodev mount option can be used to prevent creation of device -files in /dev/shm. Legitimate character and block devices should -not exist within temporary directories like /dev/shm. -Add the nodev option to the fourth column of -/etc/fstab for the line which controls mounting of -/dev/shm. - 11 - 13 - 14 - 3 - 8 - 9 - APO13.01 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS05.02 - DSS05.05 - DSS05.06 - DSS06.06 - CCI-001764 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 7.6 - A.11.2.9 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.8.2.1 - A.8.2.2 - A.8.2.3 - A.8.3.1 - A.8.3.3 - A.9.1.2 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 - CM-7(a) - CM-7(b) - CM-6(a) - AC-6 - AC-6(1) - MP-7 - PR.IP-1 - PR.PT-2 - PR.PT-3 - SRG-OS-000368-GPOS-00154 - The only legitimate location for device files is the /dev directory -located on the root partition. The only exception to this is chroot jails. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -function perform_remediation { - - - - mount_point_match_regexp="$(printf "[^#].*[[:space:]]%s[[:space:]]" /dev/shm)" - - # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab - if ! grep "$mount_point_match_regexp" /etc/fstab; then - # runtime opts without some automatic kernel/userspace-added defaults - previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 | awk '{print $4}' \ - | sed -E "s/(rw|defaults|seclabel|nodev)(,|$)//g;s/,$//") - [ "$previous_mount_opts" ] && previous_mount_opts+="," - # In iso9660 filesystems mtab could describe a "blocksize" value, this should be reflected in - # fstab as "block". The next variable is to satisfy shellcheck SC2050. - fs_type="tmpfs" - if [ "$fs_type" == "iso9660" ] ; then - previous_mount_opts=$(sed 's/blocksize=/block=/' <<< "$previous_mount_opts") - fi - echo "tmpfs /dev/shm tmpfs defaults,${previous_mount_opts}nodev 0 0" >> /etc/fstab - # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it - elif ! grep "$mount_point_match_regexp" /etc/fstab | grep "nodev"; then - previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}') - sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,nodev|" /etc/fstab - fi - - - if mkdir -p "/dev/shm"; then - if mountpoint -q "/dev/shm"; then - mount -o remount --target "/dev/shm" - fi - fi -} - -perform_remediation - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: 'Add nodev Option to /dev/shm: Check information associated to mountpoint' - command: findmnt '/dev/shm' - register: device_name - failed_when: device_name.rc > 1 - changed_when: false - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_dev_shm_nodev - - no_reboot_needed - -- name: 'Add nodev Option to /dev/shm: Create mount_info dictionary variable' - set_fact: - mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' - with_together: - - '{{ device_name.stdout_lines[0].split() | list | lower }}' - - '{{ device_name.stdout_lines[1].split() | list }}' - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - device_name.stdout is defined and device_name.stdout_lines is defined - - (device_name.stdout | length > 0) - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_dev_shm_nodev - - no_reboot_needed - -- name: 'Add nodev Option to /dev/shm: If /dev/shm not mounted, craft mount_info manually' - set_fact: - mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' - with_together: - - - target - - source - - fstype - - options - - - /dev/shm - - tmpfs - - tmpfs - - defaults - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - ("" | length == 0) - - (device_name.stdout | length == 0) - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_dev_shm_nodev - - no_reboot_needed - -- name: 'Add nodev Option to /dev/shm: Make sure nodev option is part of the to /dev/shm - options' - set_fact: - mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',nodev'' - }) }}' - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - mount_info is defined and "nodev" not in mount_info.options - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_dev_shm_nodev - - no_reboot_needed - -- name: 'Add nodev Option to /dev/shm: Ensure /dev/shm is mounted with nodev option' - mount: - path: /dev/shm - src: '{{ mount_info.source }}' - opts: '{{ mount_info.options }}' - state: mounted - fstype: '{{ mount_info.fstype }}' - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("" | - length == 0) - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_dev_shm_nodev - - no_reboot_needed - - - - - - - - - - Add noexec Option to /dev/shm - The noexec mount option can be used to prevent binaries -from being executed out of /dev/shm. -It can be dangerous to allow the execution of binaries -from world-writable temporary storage directories such as /dev/shm. -Add the noexec option to the fourth column of -/etc/fstab for the line which controls mounting of -/dev/shm. - 11 - 13 - 14 - 3 - 8 - 9 - APO13.01 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS05.02 - DSS05.05 - DSS05.06 - DSS06.06 - CCI-001764 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 7.6 - A.11.2.9 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.8.2.1 - A.8.2.2 - A.8.2.3 - A.8.3.1 - A.8.3.3 - A.9.1.2 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 - CM-7(a) - CM-7(b) - CM-6(a) - AC-6 - AC-6(1) - MP-7 - PR.IP-1 - PR.PT-2 - PR.PT-3 - SRG-OS-000368-GPOS-00154 - Allowing users to execute binaries from world-writable directories -such as /dev/shm can expose the system to potential compromise. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -function perform_remediation { - - - - mount_point_match_regexp="$(printf "[^#].*[[:space:]]%s[[:space:]]" /dev/shm)" - - # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab - if ! grep "$mount_point_match_regexp" /etc/fstab; then - # runtime opts without some automatic kernel/userspace-added defaults - previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 | awk '{print $4}' \ - | sed -E "s/(rw|defaults|seclabel|noexec)(,|$)//g;s/,$//") - [ "$previous_mount_opts" ] && previous_mount_opts+="," - # In iso9660 filesystems mtab could describe a "blocksize" value, this should be reflected in - # fstab as "block". The next variable is to satisfy shellcheck SC2050. - fs_type="tmpfs" - if [ "$fs_type" == "iso9660" ] ; then - previous_mount_opts=$(sed 's/blocksize=/block=/' <<< "$previous_mount_opts") - fi - echo "tmpfs /dev/shm tmpfs defaults,${previous_mount_opts}noexec 0 0" >> /etc/fstab - # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it - elif ! grep "$mount_point_match_regexp" /etc/fstab | grep "noexec"; then - previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}') - sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,noexec|" /etc/fstab - fi - - - if mkdir -p "/dev/shm"; then - if mountpoint -q "/dev/shm"; then - mount -o remount --target "/dev/shm" - fi - fi -} - -perform_remediation - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: 'Add noexec Option to /dev/shm: Check information associated to mountpoint' - command: findmnt '/dev/shm' - register: device_name - failed_when: device_name.rc > 1 - changed_when: false - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_dev_shm_noexec - - no_reboot_needed - -- name: 'Add noexec Option to /dev/shm: Create mount_info dictionary variable' - set_fact: - mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' - with_together: - - '{{ device_name.stdout_lines[0].split() | list | lower }}' - - '{{ device_name.stdout_lines[1].split() | list }}' - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - device_name.stdout is defined and device_name.stdout_lines is defined - - (device_name.stdout | length > 0) - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_dev_shm_noexec - - no_reboot_needed - -- name: 'Add noexec Option to /dev/shm: If /dev/shm not mounted, craft mount_info - manually' - set_fact: - mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' - with_together: - - - target - - source - - fstype - - options - - - /dev/shm - - tmpfs - - tmpfs - - defaults - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - ("" | length == 0) - - (device_name.stdout | length == 0) - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_dev_shm_noexec - - no_reboot_needed - -- name: 'Add noexec Option to /dev/shm: Make sure noexec option is part of the to - /dev/shm options' - set_fact: - mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',noexec'' - }) }}' - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - mount_info is defined and "noexec" not in mount_info.options - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_dev_shm_noexec - - no_reboot_needed - -- name: 'Add noexec Option to /dev/shm: Ensure /dev/shm is mounted with noexec option' - mount: - path: /dev/shm - src: '{{ mount_info.source }}' - opts: '{{ mount_info.options }}' - state: mounted - fstype: '{{ mount_info.fstype }}' - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("" | - length == 0) - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_dev_shm_noexec - - no_reboot_needed - - - - - - - - - - Add nosuid Option to /dev/shm - The nosuid mount option can be used to prevent execution -of setuid programs in /dev/shm. The SUID and SGID permissions should not -be required in these world-writable directories. -Add the nosuid option to the fourth column of -/etc/fstab for the line which controls mounting of -/dev/shm. - 11 - 13 - 14 - 3 - 8 - 9 - APO13.01 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS05.02 - DSS05.05 - DSS05.06 - DSS06.06 - CCI-001764 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 7.6 - A.11.2.9 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.8.2.1 - A.8.2.2 - A.8.2.3 - A.8.3.1 - A.8.3.3 - A.9.1.2 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 - CM-7(a) - CM-7(b) - CM-6(a) - AC-6 - AC-6(1) - MP-7 - PR.IP-1 - PR.PT-2 - PR.PT-3 - SRG-OS-000368-GPOS-00154 - The presence of SUID and SGID executables should be tightly controlled. Users -should not be able to execute SUID or SGID binaries from temporary storage partitions. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -function perform_remediation { - - - - mount_point_match_regexp="$(printf "[^#].*[[:space:]]%s[[:space:]]" /dev/shm)" - - # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab - if ! grep "$mount_point_match_regexp" /etc/fstab; then - # runtime opts without some automatic kernel/userspace-added defaults - previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 | awk '{print $4}' \ - | sed -E "s/(rw|defaults|seclabel|nosuid)(,|$)//g;s/,$//") - [ "$previous_mount_opts" ] && previous_mount_opts+="," - # In iso9660 filesystems mtab could describe a "blocksize" value, this should be reflected in - # fstab as "block". The next variable is to satisfy shellcheck SC2050. - fs_type="tmpfs" - if [ "$fs_type" == "iso9660" ] ; then - previous_mount_opts=$(sed 's/blocksize=/block=/' <<< "$previous_mount_opts") - fi - echo "tmpfs /dev/shm tmpfs defaults,${previous_mount_opts}nosuid 0 0" >> /etc/fstab - # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it - elif ! grep "$mount_point_match_regexp" /etc/fstab | grep "nosuid"; then - previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}') - sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,nosuid|" /etc/fstab - fi - - - if mkdir -p "/dev/shm"; then - if mountpoint -q "/dev/shm"; then - mount -o remount --target "/dev/shm" - fi - fi -} - -perform_remediation - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: 'Add nosuid Option to /dev/shm: Check information associated to mountpoint' - command: findmnt '/dev/shm' - register: device_name - failed_when: device_name.rc > 1 - changed_when: false - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_dev_shm_nosuid - - no_reboot_needed - -- name: 'Add nosuid Option to /dev/shm: Create mount_info dictionary variable' - set_fact: - mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' - with_together: - - '{{ device_name.stdout_lines[0].split() | list | lower }}' - - '{{ device_name.stdout_lines[1].split() | list }}' - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - device_name.stdout is defined and device_name.stdout_lines is defined - - (device_name.stdout | length > 0) - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_dev_shm_nosuid - - no_reboot_needed - -- name: 'Add nosuid Option to /dev/shm: If /dev/shm not mounted, craft mount_info - manually' - set_fact: - mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' - with_together: - - - target - - source - - fstype - - options - - - /dev/shm - - tmpfs - - tmpfs - - defaults - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - ("" | length == 0) - - (device_name.stdout | length == 0) - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_dev_shm_nosuid - - no_reboot_needed - -- name: 'Add nosuid Option to /dev/shm: Make sure nosuid option is part of the to - /dev/shm options' - set_fact: - mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',nosuid'' - }) }}' - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - mount_info is defined and "nosuid" not in mount_info.options - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_dev_shm_nosuid - - no_reboot_needed - -- name: 'Add nosuid Option to /dev/shm: Ensure /dev/shm is mounted with nosuid option' - mount: - path: /dev/shm - src: '{{ mount_info.source }}' - opts: '{{ mount_info.options }}' - state: mounted - fstype: '{{ mount_info.fstype }}' - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("" | - length == 0) - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_dev_shm_nosuid - - no_reboot_needed - - - - - - - - - - Add grpquota Option to /home - The grpquota mount option allows for the filesystem to have disk quotas configured. -Add the grpquota option to the fourth column of -/etc/fstab for the line which controls mounting of -/home. - The quota options for XFS file systems can only be activated when mounting the partition. -It is not possible to enable them by remounting an already mounted partition. Therefore, -if the desired options were not defined before mounting the partition, dismount and mount -it again to apply the quota options. - OVAL looks for partitions whose mount point is a substring of any interactive user's home -directory and validates that grpquota option is there. Because of this, there could be -false negatives when several partitions share a base substring. For example, if there is a -home directory in /var/tmp/user1 and there are partitions mounted in -/var and /var/tmp. The grpquota option is only expected in -/var/tmp, but OVAL will check both. -Bash remediation uses the df command to find out the partition where the home -directory is mounted. However, if the directory doesn't exist the remediation won't be -applied. - CM-6(b) - To ensure the availability of disk space on /home, it is important to limit the impact a -single user or group can cause for other users (or the wider system) by intentionally or -accidentally filling up the partition. Quotas can also be applied to inodes for filesystems -where inode exhaustion is a concern. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -function perform_remediation (){ - - mount_point_match_regexp="$(printf "[^#].*[[:space:]]%s[[:space:]]" $1)" - - # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab - if ! grep "$mount_point_match_regexp" /etc/fstab; then - # runtime opts without some automatic kernel/userspace-added defaults - previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 | awk '{print $4}' \ - | sed -E "s/(rw|defaults|seclabel|grpquota)(,|$)//g;s/,$//") - [ "$previous_mount_opts" ] && previous_mount_opts+="," - # In iso9660 filesystems mtab could describe a "blocksize" value, this should be reflected in - # fstab as "block". The next variable is to satisfy shellcheck SC2050. - fs_type="" - if [ "$fs_type" == "iso9660" ] ; then - previous_mount_opts=$(sed 's/blocksize=/block=/' <<< "$previous_mount_opts") - fi - echo " $1 defaults,${previous_mount_opts}grpquota 0 0" >> /etc/fstab - # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it - elif ! grep "$mount_point_match_regexp" /etc/fstab | grep "grpquota"; then - previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}') - sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,grpquota|" /etc/fstab - fi - - if mkdir -p "$1"; then - if mountpoint -q "$1"; then - mount -o remount --target "$1" - fi - fi -} - -readarray -t home_directories < \ - <(awk -F':' '{if ($3>=1000 && $3!= 65534) print $6}' /etc/passwd ) - - -for home_directory in "${home_directories[@]}" -do - if [ -d $home_directory ]; then - fstab_mount_point=$(df $home_directory | awk '/^\/dev/ {print $6}') - if ! grep -qP "^/$|^/lib$|^/opt$|^/usr$|^/bin$|^/sbin$|^/boot$|^/dev$|^/proc$" <<< $fstab_mount_point - then - perform_remediation "$fstab_mount_point" - fi - fi -done - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - - - - - - - - Add nodev Option to /home - The nodev mount option can be used to prevent device files from -being created in /home. -Legitimate character and block devices should exist only in -the /dev directory on the root partition or within chroot -jails built for system services. -Add the nodev option to the fourth column of -/etc/fstab for the line which controls mounting of -/home. - BP28(R12) - SRG-OS-000368-GPOS-00154 - The only legitimate location for device files is the /dev directory -located on the root partition. The only exception to this is chroot jails. - - # Remediation is applicable only in certain platforms -if ( [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && findmnt --kernel "/home" > /dev/null || findmnt --fstab "/home" > /dev/null ); then - -function perform_remediation { - - mount_point_match_regexp="$(printf "[^#].*[[:space:]]%s[[:space:]]" "/home")" - - grep "$mount_point_match_regexp" -q /etc/fstab \ - || { echo "The mount point '/home' is not even in /etc/fstab, so we can't set up mount options" >&2; - echo "Not remediating, because there is no record of /home in /etc/fstab" >&2; return 1; } - - - - mount_point_match_regexp="$(printf "[^#].*[[:space:]]%s[[:space:]]" /home)" - - # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab - if ! grep "$mount_point_match_regexp" /etc/fstab; then - # runtime opts without some automatic kernel/userspace-added defaults - previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 | awk '{print $4}' \ - | sed -E "s/(rw|defaults|seclabel|nodev)(,|$)//g;s/,$//") - [ "$previous_mount_opts" ] && previous_mount_opts+="," - # In iso9660 filesystems mtab could describe a "blocksize" value, this should be reflected in - # fstab as "block". The next variable is to satisfy shellcheck SC2050. - fs_type="" - if [ "$fs_type" == "iso9660" ] ; then - previous_mount_opts=$(sed 's/blocksize=/block=/' <<< "$previous_mount_opts") - fi - echo " /home defaults,${previous_mount_opts}nodev 0 0" >> /etc/fstab - # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it - elif ! grep "$mount_point_match_regexp" /etc/fstab | grep "nodev"; then - previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}') - sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,nodev|" /etc/fstab - fi - - - if mkdir -p "/home"; then - if mountpoint -q "/home"; then - mount -o remount --target "/home" - fi - fi -} - -perform_remediation - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: 'Add nodev Option to /home: Check information associated to mountpoint' - command: findmnt --fstab '/home' - register: device_name - failed_when: device_name.rc > 1 - changed_when: false - when: ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", - "container"] and "/home" in ansible_mounts | map(attribute="mount") | list ) - tags: - - configure_strategy - - high_disruption - - low_complexity - - mount_option_home_nodev - - no_reboot_needed - - unknown_severity - -- name: 'Add nodev Option to /home: Create mount_info dictionary variable' - set_fact: - mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' - with_together: - - '{{ device_name.stdout_lines[0].split() | list | lower }}' - - '{{ device_name.stdout_lines[1].split() | list }}' - when: - - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - and "/home" in ansible_mounts | map(attribute="mount") | list ) - - device_name.stdout is defined and device_name.stdout_lines is defined - - (device_name.stdout | length > 0) - tags: - - configure_strategy - - high_disruption - - low_complexity - - mount_option_home_nodev - - no_reboot_needed - - unknown_severity - -- name: 'Add nodev Option to /home: If /home not mounted, craft mount_info manually' - set_fact: - mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' - with_together: - - - target - - source - - fstype - - options - - - /home - - '' - - '' - - defaults - when: - - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - and "/home" in ansible_mounts | map(attribute="mount") | list ) - - ("--fstab" | length == 0) - - (device_name.stdout | length == 0) - tags: - - configure_strategy - - high_disruption - - low_complexity - - mount_option_home_nodev - - no_reboot_needed - - unknown_severity - -- name: 'Add nodev Option to /home: Make sure nodev option is part of the to /home - options' - set_fact: - mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',nodev'' - }) }}' - when: - - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - and "/home" in ansible_mounts | map(attribute="mount") | list ) - - mount_info is defined and "nodev" not in mount_info.options - tags: - - configure_strategy - - high_disruption - - low_complexity - - mount_option_home_nodev - - no_reboot_needed - - unknown_severity - -- name: 'Add nodev Option to /home: Ensure /home is mounted with nodev option' - mount: - path: /home - src: '{{ mount_info.source }}' - opts: '{{ mount_info.options }}' - state: mounted - fstype: '{{ mount_info.fstype }}' - when: - - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - and "/home" in ansible_mounts | map(attribute="mount") | list ) - - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" - | length == 0) - tags: - - configure_strategy - - high_disruption - - low_complexity - - mount_option_home_nodev - - no_reboot_needed - - unknown_severity - - -part /home --mountoptions="nodev" - - - - - - - - - - Add noexec Option to /home - The noexec mount option can be used to prevent binaries from being -executed out of /home. -Add the noexec option to the fourth column of -/etc/fstab for the line which controls mounting of -/home. - OVAL looks for partitions whose mount point is a substring of any interactive user's home -directory and validates that noexec option is there. Because of this, there could be false -negatives when several partitions share a base substring. For example, if there is a home -directory in /var/tmp/user1 and there are partitions mounted in /var and -/var/tmp. The noexec option is only expected in /var/tmp, but OVAL will -check both. -Bash remediation uses the df command to find out the partition where the home -directory is mounted. However, if the directory doesn't exist the remediation won't be -applied. - BP28(R12) - CCI-000366 - CM-6(b) - SRG-OS-000480-GPOS-00227 - The /home directory contains data of individual users. Binaries in -this directory should not be considered as trusted and users should not be -able to execute them. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -function perform_remediation (){ - - mount_point_match_regexp="$(printf "[^#].*[[:space:]]%s[[:space:]]" $1)" - - # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab - if ! grep "$mount_point_match_regexp" /etc/fstab; then - # runtime opts without some automatic kernel/userspace-added defaults - previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 | awk '{print $4}' \ - | sed -E "s/(rw|defaults|seclabel|noexec)(,|$)//g;s/,$//") - [ "$previous_mount_opts" ] && previous_mount_opts+="," - # In iso9660 filesystems mtab could describe a "blocksize" value, this should be reflected in - # fstab as "block". The next variable is to satisfy shellcheck SC2050. - fs_type="" - if [ "$fs_type" == "iso9660" ] ; then - previous_mount_opts=$(sed 's/blocksize=/block=/' <<< "$previous_mount_opts") - fi - echo " $1 defaults,${previous_mount_opts}noexec 0 0" >> /etc/fstab - # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it - elif ! grep "$mount_point_match_regexp" /etc/fstab | grep "noexec"; then - previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}') - sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,noexec|" /etc/fstab - fi - - if mkdir -p "$1"; then - if mountpoint -q "$1"; then - mount -o remount --target "$1" - fi - fi -} - -readarray -t home_directories < \ - <(awk -F':' '{if ($3>=1000 && $3!= 65534) print $6}' /etc/passwd ) - - -for home_directory in "${home_directories[@]}" -do - if [ -d $home_directory ]; then - fstab_mount_point=$(df $home_directory | awk '/^\/dev/ {print $6}') - if ! grep -qP "^/$|^/lib$|^/opt$|^/usr$|^/bin$|^/sbin$|^/boot$|^/dev$|^/proc$" <<< $fstab_mount_point - then - perform_remediation "$fstab_mount_point" - fi - fi -done - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - - - - - - - - Add nosuid Option to /home - The nosuid mount option can be used to prevent -execution of setuid programs in /home. The SUID and SGID permissions -should not be required in these user data directories. -Add the nosuid option to the fourth column of -/etc/fstab for the line which controls mounting of -/home. - OVAL looks for partitions whose mount point is a substring of any interactive user's home -directory and validates that noexec option is there. Because of this, there could be false -negatives when several partitions share a base substring. For example, if there is a home -directory in /var/tmp/user1 and there are partitions mounted in /var and -/var/tmp. The noexec option is only expected in /var/tmp, but OVAL will -check both. -Bash remediation uses the df command to find out the partition where the home -directory is mounted. However, if the directory doesn't exist the remediation won't be -applied. - BP28(R28) - 11 - 13 - 14 - 3 - 8 - 9 - APO13.01 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS05.02 - DSS05.05 - DSS05.06 - DSS06.06 - CCI-000366 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 7.6 - A.11.2.9 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.8.2.1 - A.8.2.2 - A.8.2.3 - A.8.3.1 - A.8.3.3 - A.9.1.2 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 - CM-7(a) - CM-7(b) - CM-6(a) - AC-6 - AC-6(1) - MP-7 - PR.IP-1 - PR.PT-2 - PR.PT-3 - SRG-OS-000368-GPOS-00154 - SRG-OS-000480-GPOS-00227 - The presence of SUID and SGID executables should be tightly controlled. Users -should not be able to execute SUID or SGID binaries from user home directory partitions. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -function perform_remediation (){ - - mount_point_match_regexp="$(printf "[^#].*[[:space:]]%s[[:space:]]" $1)" - - # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab - if ! grep "$mount_point_match_regexp" /etc/fstab; then - # runtime opts without some automatic kernel/userspace-added defaults - previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 | awk '{print $4}' \ - | sed -E "s/(rw|defaults|seclabel|nosuid)(,|$)//g;s/,$//") - [ "$previous_mount_opts" ] && previous_mount_opts+="," - # In iso9660 filesystems mtab could describe a "blocksize" value, this should be reflected in - # fstab as "block". The next variable is to satisfy shellcheck SC2050. - fs_type="" - if [ "$fs_type" == "iso9660" ] ; then - previous_mount_opts=$(sed 's/blocksize=/block=/' <<< "$previous_mount_opts") - fi - echo " $1 defaults,${previous_mount_opts}nosuid 0 0" >> /etc/fstab - # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it - elif ! grep "$mount_point_match_regexp" /etc/fstab | grep "nosuid"; then - previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}') - sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,nosuid|" /etc/fstab - fi - - if mkdir -p "$1"; then - if mountpoint -q "$1"; then - mount -o remount --target "$1" - fi - fi -} - -readarray -t home_directories < \ - <(awk -F':' '{if ($3>=1000 && $3!= 65534) print $6}' /etc/passwd ) - - -for home_directory in "${home_directories[@]}" -do - if [ -d $home_directory ]; then - fstab_mount_point=$(df $home_directory | awk '/^\/dev/ {print $6}') - if ! grep -qP "^/$|^/lib$|^/opt$|^/usr$|^/bin$|^/sbin$|^/boot$|^/dev$|^/proc$" <<< $fstab_mount_point - then - perform_remediation "$fstab_mount_point" - fi - fi -done - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - - - - - - - - Add usrquota Option to /home - The usrquota mount option allows for the filesystem to have disk quotas configured. -Add the usrquota option to the fourth column of -/etc/fstab for the line which controls mounting of -/home. - The quota options for XFS file systems can only be activated when mounting the partition. -It is not possible to enable them by remounting an already mounted partition. Therefore, -if the desired options were not defined before mounting the partition, dismount and mount -it again to apply the quota options. - OVAL looks for partitions whose mount point is a substring of any interactive user's home -directory and validates that usrquota option is there. Because of this, there could be -false negatives when several partitions share a base substring. For example, if there is a -home directory in /var/tmp/user1 and there are partitions mounted in -/var and /var/tmp. The usrquota option is only expected in -/var/tmp, but OVAL will check both. -Bash remediation uses the df command to find out the partition where the home -directory is mounted. However, if the directory doesn't exist the remediation won't be -applied. - CM-6(b) - To ensure the availability of disk space on /home, it is important to limit the impact a -single user or group can cause for other users (or the wider system) by intentionally or -accidentally filling up the partition. Quotas can also be applied to inodes for filesystems -where inode exhaustion is a concern. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -function perform_remediation (){ - - mount_point_match_regexp="$(printf "[^#].*[[:space:]]%s[[:space:]]" $1)" - - # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab - if ! grep "$mount_point_match_regexp" /etc/fstab; then - # runtime opts without some automatic kernel/userspace-added defaults - previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 | awk '{print $4}' \ - | sed -E "s/(rw|defaults|seclabel|usrquota)(,|$)//g;s/,$//") - [ "$previous_mount_opts" ] && previous_mount_opts+="," - # In iso9660 filesystems mtab could describe a "blocksize" value, this should be reflected in - # fstab as "block". The next variable is to satisfy shellcheck SC2050. - fs_type="" - if [ "$fs_type" == "iso9660" ] ; then - previous_mount_opts=$(sed 's/blocksize=/block=/' <<< "$previous_mount_opts") - fi - echo " $1 defaults,${previous_mount_opts}usrquota 0 0" >> /etc/fstab - # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it - elif ! grep "$mount_point_match_regexp" /etc/fstab | grep "usrquota"; then - previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}') - sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,usrquota|" /etc/fstab - fi - - if mkdir -p "$1"; then - if mountpoint -q "$1"; then - mount -o remount --target "$1" - fi - fi -} - -readarray -t home_directories < \ - <(awk -F':' '{if ($3>=1000 && $3!= 65534) print $6}' /etc/passwd ) - - -for home_directory in "${home_directories[@]}" -do - if [ -d $home_directory ]; then - fstab_mount_point=$(df $home_directory | awk '/^\/dev/ {print $6}') - if ! grep -qP "^/$|^/lib$|^/opt$|^/usr$|^/bin$|^/sbin$|^/boot$|^/dev$|^/proc$" <<< $fstab_mount_point - then - perform_remediation "$fstab_mount_point" - fi - fi -done - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - - - - - - - - Add nodev Option to Non-Root Local Partitions - The nodev mount option prevents files from being interpreted as -character or block devices. Legitimate character and block devices should -exist only in the /dev directory on the root partition or within -chroot jails built for system services. -Add the nodev option to the fourth column of -/etc/fstab for the line which controls mounting of - - any non-root local partitions. - BP28(R12) - 11 - 14 - 3 - 9 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS05.02 - DSS05.05 - DSS06.06 - CCI-000366 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 7.6 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.9.1.2 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 - CM-7(a) - CM-7(b) - CM-6(a) - AC-6 - AC-6(1) - MP-7 - PR.IP-1 - PR.PT-3 - SRG-OS-000368-GPOS-00154 - SRG-OS-000480-GPOS-00227 - The nodev mount option prevents files from being -interpreted as character or block devices. The only legitimate location -for device files is the /dev directory located on the root partition. -The only exception to this is chroot jails, for which it is not advised -to set nodev on these filesystems. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -MOUNT_OPTION="nodev" -# Create array of local non-root partitions -readarray -t partitions_records < <(findmnt --mtab --raw --evaluate | grep "^/\w" | grep "\s/dev/\w") - -# Create array of polyinstantiated directories, in case one of them is found in mtab -readarray -t polyinstantiated_dirs < \ - <(grep -oP "^\s*[^#\s]+\s+\S+" /etc/security/namespace.conf | grep -oP "(?<=\s)\S+?(?=/?\$)") - - -for partition_record in "${partitions_records[@]}"; do - # Get all important information for fstab - mount_point="$(echo ${partition_record} | cut -d " " -f1)" - device="$(echo ${partition_record} | cut -d " " -f2)" - device_type="$(echo ${partition_record} | cut -d " " -f3)" - if ! printf '%s\0' "${polyinstantiated_dirs[@]}" | grep -qxzF "$mount_point"; then - # device and device_type will be used only in case when the device doesn't have fstab record - mount_point_match_regexp="$(printf "[^#].*[[:space:]]%s[[:space:]]" $mount_point)" - - # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab - if ! grep "$mount_point_match_regexp" /etc/fstab; then - # runtime opts without some automatic kernel/userspace-added defaults - previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 | awk '{print $4}' \ - | sed -E "s/(rw|defaults|seclabel|$MOUNT_OPTION)(,|$)//g;s/,$//") - [ "$previous_mount_opts" ] && previous_mount_opts+="," - # In iso9660 filesystems mtab could describe a "blocksize" value, this should be reflected in - # fstab as "block". The next variable is to satisfy shellcheck SC2050. - fs_type="$device_type" - if [ "$fs_type" == "iso9660" ] ; then - previous_mount_opts=$(sed 's/blocksize=/block=/' <<< "$previous_mount_opts") - fi - echo "$device $mount_point $device_type defaults,${previous_mount_opts}$MOUNT_OPTION 0 0" >> /etc/fstab - # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it - elif ! grep "$mount_point_match_regexp" /etc/fstab | grep "$MOUNT_OPTION"; then - previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}') - sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,$MOUNT_OPTION|" /etc/fstab - fi - if mkdir -p "$mount_point"; then - if mountpoint -q "$mount_point"; then - mount -o remount --target "$mount_point" - fi - fi - fi -done - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Ensure non-root local partitions are mounted with nodev option - mount: - path: '{{ item.mount }}' - src: '{{ item.device }}' - opts: '{{ item.options }},nodev' - state: mounted - fstype: '{{ item.fstype }}' - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - item.mount is match('/\w') - - item.options is not search('nodev') - with_items: - - '{{ ansible_facts.mounts }}' - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_nodev_nonroot_local_partitions - - no_reboot_needed - - - - - - - - - - Add nodev Option to Removable Media Partitions - The nodev mount option prevents files from being -interpreted as character or block devices. -Legitimate character and block devices should exist only in -the /dev directory on the root partition or within chroot -jails built for system services. -Add the nodev option to the fourth column of -/etc/fstab for the line which controls mounting of - - any removable media partitions. - 11 - 12 - 13 - 14 - 16 - 3 - 8 - 9 - APO13.01 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS01.04 - DSS05.02 - DSS05.03 - DSS05.04 - DSS05.05 - DSS05.06 - DSS05.07 - DSS06.03 - DSS06.06 - CCI-000366 - 4.3.3.2.2 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 7.6 - A.11.2.6 - A.11.2.9 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.13.1.1 - A.13.2.1 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.6.2.1 - A.6.2.2 - A.7.1.1 - A.8.2.1 - A.8.2.2 - A.8.2.3 - A.8.3.1 - A.8.3.3 - A.9.1.2 - A.9.2.1 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 - CM-7(a) - CM-7(b) - CM-6(a) - AC-6 - AC-6(1) - MP-7 - PR.AC-3 - PR.AC-6 - PR.IP-1 - PR.PT-2 - PR.PT-3 - SRG-OS-000480-GPOS-00227 - The only legitimate location for device files is the /dev directory -located on the root partition. An exception to this is chroot jails, and it is -not advised to set nodev on partitions which contain their root -filesystems. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -var_removable_partition='' - - -device_regex="^\s*$var_removable_partition\s\+" -mount_option="nodev" - -if grep -q $device_regex /etc/fstab ; then - previous_opts=$(grep $device_regex /etc/fstab | awk '{print $4}') - sed -i "s|\($device_regex.*$previous_opts\)|\1,$mount_option|" /etc/fstab -else - echo "Not remediating, because there is no record of $var_removable_partition in /etc/fstab" >&2 - return 1 -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: XCCDF Value var_removable_partition # promote to variable - set_fact: - var_removable_partition: !!str - tags: - - always - -- name: Ensure permission nodev are set on var_removable_partition - lineinfile: - path: /etc/fstab - regexp: ^\s*({{ var_removable_partition }})\s+([^\s]*)\s+([^\s]*)\s+([^\s]*)(.*)$ - backrefs: true - line: \1 \2 \3 \4,nodev \5 - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_nodev_removable_partitions - - no_reboot_needed - - - - - - - - - - - Add noexec Option to Removable Media Partitions - The noexec mount option prevents the direct execution of binaries -on the mounted filesystem. Preventing the direct execution of binaries from -removable media (such as a USB key) provides a defense against malicious -software that may be present on such untrusted media. -Add the noexec option to the fourth column of -/etc/fstab for the line which controls mounting of - - any removable media partitions. - 11 - 12 - 13 - 14 - 16 - 3 - 8 - 9 - APO13.01 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS01.04 - DSS05.02 - DSS05.03 - DSS05.04 - DSS05.05 - DSS05.06 - DSS05.07 - DSS06.03 - DSS06.06 - CCI-000087 - CCI-000366 - 4.3.3.2.2 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 7.6 - A.11.2.6 - A.11.2.9 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.13.1.1 - A.13.2.1 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.6.2.1 - A.6.2.2 - A.7.1.1 - A.8.2.1 - A.8.2.2 - A.8.2.3 - A.8.3.1 - A.8.3.3 - A.9.1.2 - A.9.2.1 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 - CM-7(a) - CM-7(b) - CM-6(a) - AC-6 - AC-6(1) - MP-7 - PR.AC-3 - PR.AC-6 - PR.IP-1 - PR.PT-2 - PR.PT-3 - SRG-OS-000480-GPOS-00227 - Allowing users to execute binaries from removable media such as USB keys exposes -the system to potential compromise. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -var_removable_partition='' - - -device_regex="^\s*$var_removable_partition\s\+" -mount_option="noexec" - -if grep -q $device_regex /etc/fstab ; then - previous_opts=$(grep $device_regex /etc/fstab | awk '{print $4}') - sed -i "s|\($device_regex.*$previous_opts\)|\1,$mount_option|" /etc/fstab -else - echo "Not remediating, because there is no record of $var_removable_partition in /etc/fstab" >&2 - return 1 -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: XCCDF Value var_removable_partition # promote to variable - set_fact: - var_removable_partition: !!str - tags: - - always - -- name: Ensure permission noexec are set on var_removable_partition - lineinfile: - path: /etc/fstab - regexp: ^\s*({{ var_removable_partition }})\s+([^\s]*)\s+([^\s]*)\s+([^\s]*)(.*)$ - backrefs: true - line: \1 \2 \3 \4,noexec \5 - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_noexec_removable_partitions - - no_reboot_needed - - - - - - - - - - - Add nosuid Option to Removable Media Partitions - The nosuid mount option prevents set-user-identifier (SUID) -and set-group-identifier (SGID) permissions from taking effect. These permissions -allow users to execute binaries with the same permissions as the owner and group -of the file respectively. Users should not be allowed to introduce SUID and SGID -files into the system via partitions mounted from removeable media. -Add the nosuid option to the fourth column of -/etc/fstab for the line which controls mounting of - - any removable media partitions. - 11 - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - 8 - 9 - APO01.06 - APO13.01 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS01.04 - DSS05.02 - DSS05.03 - DSS05.04 - DSS05.05 - DSS05.06 - DSS05.07 - DSS06.02 - DSS06.03 - DSS06.06 - CCI-000366 - 4.3.3.2.2 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 5.2 - SR 7.6 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.11.2.6 - A.11.2.9 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.6.1.2 - A.6.2.1 - A.6.2.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.1 - A.8.2.2 - A.8.2.3 - A.8.3.1 - A.8.3.3 - A.9.1.1 - A.9.1.2 - A.9.2.1 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 - CM-7(a) - CM-7(b) - CM-6(a) - AC-6 - AC-6(1) - MP-7 - PR.AC-3 - PR.AC-4 - PR.AC-6 - PR.DS-5 - PR.IP-1 - PR.PT-2 - PR.PT-3 - SRG-OS-000480-GPOS-00227 - The presence of SUID and SGID executables should be tightly controlled. Allowing -users to introduce SUID or SGID binaries from partitions mounted off of -removable media would allow them to introduce their own highly-privileged programs. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -var_removable_partition='' - - -device_regex="^\s*$var_removable_partition\s\+" -mount_option="nosuid" - -if grep -q $device_regex /etc/fstab ; then - previous_opts=$(grep $device_regex /etc/fstab | awk '{print $4}') - sed -i "s|\($device_regex.*$previous_opts\)|\1,$mount_option|" /etc/fstab -else - echo "Not remediating, because there is no record of $var_removable_partition in /etc/fstab" >&2 - return 1 -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: XCCDF Value var_removable_partition # promote to variable - set_fact: - var_removable_partition: !!str - tags: - - always - -- name: Ensure permission nosuid are set on var_removable_partition - lineinfile: - path: /etc/fstab - regexp: ^\s*({{ var_removable_partition }})\s+([^\s]*)\s+([^\s]*)\s+([^\s]*)(.*)$ - backrefs: true - line: \1 \2 \3 \4,nosuid \5 - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_nosuid_removable_partitions - - no_reboot_needed - - - - - - - - - - - Add nosuid Option to /opt - The nosuid mount option can be used to prevent -execution of setuid programs in /opt. The SUID and SGID permissions -should not be required in this directory. -Add the nosuid option to the fourth column of -/etc/fstab for the line which controls mounting of -/opt. - BP28(R12) - The presence of SUID and SGID executables should be tightly controlled. The -/opt directory contains additional software packages. Users should -not be able to execute SUID or SGID binaries from this directory. - - # Remediation is applicable only in certain platforms -if ( [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && findmnt --kernel "/opt" > /dev/null || findmnt --fstab "/opt" > /dev/null ); then - -function perform_remediation { - - mount_point_match_regexp="$(printf "[^#].*[[:space:]]%s[[:space:]]" "/opt")" - - grep "$mount_point_match_regexp" -q /etc/fstab \ - || { echo "The mount point '/opt' is not even in /etc/fstab, so we can't set up mount options" >&2; - echo "Not remediating, because there is no record of /opt in /etc/fstab" >&2; return 1; } - - - - mount_point_match_regexp="$(printf "[^#].*[[:space:]]%s[[:space:]]" /opt)" - - # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab - if ! grep "$mount_point_match_regexp" /etc/fstab; then - # runtime opts without some automatic kernel/userspace-added defaults - previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 | awk '{print $4}' \ - | sed -E "s/(rw|defaults|seclabel|nosuid)(,|$)//g;s/,$//") - [ "$previous_mount_opts" ] && previous_mount_opts+="," - # In iso9660 filesystems mtab could describe a "blocksize" value, this should be reflected in - # fstab as "block". The next variable is to satisfy shellcheck SC2050. - fs_type="" - if [ "$fs_type" == "iso9660" ] ; then - previous_mount_opts=$(sed 's/blocksize=/block=/' <<< "$previous_mount_opts") - fi - echo " /opt defaults,${previous_mount_opts}nosuid 0 0" >> /etc/fstab - # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it - elif ! grep "$mount_point_match_regexp" /etc/fstab | grep "nosuid"; then - previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}') - sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,nosuid|" /etc/fstab - fi - - - if mkdir -p "/opt"; then - if mountpoint -q "/opt"; then - mount -o remount --target "/opt" - fi - fi -} - -perform_remediation - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: 'Add nosuid Option to /opt: Check information associated to mountpoint' - command: findmnt --fstab '/opt' - register: device_name - failed_when: device_name.rc > 1 - changed_when: false - when: ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", - "container"] and "/opt" in ansible_mounts | map(attribute="mount") | list ) - tags: - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_opt_nosuid - - no_reboot_needed - -- name: 'Add nosuid Option to /opt: Create mount_info dictionary variable' - set_fact: - mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' - with_together: - - '{{ device_name.stdout_lines[0].split() | list | lower }}' - - '{{ device_name.stdout_lines[1].split() | list }}' - when: - - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - and "/opt" in ansible_mounts | map(attribute="mount") | list ) - - device_name.stdout is defined and device_name.stdout_lines is defined - - (device_name.stdout | length > 0) - tags: - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_opt_nosuid - - no_reboot_needed - -- name: 'Add nosuid Option to /opt: If /opt not mounted, craft mount_info manually' - set_fact: - mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' - with_together: - - - target - - source - - fstype - - options - - - /opt - - '' - - '' - - defaults - when: - - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - and "/opt" in ansible_mounts | map(attribute="mount") | list ) - - ("--fstab" | length == 0) - - (device_name.stdout | length == 0) - tags: - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_opt_nosuid - - no_reboot_needed - -- name: 'Add nosuid Option to /opt: Make sure nosuid option is part of the to /opt - options' - set_fact: - mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',nosuid'' - }) }}' - when: - - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - and "/opt" in ansible_mounts | map(attribute="mount") | list ) - - mount_info is defined and "nosuid" not in mount_info.options - tags: - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_opt_nosuid - - no_reboot_needed - -- name: 'Add nosuid Option to /opt: Ensure /opt is mounted with nosuid option' - mount: - path: /opt - src: '{{ mount_info.source }}' - opts: '{{ mount_info.options }}' - state: mounted - fstype: '{{ mount_info.fstype }}' - when: - - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - and "/opt" in ansible_mounts | map(attribute="mount") | list ) - - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" - | length == 0) - tags: - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_opt_nosuid - - no_reboot_needed - - -part /opt --mountoptions="nosuid" - - - - - - - - - - Add nosuid Option to /srv - The nosuid mount option can be used to prevent -execution of setuid programs in /srv. The SUID and SGID permissions -should not be required in this directory. -Add the nosuid option to the fourth column of -/etc/fstab for the line which controls mounting of -/srv. - BP28(R12) - The presence of SUID and SGID executables should be tightly controlled. The -/srv directory contains files served by various network services such as FTP. Users should -not be able to execute SUID or SGID binaries from this directory. - - # Remediation is applicable only in certain platforms -if ( [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && findmnt --kernel "/srv" > /dev/null || findmnt --fstab "/srv" > /dev/null ); then - -function perform_remediation { - - mount_point_match_regexp="$(printf "[^#].*[[:space:]]%s[[:space:]]" "/srv")" - - grep "$mount_point_match_regexp" -q /etc/fstab \ - || { echo "The mount point '/srv' is not even in /etc/fstab, so we can't set up mount options" >&2; - echo "Not remediating, because there is no record of /srv in /etc/fstab" >&2; return 1; } - - - - mount_point_match_regexp="$(printf "[^#].*[[:space:]]%s[[:space:]]" /srv)" - - # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab - if ! grep "$mount_point_match_regexp" /etc/fstab; then - # runtime opts without some automatic kernel/userspace-added defaults - previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 | awk '{print $4}' \ - | sed -E "s/(rw|defaults|seclabel|nosuid)(,|$)//g;s/,$//") - [ "$previous_mount_opts" ] && previous_mount_opts+="," - # In iso9660 filesystems mtab could describe a "blocksize" value, this should be reflected in - # fstab as "block". The next variable is to satisfy shellcheck SC2050. - fs_type="" - if [ "$fs_type" == "iso9660" ] ; then - previous_mount_opts=$(sed 's/blocksize=/block=/' <<< "$previous_mount_opts") - fi - echo " /srv defaults,${previous_mount_opts}nosuid 0 0" >> /etc/fstab - # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it - elif ! grep "$mount_point_match_regexp" /etc/fstab | grep "nosuid"; then - previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}') - sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,nosuid|" /etc/fstab - fi - - - if mkdir -p "/srv"; then - if mountpoint -q "/srv"; then - mount -o remount --target "/srv" - fi - fi -} - -perform_remediation - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: 'Add nosuid Option to /srv: Check information associated to mountpoint' - command: findmnt --fstab '/srv' - register: device_name - failed_when: device_name.rc > 1 - changed_when: false - when: ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", - "container"] and "/srv" in ansible_mounts | map(attribute="mount") | list ) - tags: - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_srv_nosuid - - no_reboot_needed - -- name: 'Add nosuid Option to /srv: Create mount_info dictionary variable' - set_fact: - mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' - with_together: - - '{{ device_name.stdout_lines[0].split() | list | lower }}' - - '{{ device_name.stdout_lines[1].split() | list }}' - when: - - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - and "/srv" in ansible_mounts | map(attribute="mount") | list ) - - device_name.stdout is defined and device_name.stdout_lines is defined - - (device_name.stdout | length > 0) - tags: - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_srv_nosuid - - no_reboot_needed - -- name: 'Add nosuid Option to /srv: If /srv not mounted, craft mount_info manually' - set_fact: - mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' - with_together: - - - target - - source - - fstype - - options - - - /srv - - '' - - '' - - defaults - when: - - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - and "/srv" in ansible_mounts | map(attribute="mount") | list ) - - ("--fstab" | length == 0) - - (device_name.stdout | length == 0) - tags: - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_srv_nosuid - - no_reboot_needed - -- name: 'Add nosuid Option to /srv: Make sure nosuid option is part of the to /srv - options' - set_fact: - mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',nosuid'' - }) }}' - when: - - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - and "/srv" in ansible_mounts | map(attribute="mount") | list ) - - mount_info is defined and "nosuid" not in mount_info.options - tags: - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_srv_nosuid - - no_reboot_needed - -- name: 'Add nosuid Option to /srv: Ensure /srv is mounted with nosuid option' - mount: - path: /srv - src: '{{ mount_info.source }}' - opts: '{{ mount_info.options }}' - state: mounted - fstype: '{{ mount_info.fstype }}' - when: - - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - and "/srv" in ansible_mounts | map(attribute="mount") | list ) - - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" - | length == 0) - tags: - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_srv_nosuid - - no_reboot_needed - - -part /srv --mountoptions="nosuid" - - - - - - - - - - Add nodev Option to /tmp - The nodev mount option can be used to prevent device files from -being created in /tmp. Legitimate character and block devices -should not exist within temporary directories like /tmp. -Add the nodev option to the fourth column of -/etc/fstab for the line which controls mounting of -/tmp. - BP28(R12) - 11 - 13 - 14 - 3 - 8 - 9 - APO13.01 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS05.02 - DSS05.05 - DSS05.06 - DSS06.06 - CCI-001764 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 7.6 - A.11.2.9 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.8.2.1 - A.8.2.2 - A.8.2.3 - A.8.3.1 - A.8.3.3 - A.9.1.2 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 - CM-7(a) - CM-7(b) - CM-6(a) - AC-6 - AC-6(1) - MP-7 - PR.IP-1 - PR.PT-2 - PR.PT-3 - SRG-OS-000368-GPOS-00154 - The only legitimate location for device files is the /dev directory -located on the root partition. The only exception to this is chroot jails. - - # Remediation is applicable only in certain platforms -if ( [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && findmnt --kernel "/tmp" > /dev/null || findmnt --fstab "/tmp" > /dev/null ); then - -function perform_remediation { - - mount_point_match_regexp="$(printf "[^#].*[[:space:]]%s[[:space:]]" "/tmp")" - - grep "$mount_point_match_regexp" -q /etc/fstab \ - || { echo "The mount point '/tmp' is not even in /etc/fstab, so we can't set up mount options" >&2; - echo "Not remediating, because there is no record of /tmp in /etc/fstab" >&2; return 1; } - - - - mount_point_match_regexp="$(printf "[^#].*[[:space:]]%s[[:space:]]" /tmp)" - - # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab - if ! grep "$mount_point_match_regexp" /etc/fstab; then - # runtime opts without some automatic kernel/userspace-added defaults - previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 | awk '{print $4}' \ - | sed -E "s/(rw|defaults|seclabel|nodev)(,|$)//g;s/,$//") - [ "$previous_mount_opts" ] && previous_mount_opts+="," - # In iso9660 filesystems mtab could describe a "blocksize" value, this should be reflected in - # fstab as "block". The next variable is to satisfy shellcheck SC2050. - fs_type="" - if [ "$fs_type" == "iso9660" ] ; then - previous_mount_opts=$(sed 's/blocksize=/block=/' <<< "$previous_mount_opts") - fi - echo " /tmp defaults,${previous_mount_opts}nodev 0 0" >> /etc/fstab - # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it - elif ! grep "$mount_point_match_regexp" /etc/fstab | grep "nodev"; then - previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}') - sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,nodev|" /etc/fstab - fi - - - if mkdir -p "/tmp"; then - if mountpoint -q "/tmp"; then - mount -o remount --target "/tmp" - fi - fi -} - -perform_remediation - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: 'Add nodev Option to /tmp: Check information associated to mountpoint' - command: findmnt --fstab '/tmp' - register: device_name - failed_when: device_name.rc > 1 - changed_when: false - when: ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", - "container"] and "/tmp" in ansible_mounts | map(attribute="mount") | list ) - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_tmp_nodev - - no_reboot_needed - -- name: 'Add nodev Option to /tmp: Create mount_info dictionary variable' - set_fact: - mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' - with_together: - - '{{ device_name.stdout_lines[0].split() | list | lower }}' - - '{{ device_name.stdout_lines[1].split() | list }}' - when: - - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - and "/tmp" in ansible_mounts | map(attribute="mount") | list ) - - device_name.stdout is defined and device_name.stdout_lines is defined - - (device_name.stdout | length > 0) - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_tmp_nodev - - no_reboot_needed - -- name: 'Add nodev Option to /tmp: If /tmp not mounted, craft mount_info manually' - set_fact: - mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' - with_together: - - - target - - source - - fstype - - options - - - /tmp - - '' - - '' - - defaults - when: - - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - and "/tmp" in ansible_mounts | map(attribute="mount") | list ) - - ("--fstab" | length == 0) - - (device_name.stdout | length == 0) - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_tmp_nodev - - no_reboot_needed - -- name: 'Add nodev Option to /tmp: Make sure nodev option is part of the to /tmp options' - set_fact: - mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',nodev'' - }) }}' - when: - - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - and "/tmp" in ansible_mounts | map(attribute="mount") | list ) - - mount_info is defined and "nodev" not in mount_info.options - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_tmp_nodev - - no_reboot_needed - -- name: 'Add nodev Option to /tmp: Ensure /tmp is mounted with nodev option' - mount: - path: /tmp - src: '{{ mount_info.source }}' - opts: '{{ mount_info.options }}' - state: mounted - fstype: '{{ mount_info.fstype }}' - when: - - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - and "/tmp" in ansible_mounts | map(attribute="mount") | list ) - - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" - | length == 0) - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_tmp_nodev - - no_reboot_needed - - -part /tmp --mountoptions="nodev" - - - - - - - - - - Add noexec Option to /tmp - The noexec mount option can be used to prevent binaries -from being executed out of /tmp. -Add the noexec option to the fourth column of -/etc/fstab for the line which controls mounting of -/tmp. - BP28(R12) - 11 - 13 - 14 - 3 - 8 - 9 - APO13.01 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS05.02 - DSS05.05 - DSS05.06 - DSS06.06 - CCI-001764 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 7.6 - A.11.2.9 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.8.2.1 - A.8.2.2 - A.8.2.3 - A.8.3.1 - A.8.3.3 - A.9.1.2 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 - CM-7(a) - CM-7(b) - CM-6(a) - AC-6 - AC-6(1) - MP-7 - PR.IP-1 - PR.PT-2 - PR.PT-3 - SRG-OS-000368-GPOS-00154 - Allowing users to execute binaries from world-writable directories -such as /tmp should never be necessary in normal operation and -can expose the system to potential compromise. - - # Remediation is applicable only in certain platforms -if ( [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && findmnt --kernel "/tmp" > /dev/null || findmnt --fstab "/tmp" > /dev/null ); then - -function perform_remediation { - - mount_point_match_regexp="$(printf "[^#].*[[:space:]]%s[[:space:]]" "/tmp")" - - grep "$mount_point_match_regexp" -q /etc/fstab \ - || { echo "The mount point '/tmp' is not even in /etc/fstab, so we can't set up mount options" >&2; - echo "Not remediating, because there is no record of /tmp in /etc/fstab" >&2; return 1; } - - - - mount_point_match_regexp="$(printf "[^#].*[[:space:]]%s[[:space:]]" /tmp)" - - # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab - if ! grep "$mount_point_match_regexp" /etc/fstab; then - # runtime opts without some automatic kernel/userspace-added defaults - previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 | awk '{print $4}' \ - | sed -E "s/(rw|defaults|seclabel|noexec)(,|$)//g;s/,$//") - [ "$previous_mount_opts" ] && previous_mount_opts+="," - # In iso9660 filesystems mtab could describe a "blocksize" value, this should be reflected in - # fstab as "block". The next variable is to satisfy shellcheck SC2050. - fs_type="" - if [ "$fs_type" == "iso9660" ] ; then - previous_mount_opts=$(sed 's/blocksize=/block=/' <<< "$previous_mount_opts") - fi - echo " /tmp defaults,${previous_mount_opts}noexec 0 0" >> /etc/fstab - # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it - elif ! grep "$mount_point_match_regexp" /etc/fstab | grep "noexec"; then - previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}') - sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,noexec|" /etc/fstab - fi - - - if mkdir -p "/tmp"; then - if mountpoint -q "/tmp"; then - mount -o remount --target "/tmp" - fi - fi -} - -perform_remediation - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: 'Add noexec Option to /tmp: Check information associated to mountpoint' - command: findmnt --fstab '/tmp' - register: device_name - failed_when: device_name.rc > 1 - changed_when: false - when: ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", - "container"] and "/tmp" in ansible_mounts | map(attribute="mount") | list ) - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_tmp_noexec - - no_reboot_needed - -- name: 'Add noexec Option to /tmp: Create mount_info dictionary variable' - set_fact: - mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' - with_together: - - '{{ device_name.stdout_lines[0].split() | list | lower }}' - - '{{ device_name.stdout_lines[1].split() | list }}' - when: - - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - and "/tmp" in ansible_mounts | map(attribute="mount") | list ) - - device_name.stdout is defined and device_name.stdout_lines is defined - - (device_name.stdout | length > 0) - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_tmp_noexec - - no_reboot_needed - -- name: 'Add noexec Option to /tmp: If /tmp not mounted, craft mount_info manually' - set_fact: - mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' - with_together: - - - target - - source - - fstype - - options - - - /tmp - - '' - - '' - - defaults - when: - - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - and "/tmp" in ansible_mounts | map(attribute="mount") | list ) - - ("--fstab" | length == 0) - - (device_name.stdout | length == 0) - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_tmp_noexec - - no_reboot_needed - -- name: 'Add noexec Option to /tmp: Make sure noexec option is part of the to /tmp - options' - set_fact: - mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',noexec'' - }) }}' - when: - - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - and "/tmp" in ansible_mounts | map(attribute="mount") | list ) - - mount_info is defined and "noexec" not in mount_info.options - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_tmp_noexec - - no_reboot_needed - -- name: 'Add noexec Option to /tmp: Ensure /tmp is mounted with noexec option' - mount: - path: /tmp - src: '{{ mount_info.source }}' - opts: '{{ mount_info.options }}' - state: mounted - fstype: '{{ mount_info.fstype }}' - when: - - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - and "/tmp" in ansible_mounts | map(attribute="mount") | list ) - - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" - | length == 0) - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_tmp_noexec - - no_reboot_needed - - -part /tmp --mountoptions="noexec" - - - - - - - - - - Add nosuid Option to /tmp - The nosuid mount option can be used to prevent -execution of setuid programs in /tmp. The SUID and SGID permissions -should not be required in these world-writable directories. -Add the nosuid option to the fourth column of -/etc/fstab for the line which controls mounting of -/tmp. - BP28(R12) - 11 - 13 - 14 - 3 - 8 - 9 - APO13.01 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS05.02 - DSS05.05 - DSS05.06 - DSS06.06 - CCI-001764 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 7.6 - A.11.2.9 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.8.2.1 - A.8.2.2 - A.8.2.3 - A.8.3.1 - A.8.3.3 - A.9.1.2 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 - CM-7(a) - CM-7(b) - CM-6(a) - AC-6 - AC-6(1) - MP-7 - PR.IP-1 - PR.PT-2 - PR.PT-3 - SRG-OS-000368-GPOS-00154 - The presence of SUID and SGID executables should be tightly controlled. Users -should not be able to execute SUID or SGID binaries from temporary storage partitions. - - # Remediation is applicable only in certain platforms -if ( [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && findmnt --kernel "/tmp" > /dev/null || findmnt --fstab "/tmp" > /dev/null ); then - -function perform_remediation { - - mount_point_match_regexp="$(printf "[^#].*[[:space:]]%s[[:space:]]" "/tmp")" - - grep "$mount_point_match_regexp" -q /etc/fstab \ - || { echo "The mount point '/tmp' is not even in /etc/fstab, so we can't set up mount options" >&2; - echo "Not remediating, because there is no record of /tmp in /etc/fstab" >&2; return 1; } - - - - mount_point_match_regexp="$(printf "[^#].*[[:space:]]%s[[:space:]]" /tmp)" - - # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab - if ! grep "$mount_point_match_regexp" /etc/fstab; then - # runtime opts without some automatic kernel/userspace-added defaults - previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 | awk '{print $4}' \ - | sed -E "s/(rw|defaults|seclabel|nosuid)(,|$)//g;s/,$//") - [ "$previous_mount_opts" ] && previous_mount_opts+="," - # In iso9660 filesystems mtab could describe a "blocksize" value, this should be reflected in - # fstab as "block". The next variable is to satisfy shellcheck SC2050. - fs_type="" - if [ "$fs_type" == "iso9660" ] ; then - previous_mount_opts=$(sed 's/blocksize=/block=/' <<< "$previous_mount_opts") - fi - echo " /tmp defaults,${previous_mount_opts}nosuid 0 0" >> /etc/fstab - # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it - elif ! grep "$mount_point_match_regexp" /etc/fstab | grep "nosuid"; then - previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}') - sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,nosuid|" /etc/fstab - fi - - - if mkdir -p "/tmp"; then - if mountpoint -q "/tmp"; then - mount -o remount --target "/tmp" - fi - fi -} - -perform_remediation - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: 'Add nosuid Option to /tmp: Check information associated to mountpoint' - command: findmnt --fstab '/tmp' - register: device_name - failed_when: device_name.rc > 1 - changed_when: false - when: ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", - "container"] and "/tmp" in ansible_mounts | map(attribute="mount") | list ) - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_tmp_nosuid - - no_reboot_needed - -- name: 'Add nosuid Option to /tmp: Create mount_info dictionary variable' - set_fact: - mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' - with_together: - - '{{ device_name.stdout_lines[0].split() | list | lower }}' - - '{{ device_name.stdout_lines[1].split() | list }}' - when: - - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - and "/tmp" in ansible_mounts | map(attribute="mount") | list ) - - device_name.stdout is defined and device_name.stdout_lines is defined - - (device_name.stdout | length > 0) - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_tmp_nosuid - - no_reboot_needed - -- name: 'Add nosuid Option to /tmp: If /tmp not mounted, craft mount_info manually' - set_fact: - mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' - with_together: - - - target - - source - - fstype - - options - - - /tmp - - '' - - '' - - defaults - when: - - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - and "/tmp" in ansible_mounts | map(attribute="mount") | list ) - - ("--fstab" | length == 0) - - (device_name.stdout | length == 0) - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_tmp_nosuid - - no_reboot_needed - -- name: 'Add nosuid Option to /tmp: Make sure nosuid option is part of the to /tmp - options' - set_fact: - mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',nosuid'' - }) }}' - when: - - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - and "/tmp" in ansible_mounts | map(attribute="mount") | list ) - - mount_info is defined and "nosuid" not in mount_info.options - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_tmp_nosuid - - no_reboot_needed - -- name: 'Add nosuid Option to /tmp: Ensure /tmp is mounted with nosuid option' - mount: - path: /tmp - src: '{{ mount_info.source }}' - opts: '{{ mount_info.options }}' - state: mounted - fstype: '{{ mount_info.fstype }}' - when: - - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - and "/tmp" in ansible_mounts | map(attribute="mount") | list ) - - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" - | length == 0) - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_tmp_nosuid - - no_reboot_needed - - -part /tmp --mountoptions="nosuid" - - - - - - - - - - Add nodev Option to /var/log/audit - The nodev mount option can be used to prevent device files from -being created in /var/log/audit. -Legitimate character and block devices should exist only in -the /dev directory on the root partition or within chroot -jails built for system services. -Add the nodev option to the fourth column of -/etc/fstab for the line which controls mounting of -/var/log/audit. - CCI-001764 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 - CM-7(a) - CM-7(b) - CM-6(a) - AC-6 - AC-6(1) - MP-7 - PR.IP-1 - PR.PT-2 - PR.PT-3 - SRG-OS-000368-GPOS-00154 - The only legitimate location for device files is the /dev directory -located on the root partition. The only exception to this is chroot jails. - - # Remediation is applicable only in certain platforms -if ( [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && findmnt --kernel "/var/log/audit" > /dev/null || findmnt --fstab "/var/log/audit" > /dev/null ); then - -function perform_remediation { - - mount_point_match_regexp="$(printf "[^#].*[[:space:]]%s[[:space:]]" "/var/log/audit")" - - grep "$mount_point_match_regexp" -q /etc/fstab \ - || { echo "The mount point '/var/log/audit' is not even in /etc/fstab, so we can't set up mount options" >&2; - echo "Not remediating, because there is no record of /var/log/audit in /etc/fstab" >&2; return 1; } - - - - mount_point_match_regexp="$(printf "[^#].*[[:space:]]%s[[:space:]]" /var/log/audit)" - - # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab - if ! grep "$mount_point_match_regexp" /etc/fstab; then - # runtime opts without some automatic kernel/userspace-added defaults - previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 | awk '{print $4}' \ - | sed -E "s/(rw|defaults|seclabel|nodev)(,|$)//g;s/,$//") - [ "$previous_mount_opts" ] && previous_mount_opts+="," - # In iso9660 filesystems mtab could describe a "blocksize" value, this should be reflected in - # fstab as "block". The next variable is to satisfy shellcheck SC2050. - fs_type="" - if [ "$fs_type" == "iso9660" ] ; then - previous_mount_opts=$(sed 's/blocksize=/block=/' <<< "$previous_mount_opts") - fi - echo " /var/log/audit defaults,${previous_mount_opts}nodev 0 0" >> /etc/fstab - # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it - elif ! grep "$mount_point_match_regexp" /etc/fstab | grep "nodev"; then - previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}') - sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,nodev|" /etc/fstab - fi - - - if mkdir -p "/var/log/audit"; then - if mountpoint -q "/var/log/audit"; then - mount -o remount --target "/var/log/audit" - fi - fi -} - -perform_remediation - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: 'Add nodev Option to /var/log/audit: Check information associated to mountpoint' - command: findmnt --fstab '/var/log/audit' - register: device_name - failed_when: device_name.rc > 1 - changed_when: false - when: ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", - "container"] and "/var/log/audit" in ansible_mounts | map(attribute="mount") | - list ) - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_var_log_audit_nodev - - no_reboot_needed - -- name: 'Add nodev Option to /var/log/audit: Create mount_info dictionary variable' - set_fact: - mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' - with_together: - - '{{ device_name.stdout_lines[0].split() | list | lower }}' - - '{{ device_name.stdout_lines[1].split() | list }}' - when: - - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - and "/var/log/audit" in ansible_mounts | map(attribute="mount") | list ) - - device_name.stdout is defined and device_name.stdout_lines is defined - - (device_name.stdout | length > 0) - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_var_log_audit_nodev - - no_reboot_needed - -- name: 'Add nodev Option to /var/log/audit: If /var/log/audit not mounted, craft - mount_info manually' - set_fact: - mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' - with_together: - - - target - - source - - fstype - - options - - - /var/log/audit - - '' - - '' - - defaults - when: - - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - and "/var/log/audit" in ansible_mounts | map(attribute="mount") | list ) - - ("--fstab" | length == 0) - - (device_name.stdout | length == 0) - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_var_log_audit_nodev - - no_reboot_needed - -- name: 'Add nodev Option to /var/log/audit: Make sure nodev option is part of the - to /var/log/audit options' - set_fact: - mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',nodev'' - }) }}' - when: - - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - and "/var/log/audit" in ansible_mounts | map(attribute="mount") | list ) - - mount_info is defined and "nodev" not in mount_info.options - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_var_log_audit_nodev - - no_reboot_needed - -- name: 'Add nodev Option to /var/log/audit: Ensure /var/log/audit is mounted with - nodev option' - mount: - path: /var/log/audit - src: '{{ mount_info.source }}' - opts: '{{ mount_info.options }}' - state: mounted - fstype: '{{ mount_info.fstype }}' - when: - - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - and "/var/log/audit" in ansible_mounts | map(attribute="mount") | list ) - - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" - | length == 0) - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_var_log_audit_nodev - - no_reboot_needed - - -part /var/log/audit --mountoptions="nodev" - - - - - - - - - - Add noexec Option to /var/log/audit - The noexec mount option can be used to prevent binaries -from being executed out of /var/log/audit. -Add the noexec option to the fourth column of -/etc/fstab for the line which controls mounting of -/var/log/audit. - CCI-001764 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 - CM-7(a) - CM-7(b) - CM-6(a) - AC-6 - AC-6(1) - MP-7 - PR.IP-1 - PR.PT-2 - PR.PT-3 - SRG-OS-000368-GPOS-00154 - Allowing users to execute binaries from directories containing audit log files -such as /var/log/audit should never be necessary in normal operation and -can expose the system to potential compromise. - - # Remediation is applicable only in certain platforms -if ( [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && findmnt --kernel "/var/log/audit" > /dev/null || findmnt --fstab "/var/log/audit" > /dev/null ); then - -function perform_remediation { - - mount_point_match_regexp="$(printf "[^#].*[[:space:]]%s[[:space:]]" "/var/log/audit")" - - grep "$mount_point_match_regexp" -q /etc/fstab \ - || { echo "The mount point '/var/log/audit' is not even in /etc/fstab, so we can't set up mount options" >&2; - echo "Not remediating, because there is no record of /var/log/audit in /etc/fstab" >&2; return 1; } - - - - mount_point_match_regexp="$(printf "[^#].*[[:space:]]%s[[:space:]]" /var/log/audit)" - - # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab - if ! grep "$mount_point_match_regexp" /etc/fstab; then - # runtime opts without some automatic kernel/userspace-added defaults - previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 | awk '{print $4}' \ - | sed -E "s/(rw|defaults|seclabel|noexec)(,|$)//g;s/,$//") - [ "$previous_mount_opts" ] && previous_mount_opts+="," - # In iso9660 filesystems mtab could describe a "blocksize" value, this should be reflected in - # fstab as "block". The next variable is to satisfy shellcheck SC2050. - fs_type="" - if [ "$fs_type" == "iso9660" ] ; then - previous_mount_opts=$(sed 's/blocksize=/block=/' <<< "$previous_mount_opts") - fi - echo " /var/log/audit defaults,${previous_mount_opts}noexec 0 0" >> /etc/fstab - # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it - elif ! grep "$mount_point_match_regexp" /etc/fstab | grep "noexec"; then - previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}') - sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,noexec|" /etc/fstab - fi - - - if mkdir -p "/var/log/audit"; then - if mountpoint -q "/var/log/audit"; then - mount -o remount --target "/var/log/audit" - fi - fi -} - -perform_remediation - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: 'Add noexec Option to /var/log/audit: Check information associated to mountpoint' - command: findmnt --fstab '/var/log/audit' - register: device_name - failed_when: device_name.rc > 1 - changed_when: false - when: ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", - "container"] and "/var/log/audit" in ansible_mounts | map(attribute="mount") | - list ) - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_var_log_audit_noexec - - no_reboot_needed - -- name: 'Add noexec Option to /var/log/audit: Create mount_info dictionary variable' - set_fact: - mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' - with_together: - - '{{ device_name.stdout_lines[0].split() | list | lower }}' - - '{{ device_name.stdout_lines[1].split() | list }}' - when: - - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - and "/var/log/audit" in ansible_mounts | map(attribute="mount") | list ) - - device_name.stdout is defined and device_name.stdout_lines is defined - - (device_name.stdout | length > 0) - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_var_log_audit_noexec - - no_reboot_needed - -- name: 'Add noexec Option to /var/log/audit: If /var/log/audit not mounted, craft - mount_info manually' - set_fact: - mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' - with_together: - - - target - - source - - fstype - - options - - - /var/log/audit - - '' - - '' - - defaults - when: - - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - and "/var/log/audit" in ansible_mounts | map(attribute="mount") | list ) - - ("--fstab" | length == 0) - - (device_name.stdout | length == 0) - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_var_log_audit_noexec - - no_reboot_needed - -- name: 'Add noexec Option to /var/log/audit: Make sure noexec option is part of the - to /var/log/audit options' - set_fact: - mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',noexec'' - }) }}' - when: - - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - and "/var/log/audit" in ansible_mounts | map(attribute="mount") | list ) - - mount_info is defined and "noexec" not in mount_info.options - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_var_log_audit_noexec - - no_reboot_needed - -- name: 'Add noexec Option to /var/log/audit: Ensure /var/log/audit is mounted with - noexec option' - mount: - path: /var/log/audit - src: '{{ mount_info.source }}' - opts: '{{ mount_info.options }}' - state: mounted - fstype: '{{ mount_info.fstype }}' - when: - - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - and "/var/log/audit" in ansible_mounts | map(attribute="mount") | list ) - - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" - | length == 0) - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_var_log_audit_noexec - - no_reboot_needed - - -part /var/log/audit --mountoptions="noexec" - - - - - - - - - - Add nosuid Option to /var/log/audit - The nosuid mount option can be used to prevent -execution of setuid programs in /var/log/audit. The SUID and SGID permissions -should not be required in directories containing audit log files. -Add the nosuid option to the fourth column of -/etc/fstab for the line which controls mounting of -/var/log/audit. - CCI-001764 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 - CM-7(a) - CM-7(b) - CM-6(a) - AC-6 - AC-6(1) - MP-7 - PR.IP-1 - PR.PT-2 - PR.PT-3 - SRG-OS-000368-GPOS-00154 - The presence of SUID and SGID executables should be tightly controlled. Users -should not be able to execute SUID or SGID binaries from partitions -designated for audit log files. - - # Remediation is applicable only in certain platforms -if ( [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && findmnt --kernel "/var/log/audit" > /dev/null || findmnt --fstab "/var/log/audit" > /dev/null ); then - -function perform_remediation { - - mount_point_match_regexp="$(printf "[^#].*[[:space:]]%s[[:space:]]" "/var/log/audit")" - - grep "$mount_point_match_regexp" -q /etc/fstab \ - || { echo "The mount point '/var/log/audit' is not even in /etc/fstab, so we can't set up mount options" >&2; - echo "Not remediating, because there is no record of /var/log/audit in /etc/fstab" >&2; return 1; } - - - - mount_point_match_regexp="$(printf "[^#].*[[:space:]]%s[[:space:]]" /var/log/audit)" - - # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab - if ! grep "$mount_point_match_regexp" /etc/fstab; then - # runtime opts without some automatic kernel/userspace-added defaults - previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 | awk '{print $4}' \ - | sed -E "s/(rw|defaults|seclabel|nosuid)(,|$)//g;s/,$//") - [ "$previous_mount_opts" ] && previous_mount_opts+="," - # In iso9660 filesystems mtab could describe a "blocksize" value, this should be reflected in - # fstab as "block". The next variable is to satisfy shellcheck SC2050. - fs_type="" - if [ "$fs_type" == "iso9660" ] ; then - previous_mount_opts=$(sed 's/blocksize=/block=/' <<< "$previous_mount_opts") - fi - echo " /var/log/audit defaults,${previous_mount_opts}nosuid 0 0" >> /etc/fstab - # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it - elif ! grep "$mount_point_match_regexp" /etc/fstab | grep "nosuid"; then - previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}') - sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,nosuid|" /etc/fstab - fi - - - if mkdir -p "/var/log/audit"; then - if mountpoint -q "/var/log/audit"; then - mount -o remount --target "/var/log/audit" - fi - fi -} - -perform_remediation - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: 'Add nosuid Option to /var/log/audit: Check information associated to mountpoint' - command: findmnt --fstab '/var/log/audit' - register: device_name - failed_when: device_name.rc > 1 - changed_when: false - when: ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", - "container"] and "/var/log/audit" in ansible_mounts | map(attribute="mount") | - list ) - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_var_log_audit_nosuid - - no_reboot_needed - -- name: 'Add nosuid Option to /var/log/audit: Create mount_info dictionary variable' - set_fact: - mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' - with_together: - - '{{ device_name.stdout_lines[0].split() | list | lower }}' - - '{{ device_name.stdout_lines[1].split() | list }}' - when: - - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - and "/var/log/audit" in ansible_mounts | map(attribute="mount") | list ) - - device_name.stdout is defined and device_name.stdout_lines is defined - - (device_name.stdout | length > 0) - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_var_log_audit_nosuid - - no_reboot_needed - -- name: 'Add nosuid Option to /var/log/audit: If /var/log/audit not mounted, craft - mount_info manually' - set_fact: - mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' - with_together: - - - target - - source - - fstype - - options - - - /var/log/audit - - '' - - '' - - defaults - when: - - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - and "/var/log/audit" in ansible_mounts | map(attribute="mount") | list ) - - ("--fstab" | length == 0) - - (device_name.stdout | length == 0) - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_var_log_audit_nosuid - - no_reboot_needed - -- name: 'Add nosuid Option to /var/log/audit: Make sure nosuid option is part of the - to /var/log/audit options' - set_fact: - mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',nosuid'' - }) }}' - when: - - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - and "/var/log/audit" in ansible_mounts | map(attribute="mount") | list ) - - mount_info is defined and "nosuid" not in mount_info.options - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_var_log_audit_nosuid - - no_reboot_needed - -- name: 'Add nosuid Option to /var/log/audit: Ensure /var/log/audit is mounted with - nosuid option' - mount: - path: /var/log/audit - src: '{{ mount_info.source }}' - opts: '{{ mount_info.options }}' - state: mounted - fstype: '{{ mount_info.fstype }}' - when: - - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - and "/var/log/audit" in ansible_mounts | map(attribute="mount") | list ) - - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" - | length == 0) - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_var_log_audit_nosuid - - no_reboot_needed - - -part /var/log/audit --mountoptions="nosuid" - - - - - - - - - - Add nodev Option to /var/log - The nodev mount option can be used to prevent device files from -being created in /var/log. -Legitimate character and block devices should exist only in -the /dev directory on the root partition or within chroot -jails built for system services. -Add the nodev option to the fourth column of -/etc/fstab for the line which controls mounting of -/var/log. - CCI-001764 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 - CM-7(a) - CM-7(b) - CM-6(a) - AC-6 - AC-6(1) - MP-7 - PR.IP-1 - PR.PT-2 - PR.PT-3 - SRG-OS-000368-GPOS-00154 - The only legitimate location for device files is the /dev directory -located on the root partition. The only exception to this is chroot jails. - - # Remediation is applicable only in certain platforms -if ( [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && findmnt --kernel "/var/log" > /dev/null || findmnt --fstab "/var/log" > /dev/null ); then - -function perform_remediation { - - mount_point_match_regexp="$(printf "[^#].*[[:space:]]%s[[:space:]]" "/var/log")" - - grep "$mount_point_match_regexp" -q /etc/fstab \ - || { echo "The mount point '/var/log' is not even in /etc/fstab, so we can't set up mount options" >&2; - echo "Not remediating, because there is no record of /var/log in /etc/fstab" >&2; return 1; } - - - - mount_point_match_regexp="$(printf "[^#].*[[:space:]]%s[[:space:]]" /var/log)" - - # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab - if ! grep "$mount_point_match_regexp" /etc/fstab; then - # runtime opts without some automatic kernel/userspace-added defaults - previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 | awk '{print $4}' \ - | sed -E "s/(rw|defaults|seclabel|nodev)(,|$)//g;s/,$//") - [ "$previous_mount_opts" ] && previous_mount_opts+="," - # In iso9660 filesystems mtab could describe a "blocksize" value, this should be reflected in - # fstab as "block". The next variable is to satisfy shellcheck SC2050. - fs_type="" - if [ "$fs_type" == "iso9660" ] ; then - previous_mount_opts=$(sed 's/blocksize=/block=/' <<< "$previous_mount_opts") - fi - echo " /var/log defaults,${previous_mount_opts}nodev 0 0" >> /etc/fstab - # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it - elif ! grep "$mount_point_match_regexp" /etc/fstab | grep "nodev"; then - previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}') - sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,nodev|" /etc/fstab - fi - - - if mkdir -p "/var/log"; then - if mountpoint -q "/var/log"; then - mount -o remount --target "/var/log" - fi - fi -} - -perform_remediation - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: 'Add nodev Option to /var/log: Check information associated to mountpoint' - command: findmnt --fstab '/var/log' - register: device_name - failed_when: device_name.rc > 1 - changed_when: false - when: ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", - "container"] and "/var/log" in ansible_mounts | map(attribute="mount") | list - ) - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_var_log_nodev - - no_reboot_needed - -- name: 'Add nodev Option to /var/log: Create mount_info dictionary variable' - set_fact: - mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' - with_together: - - '{{ device_name.stdout_lines[0].split() | list | lower }}' - - '{{ device_name.stdout_lines[1].split() | list }}' - when: - - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - and "/var/log" in ansible_mounts | map(attribute="mount") | list ) - - device_name.stdout is defined and device_name.stdout_lines is defined - - (device_name.stdout | length > 0) - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_var_log_nodev - - no_reboot_needed - -- name: 'Add nodev Option to /var/log: If /var/log not mounted, craft mount_info manually' - set_fact: - mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' - with_together: - - - target - - source - - fstype - - options - - - /var/log - - '' - - '' - - defaults - when: - - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - and "/var/log" in ansible_mounts | map(attribute="mount") | list ) - - ("--fstab" | length == 0) - - (device_name.stdout | length == 0) - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_var_log_nodev - - no_reboot_needed - -- name: 'Add nodev Option to /var/log: Make sure nodev option is part of the to /var/log - options' - set_fact: - mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',nodev'' - }) }}' - when: - - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - and "/var/log" in ansible_mounts | map(attribute="mount") | list ) - - mount_info is defined and "nodev" not in mount_info.options - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_var_log_nodev - - no_reboot_needed - -- name: 'Add nodev Option to /var/log: Ensure /var/log is mounted with nodev option' - mount: - path: /var/log - src: '{{ mount_info.source }}' - opts: '{{ mount_info.options }}' - state: mounted - fstype: '{{ mount_info.fstype }}' - when: - - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - and "/var/log" in ansible_mounts | map(attribute="mount") | list ) - - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" - | length == 0) - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_var_log_nodev - - no_reboot_needed - - -part /var/log --mountoptions="nodev" - - - - - - - - - - Add noexec Option to /var/log - The noexec mount option can be used to prevent binaries -from being executed out of /var/log. -Add the noexec option to the fourth column of -/etc/fstab for the line which controls mounting of -/var/log. - BP28(R12) - CCI-001764 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 - CM-7(a) - CM-7(b) - CM-6(a) - AC-6 - AC-6(1) - MP-7 - PR.IP-1 - PR.PT-2 - PR.PT-3 - SRG-OS-000368-GPOS-00154 - Allowing users to execute binaries from directories containing log files -such as /var/log should never be necessary in normal operation and -can expose the system to potential compromise. - - # Remediation is applicable only in certain platforms -if ( [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && findmnt --kernel "/var/log" > /dev/null || findmnt --fstab "/var/log" > /dev/null ); then - -function perform_remediation { - - mount_point_match_regexp="$(printf "[^#].*[[:space:]]%s[[:space:]]" "/var/log")" - - grep "$mount_point_match_regexp" -q /etc/fstab \ - || { echo "The mount point '/var/log' is not even in /etc/fstab, so we can't set up mount options" >&2; - echo "Not remediating, because there is no record of /var/log in /etc/fstab" >&2; return 1; } - - - - mount_point_match_regexp="$(printf "[^#].*[[:space:]]%s[[:space:]]" /var/log)" - - # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab - if ! grep "$mount_point_match_regexp" /etc/fstab; then - # runtime opts without some automatic kernel/userspace-added defaults - previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 | awk '{print $4}' \ - | sed -E "s/(rw|defaults|seclabel|noexec)(,|$)//g;s/,$//") - [ "$previous_mount_opts" ] && previous_mount_opts+="," - # In iso9660 filesystems mtab could describe a "blocksize" value, this should be reflected in - # fstab as "block". The next variable is to satisfy shellcheck SC2050. - fs_type="" - if [ "$fs_type" == "iso9660" ] ; then - previous_mount_opts=$(sed 's/blocksize=/block=/' <<< "$previous_mount_opts") - fi - echo " /var/log defaults,${previous_mount_opts}noexec 0 0" >> /etc/fstab - # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it - elif ! grep "$mount_point_match_regexp" /etc/fstab | grep "noexec"; then - previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}') - sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,noexec|" /etc/fstab - fi - - - if mkdir -p "/var/log"; then - if mountpoint -q "/var/log"; then - mount -o remount --target "/var/log" - fi - fi -} - -perform_remediation - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: 'Add noexec Option to /var/log: Check information associated to mountpoint' - command: findmnt --fstab '/var/log' - register: device_name - failed_when: device_name.rc > 1 - changed_when: false - when: ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", - "container"] and "/var/log" in ansible_mounts | map(attribute="mount") | list - ) - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_var_log_noexec - - no_reboot_needed - -- name: 'Add noexec Option to /var/log: Create mount_info dictionary variable' - set_fact: - mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' - with_together: - - '{{ device_name.stdout_lines[0].split() | list | lower }}' - - '{{ device_name.stdout_lines[1].split() | list }}' - when: - - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - and "/var/log" in ansible_mounts | map(attribute="mount") | list ) - - device_name.stdout is defined and device_name.stdout_lines is defined - - (device_name.stdout | length > 0) - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_var_log_noexec - - no_reboot_needed - -- name: 'Add noexec Option to /var/log: If /var/log not mounted, craft mount_info - manually' - set_fact: - mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' - with_together: - - - target - - source - - fstype - - options - - - /var/log - - '' - - '' - - defaults - when: - - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - and "/var/log" in ansible_mounts | map(attribute="mount") | list ) - - ("--fstab" | length == 0) - - (device_name.stdout | length == 0) - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_var_log_noexec - - no_reboot_needed - -- name: 'Add noexec Option to /var/log: Make sure noexec option is part of the to - /var/log options' - set_fact: - mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',noexec'' - }) }}' - when: - - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - and "/var/log" in ansible_mounts | map(attribute="mount") | list ) - - mount_info is defined and "noexec" not in mount_info.options - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_var_log_noexec - - no_reboot_needed - -- name: 'Add noexec Option to /var/log: Ensure /var/log is mounted with noexec option' - mount: - path: /var/log - src: '{{ mount_info.source }}' - opts: '{{ mount_info.options }}' - state: mounted - fstype: '{{ mount_info.fstype }}' - when: - - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - and "/var/log" in ansible_mounts | map(attribute="mount") | list ) - - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" - | length == 0) - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_var_log_noexec - - no_reboot_needed - - -part /var/log --mountoptions="noexec" - - - - - - - - - - Add nosuid Option to /var/log - The nosuid mount option can be used to prevent -execution of setuid programs in /var/log. The SUID and SGID permissions -should not be required in directories containing log files. -Add the nosuid option to the fourth column of -/etc/fstab for the line which controls mounting of -/var/log. - BP28(R12) - CCI-001764 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 - CM-7(a) - CM-7(b) - CM-6(a) - AC-6 - AC-6(1) - MP-7 - PR.IP-1 - PR.PT-2 - PR.PT-3 - SRG-OS-000368-GPOS-00154 - The presence of SUID and SGID executables should be tightly controlled. Users -should not be able to execute SUID or SGID binaries from partitions -designated for log files. - - # Remediation is applicable only in certain platforms -if ( [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && findmnt --kernel "/var/log" > /dev/null || findmnt --fstab "/var/log" > /dev/null ); then - -function perform_remediation { - - mount_point_match_regexp="$(printf "[^#].*[[:space:]]%s[[:space:]]" "/var/log")" - - grep "$mount_point_match_regexp" -q /etc/fstab \ - || { echo "The mount point '/var/log' is not even in /etc/fstab, so we can't set up mount options" >&2; - echo "Not remediating, because there is no record of /var/log in /etc/fstab" >&2; return 1; } - - - - mount_point_match_regexp="$(printf "[^#].*[[:space:]]%s[[:space:]]" /var/log)" - - # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab - if ! grep "$mount_point_match_regexp" /etc/fstab; then - # runtime opts without some automatic kernel/userspace-added defaults - previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 | awk '{print $4}' \ - | sed -E "s/(rw|defaults|seclabel|nosuid)(,|$)//g;s/,$//") - [ "$previous_mount_opts" ] && previous_mount_opts+="," - # In iso9660 filesystems mtab could describe a "blocksize" value, this should be reflected in - # fstab as "block". The next variable is to satisfy shellcheck SC2050. - fs_type="" - if [ "$fs_type" == "iso9660" ] ; then - previous_mount_opts=$(sed 's/blocksize=/block=/' <<< "$previous_mount_opts") - fi - echo " /var/log defaults,${previous_mount_opts}nosuid 0 0" >> /etc/fstab - # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it - elif ! grep "$mount_point_match_regexp" /etc/fstab | grep "nosuid"; then - previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}') - sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,nosuid|" /etc/fstab - fi - - - if mkdir -p "/var/log"; then - if mountpoint -q "/var/log"; then - mount -o remount --target "/var/log" - fi - fi -} - -perform_remediation - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: 'Add nosuid Option to /var/log: Check information associated to mountpoint' - command: findmnt --fstab '/var/log' - register: device_name - failed_when: device_name.rc > 1 - changed_when: false - when: ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", - "container"] and "/var/log" in ansible_mounts | map(attribute="mount") | list - ) - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_var_log_nosuid - - no_reboot_needed - -- name: 'Add nosuid Option to /var/log: Create mount_info dictionary variable' - set_fact: - mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' - with_together: - - '{{ device_name.stdout_lines[0].split() | list | lower }}' - - '{{ device_name.stdout_lines[1].split() | list }}' - when: - - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - and "/var/log" in ansible_mounts | map(attribute="mount") | list ) - - device_name.stdout is defined and device_name.stdout_lines is defined - - (device_name.stdout | length > 0) - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_var_log_nosuid - - no_reboot_needed - -- name: 'Add nosuid Option to /var/log: If /var/log not mounted, craft mount_info - manually' - set_fact: - mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' - with_together: - - - target - - source - - fstype - - options - - - /var/log - - '' - - '' - - defaults - when: - - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - and "/var/log" in ansible_mounts | map(attribute="mount") | list ) - - ("--fstab" | length == 0) - - (device_name.stdout | length == 0) - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_var_log_nosuid - - no_reboot_needed - -- name: 'Add nosuid Option to /var/log: Make sure nosuid option is part of the to - /var/log options' - set_fact: - mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',nosuid'' - }) }}' - when: - - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - and "/var/log" in ansible_mounts | map(attribute="mount") | list ) - - mount_info is defined and "nosuid" not in mount_info.options - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_var_log_nosuid - - no_reboot_needed - -- name: 'Add nosuid Option to /var/log: Ensure /var/log is mounted with nosuid option' - mount: - path: /var/log - src: '{{ mount_info.source }}' - opts: '{{ mount_info.options }}' - state: mounted - fstype: '{{ mount_info.fstype }}' - when: - - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - and "/var/log" in ansible_mounts | map(attribute="mount") | list ) - - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" - | length == 0) - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_var_log_nosuid - - no_reboot_needed - - -part /var/log --mountoptions="nosuid" - - - - - - - - - - Add nodev Option to /var - The nodev mount option can be used to prevent device files from -being created in /var. -Legitimate character and block devices should exist only in -the /dev directory on the root partition or within chroot -jails built for system services. -Add the nodev option to the fourth column of -/etc/fstab for the line which controls mounting of -/var. - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 - CM-7(a) - CM-7(b) - CM-6(a) - AC-6 - AC-6(1) - MP-7 - PR.IP-1 - PR.PT-2 - PR.PT-3 - SRG-OS-000368-GPOS-00154 - The only legitimate location for device files is the /dev directory -located on the root partition. The only exception to this is chroot jails. - - # Remediation is applicable only in certain platforms -if ( [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && findmnt --kernel "/var" > /dev/null || findmnt --fstab "/var" > /dev/null ); then - -function perform_remediation { - - mount_point_match_regexp="$(printf "[^#].*[[:space:]]%s[[:space:]]" "/var")" - - grep "$mount_point_match_regexp" -q /etc/fstab \ - || { echo "The mount point '/var' is not even in /etc/fstab, so we can't set up mount options" >&2; - echo "Not remediating, because there is no record of /var in /etc/fstab" >&2; return 1; } - - - - mount_point_match_regexp="$(printf "[^#].*[[:space:]]%s[[:space:]]" /var)" - - # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab - if ! grep "$mount_point_match_regexp" /etc/fstab; then - # runtime opts without some automatic kernel/userspace-added defaults - previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 | awk '{print $4}' \ - | sed -E "s/(rw|defaults|seclabel|nodev)(,|$)//g;s/,$//") - [ "$previous_mount_opts" ] && previous_mount_opts+="," - # In iso9660 filesystems mtab could describe a "blocksize" value, this should be reflected in - # fstab as "block". The next variable is to satisfy shellcheck SC2050. - fs_type="" - if [ "$fs_type" == "iso9660" ] ; then - previous_mount_opts=$(sed 's/blocksize=/block=/' <<< "$previous_mount_opts") - fi - echo " /var defaults,${previous_mount_opts}nodev 0 0" >> /etc/fstab - # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it - elif ! grep "$mount_point_match_regexp" /etc/fstab | grep "nodev"; then - previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}') - sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,nodev|" /etc/fstab - fi - - - if mkdir -p "/var"; then - if mountpoint -q "/var"; then - mount -o remount --target "/var" - fi - fi -} - -perform_remediation - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: 'Add nodev Option to /var: Check information associated to mountpoint' - command: findmnt --fstab '/var' - register: device_name - failed_when: device_name.rc > 1 - changed_when: false - when: ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", - "container"] and "/var" in ansible_mounts | map(attribute="mount") | list ) - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_var_nodev - - no_reboot_needed - -- name: 'Add nodev Option to /var: Create mount_info dictionary variable' - set_fact: - mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' - with_together: - - '{{ device_name.stdout_lines[0].split() | list | lower }}' - - '{{ device_name.stdout_lines[1].split() | list }}' - when: - - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - and "/var" in ansible_mounts | map(attribute="mount") | list ) - - device_name.stdout is defined and device_name.stdout_lines is defined - - (device_name.stdout | length > 0) - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_var_nodev - - no_reboot_needed - -- name: 'Add nodev Option to /var: If /var not mounted, craft mount_info manually' - set_fact: - mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' - with_together: - - - target - - source - - fstype - - options - - - /var - - '' - - '' - - defaults - when: - - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - and "/var" in ansible_mounts | map(attribute="mount") | list ) - - ("--fstab" | length == 0) - - (device_name.stdout | length == 0) - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_var_nodev - - no_reboot_needed - -- name: 'Add nodev Option to /var: Make sure nodev option is part of the to /var options' - set_fact: - mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',nodev'' - }) }}' - when: - - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - and "/var" in ansible_mounts | map(attribute="mount") | list ) - - mount_info is defined and "nodev" not in mount_info.options - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_var_nodev - - no_reboot_needed - -- name: 'Add nodev Option to /var: Ensure /var is mounted with nodev option' - mount: - path: /var - src: '{{ mount_info.source }}' - opts: '{{ mount_info.options }}' - state: mounted - fstype: '{{ mount_info.fstype }}' - when: - - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - and "/var" in ansible_mounts | map(attribute="mount") | list ) - - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" - | length == 0) - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_var_nodev - - no_reboot_needed - - -part /var --mountoptions="nodev" - - - - - - - - - - Add noexec Option to /var - The noexec mount option can be used to prevent binaries from being -executed out of /var. -Add the noexec option to the fourth column of -/etc/fstab for the line which controls mounting of -/var. - BP28(R12) - The /var directory contains variable system data such as logs, -mails and caches. No binaries should be executed from this directory. - - # Remediation is applicable only in certain platforms -if ( [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && findmnt --kernel "/var" > /dev/null || findmnt --fstab "/var" > /dev/null ); then - -function perform_remediation { - - mount_point_match_regexp="$(printf "[^#].*[[:space:]]%s[[:space:]]" "/var")" - - grep "$mount_point_match_regexp" -q /etc/fstab \ - || { echo "The mount point '/var' is not even in /etc/fstab, so we can't set up mount options" >&2; - echo "Not remediating, because there is no record of /var in /etc/fstab" >&2; return 1; } - - - - mount_point_match_regexp="$(printf "[^#].*[[:space:]]%s[[:space:]]" /var)" - - # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab - if ! grep "$mount_point_match_regexp" /etc/fstab; then - # runtime opts without some automatic kernel/userspace-added defaults - previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 | awk '{print $4}' \ - | sed -E "s/(rw|defaults|seclabel|noexec)(,|$)//g;s/,$//") - [ "$previous_mount_opts" ] && previous_mount_opts+="," - # In iso9660 filesystems mtab could describe a "blocksize" value, this should be reflected in - # fstab as "block". The next variable is to satisfy shellcheck SC2050. - fs_type="" - if [ "$fs_type" == "iso9660" ] ; then - previous_mount_opts=$(sed 's/blocksize=/block=/' <<< "$previous_mount_opts") - fi - echo " /var defaults,${previous_mount_opts}noexec 0 0" >> /etc/fstab - # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it - elif ! grep "$mount_point_match_regexp" /etc/fstab | grep "noexec"; then - previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}') - sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,noexec|" /etc/fstab - fi - - - if mkdir -p "/var"; then - if mountpoint -q "/var"; then - mount -o remount --target "/var" - fi - fi -} - -perform_remediation - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: 'Add noexec Option to /var: Check information associated to mountpoint' - command: findmnt --fstab '/var' - register: device_name - failed_when: device_name.rc > 1 - changed_when: false - when: ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", - "container"] and "/var" in ansible_mounts | map(attribute="mount") | list ) - tags: - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_var_noexec - - no_reboot_needed - -- name: 'Add noexec Option to /var: Create mount_info dictionary variable' - set_fact: - mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' - with_together: - - '{{ device_name.stdout_lines[0].split() | list | lower }}' - - '{{ device_name.stdout_lines[1].split() | list }}' - when: - - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - and "/var" in ansible_mounts | map(attribute="mount") | list ) - - device_name.stdout is defined and device_name.stdout_lines is defined - - (device_name.stdout | length > 0) - tags: - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_var_noexec - - no_reboot_needed - -- name: 'Add noexec Option to /var: If /var not mounted, craft mount_info manually' - set_fact: - mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' - with_together: - - - target - - source - - fstype - - options - - - /var - - '' - - '' - - defaults - when: - - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - and "/var" in ansible_mounts | map(attribute="mount") | list ) - - ("--fstab" | length == 0) - - (device_name.stdout | length == 0) - tags: - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_var_noexec - - no_reboot_needed - -- name: 'Add noexec Option to /var: Make sure noexec option is part of the to /var - options' - set_fact: - mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',noexec'' - }) }}' - when: - - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - and "/var" in ansible_mounts | map(attribute="mount") | list ) - - mount_info is defined and "noexec" not in mount_info.options - tags: - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_var_noexec - - no_reboot_needed - -- name: 'Add noexec Option to /var: Ensure /var is mounted with noexec option' - mount: - path: /var - src: '{{ mount_info.source }}' - opts: '{{ mount_info.options }}' - state: mounted - fstype: '{{ mount_info.fstype }}' - when: - - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - and "/var" in ansible_mounts | map(attribute="mount") | list ) - - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" - | length == 0) - tags: - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_var_noexec - - no_reboot_needed - - -part /var --mountoptions="noexec" - - - - - - - - - - Add nosuid Option to /var - The nosuid mount option can be used to prevent -execution of setuid programs in /var. The SUID and SGID permissions -should not be required for this directory. -Add the nosuid option to the fourth column of -/etc/fstab for the line which controls mounting of -/var. - BP28(R12) - The presence of SUID and SGID executables should be tightly controlled. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -function perform_remediation { - - mount_point_match_regexp="$(printf "[^#].*[[:space:]]%s[[:space:]]" "/var")" - - grep "$mount_point_match_regexp" -q /etc/fstab \ - || { echo "The mount point '/var' is not even in /etc/fstab, so we can't set up mount options" >&2; - echo "Not remediating, because there is no record of /var in /etc/fstab" >&2; return 1; } - - - - mount_point_match_regexp="$(printf "[^#].*[[:space:]]%s[[:space:]]" /var)" - - # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab - if ! grep "$mount_point_match_regexp" /etc/fstab; then - # runtime opts without some automatic kernel/userspace-added defaults - previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 | awk '{print $4}' \ - | sed -E "s/(rw|defaults|seclabel|nosuid)(,|$)//g;s/,$//") - [ "$previous_mount_opts" ] && previous_mount_opts+="," - # In iso9660 filesystems mtab could describe a "blocksize" value, this should be reflected in - # fstab as "block". The next variable is to satisfy shellcheck SC2050. - fs_type="" - if [ "$fs_type" == "iso9660" ] ; then - previous_mount_opts=$(sed 's/blocksize=/block=/' <<< "$previous_mount_opts") - fi - echo " /var defaults,${previous_mount_opts}nosuid 0 0" >> /etc/fstab - # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it - elif ! grep "$mount_point_match_regexp" /etc/fstab | grep "nosuid"; then - previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}') - sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,nosuid|" /etc/fstab - fi - - - if mkdir -p "/var"; then - if mountpoint -q "/var"; then - mount -o remount --target "/var" - fi - fi -} - -perform_remediation - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: 'Add nosuid Option to /var: Check information associated to mountpoint' - command: findmnt --fstab '/var' - register: device_name - failed_when: device_name.rc > 1 - changed_when: false - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - configure_strategy - - high_disruption - - low_complexity - - mount_option_var_nosuid - - no_reboot_needed - - unknown_severity - -- name: 'Add nosuid Option to /var: Create mount_info dictionary variable' - set_fact: - mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' - with_together: - - '{{ device_name.stdout_lines[0].split() | list | lower }}' - - '{{ device_name.stdout_lines[1].split() | list }}' - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - device_name.stdout is defined and device_name.stdout_lines is defined - - (device_name.stdout | length > 0) - tags: - - configure_strategy - - high_disruption - - low_complexity - - mount_option_var_nosuid - - no_reboot_needed - - unknown_severity - -- name: 'Add nosuid Option to /var: If /var not mounted, craft mount_info manually' - set_fact: - mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' - with_together: - - - target - - source - - fstype - - options - - - /var - - '' - - '' - - defaults - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - ("--fstab" | length == 0) - - (device_name.stdout | length == 0) - tags: - - configure_strategy - - high_disruption - - low_complexity - - mount_option_var_nosuid - - no_reboot_needed - - unknown_severity - -- name: 'Add nosuid Option to /var: Make sure nosuid option is part of the to /var - options' - set_fact: - mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',nosuid'' - }) }}' - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - mount_info is defined and "nosuid" not in mount_info.options - tags: - - configure_strategy - - high_disruption - - low_complexity - - mount_option_var_nosuid - - no_reboot_needed - - unknown_severity - -- name: 'Add nosuid Option to /var: Ensure /var is mounted with nosuid option' - mount: - path: /var - src: '{{ mount_info.source }}' - opts: '{{ mount_info.options }}' - state: mounted - fstype: '{{ mount_info.fstype }}' - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" - | length == 0) - tags: - - configure_strategy - - high_disruption - - low_complexity - - mount_option_var_nosuid - - no_reboot_needed - - unknown_severity - - -part /var --mountoptions="nosuid" - - - - - - - - - - Add nodev Option to /var/tmp - The nodev mount option can be used to prevent device files from -being created in /var/tmp. Legitimate character and block devices -should not exist within temporary directories like /var/tmp. -Add the nodev option to the fourth column of -/etc/fstab for the line which controls mounting of -/var/tmp. - BP28(R12) - CCI-001764 - SRG-OS-000368-GPOS-00154 - The only legitimate location for device files is the /dev directory -located on the root partition. The only exception to this is chroot jails. - - # Remediation is applicable only in certain platforms -if ( [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && findmnt --kernel "/var/tmp" > /dev/null || findmnt --fstab "/var/tmp" > /dev/null ); then - -function perform_remediation { - - mount_point_match_regexp="$(printf "[^#].*[[:space:]]%s[[:space:]]" "/var/tmp")" - - grep "$mount_point_match_regexp" -q /etc/fstab \ - || { echo "The mount point '/var/tmp' is not even in /etc/fstab, so we can't set up mount options" >&2; - echo "Not remediating, because there is no record of /var/tmp in /etc/fstab" >&2; return 1; } - - - - mount_point_match_regexp="$(printf "[^#].*[[:space:]]%s[[:space:]]" /var/tmp)" - - # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab - if ! grep "$mount_point_match_regexp" /etc/fstab; then - # runtime opts without some automatic kernel/userspace-added defaults - previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 | awk '{print $4}' \ - | sed -E "s/(rw|defaults|seclabel|nodev)(,|$)//g;s/,$//") - [ "$previous_mount_opts" ] && previous_mount_opts+="," - # In iso9660 filesystems mtab could describe a "blocksize" value, this should be reflected in - # fstab as "block". The next variable is to satisfy shellcheck SC2050. - fs_type="" - if [ "$fs_type" == "iso9660" ] ; then - previous_mount_opts=$(sed 's/blocksize=/block=/' <<< "$previous_mount_opts") - fi - echo " /var/tmp defaults,${previous_mount_opts}nodev 0 0" >> /etc/fstab - # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it - elif ! grep "$mount_point_match_regexp" /etc/fstab | grep "nodev"; then - previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}') - sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,nodev|" /etc/fstab - fi - - - if mkdir -p "/var/tmp"; then - if mountpoint -q "/var/tmp"; then - mount -o remount --target "/var/tmp" - fi - fi -} - -perform_remediation - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: 'Add nodev Option to /var/tmp: Check information associated to mountpoint' - command: findmnt --fstab '/var/tmp' - register: device_name - failed_when: device_name.rc > 1 - changed_when: false - when: ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", - "container"] and "/var/tmp" in ansible_mounts | map(attribute="mount") | list - ) - tags: - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_var_tmp_nodev - - no_reboot_needed - -- name: 'Add nodev Option to /var/tmp: Create mount_info dictionary variable' - set_fact: - mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' - with_together: - - '{{ device_name.stdout_lines[0].split() | list | lower }}' - - '{{ device_name.stdout_lines[1].split() | list }}' - when: - - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - and "/var/tmp" in ansible_mounts | map(attribute="mount") | list ) - - device_name.stdout is defined and device_name.stdout_lines is defined - - (device_name.stdout | length > 0) - tags: - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_var_tmp_nodev - - no_reboot_needed - -- name: 'Add nodev Option to /var/tmp: If /var/tmp not mounted, craft mount_info manually' - set_fact: - mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' - with_together: - - - target - - source - - fstype - - options - - - /var/tmp - - '' - - '' - - defaults - when: - - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - and "/var/tmp" in ansible_mounts | map(attribute="mount") | list ) - - ("--fstab" | length == 0) - - (device_name.stdout | length == 0) - tags: - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_var_tmp_nodev - - no_reboot_needed - -- name: 'Add nodev Option to /var/tmp: Make sure nodev option is part of the to /var/tmp - options' - set_fact: - mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',nodev'' - }) }}' - when: - - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - and "/var/tmp" in ansible_mounts | map(attribute="mount") | list ) - - mount_info is defined and "nodev" not in mount_info.options - tags: - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_var_tmp_nodev - - no_reboot_needed - -- name: 'Add nodev Option to /var/tmp: Ensure /var/tmp is mounted with nodev option' - mount: - path: /var/tmp - src: '{{ mount_info.source }}' - opts: '{{ mount_info.options }}' - state: mounted - fstype: '{{ mount_info.fstype }}' - when: - - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - and "/var/tmp" in ansible_mounts | map(attribute="mount") | list ) - - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" - | length == 0) - tags: - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_var_tmp_nodev - - no_reboot_needed - - -part /var/tmp --mountoptions="nodev" - - - - - - - - - - Add noexec Option to /var/tmp - The noexec mount option can be used to prevent binaries -from being executed out of /var/tmp. -Add the noexec option to the fourth column of -/etc/fstab for the line which controls mounting of -/var/tmp. - BP28(R12) - CCI-001764 - SRG-OS-000368-GPOS-00154 - Allowing users to execute binaries from world-writable directories -such as /var/tmp should never be necessary in normal operation and -can expose the system to potential compromise. - - # Remediation is applicable only in certain platforms -if ( [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && findmnt --kernel "/var/tmp" > /dev/null || findmnt --fstab "/var/tmp" > /dev/null ); then - -function perform_remediation { - - mount_point_match_regexp="$(printf "[^#].*[[:space:]]%s[[:space:]]" "/var/tmp")" - - grep "$mount_point_match_regexp" -q /etc/fstab \ - || { echo "The mount point '/var/tmp' is not even in /etc/fstab, so we can't set up mount options" >&2; - echo "Not remediating, because there is no record of /var/tmp in /etc/fstab" >&2; return 1; } - - - - mount_point_match_regexp="$(printf "[^#].*[[:space:]]%s[[:space:]]" /var/tmp)" - - # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab - if ! grep "$mount_point_match_regexp" /etc/fstab; then - # runtime opts without some automatic kernel/userspace-added defaults - previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 | awk '{print $4}' \ - | sed -E "s/(rw|defaults|seclabel|noexec)(,|$)//g;s/,$//") - [ "$previous_mount_opts" ] && previous_mount_opts+="," - # In iso9660 filesystems mtab could describe a "blocksize" value, this should be reflected in - # fstab as "block". The next variable is to satisfy shellcheck SC2050. - fs_type="" - if [ "$fs_type" == "iso9660" ] ; then - previous_mount_opts=$(sed 's/blocksize=/block=/' <<< "$previous_mount_opts") - fi - echo " /var/tmp defaults,${previous_mount_opts}noexec 0 0" >> /etc/fstab - # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it - elif ! grep "$mount_point_match_regexp" /etc/fstab | grep "noexec"; then - previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}') - sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,noexec|" /etc/fstab - fi - - - if mkdir -p "/var/tmp"; then - if mountpoint -q "/var/tmp"; then - mount -o remount --target "/var/tmp" - fi - fi -} - -perform_remediation - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: 'Add noexec Option to /var/tmp: Check information associated to mountpoint' - command: findmnt --fstab '/var/tmp' - register: device_name - failed_when: device_name.rc > 1 - changed_when: false - when: ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", - "container"] and "/var/tmp" in ansible_mounts | map(attribute="mount") | list - ) - tags: - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_var_tmp_noexec - - no_reboot_needed - -- name: 'Add noexec Option to /var/tmp: Create mount_info dictionary variable' - set_fact: - mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' - with_together: - - '{{ device_name.stdout_lines[0].split() | list | lower }}' - - '{{ device_name.stdout_lines[1].split() | list }}' - when: - - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - and "/var/tmp" in ansible_mounts | map(attribute="mount") | list ) - - device_name.stdout is defined and device_name.stdout_lines is defined - - (device_name.stdout | length > 0) - tags: - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_var_tmp_noexec - - no_reboot_needed - -- name: 'Add noexec Option to /var/tmp: If /var/tmp not mounted, craft mount_info - manually' - set_fact: - mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' - with_together: - - - target - - source - - fstype - - options - - - /var/tmp - - '' - - '' - - defaults - when: - - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - and "/var/tmp" in ansible_mounts | map(attribute="mount") | list ) - - ("--fstab" | length == 0) - - (device_name.stdout | length == 0) - tags: - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_var_tmp_noexec - - no_reboot_needed - -- name: 'Add noexec Option to /var/tmp: Make sure noexec option is part of the to - /var/tmp options' - set_fact: - mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',noexec'' - }) }}' - when: - - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - and "/var/tmp" in ansible_mounts | map(attribute="mount") | list ) - - mount_info is defined and "noexec" not in mount_info.options - tags: - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_var_tmp_noexec - - no_reboot_needed - -- name: 'Add noexec Option to /var/tmp: Ensure /var/tmp is mounted with noexec option' - mount: - path: /var/tmp - src: '{{ mount_info.source }}' - opts: '{{ mount_info.options }}' - state: mounted - fstype: '{{ mount_info.fstype }}' - when: - - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - and "/var/tmp" in ansible_mounts | map(attribute="mount") | list ) - - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" - | length == 0) - tags: - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_var_tmp_noexec - - no_reboot_needed - - -part /var/tmp --mountoptions="noexec" - - - - - - - - - - Add nosuid Option to /var/tmp - The nosuid mount option can be used to prevent -execution of setuid programs in /var/tmp. The SUID and SGID permissions -should not be required in these world-writable directories. -Add the nosuid option to the fourth column of -/etc/fstab for the line which controls mounting of -/var/tmp. - BP28(R12) - CCI-001764 - SRG-OS-000368-GPOS-00154 - The presence of SUID and SGID executables should be tightly controlled. Users -should not be able to execute SUID or SGID binaries from temporary storage partitions. - - # Remediation is applicable only in certain platforms -if ( [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && findmnt --kernel "/var/tmp" > /dev/null || findmnt --fstab "/var/tmp" > /dev/null ); then - -function perform_remediation { - - mount_point_match_regexp="$(printf "[^#].*[[:space:]]%s[[:space:]]" "/var/tmp")" - - grep "$mount_point_match_regexp" -q /etc/fstab \ - || { echo "The mount point '/var/tmp' is not even in /etc/fstab, so we can't set up mount options" >&2; - echo "Not remediating, because there is no record of /var/tmp in /etc/fstab" >&2; return 1; } - - - - mount_point_match_regexp="$(printf "[^#].*[[:space:]]%s[[:space:]]" /var/tmp)" - - # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab - if ! grep "$mount_point_match_regexp" /etc/fstab; then - # runtime opts without some automatic kernel/userspace-added defaults - previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 | awk '{print $4}' \ - | sed -E "s/(rw|defaults|seclabel|nosuid)(,|$)//g;s/,$//") - [ "$previous_mount_opts" ] && previous_mount_opts+="," - # In iso9660 filesystems mtab could describe a "blocksize" value, this should be reflected in - # fstab as "block". The next variable is to satisfy shellcheck SC2050. - fs_type="" - if [ "$fs_type" == "iso9660" ] ; then - previous_mount_opts=$(sed 's/blocksize=/block=/' <<< "$previous_mount_opts") - fi - echo " /var/tmp defaults,${previous_mount_opts}nosuid 0 0" >> /etc/fstab - # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it - elif ! grep "$mount_point_match_regexp" /etc/fstab | grep "nosuid"; then - previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}') - sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,nosuid|" /etc/fstab - fi - - - if mkdir -p "/var/tmp"; then - if mountpoint -q "/var/tmp"; then - mount -o remount --target "/var/tmp" - fi - fi -} - -perform_remediation - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: 'Add nosuid Option to /var/tmp: Check information associated to mountpoint' - command: findmnt --fstab '/var/tmp' - register: device_name - failed_when: device_name.rc > 1 - changed_when: false - when: ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", - "container"] and "/var/tmp" in ansible_mounts | map(attribute="mount") | list - ) - tags: - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_var_tmp_nosuid - - no_reboot_needed - -- name: 'Add nosuid Option to /var/tmp: Create mount_info dictionary variable' - set_fact: - mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' - with_together: - - '{{ device_name.stdout_lines[0].split() | list | lower }}' - - '{{ device_name.stdout_lines[1].split() | list }}' - when: - - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - and "/var/tmp" in ansible_mounts | map(attribute="mount") | list ) - - device_name.stdout is defined and device_name.stdout_lines is defined - - (device_name.stdout | length > 0) - tags: - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_var_tmp_nosuid - - no_reboot_needed - -- name: 'Add nosuid Option to /var/tmp: If /var/tmp not mounted, craft mount_info - manually' - set_fact: - mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' - with_together: - - - target - - source - - fstype - - options - - - /var/tmp - - '' - - '' - - defaults - when: - - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - and "/var/tmp" in ansible_mounts | map(attribute="mount") | list ) - - ("--fstab" | length == 0) - - (device_name.stdout | length == 0) - tags: - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_var_tmp_nosuid - - no_reboot_needed - -- name: 'Add nosuid Option to /var/tmp: Make sure nosuid option is part of the to - /var/tmp options' - set_fact: - mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',nosuid'' - }) }}' - when: - - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - and "/var/tmp" in ansible_mounts | map(attribute="mount") | list ) - - mount_info is defined and "nosuid" not in mount_info.options - tags: - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_var_tmp_nosuid - - no_reboot_needed - -- name: 'Add nosuid Option to /var/tmp: Ensure /var/tmp is mounted with nosuid option' - mount: - path: /var/tmp - src: '{{ mount_info.source }}' - opts: '{{ mount_info.options }}' - state: mounted - fstype: '{{ mount_info.fstype }}' - when: - - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - and "/var/tmp" in ansible_mounts | map(attribute="mount") | list ) - - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" - | length == 0) - tags: - - configure_strategy - - high_disruption - - low_complexity - - medium_severity - - mount_option_var_tmp_nosuid - - no_reboot_needed - - -part /var/tmp --mountoptions="nosuid" - - - - - - - - - - - Verify Permissions on Important Files and -Directories Are Configured in /etc/permissions.local - Permissions for many files on a system must be set -restrictively to ensure sensitive information is properly protected. -This section discusses the /etc/permissions.local file, where -expected permissions can be configured to be checked and fixed through -usage of the chkstat command. - - - Restrict Programs from Dangerous Execution Patterns - The recommendations in this section are designed to -ensure that the system's features to protect against potentially -dangerous program execution are activated. -These protections are applied at the system initialization or -kernel level, and defend against certain types of badly-configured -or compromised programs. - - kernel.unprivileged_bpf_disabled - Prevent unprivileged processes from using the bpf() syscall. - 2 - 1 - 2 - - - Disable the uvcvideo module - If the device contains a camera it should be covered or disabled when not in use. - CCI-000381 - CM-7 (a) - CM-7 (5) (b) - SRG-OS-000095-GPOS-00049 - SRG-OS-000370-GPOS-00155 - Failing to disconnect from collaborative computing devices (i.e., cameras) can result in subsequent compromises of organizational information. -Providing easy methods to physically disconnect from such devices after a collaborative computing session helps to ensure participants actually carry out the disconnect activity without having to go through complex and tedious procedures. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -if LC_ALL=C grep -q -m 1 "^install uvcvideo" /etc/modprobe.d/uvcvideo.conf ; then - - sed -i 's#^install uvcvideo.*#install uvcvideo /bin/true#g' /etc/modprobe.d/uvcvideo.conf -else - echo -e "\n# Disable per security requirements" >> /etc/modprobe.d/uvcvideo.conf - echo "install uvcvideo /bin/true" >> /etc/modprobe.d/uvcvideo.conf -fi - -if ! LC_ALL=C grep -q -m 1 "^blacklist uvcvideo$" /etc/modprobe.d/uvcvideo.conf ; then - echo "blacklist uvcvideo" >> /etc/modprobe.d/uvcvideo.conf -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Ensure kernel module 'uvcvideo' is disabled - lineinfile: - create: true - dest: /etc/modprobe.d/uvcvideo.conf - regexp: install\s+uvcvideo - line: install uvcvideo /bin/true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-CM-7 (5) (b) - - NIST-800-53-CM-7 (a) - - disable_strategy - - kernel_module_uvcvideo_disabled - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - -- name: Ensure kernel module 'uvcvideo' is blacklisted - lineinfile: - create: true - dest: /etc/modprobe.d/uvcvideo.conf - regexp: ^blacklist uvcvideo$ - line: blacklist uvcvideo - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-CM-7 (5) (b) - - NIST-800-53-CM-7 (a) - - disable_strategy - - kernel_module_uvcvideo_disabled - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - - - - - - - - - Disable storing core dumps - To set the runtime status of the kernel.core_pattern kernel parameter, run the following command: $ sudo sysctl -w kernel.core_pattern=|/bin/false -To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: kernel.core_pattern = |/bin/false - CCI-000366 - SC-7(10) - FMT_SMF_EXT.1 - SRG-OS-000480-GPOS-00227 - A core dump includes a memory image taken at the time the operating system -terminates an application. The memory image could contain sensitive data and is generally useful -only for developers trying to debug problems. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Comment out any occurrences of kernel.core_pattern from /etc/sysctl.d/*.conf files - -for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do - - matching_list=$(grep -P '^(?!#).*[\s]*kernel.core_pattern.*$' $f | uniq ) - if ! test -z "$matching_list"; then - while IFS= read -r entry; do - escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") - # comment out "kernel.core_pattern" matches to preserve user data - sed -i "s/^${escaped_entry}$/# &/g" $f - done <<< "$matching_list" - fi -done - -# -# Set sysctl config file which to save the desired value -# - -SYSCONFIG_FILE="/etc/sysctl.conf" - - -# -# Set runtime for kernel.core_pattern -# -/sbin/sysctl -q -n -w kernel.core_pattern="|/bin/false" - -# -# If kernel.core_pattern present in /etc/sysctl.conf, change value to "|/bin/false" -# else, add "kernel.core_pattern = |/bin/false" to /etc/sysctl.conf -# - -# Strip any search characters in the key arg so that the key can be replaced without -# adding any search characters to the config file. -stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^kernel.core_pattern") - -# shellcheck disable=SC2059 -printf -v formatted_output "%s = %s" "$stripped_key" "|/bin/false" - -# If the key exists, change it. Otherwise, add it to the config_file. -# We search for the key string followed by a word boundary (matched by \>), -# so if we search for 'setting', 'setting2' won't match. -if LC_ALL=C grep -q -m 1 -i -e "^kernel.core_pattern\\>" "${SYSCONFIG_FILE}"; then - escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") - LC_ALL=C sed -i --follow-symlinks "s/^kernel.core_pattern\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" -else - if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then - LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" - fi - printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: List /etc/sysctl.d/*.conf files - find: - paths: - - /etc/sysctl.d/ - - /run/sysctl.d/ - - /usr/local/lib/sysctl.d/ - contains: ^[\s]*kernel.core_pattern.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-SC-7(10) - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_kernel_core_pattern - -- name: Comment out any occurrences of kernel.core_pattern from config files - replace: - path: '{{ item.path }}' - regexp: ^[\s]*kernel.core_pattern - replace: '#kernel.core_pattern' - loop: '{{ find_sysctl_d.files }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-SC-7(10) - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_kernel_core_pattern - -- name: Ensure sysctl kernel.core_pattern is set to |/bin/false - sysctl: - name: kernel.core_pattern - value: '|/bin/false' - sysctl_file: /etc/sysctl.conf - state: present - reload: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-SC-7(10) - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_kernel_core_pattern - - - - - - - - - - Configure file name of core dumps - To set the runtime status of the kernel.core_uses_pid kernel parameter, run the following command: $ sudo sysctl -w kernel.core_uses_pid=0 -To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: kernel.core_uses_pid = 0 - FMT_SMF_EXT.1 - The default coredump filename is core. By setting -core_uses_pid to 1, the coredump filename becomes -core.PID. If core_pattern does not include -%p (default does not) and core_uses_pid is set, then -.PID will be appended to the filename. -When combined with kernel.core_pattern = "" configuration, it -is ensured that no core dumps are generated and also no confusing error -messages are printed by a shell. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Comment out any occurrences of kernel.core_uses_pid from /etc/sysctl.d/*.conf files - -for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do - - matching_list=$(grep -P '^(?!#).*[\s]*kernel.core_uses_pid.*$' $f | uniq ) - if ! test -z "$matching_list"; then - while IFS= read -r entry; do - escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") - # comment out "kernel.core_uses_pid" matches to preserve user data - sed -i "s/^${escaped_entry}$/# &/g" $f - done <<< "$matching_list" - fi -done - -# -# Set sysctl config file which to save the desired value -# - -SYSCONFIG_FILE="/etc/sysctl.conf" - - -# -# Set runtime for kernel.core_uses_pid -# -/sbin/sysctl -q -n -w kernel.core_uses_pid="0" - -# -# If kernel.core_uses_pid present in /etc/sysctl.conf, change value to "0" -# else, add "kernel.core_uses_pid = 0" to /etc/sysctl.conf -# - -# Strip any search characters in the key arg so that the key can be replaced without -# adding any search characters to the config file. -stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^kernel.core_uses_pid") - -# shellcheck disable=SC2059 -printf -v formatted_output "%s = %s" "$stripped_key" "0" - -# If the key exists, change it. Otherwise, add it to the config_file. -# We search for the key string followed by a word boundary (matched by \>), -# so if we search for 'setting', 'setting2' won't match. -if LC_ALL=C grep -q -m 1 -i -e "^kernel.core_uses_pid\\>" "${SYSCONFIG_FILE}"; then - escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") - LC_ALL=C sed -i --follow-symlinks "s/^kernel.core_uses_pid\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" -else - if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then - LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" - fi - printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: List /etc/sysctl.d/*.conf files - find: - paths: - - /etc/sysctl.d/ - - /run/sysctl.d/ - - /usr/local/lib/sysctl.d/ - contains: ^[\s]*kernel.core_uses_pid.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_kernel_core_uses_pid - -- name: Comment out any occurrences of kernel.core_uses_pid from config files - replace: - path: '{{ item.path }}' - regexp: ^[\s]*kernel.core_uses_pid - replace: '#kernel.core_uses_pid' - loop: '{{ find_sysctl_d.files }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_kernel_core_uses_pid - -- name: Ensure sysctl kernel.core_uses_pid is set to 0 - sysctl: - name: kernel.core_uses_pid - value: '0' - sysctl_file: /etc/sysctl.conf - state: present - reload: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_kernel_core_uses_pid - - - - - - - - - - Restrict Access to Kernel Message Buffer - To set the runtime status of the kernel.dmesg_restrict kernel parameter, run the following command: $ sudo sysctl -w kernel.dmesg_restrict=1 -To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: kernel.dmesg_restrict = 1 - BP28(R23) - 3.1.5 - CCI-001090 - CCI-001314 - 164.308(a)(1)(ii)(D) - 164.308(a)(3) - 164.308(a)(4) - 164.310(b) - 164.310(c) - 164.312(a) - 164.312(e) - SI-11(a) - SI-11(b) - SRG-OS-000132-GPOS-00067 - SRG-OS-000138-GPOS-00069 - SRG-APP-000243-CTR-000600 - Unprivileged access to the kernel syslog can expose sensitive kernel -address information. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Comment out any occurrences of kernel.dmesg_restrict from /etc/sysctl.d/*.conf files - -for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do - - matching_list=$(grep -P '^(?!#).*[\s]*kernel.dmesg_restrict.*$' $f | uniq ) - if ! test -z "$matching_list"; then - while IFS= read -r entry; do - escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") - # comment out "kernel.dmesg_restrict" matches to preserve user data - sed -i "s/^${escaped_entry}$/# &/g" $f - done <<< "$matching_list" - fi -done - -# -# Set sysctl config file which to save the desired value -# - -SYSCONFIG_FILE="/etc/sysctl.conf" - - -# -# Set runtime for kernel.dmesg_restrict -# -/sbin/sysctl -q -n -w kernel.dmesg_restrict="1" - -# -# If kernel.dmesg_restrict present in /etc/sysctl.conf, change value to "1" -# else, add "kernel.dmesg_restrict = 1" to /etc/sysctl.conf -# - -# Strip any search characters in the key arg so that the key can be replaced without -# adding any search characters to the config file. -stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^kernel.dmesg_restrict") - -# shellcheck disable=SC2059 -printf -v formatted_output "%s = %s" "$stripped_key" "1" - -# If the key exists, change it. Otherwise, add it to the config_file. -# We search for the key string followed by a word boundary (matched by \>), -# so if we search for 'setting', 'setting2' won't match. -if LC_ALL=C grep -q -m 1 -i -e "^kernel.dmesg_restrict\\>" "${SYSCONFIG_FILE}"; then - escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") - LC_ALL=C sed -i --follow-symlinks "s/^kernel.dmesg_restrict\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" -else - if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then - LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" - fi - printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: List /etc/sysctl.d/*.conf files - find: - paths: - - /etc/sysctl.d/ - - /run/sysctl.d/ - - /usr/local/lib/sysctl.d/ - contains: ^[\s]*kernel.dmesg_restrict.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.5 - - NIST-800-53-SI-11(a) - - NIST-800-53-SI-11(b) - - disable_strategy - - low_complexity - - low_severity - - medium_disruption - - reboot_required - - sysctl_kernel_dmesg_restrict - -- name: Comment out any occurrences of kernel.dmesg_restrict from config files - replace: - path: '{{ item.path }}' - regexp: ^[\s]*kernel.dmesg_restrict - replace: '#kernel.dmesg_restrict' - loop: '{{ find_sysctl_d.files }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.5 - - NIST-800-53-SI-11(a) - - NIST-800-53-SI-11(b) - - disable_strategy - - low_complexity - - low_severity - - medium_disruption - - reboot_required - - sysctl_kernel_dmesg_restrict - -- name: Ensure sysctl kernel.dmesg_restrict is set to 1 - sysctl: - name: kernel.dmesg_restrict - value: '1' - sysctl_file: /etc/sysctl.conf - state: present - reload: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.5 - - NIST-800-53-SI-11(a) - - NIST-800-53-SI-11(b) - - disable_strategy - - low_complexity - - low_severity - - medium_disruption - - reboot_required - - sysctl_kernel_dmesg_restrict - - - - - - - - - - Disable Kernel Image Loading - To set the runtime status of the kernel.kexec_load_disabled kernel parameter, run the following command: $ sudo sysctl -w kernel.kexec_load_disabled=1 -To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: kernel.kexec_load_disabled = 1 - CCI-001749 - CM-6 - SRG-OS-000480-GPOS-00227 - SRG-OS-000366-GPOS-00153 - Disabling kexec_load allows greater control of the kernel memory. -It makes it impossible to load another kernel image after it has been disabled. - - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Comment out any occurrences of kernel.kexec_load_disabled from /etc/sysctl.d/*.conf files - -for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do - - matching_list=$(grep -P '^(?!#).*[\s]*kernel.kexec_load_disabled.*$' $f | uniq ) - if ! test -z "$matching_list"; then - while IFS= read -r entry; do - escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") - # comment out "kernel.kexec_load_disabled" matches to preserve user data - sed -i "s/^${escaped_entry}$/# &/g" $f - done <<< "$matching_list" - fi -done - -# -# Set sysctl config file which to save the desired value -# - -SYSCONFIG_FILE="/etc/sysctl.conf" - - -# -# Set runtime for kernel.kexec_load_disabled -# -/sbin/sysctl -q -n -w kernel.kexec_load_disabled="1" - -# -# If kernel.kexec_load_disabled present in /etc/sysctl.conf, change value to "1" -# else, add "kernel.kexec_load_disabled = 1" to /etc/sysctl.conf -# - -# Strip any search characters in the key arg so that the key can be replaced without -# adding any search characters to the config file. -stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^kernel.kexec_load_disabled") - -# shellcheck disable=SC2059 -printf -v formatted_output "%s = %s" "$stripped_key" "1" - -# If the key exists, change it. Otherwise, add it to the config_file. -# We search for the key string followed by a word boundary (matched by \>), -# so if we search for 'setting', 'setting2' won't match. -if LC_ALL=C grep -q -m 1 -i -e "^kernel.kexec_load_disabled\\>" "${SYSCONFIG_FILE}"; then - escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") - LC_ALL=C sed -i --follow-symlinks "s/^kernel.kexec_load_disabled\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" -else - if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then - LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" - fi - printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: List /etc/sysctl.d/*.conf files - find: - paths: - - /etc/sysctl.d/ - - /run/sysctl.d/ - - /usr/local/lib/sysctl.d/ - contains: ^[\s]*kernel.kexec_load_disabled.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-CM-6 - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_kernel_kexec_load_disabled - -- name: Comment out any occurrences of kernel.kexec_load_disabled from config files - replace: - path: '{{ item.path }}' - regexp: ^[\s]*kernel.kexec_load_disabled - replace: '#kernel.kexec_load_disabled' - loop: '{{ find_sysctl_d.files }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-CM-6 - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_kernel_kexec_load_disabled - -- name: Ensure sysctl kernel.kexec_load_disabled is set to 1 - sysctl: - name: kernel.kexec_load_disabled - value: '1' - sysctl_file: /etc/sysctl.conf - state: present - reload: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-CM-6 - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_kernel_kexec_load_disabled - - - - - - - - - - Disable loading and unloading of kernel modules - To set the runtime status of the kernel.modules_disabled kernel parameter, run the following command: $ sudo sysctl -w kernel.modules_disabled=1 -To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: kernel.modules_disabled = 1 - This rule doesn't come with Bash remediation. Remediating this rule during the installation process disrupts the install and boot process. - BP28(R24) - Malicious kernel modules can have a significant impact on system security and -availability. Disabling loading of kernel modules prevents this threat. Note -that once this option has been set, it cannot be reverted without doing a -system reboot. Make sure that all needed kernel modules are loaded before -setting this option. - - - name: List /etc/sysctl.d/*.conf files - find: - paths: - - /etc/sysctl.d/ - - /run/sysctl.d/ - - /usr/local/lib/sysctl.d/ - contains: ^[\s]*kernel.modules_disabled.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_kernel_modules_disabled - -- name: Comment out any occurrences of kernel.modules_disabled from config files - replace: - path: '{{ item.path }}' - regexp: ^[\s]*kernel.modules_disabled - replace: '#kernel.modules_disabled' - loop: '{{ find_sysctl_d.files }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_kernel_modules_disabled - -- name: Ensure sysctl kernel.modules_disabled is set to 1 - sysctl: - name: kernel.modules_disabled - value: '1' - sysctl_file: /etc/sysctl.conf - state: present - reload: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_kernel_modules_disabled - - - - - - - - - - Kernel panic on oops - To set the runtime status of the kernel.panic_on_oops kernel parameter, run the following command: $ sudo sysctl -w kernel.panic_on_oops=1 -To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: kernel.panic_on_oops = 1 - The system may start to panic when it normally wouldn't. A non-catastrophic error that -would have allowed the system to continue operating will now result in a panic. - BP28(R9) - An attacker trying to exploit the kernel may trigger kernel OOPSes, -panicking the system will impede them from continuing. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Comment out any occurrences of kernel.panic_on_oops from /etc/sysctl.d/*.conf files - -for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do - - matching_list=$(grep -P '^(?!#).*[\s]*kernel.panic_on_oops.*$' $f | uniq ) - if ! test -z "$matching_list"; then - while IFS= read -r entry; do - escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") - # comment out "kernel.panic_on_oops" matches to preserve user data - sed -i "s/^${escaped_entry}$/# &/g" $f - done <<< "$matching_list" - fi -done - -# -# Set sysctl config file which to save the desired value -# - -SYSCONFIG_FILE="/etc/sysctl.conf" - - -# -# Set runtime for kernel.panic_on_oops -# -/sbin/sysctl -q -n -w kernel.panic_on_oops="1" - -# -# If kernel.panic_on_oops present in /etc/sysctl.conf, change value to "1" -# else, add "kernel.panic_on_oops = 1" to /etc/sysctl.conf -# - -# Strip any search characters in the key arg so that the key can be replaced without -# adding any search characters to the config file. -stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^kernel.panic_on_oops") - -# shellcheck disable=SC2059 -printf -v formatted_output "%s = %s" "$stripped_key" "1" - -# If the key exists, change it. Otherwise, add it to the config_file. -# We search for the key string followed by a word boundary (matched by \>), -# so if we search for 'setting', 'setting2' won't match. -if LC_ALL=C grep -q -m 1 -i -e "^kernel.panic_on_oops\\>" "${SYSCONFIG_FILE}"; then - escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") - LC_ALL=C sed -i --follow-symlinks "s/^kernel.panic_on_oops\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" -else - if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then - LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" - fi - printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: List /etc/sysctl.d/*.conf files - find: - paths: - - /etc/sysctl.d/ - - /run/sysctl.d/ - - /usr/local/lib/sysctl.d/ - contains: ^[\s]*kernel.panic_on_oops.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_kernel_panic_on_oops - -- name: Comment out any occurrences of kernel.panic_on_oops from config files - replace: - path: '{{ item.path }}' - regexp: ^[\s]*kernel.panic_on_oops - replace: '#kernel.panic_on_oops' - loop: '{{ find_sysctl_d.files }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_kernel_panic_on_oops - -- name: Ensure sysctl kernel.panic_on_oops is set to 1 - sysctl: - name: kernel.panic_on_oops - value: '1' - sysctl_file: /etc/sysctl.conf - state: present - reload: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_kernel_panic_on_oops - - - - - - - - - - Limit CPU consumption of the Perf system - To set the runtime status of the kernel.perf_cpu_time_max_percent kernel parameter, run the following command: $ sudo sysctl -w kernel.perf_cpu_time_max_percent=1 -To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: kernel.perf_cpu_time_max_percent = 1 - BP28(R23) - The kernel.perf_cpu_time_max_percent configures a treshold of -maximum percentile of CPU that can be used by Perf system. Restricting usage -of Perf system decreases risk of potential availability problems. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Comment out any occurrences of kernel.perf_cpu_time_max_percent from /etc/sysctl.d/*.conf files - -for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do - - matching_list=$(grep -P '^(?!#).*[\s]*kernel.perf_cpu_time_max_percent.*$' $f | uniq ) - if ! test -z "$matching_list"; then - while IFS= read -r entry; do - escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") - # comment out "kernel.perf_cpu_time_max_percent" matches to preserve user data - sed -i "s/^${escaped_entry}$/# &/g" $f - done <<< "$matching_list" - fi -done - -# -# Set sysctl config file which to save the desired value -# - -SYSCONFIG_FILE="/etc/sysctl.conf" - - -# -# Set runtime for kernel.perf_cpu_time_max_percent -# -/sbin/sysctl -q -n -w kernel.perf_cpu_time_max_percent="1" - -# -# If kernel.perf_cpu_time_max_percent present in /etc/sysctl.conf, change value to "1" -# else, add "kernel.perf_cpu_time_max_percent = 1" to /etc/sysctl.conf -# - -# Strip any search characters in the key arg so that the key can be replaced without -# adding any search characters to the config file. -stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^kernel.perf_cpu_time_max_percent") - -# shellcheck disable=SC2059 -printf -v formatted_output "%s = %s" "$stripped_key" "1" - -# If the key exists, change it. Otherwise, add it to the config_file. -# We search for the key string followed by a word boundary (matched by \>), -# so if we search for 'setting', 'setting2' won't match. -if LC_ALL=C grep -q -m 1 -i -e "^kernel.perf_cpu_time_max_percent\\>" "${SYSCONFIG_FILE}"; then - escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") - LC_ALL=C sed -i --follow-symlinks "s/^kernel.perf_cpu_time_max_percent\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" -else - if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then - LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" - fi - printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: List /etc/sysctl.d/*.conf files - find: - paths: - - /etc/sysctl.d/ - - /run/sysctl.d/ - - /usr/local/lib/sysctl.d/ - contains: ^[\s]*kernel.perf_cpu_time_max_percent.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_kernel_perf_cpu_time_max_percent - -- name: Comment out any occurrences of kernel.perf_cpu_time_max_percent from config - files - replace: - path: '{{ item.path }}' - regexp: ^[\s]*kernel.perf_cpu_time_max_percent - replace: '#kernel.perf_cpu_time_max_percent' - loop: '{{ find_sysctl_d.files }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_kernel_perf_cpu_time_max_percent - -- name: Ensure sysctl kernel.perf_cpu_time_max_percent is set to 1 - sysctl: - name: kernel.perf_cpu_time_max_percent - value: '1' - sysctl_file: /etc/sysctl.conf - state: present - reload: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_kernel_perf_cpu_time_max_percent - - - - - - - - - - Limit sampling frequency of the Perf system - To set the runtime status of the kernel.perf_event_max_sample_rate kernel parameter, run the following command: $ sudo sysctl -w kernel.perf_event_max_sample_rate=1 -To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: kernel.perf_event_max_sample_rate = 1 - BP28(R23) - The kernel.perf_event_max_sample_rate parameter configures maximum -frequency of collecting of samples for the Perf system. It is expressed in -samples per second. Restricting usage of Perf system decreases risk -of potential availability problems. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Comment out any occurrences of kernel.perf_event_max_sample_rate from /etc/sysctl.d/*.conf files - -for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do - - matching_list=$(grep -P '^(?!#).*[\s]*kernel.perf_event_max_sample_rate.*$' $f | uniq ) - if ! test -z "$matching_list"; then - while IFS= read -r entry; do - escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") - # comment out "kernel.perf_event_max_sample_rate" matches to preserve user data - sed -i "s/^${escaped_entry}$/# &/g" $f - done <<< "$matching_list" - fi -done - -# -# Set sysctl config file which to save the desired value -# - -SYSCONFIG_FILE="/etc/sysctl.conf" - - -# -# Set runtime for kernel.perf_event_max_sample_rate -# -/sbin/sysctl -q -n -w kernel.perf_event_max_sample_rate="1" - -# -# If kernel.perf_event_max_sample_rate present in /etc/sysctl.conf, change value to "1" -# else, add "kernel.perf_event_max_sample_rate = 1" to /etc/sysctl.conf -# - -# Strip any search characters in the key arg so that the key can be replaced without -# adding any search characters to the config file. -stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^kernel.perf_event_max_sample_rate") - -# shellcheck disable=SC2059 -printf -v formatted_output "%s = %s" "$stripped_key" "1" - -# If the key exists, change it. Otherwise, add it to the config_file. -# We search for the key string followed by a word boundary (matched by \>), -# so if we search for 'setting', 'setting2' won't match. -if LC_ALL=C grep -q -m 1 -i -e "^kernel.perf_event_max_sample_rate\\>" "${SYSCONFIG_FILE}"; then - escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") - LC_ALL=C sed -i --follow-symlinks "s/^kernel.perf_event_max_sample_rate\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" -else - if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then - LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" - fi - printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: List /etc/sysctl.d/*.conf files - find: - paths: - - /etc/sysctl.d/ - - /run/sysctl.d/ - - /usr/local/lib/sysctl.d/ - contains: ^[\s]*kernel.perf_event_max_sample_rate.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_kernel_perf_event_max_sample_rate - -- name: Comment out any occurrences of kernel.perf_event_max_sample_rate from config - files - replace: - path: '{{ item.path }}' - regexp: ^[\s]*kernel.perf_event_max_sample_rate - replace: '#kernel.perf_event_max_sample_rate' - loop: '{{ find_sysctl_d.files }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_kernel_perf_event_max_sample_rate - -- name: Ensure sysctl kernel.perf_event_max_sample_rate is set to 1 - sysctl: - name: kernel.perf_event_max_sample_rate - value: '1' - sysctl_file: /etc/sysctl.conf - state: present - reload: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_kernel_perf_event_max_sample_rate - - - - - - - - - - Disallow kernel profiling by unprivileged users - To set the runtime status of the kernel.perf_event_paranoid kernel parameter, run the following command: $ sudo sysctl -w kernel.perf_event_paranoid=2 -To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: kernel.perf_event_paranoid = 2 - BP28(R23) - CCI-001090 - AC-6 - FMT_SMF_EXT.1 - SRG-OS-000132-GPOS-00067 - SRG-OS-000138-GPOS-00069 - SRG-APP-000243-CTR-000600 - Kernel profiling can reveal sensitive information about kernel behaviour. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Comment out any occurrences of kernel.perf_event_paranoid from /etc/sysctl.d/*.conf files - -for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do - - matching_list=$(grep -P '^(?!#).*[\s]*kernel.perf_event_paranoid.*$' $f | uniq ) - if ! test -z "$matching_list"; then - while IFS= read -r entry; do - escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") - # comment out "kernel.perf_event_paranoid" matches to preserve user data - sed -i "s/^${escaped_entry}$/# &/g" $f - done <<< "$matching_list" - fi -done - -# -# Set sysctl config file which to save the desired value -# - -SYSCONFIG_FILE="/etc/sysctl.conf" - - -# -# Set runtime for kernel.perf_event_paranoid -# -/sbin/sysctl -q -n -w kernel.perf_event_paranoid="2" - -# -# If kernel.perf_event_paranoid present in /etc/sysctl.conf, change value to "2" -# else, add "kernel.perf_event_paranoid = 2" to /etc/sysctl.conf -# - -# Strip any search characters in the key arg so that the key can be replaced without -# adding any search characters to the config file. -stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^kernel.perf_event_paranoid") - -# shellcheck disable=SC2059 -printf -v formatted_output "%s = %s" "$stripped_key" "2" - -# If the key exists, change it. Otherwise, add it to the config_file. -# We search for the key string followed by a word boundary (matched by \>), -# so if we search for 'setting', 'setting2' won't match. -if LC_ALL=C grep -q -m 1 -i -e "^kernel.perf_event_paranoid\\>" "${SYSCONFIG_FILE}"; then - escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") - LC_ALL=C sed -i --follow-symlinks "s/^kernel.perf_event_paranoid\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" -else - if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then - LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" - fi - printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: List /etc/sysctl.d/*.conf files - find: - paths: - - /etc/sysctl.d/ - - /run/sysctl.d/ - - /usr/local/lib/sysctl.d/ - contains: ^[\s]*kernel.perf_event_paranoid.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-6 - - disable_strategy - - low_complexity - - low_severity - - medium_disruption - - reboot_required - - sysctl_kernel_perf_event_paranoid - -- name: Comment out any occurrences of kernel.perf_event_paranoid from config files - replace: - path: '{{ item.path }}' - regexp: ^[\s]*kernel.perf_event_paranoid - replace: '#kernel.perf_event_paranoid' - loop: '{{ find_sysctl_d.files }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-6 - - disable_strategy - - low_complexity - - low_severity - - medium_disruption - - reboot_required - - sysctl_kernel_perf_event_paranoid - -- name: Ensure sysctl kernel.perf_event_paranoid is set to 2 - sysctl: - name: kernel.perf_event_paranoid - value: '2' - sysctl_file: /etc/sysctl.conf - state: present - reload: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-6 - - disable_strategy - - low_complexity - - low_severity - - medium_disruption - - reboot_required - - sysctl_kernel_perf_event_paranoid - - - - - - - - - - Configure maximum number of process identifiers - To set the runtime status of the kernel.pid_max kernel parameter, run the following command: $ sudo sysctl -w kernel.pid_max=65536 -To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: kernel.pid_max = 65536 - BP28(R23) - The kernel.pid_max parameter configures upper limit on process -identifiers (PID). If this number is not high enough, it might happen that -forking of new processes is not possible, because all available PIDs are -exhausted. Increasing this number enhances availability. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Comment out any occurrences of kernel.pid_max from /etc/sysctl.d/*.conf files - -for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do - - matching_list=$(grep -P '^(?!#).*[\s]*kernel.pid_max.*$' $f | uniq ) - if ! test -z "$matching_list"; then - while IFS= read -r entry; do - escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") - # comment out "kernel.pid_max" matches to preserve user data - sed -i "s/^${escaped_entry}$/# &/g" $f - done <<< "$matching_list" - fi -done - -# -# Set sysctl config file which to save the desired value -# - -SYSCONFIG_FILE="/etc/sysctl.conf" - - -# -# Set runtime for kernel.pid_max -# -/sbin/sysctl -q -n -w kernel.pid_max="65536" - -# -# If kernel.pid_max present in /etc/sysctl.conf, change value to "65536" -# else, add "kernel.pid_max = 65536" to /etc/sysctl.conf -# - -# Strip any search characters in the key arg so that the key can be replaced without -# adding any search characters to the config file. -stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^kernel.pid_max") - -# shellcheck disable=SC2059 -printf -v formatted_output "%s = %s" "$stripped_key" "65536" - -# If the key exists, change it. Otherwise, add it to the config_file. -# We search for the key string followed by a word boundary (matched by \>), -# so if we search for 'setting', 'setting2' won't match. -if LC_ALL=C grep -q -m 1 -i -e "^kernel.pid_max\\>" "${SYSCONFIG_FILE}"; then - escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") - LC_ALL=C sed -i --follow-symlinks "s/^kernel.pid_max\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" -else - if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then - LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" - fi - printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: List /etc/sysctl.d/*.conf files - find: - paths: - - /etc/sysctl.d/ - - /run/sysctl.d/ - - /usr/local/lib/sysctl.d/ - contains: ^[\s]*kernel.pid_max.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_kernel_pid_max - -- name: Comment out any occurrences of kernel.pid_max from config files - replace: - path: '{{ item.path }}' - regexp: ^[\s]*kernel.pid_max - replace: '#kernel.pid_max' - loop: '{{ find_sysctl_d.files }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_kernel_pid_max - -- name: Ensure sysctl kernel.pid_max is set to 65536 - sysctl: - name: kernel.pid_max - value: '65536' - sysctl_file: /etc/sysctl.conf - state: present - reload: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_kernel_pid_max - - - - - - - - - - Disallow magic SysRq key - To set the runtime status of the kernel.sysrq kernel parameter, run the following command: $ sudo sysctl -w kernel.sysrq=0 -To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: kernel.sysrq = 0 - BP28(R23) - The Magic SysRq key allows sending certain commands directly to the running -kernel. It can dump various system and process information, potentially -revealing sensitive information. It can also reboot or shutdown the machine, -disturbing its availability. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Comment out any occurrences of kernel.sysrq from /etc/sysctl.d/*.conf files - -for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do - - matching_list=$(grep -P '^(?!#).*[\s]*kernel.sysrq.*$' $f | uniq ) - if ! test -z "$matching_list"; then - while IFS= read -r entry; do - escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") - # comment out "kernel.sysrq" matches to preserve user data - sed -i "s/^${escaped_entry}$/# &/g" $f - done <<< "$matching_list" - fi -done - -# -# Set sysctl config file which to save the desired value -# - -SYSCONFIG_FILE="/etc/sysctl.conf" - - -# -# Set runtime for kernel.sysrq -# -/sbin/sysctl -q -n -w kernel.sysrq="0" - -# -# If kernel.sysrq present in /etc/sysctl.conf, change value to "0" -# else, add "kernel.sysrq = 0" to /etc/sysctl.conf -# - -# Strip any search characters in the key arg so that the key can be replaced without -# adding any search characters to the config file. -stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^kernel.sysrq") - -# shellcheck disable=SC2059 -printf -v formatted_output "%s = %s" "$stripped_key" "0" - -# If the key exists, change it. Otherwise, add it to the config_file. -# We search for the key string followed by a word boundary (matched by \>), -# so if we search for 'setting', 'setting2' won't match. -if LC_ALL=C grep -q -m 1 -i -e "^kernel.sysrq\\>" "${SYSCONFIG_FILE}"; then - escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") - LC_ALL=C sed -i --follow-symlinks "s/^kernel.sysrq\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" -else - if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then - LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" - fi - printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: List /etc/sysctl.d/*.conf files - find: - paths: - - /etc/sysctl.d/ - - /run/sysctl.d/ - - /usr/local/lib/sysctl.d/ - contains: ^[\s]*kernel.sysrq.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_kernel_sysrq - -- name: Comment out any occurrences of kernel.sysrq from config files - replace: - path: '{{ item.path }}' - regexp: ^[\s]*kernel.sysrq - replace: '#kernel.sysrq' - loop: '{{ find_sysctl_d.files }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_kernel_sysrq - -- name: Ensure sysctl kernel.sysrq is set to 0 - sysctl: - name: kernel.sysrq - value: '0' - sysctl_file: /etc/sysctl.conf - state: present - reload: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_kernel_sysrq - - - - - - - - - - Disable Access to Network bpf() Syscall From Unprivileged Processes - To set the runtime status of the kernel.unprivileged_bpf_disabled kernel parameter, run the following command: $ sudo sysctl -w kernel.unprivileged_bpf_disabled=1 -To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: kernel.unprivileged_bpf_disabled = 1 - BP28(R9) - CCI-000366 - AC-6 - SC-7(10) - FMT_SMF_EXT.1 - SRG-OS-000132-GPOS-00067 - SRG-OS-000480-GPOS-00227 - Loading and accessing the packet filters programs and maps using the bpf() -syscall has the potential of revealing sensitive information about the kernel state. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Comment out any occurrences of kernel.unprivileged_bpf_disabled from /etc/sysctl.d/*.conf files - -for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do - - matching_list=$(grep -P '^(?!#).*[\s]*kernel.unprivileged_bpf_disabled.*$' $f | uniq ) - if ! test -z "$matching_list"; then - while IFS= read -r entry; do - escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") - # comment out "kernel.unprivileged_bpf_disabled" matches to preserve user data - sed -i "s/^${escaped_entry}$/# &/g" $f - done <<< "$matching_list" - fi -done - -# -# Set sysctl config file which to save the desired value -# - -SYSCONFIG_FILE="/etc/sysctl.conf" - - -# -# Set runtime for kernel.unprivileged_bpf_disabled -# -/sbin/sysctl -q -n -w kernel.unprivileged_bpf_disabled="1" - -# -# If kernel.unprivileged_bpf_disabled present in /etc/sysctl.conf, change value to "1" -# else, add "kernel.unprivileged_bpf_disabled = 1" to /etc/sysctl.conf -# - -# Strip any search characters in the key arg so that the key can be replaced without -# adding any search characters to the config file. -stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^kernel.unprivileged_bpf_disabled") - -# shellcheck disable=SC2059 -printf -v formatted_output "%s = %s" "$stripped_key" "1" - -# If the key exists, change it. Otherwise, add it to the config_file. -# We search for the key string followed by a word boundary (matched by \>), -# so if we search for 'setting', 'setting2' won't match. -if LC_ALL=C grep -q -m 1 -i -e "^kernel.unprivileged_bpf_disabled\\>" "${SYSCONFIG_FILE}"; then - escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") - LC_ALL=C sed -i --follow-symlinks "s/^kernel.unprivileged_bpf_disabled\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" -else - if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then - LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" - fi - printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: List /etc/sysctl.d/*.conf files - find: - paths: - - /etc/sysctl.d/ - - /run/sysctl.d/ - - /usr/local/lib/sysctl.d/ - contains: ^[\s]*kernel.unprivileged_bpf_disabled.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-6 - - NIST-800-53-SC-7(10) - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_kernel_unprivileged_bpf_disabled - -- name: Comment out any occurrences of kernel.unprivileged_bpf_disabled from config - files - replace: - path: '{{ item.path }}' - regexp: ^[\s]*kernel.unprivileged_bpf_disabled - replace: '#kernel.unprivileged_bpf_disabled' - loop: '{{ find_sysctl_d.files }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-6 - - NIST-800-53-SC-7(10) - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_kernel_unprivileged_bpf_disabled - -- name: Ensure sysctl kernel.unprivileged_bpf_disabled is set to 1 - sysctl: - name: kernel.unprivileged_bpf_disabled - value: '1' - sysctl_file: /etc/sysctl.conf - state: present - reload: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-6 - - NIST-800-53-SC-7(10) - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_kernel_unprivileged_bpf_disabled - - - - - - - - - - Restrict usage of ptrace to descendant processes - To set the runtime status of the kernel.yama.ptrace_scope kernel parameter, run the following command: $ sudo sysctl -w kernel.yama.ptrace_scope=1 -To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: kernel.yama.ptrace_scope = 1 - BP28(R25) - CCI-000366 - SC-7(10) - SRG-OS-000132-GPOS-00067 - SRG-OS-000480-GPOS-00227 - Unrestricted usage of ptrace allows compromised binaries to run ptrace -on another processes of the user. Like this, the attacker can steal -sensitive information from the target processes (e.g. SSH sessions, web browser, ...) -without any additional assistance from the user (i.e. without resorting to phishing). - - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Comment out any occurrences of kernel.yama.ptrace_scope from /etc/sysctl.d/*.conf files - -for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do - - matching_list=$(grep -P '^(?!#).*[\s]*kernel.yama.ptrace_scope.*$' $f | uniq ) - if ! test -z "$matching_list"; then - while IFS= read -r entry; do - escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") - # comment out "kernel.yama.ptrace_scope" matches to preserve user data - sed -i "s/^${escaped_entry}$/# &/g" $f - done <<< "$matching_list" - fi -done - -# -# Set sysctl config file which to save the desired value -# - -SYSCONFIG_FILE="/etc/sysctl.conf" - - -# -# Set runtime for kernel.yama.ptrace_scope -# -/sbin/sysctl -q -n -w kernel.yama.ptrace_scope="1" - -# -# If kernel.yama.ptrace_scope present in /etc/sysctl.conf, change value to "1" -# else, add "kernel.yama.ptrace_scope = 1" to /etc/sysctl.conf -# - -# Strip any search characters in the key arg so that the key can be replaced without -# adding any search characters to the config file. -stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^kernel.yama.ptrace_scope") - -# shellcheck disable=SC2059 -printf -v formatted_output "%s = %s" "$stripped_key" "1" - -# If the key exists, change it. Otherwise, add it to the config_file. -# We search for the key string followed by a word boundary (matched by \>), -# so if we search for 'setting', 'setting2' won't match. -if LC_ALL=C grep -q -m 1 -i -e "^kernel.yama.ptrace_scope\\>" "${SYSCONFIG_FILE}"; then - escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") - LC_ALL=C sed -i --follow-symlinks "s/^kernel.yama.ptrace_scope\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" -else - if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then - LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" - fi - printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: List /etc/sysctl.d/*.conf files - find: - paths: - - /etc/sysctl.d/ - - /run/sysctl.d/ - - /usr/local/lib/sysctl.d/ - contains: ^[\s]*kernel.yama.ptrace_scope.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-SC-7(10) - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_kernel_yama_ptrace_scope - -- name: Comment out any occurrences of kernel.yama.ptrace_scope from config files - replace: - path: '{{ item.path }}' - regexp: ^[\s]*kernel.yama.ptrace_scope - replace: '#kernel.yama.ptrace_scope' - loop: '{{ find_sysctl_d.files }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-SC-7(10) - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_kernel_yama_ptrace_scope - -- name: Ensure sysctl kernel.yama.ptrace_scope is set to 1 - sysctl: - name: kernel.yama.ptrace_scope - value: '1' - sysctl_file: /etc/sysctl.conf - state: present - reload: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-SC-7(10) - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_kernel_yama_ptrace_scope - - - - - - - - - - Harden the operation of the BPF just-in-time compiler - To set the runtime status of the net.core.bpf_jit_harden kernel parameter, run the following command: $ sudo sysctl -w net.core.bpf_jit_harden=2 -To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.core.bpf_jit_harden = 2 - BP28(R12) - CCI-000366 - CM-6 - SC-7(10) - FMT_SMF_EXT.1 - SRG-OS-000480-GPOS-00227 - When hardened, the extended Berkeley Packet Filter just-in-time compiler -will randomize any kernel addresses in the BPF programs and maps, -and will not expose the JIT addresses in /proc/kallsyms. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Comment out any occurrences of net.core.bpf_jit_harden from /etc/sysctl.d/*.conf files - -for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do - - matching_list=$(grep -P '^(?!#).*[\s]*net.core.bpf_jit_harden.*$' $f | uniq ) - if ! test -z "$matching_list"; then - while IFS= read -r entry; do - escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") - # comment out "net.core.bpf_jit_harden" matches to preserve user data - sed -i "s/^${escaped_entry}$/# &/g" $f - done <<< "$matching_list" - fi -done - -# -# Set sysctl config file which to save the desired value -# - -SYSCONFIG_FILE="/etc/sysctl.conf" - - -# -# Set runtime for net.core.bpf_jit_harden -# -/sbin/sysctl -q -n -w net.core.bpf_jit_harden="2" - -# -# If net.core.bpf_jit_harden present in /etc/sysctl.conf, change value to "2" -# else, add "net.core.bpf_jit_harden = 2" to /etc/sysctl.conf -# - -# Strip any search characters in the key arg so that the key can be replaced without -# adding any search characters to the config file. -stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.core.bpf_jit_harden") - -# shellcheck disable=SC2059 -printf -v formatted_output "%s = %s" "$stripped_key" "2" - -# If the key exists, change it. Otherwise, add it to the config_file. -# We search for the key string followed by a word boundary (matched by \>), -# so if we search for 'setting', 'setting2' won't match. -if LC_ALL=C grep -q -m 1 -i -e "^net.core.bpf_jit_harden\\>" "${SYSCONFIG_FILE}"; then - escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") - LC_ALL=C sed -i --follow-symlinks "s/^net.core.bpf_jit_harden\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" -else - if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then - LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" - fi - printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: List /etc/sysctl.d/*.conf files - find: - paths: - - /etc/sysctl.d/ - - /run/sysctl.d/ - - /usr/local/lib/sysctl.d/ - contains: ^[\s]*net.core.bpf_jit_harden.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-CM-6 - - NIST-800-53-SC-7(10) - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_core_bpf_jit_harden - -- name: Comment out any occurrences of net.core.bpf_jit_harden from config files - replace: - path: '{{ item.path }}' - regexp: ^[\s]*net.core.bpf_jit_harden - replace: '#net.core.bpf_jit_harden' - loop: '{{ find_sysctl_d.files }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-CM-6 - - NIST-800-53-SC-7(10) - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_core_bpf_jit_harden - -- name: Ensure sysctl net.core.bpf_jit_harden is set to 2 - sysctl: - name: net.core.bpf_jit_harden - value: '2' - sysctl_file: /etc/sysctl.conf - state: present - reload: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-CM-6 - - NIST-800-53-SC-7(10) - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_net_core_bpf_jit_harden - - - - - - - - - - Disable the use of user namespaces - To set the runtime status of the user.max_user_namespaces kernel parameter, -run the following command: -$ sudo sysctl -w user.max_user_namespaces=0 - -To make sure that the setting is persistent, -add the following line to a file in the directory /etc/sysctl.d: -user.max_user_namespaces = 0 -When containers are deployed on the machine, the value should be set -to large non-zero value. - This configuration baseline was created to deploy the base operating system for general purpose -workloads. When the operating system is configured for certain purposes, such as to host Linux Containers, -it is expected that user.max_user_namespaces will be enabled. - CCI-000366 - SC-39 - CM-6(a) - FMT_SMF_EXT.1 - SRG-OS-000480-GPOS-00227 - It is detrimental for operating systems to provide, or install by default, functionality exceeding requirements or system objectives. -These unnecessary capabilities or services are often overlooked and therefore may remain unsecured. -They increase the risk to the platform by providing additional attack vectors. -User namespaces are used primarily for Linux containers. The value 0 -disallows the use of user namespaces. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Comment out any occurrences of user.max_user_namespaces from /etc/sysctl.d/*.conf files - -for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do - - matching_list=$(grep -P '^(?!#).*[\s]*user.max_user_namespaces.*$' $f | uniq ) - if ! test -z "$matching_list"; then - while IFS= read -r entry; do - escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") - # comment out "user.max_user_namespaces" matches to preserve user data - sed -i "s/^${escaped_entry}$/# &/g" $f - done <<< "$matching_list" - fi -done - -# -# Set sysctl config file which to save the desired value -# - -SYSCONFIG_FILE="/etc/sysctl.conf" - - -# -# Set runtime for user.max_user_namespaces -# -/sbin/sysctl -q -n -w user.max_user_namespaces="0" - -# -# If user.max_user_namespaces present in /etc/sysctl.conf, change value to "0" -# else, add "user.max_user_namespaces = 0" to /etc/sysctl.conf -# - -# Strip any search characters in the key arg so that the key can be replaced without -# adding any search characters to the config file. -stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^user.max_user_namespaces") - -# shellcheck disable=SC2059 -printf -v formatted_output "%s = %s" "$stripped_key" "0" - -# If the key exists, change it. Otherwise, add it to the config_file. -# We search for the key string followed by a word boundary (matched by \>), -# so if we search for 'setting', 'setting2' won't match. -if LC_ALL=C grep -q -m 1 -i -e "^user.max_user_namespaces\\>" "${SYSCONFIG_FILE}"; then - escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") - LC_ALL=C sed -i --follow-symlinks "s/^user.max_user_namespaces\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" -else - if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then - LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" - fi - printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: List /etc/sysctl.d/*.conf files - find: - paths: - - /etc/sysctl.d/ - - /run/sysctl.d/ - - /usr/local/lib/sysctl.d/ - contains: ^[\s]*user.max_user_namespaces.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-SC-39 - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_user_max_user_namespaces - -- name: Comment out any occurrences of user.max_user_namespaces from config files - replace: - path: '{{ item.path }}' - regexp: ^[\s]*user.max_user_namespaces - replace: '#user.max_user_namespaces' - loop: '{{ find_sysctl_d.files }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-SC-39 - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_user_max_user_namespaces - -- name: Ensure sysctl user.max_user_namespaces is set to 0 - sysctl: - name: user.max_user_namespaces - value: '0' - sysctl_file: /etc/sysctl.conf - state: present - reload: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-SC-39 - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_user_max_user_namespaces - - - - - - - - - - Prevent applications from mapping low portion of virtual memory - To set the runtime status of the vm.mmap_min_addr kernel parameter, run the following command: $ sudo sysctl -w vm.mmap_min_addr=65536 -To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: vm.mmap_min_addr = 65536 - BP28(R23) - The vm.mmap_min_addr parameter specifies the minimum virtual -address that a process is allowed to mmap. Allowing a process to mmap low -portion of virtual memory can have security implications such as such as -heightened risk of kernel null pointer dereference defects. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Comment out any occurrences of vm.mmap_min_addr from /etc/sysctl.d/*.conf files - -for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do - - matching_list=$(grep -P '^(?!#).*[\s]*vm.mmap_min_addr.*$' $f | uniq ) - if ! test -z "$matching_list"; then - while IFS= read -r entry; do - escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") - # comment out "vm.mmap_min_addr" matches to preserve user data - sed -i "s/^${escaped_entry}$/# &/g" $f - done <<< "$matching_list" - fi -done - -# -# Set sysctl config file which to save the desired value -# - -SYSCONFIG_FILE="/etc/sysctl.conf" - - -# -# Set runtime for vm.mmap_min_addr -# -/sbin/sysctl -q -n -w vm.mmap_min_addr="65536" - -# -# If vm.mmap_min_addr present in /etc/sysctl.conf, change value to "65536" -# else, add "vm.mmap_min_addr = 65536" to /etc/sysctl.conf -# - -# Strip any search characters in the key arg so that the key can be replaced without -# adding any search characters to the config file. -stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^vm.mmap_min_addr") - -# shellcheck disable=SC2059 -printf -v formatted_output "%s = %s" "$stripped_key" "65536" - -# If the key exists, change it. Otherwise, add it to the config_file. -# We search for the key string followed by a word boundary (matched by \>), -# so if we search for 'setting', 'setting2' won't match. -if LC_ALL=C grep -q -m 1 -i -e "^vm.mmap_min_addr\\>" "${SYSCONFIG_FILE}"; then - escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") - LC_ALL=C sed -i --follow-symlinks "s/^vm.mmap_min_addr\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" -else - if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then - LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" - fi - printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: List /etc/sysctl.d/*.conf files - find: - paths: - - /etc/sysctl.d/ - - /run/sysctl.d/ - - /usr/local/lib/sysctl.d/ - contains: ^[\s]*vm.mmap_min_addr.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_vm_mmap_min_addr - -- name: Comment out any occurrences of vm.mmap_min_addr from config files - replace: - path: '{{ item.path }}' - regexp: ^[\s]*vm.mmap_min_addr - replace: '#vm.mmap_min_addr' - loop: '{{ find_sysctl_d.files }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_vm_mmap_min_addr - -- name: Ensure sysctl vm.mmap_min_addr is set to 65536 - sysctl: - name: vm.mmap_min_addr - value: '65536' - sysctl_file: /etc/sysctl.conf - state: present - reload: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_vm_mmap_min_addr - - - - - - - - - - Disable Core Dumps - A core dump file is the memory image of an executable -program when it was terminated by the operating system due to -errant behavior. In most cases, only software developers -legitimately need to access these files. The core dump files may -also contain sensitive information, or unnecessarily occupy large -amounts of disk space. - -Once a hard limit is set in /etc/security/limits.conf, or -to a file within the /etc/security/limits.d/ directory, a -user cannot increase that limit within his or her own session. If access -to core dumps is required, consider restricting them to only -certain users or groups. See the limits.conf man page for more -information. - -The core dumps of setuid programs are further protected. The -sysctl variable fs.suid_dumpable controls whether -the kernel allows core dumps from these programs at all. The default -value of 0 is recommended. - - Disable acquiring, saving, and processing core dumps - The systemd-coredump.socket unit is a socket activation of -the systemd-coredump@.service which processes core dumps. -By masking the unit, core dump processing is disabled. - CCI-000366 - SC-7(10) - FMT_SMF_EXT.1 - SRG-OS-000480-GPOS-00227 - A core dump includes a memory image taken at the time the operating system -terminates an application. The memory image could contain sensitive data -and is generally useful only for developers trying to debug problems. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -SOCKET_NAME="systemd-coredump.socket" -SYSTEMCTL_EXEC='/usr/bin/systemctl' - -if "$SYSTEMCTL_EXEC" -q list-unit-files --type socket | grep -q "$SOCKET_NAME"; then - "$SYSTEMCTL_EXEC" stop "$SOCKET_NAME" - "$SYSTEMCTL_EXEC" mask "$SOCKET_NAME" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Disable acquiring, saving, and processing core dumps - Collect systemd Socket - Units Present in the System - ansible.builtin.command: - cmd: systemctl -q list-unit-files --type socket - register: result_systemd_unit_files - changed_when: false - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-SC-7(10) - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_systemd-coredump_disabled - -- name: Disable acquiring, saving, and processing core dumps - Ensure systemd-coredump.socket - is Masked - ansible.builtin.systemd: - name: systemd-coredump.socket - state: stopped - enabled: false - masked: true - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - result_systemd_unit_files.stdout_lines is search("systemd-coredump.socket") - tags: - - NIST-800-53-SC-7(10) - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_systemd-coredump_disabled - - - - - - - - - - Disable core dump backtraces - The ProcessSizeMax option in [Coredump] section -of /etc/systemd/coredump.conf -specifies the maximum size in bytes of a core which will be processed. -Core dumps exceeding this size may be stored, but the backtrace will not -be generated. - If the /etc/systemd/coredump.conf file -does not already contain the [Coredump] section, -the value will not be configured correctly. - CCI-000366 - CM-6 - FMT_SMF_EXT.1 - Req-3.2 - 3.3.1.1 - 3.3.1.2 - 3.3.1.3 - SRG-OS-000480-GPOS-00227 - A core dump includes a memory image taken at the time the operating system -terminates an application. The memory image could contain sensitive data -and is generally useful only for developers or system operators trying to -debug problems. - -Enabling core dumps on production systems is not recommended, -however there may be overriding operational requirements to enable advanced -debuging. Permitting temporary enablement of core dumps during such situations -should be reviewed through local needs and policy. - - # Remediation is applicable only in certain platforms -if rpm --quiet -q systemd; then - -if [ -e "/etc/systemd/coredump.conf" ] ; then - - LC_ALL=C sed -i "/^\s*ProcessSizeMax\s*=\s*/Id" "/etc/systemd/coredump.conf" -else - touch "/etc/systemd/coredump.conf" -fi -# make sure file has newline at the end -sed -i -e '$a\' "/etc/systemd/coredump.conf" - -cp "/etc/systemd/coredump.conf" "/etc/systemd/coredump.conf.bak" -# Insert at the end of the file -printf '%s\n' "ProcessSizeMax=0" >> "/etc/systemd/coredump.conf" -# Clean up after ourselves. -rm "/etc/systemd/coredump.conf.bak" - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Gather the package facts - package_facts: - manager: auto - tags: - - NIST-800-53-CM-6 - - PCI-DSS-Req-3.2 - - PCI-DSSv4-3.3.1.1 - - PCI-DSSv4-3.3.1.2 - - PCI-DSSv4-3.3.1.3 - - coredump_disable_backtraces - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - -- name: Disable core dump backtraces - block: - - - name: Check for duplicate values - lineinfile: - path: /etc/systemd/coredump.conf - create: false - regexp: ^\s*ProcessSizeMax\s*=\s* - state: absent - check_mode: true - changed_when: false - register: dupes - - - name: Deduplicate values from /etc/systemd/coredump.conf - lineinfile: - path: /etc/systemd/coredump.conf - create: false - regexp: ^\s*ProcessSizeMax\s*=\s* - state: absent - when: dupes.found is defined and dupes.found > 1 - - - name: Insert correct line to /etc/systemd/coredump.conf - lineinfile: - path: /etc/systemd/coredump.conf - create: false - regexp: ^\s*ProcessSizeMax\s*=\s* - line: ProcessSizeMax=0 - state: present - when: '"systemd" in ansible_facts.packages' - tags: - - NIST-800-53-CM-6 - - PCI-DSS-Req-3.2 - - PCI-DSSv4-3.3.1.1 - - PCI-DSSv4-3.3.1.2 - - PCI-DSSv4-3.3.1.3 - - coredump_disable_backtraces - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - - - - - - - - - Disable storing core dump - The Storage option in [Coredump] sectionof /etc/systemd/coredump.conf -can be set to none to disable storing core dumps permanently. - If the /etc/systemd/coredump.conf file -does not already contain the [Coredump] section, -the value will not be configured correctly. - CCI-000366 - CM-6 - FMT_SMF_EXT.1 - Req-3.2 - 3.3.1.1 - 3.3.1.2 - 3.3.1.3 - SRG-OS-000480-GPOS-00227 - A core dump includes a memory image taken at the time the operating system -terminates an application. The memory image could contain sensitive data -and is generally useful only for developers or system operators trying to -debug problems. Enabling core dumps on production systems is not recommended, -however there may be overriding operational requirements to enable advanced -debuging. Permitting temporary enablement of core dumps during such situations -should be reviewed through local needs and policy. - - # Remediation is applicable only in certain platforms -if rpm --quiet -q systemd; then - -if [ -e "/etc/systemd/coredump.conf" ] ; then - - LC_ALL=C sed -i "/^\s*Storage\s*=\s*/Id" "/etc/systemd/coredump.conf" -else - touch "/etc/systemd/coredump.conf" -fi -# make sure file has newline at the end -sed -i -e '$a\' "/etc/systemd/coredump.conf" - -cp "/etc/systemd/coredump.conf" "/etc/systemd/coredump.conf.bak" -# Insert at the end of the file -printf '%s\n' "Storage=none" >> "/etc/systemd/coredump.conf" -# Clean up after ourselves. -rm "/etc/systemd/coredump.conf.bak" - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Gather the package facts - package_facts: - manager: auto - tags: - - NIST-800-53-CM-6 - - PCI-DSS-Req-3.2 - - PCI-DSSv4-3.3.1.1 - - PCI-DSSv4-3.3.1.2 - - PCI-DSSv4-3.3.1.3 - - coredump_disable_storage - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - -- name: Disable storing core dump - block: - - - name: Check for duplicate values - lineinfile: - path: /etc/systemd/coredump.conf - create: false - regexp: ^\s*Storage\s*=\s* - state: absent - check_mode: true - changed_when: false - register: dupes - - - name: Deduplicate values from /etc/systemd/coredump.conf - lineinfile: - path: /etc/systemd/coredump.conf - create: false - regexp: ^\s*Storage\s*=\s* - state: absent - when: dupes.found is defined and dupes.found > 1 - - - name: Insert correct line to /etc/systemd/coredump.conf - lineinfile: - path: /etc/systemd/coredump.conf - create: false - regexp: ^\s*Storage\s*=\s* - line: Storage=none - state: present - when: '"systemd" in ansible_facts.packages' - tags: - - NIST-800-53-CM-6 - - PCI-DSS-Req-3.2 - - PCI-DSSv4-3.3.1.1 - - PCI-DSSv4-3.3.1.2 - - PCI-DSSv4-3.3.1.3 - - coredump_disable_storage - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - - - - - - - - - Disable Core Dumps for All Users - To disable core dumps for all users, add the following line to -/etc/security/limits.conf, or to a file within the -/etc/security/limits.d/ directory: -* hard core 0 - 1 - 12 - 13 - 15 - 16 - 2 - 7 - 8 - APO13.01 - BAI04.04 - DSS01.03 - DSS03.05 - DSS05.07 - CCI-000366 - SR 6.2 - SR 7.1 - SR 7.2 - A.12.1.3 - A.17.2.1 - CM-6 - SC-7(10) - DE.CM-1 - PR.DS-4 - 3.3.1.1 - 3.3.1.2 - 3.3.1.3 - SRG-OS-000480-GPOS-00227 - A core dump includes a memory image taken at the time the operating system -terminates an application. The memory image could contain sensitive data and is generally useful -only for developers trying to debug problems. - - # Remediation is applicable only in certain platforms -if rpm --quiet -q pam; then - -SECURITY_LIMITS_FILE="/etc/security/limits.conf" - -if grep -qE '^\s*\*\s+hard\s+core' $SECURITY_LIMITS_FILE; then - sed -ri 's/(hard\s+core\s+)[[:digit:]]+/\1 0/' $SECURITY_LIMITS_FILE -else - echo "* hard core 0" >> $SECURITY_LIMITS_FILE -fi - -if ls /etc/security/limits.d/*.conf > /dev/null; then - sed -ri '/^\s*\*\s+hard\s+core/d' /etc/security/limits.d/*.conf -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Gather the package facts - package_facts: - manager: auto - tags: - - NIST-800-53-CM-6 - - NIST-800-53-SC-7(10) - - PCI-DSSv4-3.3.1.1 - - PCI-DSSv4-3.3.1.2 - - PCI-DSSv4-3.3.1.3 - - disable_users_coredumps - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - -- name: Disable core dumps with limits - lineinfile: - dest: /etc/security/limits.conf - regexp: ^[^#].*core - line: '* hard core 0' - create: true - when: '"pam" in ansible_facts.packages' - tags: - - NIST-800-53-CM-6 - - NIST-800-53-SC-7(10) - - PCI-DSSv4-3.3.1.1 - - PCI-DSSv4-3.3.1.2 - - PCI-DSSv4-3.3.1.3 - - disable_users_coredumps - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - - - - - - - - - Disable Core Dumps for SUID programs - To set the runtime status of the fs.suid_dumpable kernel parameter, run the following command: $ sudo sysctl -w fs.suid_dumpable=0 -To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: fs.suid_dumpable = 0 - BP28(R23) - 164.308(a)(1)(ii)(D) - 164.308(a)(3) - 164.308(a)(4) - 164.310(b) - 164.310(c) - 164.312(a) - 164.312(e) - SI-11(a) - SI-11(b) - 3.3.1.1 - 3.3.1.2 - 3.3.1.3 - The core dump of a setuid program is more likely to contain -sensitive data, as the program itself runs with greater privileges than the -user who initiated execution of the program. Disabling the ability for any -setuid program to write a core file decreases the risk of unauthorized access -of such data. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Comment out any occurrences of fs.suid_dumpable from /etc/sysctl.d/*.conf files - -for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do - - matching_list=$(grep -P '^(?!#).*[\s]*fs.suid_dumpable.*$' $f | uniq ) - if ! test -z "$matching_list"; then - while IFS= read -r entry; do - escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") - # comment out "fs.suid_dumpable" matches to preserve user data - sed -i "s/^${escaped_entry}$/# &/g" $f - done <<< "$matching_list" - fi -done - -# -# Set sysctl config file which to save the desired value -# - -SYSCONFIG_FILE="/etc/sysctl.conf" - - -# -# Set runtime for fs.suid_dumpable -# -/sbin/sysctl -q -n -w fs.suid_dumpable="0" - -# -# If fs.suid_dumpable present in /etc/sysctl.conf, change value to "0" -# else, add "fs.suid_dumpable = 0" to /etc/sysctl.conf -# - -# Strip any search characters in the key arg so that the key can be replaced without -# adding any search characters to the config file. -stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^fs.suid_dumpable") - -# shellcheck disable=SC2059 -printf -v formatted_output "%s = %s" "$stripped_key" "0" - -# If the key exists, change it. Otherwise, add it to the config_file. -# We search for the key string followed by a word boundary (matched by \>), -# so if we search for 'setting', 'setting2' won't match. -if LC_ALL=C grep -q -m 1 -i -e "^fs.suid_dumpable\\>" "${SYSCONFIG_FILE}"; then - escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") - LC_ALL=C sed -i --follow-symlinks "s/^fs.suid_dumpable\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" -else - if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then - LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" - fi - printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: List /etc/sysctl.d/*.conf files - find: - paths: - - /etc/sysctl.d/ - - /run/sysctl.d/ - - /usr/local/lib/sysctl.d/ - contains: ^[\s]*fs.suid_dumpable.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-SI-11(a) - - NIST-800-53-SI-11(b) - - PCI-DSSv4-3.3.1.1 - - PCI-DSSv4-3.3.1.2 - - PCI-DSSv4-3.3.1.3 - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_fs_suid_dumpable - -- name: Comment out any occurrences of fs.suid_dumpable from config files - replace: - path: '{{ item.path }}' - regexp: ^[\s]*fs.suid_dumpable - replace: '#fs.suid_dumpable' - loop: '{{ find_sysctl_d.files }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-SI-11(a) - - NIST-800-53-SI-11(b) - - PCI-DSSv4-3.3.1.1 - - PCI-DSSv4-3.3.1.2 - - PCI-DSSv4-3.3.1.3 - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_fs_suid_dumpable - -- name: Ensure sysctl fs.suid_dumpable is set to 0 - sysctl: - name: fs.suid_dumpable - value: '0' - sysctl_file: /etc/sysctl.conf - state: present - reload: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-SI-11(a) - - NIST-800-53-SI-11(b) - - PCI-DSSv4-3.3.1.1 - - PCI-DSSv4-3.3.1.2 - - PCI-DSSv4-3.3.1.3 - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_fs_suid_dumpable - - - - - - - - - - - Daemon Umask - The umask is a per-process setting which limits -the default permissions for creation of new files and directories. -The system includes initialization scripts which set the default umask -for system daemons. - - daemon umask - Enter umask for daemons - 022 - 027 - 022 - - - - Enable ExecShield - ExecShield describes kernel features that provide -protection against exploitation of memory corruption errors such as buffer -overflows. These features include random placement of the stack and other -memory regions, prevention of execution in memory that should only hold data, -and special handling of text buffers. These protections are enabled by default -on 32-bit systems and controlled through sysctl variables -kernel.exec-shield and kernel.randomize_va_space. On the latest -64-bit systems, kernel.exec-shield cannot be enabled or disabled with -sysctl. - - kernel.kptr_restrict - Configure exposition of kernel pointer addresses - 1 - 1 - 2 - - - Restrict Exposed Kernel Pointer Addresses Access - To set the runtime status of the kernel.kptr_restrict kernel parameter, run the following command: $ sudo sysctl -w kernel.kptr_restrict= -To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: kernel.kptr_restrict = - BP28(R23) - CCI-002824 - CCI-000366 - CIP-002-5 R1.1 - CIP-002-5 R1.2 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 4.1 - CIP-004-6 4.2 - CIP-004-6 R2.2.3 - CIP-004-6 R2.2.4 - CIP-004-6 R2.3 - CIP-004-6 R4 - CIP-005-6 R1 - CIP-005-6 R1.1 - CIP-005-6 R1.2 - CIP-007-3 R3 - CIP-007-3 R3.1 - CIP-007-3 R5.1 - CIP-007-3 R5.1.2 - CIP-007-3 R5.1.3 - CIP-007-3 R5.2.1 - CIP-007-3 R5.2.3 - CIP-007-3 R8.4 - CIP-009-6 R.1.1 - CIP-009-6 R4 - SC-30 - SC-30(2) - SC-30(5) - CM-6(a) - SRG-OS-000132-GPOS-00067 - SRG-OS-000433-GPOS-00192 - SRG-OS-000480-GPOS-00227 - Exposing kernel pointers (through procfs or seq_printf()) exposes kernel -writeable structures which may contain functions pointers. If a write vulnerability -occurs in the kernel, allowing write access to any of this structure, the kernel can -be compromised. This option disallow any program without the CAP_SYSLOG capability -to get the addresses of kernel pointers by replacing them with 0. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Comment out any occurrences of kernel.kptr_restrict from /etc/sysctl.d/*.conf files - -for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do - - matching_list=$(grep -P '^(?!#).*[\s]*kernel.kptr_restrict.*$' $f | uniq ) - if ! test -z "$matching_list"; then - while IFS= read -r entry; do - escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") - # comment out "kernel.kptr_restrict" matches to preserve user data - sed -i "s/^${escaped_entry}$/# &/g" $f - done <<< "$matching_list" - fi -done - -# -# Set sysctl config file which to save the desired value -# - -SYSCONFIG_FILE="/etc/sysctl.conf" - -sysctl_kernel_kptr_restrict_value='' - - -# -# Set runtime for kernel.kptr_restrict -# -/sbin/sysctl -q -n -w kernel.kptr_restrict="$sysctl_kernel_kptr_restrict_value" - -# -# If kernel.kptr_restrict present in /etc/sysctl.conf, change value to appropriate value -# else, add "kernel.kptr_restrict = value" to /etc/sysctl.conf -# - -# Strip any search characters in the key arg so that the key can be replaced without -# adding any search characters to the config file. -stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^kernel.kptr_restrict") - -# shellcheck disable=SC2059 -printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_kernel_kptr_restrict_value" - -# If the key exists, change it. Otherwise, add it to the config_file. -# We search for the key string followed by a word boundary (matched by \>), -# so if we search for 'setting', 'setting2' won't match. -if LC_ALL=C grep -q -m 1 -i -e "^kernel.kptr_restrict\\>" "${SYSCONFIG_FILE}"; then - escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") - LC_ALL=C sed -i --follow-symlinks "s/^kernel.kptr_restrict\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" -else - if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then - LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" - fi - printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: List /etc/sysctl.d/*.conf files - find: - paths: - - /etc/sysctl.d/ - - /run/sysctl.d/ - - /usr/local/lib/sysctl.d/ - contains: ^[\s]*kernel.kptr_restrict.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-SC-30 - - NIST-800-53-SC-30(2) - - NIST-800-53-SC-30(5) - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_kernel_kptr_restrict - -- name: Comment out any occurrences of kernel.kptr_restrict from config files - replace: - path: '{{ item.path }}' - regexp: ^[\s]*kernel.kptr_restrict - replace: '#kernel.kptr_restrict' - loop: '{{ find_sysctl_d.files }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-SC-30 - - NIST-800-53-SC-30(2) - - NIST-800-53-SC-30(5) - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_kernel_kptr_restrict -- name: XCCDF Value sysctl_kernel_kptr_restrict_value # promote to variable - set_fact: - sysctl_kernel_kptr_restrict_value: !!str - tags: - - always - -- name: Ensure sysctl kernel.kptr_restrict is set - sysctl: - name: kernel.kptr_restrict - value: '{{ sysctl_kernel_kptr_restrict_value }}' - sysctl_file: /etc/sysctl.conf - state: present - reload: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-SC-30 - - NIST-800-53-SC-30(2) - - NIST-800-53-SC-30(5) - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_kernel_kptr_restrict - - - - - - - - - - Enable Randomized Layout of Virtual Address Space - To set the runtime status of the kernel.randomize_va_space kernel parameter, run the following command: $ sudo sysctl -w kernel.randomize_va_space=2 -To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: kernel.randomize_va_space = 2 - BP28(R23) - 3.1.7 - CCI-000366 - CCI-002824 - 164.308(a)(1)(ii)(D) - 164.308(a)(3) - 164.308(a)(4) - 164.310(b) - 164.310(c) - 164.312(a) - 164.312(e) - CIP-002-5 R1.1 - CIP-002-5 R1.2 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 4.1 - CIP-004-6 4.2 - CIP-004-6 R2.2.3 - CIP-004-6 R2.2.4 - CIP-004-6 R2.3 - CIP-004-6 R4 - CIP-005-6 R1 - CIP-005-6 R1.1 - CIP-005-6 R1.2 - CIP-007-3 R3 - CIP-007-3 R3.1 - CIP-007-3 R5.1 - CIP-007-3 R5.1.2 - CIP-007-3 R5.1.3 - CIP-007-3 R5.2.1 - CIP-007-3 R5.2.3 - CIP-007-3 R8.4 - CIP-009-6 R.1.1 - CIP-009-6 R4 - SC-30 - SC-30(2) - CM-6(a) - Req-2.2.1 - 2.2.3 - SRG-OS-000433-GPOS-00193 - SRG-OS-000480-GPOS-00227 - SRG-APP-000450-CTR-001105 - Address space layout randomization (ASLR) makes it more difficult for an -attacker to predict the location of attack code they have introduced into a -process's address space during an attempt at exploitation. Additionally, -ASLR makes it more difficult for an attacker to know the location of -existing code in order to re-purpose it using return oriented programming -(ROP) techniques. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Comment out any occurrences of kernel.randomize_va_space from /etc/sysctl.d/*.conf files - -for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do - - matching_list=$(grep -P '^(?!#).*[\s]*kernel.randomize_va_space.*$' $f | uniq ) - if ! test -z "$matching_list"; then - while IFS= read -r entry; do - escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry") - # comment out "kernel.randomize_va_space" matches to preserve user data - sed -i "s/^${escaped_entry}$/# &/g" $f - done <<< "$matching_list" - fi -done - -# -# Set sysctl config file which to save the desired value -# - -SYSCONFIG_FILE="/etc/sysctl.conf" - - -# -# Set runtime for kernel.randomize_va_space -# -/sbin/sysctl -q -n -w kernel.randomize_va_space="2" - -# -# If kernel.randomize_va_space present in /etc/sysctl.conf, change value to "2" -# else, add "kernel.randomize_va_space = 2" to /etc/sysctl.conf -# - -# Strip any search characters in the key arg so that the key can be replaced without -# adding any search characters to the config file. -stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^kernel.randomize_va_space") - -# shellcheck disable=SC2059 -printf -v formatted_output "%s = %s" "$stripped_key" "2" - -# If the key exists, change it. Otherwise, add it to the config_file. -# We search for the key string followed by a word boundary (matched by \>), -# so if we search for 'setting', 'setting2' won't match. -if LC_ALL=C grep -q -m 1 -i -e "^kernel.randomize_va_space\\>" "${SYSCONFIG_FILE}"; then - escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") - LC_ALL=C sed -i --follow-symlinks "s/^kernel.randomize_va_space\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}" -else - if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then - LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}" - fi - printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: List /etc/sysctl.d/*.conf files - find: - paths: - - /etc/sysctl.d/ - - /run/sysctl.d/ - - /usr/local/lib/sysctl.d/ - contains: ^[\s]*kernel.randomize_va_space.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.7 - - NIST-800-53-CM-6(a) - - NIST-800-53-SC-30 - - NIST-800-53-SC-30(2) - - PCI-DSS-Req-2.2.1 - - PCI-DSSv4-2.2.3 - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_kernel_randomize_va_space - -- name: Comment out any occurrences of kernel.randomize_va_space from config files - replace: - path: '{{ item.path }}' - regexp: ^[\s]*kernel.randomize_va_space - replace: '#kernel.randomize_va_space' - loop: '{{ find_sysctl_d.files }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.7 - - NIST-800-53-CM-6(a) - - NIST-800-53-SC-30 - - NIST-800-53-SC-30(2) - - PCI-DSS-Req-2.2.1 - - PCI-DSSv4-2.2.3 - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_kernel_randomize_va_space - -- name: Ensure sysctl kernel.randomize_va_space is set to 2 - sysctl: - name: kernel.randomize_va_space - value: '2' - sysctl_file: /etc/sysctl.conf - state: present - reload: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.7 - - NIST-800-53-CM-6(a) - - NIST-800-53-SC-30 - - NIST-800-53-SC-30(2) - - PCI-DSS-Req-2.2.1 - - PCI-DSSv4-2.2.3 - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_kernel_randomize_va_space - - - - - - - - - - - Enable Execute Disable (XD) or No Execute (NX) Support on -x86 Systems - Recent processors in the x86 family support the -ability to prevent code execution on a per memory page basis. -Generically and on AMD processors, this ability is called No -Execute (NX), while on Intel processors it is called Execute -Disable (XD). This ability can help prevent exploitation of buffer -overflow vulnerabilities and should be activated whenever possible. -Extra steps must be taken to ensure that this protection is -enabled, particularly on 32-bit x86 systems. Other processors, such -as Itanium and POWER, have included such support since inception -and the standard kernel for those platforms supports the -feature. This is enabled by default on the latest Oracle Linux, Red Hat and -Fedora systems if supported by the hardware. - - Enable NX or XD Support in the BIOS - Reboot the system and enter the BIOS or Setup configuration menu. -Navigate the BIOS configuration menu and make sure that the option is enabled. The setting may be located -under a Security section. Look for Execute Disable (XD) on Intel-based systems and No Execute (NX) -on AMD-based systems. - 11 - 3 - 9 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - 3.1.7 - CCI-002824 - 4.3.4.3.2 - 4.3.4.3.3 - SR 7.6 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.14.2.2 - A.14.2.3 - A.14.2.4 - SC-39 - CM-6(a) - PR.IP-1 - 2.2.1 - SRG-OS-000433-GPOS-00192 - SRG-APP-000450-CTR-001105 - Computers with the ability to prevent this type of code execution frequently put an option in the BIOS that will -allow users to turn the feature on or off at will. - - - - - - - - - - - Memory Poisoning - Memory Poisoning consists of writing a special value to uninitialized or freed memory. -Poisoning can be used as a mechanism to prevent leak of information and detection of -corrupted memory. - - - slub_debug - debug options - Defines the debug options to use in slub_debug kernel command line argument. - P - F - Z - P - FZ - FZP - - - Enable page allocator poisoning - To enable poisoning of free pages, -add the argument page_poison=1 to the default -GRUB 2 command line for the Linux operating system. -To ensure that page_poison=1 is added as a kernel command line -argument to newly installed kernels, add page_poison=1 to the -default Grub2 command line for Linux operating systems. Modify the line within -/etc/default/grub as shown below: -GRUB_CMDLINE_LINUX="... page_poison=1 ..." -Run the following command to update command line for already installed kernels:# grubby --update-kernel=ALL --args="page_poison=1" - BP28(R8) - CCI-001084 - CM-6(a) - SRG-OS-000480-GPOS-00227 - SRG-OS-000134-GPOS-00068 - Poisoning writes an arbitrary value to freed pages, so any modification or -reference to that page after being freed or before being initialized will be -detected and prevented. -This prevents many types of use-after-free vulnerabilities at little performance cost. -Also prevents leak of data and detection of corrupted memory. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && { rpm --quiet -q grub2-common; }; then - -grubby --update-kernel=ALL --args=page_poison=1 - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Gather the package facts - package_facts: - manager: auto - tags: - - NIST-800-53-CM-6(a) - - grub2_page_poison_argument - - low_disruption - - medium_complexity - - medium_severity - - reboot_required - - restrict_strategy - -- name: Update grub defaults and the bootloader menu - command: /sbin/grubby --update-kernel=ALL --args="page_poison=1" - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - '"grub2-common" in ansible_facts.packages' - tags: - - NIST-800-53-CM-6(a) - - grub2_page_poison_argument - - low_disruption - - medium_complexity - - medium_severity - - reboot_required - - restrict_strategy - - [customizations.kernel] -append = "page_poison=1" - - - - - - - - - - Enable SLUB/SLAB allocator poisoning - To enable poisoning of SLUB/SLAB objects, -add the argument slub_debug= to the default -GRUB 2 command line for the Linux operating system. -To ensure that slub_debug= is added as a kernel command line -argument to newly installed kernels, add slub_debug= to the -default Grub2 command line for Linux operating systems. Modify the line within -/etc/default/grub as shown below: -GRUB_CMDLINE_LINUX="... slub_debug= ..." -Run the following command to update command line for already installed kernels:# grubby --update-kernel=ALL --args="slub_debug=" - BP28(R8) - CCI-001084 - CM-6(a) - SRG-OS-000433-GPOS-00192 - SRG-OS-000134-GPOS-00068 - Poisoning writes an arbitrary value to freed objects, so any modification or -reference to that object after being freed or before being initialized will be -detected and prevented. -This prevents many types of use-after-free vulnerabilities at little performance cost. -Also prevents leak of data and detection of corrupted memory. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && { rpm --quiet -q grub2-common; }; then - -var_slub_debug_options='' - - - -grubby --update-kernel=ALL --args=slub_debug=$var_slub_debug_options - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Gather the package facts - package_facts: - manager: auto - tags: - - NIST-800-53-CM-6(a) - - grub2_slub_debug_argument - - low_disruption - - medium_complexity - - medium_severity - - reboot_required - - restrict_strategy -- name: XCCDF Value var_slub_debug_options # promote to variable - set_fact: - var_slub_debug_options: !!str - tags: - - always - -- name: Update grub defaults and the bootloader menu - command: /sbin/grubby --update-kernel=ALL --args="slub_debug={{ var_slub_debug_options - }}" - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - '"grub2-common" in ansible_facts.packages' - tags: - - NIST-800-53-CM-6(a) - - grub2_slub_debug_argument - - low_disruption - - medium_complexity - - medium_severity - - reboot_required - - restrict_strategy - - [customizations.kernel] -append = "slub_debug=" - - - - - - - - - - - - - - SELinux - SELinux is a feature of the Linux kernel which can be -used to guard against misconfigured or compromised programs. -SELinux enforces the idea that programs should be limited in what -files they can access and what actions they can take. - -The default SELinux policy, as configured on Oracle Linux 9, has been -sufficiently developed and debugged that it should be usable on -almost any system with minimal configuration and a small -amount of system administrator training. This policy prevents -system services - including most of the common network-visible -services such as mail servers, FTP servers, and DNS servers - from -accessing files which those services have no valid reason to -access. This action alone prevents a huge amount of possible damage -from network attacks against services, from trojaned software, and -so forth. - -This guide recommends that SELinux be enabled using the -default (targeted) policy on every Oracle Linux 9 system, unless that -system has unusual requirements which make a stronger policy -appropriate. - -For more information on SELinux, see https://docs.oracle.com/en/operating-systems/oracle-linux/selinux/. - - - SELinux policy - Type of policy in use. Possible values are: -targeted - Only targeted network daemons are protected. -strict - Full SELinux protection. -mls - Multiple levels of security - targeted - mls - targeted - - - SELinux state - enforcing - SELinux security policy is enforced. -permissive - SELinux prints warnings instead of enforcing. -disabled - SELinux is fully disabled. - enforcing - disabled - enforcing - permissive - - - Install policycoreutils-python-utils package - The policycoreutils-python-utils package can be installed with the following command: - -$ sudo yum install policycoreutils-python-utils - SRG-OS-000480-GPOS-00227 - This package is required to operate and manage an SELinux environment and its policies. -It provides utilities such as semanage, audit2allow, audit2why, chcat and sandbox. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -if ! rpm -q --quiet "policycoreutils-python-utils" ; then - yum install -y "policycoreutils-python-utils" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Ensure policycoreutils-python-utils is installed - package: - name: policycoreutils-python-utils - state: present - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - enable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - package_policycoreutils-python-utils_installed - - include install_policycoreutils-python-utils - -class install_policycoreutils-python-utils { - package { 'policycoreutils-python-utils': - ensure => 'installed', - } -} - - -package --add=policycoreutils-python-utils - - -[[packages]] -name = "policycoreutils-python-utils" -version = "*" - - - - - - - - - - Install policycoreutils Package - The policycoreutils package can be installed with the following command: - -$ sudo yum install policycoreutils - CCI-001084 - SRG-OS-000480-GPOS-00227 - SRG-OS-000134-GPOS-00068 - Security-enhanced Linux is a feature of the Linux kernel and a number of utilities -with enhanced security functionality designed to add mandatory access controls to Linux. -The Security-enhanced Linux kernel contains new architectural components originally -developed to improve security of the Flask operating system. These architectural components -provide general support for the enforcement of many kinds of mandatory access control -policies, including those based on the concepts of Type Enforcement, Role-based Access -Control, and Multi-level Security. - -policycoreutils contains the policy core utilities that are required for -basic operation of an SELinux-enabled system. These utilities include load_policy -to load SELinux policies, setfiles to label filesystems, newrole to -switch roles, and so on. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -if ! rpm -q --quiet "policycoreutils" ; then - yum install -y "policycoreutils" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Ensure policycoreutils is installed - package: - name: policycoreutils - state: present - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - enable_strategy - - low_complexity - - low_disruption - - low_severity - - no_reboot_needed - - package_policycoreutils_installed - - include install_policycoreutils - -class install_policycoreutils { - package { 'policycoreutils': - ensure => 'installed', - } -} - - -package --add=policycoreutils - - -[[packages]] -name = "policycoreutils" -version = "*" - - - - - - - - - - Uninstall setroubleshoot-plugins Package - The SETroubleshoot plugins are used to analyze SELinux AVC data. The service provides information around configuration errors, -unauthorized intrusions, and other potential errors. -The setroubleshoot-plugins package can be removed with the following command: - -$ sudo yum erase setroubleshoot-plugins - BP28(R68) - The SETroubleshoot service is an unnecessary daemon to -have running on a server. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# CAUTION: This remediation script will remove setroubleshoot-plugins -# from the system, and may remove any packages -# that depend on setroubleshoot-plugins. Execute this -# remediation AFTER testing on a non-production -# system! - -if rpm -q --quiet "setroubleshoot-plugins" ; then - - yum remove -y "setroubleshoot-plugins" - -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Ensure setroubleshoot-plugins is removed - package: - name: setroubleshoot-plugins - state: absent - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - low_disruption - - low_severity - - no_reboot_needed - - package_setroubleshoot-plugins_removed - - include remove_setroubleshoot-plugins - -class remove_setroubleshoot-plugins { - package { 'setroubleshoot-plugins': - ensure => 'purged', - } -} - - -package --remove=setroubleshoot-plugins - - - - - - - - - - Uninstall setroubleshoot-server Package - The SETroubleshoot service notifies desktop users of SELinux -denials. The service provides information around configuration errors, -unauthorized intrusions, and other potential errors. -The setroubleshoot-server package can be removed with the following command: - -$ sudo yum erase setroubleshoot-server - BP28(R68) - The SETroubleshoot service is an unnecessary daemon to have -running on a server. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# CAUTION: This remediation script will remove setroubleshoot-server -# from the system, and may remove any packages -# that depend on setroubleshoot-server. Execute this -# remediation AFTER testing on a non-production -# system! - -if rpm -q --quiet "setroubleshoot-server" ; then - - yum remove -y "setroubleshoot-server" - -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Ensure setroubleshoot-server is removed - package: - name: setroubleshoot-server - state: absent - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - low_disruption - - low_severity - - no_reboot_needed - - package_setroubleshoot-server_removed - - include remove_setroubleshoot-server - -class remove_setroubleshoot-server { - package { 'setroubleshoot-server': - ensure => 'purged', - } -} - - -package --remove=setroubleshoot-server - - - - - - - - - - Uninstall setroubleshoot Package - The SETroubleshoot service notifies desktop users of SELinux -denials. The service provides information around configuration errors, -unauthorized intrusions, and other potential errors. -The setroubleshoot package can be removed with the following command: - -$ sudo yum erase setroubleshoot - BP28(R68) - The SETroubleshoot service is an unnecessary daemon to -have running on a server, especially if -X Windows is removed or disabled. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# CAUTION: This remediation script will remove setroubleshoot -# from the system, and may remove any packages -# that depend on setroubleshoot. Execute this -# remediation AFTER testing on a non-production -# system! - -if rpm -q --quiet "setroubleshoot" ; then - - yum remove -y "setroubleshoot" - -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Ensure setroubleshoot is removed - package: - name: setroubleshoot - state: absent - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - low_disruption - - low_severity - - no_reboot_needed - - package_setroubleshoot_removed - - include remove_setroubleshoot - -class remove_setroubleshoot { - package { 'setroubleshoot': - ensure => 'purged', - } -} - - -package --remove=setroubleshoot - - - - - - - Ensure SELinux Not Disabled in /etc/default/grub - SELinux can be disabled at boot time by an argument in -/etc/default/grub. -Remove any instances of selinux=0 from the kernel arguments in that -file to prevent SELinux from being disabled at boot. - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 4 - 5 - 6 - 8 - 9 - APO01.06 - APO11.04 - APO13.01 - BAI03.05 - DSS01.05 - DSS03.01 - DSS05.02 - DSS05.04 - DSS05.05 - DSS05.07 - DSS06.02 - DSS06.03 - DSS06.06 - MEA02.01 - 3.1.2 - 3.7.2 - CCI-000022 - CCI-000032 - 164.308(a)(1)(ii)(D) - 164.308(a)(3) - 164.308(a)(4) - 164.310(b) - 164.310(c) - 164.312(a) - 164.312(e) - 4.2.3.4 - 4.3.3.2.2 - 4.3.3.3.9 - 4.3.3.4 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.4.7 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - 4.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 2.8 - SR 2.9 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 7.1 - SR 7.6 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.12.1.1 - A.12.1.2 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.13.1.1 - A.13.1.2 - A.13.1.3 - A.13.2.1 - A.13.2.2 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.1 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.2.3 - CIP-004-6 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.2 - CIP-007-3 R5.2 - CIP-007-3 R5.3.1 - CIP-007-3 R5.3.2 - CIP-007-3 R5.3.3 - AC-3 - AC-3(3)(a) - DE.AE-1 - ID.AM-3 - PR.AC-4 - PR.AC-5 - PR.AC-6 - PR.DS-5 - PR.PT-1 - PR.PT-3 - PR.PT-4 - Disabling a major host protection feature, such as SELinux, at boot time prevents -it from confining system services at boot time. Further, it increases -the chances that it will remain off during system operation. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && { rpm --quiet -q grub2-common; }; then - -sed -i --follow-symlinks "s/selinux=0//gI" /etc/default/grub /etc/grub2.cfg /etc/grub.d/* -sed -i --follow-symlinks "s/enforcing=0//gI" /etc/default/grub /etc/grub2.cfg /etc/grub.d/* - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Gather the package facts - package_facts: - manager: auto - tags: - - NIST-800-171-3.1.2 - - NIST-800-171-3.7.2 - - NIST-800-53-AC-3 - - NIST-800-53-AC-3(3)(a) - - grub2_enable_selinux - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - -- name: Ensure SELinux Not Disabled in /etc/default/grub - Find /etc/grub.d/ files - ansible.builtin.find: - paths: - - /etc/grub.d/ - follow: true - register: result_grub_d - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - '"grub2-common" in ansible_facts.packages' - tags: - - NIST-800-171-3.1.2 - - NIST-800-171-3.7.2 - - NIST-800-53-AC-3 - - NIST-800-53-AC-3(3)(a) - - grub2_enable_selinux - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - -- name: Ensure SELinux Not Disabled in /etc/default/grub - Ensure SELinux Not Disabled - in /etc/grub.d/ files - ansible.builtin.replace: - dest: '{{ item.path }}' - regexp: (selinux|enforcing)=0 - with_items: - - '{{ result_grub_d.files }}' - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - '"grub2-common" in ansible_facts.packages' - tags: - - NIST-800-171-3.1.2 - - NIST-800-171-3.7.2 - - NIST-800-53-AC-3 - - NIST-800-53-AC-3(3)(a) - - grub2_enable_selinux - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - -- name: Ensure SELinux Not Disabled in /etc/default/grub - Check if /etc/grub2.cfg - exists - ansible.builtin.stat: - path: /etc/grub2.cfg - register: result_grub2_cfg_present - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - '"grub2-common" in ansible_facts.packages' - tags: - - NIST-800-171-3.1.2 - - NIST-800-171-3.7.2 - - NIST-800-53-AC-3 - - NIST-800-53-AC-3(3)(a) - - grub2_enable_selinux - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - -- name: Ensure SELinux Not Disabled in /etc/default/grub - Check if /etc/default/grub - exists - ansible.builtin.stat: - path: /etc/default/grub - register: result_default_grub_present - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - '"grub2-common" in ansible_facts.packages' - tags: - - NIST-800-171-3.1.2 - - NIST-800-171-3.7.2 - - NIST-800-53-AC-3 - - NIST-800-53-AC-3(3)(a) - - grub2_enable_selinux - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - -- name: Ensure SELinux Not Disabled in /etc/default/grub - Ensure SELinux Not Disabled - in /etc/grub2.cfg - ansible.builtin.replace: - dest: /etc/grub2.cfg - regexp: (selinux|enforcing)=0 - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - '"grub2-common" in ansible_facts.packages' - - result_grub2_cfg_present.stat.exists - tags: - - NIST-800-171-3.1.2 - - NIST-800-171-3.7.2 - - NIST-800-53-AC-3 - - NIST-800-53-AC-3(3)(a) - - grub2_enable_selinux - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - -- name: Ensure SELinux Not Disabled in /etc/default/grub - Ensure SELinux Not Disabled - in /etc/default/grub - ansible.builtin.replace: - dest: /etc/default/grub - regexp: (selinux|enforcing)=0 - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - '"grub2-common" in ansible_facts.packages' - - result_default_grub_present.stat.exists - tags: - - NIST-800-171-3.1.2 - - NIST-800-171-3.7.2 - - NIST-800-53-AC-3 - - NIST-800-53-AC-3(3)(a) - - grub2_enable_selinux - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - - - - - - - - - Ensure No Daemons are Unconfined by SELinux - Daemons for which the SELinux policy does not contain rules will inherit the -context of the parent process. Because daemons are launched during -startup and descend from the init process, they inherit the unconfined_service_t context. - - -To check for unconfined daemons, run the following command: -$ sudo ps -eZ | grep "unconfined_service_t" -It should produce no output in a well-configured system. - Automatic remediation of this control is not available. Remediation -can be achieved by amending SELinux policy or stopping the unconfined -daemons as outlined above. - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - 6 - 9 - APO01.06 - APO11.04 - BAI03.05 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS05.02 - DSS05.04 - DSS05.05 - DSS05.07 - DSS06.02 - DSS06.06 - MEA02.01 - 3.1.2 - 3.1.5 - 3.7.2 - 164.308(a)(1)(ii)(D) - 164.308(a)(3) - 164.308(a)(4) - 164.310(b) - 164.310(c) - 164.312(a) - 164.312(e) - 4.3.3.3.9 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - 4.3.4.4.7 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 2.8 - SR 2.9 - SR 5.2 - SR 7.6 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.12.1.2 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.5.1 - A.12.6.2 - A.12.7.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 - CM-7(a) - CM-7(b) - CM-6(a) - AC-3(3)(a) - AC-6 - PR.AC-4 - PR.DS-5 - PR.IP-1 - PR.PT-1 - PR.PT-3 - Daemons which run with the unconfined_service_t context may cause AVC denials, -or allow privileges that the daemon does not require. - - - - - - - - - Ensure SELinux is Not Disabled - The SELinux state should be set to enforcing or permissive at system boot -time. In the file /etc/selinux/config, add or correct the following line to configure -the system to boot into enforcing or permissive mode: -SELINUX=enforcing -OR -SELINUX=permissive - In case the SELinux is "disabled", the automated remediation will adopt a more -conservative approach and set it to "permissive" in order to avoid any system disruption -and give the administrator the opportunity to assess the impact and necessary efforts -before setting it to "enforcing", which is strongly recommended. - Running SELinux in disabled mode is strongly discouraged. It prevents enforcing the SELinux -controls without a system reboot. It also avoids labeling any persistent objects such as -files, making it difficult to enable SELinux in the future. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -if [ -e "/etc/selinux/config" ] ; then - - LC_ALL=C sed -i "/^SELINUX=/Id" "/etc/selinux/config" -else - touch "/etc/selinux/config" -fi -# make sure file has newline at the end -sed -i -e '$a\' "/etc/selinux/config" - -cp "/etc/selinux/config" "/etc/selinux/config.bak" -# Insert at the end of the file -printf '%s\n' "SELINUX=permissive" >> "/etc/selinux/config" -# Clean up after ourselves. -rm "/etc/selinux/config.bak" - -fixfiles onboot -fixfiles -f relabel - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Ensure SELinux is Not Disabled - block: - - - name: Check for duplicate values - lineinfile: - path: /etc/selinux/config - create: false - regexp: ^SELINUX= - state: absent - check_mode: true - changed_when: false - register: dupes - - - name: Deduplicate values from /etc/selinux/config - lineinfile: - path: /etc/selinux/config - create: false - regexp: ^SELINUX= - state: absent - when: dupes.found is defined and dupes.found > 1 - - - name: Insert correct line to /etc/selinux/config - lineinfile: - path: /etc/selinux/config - create: true - regexp: ^SELINUX= - line: SELINUX=permissive - state: present - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - high_severity - - low_complexity - - low_disruption - - reboot_required - - restrict_strategy - - selinux_not_disabled - - - - - - - - - - Configure SELinux Policy - The SELinux targeted policy is appropriate for -general-purpose desktops and servers, as well as systems in many other roles. -To configure the system to use this policy, add or correct the following line -in /etc/selinux/config: -SELINUXTYPE= -Other policies, such as mls, provide additional security labeling -and greater confinement but are not compatible with many general-purpose -use cases. - BP28(R66) - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 4 - 5 - 6 - 8 - 9 - APO01.06 - APO11.04 - APO13.01 - BAI03.05 - DSS01.05 - DSS03.01 - DSS05.02 - DSS05.04 - DSS05.05 - DSS05.07 - DSS06.02 - DSS06.03 - DSS06.06 - MEA02.01 - 3.1.2 - 3.7.2 - CCI-002165 - CCI-002696 - 164.308(a)(1)(ii)(D) - 164.308(a)(3) - 164.308(a)(4) - 164.310(b) - 164.310(c) - 164.312(a) - 164.312(e) - 4.2.3.4 - 4.3.3.2.2 - 4.3.3.3.9 - 4.3.3.4 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.4.7 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - 4.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 2.8 - SR 2.9 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 7.1 - SR 7.6 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.12.1.1 - A.12.1.2 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.13.1.1 - A.13.1.2 - A.13.1.3 - A.13.2.1 - A.13.2.2 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.1 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.2 - CIP-003-8 R5.3 - CIP-004-6 R2.2.3 - CIP-004-6 R2.3 - CIP-004-6 R3.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.2 - CIP-007-3 R5.2 - CIP-007-3 R5.3.1 - CIP-007-3 R5.3.2 - CIP-007-3 R5.3.3 - CIP-007-3 R6.5 - AC-3 - AC-3(3)(a) - AU-9 - SC-7(21) - DE.AE-1 - ID.AM-3 - PR.AC-4 - PR.AC-5 - PR.AC-6 - PR.DS-5 - PR.PT-1 - PR.PT-3 - PR.PT-4 - SRG-OS-000445-GPOS-00199 - SRG-APP-000233-CTR-000585 - Setting the SELinux policy to targeted or a more specialized policy -ensures the system will confine processes that are likely to be -targeted for exploitation, such as network or system services. - -Note: During the development or debugging of SELinux modules, it is common to -temporarily place non-production systems in permissive mode. In such -temporary cases, SELinux policies should be developed, and once work -is completed, the system should be reconfigured to -. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -var_selinux_policy_name='' - - -if [ -e "/etc/selinux/config" ] ; then - - LC_ALL=C sed -i "/^SELINUXTYPE=/Id" "/etc/selinux/config" -else - touch "/etc/selinux/config" -fi -# make sure file has newline at the end -sed -i -e '$a\' "/etc/selinux/config" - -cp "/etc/selinux/config" "/etc/selinux/config.bak" -# Insert at the end of the file -printf '%s\n' "SELINUXTYPE=$var_selinux_policy_name" >> "/etc/selinux/config" -# Clean up after ourselves. -rm "/etc/selinux/config.bak" - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: XCCDF Value var_selinux_policy_name # promote to variable - set_fact: - var_selinux_policy_name: !!str - tags: - - always - -- name: Configure SELinux Policy - block: - - - name: Check for duplicate values - lineinfile: - path: /etc/selinux/config - create: false - regexp: ^SELINUXTYPE= - state: absent - check_mode: true - changed_when: false - register: dupes - - - name: Deduplicate values from /etc/selinux/config - lineinfile: - path: /etc/selinux/config - create: false - regexp: ^SELINUXTYPE= - state: absent - when: dupes.found is defined and dupes.found > 1 - - - name: Insert correct line to /etc/selinux/config - lineinfile: - path: /etc/selinux/config - create: true - regexp: ^SELINUXTYPE= - line: SELINUXTYPE={{ var_selinux_policy_name }} - state: present - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.2 - - NIST-800-171-3.7.2 - - NIST-800-53-AC-3 - - NIST-800-53-AC-3(3)(a) - - NIST-800-53-AU-9 - - NIST-800-53-SC-7(21) - - low_complexity - - low_disruption - - medium_severity - - reboot_required - - restrict_strategy - - selinux_policytype - - - - - - - - - - - Ensure SELinux State is Enforcing - The SELinux state should be set to at -system boot time. In the file /etc/selinux/config, add or correct the -following line to configure the system to boot into enforcing mode: -SELINUX= - BP28(R4) - BP28(R66) - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 4 - 5 - 6 - 8 - 9 - APO01.06 - APO11.04 - APO13.01 - BAI03.05 - DSS01.05 - DSS03.01 - DSS05.02 - DSS05.04 - DSS05.05 - DSS05.07 - DSS06.02 - DSS06.03 - DSS06.06 - MEA02.01 - 3.1.2 - 3.7.2 - CCI-001084 - CCI-002165 - CCI-002696 - 164.308(a)(1)(ii)(D) - 164.308(a)(3) - 164.308(a)(4) - 164.310(b) - 164.310(c) - 164.312(a) - 164.312(e) - 4.2.3.4 - 4.3.3.2.2 - 4.3.3.3.9 - 4.3.3.4 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.4.7 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - 4.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 2.8 - SR 2.9 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 7.1 - SR 7.6 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.12.1.1 - A.12.1.2 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.13.1.1 - A.13.1.2 - A.13.1.3 - A.13.2.1 - A.13.2.2 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.1 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.2 - CIP-003-8 R5.3 - CIP-004-6 R2.2.3 - CIP-004-6 R2.3 - CIP-004-6 R3.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.2 - CIP-007-3 R5.2 - CIP-007-3 R5.3.1 - CIP-007-3 R5.3.2 - CIP-007-3 R5.3.3 - CIP-007-3 R6.5 - AC-3 - AC-3(3)(a) - AU-9 - SC-7(21) - DE.AE-1 - ID.AM-3 - PR.AC-4 - PR.AC-5 - PR.AC-6 - PR.DS-5 - PR.PT-1 - PR.PT-3 - PR.PT-4 - SRG-OS-000445-GPOS-00199 - SRG-OS-000134-GPOS-00068 - Setting the SELinux state to enforcing ensures SELinux is able to confine -potentially compromised processes to the security policy, which is designed to -prevent them from causing damage to the system or further elevating their -privileges. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -var_selinux_state='' - - -if [ -e "/etc/selinux/config" ] ; then - - LC_ALL=C sed -i "/^SELINUX=/Id" "/etc/selinux/config" -else - touch "/etc/selinux/config" -fi -# make sure file has newline at the end -sed -i -e '$a\' "/etc/selinux/config" - -cp "/etc/selinux/config" "/etc/selinux/config.bak" -# Insert at the end of the file -printf '%s\n' "SELINUX=$var_selinux_state" >> "/etc/selinux/config" -# Clean up after ourselves. -rm "/etc/selinux/config.bak" - -fixfiles onboot -fixfiles -f relabel - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: XCCDF Value var_selinux_state # promote to variable - set_fact: - var_selinux_state: !!str - tags: - - always - -- name: Ensure SELinux State is Enforcing - block: - - - name: Check for duplicate values - lineinfile: - path: /etc/selinux/config - create: false - regexp: ^SELINUX= - state: absent - check_mode: true - changed_when: false - register: dupes - - - name: Deduplicate values from /etc/selinux/config - lineinfile: - path: /etc/selinux/config - create: false - regexp: ^SELINUX= - state: absent - when: dupes.found is defined and dupes.found > 1 - - - name: Insert correct line to /etc/selinux/config - lineinfile: - path: /etc/selinux/config - create: true - regexp: ^SELINUX= - line: SELINUX={{ var_selinux_state }} - state: present - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.2 - - NIST-800-171-3.7.2 - - NIST-800-53-AC-3 - - NIST-800-53-AC-3(3)(a) - - NIST-800-53-AU-9 - - NIST-800-53-SC-7(21) - - high_severity - - low_complexity - - low_disruption - - no_reboot_needed - - restrict_strategy - - selinux_state - - - - - - - - - - - SELinux - Booleans - Enable or Disable runtime customization of SELinux system policies -without having to reload or recompile the SELinux policy. - - - abrt_anon_write SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - abrt_handle_event SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - abrt_upload_watch_anon_write SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - true - false - true - - - antivirus_can_scan_system SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - antivirus_use_jit SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - auditadm_exec_content SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - true - false - true - - - authlogin_nsswitch_use_ldap SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - authlogin_radius SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - authlogin_yubikey SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - awstats_purge_apache_log_files SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - boinc_execmem SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - true - false - true - - - cdrecord_read_content SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - cluster_can_network_connect SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - cluster_manage_all_files SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - cluster_use_execmem SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - cobbler_anon_write SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - cobbler_can_network_connect SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - cobbler_use_cifs SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - cobbler_use_nfs SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - collectd_tcp_network_connect SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - condor_tcp_network_connect SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - conman_can_network SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - container_connect_any SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - cron_can_relabel SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - cron_system_cronjob_use_shares SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - cron_userdomain_transition SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - true - false - true - - - cups_execmem SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - cvs_read_shadow SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - daemons_dump_core SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - daemons_enable_cluster_mode SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - daemons_use_tcp_wrapper SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - daemons_use_tty SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - dbadm_exec_content SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - true - false - true - - - dbadm_manage_user_files SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - dbadm_read_user_files SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - deny_execmem SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - deny_ptrace SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - dhcpc_exec_iptables SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - dhcpd_use_ldap SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - domain_fd_use SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - true - false - true - - - domain_kernel_load_modules SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - entropyd_use_audio SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - true - false - true - - - exim_can_connect_db SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - exim_manage_user_files SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - exim_read_user_files SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - fcron_crond SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - fenced_can_network_connect SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - fenced_can_ssh SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - fips_mode SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - true - false - true - - - ftpd_anon_write SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - ftpd_connect_all_unreserved SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - ftpd_connect_db SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - ftpd_full_access SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - ftpd_use_cifs SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - ftpd_use_fusefs SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - ftpd_use_nfs SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - ftpd_use_passive_mode SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - git_cgi_enable_homedirs SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - git_cgi_use_cifs SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - git_cgi_use_nfs SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - git_session_bind_all_unreserved_ports SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - git_session_users SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - git_system_enable_homedirs SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - git_system_use_cifs SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - git_system_use_nfs SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - gitosis_can_sendmail SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - glance_api_can_network SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - glance_use_execmem SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - glance_use_fusefs SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - global_ssp SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - gluster_anon_write SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - gluster_export_all_ro SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - gluster_export_all_rw SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - true - false - true - - - gpg_web_anon_write SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - gssd_read_tmp SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - true - false - true - - - guest_exec_content SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - true - false - true - - - haproxy_connect_any SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - httpd_anon_write SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - httpd_builtin_scripting SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - true - false - true - - - httpd_can_check_spam SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - httpd_can_connect_ftp SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - httpd_can_connect_ldap SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - httpd_can_connect_mythtv SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - httpd_can_connect_zabbix SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - httpd_can_network_connect SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - httpd_can_network_connect_cobbler SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - httpd_can_network_connect_db SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - httpd_can_network_memcache SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - httpd_can_network_relay SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - httpd_can_sendmail SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - httpd_dbus_avahi SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - httpd_dbus_sssd SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - httpd_dontaudit_search_dirs SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - httpd_enable_cgi SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - true - false - true - - - httpd_enable_ftp_server SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - httpd_enable_homedirs SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - httpd_execmem SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - httpd_graceful_shutdown SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - true - false - true - - - httpd_manage_ipa SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - httpd_mod_auth_ntlm_winbind SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - httpd_mod_auth_pam SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - httpd_read_user_content SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - httpd_run_ipa SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - httpd_run_preupgrade SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - httpd_run_stickshift SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - httpd_serve_cobbler_files SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - httpd_setrlimit SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - httpd_ssi_exec SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - httpd_sys_script_anon_write SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - httpd_tmp_exec SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - httpd_tty_comm SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - httpd_unified SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - httpd_use_cifs SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - httpd_use_fusefs SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - httpd_use_gpg SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - httpd_use_nfs SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - httpd_use_openstack SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - httpd_use_sasl SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - httpd_verify_dns SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - icecast_use_any_tcp_ports SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - irc_use_any_tcp_ports SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - irssi_use_full_network SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - kdumpgui_run_bootloader SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - kerberos_enabled SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - true - false - true - - - ksmtuned_use_cifs SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - ksmtuned_use_nfs SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - logadm_exec_content SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - true - false - true - - - logging_syslogd_can_sendmail SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - logging_syslogd_run_nagios_plugins SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - logging_syslogd_use_tty SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - true - false - true - - - login_console_enabled SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - true - false - true - - - logrotate_use_nfs SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - logwatch_can_network_connect_mail SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - lsmd_plugin_connect_any SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - mailman_use_fusefs SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - mcelog_client SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - mcelog_exec_scripts SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - true - false - true - - - mcelog_foreground SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - mcelog_server SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - minidlna_read_generic_user_content SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - mmap_low_allowed SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - mock_enable_homedirs SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - mount_anyfile SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - true - false - true - - - mozilla_plugin_bind_unreserved_ports SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - mozilla_plugin_can_network_connect SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - mozilla_plugin_use_bluejeans SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - mozilla_plugin_use_gps SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - mozilla_plugin_use_spice SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - mozilla_read_content SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - mpd_enable_homedirs SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - mpd_use_cifs SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - mpd_use_nfs SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - mplayer_execstack SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - mysql_connect_any SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - nagios_run_pnp4nagios SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - nagios_run_sudo SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - named_tcp_bind_http_port SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - named_write_master_zones SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - neutron_can_network SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - nfs_export_all_ro SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - true - false - true - - - nfs_export_all_rw SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - true - false - true - - - nfsd_anon_write SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - nis_enabled SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - nscd_use_shm SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - true - false - true - - - openshift_use_nfs SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - openvpn_can_network_connect SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - true - false - true - - - openvpn_enable_homedirs SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - true - false - true - - - openvpn_run_unconfined SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - pcp_bind_all_unreserved_ports SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - pcp_read_generic_logs SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - piranha_lvs_can_network_connect SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - polipo_connect_all_unreserved SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - polipo_session_bind_all_unreserved_ports SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - polipo_session_users SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - polipo_use_cifs SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - polipo_use_nfs SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - polyinstantiation_enabled SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - postfix_local_write_mail_spool SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - true - false - true - - - postgresql_can_rsync SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - postgresql_selinux_transmit_client_label SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - postgresql_selinux_unconfined_dbadm SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - true - false - true - - - postgresql_selinux_users_ddl SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - true - false - true - - - pppd_can_insmod SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - pppd_for_user SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - privoxy_connect_any SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - true - false - true - - - prosody_bind_http_port SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - puppetagent_manage_all_files SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - puppetmaster_use_db SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - racoon_read_shadow SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - rsync_anon_write SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - rsync_client SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - rsync_export_all_ro SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - rsync_full_access SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - samba_create_home_dirs SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - samba_domain_controller SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - samba_enable_home_dirs SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - samba_export_all_ro SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - samba_export_all_rw SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - samba_load_libgfapi SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - samba_portmapper SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - samba_run_unconfined SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - samba_share_fusefs SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - samba_share_nfs SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - sanlock_use_fusefs SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - sanlock_use_nfs SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - sanlock_use_samba SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - saslauthd_read_shadow SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - secadm_exec_content SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - true - false - true - - - secure_mode SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - secure_mode_insmod SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - secure_mode_policyload SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - selinuxuser_direct_dri_enabled SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - true - false - true - - - selinuxuser_execheap SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - selinuxuser_execmod SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - true - false - true - - - selinuxuser_execstack SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - selinuxuser_mysql_connect_enabled SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - selinuxuser_ping SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - true - false - true - - - selinuxuser_postgresql_connect_enabled SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - selinuxuser_rw_noexattrfile SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - true - false - true - - - selinuxuser_share_music SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - selinuxuser_tcp_server SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - selinuxuser_udp_server SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - selinuxuser_use_ssh_chroot SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - sge_domain_can_network_connect SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - sge_use_nfs SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - smartmon_3ware SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - smbd_anon_write SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - spamassassin_can_network SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - spamd_enable_home_dirs SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - true - false - true - - - squid_connect_any SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - true - false - true - - - squid_use_tproxy SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - ssh_chroot_rw_homedirs SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - ssh_keysign SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - ssh_sysadm_login SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - staff_exec_content SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - true - false - true - - - staff_use_svirt SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - swift_can_network SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - sysadm_exec_content SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - true - false - true - - - telepathy_connect_all_ports SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - telepathy_tcp_connect_generic_network_ports SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - true - false - true - - - tftp_anon_write SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - tftp_home_dir SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - tmpreaper_use_nfs SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - tmpreaper_use_samba SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - tor_bind_all_unreserved_ports SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - tor_can_network_relay SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - unconfined_chrome_sandbox_transition SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - true - false - true - - - unconfined_login SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - true - false - true - - - unconfined_mozilla_plugin_transition SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - true - false - true - - - unprivuser_use_svirt SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - use_ecryptfs_home_dirs SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - use_fusefs_home_dirs SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - use_lpd_server SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - use_nfs_home_dirs SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - use_samba_home_dirs SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - user_exec_content SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - true - false - true - - - varnishd_connect_any SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - virt_read_qemu_ga_data SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - virt_rw_qemu_ga_data SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - virt_sandbox_use_all_caps SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - true - false - true - - - virt_sandbox_use_audit SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - true - false - true - - - virt_sandbox_use_mknod SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - virt_sandbox_use_netlink SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - virt_sandbox_use_sys_admin SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - virt_transition_userdomain SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - virt_use_comm SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - virt_use_execmem SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - virt_use_fusefs SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - virt_use_nfs SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - virt_use_rawip SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - virt_use_samba SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - virt_use_sanlock SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - virt_use_usb SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - true - false - true - - - virt_use_xserver SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - webadm_manage_user_files SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - webadm_read_user_files SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - wine_mmap_zero_ignore SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - xdm_bind_vnc_tcp_port SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - xdm_exec_bootloader SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - xdm_sysadm_login SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - xdm_write_home SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - xen_use_nfs SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - xend_run_blktap SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - true - false - true - - - xend_run_qemu SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - true - false - true - - - xguest_connect_network SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - true - false - true - - - xguest_exec_content SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - true - false - true - - - xguest_mount_media SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - true - false - true - - - xguest_use_bluetooth SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - true - false - true - - - xserver_clients_write_xshm SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - xserver_execmem SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - xserver_object_manager SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - zabbix_can_network SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - zarafa_setrlimit SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - zebra_write_config SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - zoneminder_anon_write SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - zoneminder_run_sudo SELinux Boolean - default - Default SELinux boolean setting. -on - SELinux boolean is enabled. -off - SELinux boolean is disabled. - false - false - true - - - Configure the deny_execmem SELinux Boolean - By default, the SELinux boolean deny_execmem is disabled. -This setting should be configured to . - -To set the deny_execmem SELinux boolean, run the following command: -$ sudo setsebool -P deny_execmem - This rule doesn't come with a remediation, as enabling this SELinux boolean can cause -applications to malfunction, for example Graphical login managers and Firefox. - Proper function and stability should be assessed before applying enabling the SELinux -boolean in production systems. - BP28(R67) - Allowing user domain applications to map a memory region as both writable and -executable makes them more susceptible to data execution attacks. - - - - - - - - - - Configure the polyinstantiation_enabled SELinux Boolean - By default, the SELinux boolean polyinstantiation_enabled is disabled. -This setting should be configured to . - -To set the polyinstantiation_enabled SELinux boolean, run the following command: -$ sudo setsebool -P polyinstantiation_enabled - BP28(R39) - - # Remediation is applicable only in certain platforms -if ! ( [ "${container:-}" == "bwrap-osbuild" ] ) && [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -var_polyinstantiation_enabled='' - - -setsebool -P polyinstantiation_enabled $var_polyinstantiation_enabled - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: XCCDF Value var_polyinstantiation_enabled # promote to variable - set_fact: - var_polyinstantiation_enabled: !!str - tags: - - always - -- name: Ensure python3-libsemanage installed - package: - name: python3-libsemanage - state: present - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - not ( lookup("env", "container") == "bwrap-osbuild" ) - tags: - - enable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - sebool_polyinstantiation_enabled - -- name: Set SELinux boolean polyinstantiation_enabled accordingly - seboolean: - name: polyinstantiation_enabled - state: '{{ var_polyinstantiation_enabled }}' - persistent: true - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - not ( lookup("env", "container") == "bwrap-osbuild" ) - tags: - - enable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - sebool_polyinstantiation_enabled - - - - - - - - - - - Configure the secure_mode_insmod SELinux Boolean - By default, the SELinux boolean secure_mode_insmod is disabled. -This setting should be configured to . - -To set the secure_mode_insmod SELinux boolean, run the following command: -$ sudo setsebool -P secure_mode_insmod - BP28(R67) - - # Remediation is applicable only in certain platforms -if ! ( [ "${container:-}" == "bwrap-osbuild" ] ) && [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -var_secure_mode_insmod='' - -setsebool -P secure_mode_insmod $var_secure_mode_insmod - -# Preload vfat in initramfs, otherwise the system fails to reboot -echo "vfat" >> /etc/modules-load.d/vfat.conf -dracut -f --regenerate-all - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: XCCDF Value var_secure_mode_insmod # promote to variable - set_fact: - var_secure_mode_insmod: !!str - tags: - - always - -- name: Configure the secure_mode_insmod SELinux Boolean - Ensure libsemanage-python - installed - ansible.builtin.package: - name: libsemanage-python - state: present - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - not ( lookup("env", "container") == "bwrap-osbuild" ) - tags: - - enable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - sebool_secure_mode_insmod - -- name: Configure the secure_mode_insmod SELinux Boolean - Set SELinux boolean secure_mode_insmod - accordingly - ansible.posix.seboolean: - name: secure_mode_insmod - state: '{{ var_secure_mode_insmod }}' - persistent: true - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - not ( lookup("env", "container") == "bwrap-osbuild" ) - tags: - - enable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - sebool_secure_mode_insmod - -- name: Configure the secure_mode_insmod SELinux Boolean - Add vfat to static kernel - module list - ansible.builtin.lineinfile: - create: true - dest: /etc/modules-load.d/vfat.conf - regexp: ^\s*\bvfat\b - line: vfat - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - not ( lookup("env", "container") == "bwrap-osbuild" ) - tags: - - enable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - sebool_secure_mode_insmod - -- name: Configure the secure_mode_insmod SELinux Boolean - Regenerate initramfs - ansible.builtin.command: - cmd: dracut -f --regenerate-all - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - not ( lookup("env", "container") == "bwrap-osbuild" ) - tags: - - enable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - sebool_secure_mode_insmod - - - - - - - - - - - Disable the selinuxuser_execheap SELinux Boolean - By default, the SELinux boolean selinuxuser_execheap is disabled. -When enabled this boolean is enabled it allows selinuxusers to execute code from the heap. -If this setting is enabled, it should be disabled. - -To disable the selinuxuser_execheap SELinux boolean, run the following command: -$ sudo setsebool -P selinuxuser_execheap off - BP28(R67) - 164.308(a)(1)(ii)(D) - 164.308(a)(3) - 164.308(a)(4) - 164.310(b) - 164.310(c) - 164.312(a) - 164.312(e) - Disabling code execution from the heap blocks buffer overflow attacks. - # Remediation is applicable only in certain platforms -if ! ( [ "${container:-}" == "bwrap-osbuild" ] ) && [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -var_selinuxuser_execheap='' - - -setsebool -P selinuxuser_execheap $var_selinuxuser_execheap - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: XCCDF Value var_selinuxuser_execheap # promote to variable - set_fact: - var_selinuxuser_execheap: !!str - tags: - - always - -- name: Ensure python3-libsemanage installed - package: - name: python3-libsemanage - state: present - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - not ( lookup("env", "container") == "bwrap-osbuild" ) - tags: - - enable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - sebool_selinuxuser_execheap - -- name: Set SELinux boolean selinuxuser_execheap accordingly - seboolean: - name: selinuxuser_execheap - state: '{{ var_selinuxuser_execheap }}' - persistent: true - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - not ( lookup("env", "container") == "bwrap-osbuild" ) - tags: - - enable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - sebool_selinuxuser_execheap - - - - - - - - - - - Enable the selinuxuser_execmod SELinux Boolean - By default, the SELinux boolean selinuxuser_execmod is enabled. -If this setting is disabled, it should be enabled. - -To enable the selinuxuser_execmod SELinux boolean, run the following command: -$ sudo setsebool -P selinuxuser_execmod on - 164.308(a)(1)(ii)(D) - 164.308(a)(3) - 164.308(a)(4) - 164.310(b) - 164.310(c) - 164.312(a) - 164.312(e) - - # Remediation is applicable only in certain platforms -if ! ( [ "${container:-}" == "bwrap-osbuild" ] ) && [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -var_selinuxuser_execmod='' - - -setsebool -P selinuxuser_execmod $var_selinuxuser_execmod - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: XCCDF Value var_selinuxuser_execmod # promote to variable - set_fact: - var_selinuxuser_execmod: !!str - tags: - - always - -- name: Ensure python3-libsemanage installed - package: - name: python3-libsemanage - state: present - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - not ( lookup("env", "container") == "bwrap-osbuild" ) - tags: - - enable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - sebool_selinuxuser_execmod - -- name: Set SELinux boolean selinuxuser_execmod accordingly - seboolean: - name: selinuxuser_execmod - state: '{{ var_selinuxuser_execmod }}' - persistent: true - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - not ( lookup("env", "container") == "bwrap-osbuild" ) - tags: - - enable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - sebool_selinuxuser_execmod - - - - - - - - - - - Disable the selinuxuser_execstack SELinux Boolean - By default, the SELinux boolean selinuxuser_execstack is enabled. -This setting should be disabled as unconfined executables should not be able -to make their stack executable. - -To disable the selinuxuser_execstack SELinux boolean, run the following command: -$ sudo setsebool -P selinuxuser_execstack off - BP28(R67) - 164.308(a)(1)(ii)(D) - 164.308(a)(3) - 164.308(a)(4) - 164.310(b) - 164.310(c) - 164.312(a) - 164.312(e) - Disabling code execution from the stack blocks buffer overflow attacks. - # Remediation is applicable only in certain platforms -if ! ( [ "${container:-}" == "bwrap-osbuild" ] ) && [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -var_selinuxuser_execstack='' - - -setsebool -P selinuxuser_execstack $var_selinuxuser_execstack - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: XCCDF Value var_selinuxuser_execstack # promote to variable - set_fact: - var_selinuxuser_execstack: !!str - tags: - - always - -- name: Ensure python3-libsemanage installed - package: - name: python3-libsemanage - state: present - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - not ( lookup("env", "container") == "bwrap-osbuild" ) - tags: - - enable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - sebool_selinuxuser_execstack - -- name: Set SELinux boolean selinuxuser_execstack accordingly - seboolean: - name: selinuxuser_execstack - state: '{{ var_selinuxuser_execstack }}' - persistent: true - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - not ( lookup("env", "container") == "bwrap-osbuild" ) - tags: - - enable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - sebool_selinuxuser_execstack - - - - - - - - - - - Disable the ssh_sysadm_login SELinux Boolean - By default, the SELinux boolean ssh_sysadm_login is disabled. -If this setting is enabled, it should be disabled. - -To disable the ssh_sysadm_login SELinux boolean, run the following command: -$ sudo setsebool -P ssh_sysadm_login off - BP28(R67) - CCI-002165 - CCI-002235 - SRG-OS-000324-GPOS-00125 - Preventing non-privileged users from executing privileged functions mitigates -the risk that unauthorized individuals or processes may gain unnecessary access -to information or privileges. - -Privileged functions include, for example, establishing accounts, performing -system integrity checks, or administering cryptographic key management -activities. Non-privileged users are individuals who do not possess appropriate -authorizations. Circumventing intrusion detection and prevention mechanisms or -malicious code protection mechanisms are examples of privileged functions that -require protection from non-privileged users. - # Remediation is applicable only in certain platforms -if ! ( [ "${container:-}" == "bwrap-osbuild" ] ) && [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -var_ssh_sysadm_login='' - - -setsebool -P ssh_sysadm_login $var_ssh_sysadm_login - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: XCCDF Value var_ssh_sysadm_login # promote to variable - set_fact: - var_ssh_sysadm_login: !!str - tags: - - always - -- name: Ensure python3-libsemanage installed - package: - name: python3-libsemanage - state: present - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - not ( lookup("env", "container") == "bwrap-osbuild" ) - tags: - - enable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - sebool_ssh_sysadm_login - -- name: Set SELinux boolean ssh_sysadm_login accordingly - seboolean: - name: ssh_sysadm_login - state: '{{ var_ssh_sysadm_login }}' - persistent: true - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - not ( lookup("env", "container") == "bwrap-osbuild" ) - tags: - - enable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - sebool_ssh_sysadm_login - - - - - - - - - - - - - - Services - The best protection against vulnerable software is running less software. This section describes how to review -the software which Oracle Linux 9 installs on a system and disable software which is not needed. It -then enumerates the software packages installed on a default Oracle Linux 9 system and provides guidance about which -ones can be safely disabled. - -Oracle Linux 9 provides a convenient minimal install option that essentially installs the bare necessities for a functional -system. When building Oracle Linux 9 systems, it is highly recommended to select the minimal packages and then build up -the system from there. - - Apport Service - The Apport service provides debugging and crash reporting -features on Ubuntu distributions. - - - APT service configuration - The apt service manage the package management and update of the whole system. Its configuration need to be properly defined to ensure efficient security updates, packages and repository authentication and proper lifecycle management. - - - Avahi Server - The Avahi daemon implements the DNS Service Discovery -and Multicast DNS protocols, which provide service and host -discovery on a network. It allows a system to automatically -identify resources on the network, such as printers or web servers. -This capability is also known as mDNSresponder and is a major part -of Zeroconf networking. - - Configure Avahi if Necessary - If your system requires the Avahi daemon, its configuration can be restricted -to improve security. The Avahi daemon configuration file is -/etc/avahi/avahi-daemon.conf. The following security recommendations -should be applied to this file: -See the avahi-daemon.conf(5) man page, or documentation at - - http://www.avahi.org, for more detailed information -about the configuration options. - - Disable Avahi Publishing - To prevent Avahi from publishing its records, edit /etc/avahi/avahi-daemon.conf -and ensure the following line appears in the [publish] section: -disable-publishing=yes - 11 - 14 - 3 - 9 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS05.02 - DSS05.05 - DSS06.06 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 7.6 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.9.1.2 - CM-7(a) - CM-7(b) - CM-6(a) - PR.IP-1 - PR.PT-3 - This helps ensure that no record will be published by Avahi. - - - - Disable Avahi Server if Possible - Because the Avahi daemon service keeps an open network -port, it is subject to network attacks. -Disabling it can reduce the system's vulnerability to such attacks. - - Disable Avahi Server Software - -The avahi-daemon service can be disabled with the following command: -$ sudo systemctl mask --now avahi-daemon.service - 11 - 14 - 3 - 9 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS05.02 - DSS05.05 - DSS06.06 - CCI-000366 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 7.6 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.9.1.2 - CM-7(a) - CM-7(b) - CM-6(a) - PR.IP-1 - PR.PT-3 - 2.2.4 - Because the Avahi daemon service keeps an open network -port, it is subject to network attacks. Its functionality -is convenient but is only appropriate if the local network -can be trusted. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -SYSTEMCTL_EXEC='/usr/bin/systemctl' -"$SYSTEMCTL_EXEC" stop 'avahi-daemon.service' -"$SYSTEMCTL_EXEC" disable 'avahi-daemon.service' -"$SYSTEMCTL_EXEC" mask 'avahi-daemon.service' -# Disable socket activation if we have a unit file for it -if "$SYSTEMCTL_EXEC" -q list-unit-files avahi-daemon.socket; then - "$SYSTEMCTL_EXEC" stop 'avahi-daemon.socket' - "$SYSTEMCTL_EXEC" mask 'avahi-daemon.socket' -fi -# The service may not be running because it has been started and failed, -# so let's reset the state so OVAL checks pass. -# Service should be 'inactive', not 'failed' after reboot though. -"$SYSTEMCTL_EXEC" reset-failed 'avahi-daemon.service' || true - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Block Disable service avahi-daemon - block: - - - name: Disable service avahi-daemon - block: - - - name: Disable service avahi-daemon - systemd: - name: avahi-daemon.service - enabled: 'no' - state: stopped - masked: 'yes' - rescue: - - - name: Intentionally ignored previous 'Disable service avahi-daemon' failure, - service was already disabled - meta: noop - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - PCI-DSSv4-2.2.4 - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_avahi-daemon_disabled - -- name: Unit Socket Exists - avahi-daemon.socket - command: systemctl -q list-unit-files avahi-daemon.socket - register: socket_file_exists - changed_when: false - failed_when: socket_file_exists.rc not in [0, 1] - check_mode: false - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - PCI-DSSv4-2.2.4 - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_avahi-daemon_disabled - -- name: Disable socket avahi-daemon - systemd: - name: avahi-daemon.socket - enabled: 'no' - state: stopped - masked: 'yes' - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - socket_file_exists.stdout_lines is search("avahi-daemon.socket",multiline=True) - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - PCI-DSSv4-2.2.4 - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_avahi-daemon_disabled - - include disable_avahi-daemon - -class disable_avahi-daemon { - service {'avahi-daemon': - enable => false, - ensure => 'stopped', - } -} - - -[customizations.services] -disabled = ["avahi-daemon"] - - - - - - - - - - - - Base Services - This section addresses the base services that are installed on a -Oracle Linux 9 default installation which are not covered in other -sections. Some of these services listen on the network and -should be treated with particular discretion. Other services are local -system utilities that may or may not be extraneous. In general, system services -should be disabled if not required. - - Disable Automatic Bug Reporting Tool (abrtd) - The Automatic Bug Reporting Tool (abrtd) daemon collects -and reports crash data when an application crash is detected. Using a variety -of plugins, abrtd can email crash reports to system administrators, log crash -reports to files, or forward crash reports to a centralized issue tracking -system such as RHTSupport. - -The abrtd service can be disabled with the following command: -$ sudo systemctl mask --now abrtd.service - 11 - 12 - 14 - 15 - 3 - 8 - 9 - APO13.01 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS01.04 - DSS05.02 - DSS05.03 - DSS05.05 - DSS06.06 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 7.1 - SR 7.6 - A.11.2.6 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.6.2.1 - A.6.2.2 - A.9.1.2 - CM-7(a) - CM-6(a) - PR.AC-3 - PR.IP-1 - PR.PT-3 - PR.PT-4 - Mishandling crash data could expose sensitive information about -vulnerabilities in software executing on the system, as well as sensitive -information from within a process's address space or registers. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -SYSTEMCTL_EXEC='/usr/bin/systemctl' -"$SYSTEMCTL_EXEC" stop 'abrtd.service' -"$SYSTEMCTL_EXEC" disable 'abrtd.service' -"$SYSTEMCTL_EXEC" mask 'abrtd.service' -# Disable socket activation if we have a unit file for it -if "$SYSTEMCTL_EXEC" -q list-unit-files abrtd.socket; then - "$SYSTEMCTL_EXEC" stop 'abrtd.socket' - "$SYSTEMCTL_EXEC" mask 'abrtd.socket' -fi -# The service may not be running because it has been started and failed, -# so let's reset the state so OVAL checks pass. -# Service should be 'inactive', not 'failed' after reboot though. -"$SYSTEMCTL_EXEC" reset-failed 'abrtd.service' || true - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Block Disable service abrtd - block: - - - name: Disable service abrtd - block: - - - name: Disable service abrtd - systemd: - name: abrtd.service - enabled: 'no' - state: stopped - masked: 'yes' - rescue: - - - name: Intentionally ignored previous 'Disable service abrtd' failure, service - was already disabled - meta: noop - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_abrtd_disabled - -- name: Unit Socket Exists - abrtd.socket - command: systemctl -q list-unit-files abrtd.socket - register: socket_file_exists - changed_when: false - failed_when: socket_file_exists.rc not in [0, 1] - check_mode: false - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_abrtd_disabled - -- name: Disable socket abrtd - systemd: - name: abrtd.socket - enabled: 'no' - state: stopped - masked: 'yes' - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - socket_file_exists.stdout_lines is search("abrtd.socket",multiline=True) - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_abrtd_disabled - - include disable_abrtd - -class disable_abrtd { - service {'abrtd': - enable => false, - ensure => 'stopped', - } -} - - -[customizations.services] -disabled = ["abrtd"] - - - - - - - - - - Disable KDump Kernel Crash Analyzer (kdump) - The kdump service provides a kernel crash dump analyzer. It uses the kexec -system call to boot a secondary kernel ("capture" kernel) following a system -crash, which can load information from the crashed kernel for analysis. - -The kdump service can be disabled with the following command: -$ sudo systemctl mask --now kdump.service - 11 - 12 - 14 - 15 - 3 - 8 - 9 - APO13.01 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS01.04 - DSS05.02 - DSS05.03 - DSS05.05 - DSS06.06 - CCI-000366 - CCI-001665 - 164.308(a)(1)(ii)(D) - 164.308(a)(3) - 164.308(a)(4) - 164.310(b) - 164.310(c) - 164.312(a) - 164.312(e) - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 7.1 - SR 7.6 - A.11.2.6 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.6.2.1 - A.6.2.2 - A.9.1.2 - CM-7(a) - CM-7(b) - CM-6(a) - PR.AC-3 - PR.IP-1 - PR.PT-3 - PR.PT-4 - FMT_SMF_EXT.1.1 - SRG-OS-000269-GPOS-00103 - SRG-OS-000480-GPOS-00227 - Kernel core dumps may contain the full contents of system memory at the -time of the crash. Kernel core dumps consume a considerable amount of disk -space and may result in denial of service by exhausting the available space -on the target file system partition. Unless the system is used for kernel -development or testing, there is little need to run the kdump service. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -SYSTEMCTL_EXEC='/usr/bin/systemctl' -"$SYSTEMCTL_EXEC" stop 'kdump.service' -"$SYSTEMCTL_EXEC" disable 'kdump.service' -"$SYSTEMCTL_EXEC" mask 'kdump.service' -# Disable socket activation if we have a unit file for it -if "$SYSTEMCTL_EXEC" -q list-unit-files kdump.socket; then - "$SYSTEMCTL_EXEC" stop 'kdump.socket' - "$SYSTEMCTL_EXEC" mask 'kdump.socket' -fi -# The service may not be running because it has been started and failed, -# so let's reset the state so OVAL checks pass. -# Service should be 'inactive', not 'failed' after reboot though. -"$SYSTEMCTL_EXEC" reset-failed 'kdump.service' || true - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Block Disable service kdump - block: - - - name: Disable service kdump - block: - - - name: Disable service kdump - systemd: - name: kdump.service - enabled: 'no' - state: stopped - masked: 'yes' - rescue: - - - name: Intentionally ignored previous 'Disable service kdump' failure, service - was already disabled - meta: noop - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_kdump_disabled - -- name: Unit Socket Exists - kdump.socket - command: systemctl -q list-unit-files kdump.socket - register: socket_file_exists - changed_when: false - failed_when: socket_file_exists.rc not in [0, 1] - check_mode: false - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_kdump_disabled - -- name: Disable socket kdump - systemd: - name: kdump.socket - enabled: 'no' - state: stopped - masked: 'yes' - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - socket_file_exists.stdout_lines is search("kdump.socket",multiline=True) - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_kdump_disabled - - include disable_kdump - -class disable_kdump { - service {'kdump': - enable => false, - ensure => 'stopped', - } -} - - -kdump --disable - - -[customizations.services] -disabled = ["kdump"] - - - - - - - - - - Disable ntpdate Service (ntpdate) - The ntpdate service sets the local hardware clock by polling NTP servers -when the system boots. It synchronizes to the NTP servers listed in -/etc/ntp/step-tickers or /etc/ntp.conf -and then sets the local hardware clock to the newly synchronized -system time. - -The ntpdate service can be disabled with the following command: -$ sudo systemctl mask --now ntpdate.service - 11 - 12 - 14 - 15 - 3 - 8 - 9 - APO13.01 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS01.04 - DSS05.02 - DSS05.03 - DSS05.05 - DSS06.06 - CCI-000382 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 7.1 - SR 7.6 - A.11.2.6 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.6.2.1 - A.6.2.2 - A.9.1.2 - CM-7(a) - CM-7(b) - CM-6(a) - PR.AC-3 - PR.IP-1 - PR.PT-3 - PR.PT-4 - The ntpdate service may only be suitable for systems which -are rebooted frequently enough that clock drift does not cause problems between -reboots. In any event, the functionality of the ntpdate service is now -available in the ntpd program and should be considered deprecated. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -SYSTEMCTL_EXEC='/usr/bin/systemctl' -"$SYSTEMCTL_EXEC" stop 'ntpdate.service' -"$SYSTEMCTL_EXEC" disable 'ntpdate.service' -"$SYSTEMCTL_EXEC" mask 'ntpdate.service' -# Disable socket activation if we have a unit file for it -if "$SYSTEMCTL_EXEC" -q list-unit-files ntpdate.socket; then - "$SYSTEMCTL_EXEC" stop 'ntpdate.socket' - "$SYSTEMCTL_EXEC" mask 'ntpdate.socket' -fi -# The service may not be running because it has been started and failed, -# so let's reset the state so OVAL checks pass. -# Service should be 'inactive', not 'failed' after reboot though. -"$SYSTEMCTL_EXEC" reset-failed 'ntpdate.service' || true - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Block Disable service ntpdate - block: - - - name: Disable service ntpdate - block: - - - name: Disable service ntpdate - systemd: - name: ntpdate.service - enabled: 'no' - state: stopped - masked: 'yes' - rescue: - - - name: Intentionally ignored previous 'Disable service ntpdate' failure, service - was already disabled - meta: noop - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - low_complexity - - low_disruption - - low_severity - - no_reboot_needed - - service_ntpdate_disabled - -- name: Unit Socket Exists - ntpdate.socket - command: systemctl -q list-unit-files ntpdate.socket - register: socket_file_exists - changed_when: false - failed_when: socket_file_exists.rc not in [0, 1] - check_mode: false - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - low_complexity - - low_disruption - - low_severity - - no_reboot_needed - - service_ntpdate_disabled - -- name: Disable socket ntpdate - systemd: - name: ntpdate.socket - enabled: 'no' - state: stopped - masked: 'yes' - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - socket_file_exists.stdout_lines is search("ntpdate.socket",multiline=True) - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - low_complexity - - low_disruption - - low_severity - - no_reboot_needed - - service_ntpdate_disabled - - include disable_ntpdate - -class disable_ntpdate { - service {'ntpdate': - enable => false, - ensure => 'stopped', - } -} - - -[customizations.services] -disabled = ["ntpdate"] - - - - - - - - - - Disable Odd Job Daemon (oddjobd) - The oddjobd service exists to provide an interface and -access control mechanism through which -specified privileged tasks can run tasks for unprivileged client -applications. Communication with oddjobd through the system message bus. - -The oddjobd service can be disabled with the following command: -$ sudo systemctl mask --now oddjobd.service - 11 - 14 - 3 - 9 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS05.02 - DSS05.05 - DSS06.06 - CCI-000381 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 7.6 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.9.1.2 - CM-7(a) - CM-7(b) - CM-6(a) - PR.IP-1 - PR.PT-3 - The oddjobd service may provide necessary functionality in -some environments, and can be disabled if it is not needed. Execution of -tasks by privileged programs, on behalf of unprivileged ones, has traditionally -been a source of privilege escalation security issues. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -SYSTEMCTL_EXEC='/usr/bin/systemctl' -"$SYSTEMCTL_EXEC" stop 'oddjobd.service' -"$SYSTEMCTL_EXEC" disable 'oddjobd.service' -"$SYSTEMCTL_EXEC" mask 'oddjobd.service' -# Disable socket activation if we have a unit file for it -if "$SYSTEMCTL_EXEC" -q list-unit-files oddjobd.socket; then - "$SYSTEMCTL_EXEC" stop 'oddjobd.socket' - "$SYSTEMCTL_EXEC" mask 'oddjobd.socket' -fi -# The service may not be running because it has been started and failed, -# so let's reset the state so OVAL checks pass. -# Service should be 'inactive', not 'failed' after reboot though. -"$SYSTEMCTL_EXEC" reset-failed 'oddjobd.service' || true - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Block Disable service oddjobd - block: - - - name: Disable service oddjobd - block: - - - name: Disable service oddjobd - systemd: - name: oddjobd.service - enabled: 'no' - state: stopped - masked: 'yes' - rescue: - - - name: Intentionally ignored previous 'Disable service oddjobd' failure, service - was already disabled - meta: noop - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_oddjobd_disabled - -- name: Unit Socket Exists - oddjobd.socket - command: systemctl -q list-unit-files oddjobd.socket - register: socket_file_exists - changed_when: false - failed_when: socket_file_exists.rc not in [0, 1] - check_mode: false - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_oddjobd_disabled - -- name: Disable socket oddjobd - systemd: - name: oddjobd.socket - enabled: 'no' - state: stopped - masked: 'yes' - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - socket_file_exists.stdout_lines is search("oddjobd.socket",multiline=True) - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_oddjobd_disabled - - include disable_oddjobd - -class disable_oddjobd { - service {'oddjobd': - enable => false, - ensure => 'stopped', - } -} - - -[customizations.services] -disabled = ["oddjobd"] - - - - - - - - - - Disable Apache Qpid (qpidd) - The qpidd service provides high speed, secure, -guaranteed delivery services. It is an implementation of the Advanced Message -Queuing Protocol. By default the qpidd service will bind to port 5672 and -listen for connection attempts. - -The qpidd service can be disabled with the following command: -$ sudo systemctl mask --now qpidd.service - 11 - 12 - 14 - 15 - 3 - 8 - 9 - APO13.01 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS01.04 - DSS05.02 - DSS05.03 - DSS05.05 - DSS06.06 - CCI-000382 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 7.1 - SR 7.6 - A.11.2.6 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.6.2.1 - A.6.2.2 - A.9.1.2 - CM-7(a) - CM-7(b) - CM-6(a) - PR.AC-3 - PR.IP-1 - PR.PT-3 - PR.PT-4 - The qpidd service is automatically installed when the base package -selection is selected during installation. The qpidd service listens for -network connections, which increases the attack surface of the system. If -the system is not intended to receive AMQP traffic, then the qpidd -service is not needed and should be disabled or removed. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -SYSTEMCTL_EXEC='/usr/bin/systemctl' -"$SYSTEMCTL_EXEC" stop 'qpidd.service' -"$SYSTEMCTL_EXEC" disable 'qpidd.service' -"$SYSTEMCTL_EXEC" mask 'qpidd.service' -# Disable socket activation if we have a unit file for it -if "$SYSTEMCTL_EXEC" -q list-unit-files qpidd.socket; then - "$SYSTEMCTL_EXEC" stop 'qpidd.socket' - "$SYSTEMCTL_EXEC" mask 'qpidd.socket' -fi -# The service may not be running because it has been started and failed, -# so let's reset the state so OVAL checks pass. -# Service should be 'inactive', not 'failed' after reboot though. -"$SYSTEMCTL_EXEC" reset-failed 'qpidd.service' || true - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Block Disable service qpidd - block: - - - name: Disable service qpidd - block: - - - name: Disable service qpidd - systemd: - name: qpidd.service - enabled: 'no' - state: stopped - masked: 'yes' - rescue: - - - name: Intentionally ignored previous 'Disable service qpidd' failure, service - was already disabled - meta: noop - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - low_complexity - - low_disruption - - low_severity - - no_reboot_needed - - service_qpidd_disabled - -- name: Unit Socket Exists - qpidd.socket - command: systemctl -q list-unit-files qpidd.socket - register: socket_file_exists - changed_when: false - failed_when: socket_file_exists.rc not in [0, 1] - check_mode: false - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - low_complexity - - low_disruption - - low_severity - - no_reboot_needed - - service_qpidd_disabled - -- name: Disable socket qpidd - systemd: - name: qpidd.socket - enabled: 'no' - state: stopped - masked: 'yes' - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - socket_file_exists.stdout_lines is search("qpidd.socket",multiline=True) - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - low_complexity - - low_disruption - - low_severity - - no_reboot_needed - - service_qpidd_disabled - - include disable_qpidd - -class disable_qpidd { - service {'qpidd': - enable => false, - ensure => 'stopped', - } -} - - -[customizations.services] -disabled = ["qpidd"] - - - - - - - - - - Disable Network Router Discovery Daemon (rdisc) - The rdisc service implements the client side of the ICMP -Internet Router Discovery Protocol (IRDP), which allows discovery of routers on -the local subnet. If a router is discovered then the local routing table is -updated with a corresponding default route. By default this daemon is disabled. - -The rdisc service can be disabled with the following command: -$ sudo systemctl mask --now rdisc.service - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 4 - 6 - 8 - 9 - APO01.06 - APO13.01 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS01.04 - DSS01.05 - DSS03.01 - DSS05.02 - DSS05.03 - DSS05.04 - DSS05.05 - DSS05.07 - DSS06.02 - DSS06.06 - CCI-000382 - 4.2.3.4 - 4.3.3.4 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - 4.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 7.1 - SR 7.6 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.11.2.6 - A.12.1.1 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.13.1.1 - A.13.1.2 - A.13.1.3 - A.13.2.1 - A.13.2.2 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.6.1.2 - A.6.2.1 - A.6.2.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - AC-4 - CM-7(a) - CM-7(b) - CM-6(a) - DE.AE-1 - ID.AM-3 - PR.AC-3 - PR.AC-5 - PR.DS-5 - PR.IP-1 - PR.PT-3 - PR.PT-4 - General-purpose systems typically have their network and routing -information configured statically by a system administrator. Workstations or -some special-purpose systems often use DHCP (instead of IRDP) to retrieve -dynamic network configuration information. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -SYSTEMCTL_EXEC='/usr/bin/systemctl' -"$SYSTEMCTL_EXEC" stop 'rdisc.service' -"$SYSTEMCTL_EXEC" disable 'rdisc.service' -"$SYSTEMCTL_EXEC" mask 'rdisc.service' -# Disable socket activation if we have a unit file for it -if "$SYSTEMCTL_EXEC" -q list-unit-files rdisc.socket; then - "$SYSTEMCTL_EXEC" stop 'rdisc.socket' - "$SYSTEMCTL_EXEC" mask 'rdisc.socket' -fi -# The service may not be running because it has been started and failed, -# so let's reset the state so OVAL checks pass. -# Service should be 'inactive', not 'failed' after reboot though. -"$SYSTEMCTL_EXEC" reset-failed 'rdisc.service' || true - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Block Disable service rdisc - block: - - - name: Disable service rdisc - block: - - - name: Disable service rdisc - systemd: - name: rdisc.service - enabled: 'no' - state: stopped - masked: 'yes' - rescue: - - - name: Intentionally ignored previous 'Disable service rdisc' failure, service - was already disabled - meta: noop - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-4 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_rdisc_disabled - -- name: Unit Socket Exists - rdisc.socket - command: systemctl -q list-unit-files rdisc.socket - register: socket_file_exists - changed_when: false - failed_when: socket_file_exists.rc not in [0, 1] - check_mode: false - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-4 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_rdisc_disabled - -- name: Disable socket rdisc - systemd: - name: rdisc.socket - enabled: 'no' - state: stopped - masked: 'yes' - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - socket_file_exists.stdout_lines is search("rdisc.socket",multiline=True) - tags: - - NIST-800-53-AC-4 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_rdisc_disabled - - include disable_rdisc - -class disable_rdisc { - service {'rdisc': - enable => false, - ensure => 'stopped', - } -} - - -[customizations.services] -disabled = ["rdisc"] - - - - - - - - - - - Cron and At Daemons - The cron and at services are used to allow commands to -be executed at a later time. The cron service is required by almost -all systems to perform necessary maintenance tasks, while at may or -may not be required on a given system. Both daemons should be -configured defensively. - - - Install the cron service - The Cron service should be installed. - BP28(R50) - 11 - 14 - 3 - 9 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS05.02 - DSS05.05 - DSS06.06 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 7.6 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.9.1.2 - CM-6(a) - PR.IP-1 - PR.PT-3 - The cron service allow periodic job execution, needed for almost all administrative tasks and services (software update, log rotating, etc.). Access to cron service should be restricted to administrative accounts only. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -if ! rpm -q --quiet "cron" ; then - yum install -y "cron" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Ensure cron is installed - package: - name: cron - state: present - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-CM-6(a) - - enable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - package_cron_installed - - include install_cron - -class install_cron { - package { 'cron': - ensure => 'installed', - } -} - - -package --add=cron - - -[[packages]] -name = "cron" -version = "*" - - - - - - - - - - Enable cron Service - The crond service is used to execute commands at -preconfigured times. It is required by almost all systems to perform necessary -maintenance tasks, such as notifying root of system activity. - -The cron service can be enabled with the following command: -$ sudo systemctl enable cron.service - 11 - 14 - 3 - 9 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS05.02 - DSS05.05 - DSS06.06 - 164.308(a)(4)(i) - 164.308(b)(1) - 164.308(b)(3) - 164.310(b) - 164.312(e)(1) - 164.312(e)(2)(ii) - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 7.6 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.9.1.2 - CM-6(a) - PR.IP-1 - PR.PT-3 - 2.2.6 - Due to its usage for maintenance and security-supporting tasks, -enabling the cron daemon is essential. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -SYSTEMCTL_EXEC='/usr/bin/systemctl' -"$SYSTEMCTL_EXEC" unmask 'cron.service' -"$SYSTEMCTL_EXEC" start 'cron.service' -"$SYSTEMCTL_EXEC" enable 'cron.service' - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Enable service cron - block: - - - name: Gather the package facts - package_facts: - manager: auto - - - name: Enable service cron - systemd: - name: cron - enabled: 'yes' - state: started - masked: 'no' - when: - - '"cron" in ansible_facts.packages' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-CM-6(a) - - PCI-DSSv4-2.2.6 - - enable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_cron_enabled - - include enable_cron - -class enable_cron { - service {'cron': - enable => true, - ensure => 'running', - } -} - - -[customizations.services] -enabled = ["cron"] - - - - - - - - - - Enable cron Service - The crond service is used to execute commands at -preconfigured times. It is required by almost all systems to perform necessary -maintenance tasks, such as notifying root of system activity. - -The crond service can be enabled with the following command: -$ sudo systemctl enable crond.service - 11 - 14 - 3 - 9 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS05.02 - DSS05.05 - DSS06.06 - 164.308(a)(4)(i) - 164.308(b)(1) - 164.308(b)(3) - 164.310(b) - 164.312(e)(1) - 164.312(e)(2)(ii) - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 7.6 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.9.1.2 - CM-6(a) - PR.IP-1 - PR.PT-3 - Due to its usage for maintenance and security-supporting tasks, -enabling the cron daemon is essential. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -SYSTEMCTL_EXEC='/usr/bin/systemctl' -"$SYSTEMCTL_EXEC" unmask 'crond.service' -"$SYSTEMCTL_EXEC" start 'crond.service' -"$SYSTEMCTL_EXEC" enable 'crond.service' - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Enable service crond - block: - - - name: Gather the package facts - package_facts: - manager: auto - - - name: Enable service crond - systemd: - name: crond - enabled: 'yes' - state: started - masked: 'no' - when: - - '"cronie" in ansible_facts.packages' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-CM-6(a) - - enable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_crond_enabled - - include enable_crond - -class enable_crond { - service {'crond': - enable => true, - ensure => 'running', - } -} - - -[customizations.services] -enabled = ["crond"] - - - - - - - - - - Disable At Service (atd) - The at and batch commands can be used to -schedule tasks that are meant to be executed only once. This allows delayed -execution in a manner similar to cron, except that it is not -recurring. The daemon atd keeps track of tasks scheduled via -at and batch, and executes them at the specified time. - -The atd service can be disabled with the following command: -$ sudo systemctl mask --now atd.service - 11 - 14 - 3 - 9 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS05.02 - DSS05.05 - DSS06.06 - CCI-000381 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 7.6 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.9.1.2 - CM-7(a) - CM-7(b) - CM-6(a) - PR.IP-1 - PR.PT-3 - The atd service could be used by an unsophisticated insider to carry -out activities outside of a normal login session, which could complicate -accountability. Furthermore, the need to schedule tasks with at or -batch is not common. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -SYSTEMCTL_EXEC='/usr/bin/systemctl' -"$SYSTEMCTL_EXEC" stop 'atd.service' -"$SYSTEMCTL_EXEC" disable 'atd.service' -"$SYSTEMCTL_EXEC" mask 'atd.service' -# Disable socket activation if we have a unit file for it -if "$SYSTEMCTL_EXEC" -q list-unit-files atd.socket; then - "$SYSTEMCTL_EXEC" stop 'atd.socket' - "$SYSTEMCTL_EXEC" mask 'atd.socket' -fi -# The service may not be running because it has been started and failed, -# so let's reset the state so OVAL checks pass. -# Service should be 'inactive', not 'failed' after reboot though. -"$SYSTEMCTL_EXEC" reset-failed 'atd.service' || true - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Block Disable service atd - block: - - - name: Disable service atd - block: - - - name: Disable service atd - systemd: - name: atd.service - enabled: 'no' - state: stopped - masked: 'yes' - rescue: - - - name: Intentionally ignored previous 'Disable service atd' failure, service - was already disabled - meta: noop - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_atd_disabled - -- name: Unit Socket Exists - atd.socket - command: systemctl -q list-unit-files atd.socket - register: socket_file_exists - changed_when: false - failed_when: socket_file_exists.rc not in [0, 1] - check_mode: false - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_atd_disabled - -- name: Disable socket atd - systemd: - name: atd.socket - enabled: 'no' - state: stopped - masked: 'yes' - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - socket_file_exists.stdout_lines is search("atd.socket",multiline=True) - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_atd_disabled - - include disable_atd - -class disable_atd { - service {'atd': - enable => false, - ensure => 'stopped', - } -} - - -[customizations.services] -disabled = ["atd"] - - - - - - - - - - Verify Group Who Owns cron.d - -To properly set the group owner of /etc/cron.d, run the command: -$ sudo chgrp root /etc/cron.d - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - APO01.06 - DSS05.04 - DSS05.07 - DSS06.02 - 4.3.3.7.3 - SR 2.1 - SR 5.2 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CM-6(a) - AC-6(1) - PR.AC-4 - PR.DS-5 - SRG-OS-000480-GPOS-00227 - Service configuration files enable or disable features of their respective services that if configured incorrectly -can lead to insecure and vulnerable configurations. Therefore, service configuration files should be owned by the -correct group to prevent unauthorized changes. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -find -H /etc/cron.d/ -maxdepth 1 -type d -exec chgrp 0 {} \; - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Ensure group owner on /etc/cron.d/ - file: - path: /etc/cron.d/ - state: directory - group: '0' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - configure_strategy - - file_groupowner_cron_d - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Verify Group Who Owns cron.daily - -To properly set the group owner of /etc/cron.daily, run the command: -$ sudo chgrp root /etc/cron.daily - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - APO01.06 - DSS05.04 - DSS05.07 - DSS06.02 - 4.3.3.7.3 - SR 2.1 - SR 5.2 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CM-6(a) - AC-6(1) - PR.AC-4 - PR.DS-5 - SRG-OS-000480-GPOS-00227 - Service configuration files enable or disable features of their respective services that if configured incorrectly -can lead to insecure and vulnerable configurations. Therefore, service configuration files should be owned by the -correct group to prevent unauthorized changes. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -find -H /etc/cron.daily/ -maxdepth 1 -type d -exec chgrp 0 {} \; - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Ensure group owner on /etc/cron.daily/ - file: - path: /etc/cron.daily/ - state: directory - group: '0' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - configure_strategy - - file_groupowner_cron_daily - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Verify Group Who Owns cron.hourly - -To properly set the group owner of /etc/cron.hourly, run the command: -$ sudo chgrp root /etc/cron.hourly - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - APO01.06 - DSS05.04 - DSS05.07 - DSS06.02 - 4.3.3.7.3 - SR 2.1 - SR 5.2 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CM-6(a) - AC-6(1) - PR.AC-4 - PR.DS-5 - SRG-OS-000480-GPOS-00227 - Service configuration files enable or disable features of their respective services that if configured incorrectly -can lead to insecure and vulnerable configurations. Therefore, service configuration files should be owned by the -correct group to prevent unauthorized changes. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -find -H /etc/cron.hourly/ -maxdepth 1 -type d -exec chgrp 0 {} \; - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Ensure group owner on /etc/cron.hourly/ - file: - path: /etc/cron.hourly/ - state: directory - group: '0' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - configure_strategy - - file_groupowner_cron_hourly - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Verify Group Who Owns cron.monthly - -To properly set the group owner of /etc/cron.monthly, run the command: -$ sudo chgrp root /etc/cron.monthly - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - APO01.06 - DSS05.04 - DSS05.07 - DSS06.02 - 4.3.3.7.3 - SR 2.1 - SR 5.2 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CM-6(a) - AC-6(1) - PR.AC-4 - PR.DS-5 - SRG-OS-000480-GPOS-00227 - Service configuration files enable or disable features of their respective services that if configured incorrectly -can lead to insecure and vulnerable configurations. Therefore, service configuration files should be owned by the -correct group to prevent unauthorized changes. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -find -H /etc/cron.monthly/ -maxdepth 1 -type d -exec chgrp 0 {} \; - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Ensure group owner on /etc/cron.monthly/ - file: - path: /etc/cron.monthly/ - state: directory - group: '0' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - configure_strategy - - file_groupowner_cron_monthly - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Verify Group Who Owns cron.weekly - -To properly set the group owner of /etc/cron.weekly, run the command: -$ sudo chgrp root /etc/cron.weekly - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - APO01.06 - DSS05.04 - DSS05.07 - DSS06.02 - 4.3.3.7.3 - SR 2.1 - SR 5.2 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CM-6(a) - AC-6(1) - PR.AC-4 - PR.DS-5 - SRG-OS-000480-GPOS-00227 - Service configuration files enable or disable features of their respective services that if configured incorrectly -can lead to insecure and vulnerable configurations. Therefore, service configuration files should be owned by the -correct group to prevent unauthorized changes. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -find -H /etc/cron.weekly/ -maxdepth 1 -type d -exec chgrp 0 {} \; - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Ensure group owner on /etc/cron.weekly/ - file: - path: /etc/cron.weekly/ - state: directory - group: '0' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - configure_strategy - - file_groupowner_cron_weekly - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Verify Group Who Owns Crontab - -To properly set the group owner of /etc/crontab, run the command: -$ sudo chgrp root /etc/crontab - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - APO01.06 - DSS05.04 - DSS05.07 - DSS06.02 - 4.3.3.7.3 - SR 2.1 - SR 5.2 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CM-6(a) - AC-6(1) - PR.AC-4 - PR.DS-5 - SRG-OS-000480-GPOS-00227 - Service configuration files enable or disable features of their respective services that if configured incorrectly -can lead to insecure and vulnerable configurations. Therefore, service configuration files should be owned by the -correct group to prevent unauthorized changes. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -chgrp 0 /etc/crontab - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Test for existence /etc/crontab - stat: - path: /etc/crontab - register: file_exists - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - configure_strategy - - file_groupowner_crontab - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Ensure group owner 0 on /etc/crontab - file: - path: /etc/crontab - group: '0' - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - file_exists.stat is defined and file_exists.stat.exists - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - configure_strategy - - file_groupowner_crontab - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Verify Owner on cron.d - -To properly set the owner of /etc/cron.d, run the command: -$ sudo chown root /etc/cron.d - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - APO01.06 - DSS05.04 - DSS05.07 - DSS06.02 - 4.3.3.7.3 - SR 2.1 - SR 5.2 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CM-6(a) - AC-6(1) - PR.AC-4 - PR.DS-5 - SRG-OS-000480-GPOS-00227 - Service configuration files enable or disable features of their respective services that if configured incorrectly -can lead to insecure and vulnerable configurations. Therefore, service configuration files should be owned by the -correct user to prevent unauthorized changes. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -find -H /etc/cron.d/ -maxdepth 1 -type d -exec chown 0 {} \; - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Ensure owner on directory /etc/cron.d/ - file: - path: /etc/cron.d/ - state: directory - owner: '0' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - configure_strategy - - file_owner_cron_d - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Verify Owner on cron.daily - -To properly set the owner of /etc/cron.daily, run the command: -$ sudo chown root /etc/cron.daily - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - APO01.06 - DSS05.04 - DSS05.07 - DSS06.02 - 4.3.3.7.3 - SR 2.1 - SR 5.2 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CM-6(a) - AC-6(1) - PR.AC-4 - PR.DS-5 - SRG-OS-000480-GPOS-00227 - Service configuration files enable or disable features of their respective services that if configured incorrectly -can lead to insecure and vulnerable configurations. Therefore, service configuration files should be owned by the -correct user to prevent unauthorized changes. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -find -H /etc/cron.daily/ -maxdepth 1 -type d -exec chown 0 {} \; - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Ensure owner on directory /etc/cron.daily/ - file: - path: /etc/cron.daily/ - state: directory - owner: '0' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - configure_strategy - - file_owner_cron_daily - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Verify Owner on cron.hourly - -To properly set the owner of /etc/cron.hourly, run the command: -$ sudo chown root /etc/cron.hourly - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - APO01.06 - DSS05.04 - DSS05.07 - DSS06.02 - 4.3.3.7.3 - SR 2.1 - SR 5.2 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CM-6(a) - AC-6(1) - PR.AC-4 - PR.DS-5 - SRG-OS-000480-GPOS-00227 - Service configuration files enable or disable features of their respective services that if configured incorrectly -can lead to insecure and vulnerable configurations. Therefore, service configuration files should be owned by the -correct user to prevent unauthorized changes. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -find -H /etc/cron.hourly/ -maxdepth 1 -type d -exec chown 0 {} \; - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Ensure owner on directory /etc/cron.hourly/ - file: - path: /etc/cron.hourly/ - state: directory - owner: '0' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - configure_strategy - - file_owner_cron_hourly - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Verify Owner on cron.monthly - -To properly set the owner of /etc/cron.monthly, run the command: -$ sudo chown root /etc/cron.monthly - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - APO01.06 - DSS05.04 - DSS05.07 - DSS06.02 - 4.3.3.7.3 - SR 2.1 - SR 5.2 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CM-6(a) - AC-6(1) - PR.AC-4 - PR.DS-5 - SRG-OS-000480-GPOS-00227 - Service configuration files enable or disable features of their respective services that if configured incorrectly -can lead to insecure and vulnerable configurations. Therefore, service configuration files should be owned by the -correct user to prevent unauthorized changes. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -find -H /etc/cron.monthly/ -maxdepth 1 -type d -exec chown 0 {} \; - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Ensure owner on directory /etc/cron.monthly/ - file: - path: /etc/cron.monthly/ - state: directory - owner: '0' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - configure_strategy - - file_owner_cron_monthly - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Verify Owner on cron.weekly - -To properly set the owner of /etc/cron.weekly, run the command: -$ sudo chown root /etc/cron.weekly - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - APO01.06 - DSS05.04 - DSS05.07 - DSS06.02 - 4.3.3.7.3 - SR 2.1 - SR 5.2 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CM-6(a) - AC-6(1) - PR.AC-4 - PR.DS-5 - SRG-OS-000480-GPOS-00227 - Service configuration files enable or disable features of their respective services that if configured incorrectly -can lead to insecure and vulnerable configurations. Therefore, service configuration files should be owned by the -correct user to prevent unauthorized changes. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -find -H /etc/cron.weekly/ -maxdepth 1 -type d -exec chown 0 {} \; - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Ensure owner on directory /etc/cron.weekly/ - file: - path: /etc/cron.weekly/ - state: directory - owner: '0' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - configure_strategy - - file_owner_cron_weekly - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Verify Owner on crontab - -To properly set the owner of /etc/crontab, run the command: -$ sudo chown root /etc/crontab - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - APO01.06 - DSS05.04 - DSS05.07 - DSS06.02 - 4.3.3.7.3 - SR 2.1 - SR 5.2 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CM-6(a) - AC-6(1) - PR.AC-4 - PR.DS-5 - SRG-OS-000480-GPOS-00227 - Service configuration files enable or disable features of their respective services that if configured incorrectly -can lead to insecure and vulnerable configurations. Therefore, service configuration files should be owned by the -correct user to prevent unauthorized changes. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -chown 0 /etc/crontab - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Test for existence /etc/crontab - stat: - path: /etc/crontab - register: file_exists - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - configure_strategy - - file_owner_crontab - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Ensure owner 0 on /etc/crontab - file: - path: /etc/crontab - owner: '0' - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - file_exists.stat is defined and file_exists.stat.exists - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - configure_strategy - - file_owner_crontab - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Verify Permissions on cron.d - -To properly set the permissions of /etc/cron.d, run the command: -$ sudo chmod 0700 /etc/cron.d - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - APO01.06 - DSS05.04 - DSS05.07 - DSS06.02 - 4.3.3.7.3 - SR 2.1 - SR 5.2 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CM-6(a) - AC-6(1) - PR.AC-4 - PR.DS-5 - 2.2.6 - SRG-OS-000480-GPOS-00227 - Service configuration files enable or disable features of their respective services that if configured incorrectly -can lead to insecure and vulnerable configurations. Therefore, service configuration files should have the -correct access rights to prevent unauthorized changes. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -find -H /etc/cron.d/ -maxdepth 1 -perm /u+s,g+xwrs,o+xwrt -type d -exec chmod u-s,g-xwrs,o-xwrt {} \; - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Set permissions for /etc/cron.d/ - file: - path: /etc/cron.d/ - state: directory - mode: u-s,g-xwrs,o-xwrt - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSSv4-2.2.6 - - configure_strategy - - file_permissions_cron_d - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Verify Permissions on cron.daily - -To properly set the permissions of /etc/cron.daily, run the command: -$ sudo chmod 0700 /etc/cron.daily - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - APO01.06 - DSS05.04 - DSS05.07 - DSS06.02 - 4.3.3.7.3 - SR 2.1 - SR 5.2 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CM-6(a) - AC-6(1) - PR.AC-4 - PR.DS-5 - 2.2.6 - SRG-OS-000480-GPOS-00227 - Service configuration files enable or disable features of their respective services that if configured incorrectly -can lead to insecure and vulnerable configurations. Therefore, service configuration files should have the -correct access rights to prevent unauthorized changes. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -find -H /etc/cron.daily/ -maxdepth 1 -perm /u+s,g+xwrs,o+xwrt -type d -exec chmod u-s,g-xwrs,o-xwrt {} \; - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Set permissions for /etc/cron.daily/ - file: - path: /etc/cron.daily/ - state: directory - mode: u-s,g-xwrs,o-xwrt - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSSv4-2.2.6 - - configure_strategy - - file_permissions_cron_daily - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Verify Permissions on cron.hourly - -To properly set the permissions of /etc/cron.hourly, run the command: -$ sudo chmod 0700 /etc/cron.hourly - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - APO01.06 - DSS05.04 - DSS05.07 - DSS06.02 - 4.3.3.7.3 - SR 2.1 - SR 5.2 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CM-6(a) - AC-6(1) - PR.AC-4 - PR.DS-5 - 2.2.6 - SRG-OS-000480-GPOS-00227 - Service configuration files enable or disable features of their respective services that if configured incorrectly -can lead to insecure and vulnerable configurations. Therefore, service configuration files should have the -correct access rights to prevent unauthorized changes. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -find -H /etc/cron.hourly/ -maxdepth 1 -perm /u+s,g+xwrs,o+xwrt -type d -exec chmod u-s,g-xwrs,o-xwrt {} \; - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Set permissions for /etc/cron.hourly/ - file: - path: /etc/cron.hourly/ - state: directory - mode: u-s,g-xwrs,o-xwrt - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSSv4-2.2.6 - - configure_strategy - - file_permissions_cron_hourly - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Verify Permissions on cron.monthly - -To properly set the permissions of /etc/cron.monthly, run the command: -$ sudo chmod 0700 /etc/cron.monthly - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - APO01.06 - DSS05.04 - DSS05.07 - DSS06.02 - 4.3.3.7.3 - SR 2.1 - SR 5.2 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CM-6(a) - AC-6(1) - PR.AC-4 - PR.DS-5 - 2.2.6 - SRG-OS-000480-GPOS-00227 - Service configuration files enable or disable features of their respective services that if configured incorrectly -can lead to insecure and vulnerable configurations. Therefore, service configuration files should have the -correct access rights to prevent unauthorized changes. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -find -H /etc/cron.monthly/ -maxdepth 1 -perm /u+s,g+xwrs,o+xwrt -type d -exec chmod u-s,g-xwrs,o-xwrt {} \; - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Set permissions for /etc/cron.monthly/ - file: - path: /etc/cron.monthly/ - state: directory - mode: u-s,g-xwrs,o-xwrt - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSSv4-2.2.6 - - configure_strategy - - file_permissions_cron_monthly - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Verify Permissions on cron.weekly - -To properly set the permissions of /etc/cron.weekly, run the command: -$ sudo chmod 0700 /etc/cron.weekly - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - APO01.06 - DSS05.04 - DSS05.07 - DSS06.02 - 4.3.3.7.3 - SR 2.1 - SR 5.2 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CM-6(a) - AC-6(1) - PR.AC-4 - PR.DS-5 - 2.2.6 - SRG-OS-000480-GPOS-00227 - Service configuration files enable or disable features of their respective services that if configured incorrectly -can lead to insecure and vulnerable configurations. Therefore, service configuration files should have the -correct access rights to prevent unauthorized changes. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -find -H /etc/cron.weekly/ -maxdepth 1 -perm /u+s,g+xwrs,o+xwrt -type d -exec chmod u-s,g-xwrs,o-xwrt {} \; - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Set permissions for /etc/cron.weekly/ - file: - path: /etc/cron.weekly/ - state: directory - mode: u-s,g-xwrs,o-xwrt - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSSv4-2.2.6 - - configure_strategy - - file_permissions_cron_weekly - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Verify Permissions on crontab - -To properly set the permissions of /etc/crontab, run the command: -$ sudo chmod 0600 /etc/crontab - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - APO01.06 - DSS05.04 - DSS05.07 - DSS06.02 - 4.3.3.7.3 - SR 2.1 - SR 5.2 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CM-6(a) - AC-6(1) - PR.AC-4 - PR.DS-5 - 2.2.6 - SRG-OS-000480-GPOS-00227 - Service configuration files enable or disable features of their respective services that if configured incorrectly -can lead to insecure and vulnerable configurations. Therefore, service configuration files should have the -correct access rights to prevent unauthorized changes. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -chmod u-xs,g-xwrs,o-xwrt /etc/crontab - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Test for existence /etc/crontab - stat: - path: /etc/crontab - register: file_exists - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSSv4-2.2.6 - - configure_strategy - - file_permissions_crontab - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Ensure permission u-xs,g-xwrs,o-xwrt on /etc/crontab - file: - path: /etc/crontab - mode: u-xs,g-xwrs,o-xwrt - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - file_exists.stat is defined and file_exists.stat.exists - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSSv4-2.2.6 - - configure_strategy - - file_permissions_crontab - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Restrict at and cron to Authorized Users if Necessary - The /etc/cron.allow and /etc/at.allow files contain lists of -users who are allowed to use cron and at to delay execution of -processes. If these files exist and if the corresponding files -/etc/cron.deny and /etc/at.deny do not exist, then only users -listed in the relevant allow files can run the crontab and at commands -to submit jobs to be run at scheduled intervals. On many systems, only the -system administrator needs the ability to schedule jobs. Note that even if a -given user is not listed in cron.allow, cron jobs can still be run as -that user. The cron.allow file controls only administrative access -to the crontab command for scheduling and modifying cron jobs. - - -To restrict at and cron to only authorized users: -Remove the cron.deny file:$ sudo rm /etc/cron.denyEdit /etc/cron.allow, adding one line for each user allowed to use -the crontab command to create cron jobs.Remove the at.deny file:$ sudo rm /etc/at.denyEdit /etc/at.allow, adding one line for each user allowed to use -the at command to create at jobs. - - Verify Group Who Owns /etc/cron.allow file - If /etc/cron.allow exists, it must be group-owned by root. - -To properly set the group owner of /etc/cron.allow, run the command: -$ sudo chgrp root /etc/cron.allow - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - APO01.06 - DSS05.04 - DSS05.07 - DSS06.02 - CCI-000366 - 4.3.3.7.3 - SR 2.1 - SR 5.2 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CM-6(a) - AC-6(1) - PR.AC-4 - PR.DS-5 - 2.2.6 - SRG-OS-000480-GPOS-00227 - If the owner of the cron.allow file is not set to root, the possibility exists for an -unauthorized user to view or edit sensitive information. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -chgrp 0 /etc/cron.allow - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Test for existence /etc/cron.allow - stat: - path: /etc/cron.allow - register: file_exists - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSSv4-2.2.6 - - configure_strategy - - file_groupowner_cron_allow - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Ensure group owner 0 on /etc/cron.allow - file: - path: /etc/cron.allow - group: '0' - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - file_exists.stat is defined and file_exists.stat.exists - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSSv4-2.2.6 - - configure_strategy - - file_groupowner_cron_allow - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Verify User Who Owns /etc/cron.allow file - If /etc/cron.allow exists, it must be owned by root. - -To properly set the owner of /etc/cron.allow, run the command: -$ sudo chown root /etc/cron.allow - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - APO01.06 - DSS05.04 - DSS05.07 - DSS06.02 - CCI-000366 - 4.3.3.7.3 - SR 2.1 - SR 5.2 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CM-6(a) - AC-6(1) - PR.AC-4 - PR.DS-5 - 2.2.6 - SRG-OS-000480-GPOS-00227 - If the owner of the cron.allow file is not set to root, the possibility exists for an -unauthorized user to view or edit sensitive information. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -chown 0 /etc/cron.allow - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Test for existence /etc/cron.allow - stat: - path: /etc/cron.allow - register: file_exists - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSSv4-2.2.6 - - configure_strategy - - file_owner_cron_allow - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Ensure owner 0 on /etc/cron.allow - file: - path: /etc/cron.allow - owner: '0' - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - file_exists.stat is defined and file_exists.stat.exists - tags: - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSSv4-2.2.6 - - configure_strategy - - file_owner_cron_allow - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Verify Permissions on /etc/cron.allow file - If /etc/cron.allow exists, it must have permissions 0640 -or more restrictive. - - -To properly set the permissions of /etc/cron.allow, run the command: -$ sudo chmod 0640 /etc/cron.allow - 2.2.6 - SRG-OS-000480-GPOS-00227 - If the permissions of the cron.allow file are not set to 0640 or more restrictive, -the possibility exists for an unauthorized user to view or edit sensitive information. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -chmod u-xs,g-xws,o-xwrt /etc/cron.allow - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Test for existence /etc/cron.allow - stat: - path: /etc/cron.allow - register: file_exists - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - PCI-DSSv4-2.2.6 - - configure_strategy - - file_permissions_cron_allow - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Ensure permission u-xs,g-xws,o-xwrt on /etc/cron.allow - file: - path: /etc/cron.allow - mode: u-xs,g-xws,o-xwrt - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - file_exists.stat is defined and file_exists.stat.exists - tags: - - PCI-DSSv4-2.2.6 - - configure_strategy - - file_permissions_cron_allow - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - - - Deprecated services - Some deprecated software services impact the overall system security due to their behavior (leak of -confidentiality in network exchange, usage as uncontrolled communication channel, risk associated with the service due to its old age, etc. - - Uninstall the inet-based telnet server - The inet-based telnet daemon should be uninstalled. - NT007(R03) - 11 - 12 - 14 - 15 - 3 - 8 - 9 - APO13.01 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS01.04 - DSS05.02 - DSS05.03 - DSS05.05 - DSS06.06 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 7.1 - SR 7.6 - A.11.2.6 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.6.2.1 - A.6.2.2 - A.9.1.2 - CM-7(a) - CM-7(b) - CM-6(a) - PR.AC-3 - PR.IP-1 - PR.PT-3 - PR.PT-4 - telnet allows clear text communications, and does not protect any -data transmission between client and server. Any confidential data can be -listened and no integrity checking is made. - -# CAUTION: This remediation script will remove inetutils-telnetd -# from the system, and may remove any packages -# that depend on inetutils-telnetd. Execute this -# remediation AFTER testing on a non-production -# system! - -if rpm -q --quiet "inetutils-telnetd" ; then - - yum remove -y "inetutils-telnetd" - -fi - - - name: Ensure inetutils-telnetd is removed - package: - name: inetutils-telnetd - state: absent - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - high_severity - - low_complexity - - low_disruption - - no_reboot_needed - - package_inetutils-telnetd_removed - - include remove_inetutils-telnetd - -class remove_inetutils-telnetd { - package { 'inetutils-telnetd': - ensure => 'purged', - } -} - - -package --remove=inetutils-telnetd - - - - - - - Uninstall the nis package - The support for Yellowpages should not be installed unless it is required. - NIS is the historical SUN service for central account management, more and more replaced by LDAP. -NIS does not support efficiently security constraints, ACL, etc. and should not be used. - -# CAUTION: This remediation script will remove nis -# from the system, and may remove any packages -# that depend on nis. Execute this -# remediation AFTER testing on a non-production -# system! - -if rpm -q --quiet "nis" ; then - - yum remove -y "nis" - -fi - - - name: Ensure nis is removed - package: - name: nis - state: absent - tags: - - disable_strategy - - low_complexity - - low_disruption - - low_severity - - no_reboot_needed - - package_nis_removed - - include remove_nis - -class remove_nis { - package { 'nis': - ensure => 'purged', - } -} - - -package --remove=nis - - - - - - - Uninstall the ntpdate package - ntpdate is a historical ntp synchronization client for unixes. It sould be uninstalled. - ntpdate is an old not security-compliant ntp client. It should be replaced by modern ntp clients such as ntpd, able to use cryptographic mechanisms integrated in NTP. - -# CAUTION: This remediation script will remove ntpdate -# from the system, and may remove any packages -# that depend on ntpdate. Execute this -# remediation AFTER testing on a non-production -# system! - -if rpm -q --quiet "ntpdate" ; then - - yum remove -y "ntpdate" - -fi - - - name: Ensure ntpdate is removed - package: - name: ntpdate - state: absent - tags: - - disable_strategy - - low_complexity - - low_disruption - - low_severity - - no_reboot_needed - - package_ntpdate_removed - - include remove_ntpdate - -class remove_ntpdate { - package { 'ntpdate': - ensure => 'purged', - } -} - - -package --remove=ntpdate - - - - - - - Uninstall the ssl compliant telnet server - The telnet daemon, even with ssl support, should be uninstalled. - NT007(R02) - 11 - 12 - 14 - 15 - 3 - 8 - 9 - APO13.01 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS01.04 - DSS05.02 - DSS05.03 - DSS05.05 - DSS06.06 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 7.1 - SR 7.6 - A.11.2.6 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.6.2.1 - A.6.2.2 - A.9.1.2 - CM-7(a) - CM-7(b) - CM-6(a) - PR.AC-3 - PR.IP-1 - PR.PT-3 - PR.PT-4 - telnet, even with ssl support, should not be installed. -When remote shell is required, up-to-date ssh daemon can be used. - -# CAUTION: This remediation script will remove telnetd-ssl -# from the system, and may remove any packages -# that depend on telnetd-ssl. Execute this -# remediation AFTER testing on a non-production -# system! - -if rpm -q --quiet "telnetd-ssl" ; then - - yum remove -y "telnetd-ssl" - -fi - - - name: Ensure telnetd-ssl is removed - package: - name: telnetd-ssl - state: absent - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - high_severity - - low_complexity - - low_disruption - - no_reboot_needed - - package_telnetd-ssl_removed - - include remove_telnetd-ssl - -class remove_telnetd-ssl { - package { 'telnetd-ssl': - ensure => 'purged', - } -} - - -package --remove=telnetd-ssl - - - - - - - Uninstall the telnet server - The telnet daemon should be uninstalled. - BP28(R1) - NT007(R03) - 11 - 12 - 14 - 15 - 3 - 8 - 9 - APO13.01 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS01.04 - DSS05.02 - DSS05.03 - DSS05.05 - DSS06.06 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 7.1 - SR 7.6 - A.11.2.6 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.6.2.1 - A.6.2.2 - A.9.1.2 - CM-7(a) - CM-7(b) - CM-6(a) - PR.AC-3 - PR.IP-1 - PR.PT-3 - PR.PT-4 - telnet allows clear text communications, and does not protect -any data transmission between client and server. Any confidential data -can be listened and no integrity checking is made.' - -# CAUTION: This remediation script will remove telnetd -# from the system, and may remove any packages -# that depend on telnetd. Execute this -# remediation AFTER testing on a non-production -# system! - -if rpm -q --quiet "telnetd" ; then - - yum remove -y "telnetd" - -fi - - - name: Ensure telnetd is removed - package: - name: telnetd - state: absent - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - high_severity - - low_complexity - - low_disruption - - no_reboot_needed - - package_telnetd_removed - - include remove_telnetd - -class remove_telnetd { - package { 'telnetd': - ensure => 'purged', - } -} - - -package --remove=telnetd - - - - - - - - DHCP - The Dynamic Host Configuration Protocol (DHCP) allows -systems to request and obtain an IP address and other configuration -parameters from a server. - -This guide recommends configuring networking on clients by manually editing -the appropriate files under /etc/sysconfig. Use of DHCP can make client -systems vulnerable to compromise by rogue DHCP servers, and should be avoided -unless necessary. If using DHCP is necessary, however, there are best practices -that should be followed to minimize security risk. - - Configure DHCP Client if Necessary - If DHCP must be used, then certain configuration changes can -minimize the amount of information it receives and applies from the network, -and thus the amount of incorrect information a rogue DHCP server could -successfully distribute. For more information on configuring dhclient, see the -dhclient(8) and dhclient.conf(5) man pages. - - Minimize the DHCP-Configured Options - Create the file /etc/dhcp/dhclient.conf, and add an -appropriate setting for each of the ten configuration settings which can be -obtained via DHCP. For each setting, do one of the following: - -If the setting should not be configured remotely by the DHCP server, -select an appropriate static value, and add the line: -supersede setting value; -If the setting should be configured remotely by the DHCP server, add the lines: -request setting; -require setting; -For example, suppose the DHCP server should provide only the IP address itself -and the subnet mask. Then the entire file should look like: -supersede domain-name "example.com"; -supersede domain-name-servers 192.168.1.2; -supersede nis-domain ""; -supersede nis-servers ""; -supersede ntp-servers "ntp.example.com "; -supersede routers 192.168.1.1; -supersede time-offset -18000; -request subnet-mask; -require subnet-mask; - In this example, the options nis-servers and -nis-domain are set to empty strings, on the assumption that the deprecated NIS -protocol is not in use. It is necessary to supersede settings for unused -services so that they cannot be set by a hostile DHCP server. If an option is -set to an empty string, dhclient will typically not attempt to configure the -service. - By default, the DHCP client program, dhclient, requests and applies -ten configuration options (in addition to the IP address) from the DHCP server. -subnet-mask, broadcast-address, time-offset, routers, domain-name, -domain-name-servers, host-name, nis-domain, nis-servers, and ntp-servers. Many -of the options requested and applied by dhclient may be the same for every -system on a network. It is recommended that almost all configuration options be -assigned statically, and only options which must vary on a host-by-host basis -be assigned via DHCP. This limits the damage which can be done by a rogue DHCP -server. If appropriate for your site, it is also possible to supersede the -host-name directive in /etc/dhcp/dhclient.conf, establishing a static -hostname for the system. However, dhclient does not use the host name option -provided by the DHCP server (instead using the value provided by a reverse DNS -lookup). - - - - Configure DHCP Server - If the system must act as a DHCP server, the configuration -information it serves should be minimized. Also, support for other protocols -and DNS-updating schemes should be explicitly disabled unless needed. The -configuration file for dhcpd is called /etc/dhcp/dhcpd.conf. The file -begins with a number of global configuration options. The remainder of the file -is divided into sections, one for each block of addresses offered by dhcpd, -each of which contains configuration options specific to that address -block. - - Minimize Served Information - Edit /etc/dhcp/dhcpd.conf. Examine each address range section within -the file, and ensure that the following options are not defined unless there is -an operational need to provide this information via DHCP: -option domain-name -option domain-name-servers -option nis-domain -option nis-servers -option ntp-servers -option routers -option time-offset - By default, the Red Hat Enterprise Linux client installation uses DHCP -to request much of the above information from the DHCP server. In particular, -domain-name, domain-name-servers, and routers are configured via DHCP. These -settings are typically necessary for proper network functionality, but are also -usually static across systems at a given site. - 11 - 14 - 3 - 9 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS05.02 - DSS05.05 - DSS06.06 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 7.6 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.9.1.2 - CM-7(a) - CM-7(b) - CM-6(a) - PR.IP-1 - PR.PT-3 - Because the configuration information provided by the DHCP server -could be maliciously provided to clients by a rogue DHCP server, the amount of -information provided via DHCP should be minimized. Remove these definitions -from the DHCP server configuration to ensure that legitimate clients do not -unnecessarily rely on DHCP for this information. - - - - Disable DHCP Client - DHCP is the default network configuration method provided by the system -installer, and common on many networks. Nevertheless, manual management -of IP addresses for systems implies a greater degree of management and -accountability for network activity. - - - Disable DHCP Server - The DHCP server dhcpd is not installed or activated by -default. If the software was installed and activated, but the -system does not need to act as a DHCP server, it should be disabled -and removed. - - Uninstall DHCP Server Package - If the system does not need to act as a DHCP server, -the dhcp package can be uninstalled. - -The dhcp-server package can be removed with the following command: - -$ sudo yum erase dhcp-server - BP28(R1) - 11 - 14 - 3 - 9 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS05.02 - DSS05.05 - DSS06.06 - CCI-000366 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 7.6 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.9.1.2 - CM-7(a) - CM-7(b) - CM-6(a) - PR.IP-1 - PR.PT-3 - 2.2.4 - Removing the DHCP server ensures that it cannot be easily or -accidentally reactivated and disrupt network operation. - -# CAUTION: This remediation script will remove dhcp -# from the system, and may remove any packages -# that depend on dhcp. Execute this -# remediation AFTER testing on a non-production -# system! - -if rpm -q --quiet "dhcp" ; then - - yum remove -y "dhcp" - -fi - - - name: Ensure dhcp is removed - package: - name: dhcp - state: absent - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - PCI-DSSv4-2.2.4 - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - package_dhcp_removed - - include remove_dhcp - -class remove_dhcp { - package { 'dhcp': - ensure => 'purged', - } -} - - -package --remove=dhcp - - - - - - - - - - - - DNS Server - Most organizations have an operational need to run at -least one nameserver. However, there are many common attacks -involving DNS server software, and this server software should -be disabled on any system -on which it is not needed. - - Disable DNS Server - DNS software should be disabled on any systems which does not -need to be a nameserver. Note that the BIND DNS server software is -not installed on Oracle Linux 9 by default. The remainder of this section -discusses secure configuration of systems which must be -nameservers. - - Uninstall bind Package - The named service is provided by the bind package. -The bind package can be removed with the following command: - -$ sudo yum erase bind - 11 - 14 - 3 - 9 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS05.02 - DSS05.05 - DSS06.06 - CCI-000366 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 7.6 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.9.1.2 - CM-7(a) - CM-7(b) - CM-6(a) - PR.IP-1 - PR.PT-3 - 2.2.4 - If there is no need to make DNS server software available, -removing it provides a safeguard against its activation. - -# CAUTION: This remediation script will remove bind -# from the system, and may remove any packages -# that depend on bind. Execute this -# remediation AFTER testing on a non-production -# system! - -if rpm -q --quiet "bind" ; then - - yum remove -y "bind" - -fi - - - name: Ensure bind is removed - package: - name: bind - state: absent - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - PCI-DSSv4-2.2.4 - - disable_strategy - - low_complexity - - low_disruption - - low_severity - - no_reboot_needed - - package_bind_removed - - include remove_bind - -class remove_bind { - package { 'bind': - ensure => 'purged', - } -} - - -package --remove=bind - - - - - - - - - - - Isolate DNS from Other Services - This section discusses mechanisms for preventing the DNS server -from interfering with other services. This is done both to protect the -remainder of the network should a nameserver be compromised, and to make direct -attacks on nameservers more difficult. - - Run DNS Software in a chroot Jail - Install the bind-chroot package: -$ sudo yum install bind-chroot -Place a valid named.conf file inside the chroot jail: -$ sudo cp /etc/named.conf /var/named/chroot/etc/named.conf -$ sudo chown root:root /var/named/chroot/etc/named.conf -$ sudo chmod 644 /var/named/chroot/etc/named.conf -Create and populate an appropriate zone directory within the jail, based on the -options directive. If your named.conf includes: -options { -directory "/path/to/DIRNAME "; -... -} -then copy that directory and its contents from the original zone directory: -$ sudo cp -r /path/to/DIRNAME /var/named/chroot/DIRNAME -Add or correct the following line within /etc/sysconfig/named: -ROOTDIR=/var/named/chroot - If you are running BIND in a chroot jail, then you -should use the jailed named.conf as the primary nameserver -configuration file. That is, when this guide recommends editing -/etc/named.conf, you should instead edit -/var/named/chroot/etc/named.conf. - - - Run DNS Software on Dedicated Servers - Since DNS is -a high-risk service which must frequently be made available to the entire -Internet, it is strongly recommended that no other services be offered by -systems which act as organizational DNS servers. - - - - Protect DNS Data from Tampering or Attack - This section discusses DNS configuration options which make it -more difficult for attackers to gain access to private DNS data or to modify -DNS data. - - Use Views to Partition External and Internal Information - If it is not possible to run external and internal nameservers on -separate physical systems, run BIND9 and simulate this feature using views. -Edit /etc/named.conf. Add or correct the following directives (where -SUBNET is the numerical IP representation of your organization in the form -xxx.xxx.xxx.xxx/xx): -acl internal { - SUBNET ; - localhost; -}; -view "internal-view" { - match-clients { internal; }; - zone "." IN { - type hint; - file "db.cache"; - }; - zone "internal.example.com " IN { - ... - }; -}; - -view "external-view" { - match-clients { any; }; - recursion no; - zone "example.com " IN { - ... - }; -}; - As shown in the example, database files which are -required for recursion, such as the root hints file, must be available to any -clients which are allowed to make recursive queries. Under typical -circumstances, this includes only the internal clients which are allowed to use -this server as a general-purpose nameserver. - - - Run Separate DNS Servers for External and Internal Queries - Is it possible to run external and internal nameservers on -separate systems? If so, follow the configuration guidance in this section. On -the external nameserver, edit /etc/named.conf to add or correct the -following directives: -options { - allow-query { any; }; - recursion no; - ... -}; -zone "example.com " IN { - ... -}; -On the internal nameserver, edit /etc/named.conf. Add or correct the -following directives, where SUBNET is the numerical IP representation of your -organization in the form xxx.xxx.xxx.xxx/xx: -acl internal { - SUBNET ; - localhost; -}; -options { - allow-query { internal; }; - ... -}; -zone "internal.example.com " IN { - ... -}; - - - - - Docker Service - The docker service is necessary to create containers, which are - self-sufficient and self-contained applications using the resource - isolation features of the kernel. - - - Application Whitelisting Daemon - Fapolicyd (File Access Policy Daemon) implements application whitelisting -to decide file access rights. Applications that are known via a reputation -source are allowed access while unknown applications are not. The daemon -makes use of the kernel's fanotify interface to determine file access rights. - - - Install fapolicyd Package - The fapolicyd package can be installed with the following command: - -$ sudo yum install fapolicyd - CCI-001764 - CCI-001774 - CM-6(a) - SI-4(22) - SRG-OS-000370-GPOS-00155 - SRG-OS-000368-GPOS-00154 - SRG-OS-000480-GPOS-00230 - fapolicyd (File Access Policy Daemon) -implements application whitelisting to decide file access rights. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -if ! rpm -q --quiet "fapolicyd" ; then - yum install -y "fapolicyd" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Ensure fapolicyd is installed - package: - name: fapolicyd - state: present - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-SI-4(22) - - enable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - package_fapolicyd_installed - - include install_fapolicyd - -class install_fapolicyd { - package { 'fapolicyd': - ensure => 'installed', - } -} - - -package --add=fapolicyd - - -[[packages]] -name = "fapolicyd" -version = "*" - - - - - - - - - - Enable the File Access Policy Service - The File Access Policy service should be enabled. - -The fapolicyd service can be enabled with the following command: -$ sudo systemctl enable fapolicyd.service - CCI-001764 - CCI-001774 - CM-6(a) - SI-4(22) - FMT_SMF_EXT.1 - SRG-OS-000370-GPOS-00155 - SRG-OS-000368-GPOS-00154 - SRG-OS-000480-GPOS-00230 - The fapolicyd service (File Access Policy Daemon) -implements application whitelisting to decide file access rights. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -SYSTEMCTL_EXEC='/usr/bin/systemctl' -"$SYSTEMCTL_EXEC" unmask 'fapolicyd.service' -"$SYSTEMCTL_EXEC" start 'fapolicyd.service' -"$SYSTEMCTL_EXEC" enable 'fapolicyd.service' - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Enable service fapolicyd - block: - - - name: Gather the package facts - package_facts: - manager: auto - - - name: Enable service fapolicyd - systemd: - name: fapolicyd - enabled: 'yes' - state: started - masked: 'no' - when: - - '"fapolicyd" in ansible_facts.packages' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-SI-4(22) - - enable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_fapolicyd_enabled - - include enable_fapolicyd - -class enable_fapolicyd { - service {'fapolicyd': - enable => true, - ensure => 'running', - } -} - - -[customizations.services] -enabled = ["fapolicyd"] - - - - - - - - - - Configure Fapolicy Module to Employ a Deny-all, Permit-by-exception Policy to Allow the Execution of Authorized Software Programs. - The Fapolicy module must be configured to employ a deny-all, permit-by-exception policy to allow the execution of authorized software programs and to prevent unauthorized software from running. - This rule doesn't come with a remediation. Before remediating the system administrator needs to create an allowlist of authorized software. - CCI-001764 - CM-7 (2) - CM-7 (5) (b) - CM-6 b - SRG-OS-000368-GPOS-00154 - SRG-OS-000370-GPOS-00155 - SRG-OS-000480-GPOS-00232 - Utilizing a whitelist provides a configuration management method for allowing the execution of only authorized software. -Using only authorized software decreases risk by limiting the number of potential vulnerabilities. Verification of whitelisted software occurs prior to execution or at system startup. - -Proceed with caution with enforcing the use of this daemon. -Improper configuration may render the system non-functional. -The "fapolicyd" API is not namespace aware and can cause issues when launching or running containers. - - - - - - - - - fapolicyd Must be Configured to Limit Access to Users Home Folders - fapolicyd needs be configured so that users cannot give access to their home folders to other users. - This rule is deprecated and there is no replacement at this time. -Previous versions of this rule provided fixtext that would cause fapolicyd not to start. - CCI-000366 - CM-6 b - SRG-OS-000480-GPOS-00230 - Users' home directories/folders may contain information of a sensitive nature. -Non-privileged users should coordinate any sharing of information with a System Administrator (SA) through shared resources. -fapolicyd can confine users to their home directory, not allowing them to make any changes outside of their own home directories. -Confining users to their home directory will minimize the risk of sharing information. - - - - FTP Server - FTP is a common method for allowing remote access to -files. Like telnet, the FTP protocol is unencrypted, which means -that passwords and other data transmitted during the session can be -captured and that the session is vulnerable to hijacking. -Therefore, running the FTP server software is not recommended. - -However, there are some FTP server configurations which may -be appropriate for some environments, particularly those which -allow only read-only anonymous access as a means of downloading -data available to the public. - - Disable vsftpd if Possible - To minimize attack surface, disable vsftpd if at all -possible. - - Uninstall vsftpd Package - The vsftpd package can be removed with the following command: $ sudo yum erase vsftpd - 11 - 14 - 3 - 9 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS05.02 - DSS05.05 - DSS06.06 - CCI-000197 - CCI-000366 - CCI-000381 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 7.6 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.9.1.2 - CM-7(a) - CM-7(b) - CM-6(a) - IA-5(1)(c) - IA-5(1).1(v) - CM-7 - CM-7.1(ii) - PR.IP-1 - PR.PT-3 - 2.2.4 - SRG-OS-000074-GPOS-00042 - SRG-OS-000095-GPOS-00049 - SRG-OS-000480-GPOS-00227 - Removing the vsftpd package decreases the risk of its -accidental activation. - -# CAUTION: This remediation script will remove vsftpd -# from the system, and may remove any packages -# that depend on vsftpd. Execute this -# remediation AFTER testing on a non-production -# system! - -if rpm -q --quiet "vsftpd" ; then - - yum remove -y "vsftpd" - -fi - - - name: Ensure vsftpd is removed - package: - name: vsftpd - state: absent - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7 - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-CM-7.1(ii) - - NIST-800-53-IA-5(1)(c) - - NIST-800-53-IA-5(1).1(v) - - PCI-DSSv4-2.2.4 - - disable_strategy - - high_severity - - low_complexity - - low_disruption - - no_reboot_needed - - package_vsftpd_removed - - include remove_vsftpd - -class remove_vsftpd { - package { 'vsftpd': - ensure => 'purged', - } -} - - -package --remove=vsftpd - - - - - - - - - - - Configure vsftpd to Provide FTP Service if Necessary - The primary vsftpd configuration file is -/etc/vsftpd.conf, if that file exists, or -/etc/vsftpd/vsftpd.conf if it does not. - - Configure Firewalls to Protect the FTP Server - -By default, iptables -blocks access to the ports used by the web server. - -To configure iptables to allow port 21 traffic, one must edit -/etc/sysconfig/iptables and -/etc/sysconfig/ip6tables (if IPv6 is in use). -Add the following line, ensuring that it appears before the final LOG and DROP lines for the INPUT chain: --A INPUT -m state --state NEW -p tcp --dport 21 -j ACCEPT -Edit the file /etc/sysconfig/iptables-config. Ensure that the space-separated list of modules contains -the FTP connection tracking module: -IPTABLES_MODULES="ip_conntrack_ftp" - These settings configure the firewall to allow connections to an FTP server. - - -The first line allows initial connections to the FTP server port. -FTP is an older protocol which is not very compatible with firewalls. During the initial FTP dialogue, the client -and server negotiate an arbitrary port to be used for data transfer. The ip_conntrack_ftp module is used by -iptables to listen to that dialogue and allow connections to the data ports which FTP negotiates. This allows an -FTP server to operate on a system which is running a firewall. - - - Restrict the Set of Users Allowed to Access FTP - This section describes how to disable non-anonymous (password-based) FTP logins, or, if it is not possible to -do this entirely due to legacy applications, how to restrict insecure FTP login to only those users who have an -identified need for this access. - - Limit Users Allowed FTP Access if Necessary - If there is a mission-critical reason for users to access their accounts via the insecure FTP protocol, limit the set of users who are allowed this access. Edit the vsftpd configuration file. Add or correct the following configuration options: -userlist_enable=YES -userlist_file=/etc/vsftp.ftpusers -userlist_deny=NO -Edit the file /etc/vsftp.ftpusers. For each user USERNAME who should be allowed to access the system via FTP, add a line containing that user's name: -USERNAME -If anonymous access is also required, add the anonymous usernames to /etc/vsftp.ftpusers as well. -anonymous -ftp - Historically, the file /etc/ftpusers contained a list of users who were not allowed to access the system via FTP. It was used to prevent system users such as the root user from logging in via the insecure FTP protocol. However, when the configuration option userlist deny=NO is set, vsftpd interprets ftpusers as the set of users who are allowed to login via FTP. Since it should be possible for most users to access their accounts via secure protocols, it is recommended that this setting be used, so that non-anonymous FTP access can be limited to legacy users who have been explicitly identified. - - - - - Use vsftpd to Provide FTP Service if Necessary - If your use-case requires FTP service, install and -set-up vsftpd to provide it. - - - - Web Server - The web server is responsible for providing access to -content via the HTTP protocol. Web servers represent a significant -security risk because: - -The HTTP port is commonly probed by malicious sourcesWeb server software is very complex, and includes a long -history of vulnerabilitiesThe HTTP protocol is unencrypted and vulnerable to passive -monitoring - -The system's default web server software is Apache 2 and is -provided in the RPM package httpd. - - Disable Apache if Possible - If Apache was installed and activated, but the system -does not need to act as a web server, then it should be disabled -and removed from the system. - - - Disable NGINX if Possible - If NGINX was installed and activated, but the system does not need to act as a web server, -then it should be removed from the system. - - - Install Apache if Necessary - If httpd was not installed and activated, but the system -needs to act as a web server, then it should be installed on the system. Follow these -guidelines to install it defensively. The httpd package can be installed with -the following command: -$ sudo yum install httpd -This method of installation is recommended over installing the "Web Server" -package group during the system installation process. The Web Server package -group includes many packages which are likely extraneous, while the -command-line method installs only the required httpd package itself. - - Confirm Minimal Built-in Modules Installed - The default httpd installation minimizes the number of -modules that are compiled directly into the binary (core prefork http_core -mod_so). This minimizes risk by limiting the capabilities allowed by the -web server. - -Query the set of compiled-in modules using the following command: -$ httpd -l -If the number of compiled-in modules is significantly larger than the -aforementioned set, this guide recommends re-installing httpd with a -reduced configuration. Minimizing the number of modules that are compiled into -the httpd binary, reduces risk by limiting the capabilities allowed by -the webserver. - - - - Secure Apache Configuration - The httpd configuration file is -/etc/httpd/conf/httpd.conf. Apply the recommendations in the remainder -of this section to this file. - - HTTPD Log Level - The setting for LogLevel in /etc/httpd/conf/httpd.conf - alert - crit - warn - emerg - error - warn - - - Maximum KeepAlive Requests for HTTPD - The setting for MaxKeepAliveRequests in httpd.conf - 100 - 1000 - 10000 - 100000 - 500 - 100 - - - Configure Operating System to Protect Web Server - The following configuration steps should be taken on the system which hosts the -web server, in order to provide as safe an environment as possible for the web server. - - Run httpd in a chroot Jail if Practical - Running httpd inside a chroot jail is designed to isolate the -web server process to a small section of the filesystem, limiting the damage if -it is compromised. Versions of Apache greater than 2.2.10 (such as the one -included with Oracle Linux 9) provide the ChrootDir directive. To run Apache -inside a chroot jail in /chroot/apache, add the following line to -/etc/httpd/conf/httpd.conf: ChrootDir /chroot/apache This -necessitates placing all files required by httpd inside -/chroot/apache , including httpd's binaries, modules, -configuration files, and served web pages. The details of this configuration -are beyond the scope of this guide. This may also require additional SELinux -configuration. - - - Restrict File and Directory Access - Minimize access to critical httpd files and directories. - - - - Configure PERL Securely - PERL (Practical Extraction and Report Language) is an interpreted language -optimized for scanning arbitrary text files, extracting information from those -text files, and printing reports based on that information. The language is -often used in shell scripting and is intended to be practical, easy to use, and -efficient means of generating interactive web pages for the user. - - - Configure PHP Securely - PHP is a widely-used and often misconfigured server-side scripting language. It should -be used with caution, but configured appropriately when needed. - -Review /etc/php.ini and make the following changes if possible: -# Do not expose PHP error messages to external users -display_errors = Off - -# Enable safe mode -safe_mode = On - -# Only allow access to executables in isolated directory -safe_mode_exec_dir = php-required-executables-path - -# Limit external access to PHP environment -safe_mode_allowed_env_vars = PHP_ - -# Restrict PHP information leakage -expose_php = Off - -# Log all errors -log_errors = On - -# Do not register globals for input data -register_globals = Off - -# Minimize allowable PHP post size -post_max_size = 1K - -# Ensure PHP redirects appropriately -cgi.force_redirect = 0 - -# Disallow uploading unless necessary -file_uploads = Off - -# Disallow treatment of file requests as fopen calls -allow_url_fopen = Off - -# Enable SQL safe mode -sql.safe_mode = On - - - - Directory Restrictions - The Directory tags in the web server configuration file allow finer grained access -control for a specified directory. All web directories should be configured on a -case-by-case basis, allowing access only where needed. - - - Minimize Web Server Loadable Modules - A default installation of httpd includes a plethora of dynamically shared objects (DSO) -that are loaded at run-time. Unlike the aforementioned compiled-in modules, a DSO can be -disabled in the configuration file by removing the corresponding LoadModule directive. - -Note: A DSO only provides additional functionality if associated directives are included -in the httpd configuration file. It should also be noted that removing a DSO will produce -errors on httpd startup if the configuration file contains directives that apply to that -module. Refer to http://httpd.apache.org/docs/ for details on which directives -are associated with each DSO. - -Following each DSO removal, the configuration can be tested with the following command -to check if everything still works: -$ sudo service httpd configtest -The purpose of each of the modules loaded by default will now be addressed one at a time. -If none of a module's directives are being used, remove it. - - httpd Core Modules - These modules comprise a basic subset of modules that are likely needed for base httpd -functionality; ensure they are not commented out in /etc/httpd/conf/httpd.conf: -LoadModule auth_basic_module modules/mod_auth_basic.so -LoadModule authn_default_module modules/mod_authn_default.so -LoadModule authz_host_module modules/mod_authz_host.so -LoadModule authz_user_module modules/mod_authz_user.so -LoadModule authz_groupfile_module modules/mod_authz_groupfile.so -LoadModule authz_default_module modules/mod_authz_default.so -LoadModule log_config_module modules/mod_log_config.so -LoadModule logio_module modules/mod_logio.so -LoadModule setenvif_module modules/mod_setenvif.so -LoadModule mime_module modules/mod_mome.so -LoadModule autoindex_module modules/mod_autoindex.so -LoadModule negotiation_module modules/mod_negotiation.so -LoadModule dir_module modules/mod_dir.so -LoadModule alias_module modules/mod_alias.so -Minimizing the number of loadable modules available to the web server reduces risk -by limiting the capabilities allowed by the web server. - - Minimize Modules for HTTP Basic Authentication - The following modules are necessary if this web server will provide content that will -be restricted by a password. - -Authentication can be performed using local plain text password files (authn_file), -local DBM password files (authn_dbm) or an LDAP directory. The only module required by -the web server depends on your choice of authentication. Comment out the modules you don't -need from the following: -LoadModule authn_file_module modules/mod_authn_file.so -LoadModule authn_dbm_module modules/mod_authn_dbm.so -authn_alias allows for authentication based on aliases. authn_anon -allows anonymous authentication similar to that of anonymous ftp sites. authz_owner -allows authorization based on file ownership. authz_dbm allows for authorization -based on group membership if the web server is using DBM authentication. - -If the above functionality is unnecessary, comment out the related module: -#LoadModule authn_alias_module modules/mod_authn_alias.so -#LoadModule authn_anon_module modules/mod_authn_anon.so -#LoadModule authz_owner_module modules/mod_authz_owner.so -#LoadModule authz_dbm_module modules/mod_authz_dbm.so - - - Minimize Configuration Files Included - The Include directive directs httpd to load supplementary configuration files -from a provided path. The default configuration loads all files that end in .conf -from the /etc/httpd/conf.d directory. - -To restrict excess configuration, the following line should be commented out and -replaced with Include directives that only reference required configuration files: -#Include conf.d/*.conf -If the above change was made, ensure that the SSL encryption remains loaded by -explicitly including the corresponding configuration file: -Include conf.d/ssl.conf -If PHP is necessary, a similar alteration must be made: -Include conf.d/php.conf - -Explicitly listing the configuration files to be loaded during web server start-up avoids -the possibility of unwanted or malicious configuration files to be automatically included as -part of the server's running configuration. - - - Minimize Various Optional Components - The following modules perform very specific tasks, sometimes providing access to -just a few additional directives. If such functionality is not required (or if you -are not using these directives), comment out the associated module: -External filtering (response passed through external program prior to client delivery) -#LoadModule ext_filter_module modules/mod_ext_filter.soUser-specified Cache Control and Expiration -#LoadModule expires_module modules/mod_expires.soCompression Output Filter (provides content compression prior to client delivery) -#LoadModule deflate_module modules/mod_deflate.soHTTP Response/Request Header Customization -#LoadModule headers_module modules/mod_headers.soUser activity monitoring via cookies -#LoadModule usertrack_module modules/mod_usertrack.soDynamically configured mass virtual hosting -#LoadModule vhost_alias_module modules/mod_vhost_alias.so -Minimizing the number of loadable modules available to the web server reduces risk -by limiting the capabilities allowed by the web server. - - - - - Use Appropriate Modules to Improve httpd's Security - Among the modules available for httpd are several whose use may improve the -security of the web server installation. This section recommends and discusses -the deployment of security-relevant modules. - - Deploy mod_security - The security module provides an application level firewall for httpd. -Following its installation with the base ruleset, specific configuration advice can be found at - - http://www.modsecurity.org/ to design a policy that best matches the security needs of -the web applications. Usage of mod_security is highly recommended for some environments, -but it should be noted this module does not ship with Red Hat Enterprise Linux itself, -and instead is provided via Extra Packages for Enterprise Linux (EPEL). -For more information on EPEL please refer to - http://fedoraproject.org/wiki/EPEL. - - - Deploy mod_ssl - Because HTTP is a plain text protocol, all traffic is susceptible to passive -monitoring. If there is a need for confidentiality, SSL should be configured -and enabled to encrypt content. - -Note: mod_nss is a FIPS 140-2 certified alternative to mod_ssl. -The modules share a considerable amount of code and should be nearly identical -in functionality. If FIPS 140-2 validation is required, then mod_nss should -be used. If it provides some feature or its greater compatibility is required, -then mod_ssl should be used. - - - - Restrict Web Server Information Leakage - The ServerTokens and ServerSignature directives determine how -much information the web server discloses about the configuration of the -system. - - - Configure HTTPD-Served Web Content Securely - Running httpd inside a chroot jail is designed to isolate the -web server process to a small section of the filesystem, limiting the damage if -it is compromised. Versions of Apache greater than 2.2.10 (such as the one -included with Red Hat Enterprise Linux 7) provide the ChrootDir directive. To run Apache -inside a chroot jail in /chroot/apache, add the following line to -/etc/httpd/conf/httpd.conf: ChrootDir /chroot/apache This -necessitates placing all files required by httpd inside -/chroot/apache , including httpd's binaries, modules, -configuration files, and served web pages. The details of this configuration -are beyond the scope of this guide. This may also require additional SELinux -configuration. - - Web Login Banner Verbiage - Enter an appropriate login banner for your organization. Please note that new lines must -be expressed by the '\n' character and special characters like parentheses and quotation marks must be escaped with '\\'. - ^(You[\s\n]+are[\s\n]+accessing[\s\n]+a[\s\n]+U\.S\.[\s\n]+Government[\s\n]+\(USG\)[\s\n]+Information[\s\n]+System[\s\n]+\(IS\)[\s\n]+that[\s\n]+is[\s\n]+provided[\s\n]+for[\s\n]+USG\-authorized[\s\n]+use[\s\n]+only\.[\s\n]+By[\s\n]+using[\s\n]+this[\s\n]+IS[\s\n]+\(which[\s\n]+includes[\s\n]+any[\s\n]+device[\s\n]+attached[\s\n]+to[\s\n]+this[\s\n]+IS\),[\s\n]+you[\s\n]+consent[\s\n]+to[\s\n]+the[\s\n]+following[\s\n]+conditions\:(?:[\n]+|(?:\\n)+)\-The[\s\n]+USG[\s\n]+routinely[\s\n]+intercepts[\s\n]+and[\s\n]+monitors[\s\n]+communications[\s\n]+on[\s\n]+this[\s\n]+IS[\s\n]+for[\s\n]+purposes[\s\n]+including,[\s\n]+but[\s\n]+not[\s\n]+limited[\s\n]+to,[\s\n]+penetration[\s\n]+testing,[\s\n]+COMSEC[\s\n]+monitoring,[\s\n]+network[\s\n]+operations[\s\n]+and[\s\n]+defense,[\s\n]+personnel[\s\n]+misconduct[\s\n]+\(PM\),[\s\n]+law[\s\n]+enforcement[\s\n]+\(LE\),[\s\n]+and[\s\n]+counterintelligence[\s\n]+\(CI\)[\s\n]+investigations\.(?:[\n]+|(?:\\n)+)\-At[\s\n]+any[\s\n]+time,[\s\n]+the[\s\n]+USG[\s\n]+may[\s\n]+inspect[\s\n]+and[\s\n]+seize[\s\n]+data[\s\n]+stored[\s\n]+on[\s\n]+this[\s\n]+IS\.(?:[\n]+|(?:\\n)+)\-Communications[\s\n]+using,[\s\n]+or[\s\n]+data[\s\n]+stored[\s\n]+on,[\s\n]+this[\s\n]+IS[\s\n]+are[\s\n]+not[\s\n]+private,[\s\n]+are[\s\n]+subject[\s\n]+to[\s\n]+routine[\s\n]+monitoring,[\s\n]+interception,[\s\n]+and[\s\n]+search,[\s\n]+and[\s\n]+may[\s\n]+be[\s\n]+disclosed[\s\n]+or[\s\n]+used[\s\n]+for[\s\n]+any[\s\n]+USG\-authorized[\s\n]+purpose\.(?:[\n]+|(?:\\n)+)\-This[\s\n]+IS[\s\n]+includes[\s\n]+security[\s\n]+measures[\s\n]+\(e\.g\.,[\s\n]+authentication[\s\n]+and[\s\n]+access[\s\n]+controls\)[\s\n]+to[\s\n]+protect[\s\n]+USG[\s\n]+interests\-\-not[\s\n]+for[\s\n]+your[\s\n]+personal[\s\n]+benefit[\s\n]+or[\s\n]+privacy\.(?:[\n]+|(?:\\n)+)\-Notwithstanding[\s\n]+the[\s\n]+above,[\s\n]+using[\s\n]+this[\s\n]+IS[\s\n]+does[\s\n]+not[\s\n]+constitute[\s\n]+consent[\s\n]+to[\s\n]+PM,[\s\n]+LE[\s\n]+or[\s\n]+CI[\s\n]+investigative[\s\n]+searching[\s\n]+or[\s\n]+monitoring[\s\n]+of[\s\n]+the[\s\n]+content[\s\n]+of[\s\n]+privileged[\s\n]+communications,[\s\n]+or[\s\n]+work[\s\n]+product,[\s\n]+related[\s\n]+to[\s\n]+personal[\s\n]+representation[\s\n]+or[\s\n]+services[\s\n]+by[\s\n]+attorneys,[\s\n]+psychotherapists,[\s\n]+or[\s\n]+clergy,[\s\n]+and[\s\n]+their[\s\n]+assistants\.[\s\n]+Such[\s\n]+communications[\s\n]+and[\s\n]+work[\s\n]+product[\s\n]+are[\s\n]+private[\s\n]+and[\s\n]+confidential\.[\s\n]+See[\s\n]+User[\s\n]+Agreement[\s\n]+for[\s\n]+details\.|I've[\s\n]+read[\s\n]+\&[\s\n]+consent[\s\n]+to[\s\n]+terms[\s\n]+in[\s\n]+IS[\s\n]+user[\s\n]+agreem't\.)$ - ^You[\s\n]+are[\s\n]+accessing[\s\n]+a[\s\n]+U\.S\.[\s\n]+Government[\s\n]+\(USG\)[\s\n]+Information[\s\n]+System[\s\n]+\(IS\)[\s\n]+that[\s\n]+is[\s\n]+provided[\s\n]+for[\s\n]+USG\-authorized[\s\n]+use[\s\n]+only\.[\s\n]+By[\s\n]+using[\s\n]+this[\s\n]+IS[\s\n]+\(which[\s\n]+includes[\s\n]+any[\s\n]+device[\s\n]+attached[\s\n]+to[\s\n]+this[\s\n]+IS\),[\s\n]+you[\s\n]+consent[\s\n]+to[\s\n]+the[\s\n]+following[\s\n]+conditions\:(?:[\n]+|(?:\\n)+)\-The[\s\n]+USG[\s\n]+routinely[\s\n]+intercepts[\s\n]+and[\s\n]+monitors[\s\n]+communications[\s\n]+on[\s\n]+this[\s\n]+IS[\s\n]+for[\s\n]+purposes[\s\n]+including,[\s\n]+but[\s\n]+not[\s\n]+limited[\s\n]+to,[\s\n]+penetration[\s\n]+testing,[\s\n]+COMSEC[\s\n]+monitoring,[\s\n]+network[\s\n]+operations[\s\n]+and[\s\n]+defense,[\s\n]+personnel[\s\n]+misconduct[\s\n]+\(PM\),[\s\n]+law[\s\n]+enforcement[\s\n]+\(LE\),[\s\n]+and[\s\n]+counterintelligence[\s\n]+\(CI\)[\s\n]+investigations\.(?:[\n]+|(?:\\n)+)\-At[\s\n]+any[\s\n]+time,[\s\n]+the[\s\n]+USG[\s\n]+may[\s\n]+inspect[\s\n]+and[\s\n]+seize[\s\n]+data[\s\n]+stored[\s\n]+on[\s\n]+this[\s\n]+IS\.(?:[\n]+|(?:\\n)+)\-Communications[\s\n]+using,[\s\n]+or[\s\n]+data[\s\n]+stored[\s\n]+on,[\s\n]+this[\s\n]+IS[\s\n]+are[\s\n]+not[\s\n]+private,[\s\n]+are[\s\n]+subject[\s\n]+to[\s\n]+routine[\s\n]+monitoring,[\s\n]+interception,[\s\n]+and[\s\n]+search,[\s\n]+and[\s\n]+may[\s\n]+be[\s\n]+disclosed[\s\n]+or[\s\n]+used[\s\n]+for[\s\n]+any[\s\n]+USG\-authorized[\s\n]+purpose\.(?:[\n]+|(?:\\n)+)\-This[\s\n]+IS[\s\n]+includes[\s\n]+security[\s\n]+measures[\s\n]+\(e\.g\.,[\s\n]+authentication[\s\n]+and[\s\n]+access[\s\n]+controls\)[\s\n]+to[\s\n]+protect[\s\n]+USG[\s\n]+interests\-\-not[\s\n]+for[\s\n]+your[\s\n]+personal[\s\n]+benefit[\s\n]+or[\s\n]+privacy\.(?:[\n]+|(?:\\n)+)\-Notwithstanding[\s\n]+the[\s\n]+above,[\s\n]+using[\s\n]+this[\s\n]+IS[\s\n]+does[\s\n]+not[\s\n]+constitute[\s\n]+consent[\s\n]+to[\s\n]+PM,[\s\n]+LE[\s\n]+or[\s\n]+CI[\s\n]+investigative[\s\n]+searching[\s\n]+or[\s\n]+monitoring[\s\n]+of[\s\n]+the[\s\n]+content[\s\n]+of[\s\n]+privileged[\s\n]+communications,[\s\n]+or[\s\n]+work[\s\n]+product,[\s\n]+related[\s\n]+to[\s\n]+personal[\s\n]+representation[\s\n]+or[\s\n]+services[\s\n]+by[\s\n]+attorneys,[\s\n]+psychotherapists,[\s\n]+or[\s\n]+clergy,[\s\n]+and[\s\n]+their[\s\n]+assistants\.[\s\n]+Such[\s\n]+communications[\s\n]+and[\s\n]+work[\s\n]+product[\s\n]+are[\s\n]+private[\s\n]+and[\s\n]+confidential\.[\s\n]+See[\s\n]+User[\s\n]+Agreement[\s\n]+for[\s\n]+details\.$ - ^I've[\s\n]+read[\s\n]+\&[\s\n]+consent[\s\n]+to[\s\n]+terms[\s\n]+in[\s\n]+IS[\s\n]+user[\s\n]+agreem't\.$ - ^Use[\s\n]+of[\s\n]+this[\s\n]+or[\s\n]+any[\s\n]+other[\s\n]+DoD[\s\n]+interest[\s\n]+computer[\s\n]+system[\s\n]+constitutes[\s\n]+consent[\s\n]+to[\s\n]+monitoring[\s\n]+at[\s\n]+all[\s\n]+times\.[\s\n]+This[\s\n]+is[\s\n]+a[\s\n]+DoD[\s\n]+interest[\s\n]+computer[\s\n]+system\.[\s\n]+All[\s\n]+DoD[\s\n]+interest[\s\n]+computer[\s\n]+systems[\s\n]+and[\s\n]+related[\s\n]+equipment[\s\n]+are[\s\n]+intended[\s\n]+for[\s\n]+the[\s\n]+communication,[\s\n]+transmission,[\s\n]+processing,[\s\n]+and[\s\n]+storage[\s\n]+of[\s\n]+official[\s\n]+U\.S\.[\s\n]+Government[\s\n]+or[\s\n]+other[\s\n]+authorized[\s\n]+information[\s\n]+only\.[\s\n]+All[\s\n]+DoD[\s\n]+interest[\s\n]+computer[\s\n]+systems[\s\n]+are[\s\n]+subject[\s\n]+to[\s\n]+monitoring[\s\n]+at[\s\n]+all[\s\n]+times[\s\n]+to[\s\n]+ensure[\s\n]+proper[\s\n]+functioning[\s\n]+of[\s\n]+equipment[\s\n]+and[\s\n]+systems[\s\n]+including[\s\n]+security[\s\n]+devices[\s\n]+and[\s\n]+systems,[\s\n]+to[\s\n]+prevent[\s\n]+unauthorized[\s\n]+use[\s\n]+and[\s\n]+violations[\s\n]+of[\s\n]+statutes[\s\n]+and[\s\n]+security[\s\n]+regulations,[\s\n]+to[\s\n]+deter[\s\n]+criminal[\s\n]+activity,[\s\n]+and[\s\n]+for[\s\n]+other[\s\n]+similar[\s\n]+purposes\.[\s\n]+Any[\s\n]+user[\s\n]+of[\s\n]+a[\s\n]+DoD[\s\n]+interest[\s\n]+computer[\s\n]+system[\s\n]+should[\s\n]+be[\s\n]+aware[\s\n]+that[\s\n]+any[\s\n]+information[\s\n]+placed[\s\n]+in[\s\n]+the[\s\n]+system[\s\n]+is[\s\n]+subject[\s\n]+to[\s\n]+monitoring[\s\n]+and[\s\n]+is[\s\n]+not[\s\n]+subject[\s\n]+to[\s\n]+any[\s\n]+expectation[\s\n]+of[\s\n]+privacy\.[\s\n]+If[\s\n]+monitoring[\s\n]+of[\s\n]+this[\s\n]+or[\s\n]+any[\s\n]+other[\s\n]+DoD[\s\n]+interest[\s\n]+computer[\s\n]+system[\s\n]+reveals[\s\n]+possible[\s\n]+evidence[\s\n]+of[\s\n]+violation[\s\n]+of[\s\n]+criminal[\s\n]+statutes,[\s\n]+this[\s\n]+evidence[\s\n]+and[\s\n]+any[\s\n]+other[\s\n]+related[\s\n]+information,[\s\n]+including[\s\n]+identification[\s\n]+information[\s\n]+about[\s\n]+the[\s\n]+user,[\s\n]+may[\s\n]+be[\s\n]+provided[\s\n]+to[\s\n]+law[\s\n]+enforcement[\s\n]+officials\.[\s\n]+If[\s\n]+monitoring[\s\n]+of[\s\n]+this[\s\n]+or[\s\n]+any[\s\n]+other[\s\n]+DoD[\s\n]+interest[\s\n]+computer[\s\n]+systems[\s\n]+reveals[\s\n]+violations[\s\n]+of[\s\n]+security[\s\n]+regulations[\s\n]+or[\s\n]+unauthorized[\s\n]+use,[\s\n]+employees[\s\n]+who[\s\n]+violate[\s\n]+security[\s\n]+regulations[\s\n]+or[\s\n]+make[\s\n]+unauthorized[\s\n]+use[\s\n]+of[\s\n]+DoD[\s\n]+interest[\s\n]+computer[\s\n]+systems[\s\n]+are[\s\n]+subject[\s\n]+to[\s\n]+appropriate[\s\n]+disciplinary[\s\n]+action\.[\s\n]+Use[\s\n]+of[\s\n]+this[\s\n]+or[\s\n]+any[\s\n]+other[\s\n]+DoD[\s\n]+interest[\s\n]+computer[\s\n]+system[\s\n]+constitutes[\s\n]+consent[\s\n]+to[\s\n]+monitoring[\s\n]+at[\s\n]+all[\s\n]+times\.$ - ^\-\-[\s\n]+WARNING[\s\n]+\-\-[\s\n]+This[\s\n]+system[\s\n]+is[\s\n]+for[\s\n]+the[\s\n]+use[\s\n]+of[\s\n]+authorized[\s\n]+users[\s\n]+only\.[\s\n]+Individuals[\s\n]+using[\s\n]+this[\s\n]+computer[\s\n]+system[\s\n]+without[\s\n]+authority[\s\n]+or[\s\n]+in[\s\n]+excess[\s\n]+of[\s\n]+their[\s\n]+authority[\s\n]+are[\s\n]+subject[\s\n]+to[\s\n]+having[\s\n]+all[\s\n]+their[\s\n]+activities[\s\n]+on[\s\n]+this[\s\n]+system[\s\n]+monitored[\s\n]+and[\s\n]+recorded[\s\n]+by[\s\n]+system[\s\n]+personnel\.[\s\n]+Anyone[\s\n]+using[\s\n]+this[\s\n]+system[\s\n]+expressly[\s\n]+consents[\s\n]+to[\s\n]+such[\s\n]+monitoring[\s\n]+and[\s\n]+is[\s\n]+advised[\s\n]+that[\s\n]+if[\s\n]+such[\s\n]+monitoring[\s\n]+reveals[\s\n]+possible[\s\n]+evidence[\s\n]+of[\s\n]+criminal[\s\n]+activity[\s\n]+system[\s\n]+personal[\s\n]+may[\s\n]+provide[\s\n]+the[\s\n]+evidence[\s\n]+of[\s\n]+such[\s\n]+monitoring[\s\n]+to[\s\n]+law[\s\n]+enforcement[\s\n]+officials\.$ - - - - Use Denial-of-Service Protection Modules - Denial-of-service attacks are difficult to detect and prevent while maintaining -acceptable access to authorized users. However, some traffic-shaping -modules can be used to address the problem. Well-known DoS protection modules include: -mod_cband mod_bwshare mod_limitipconn mod_evasive -Denial-of-service prevention should be implemented for a web server if such a threat exists. -However, specific configuration details are very dependent on the environment and often best left -at the discretion of the administrator. - - - - - IMAP and POP3 Server - Dovecot provides IMAP and POP3 services. It is not -installed by default. The project page at - http://www.dovecot.org -contains more detailed information about Dovecot -configuration. - - Configure Dovecot if Necessary - If the system will operate as an IMAP or -POP3 server, the dovecot software should be configured securely by following -the recommendations below. - - Allow IMAP Clients to Access the Server - -The default iptables configuration does not allow inbound access to any services. -This modification will allow remote hosts to initiate connections to the IMAP daemon, -while keeping all other ports on the server in their default protected state. -To configure iptables to allow port 143 traffic, one must edit -/etc/sysconfig/iptables and -/etc/sysconfig/ip6tables (if IPv6 is in use). -Add the following line, ensuring that it appears before the final LOG and DROP lines for the INPUT chain: --A INPUT -m state --state NEW -p tcp --dport 143 -j ACCEPT - - - Enable SSL Support - SSL should be used to encrypt network traffic between the -Dovecot server and its clients. Users must authenticate to the Dovecot -server in order to read their mail, and passwords should never be -transmitted in clear text. In addition, protecting mail as it is -downloaded is a privacy measure, and clients may use SSL certificates -to authenticate the server, preventing another system from impersonating -the server. - - - Support Only the Necessary Protocols - Dovecot supports the IMAP and POP3 protocols, as well as -SSL-protected versions of those protocols. Configure the Dovecot server -to support only the protocols needed by your site. Edit /etc/dovecot/dovecot.conf. -Add or correct the following lines, replacing PROTOCOL with -only the subset of protocols (imap, imaps, -pop3, pop3s) required: -protocols = PROTOCOL -If possible, require SSL protection for all transactions. The SSL -protocol variants listen on alternate ports (995 instead of 110 for -pop3s, and 993 instead of 143 for imaps), and require SSL-aware clients. -An alternate approach is to listen on the standard port and require the -client to use the STARTTLS command before authenticating. - - - - Disable Cyrus IMAP - If the system does not need to operate as an IMAP or -POP3 server, the Cyrus IMAP software should be removed. - - - Disable Dovecot - If the system does not need to operate as an IMAP or -POP3 server, the dovecot software should be disabled and removed. - - - - Kerberos - The Kerberos protocol is used for authentication across -non-secure network. Authentication can happen between -various types of principals -- users, service, or hosts. -Their identity and encryption keys can be stored in keytab -files. - - - - LDAP - LDAP is a popular directory service, that is, a -standardized way of looking up information from a central database. -Oracle Linux 9 includes software that enables a system to act as both -an LDAP client and server. - - Configure OpenLDAP Clients - This section provides information on which security settings are -important to configure in OpenLDAP clients by manually editing the appropriate -configuration files. Oracle Linux 9 provides an automated configuration tool called -authconfig and a graphical wrapper for authconfig called -system-config-authentication. However, these tools do not provide as -much control over configuration as manual editing of configuration files. The -authconfig tools do not allow you to specify locations of SSL certificate -files, which is useful when trying to use SSL cleanly across several protocols. -Installation and configuration of OpenLDAP on Oracle Linux 9 is available at - Before configuring any system to be an -LDAP client, ensure that a working LDAP server is present on the -network. - - - Configure OpenLDAP Server - This section details some security-relevant settings -for an OpenLDAP server. - - Install and Protect LDAP Certificate Files - Create the PKI directory for LDAP certificates if it does not already exist: -$ sudo mkdir /etc/pki/tls/ldap -$ sudo chown root:root /etc/pki/tls/ldap -$ sudo chmod 755 /etc/pki/tls/ldap -Using removable media or some other secure transmission format, install the certificate files -onto the LDAP server: -/etc/pki/tls/ldap/serverkey.pem: the private key ldapserverkey.pem/etc/pki/tls/ldap/servercert.pem: the certificate file ldapservercert.pem -Verify the ownership and permissions of these files: -$ sudo chown root:ldap /etc/pki/tls/ldap/serverkey.pem -$ sudo chown root:ldap /etc/pki/tls/ldap/servercert.pem -$ sudo chmod 640 /etc/pki/tls/ldap/serverkey.pem -$ sudo chmod 640 /etc/pki/tls/ldap/servercert.pem -Verify that the CA's public certificate file has been installed as -/etc/pki/tls/CA/cacert.pem, and has the correct permissions: -$ sudo mkdir /etc/pki/tls/CA -$ sudo chown root:root /etc/pki/tls/CA/cacert.pem -$ sudo chmod 644 /etc/pki/tls/CA/cacert.pem - -As a result of these steps, the LDAP server will have access to its own private -certificate and the key with which that certificate is encrypted, and to the -public certificate file belonging to the CA. Note that it would be possible for -the key to be protected further, so that processes running as ldap could not -read it. If this were done, the LDAP server process would need to be restarted -manually whenever the server rebooted. - - - - - Mail Server Software - Mail servers are used to send and receive email over the network. -Mail is a very common service, and Mail Transfer Agents (MTAs) are obvious -targets of network attack. -Ensure that systems are not running MTAs unnecessarily, -and configure needed MTAs as defensively as possible. - -Very few systems at any site should be configured to directly receive email over the -network. Users should instead use mail client programs to retrieve email -from a central server that supports protocols such as IMAP or POP3. -However, it is normal for most systems to be independently capable of sending email, -for instance so that cron jobs can report output to an administrator. -Most MTAs, including Postfix, support a submission-only mode in which mail can be sent from -the local system to a central site MTA (or directly delivered to a local account), -but the system still cannot receive mail directly over a network. - -The alternatives program in Oracle Linux 9 permits selection of other mail server software -(such as Sendmail), but Postfix is the default and is preferred. -Postfix was coded with security in mind and can also be more effectively contained by -SELinux as its modular design has resulted in separate processes performing specific actions. -More information is available on its website, - http://www.postfix.org. - - - The Postfix package is installed - A mail server is required for sending emails. -The postfix package can be installed with the following command: - -$ sudo yum install postfix - SRG-OS-000046-GPOS-00022 - Emails can be used to notify designated personnel about important -system events such as failures or warnings. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -if ! rpm -q --quiet "postfix" ; then - yum install -y "postfix" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Ensure postfix is installed - package: - name: postfix - state: present - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - enable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - package_postfix_installed - - include install_postfix - -class install_postfix { - package { 'postfix': - ensure => 'installed', - } -} - - -package --add=postfix - - -[[packages]] -name = "postfix" -version = "*" - - - - - - - - - - Uninstall Sendmail Package - Sendmail is not the default mail transfer agent and is -not installed by default. -The sendmail package can be removed with the following command: - -$ sudo yum erase sendmail - BP28(R1) - 11 - 14 - 3 - 9 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS05.02 - DSS05.05 - DSS06.06 - CCI-000381 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 7.6 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.9.1.2 - CM-7(a) - CM-7(b) - CM-6(a) - PR.IP-1 - PR.PT-3 - SRG-OS-000480-GPOS-00227 - SRG-OS-000095-GPOS-00049 - The sendmail software was not developed with security in mind and -its design prevents it from being effectively contained by SELinux. Postfix -should be used instead. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# CAUTION: This remediation script will remove sendmail -# from the system, and may remove any packages -# that depend on sendmail. Execute this -# remediation AFTER testing on a non-production -# system! - -if rpm -q --quiet "sendmail" ; then - - yum remove -y "sendmail" - -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Ensure sendmail is removed - package: - name: sendmail - state: absent - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - package_sendmail_removed - - include remove_sendmail - -class remove_sendmail { - package { 'sendmail': - ensure => 'purged', - } -} - - -package --remove=sendmail - - - - - - - - - - Enable Postfix Service - The Postfix mail transfer agent is used for local mail delivery -within the system. The default configuration only listens for connections to -the default SMTP port (port 25) on the loopback interface (127.0.0.1). It is -recommended to leave this service enabled for local mail delivery. - -The postfix service can be enabled with the following command: -$ sudo systemctl enable postfix.service - Local mail delivery is essential to some system maintenance and -notification tasks. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -SYSTEMCTL_EXEC='/usr/bin/systemctl' -"$SYSTEMCTL_EXEC" unmask 'postfix.service' -"$SYSTEMCTL_EXEC" start 'postfix.service' -"$SYSTEMCTL_EXEC" enable 'postfix.service' - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Enable service postfix - block: - - - name: Gather the package facts - package_facts: - manager: auto - - - name: Enable service postfix - systemd: - name: postfix - enabled: 'yes' - state: started - masked: 'no' - when: - - '"postfix" in ansible_facts.packages' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - enable_strategy - - low_complexity - - low_disruption - - no_reboot_needed - - service_postfix_enabled - - unknown_severity - - include enable_postfix - -class enable_postfix { - service {'postfix': - enable => true, - ensure => 'running', - } -} - - -[customizations.services] -enabled = ["postfix"] - - - - - - - - - - Configure SMTP For Mail Clients - This section discusses settings for Postfix in a submission-only -e-mail configuration. - - Postfix Network Interfaces - The setting for inet_interfaces in /etc/postfix/main.cf - loopback-only - loopback-only - localhost - - - Postfix relayhost - Specify the host all outbound email should be routed into. - smtp.$mydomain - - - Postfix Root Mail Alias - Specify an email address (string) for a root mail alias. - system.administrator@mail.mil - system.administrator@mail.mil - - - Configure System to Forward All Mail For The Root Account - Make sure that mails delivered to root user are forwarded to a monitored -email address. Make sure that the address - is a valid email address -reachable from the system in question. Use the following command to -configure the alias: -$ sudo echo "root: " >> /etc/aliases -$ sudo newaliases - BP28(R49) - CCI-000139 - CCI-000366 - CM-6(a) - SRG-OS-000046-GPOS-00022 - A number of system services utilize email messages sent to the root user to -notify system administrators of active or impending issues. These messages must -be forwarded to at least one monitored email address. - - - - - - - - - - Configure System to Forward All Mail From Postmaster to The Root Account - Verify the administrators are notified in the event of an audit processing failure. -Check that the "/etc/aliases" file has a defined value for "root". -$ sudo grep "postmaster:\s*root$" /etc/aliases - -postmaster: root - CCI-000139 - AU-5(a) - AU-5.1(ii) - SRG-OS-000046-GPOS-00022 - It is critical for the appropriate personnel to be aware if a system is at risk of failing to -process audit logs as required. Without this notification, the security personnel may be -unaware of an impending failure of the audit capability, and system operation may be adversely -affected. - -Audit processing failures include software/hardware errors, failures in the audit capturing -mechanisms, and audit storage capacity being reached or exceeded. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -if [ -e "/etc/aliases" ] ; then - - LC_ALL=C sed -i "/^\s*postmaster\s*:\s*/Id" "/etc/aliases" -else - touch "/etc/aliases" -fi -# make sure file has newline at the end -sed -i -e '$a\' "/etc/aliases" - -cp "/etc/aliases" "/etc/aliases.bak" -# Insert at the end of the file -printf '%s\n' "postmaster: root" >> "/etc/aliases" -# Clean up after ourselves. -rm "/etc/aliases.bak" - -if [ -f /usr/bin/newaliases ]; then - newaliases -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Configure System to Forward All Mail From Postmaster to The Root Account - block: - - - name: Check for duplicate values - lineinfile: - path: /etc/aliases - create: false - regexp: ^\s*postmaster\s*:\s* - state: absent - check_mode: true - changed_when: false - register: dupes - - - name: Deduplicate values from /etc/aliases - lineinfile: - path: /etc/aliases - create: false - regexp: ^\s*postmaster\s*:\s* - state: absent - when: dupes.found is defined and dupes.found > 1 - - - name: Insert correct line to /etc/aliases - lineinfile: - path: /etc/aliases - create: true - regexp: ^\s*postmaster\s*:\s* - line: 'postmaster: root' - state: present - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AU-5(a) - - NIST-800-53-AU-5.1(ii) - - configure_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - postfix_client_configure_mail_alias_postmaster - -- name: Check if newaliases command is available - ansible.builtin.stat: - path: /usr/bin/newaliases - register: result_newaliases_present - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AU-5(a) - - NIST-800-53-AU-5.1(ii) - - configure_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - postfix_client_configure_mail_alias_postmaster - -- name: Update postfix aliases - ansible.builtin.command: - cmd: newaliases - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - result_newaliases_present.stat.exists - tags: - - NIST-800-53-AU-5(a) - - NIST-800-53-AU-5.1(ii) - - configure_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - postfix_client_configure_mail_alias_postmaster - - - - - - - - - - Configure System to Forward All Mail through a specific host - Set up a relay host that will act as a gateway for all outbound email. -Edit the file /etc/postfix/main.cf to ensure that only the following -relayhost line appears: -relayhost = - A central outbound email location ensures messages sent from any network host -can be audited for potential unexpected content. Tooling on the central server -may help prevent spam or viruses from being delivered. - - - - - - - Disable Postfix Network Listening - Edit the file /etc/postfix/main.cf to ensure that only the following -inet_interfaces line appears: -inet_interfaces = - BP28(R48) - 11 - 14 - 3 - 9 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS05.02 - DSS05.05 - DSS06.06 - CCI-000382 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 7.6 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.9.1.2 - CM-7(a) - CM-7(b) - CM-6(a) - PR.IP-1 - PR.PT-3 - 2.2.4 - This ensures postfix accepts mail messages -(such as cron job reports) from the local system only, -and not from the network, which protects it from network attack. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && { rpm --quiet -q postfix; }; then - -var_postfix_inet_interfaces='' - - -if [ -e "/etc/postfix/main.cf" ] ; then - - LC_ALL=C sed -i "/^\s*inet_interfaces\s\+=\s\+/Id" "/etc/postfix/main.cf" -else - touch "/etc/postfix/main.cf" -fi -# make sure file has newline at the end -sed -i -e '$a\' "/etc/postfix/main.cf" - -cp "/etc/postfix/main.cf" "/etc/postfix/main.cf.bak" -# Insert at the end of the file -printf '%s\n' "inet_interfaces=$var_postfix_inet_interfaces" >> "/etc/postfix/main.cf" -# Clean up after ourselves. -rm "/etc/postfix/main.cf.bak" - -systemctl restart postfix - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: XCCDF Value var_postfix_inet_interfaces # promote to variable - set_fact: - var_postfix_inet_interfaces: !!str - tags: - - always - -- name: Gather list of packages - package_facts: - manager: auto - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - '' - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - PCI-DSSv4-2.2.4 - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - postfix_network_listening_disabled - - restrict_strategy - -- name: Make changes to Postfix configuration file - lineinfile: - path: /etc/postfix/main.cf - create: false - regexp: ^inet_interfaces\s*=\s.* - line: inet_interfaces = {{ var_postfix_inet_interfaces }} - state: present - insertafter: ^inet_interfaces\s*=\s.* - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - '"postfix" in ansible_facts.packages' - - '"postfix" in ansible_facts.packages' - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - PCI-DSSv4-2.2.4 - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - postfix_network_listening_disabled - - restrict_strategy - - - - - - - - - - - - Configure Operating System to Protect Mail Server - The guidance in this section is appropriate for any host which is -operating as a site MTA, whether the mail server runs using Sendmail, Postfix, -or some other software. - - - Configure SSL Certificates for Use with SMTP AUTH - If SMTP AUTH is to be used, the use of SSL to protect credentials in transit is strongly recommended. -There are also configurations for which it may be desirable to encrypt all mail in transit from one MTA to another, -though such configurations are beyond the scope of this guide. In either event, the steps for creating and installing -an SSL certificate are independent of the MTA in use, and are described here. - - Ensure Security of Postfix SSL Certificate - Create the PKI directory for mail certificates, if it does not already exist: -$ sudo mkdir /etc/pki/tls/mail -$ sudo chown root:root /etc/pki/tls/mail -$ sudo chmod 755 /etc/pki/tls/mail -Using removable media or some other secure transmission format, install the files generated in the previous -step onto the mail server: -/etc/pki/tls/mail/serverkey.pem: the private key mailserverkey.pem -/etc/pki/tls/mail/servercert.pem: the certificate file mailservercert.pem -Verify the ownership and permissions of these files: -$ sudo chown root:root /etc/pki/tls/mail/serverkey.pem -$ sudo chown root:root /etc/pki/tls/mail/servercert.pem -$ sudo chmod 600 /etc/pki/tls/mail/serverkey.pem -$ sudo chmod 644 /etc/pki/tls/mail/servercert.pem -Verify that the CA's public certificate file has been installed as /etc/pki/tls/CA/cacert.pem, and has the -correct permissions: -$ sudo chown root:root /etc/pki/tls/CA/cacert.pem -$ sudo chmod 644 /etc/pki/tls/CA/cacert.pem - - - - Configure Postfix if Necessary - Postfix stores its configuration files in the directory -/etc/postfix by default. The primary configuration file is -/etc/postfix/main.cf. - - Configure Postfix Resource Usage to Limit Denial of Service Attacks - Edit /etc/postfix/main.cf. Edit the following lines to -configure the amount of system resources Postfix can consume: -default_process_limit = 100 -smtpd_client_connection_count_limit = 10 -smtpd_client_connection_rate_limit = 30 -queue_minfree = 20971520 -header_size_limit = 51200 -message_size_limit = 10485760 -smtpd_recipient_limit = 100 -The values here are examples. - Note: The values given here are examples, and may -need to be modified for any particular site. By default, the Postfix anvil -process gathers mail receipt statistics. To get information about about what -connection rates are typical at your site, look in /var/log/maillog -for lines with the daemon name postfix/anvil. - - - Control Mail Relaying - Postfix's mail relay controls are implemented with the help of the -smtpd recipient restrictions option, which controls the restrictions placed on -the SMTP dialogue once the sender and recipient envelope addresses are known. -The guidance in the following sections should be applied to all systems. If -there are systems which must be allowed to relay mail, but which cannot be -trusted to relay unconditionally, configure SMTP AUTH with SSL support. - - Prevent Unrestricted Mail Relaying - Modify the /etc/postfix/main.cf file to restrict client connections -to the local network with the following command: -$ sudo postconf -e 'smtpd_client_restrictions = permit_mynetworks,reject' - CCI-000366 - SRG-OS-000480-GPOS-00227 - If unrestricted mail relaying is permitted, unauthorized senders could use this -host as a mail relay for the purpose of sending spam or other unauthorized -activity. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q postfix; then - -if ! grep -q ^smtpd_client_restrictions /etc/postfix/main.cf; then - echo "smtpd_client_restrictions = permit_mynetworks,reject" >> /etc/postfix/main.cf -else - sed -i "s/^smtpd_client_restrictions.*/smtpd_client_restrictions = permit_mynetworks,reject/g" /etc/postfix/main.cf -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Gather the package facts - package_facts: - manager: auto - tags: - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - postfix_prevent_unrestricted_relay - - restrict_strategy - -- name: Prevent Unrestricted Mail Relaying - block: - - - name: Check for duplicate values - lineinfile: - path: /etc/postfix/main.cf - create: false - regexp: ^[ \t]*smtpd_client_restrictions\s*=\s* - state: absent - check_mode: true - changed_when: false - register: dupes - - - name: Deduplicate values from /etc/postfix/main.cf - lineinfile: - path: /etc/postfix/main.cf - create: false - regexp: ^[ \t]*smtpd_client_restrictions\s*=\s* - state: absent - when: dupes.found is defined and dupes.found > 1 - - - name: Insert correct line to /etc/postfix/main.cf - lineinfile: - path: /etc/postfix/main.cf - create: true - regexp: ^[ \t]*smtpd_client_restrictions\s*=\s* - line: smtpd_client_restrictions = permit_mynetworks,reject - state: present - when: - - '"postfix" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - postfix_prevent_unrestricted_relay - - restrict_strategy - - - - - - - - - - Enact SMTP Recipient Restrictions - To configure Postfix to restrict addresses to which it -will send mail, see: - - http://www.postfix.org/SMTPD_ACCESS_README.html#danger - -The full contents of smtpd_recipient_restrictions will -vary by site, since this is a common place to put spam restrictions and other -site-specific options. The permit_mynetworks option allows all mail to -be relayed from the systems in mynetworks. Then, the -reject_unauth_destination option denies all mail whose destination -address is not local, preventing any other systems from relaying. These two -options should always appear in this order, and should usually follow one -another immediately unless SMTP AUTH is used. - - - Enact SMTP Relay Restrictions - To configure Postfix to restrict addresses to which it -will send mail, see: - - http://www.postfix.org/SMTPD_ACCESS_README.html#danger - -The full contents of smtpd_recipient_restrictions will -vary by site, since this is a common place to put spam restrictions and other -site-specific options. The permit_mynetworks option allows all mail to -be relayed from the systems in mynetworks. Then, the -reject_unauth_destination option denies all mail whose destination -address is not local, preventing any other systems from relaying. These two -options should always appear in this order, and should usually follow one -another immediately unless SMTP AUTH is used. - - - Use TLS for SMTP AUTH - Postfix provides options to use TLS for certificate-based -authentication and encrypted sessions. An encrypted session protects the -information that is transmitted with SMTP mail or with SASL authentication. -To configure Postfix to protect all SMTP AUTH transactions -using TLS, see - http://www.postfix.org/TLS_README.html. - - - Configure Trusted Networks and Hosts - Edit /etc/postfix/main.cf, and configure the contents of -the mynetworks variable in one of the following ways: -If any system in the subnet containing the MTA may be trusted to relay -messages, add or correct the following line: -mynetworks_style = subnet -This is also the default setting, and is in effect if all -my_networks_style directives are commented.If only the MTA host itself is trusted to relay messages, add or correct -the following line: -mynetworks_style = hostIf the set of systems which can relay is more complicated, manually -specify an entry for each netblock or IP address which is trusted to relay by -setting the mynetworks variable directly: -mynetworks = 10.0.0.0/16, 192.168.1.0/24, 127.0.0.1 - - - Require SMTP AUTH Before Relaying from Untrusted Clients - SMTP authentication allows remote clients to relay mail safely by -requiring them to authenticate before submitting mail. Postfix's SMTP AUTH uses -an authentication library called SASL, which is not part of Postfix itself. To -enable the use of SASL authentication, see - - http://www.postfix.org/SASL_README.html - - - - - - - NFS and RPC - The Network File System is a popular distributed filesystem for -the Unix environment, and is very widely deployed. This section discusses the -circumstances under which it is possible to disable NFS and its dependencies, -and then details steps which should be taken to secure -NFS's configuration. This section is relevant to systems operating as NFS -clients, as well as to those operating as NFS servers. - - Uninstall nfs-utils Package - The nfs-utils package can be removed with the following command: - -$ sudo yum erase nfs-utils - 2.2.4 - SRG-OS-000095-GPOS-00049 - nfs-utils provides a daemon for the kernel NFS server and related tools. This -package also contains the showmount program. showmount queries the mount -daemon on a remote host for information about the Network File System (NFS) server on the -remote host. For example, showmount can display the clients which are mounted on -that host. - -# CAUTION: This remediation script will remove nfs-utils -# from the system, and may remove any packages -# that depend on nfs-utils. Execute this -# remediation AFTER testing on a non-production -# system! - -if rpm -q --quiet "nfs-utils" ; then - - yum remove -y "nfs-utils" - -fi - - - name: Ensure nfs-utils is removed - package: - name: nfs-utils - state: absent - tags: - - PCI-DSSv4-2.2.4 - - disable_strategy - - low_complexity - - low_disruption - - low_severity - - no_reboot_needed - - package_nfs-utils_removed - - include remove_nfs-utils - -class remove_nfs-utils { - package { 'nfs-utils': - ensure => 'purged', - } -} - - -package --remove=nfs-utils - - - - - - - - - - Disable All NFS Services if Possible - If there is not a reason for the system to operate as either an -NFS client or an NFS server, follow all instructions in this section to disable -subsystems required by NFS. - The steps in this section will prevent a system -from operating as either an NFS client or an NFS server. Only perform these -steps on systems which do not need NFS at all. - - - Disable netfs if Possible - To determine if any network filesystems handled by netfs are -currently mounted on the system execute the following command: -$ mount -t nfs,nfs4,smbfs,cifs,ncpfs -If the command did not return any output then disable netfs. - - Disable Network File Systems (netfs) - The netfs script manages the boot-time mounting of several types -of networked filesystems, of which NFS and Samba are the most common. If these -filesystem types are not in use, the script can be disabled, protecting the -system somewhat against accidental or malicious changes to /etc/fstab -and against flaws in the netfs script itself. - -The netfs service can be disabled with the following command: -$ sudo systemctl mask --now netfs.service - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -SYSTEMCTL_EXEC='/usr/bin/systemctl' -"$SYSTEMCTL_EXEC" stop 'netfs.service' -"$SYSTEMCTL_EXEC" disable 'netfs.service' -"$SYSTEMCTL_EXEC" mask 'netfs.service' -# Disable socket activation if we have a unit file for it -if "$SYSTEMCTL_EXEC" -q list-unit-files netfs.socket; then - "$SYSTEMCTL_EXEC" stop 'netfs.socket' - "$SYSTEMCTL_EXEC" mask 'netfs.socket' -fi -# The service may not be running because it has been started and failed, -# so let's reset the state so OVAL checks pass. -# Service should be 'inactive', not 'failed' after reboot though. -"$SYSTEMCTL_EXEC" reset-failed 'netfs.service' || true - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Block Disable service netfs - block: - - - name: Disable service netfs - block: - - - name: Disable service netfs - systemd: - name: netfs.service - enabled: 'no' - state: stopped - masked: 'yes' - rescue: - - - name: Intentionally ignored previous 'Disable service netfs' failure, service - was already disabled - meta: noop - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - low_disruption - - no_reboot_needed - - service_netfs_disabled - - unknown_severity - -- name: Unit Socket Exists - netfs.socket - command: systemctl -q list-unit-files netfs.socket - register: socket_file_exists - changed_when: false - failed_when: socket_file_exists.rc not in [0, 1] - check_mode: false - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - low_disruption - - no_reboot_needed - - service_netfs_disabled - - unknown_severity - -- name: Disable socket netfs - systemd: - name: netfs.socket - enabled: 'no' - state: stopped - masked: 'yes' - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - socket_file_exists.stdout_lines is search("netfs.socket",multiline=True) - tags: - - disable_strategy - - low_complexity - - low_disruption - - no_reboot_needed - - service_netfs_disabled - - unknown_severity - - include disable_netfs - -class disable_netfs { - service {'netfs': - enable => false, - ensure => 'stopped', - } -} - - -[customizations.services] -disabled = ["netfs"] - - - - - - - - Disable Services Used Only by NFS - If NFS is not needed, disable the NFS client daemons nfslock, rpcgssd, and rpcidmapd. - -All of these daemons run with elevated privileges, and many listen for network -connections. If they are not needed, they should be disabled to improve system -security posture. - - - - - Configure All Systems which Use NFS - The steps in this section are appropriate for all systems which -run NFS, whether they operate as clients or as servers. - - Make Each System a Client or a Server, not Both - If NFS must be used, it should be deployed in the simplest -configuration possible to avoid maintainability problems which may lead to -unnecessary security exposure. Due to the reliability and security problems -caused by NFS (specially NFSv3 and NFSv2), it is not a good idea for systems -which act as NFS servers to also mount filesystems via NFS. At the least, -crossed mounts (the situation in which each of two servers mounts a filesystem -from the other) should never be used. - - - Configure NFS Services to Use Fixed Ports (NFSv3 and NFSv2) - Firewalling should be done at each host and at the border -firewalls to protect the NFS daemons from remote access, since NFS servers -should never be accessible from outside the organization. However, by default -for NFSv3 and NFSv2, the RPC Bind service assigns each NFS service to a port -dynamically at service startup time. Dynamic ports cannot be protected by port - -filtering firewalls such as iptables. - - -Therefore, restrict each service to always use a given port, so that -firewalling can be done effectively. Note that, because of the way RPC is -implemented, it is not possible to disable the RPC Bind service even if ports -are assigned statically to all RPC services. - -In NFSv4, the mounting and locking protocols have been incorporated into the -protocol, and the server listens on the the well-known TCP port 2049. As such, -NFSv4 does not need to interact with the rpcbind, lockd, and rpc.statd -daemons, which can and should be disabled in a pure NFSv4 environment. The -rpc.mountd daemon is still required on the NFS server to setup -exports, but is not involved in any over-the-wire operations. - - - - Configure NFS Clients - The steps in this section are appropriate for systems which operate as NFS clients. - - Disable NFS Server Daemons - There is no need to run the NFS server daemons nfs and -rpcsvcgssd except on a small number of properly secured systems -designated as NFS servers. Ensure that these daemons are turned off on -clients. - - - Mount Remote Filesystems with Restrictive Options - Edit the file /etc/fstab. For each filesystem whose type -(column 3) is nfs or nfs4, add the text -,nodev,nosuid to the list of mount options in column 4. If -appropriate, also add ,noexec. - -See the section titled "Restrict Partition Mount Options" for a description of -the effects of these options. In general, execution of files mounted via NFS -should be considered risky because of the possibility that an adversary could -intercept the request and substitute a malicious file. Allowing setuid files to -be executed from remote servers is particularly risky, both for this reason and -because it requires the clients to extend root-level trust to the NFS -server. - - - Mount Remote Filesystems with Kerberos Security - Add the sec=krb5:krb5i:krb5p option to the fourth column of /etc/fstab for the line which controls mounting of -any NFS mounts. - 1 - 12 - 14 - 15 - 16 - 18 - 3 - 5 - DSS05.04 - DSS05.10 - DSS06.10 - CCI-000366 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.3 - SR 1.1 - SR 1.10 - SR 1.2 - SR 1.5 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - A.18.1.4 - A.6.1.2 - A.9.1.2 - A.9.2.1 - A.9.2.3 - A.9.2.4 - A.9.3.1 - A.9.4.1 - A.9.4.2 - A.9.4.3 - A.9.4.4 - A.9.4.5 - CM-7(a) - CM-7(b) - CM-6(a) - IA-2 - IA-2(8) - IA-2(9) - AC-17(a) - PR.AC-4 - PR.AC-7 - SRG-OS-000480-GPOS-00227 - When an NFS server is configured to use AUTH_SYS a selected userid and groupid are used to handle -requests from the remote user. The userid and groupid could mistakenly or maliciously be set -incorrectly. The AUTH_GSS method of authentication uses certificates on the server and client -systems to more securely authenticate the remote mount request. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -vfstype_points=() -readarray -t vfstype_points < <(grep -E "[[:space:]]nfs[4]?[[:space:]]" /etc/fstab | awk '{print $2}') - -for vfstype_point in "${vfstype_points[@]}" -do - mount_point_match_regexp="$(printf "[^#].*[[:space:]]%s[[:space:]]" ${vfstype_point//\\/\\\\})" - - # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab - if ! grep "$mount_point_match_regexp" /etc/fstab; then - # runtime opts without some automatic kernel/userspace-added defaults - previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 | awk '{print $4}' \ - | sed -E "s/(rw|defaults|seclabel|sec=krb5:krb5i:krb5p)(,|$)//g;s/,$//") - [ "$previous_mount_opts" ] && previous_mount_opts+="," - # In iso9660 filesystems mtab could describe a "blocksize" value, this should be reflected in - # fstab as "block". The next variable is to satisfy shellcheck SC2050. - fs_type="nfs4" - if [ "$fs_type" == "iso9660" ] ; then - previous_mount_opts=$(sed 's/blocksize=/block=/' <<< "$previous_mount_opts") - fi - echo " ${vfstype_point//\\/\\\\} nfs4 defaults,${previous_mount_opts}sec=krb5:krb5i:krb5p 0 0" >> /etc/fstab - # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it - elif ! grep "$mount_point_match_regexp" /etc/fstab | grep "sec=krb5:krb5i:krb5p"; then - previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}') - sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,sec=krb5:krb5i:krb5p|" /etc/fstab - fi -done - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Get nfs and nfs4 mount points, that don't have sec=krb5:krb5i:krb5p - command: findmnt --fstab --types nfs,nfs4 -O nosec=krb5:krb5i:krb5p -n -P - register: points_register - check_mode: false - changed_when: false - failed_when: false - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-17(a) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-IA-2 - - NIST-800-53-IA-2(8) - - NIST-800-53-IA-2(9) - - configure_strategy - - low_complexity - - medium_disruption - - medium_severity - - mount_option_krb_sec_remote_filesystems - - no_reboot_needed - -- name: Add sec=krb5:krb5i:krb5p to nfs and nfs4 mount points - mount: - path: '{{ item | regex_search(''TARGET="([^"]+)"'',''\1'') | first }}' - src: '{{ item | regex_search(''SOURCE="([^"]+)"'',''\1'') | first }}' - fstype: '{{ item | regex_search(''FSTYPE="([^"]+)"'',''\1'') | first }}' - state: present - opts: '{{ item | regex_search(''OPTIONS="([^"]+)"'',''\1'') | first }},sec=krb5:krb5i:krb5p' - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - (points_register.stdout | length > 0) and '\\x09' not in item - with_items: '{{ points_register.stdout_lines }}' - tags: - - NIST-800-53-AC-17(a) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-IA-2 - - NIST-800-53-IA-2(8) - - NIST-800-53-IA-2(9) - - configure_strategy - - low_complexity - - medium_disruption - - medium_severity - - mount_option_krb_sec_remote_filesystems - - no_reboot_needed - - - - - - - - - - Mount Remote Filesystems with nodev - Add the nodev option to the fourth column of /etc/fstab for the line which controls mounting of -any NFS mounts. - 11 - 13 - 14 - 3 - 8 - 9 - APO13.01 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS05.02 - DSS05.05 - DSS05.06 - DSS06.06 - CCI-000366 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 7.6 - A.11.2.9 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.8.2.1 - A.8.2.2 - A.8.2.3 - A.8.3.1 - A.8.3.3 - A.9.1.2 - CM-6(a) - MP-2 - PR.IP-1 - PR.PT-2 - PR.PT-3 - SRG-OS-000480-GPOS-00227 - Legitimate device files should only exist in the /dev directory. NFS mounts -should not present device files to users. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -vfstype_points=() -readarray -t vfstype_points < <(grep -E "[[:space:]]nfs[4]?[[:space:]]" /etc/fstab | awk '{print $2}') - -for vfstype_point in "${vfstype_points[@]}" -do - mount_point_match_regexp="$(printf "[^#].*[[:space:]]%s[[:space:]]" ${vfstype_point//\\/\\\\})" - - # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab - if ! grep "$mount_point_match_regexp" /etc/fstab; then - # runtime opts without some automatic kernel/userspace-added defaults - previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 | awk '{print $4}' \ - | sed -E "s/(rw|defaults|seclabel|nodev)(,|$)//g;s/,$//") - [ "$previous_mount_opts" ] && previous_mount_opts+="," - # In iso9660 filesystems mtab could describe a "blocksize" value, this should be reflected in - # fstab as "block". The next variable is to satisfy shellcheck SC2050. - fs_type="nfs4" - if [ "$fs_type" == "iso9660" ] ; then - previous_mount_opts=$(sed 's/blocksize=/block=/' <<< "$previous_mount_opts") - fi - echo " ${vfstype_point//\\/\\\\} nfs4 defaults,${previous_mount_opts}nodev 0 0" >> /etc/fstab - # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it - elif ! grep "$mount_point_match_regexp" /etc/fstab | grep "nodev"; then - previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}') - sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,nodev|" /etc/fstab - fi -done - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Get nfs and nfs4 mount points, that don't have nodev - command: findmnt --fstab --types nfs,nfs4 -O nonodev -n -P - register: points_register - check_mode: false - changed_when: false - failed_when: false - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-MP-2 - - configure_strategy - - low_complexity - - medium_disruption - - medium_severity - - mount_option_nodev_remote_filesystems - - no_reboot_needed - -- name: Add nodev to nfs and nfs4 mount points - mount: - path: '{{ item | regex_search(''TARGET="([^"]+)"'',''\1'') | first }}' - src: '{{ item | regex_search(''SOURCE="([^"]+)"'',''\1'') | first }}' - fstype: '{{ item | regex_search(''FSTYPE="([^"]+)"'',''\1'') | first }}' - state: present - opts: '{{ item | regex_search(''OPTIONS="([^"]+)"'',''\1'') | first }},nodev' - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - (points_register.stdout | length > 0) and '\\x09' not in item - with_items: '{{ points_register.stdout_lines }}' - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-MP-2 - - configure_strategy - - low_complexity - - medium_disruption - - medium_severity - - mount_option_nodev_remote_filesystems - - no_reboot_needed - - - - - - - - - - Mount Remote Filesystems with noexec - Add the noexec option to the fourth column of /etc/fstab for the line which controls mounting of -any NFS mounts. - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - APO01.06 - DSS05.04 - DSS05.07 - DSS06.02 - CCI-000366 - 4.3.3.7.3 - SR 2.1 - SR 5.2 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - AC-6 - AC-6(8) - AC-6(10) - CM-6(a) - PR.AC-4 - PR.DS-5 - SRG-OS-000480-GPOS-00227 - The noexec mount option causes the system not to execute binary files. This option must be used -for mounting any file system not containing approved binary files as they may be incompatible. Executing -files from untrusted file systems increases the opportunity for unprivileged users to attain unauthorized -administrative access. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -vfstype_points=() -readarray -t vfstype_points < <(grep -E "[[:space:]]nfs[4]?[[:space:]]" /etc/fstab | awk '{print $2}') - -for vfstype_point in "${vfstype_points[@]}" -do - mount_point_match_regexp="$(printf "[^#].*[[:space:]]%s[[:space:]]" ${vfstype_point//\\/\\\\})" - - # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab - if ! grep "$mount_point_match_regexp" /etc/fstab; then - # runtime opts without some automatic kernel/userspace-added defaults - previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 | awk '{print $4}' \ - | sed -E "s/(rw|defaults|seclabel|noexec)(,|$)//g;s/,$//") - [ "$previous_mount_opts" ] && previous_mount_opts+="," - # In iso9660 filesystems mtab could describe a "blocksize" value, this should be reflected in - # fstab as "block". The next variable is to satisfy shellcheck SC2050. - fs_type="nfs4" - if [ "$fs_type" == "iso9660" ] ; then - previous_mount_opts=$(sed 's/blocksize=/block=/' <<< "$previous_mount_opts") - fi - echo " ${vfstype_point//\\/\\\\} nfs4 defaults,${previous_mount_opts}noexec 0 0" >> /etc/fstab - # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it - elif ! grep "$mount_point_match_regexp" /etc/fstab | grep "noexec"; then - previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}') - sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,noexec|" /etc/fstab - fi -done - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Get nfs and nfs4 mount points, that don't have noexec - command: findmnt --fstab --types nfs,nfs4 -O nonoexec -n -P - register: points_register - check_mode: false - changed_when: false - failed_when: false - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(10) - - NIST-800-53-AC-6(8) - - NIST-800-53-CM-6(a) - - configure_strategy - - low_complexity - - medium_disruption - - medium_severity - - mount_option_noexec_remote_filesystems - - no_reboot_needed - -- name: Add noexec to nfs and nfs4 mount points - mount: - path: '{{ item | regex_search(''TARGET="([^"]+)"'',''\1'') | first }}' - src: '{{ item | regex_search(''SOURCE="([^"]+)"'',''\1'') | first }}' - fstype: '{{ item | regex_search(''FSTYPE="([^"]+)"'',''\1'') | first }}' - state: present - opts: '{{ item | regex_search(''OPTIONS="([^"]+)"'',''\1'') | first }},noexec' - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - (points_register.stdout | length > 0) and '\\x09' not in item - with_items: '{{ points_register.stdout_lines }}' - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(10) - - NIST-800-53-AC-6(8) - - NIST-800-53-CM-6(a) - - configure_strategy - - low_complexity - - medium_disruption - - medium_severity - - mount_option_noexec_remote_filesystems - - no_reboot_needed - - - - - - - - - - Mount Remote Filesystems with nosuid - Add the nosuid option to the fourth column of /etc/fstab for the line which controls mounting of -any NFS mounts. - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - APO01.06 - DSS05.04 - DSS05.07 - DSS06.02 - CCI-000366 - 4.3.3.7.3 - SR 2.1 - SR 5.2 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - AC-6 - AC-6(1) - CM6(a) - PR.AC-4 - PR.DS-5 - SRG-OS-000480-GPOS-00227 - NFS mounts should not present suid binaries to users. Only vendor-supplied suid executables -should be installed to their default location on the local filesystem. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -vfstype_points=() -readarray -t vfstype_points < <(grep -E "[[:space:]]nfs[4]?[[:space:]]" /etc/fstab | awk '{print $2}') - -for vfstype_point in "${vfstype_points[@]}" -do - mount_point_match_regexp="$(printf "[^#].*[[:space:]]%s[[:space:]]" ${vfstype_point//\\/\\\\})" - - # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab - if ! grep "$mount_point_match_regexp" /etc/fstab; then - # runtime opts without some automatic kernel/userspace-added defaults - previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 | awk '{print $4}' \ - | sed -E "s/(rw|defaults|seclabel|nosuid)(,|$)//g;s/,$//") - [ "$previous_mount_opts" ] && previous_mount_opts+="," - # In iso9660 filesystems mtab could describe a "blocksize" value, this should be reflected in - # fstab as "block". The next variable is to satisfy shellcheck SC2050. - fs_type="nfs4" - if [ "$fs_type" == "iso9660" ] ; then - previous_mount_opts=$(sed 's/blocksize=/block=/' <<< "$previous_mount_opts") - fi - echo " ${vfstype_point//\\/\\\\} nfs4 defaults,${previous_mount_opts}nosuid 0 0" >> /etc/fstab - # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it - elif ! grep "$mount_point_match_regexp" /etc/fstab | grep "nosuid"; then - previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}') - sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,nosuid|" /etc/fstab - fi -done - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Get nfs and nfs4 mount points, that don't have nosuid - command: findmnt --fstab --types nfs,nfs4 -O nonosuid -n -P - register: points_register - check_mode: false - changed_when: false - failed_when: false - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM6(a) - - configure_strategy - - low_complexity - - medium_disruption - - medium_severity - - mount_option_nosuid_remote_filesystems - - no_reboot_needed - -- name: Add nosuid to nfs and nfs4 mount points - mount: - path: '{{ item | regex_search(''TARGET="([^"]+)"'',''\1'') | first }}' - src: '{{ item | regex_search(''SOURCE="([^"]+)"'',''\1'') | first }}' - fstype: '{{ item | regex_search(''FSTYPE="([^"]+)"'',''\1'') | first }}' - state: present - opts: '{{ item | regex_search(''OPTIONS="([^"]+)"'',''\1'') | first }},nosuid' - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - (points_register.stdout | length > 0) and '\\x09' not in item - with_items: '{{ points_register.stdout_lines }}' - tags: - - NIST-800-53-AC-6 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM6(a) - - configure_strategy - - low_complexity - - medium_disruption - - medium_severity - - mount_option_nosuid_remote_filesystems - - no_reboot_needed - - - - - - - - - - - - Configure NFS Servers - The steps in this section are appropriate for systems which operate as NFS servers. - - Ensure All-Squashing Disabled On All Exports - The all_squash maps all uids and gids to an anonymous user. -This should be disabled by removing any instances of the -all_squash option from the file /etc/exports. - The all_squash option maps all client requests to a single anonymous -uid/gid on the NFS server, negating the ability to track file access -by user ID. - - - - - - Use Kerberos Security on All Exports - Using Kerberos on all exported mounts prevents a malicious client or user from -impersonating a system user. To cryptography authenticate users to the NFS server, -add sec=krb5:krb5i:krb5p to each export in /etc/exports. - 1 - 12 - 14 - 15 - 16 - 18 - 3 - 5 - DSS05.04 - DSS05.10 - DSS06.10 - CCI-000366 - 164.308(a)(4)(i) - 164.308(b)(1) - 164.308(b)(3) - 164.310(b) - 164.312(e)(1) - 164.312(e)(2)(ii) - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.3 - SR 1.1 - SR 1.10 - SR 1.2 - SR 1.5 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - A.18.1.4 - A.6.1.2 - A.9.1.2 - A.9.2.1 - A.9.2.3 - A.9.2.4 - A.9.3.1 - A.9.4.1 - A.9.4.2 - A.9.4.3 - A.9.4.4 - A.9.4.5 - CM-7(a) - CM-7(b) - CM-6(a) - IA-2 - IA-2(8) - IA-2(9) - AC-17(a) - PR.AC-4 - PR.AC-7 - SRG-OS-000480-GPOS-00227 - When an NFS server is configured to use AUTH_SYS a selected userid and groupid are used to handle -requests from the remote user. The userid and groupid could mistakenly or maliciously be set -incorrectly. The AUTH_GSS method of authentication uses certificates on the server and client -systems to more securely authenticate the remote mount request. - -nfs_exports=() -readarray -t nfs_exports < <(grep -E "^/.*[[:space:]]+ .*\(.*\)[[:space:]]*$" /etc/exports | awk '{print $2}') - -for nfs_export in "${nfs_exports[@]}" -do - correct_export="" - if [ "$(grep -c "sec=" <<<"$nfs_export")" -eq 0 ]; then - correct_export="$(echo $nfs_export|sed -e 's/).*$/,sec=krb5\:krb5i\:krb5p)/')" - else - correct_export="$(echo $nfs_export|sed -e 's/sec=[^\,\)]*/sec=krb5\:krb5i\:krb5p/')" - fi - sed -i "s|$nfs_export|$correct_export|g" /etc/exports -done - - - name: Drop any security clause for every export - replace: - path: /etc/exports - regexp: ^(/.*\w+.*\(.*),sec=[^,]*(.*\)\w*$) - replace: \1\2 - tags: - - NIST-800-53-AC-17(a) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-IA-2 - - NIST-800-53-IA-2(8) - - NIST-800-53-IA-2(9) - - configure_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - use_kerberos_security_all_exports - -- name: Add kerberos security when no security is defined for an export - replace: - path: /etc/exports - regexp: ^(/.*\w+.*\(.*)(\)\w*$) - replace: \1,sec=krb5:krb5i:krb5p\2 - tags: - - NIST-800-53-AC-17(a) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-IA-2 - - NIST-800-53-IA-2(8) - - NIST-800-53-IA-2(9) - - configure_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - use_kerberos_security_all_exports - - - - - - - - - - Configure the Exports File Restrictively - Linux's NFS implementation uses the file /etc/exports to control what filesystems -and directories may be accessed via NFS. (See the exports(5) manpage for more information about the -format of this file.) - -The syntax of the exports file is not necessarily checked fully on reload, and syntax errors -can leave your NFS configuration more open than intended. Therefore, exercise caution when modifying -the file. - -The syntax of each line in /etc/exports is: -/DIR host1(opt1,opt2) host2(opt3) -where /DIR is a directory or filesystem to export, hostN is an IP address, netblock, -hostname, domain, or netgroup to which to export, and optN is an option. - - - Export Filesystems Read-Only if Possible - If a filesystem is being exported so that users can view the files in a convenient -fashion, but there is no need for users to edit those files, exporting the filesystem read-only -removes an attack vector against the server. The default filesystem export mode is ro, -so do not specify rw without a good reason. - - - Use Access Lists to Enforce Authorization Restrictions - When configuring NFS exports, ensure that each export line in /etc/exports contains -a list of hosts which are allowed to access that export. If no hosts are specified on an export line, -then that export is available to any remote host which requests it. All lines of the exports file should -specify the hosts (or subnets, if needed) which are allowed to access the exported directory, so that -unknown or remote hosts will be denied. - -Authorized hosts can be specified in several different formats: -Name or alias that is recognized by the resolverFully qualified domain nameIP addressIP subnets in the format address/netmask or address/CIDR - - - - - Network Time Protocol - The Network Time Protocol is used to manage the system -clock over a network. Computer clocks are not very accurate, so -time will drift unpredictably on unmanaged systems. Central time -protocols can be used both to ensure that time is consistent among -a network of systems, and that their time is consistent with the -outside world. - -If every system on a network reliably reports the same time, then it is much -easier to correlate log messages in case of an attack. In addition, a number of -cryptographic protocols (such as Kerberos) use timestamps to prevent certain -types of attacks. If your network does not have synchronized time, these -protocols may be unreliable or even unusable. - -Depending on the specifics of the network, global time accuracy may be just as -important as local synchronization, or not very important at all. If your -network is connected to the Internet, using a public timeserver (or one -provided by your enterprise) provides globally accurate timestamps which may be -essential in investigating or responding to an attack which originated outside -of your network. - -A typical network setup involves a small number of internal systems operating -as NTP servers, and the remainder obtaining time information from those -internal servers. - -There is a choice between the daemons ntpd and chronyd, which -are available from the repositories in the ntp and chrony -packages respectively. - -The default chronyd daemon can work well when external time references -are only intermittently accesible, can perform well even when the network is -congested for longer periods of time, can usually synchronize the clock faster -and with better time accuracy, and quickly adapts to sudden changes in the rate -of the clock, for example, due to changes in the temperature of the crystal -oscillator. Chronyd should be considered for all systems which are -frequently suspended or otherwise intermittently disconnected and reconnected -to a network. Mobile and virtual systems for example. - -The ntpd NTP daemon fully supports NTP protocol version 4 (RFC 5905), -including broadcast, multicast, manycast clients and servers, and the orphan -mode. It also supports extra authentication schemes based on public-key -cryptography (RFC 5906). The NTP daemon (ntpd) should be considered -for systems which are normally kept permanently on. Systems which are required -to use broadcast or multicast IP, or to perform authentication of packets with -the Autokey protocol, should consider using ntpd. - -Refer to - - - https://docs.oracle.com/en/operating-systems/oracle-linux/9/network/network-ConfiguringNetworkTime.html#ol-nettime - -for more detailed comparison of features of chronyd -and ntpd daemon features respectively, and for further guidance how to -choose between the two NTP daemons. - -The upstream manual pages at - https://chrony-project.org/documentation.html for -chronyd and - http://www.ntp.org for ntpd provide additional -information on the capabilities and configuration of each of the NTP daemons. - - - Vendor Approved Time pools - The list of vendor-approved pool servers - 0.pool.ntp.org,1.pool.ntp.org,2.pool.ntp.org,3.pool.ntp.org - 0.fedora.pool.ntp.org,1.fedora.pool.ntp.org,2.fedora.pool.ntp.org,3.fedora.pool.ntp.org - 0.rhel.pool.ntp.org,1.rhel.pool.ntp.org,2.rhel.pool.ntp.org,3.rhel.pool.ntp.org - 0.pool.ntp.org,1.pool.ntp.org,2.pool.ntp.org,3.pool.ntp.org - 0.suse.pool.ntp.org,1.suse.pool.ntp.org,2.suse.pool.ntp.org,3.suse.pool.ntp.org - 0.ntp.cloud.aliyuncs.com,1.ntp.aliyun.com,2.ntp1.aliyun.com,3.ntp1.cloud.aliyuncs.com - - - Vendor Approved Time Servers - The list of vendor-approved time servers - 0.pool.ntp.org,1.pool.ntp.org,2.pool.ntp.org,3.pool.ntp.org - 0.fedora.pool.ntp.org,1.fedora.pool.ntp.org,2.fedora.pool.ntp.org,3.fedora.pool.ntp.org - 0.rhel.pool.ntp.org,1.rhel.pool.ntp.org,2.rhel.pool.ntp.org,3.rhel.pool.ntp.org - 0.pool.ntp.org,1.pool.ntp.org,2.pool.ntp.org,3.pool.ntp.org - 0.suse.pool.ntp.org,1.suse.pool.ntp.org,2.suse.pool.ntp.org,3.suse.pool.ntp.org - 0.ntp.cloud.aliyuncs.com,1.ntp.aliyun.com,2.ntp1.aliyun.com,3.ntp1.cloud.aliyuncs.com - - - Maximum NTP or Chrony Poll - The maximum NTP or Chrony poll interval number in seconds specified as a power of two. - 17 - 16 - 10 - 10 - - - The Chrony package is installed - System time should be synchronized between all systems in an environment. This is -typically done by establishing an authoritative time server or set of servers and having all -systems synchronize their clocks to them. -The chrony package can be installed with the following command: - -$ sudo yum install chrony - BP28(R71) - 0988 - 1405 - FMT_SMF_EXT.1 - Req-10.4 - 10.6.1 - SRG-OS-000355-GPOS-00143 - Time synchronization is important to support time sensitive security mechanisms like -Kerberos and also ensures log files have consistent time records across the enterprise, -which aids in forensic investigations. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -if ! rpm -q --quiet "chrony" ; then - yum install -y "chrony" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Ensure chrony is installed - package: - name: chrony - state: present - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - PCI-DSS-Req-10.4 - - PCI-DSSv4-10.6.1 - - enable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - package_chrony_installed - - include install_chrony - -class install_chrony { - package { 'chrony': - ensure => 'installed', - } -} - - -package --add=chrony - - -[[packages]] -name = "chrony" -version = "*" - - - - - - - - - - Install the ntp service - The ntpd service should be installed. - NT012(R03) - 1 - 14 - 15 - 16 - 3 - 5 - 6 - APO11.04 - BAI03.05 - DSS05.04 - DSS05.07 - MEA02.01 - CCI-000160 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.4.4.7 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.8 - SR 2.9 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - CM-6(a) - PR.PT-1 - Req-10.4 - Time synchronization (using NTP) is required by almost all network and administrative tasks (syslog, cryptographic based services (authentication, etc.), etc.). Ntpd is regulary maintained and updated, supporting security features such as RFC 5906. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -if ! rpm -q --quiet "ntp" ; then - yum install -y "ntp" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Ensure ntp is installed - package: - name: ntp - state: present - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.4 - - enable_strategy - - high_severity - - low_complexity - - low_disruption - - no_reboot_needed - - package_ntp_installed - - include install_ntp - -class install_ntp { - package { 'ntp': - ensure => 'installed', - } -} - - -package --add=ntp - - -[[packages]] -name = "ntp" -version = "*" - - - - - - - - - - The Chronyd service is enabled - chrony is a daemon which implements the Network Time Protocol (NTP) is designed to -synchronize system clocks across a variety of systems and use a source that is highly -accurate. More information on chrony can be found at - - http://chrony.tuxfamily.org/. -Chrony can be configured to be a client and/or a server. -To enable Chronyd service, you can run: -# systemctl enable chronyd.service -This recommendation only applies if chrony is in use on the system. - 0988 - 1405 - SRG-OS-000355-GPOS-00143 - If chrony is in use on the system proper configuration is vital to ensuring time -synchronization is working properly. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && { rpm --quiet -q chrony; }; then - -SYSTEMCTL_EXEC='/usr/bin/systemctl' -"$SYSTEMCTL_EXEC" unmask 'chronyd.service' -"$SYSTEMCTL_EXEC" start 'chronyd.service' -"$SYSTEMCTL_EXEC" enable 'chronyd.service' - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Gather the package facts - package_facts: - manager: auto - tags: - - enable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_chronyd_enabled - -- name: Enable service chronyd - block: - - - name: Gather the package facts - package_facts: - manager: auto - - - name: Enable service chronyd - systemd: - name: chronyd - enabled: 'yes' - state: started - masked: 'no' - when: - - '"chrony" in ansible_facts.packages' - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - '"chrony" in ansible_facts.packages' - tags: - - enable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_chronyd_enabled - - include enable_chronyd - -class enable_chronyd { - service {'chronyd': - enable => true, - ensure => 'running', - } -} - - -[customizations.services] -enabled = ["chronyd"] - - - - - - - - - - Enable the NTP Daemon - -The ntp service can be enabled with the following command: -$ sudo systemctl enable ntp.service - NT012(R03) - 1 - 14 - 15 - 16 - 3 - 5 - 6 - APO11.04 - BAI03.05 - DSS05.04 - DSS05.07 - MEA02.01 - CCI-000160 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.4.4.7 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.8 - SR 2.9 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - CM-6(a) - AU-8(1)(a) - PR.PT-1 - Req-10.4 - 10.6.1 - Enabling the ntp service ensures that the ntp -service will be running and that the system will synchronize its time to -any servers specified. This is important whether the system is configured to be -a client (and synchronize only its own clock) or it is also acting as an NTP -server to other systems. Synchronizing time is essential for authentication -services such as Kerberos, but it is also important for maintaining accurate -logs and auditing possible security breaches. - -The NTP daemon offers all of the functionality of ntpdate, which is now -deprecated. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && { rpm --quiet -q ntp; }; then - -SYSTEMCTL_EXEC='/usr/bin/systemctl' -"$SYSTEMCTL_EXEC" unmask 'ntp.service' -"$SYSTEMCTL_EXEC" start 'ntp.service' -"$SYSTEMCTL_EXEC" enable 'ntp.service' - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Gather the package facts - package_facts: - manager: auto - tags: - - NIST-800-53-AU-8(1)(a) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.4 - - PCI-DSSv4-10.6.1 - - enable_strategy - - high_severity - - low_complexity - - low_disruption - - no_reboot_needed - - service_ntp_enabled - -- name: Enable service ntp - block: - - - name: Gather the package facts - package_facts: - manager: auto - - - name: Enable service ntp - systemd: - name: ntp - enabled: 'yes' - state: started - masked: 'no' - when: - - '"ntp" in ansible_facts.packages' - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - '"ntp" in ansible_facts.packages' - tags: - - NIST-800-53-AU-8(1)(a) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.4 - - PCI-DSSv4-10.6.1 - - enable_strategy - - high_severity - - low_complexity - - low_disruption - - no_reboot_needed - - service_ntp_enabled - - include enable_ntp - -class enable_ntp { - service {'ntp': - enable => true, - ensure => 'running', - } -} - - -[customizations.services] -enabled = ["ntp"] - - - - - - - - - - Enable the NTP Daemon - -The ntpd service can be enabled with the following command: -$ sudo systemctl enable ntpd.service - 1 - 14 - 15 - 16 - 3 - 5 - 6 - APO11.04 - BAI03.05 - DSS05.04 - DSS05.07 - MEA02.01 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.4.4.7 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.8 - SR 2.9 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - CM-6(a) - AU-8(1)(a) - PR.PT-1 - Req-10.4 - 10.6.1 - Enabling the ntpd service ensures that the ntpd -service will be running and that the system will synchronize its time to -any servers specified. This is important whether the system is configured to be -a client (and synchronize only its own clock) or it is also acting as an NTP -server to other systems. Synchronizing time is essential for authentication -services such as Kerberos, but it is also important for maintaining accurate -logs and auditing possible security breaches. - -The NTP daemon offers all of the functionality of ntpdate, which is now -deprecated. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && { rpm --quiet -q ntp; }; then - -SYSTEMCTL_EXEC='/usr/bin/systemctl' -"$SYSTEMCTL_EXEC" unmask 'ntpd.service' -"$SYSTEMCTL_EXEC" start 'ntpd.service' -"$SYSTEMCTL_EXEC" enable 'ntpd.service' - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Gather the package facts - package_facts: - manager: auto - tags: - - NIST-800-53-AU-8(1)(a) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.4 - - PCI-DSSv4-10.6.1 - - enable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_ntpd_enabled - -- name: Enable service ntpd - block: - - - name: Gather the package facts - package_facts: - manager: auto - - - name: Enable service ntpd - systemd: - name: ntpd - enabled: 'yes' - state: started - masked: 'no' - when: - - '"ntp" in ansible_facts.packages' - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - '"ntp" in ansible_facts.packages' - tags: - - NIST-800-53-AU-8(1)(a) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.4 - - PCI-DSSv4-10.6.1 - - enable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_ntpd_enabled - - include enable_ntpd - -class enable_ntpd { - service {'ntpd': - enable => true, - ensure => 'running', - } -} - - -[customizations.services] -enabled = ["ntpd"] - - - - - - - - - - Disable chrony daemon from acting as server - The port option in /etc/chrony.conf can be set to -0 to make chrony daemon to never open any listening port -for server operation and to operate strictly in a client-only mode. - CCI-000381 - AU-8(1) - AU-12(1) - FMT_SMF_EXT.1 - SRG-OS-000096-GPOS-00050 - SRG-OS-000095-GPOS-00049 - In order to prevent unauthorized connection of devices, unauthorized transfer of information, or unauthorized tunneling (i.e., embedding of data types within data types), organizations must disable or restrict unused or unnecessary physical and logical ports/protocols on information systems. -Operating systems are capable of providing a wide variety of functions and services. Some of the functions and services provided by default may not be necessary to support essential organizational operations. Additionally, it is sometimes convenient to provide multiple services from a single component (e.g., VPN and IPS); however, doing so increases risk over limiting the services provided by any one component. -To support the requirements and principles of least functionality, the operating system must support the organizational requirements, providing only essential capabilities and limiting the use of ports, protocols, and/or services to only those required, authorized, and approved to conduct official business or to address authorized quality of life issues. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Strip any search characters in the key arg so that the key can be replaced without -# adding any search characters to the config file. -stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^port") - -# shellcheck disable=SC2059 -printf -v formatted_output "%s %s" "$stripped_key" "0" - -# If the key exists, change it. Otherwise, add it to the config_file. -# We search for the key string followed by a word boundary (matched by \>), -# so if we search for 'setting', 'setting2' won't match. -if LC_ALL=C grep -q -m 1 -i -e "^port\\>" "/etc/chrony.conf"; then - escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") - LC_ALL=C sed -i --follow-symlinks "s/^port\\>.*/$escaped_formatted_output/gi" "/etc/chrony.conf" -else - if [[ -s "/etc/chrony.conf" ]] && [[ -n "$(tail -c 1 -- "/etc/chrony.conf" || true)" ]]; then - LC_ALL=C sed -i --follow-symlinks '$a'\\ "/etc/chrony.conf" - fi - printf '%s\n' "$formatted_output" >> "/etc/chrony.conf" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Disable chrony daemon from acting as server - block: - - - name: Check for duplicate values - lineinfile: - path: /etc/chrony.conf - create: false - regexp: ^\s*port\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - - name: Deduplicate values from /etc/chrony.conf - lineinfile: - path: /etc/chrony.conf - create: false - regexp: ^\s*port\s+ - state: absent - when: dupes.found is defined and dupes.found > 1 - - - name: Insert correct line to /etc/chrony.conf - lineinfile: - path: /etc/chrony.conf - create: true - regexp: ^\s*port\s+ - line: port 0 - state: present - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AU-12(1) - - NIST-800-53-AU-8(1) - - chronyd_client_only - - low_complexity - - low_disruption - - low_severity - - no_reboot_needed - - restrict_strategy - - - - - - - - - - Disable network management of chrony daemon - The cmdport option in /etc/chrony.conf can be set to -0 to stop chrony daemon from listening on the UDP port 323 -for management connections made by chronyc. - CCI-000381 - CM-7(1) - FMT_SMF_EXT.1 - SRG-OS-000096-GPOS-00050 - SRG-OS-000095-GPOS-00049 - Minimizing the exposure of the server functionality of the chrony -daemon diminishes the attack surface. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Strip any search characters in the key arg so that the key can be replaced without -# adding any search characters to the config file. -stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^cmdport") - -# shellcheck disable=SC2059 -printf -v formatted_output "%s %s" "$stripped_key" "0" - -# If the key exists, change it. Otherwise, add it to the config_file. -# We search for the key string followed by a word boundary (matched by \>), -# so if we search for 'setting', 'setting2' won't match. -if LC_ALL=C grep -q -m 1 -i -e "^cmdport\\>" "/etc/chrony.conf"; then - escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") - LC_ALL=C sed -i --follow-symlinks "s/^cmdport\\>.*/$escaped_formatted_output/gi" "/etc/chrony.conf" -else - if [[ -s "/etc/chrony.conf" ]] && [[ -n "$(tail -c 1 -- "/etc/chrony.conf" || true)" ]]; then - LC_ALL=C sed -i --follow-symlinks '$a'\\ "/etc/chrony.conf" - fi - printf '%s\n' "$formatted_output" >> "/etc/chrony.conf" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Disable network management of chrony daemon - block: - - - name: Check for duplicate values - lineinfile: - path: /etc/chrony.conf - create: false - regexp: ^\s*cmdport\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - - name: Deduplicate values from /etc/chrony.conf - lineinfile: - path: /etc/chrony.conf - create: false - regexp: ^\s*cmdport\s+ - state: absent - when: dupes.found is defined and dupes.found > 1 - - - name: Insert correct line to /etc/chrony.conf - lineinfile: - path: /etc/chrony.conf - create: true - regexp: ^\s*cmdport\s+ - line: cmdport 0 - state: present - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-CM-7(1) - - chronyd_no_chronyc_network - - low_complexity - - low_disruption - - low_severity - - no_reboot_needed - - restrict_strategy - - - - - - - - - - Configure Time Service Maxpoll Interval - The maxpoll should be configured to - in /etc/ntp.conf or -/etc/chrony.conf to continuously poll time servers. To configure -maxpoll in /etc/ntp.conf or /etc/chrony.conf -add the following after each `server`, `pool` or `peer` entry: -maxpoll -to server directives. If using chrony any pool directives -should be configured too. -If no server or pool directives are configured, the rule evaluates -to pass. - 1 - 14 - 15 - 16 - 3 - 5 - 6 - APO11.04 - BAI03.05 - DSS05.04 - DSS05.07 - MEA02.01 - CCI-001891 - CCI-002046 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.4.4.7 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.8 - SR 2.9 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - CM-6(a) - AU-8(1)(b) - AU-12(1) - PR.PT-1 - SRG-OS-000355-GPOS-00143 - SRG-OS-000356-GPOS-00144 - SRG-OS-000359-GPOS-00146 - Inaccurate time stamps make it more difficult to correlate events and can lead to an inaccurate analysis. Determining the correct time a particular event occurred on a system is critical when conducting forensic analysis and investigating system events. Sources outside the configured acceptable allowance (drift) may be inaccurate. -Synchronizing internal information system clocks provides uniformity of time stamps for information systems with multiple system clocks and systems connected over a network. -Organizations should consider endpoints that may not have regular access to the authoritative time server (e.g., mobile, teleworking, and tactical endpoints). - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && { ( rpm --quiet -q chrony || rpm --quiet -q ntp ); }; then - -var_time_service_set_maxpoll='' - - - - -pof="/usr/sbin/pidof" - - -CONFIG_FILES="/etc/ntp.conf" -$pof ntpd || { - CHRONY_NAME=/etc/chrony.conf - CHRONY_PATH=${CHRONY_NAME%%.*} - CONFIG_FILES=$(find ${CHRONY_PATH}.* -type f -name '*.conf') -} - -# get list of ntp files - -for config_file in $CONFIG_FILES; do - # Set maxpoll values to var_time_service_set_maxpoll - sed -i "s/^\(\(server\|pool\|peer\).*maxpoll\) [0-9][0-9]*\(.*\)$/\1 $var_time_service_set_maxpoll \3/" "$config_file" -done - - - - -for config_file in $CONFIG_FILES; do - # Add maxpoll to server, pool or peer entries without maxpoll - grep "^\(server\|pool\|peer\)" "$config_file" | grep -v maxpoll | while read -r line ; do - sed -i "s/$line/& maxpoll $var_time_service_set_maxpoll/" "$config_file" - done -done - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Gather the package facts - package_facts: - manager: auto - tags: - - NIST-800-53-AU-12(1) - - NIST-800-53-AU-8(1)(b) - - NIST-800-53-CM-6(a) - - chronyd_or_ntpd_set_maxpoll - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy -- name: XCCDF Value var_time_service_set_maxpoll # promote to variable - set_fact: - var_time_service_set_maxpoll: !!str - tags: - - always - -- name: Check that /etc/ntp.conf exist - stat: - path: /etc/ntp.conf - register: ntp_conf_exist_result - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - ( "chrony" in ansible_facts.packages or "ntp" in ansible_facts.packages ) - tags: - - NIST-800-53-AU-12(1) - - NIST-800-53-AU-8(1)(b) - - NIST-800-53-CM-6(a) - - chronyd_or_ntpd_set_maxpoll - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - -- name: Update the maxpoll values in /etc/ntp.conf - replace: - path: /etc/ntp.conf - regexp: ^(server.*maxpoll)[ ]+[0-9]+(.*)$ - replace: \1 {{ var_time_service_set_maxpoll }}\2 - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - ( "chrony" in ansible_facts.packages or "ntp" in ansible_facts.packages ) - - ntp_conf_exist_result.stat.exists - tags: - - NIST-800-53-AU-12(1) - - NIST-800-53-AU-8(1)(b) - - NIST-800-53-CM-6(a) - - chronyd_or_ntpd_set_maxpoll - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - -- name: Set the maxpoll values in /etc/ntp.conf - replace: - path: /etc/ntp.conf - regexp: (^server\s+((?!maxpoll).)*)$ - replace: \1 maxpoll {{ var_time_service_set_maxpoll }}\n - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - ( "chrony" in ansible_facts.packages or "ntp" in ansible_facts.packages ) - - ntp_conf_exist_result.stat.exists - tags: - - NIST-800-53-AU-12(1) - - NIST-800-53-AU-8(1)(b) - - NIST-800-53-CM-6(a) - - chronyd_or_ntpd_set_maxpoll - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - -- name: Check that /etc/chrony.conf exist - stat: - path: /etc/chrony.conf - register: chrony_conf_exist_result - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - ( "chrony" in ansible_facts.packages or "ntp" in ansible_facts.packages ) - tags: - - NIST-800-53-AU-12(1) - - NIST-800-53-AU-8(1)(b) - - NIST-800-53-CM-6(a) - - chronyd_or_ntpd_set_maxpoll - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - -- name: Get get conf files from /etc/chrony.conf - shell: | - set -o pipefail - CHRONY_NAME=/etc/chrony.conf - CHRONY_PATH=${CHRONY_NAME%%.*} - find ${CHRONY_PATH}.* -type f -name '*.conf' - register: update_chrony_files - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - ( "chrony" in ansible_facts.packages or "ntp" in ansible_facts.packages ) - - chrony_conf_exist_result.stat.exists - changed_when: false - tags: - - NIST-800-53-AU-12(1) - - NIST-800-53-AU-8(1)(b) - - NIST-800-53-CM-6(a) - - chronyd_or_ntpd_set_maxpoll - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - -- name: Update the maxpoll values in /etc/chrony.conf - replace: - path: '{{ item }}' - regexp: ^((?:server|pool|peer).*maxpoll)[ ]+[0-9]+(.*)$ - replace: \1 {{ var_time_service_set_maxpoll }}\2 - loop: '{{ update_chrony_files.stdout_lines|list|flatten|unique }}' - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - ( "chrony" in ansible_facts.packages or "ntp" in ansible_facts.packages ) - - chrony_conf_exist_result.stat.exists - tags: - - NIST-800-53-AU-12(1) - - NIST-800-53-AU-8(1)(b) - - NIST-800-53-CM-6(a) - - chronyd_or_ntpd_set_maxpoll - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - -- name: Set the maxpoll values in /etc/chrony.conf - replace: - path: '{{ item }}' - regexp: (^(?:server|pool|peer)\s+((?!maxpoll).)*)$ - replace: \1 maxpoll {{ var_time_service_set_maxpoll }}\n - loop: '{{ update_chrony_files.stdout_lines|list|flatten|unique }}' - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - ( "chrony" in ansible_facts.packages or "ntp" in ansible_facts.packages ) - - chrony_conf_exist_result.stat.exists - tags: - - NIST-800-53-AU-12(1) - - NIST-800-53-AU-8(1)(b) - - NIST-800-53-CM-6(a) - - chronyd_or_ntpd_set_maxpoll - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - - - - - - - - - - Ensure Chrony is only configured with the server directive - Check that Chrony only has time sources configured with the server directive. - This rule doesn't come with a remediation, the time source needs to be added by the administrator. - CCI-001891 - SRG-OS-000355-GPOS-00143 - SRG-OS-000356-GPOS-00144 - SRG-OS-000359-GPOS-00146 - Depending on the infrastructure being used the pool directive may not be supported. - - - - - - - - - - A remote time server for Chrony is configured - Chrony is a daemon which implements the Network Time Protocol (NTP). It is designed to -synchronize system clocks across a variety of systems and use a source that is highly -accurate. More information on chrony can be found at - - http://chrony.tuxfamily.org/. -Chrony can be configured to be a client and/or a server. -Add or edit server or pool lines to /etc/chrony.conf as appropriate: -server <remote-server> -Multiple servers may be configured. - BP28(R71) - CCI-000160 - CCI-001891 - 0988 - 1405 - CM-6(a) - AU-8(1)(a) - Req-10.4.3 - 10.6.2 - If chrony is in use on the system proper configuration is vital to ensuring time -synchronization is working properly. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && { rpm --quiet -q chrony; }; then - -var_multiple_time_servers='' - - -config_file="/etc/chrony.conf" - -if ! grep -q '^[[:space:]]*\(server\|pool\)[[:space:]]\+[[:graph:]]\+' "$config_file" ; then - if ! grep -q '#[[:space:]]*server' "$config_file" ; then - for server in $(echo "$var_multiple_time_servers" | tr ',' '\n') ; do - printf '\nserver %s' "$server" >> "$config_file" - done - else - sed -i 's/#[ \t]*server/server/g' "$config_file" - fi -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Gather the package facts - package_facts: - manager: auto - tags: - - NIST-800-53-AU-8(1)(a) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.4.3 - - PCI-DSSv4-10.6.2 - - chronyd_specify_remote_server - - configure_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed -- name: XCCDF Value var_multiple_time_servers # promote to variable - set_fact: - var_multiple_time_servers: !!str - tags: - - always - -- name: Detect if chrony is already configured with pools or servers - find: - path: /etc - patterns: chrony.conf - contains: ^[\s]*(?:server|pool)[\s]+[\w]+ - register: chrony_servers - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - '"chrony" in ansible_facts.packages' - tags: - - NIST-800-53-AU-8(1)(a) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.4.3 - - PCI-DSSv4-10.6.2 - - chronyd_specify_remote_server - - configure_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Configure remote time servers - lineinfile: - path: /etc/chrony.conf - line: server {{ item }} - state: present - create: true - loop: '{{ var_multiple_time_servers.split(",") }}' - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - '"chrony" in ansible_facts.packages' - - chrony_servers.matched == 0 - tags: - - NIST-800-53-AU-8(1)(a) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.4.3 - - PCI-DSSv4-10.6.2 - - chronyd_specify_remote_server - - configure_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Specify Additional Remote NTP Servers - Additional NTP servers can be specified for time synchronization -in the file /etc/ntp.conf. To do so, add additional lines of the -following form, substituting the IP address or hostname of a remote NTP server for -ntpserver: -server ntpserver - 1 - 14 - 15 - 16 - 3 - 5 - 6 - APO11.04 - BAI03.05 - DSS05.04 - DSS05.07 - MEA02.01 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.4.4.7 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.8 - SR 2.9 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - CM-6(a) - AU-8(1)(a) - AU-8(2) - PR.PT-1 - Req-10.4.3 - 10.6.2 - Specifying additional NTP servers increases the availability of -accurate time data, in the event that one of the specified servers becomes -unavailable. This is typical for a system acting as an NTP server for -other systems. - - - - - - Specify a Remote NTP Server - To specify a remote NTP server for time synchronization, edit -the file /etc/ntp.conf. Add or correct the following lines, -substituting the IP or hostname of a remote NTP server for ntpserver: -server ntpserver -This instructs the NTP software to contact that remote server to obtain time -data. - 1 - 14 - 15 - 16 - 3 - 5 - 6 - APO11.04 - BAI03.05 - DSS05.04 - DSS05.07 - MEA02.01 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.4.4.7 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.8 - SR 2.9 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - CM-6(a) - AU-8(1)(a) - PR.PT-1 - Req-10.4.1 - Req-10.4.3 - 10.6.1 - 10.6.2 - Synchronizing with an NTP server makes it possible -to collate system logs from multiple sources or correlate computer events with -real time events. - - - - - - - - - - - Obsolete Services - This section discusses a number of network-visible -services which have historically caused problems for system -security, and for which disabling or severely limiting the service -has been the best available guidance for some time. As a result of -this, many of these services are not installed as part of Oracle Linux 9 -by default. - -Organizations which are running these services should -switch to more secure equivalents as soon as possible. -If it remains absolutely necessary to run one of -these services for legacy reasons, care should be taken to restrict -the service as much as possible, for instance by configuring host - -firewall software such as iptables to restrict access to the - -vulnerable service to only those remote hosts which have a known -need to use it. - - Xinetd - The xinetd service acts as a dedicated listener for some -network services (mostly, obsolete ones) and can be used to provide access -controls and perform some logging. It has been largely obsoleted by other -features, and it is not installed by default. The older Inetd service -is not even available as part of Oracle Linux 9. - - - Uninstall xinetd Package - The xinetd package can be removed with the following command: - -$ sudo yum erase xinetd - BP28(R1) - 11 - 12 - 14 - 15 - 3 - 8 - 9 - APO13.01 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS01.04 - DSS05.02 - DSS05.03 - DSS05.05 - DSS06.06 - CCI-000305 - 164.308(a)(4)(i) - 164.308(b)(1) - 164.308(b)(3) - 164.310(b) - 164.312(e)(1) - 164.312(e)(2)(ii) - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 7.1 - SR 7.6 - A.11.2.6 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.6.2.1 - A.6.2.2 - A.9.1.2 - CM-7(a) - CM-7(b) - CM-6(a) - PR.AC-3 - PR.IP-1 - PR.PT-3 - PR.PT-4 - 2.2.4 - Removing the xinetd package decreases the risk of the -xinetd service's accidental (or intentional) activation. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# CAUTION: This remediation script will remove xinetd -# from the system, and may remove any packages -# that depend on xinetd. Execute this -# remediation AFTER testing on a non-production -# system! - -if rpm -q --quiet "xinetd" ; then - - yum remove -y "xinetd" - -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Ensure xinetd is removed - package: - name: xinetd - state: absent - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - PCI-DSSv4-2.2.4 - - disable_strategy - - low_complexity - - low_disruption - - low_severity - - no_reboot_needed - - package_xinetd_removed - - include remove_xinetd - -class remove_xinetd { - package { 'xinetd': - ensure => 'purged', - } -} - - -package --remove=xinetd - - - - - - - - - - Disable xinetd Service - -The xinetd service can be disabled with the following command: -$ sudo systemctl mask --now xinetd.service - 11 - 12 - 14 - 15 - 3 - 8 - 9 - APO13.01 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS01.04 - DSS05.02 - DSS05.03 - DSS05.05 - DSS06.06 - 3.4.7 - CCI-000305 - 164.308(a)(4)(i) - 164.308(b)(1) - 164.308(b)(3) - 164.310(b) - 164.312(e)(1) - 164.312(e)(2)(ii) - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 7.1 - SR 7.6 - A.11.2.6 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.6.2.1 - A.6.2.2 - A.9.1.2 - CM-7(a) - CM-7(b) - CM-6(a) - PR.AC-3 - PR.IP-1 - PR.PT-3 - PR.PT-4 - The xinetd service provides a dedicated listener service for some programs, -which is no longer necessary for commonly-used network services. Disabling -it ensures that these uncommon services are not running, and also prevents -attacks against xinetd itself. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -SYSTEMCTL_EXEC='/usr/bin/systemctl' -"$SYSTEMCTL_EXEC" stop 'xinetd.service' -"$SYSTEMCTL_EXEC" disable 'xinetd.service' -"$SYSTEMCTL_EXEC" mask 'xinetd.service' -# Disable socket activation if we have a unit file for it -if "$SYSTEMCTL_EXEC" -q list-unit-files xinetd.socket; then - "$SYSTEMCTL_EXEC" stop 'xinetd.socket' - "$SYSTEMCTL_EXEC" mask 'xinetd.socket' -fi -# The service may not be running because it has been started and failed, -# so let's reset the state so OVAL checks pass. -# Service should be 'inactive', not 'failed' after reboot though. -"$SYSTEMCTL_EXEC" reset-failed 'xinetd.service' || true - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Block Disable service xinetd - block: - - - name: Disable service xinetd - block: - - - name: Disable service xinetd - systemd: - name: xinetd.service - enabled: 'no' - state: stopped - masked: 'yes' - rescue: - - - name: Intentionally ignored previous 'Disable service xinetd' failure, service - was already disabled - meta: noop - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.4.7 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_xinetd_disabled - -- name: Unit Socket Exists - xinetd.socket - command: systemctl -q list-unit-files xinetd.socket - register: socket_file_exists - changed_when: false - failed_when: socket_file_exists.rc not in [0, 1] - check_mode: false - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.4.7 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_xinetd_disabled - -- name: Disable socket xinetd - systemd: - name: xinetd.socket - enabled: 'no' - state: stopped - masked: 'yes' - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - socket_file_exists.stdout_lines is search("xinetd.socket",multiline=True) - tags: - - NIST-800-171-3.4.7 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_xinetd_disabled - - include disable_xinetd - -class disable_xinetd { - service {'xinetd': - enable => false, - ensure => 'stopped', - } -} - - -[customizations.services] -disabled = ["xinetd"] - - - - - - - - - - - NIS - The Network Information Service (NIS), also known as 'Yellow -Pages' (YP), and its successor NIS+ have been made obsolete by -Kerberos, LDAP, and other modern centralized authentication -services. NIS should not be used because it suffers from security -problems inherent in its design, such as inadequate protection of -important authentication information. - - - Rlogin, Rsh, and Rexec - The Berkeley r-commands are legacy services which -allow cleartext remote access and have an insecure trust -model. - - Uninstall rsh-server Package - The rsh-server package can be removed with the following command: - -$ sudo yum erase rsh-server - BP28(R1) - 11 - 12 - 14 - 15 - 3 - 8 - 9 - APO13.01 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS01.04 - DSS05.02 - DSS05.03 - DSS05.05 - DSS06.06 - CCI-000381 - 164.308(a)(4)(i) - 164.308(b)(1) - 164.308(b)(3) - 164.310(b) - 164.312(e)(1) - 164.312(e)(2)(ii) - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 7.1 - SR 7.6 - A.11.2.6 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.6.2.1 - A.6.2.2 - A.9.1.2 - CM-7(a) - CM-7(b) - CM-6(a) - IA-5(1)(c) - PR.AC-3 - PR.IP-1 - PR.PT-3 - PR.PT-4 - SRG-OS-000095-GPOS-00049 - The rsh-server service provides unencrypted remote access service which does not -provide for the confidentiality and integrity of user passwords or the remote session and has very weak -authentication. If a privileged user were to login using this service, the privileged user password -could be compromised. The rsh-server package provides several obsolete and insecure -network services. Removing it decreases the risk of those services' accidental (or intentional) -activation. - -# CAUTION: This remediation script will remove rsh-server -# from the system, and may remove any packages -# that depend on rsh-server. Execute this -# remediation AFTER testing on a non-production -# system! - -if rpm -q --quiet "rsh-server" ; then - - yum remove -y "rsh-server" - -fi - - - name: Ensure rsh-server is removed - package: - name: rsh-server - state: absent - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-IA-5(1)(c) - - disable_strategy - - high_severity - - low_complexity - - low_disruption - - no_reboot_needed - - package_rsh-server_removed - - include remove_rsh-server - -class remove_rsh-server { - package { 'rsh-server': - ensure => 'purged', - } -} - - -package --remove=rsh-server - - - - - - - - - - Uninstall rsh Package - -The rsh package contains the client commands - -for the rsh services - BP28(R1) - 3.1.13 - 164.308(a)(4)(i) - 164.308(b)(1) - 164.308(b)(3) - 164.310(b) - 164.312(e)(1) - 164.312(e)(2)(ii) - A.8.2.3 - A.13.1.1 - A.13.2.1 - A.13.2.3 - A.14.1.2 - A.14.1.3 - 2.2.4 - These legacy clients contain numerous security exposures and have -been replaced with the more secure SSH package. Even if the server is removed, -it is best to ensure the clients are also removed to prevent users from -inadvertently attempting to use these commands and therefore exposing - -their credentials. Note that removing the rsh package removes - -the clients for rsh,rcp, and rlogin. - -# CAUTION: This remediation script will remove rsh -# from the system, and may remove any packages -# that depend on rsh. Execute this -# remediation AFTER testing on a non-production -# system! - -if rpm -q --quiet "rsh" ; then - - yum remove -y "rsh" - -fi - - - name: Ensure rsh is removed - package: - name: rsh - state: absent - tags: - - NIST-800-171-3.1.13 - - PCI-DSSv4-2.2.4 - - disable_strategy - - low_complexity - - low_disruption - - no_reboot_needed - - package_rsh_removed - - unknown_severity - - include remove_rsh - -class remove_rsh { - package { 'rsh': - ensure => 'purged', - } -} - - -package --remove=rsh - - - - - - - - - - Disable rlogin Service - The rlogin service, which is available with -the rsh-server package and runs as a service through xinetd or separately -as a systemd socket, should be disabled. -If using xinetd, set disable to yes in /etc/xinetd.d/rlogin. - -The rlogin socket can be disabled with the following command: -$ sudo systemctl mask --now rlogin.socket - 1 - 11 - 12 - 14 - 15 - 16 - 3 - 5 - 8 - 9 - APO13.01 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS01.04 - DSS05.02 - DSS05.03 - DSS05.04 - DSS05.05 - DSS05.07 - DSS05.10 - DSS06.03 - DSS06.06 - DSS06.10 - 3.1.13 - 3.4.7 - CCI-001436 - 164.308(a)(4)(i) - 164.308(b)(1) - 164.308(b)(3) - 164.310(b) - 164.312(e)(1) - 164.312(e)(2)(ii) - 4.3.3.2.2 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 7.1 - SR 7.6 - A.11.2.6 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.18.1.4 - A.6.2.1 - A.6.2.2 - A.7.1.1 - A.9.1.2 - A.9.2.1 - A.9.2.2 - A.9.2.3 - A.9.2.4 - A.9.2.6 - A.9.3.1 - A.9.4.2 - A.9.4.3 - CM-7(a) - CM-7(b) - CM-6(a) - IA-5(1)(c) - PR.AC-1 - PR.AC-3 - PR.AC-6 - PR.AC-7 - PR.IP-1 - PR.PT-3 - PR.PT-4 - The rlogin service uses unencrypted network communications, which -means that data from the login session, including passwords and -all other information transmitted during the session, can be -stolen by eavesdroppers on the network. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -SYSTEMCTL_EXEC='/usr/bin/systemctl' -"$SYSTEMCTL_EXEC" stop 'rlogin.service' -"$SYSTEMCTL_EXEC" disable 'rlogin.service' -"$SYSTEMCTL_EXEC" mask 'rlogin.service' -# Disable socket activation if we have a unit file for it -if "$SYSTEMCTL_EXEC" -q list-unit-files rlogin.socket; then - "$SYSTEMCTL_EXEC" stop 'rlogin.socket' - "$SYSTEMCTL_EXEC" mask 'rlogin.socket' -fi -# The service may not be running because it has been started and failed, -# so let's reset the state so OVAL checks pass. -# Service should be 'inactive', not 'failed' after reboot though. -"$SYSTEMCTL_EXEC" reset-failed 'rlogin.service' || true - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Block Disable service rlogin - block: - - - name: Disable service rlogin - block: - - - name: Disable service rlogin - systemd: - name: rlogin.service - enabled: 'no' - state: stopped - masked: 'yes' - rescue: - - - name: Intentionally ignored previous 'Disable service rlogin' failure, service - was already disabled - meta: noop - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.13 - - NIST-800-171-3.4.7 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-IA-5(1)(c) - - disable_strategy - - high_severity - - low_complexity - - low_disruption - - no_reboot_needed - - service_rlogin_disabled - -- name: Unit Socket Exists - rlogin.socket - command: systemctl -q list-unit-files rlogin.socket - register: socket_file_exists - changed_when: false - failed_when: socket_file_exists.rc not in [0, 1] - check_mode: false - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.13 - - NIST-800-171-3.4.7 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-IA-5(1)(c) - - disable_strategy - - high_severity - - low_complexity - - low_disruption - - no_reboot_needed - - service_rlogin_disabled - -- name: Disable socket rlogin - systemd: - name: rlogin.socket - enabled: 'no' - state: stopped - masked: 'yes' - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - socket_file_exists.stdout_lines is search("rlogin.socket",multiline=True) - tags: - - NIST-800-171-3.1.13 - - NIST-800-171-3.4.7 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-IA-5(1)(c) - - disable_strategy - - high_severity - - low_complexity - - low_disruption - - no_reboot_needed - - service_rlogin_disabled - - include disable_rlogin - -class disable_rlogin { - service {'rlogin': - enable => false, - ensure => 'stopped', - } -} - - -[customizations.services] -disabled = ["rlogin"] - - - - - - - - - - Remove Host-Based Authentication Files - The shosts.equiv file lists remote hosts and users that are trusted by the local -system. To remove these files, run the following command to delete them from any location: -$ sudo rm /[path]/[to]/[file]/shosts.equiv - CCI-000366 - SRG-OS-000480-GPOS-00227 - The shosts.equiv files are used to configure host-based authentication for the system via SSH. -Host-based authentication is not sufficient for preventing unauthorized access to the system, -as it does not require interactive identification and authentication of a connection request, -or for the use of two-factor authentication. - -# Identify local mounts -MOUNT_LIST=$(df --local | awk '{ print $6 }') - -# Find file on each listed mount point -for cur_mount in ${MOUNT_LIST} -do - find ${cur_mount} -xdev -type f -name "shosts.equiv" -exec rm -f {} \; -done - - - name: Remove Host-Based Authentication Files - Define Excluded (Non-Local) File - Systems and Paths - ansible.builtin.set_fact: - excluded_fstypes: - - afs - - ceph - - cifs - - smb3 - - smbfs - - sshfs - - ncpfs - - ncp - - nfs - - nfs4 - - gfs - - gfs2 - - glusterfs - - gpfs - - pvfs2 - - ocfs2 - - lustre - - davfs - - fuse.sshfs - excluded_paths: - - dev - - proc - - run - - sys - search_paths: [] - tags: - - high_severity - - low_complexity - - low_disruption - - no_host_based_files - - no_reboot_needed - - restrict_strategy - -- name: Remove Host-Based Authentication Files - Find Relevant Root Directories Ignoring - Pre-Defined Excluded Paths - ansible.builtin.find: - paths: / - file_type: directory - excludes: '{{ excluded_paths }}' - hidden: true - recurse: false - register: result_relevant_root_dirs - tags: - - high_severity - - low_complexity - - low_disruption - - no_host_based_files - - no_reboot_needed - - restrict_strategy - -- name: Remove Host-Based Authentication Files - Include Relevant Root Directories - in a List of Paths to be Searched - ansible.builtin.set_fact: - search_paths: '{{ search_paths | union([item.path]) }}' - loop: '{{ result_relevant_root_dirs.files }}' - tags: - - high_severity - - low_complexity - - low_disruption - - no_host_based_files - - no_reboot_needed - - restrict_strategy - -- name: Remove Host-Based Authentication Files - Increment Search Paths List with - Local Partitions Mount Points - ansible.builtin.set_fact: - search_paths: '{{ search_paths | union([item.mount]) }}' - loop: '{{ ansible_mounts }}' - when: - - item.fstype not in excluded_fstypes - - item.mount != '/' - tags: - - high_severity - - low_complexity - - low_disruption - - no_host_based_files - - no_reboot_needed - - restrict_strategy - -- name: Remove Host-Based Authentication Files - Increment Search Paths List with - Local NFS File System Targets - ansible.builtin.set_fact: - search_paths: '{{ search_paths | union([item.device.split('':'')[1]]) }}' - loop: '{{ ansible_mounts }}' - when: item.device is search("localhost:") - tags: - - high_severity - - low_complexity - - low_disruption - - no_host_based_files - - no_reboot_needed - - restrict_strategy - -- name: Remove Host-Based Authentication Files - Define Rule Specific Facts - ansible.builtin.set_fact: - shosts_equiv_files: - - /shosts.equiv - tags: - - high_severity - - low_complexity - - low_disruption - - no_host_based_files - - no_reboot_needed - - restrict_strategy - -- name: Remove Host-Based Authentication Files - Find All shosts.equiv Files in Local - File Systems - ansible.builtin.command: - cmd: find {{ item }} -xdev -type f -name "shosts.equiv" - loop: '{{ search_paths }}' - changed_when: false - register: result_found_shosts_equiv_files - tags: - - high_severity - - low_complexity - - low_disruption - - no_host_based_files - - no_reboot_needed - - restrict_strategy - -- name: Remove Host-Based Authentication Files - Create List of shosts.equiv Files - Present in Local File Systems - ansible.builtin.set_fact: - shosts_equiv_files: '{{ shosts_equiv_files | union(item.stdout_lines) | list }}' - loop: '{{ result_found_shosts_equiv_files.results }}' - tags: - - high_severity - - low_complexity - - low_disruption - - no_host_based_files - - no_reboot_needed - - restrict_strategy - -- name: Remove Host-Based Authentication Files - Ensure No shosts.equiv Files Are - Present in the System - ansible.builtin.file: - path: '{{ item }}' - state: absent - loop: '{{ shosts_equiv_files }}' - tags: - - high_severity - - low_complexity - - low_disruption - - no_host_based_files - - no_reboot_needed - - restrict_strategy - - - - - - - - - - Remove Rsh Trust Files - The files /etc/hosts.equiv and ~/.rhosts (in -each user's home directory) list remote hosts and users that are trusted by the -local system when using the rshd daemon. -To remove these files, run the following command to delete them from any -location: -$ sudo rm /etc/hosts.equiv -$ rm ~/.rhosts - 11 - 12 - 14 - 15 - 3 - 8 - 9 - APO13.01 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS01.04 - DSS05.02 - DSS05.03 - DSS05.05 - DSS06.06 - CCI-001436 - 164.308(a)(4)(i) - 164.308(b)(1) - 164.308(b)(3) - 164.310(b) - 164.312(e)(1) - 164.312(e)(2)(ii) - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 7.1 - SR 7.6 - A.11.2.6 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.6.2.1 - A.6.2.2 - A.9.1.2 - CM-7(a) - CM-7(b) - CM-6(a) - PR.AC-3 - PR.IP-1 - PR.PT-3 - PR.PT-4 - This action is only meaningful if .rhosts support is permitted -through PAM. Trust files are convenient, but when used in conjunction with -the R-services, they can allow unauthenticated access to a system. - -find /root -xdev -type f -name ".rhosts" -exec rm -f {} \; -find /home -maxdepth 2 -xdev -type f -name ".rhosts" -exec rm -f {} \; -rm -f /etc/hosts.equiv - - - name: Detect .rhosts files in users home directories - find: - paths: - - /root - - /home - recurse: true - patterns: .rhosts - hidden: true - file_type: file - check_mode: false - register: rhosts_locations - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - high_severity - - low_complexity - - low_disruption - - no_reboot_needed - - no_rsh_trust_files - - restrict_strategy - -- name: Remove .rhosts files - file: - path: '{{ item }}' - state: absent - with_items: '{{ rhosts_locations.files | map(attribute=''path'') | list }}' - when: rhosts_locations is success - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - high_severity - - low_complexity - - low_disruption - - no_reboot_needed - - no_rsh_trust_files - - restrict_strategy - -- name: Remove /etc/hosts.equiv file - file: - path: /etc/hosts.equiv - state: absent - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - high_severity - - low_complexity - - low_disruption - - no_reboot_needed - - no_rsh_trust_files - - restrict_strategy - - - - - - - - - - Remove User Host-Based Authentication Files - The ~/.shosts (in each user's home directory) files -list remote hosts and users that are trusted by the -local system. To remove these files, run the following command -to delete them from any location: -$ sudo find / -name '.shosts' -type f -delete - CCI-000366 - SRG-OS-000480-GPOS-00227 - The .shosts files are used to configure host-based authentication for -individual users or the system via SSH. Host-based authentication is not -sufficient for preventing unauthorized access to the system, as it does not -require interactive identification and authentication of a connection request, -or for the use of two-factor authentication. - -# Identify local mounts -MOUNT_LIST=$(df --local | awk '{ print $6 }') - -# Find file on each listed mount point -for cur_mount in ${MOUNT_LIST} -do - find ${cur_mount} -xdev -type f -name ".shosts" -exec rm -f {} \; -done - - - name: Remove User Host-Based Authentication Files - Define Excluded (Non-Local) - File Systems and Paths - ansible.builtin.set_fact: - excluded_fstypes: - - afs - - ceph - - cifs - - smb3 - - smbfs - - sshfs - - ncpfs - - ncp - - nfs - - nfs4 - - gfs - - gfs2 - - glusterfs - - gpfs - - pvfs2 - - ocfs2 - - lustre - - davfs - - fuse.sshfs - excluded_paths: - - dev - - proc - - run - - sys - search_paths: [] - tags: - - high_severity - - low_complexity - - low_disruption - - no_reboot_needed - - no_user_host_based_files - - restrict_strategy - -- name: Remove User Host-Based Authentication Files - Find Relevant Root Directories - Ignoring Pre-Defined Excluded Paths - ansible.builtin.find: - paths: / - file_type: directory - excludes: '{{ excluded_paths }}' - hidden: true - recurse: false - register: result_relevant_root_dirs - tags: - - high_severity - - low_complexity - - low_disruption - - no_reboot_needed - - no_user_host_based_files - - restrict_strategy - -- name: Remove User Host-Based Authentication Files - Include Relevant Root Directories - in a List of Paths to be Searched - ansible.builtin.set_fact: - search_paths: '{{ search_paths | union([item.path]) }}' - loop: '{{ result_relevant_root_dirs.files }}' - tags: - - high_severity - - low_complexity - - low_disruption - - no_reboot_needed - - no_user_host_based_files - - restrict_strategy - -- name: Remove User Host-Based Authentication Files - Increment Search Paths List - with Local Partitions Mount Points - ansible.builtin.set_fact: - search_paths: '{{ search_paths | union([item.mount]) }}' - loop: '{{ ansible_mounts }}' - when: - - item.fstype not in excluded_fstypes - - item.mount != '/' - tags: - - high_severity - - low_complexity - - low_disruption - - no_reboot_needed - - no_user_host_based_files - - restrict_strategy - -- name: Remove User Host-Based Authentication Files - Increment Search Paths List - with Local NFS File System Targets - ansible.builtin.set_fact: - search_paths: '{{ search_paths | union([item.device.split('':'')[1]]) }}' - loop: '{{ ansible_mounts }}' - when: item.device is search("localhost:") - tags: - - high_severity - - low_complexity - - low_disruption - - no_reboot_needed - - no_user_host_based_files - - restrict_strategy - -- name: Remove User Host-Based Authentication Files - Define Rule Specific Facts - ansible.builtin.set_fact: - user_shosts_files: - - /.shosts - tags: - - high_severity - - low_complexity - - low_disruption - - no_reboot_needed - - no_user_host_based_files - - restrict_strategy - -- name: Remove User Host-Based Authentication Files - Find All .shosts Files in Local - File Systems - ansible.builtin.command: - cmd: find {{ item }} -xdev -type f -name ".shosts" - loop: '{{ search_paths }}' - changed_when: false - register: result_found_shosts_files - tags: - - high_severity - - low_complexity - - low_disruption - - no_reboot_needed - - no_user_host_based_files - - restrict_strategy - -- name: Remove User Host-Based Authentication Files - Create List of .shosts Files - Present in Local File Systems - ansible.builtin.set_fact: - user_shosts_files: '{{ user_shosts_files | union(item.stdout_lines) | list }}' - loop: '{{ result_found_shosts_files.results }}' - tags: - - high_severity - - low_complexity - - low_disruption - - no_reboot_needed - - no_user_host_based_files - - restrict_strategy - -- name: Remove User Host-Based Authentication Files - Ensure No .shosts Files Are - Present in the System - ansible.builtin.file: - path: '{{ item }}' - state: absent - loop: '{{ user_shosts_files }}' - tags: - - high_severity - - low_complexity - - low_disruption - - no_reboot_needed - - no_user_host_based_files - - restrict_strategy - - - - - - - - - - - Chat/Messaging Services - The talk software makes it possible for users to send and receive messages -across systems through a terminal session. - - Uninstall talk-server Package - The talk-server package can be removed with the following command: $ sudo yum erase talk-server - BP28(R1) - 164.308(a)(4)(i) - 164.308(b)(1) - 164.308(b)(3) - 164.310(b) - 164.312(e)(1) - 164.312(e)(2)(ii) - The talk software presents a security risk as it uses unencrypted protocols -for communications. Removing the talk-server package decreases the -risk of the accidental (or intentional) activation of talk services. - -# CAUTION: This remediation script will remove talk-server -# from the system, and may remove any packages -# that depend on talk-server. Execute this -# remediation AFTER testing on a non-production -# system! - -if rpm -q --quiet "talk-server" ; then - - yum remove -y "talk-server" - -fi - - - name: Ensure talk-server is removed - package: - name: talk-server - state: absent - tags: - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - package_talk-server_removed - - include remove_talk-server - -class remove_talk-server { - package { 'talk-server': - ensure => 'purged', - } -} - - -package --remove=talk-server - - - - - - - - - - Uninstall talk Package - The talk package contains the client program for the -Internet talk protocol, which allows the user to chat with other users on -different systems. Talk is a communication program which copies lines from one -terminal to the terminal of another user. -The talk package can be removed with the following command: - -$ sudo yum erase talk - BP28(R1) - 164.308(a)(4)(i) - 164.308(b)(1) - 164.308(b)(3) - 164.310(b) - 164.312(e)(1) - 164.312(e)(2)(ii) - 2.2.4 - The talk software presents a security risk as it uses unencrypted protocols -for communications. Removing the talk package decreases the -risk of the accidental (or intentional) activation of talk client program. - -# CAUTION: This remediation script will remove talk -# from the system, and may remove any packages -# that depend on talk. Execute this -# remediation AFTER testing on a non-production -# system! - -if rpm -q --quiet "talk" ; then - - yum remove -y "talk" - -fi - - - name: Ensure talk is removed - package: - name: talk - state: absent - tags: - - PCI-DSSv4-2.2.4 - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - package_talk_removed - - include remove_talk - -class remove_talk { - package { 'talk': - ensure => 'purged', - } -} - - -package --remove=talk - - - - - - - - - - - Telnet - The telnet protocol does not provide confidentiality or integrity -for information transmitted on the network. This includes authentication -information such as passwords. Organizations which use telnet should be -actively working to migrate to a more secure protocol. - - Uninstall telnet-server Package - The telnet-server package can be removed with the following command: - -$ sudo yum erase telnet-server - BP28(R1) - 11 - 12 - 14 - 15 - 3 - 8 - 9 - APO13.01 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS01.04 - DSS05.02 - DSS05.03 - DSS05.05 - DSS06.06 - CCI-000381 - 164.308(a)(4)(i) - 164.308(b)(1) - 164.308(b)(3) - 164.310(b) - 164.312(e)(1) - 164.312(e)(2)(ii) - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 7.1 - SR 7.6 - A.11.2.6 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.6.2.1 - A.6.2.2 - A.9.1.2 - CM-7(a) - CM-7(b) - CM-6(a) - PR.AC-3 - PR.IP-1 - PR.PT-3 - PR.PT-4 - Req-2.2.2 - 2.2.4 - SRG-OS-000095-GPOS-00049 - It is detrimental for operating systems to provide, or install by default, -functionality exceeding requirements or mission objectives. These -unnecessary capabilities are often overlooked and therefore may remain -unsecure. They increase the risk to the platform by providing additional -attack vectors. - -The telnet service provides an unencrypted remote access service which does -not provide for the confidentiality and integrity of user passwords or the -remote session. If a privileged user were to login using this service, the -privileged user password could be compromised. - -Removing the telnet-server package decreases the risk of the -telnet service's accidental (or intentional) activation. - -# CAUTION: This remediation script will remove telnet-server -# from the system, and may remove any packages -# that depend on telnet-server. Execute this -# remediation AFTER testing on a non-production -# system! - -if rpm -q --quiet "telnet-server" ; then - - yum remove -y "telnet-server" - -fi - - - name: Ensure telnet-server is removed - package: - name: telnet-server - state: absent - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - PCI-DSS-Req-2.2.2 - - PCI-DSSv4-2.2.4 - - disable_strategy - - high_severity - - low_complexity - - low_disruption - - no_reboot_needed - - package_telnet-server_removed - - include remove_telnet-server - -class remove_telnet-server { - package { 'telnet-server': - ensure => 'purged', - } -} - - -package --remove=telnet-server - - - - - - - - - - Remove telnet Clients - The telnet client allows users to start connections to other systems via -the telnet protocol. - BP28(R1) - 3.1.13 - 164.308(a)(4)(i) - 164.308(b)(1) - 164.308(b)(3) - 164.310(b) - 164.312(e)(1) - 164.312(e)(2)(ii) - A.8.2.3 - A.13.1.1 - A.13.2.1 - A.13.2.3 - A.14.1.2 - A.14.1.3 - 2.2.4 - The telnet protocol is insecure and unencrypted. The use -of an unencrypted transmission medium could allow an unauthorized user -to steal credentials. The ssh package provides an -encrypted session and stronger security and is included in Oracle Linux 9. - -# CAUTION: This remediation script will remove telnet -# from the system, and may remove any packages -# that depend on telnet. Execute this -# remediation AFTER testing on a non-production -# system! - -if rpm -q --quiet "telnet" ; then - - yum remove -y "telnet" - -fi - - - name: Ensure telnet is removed - package: - name: telnet - state: absent - tags: - - NIST-800-171-3.1.13 - - PCI-DSSv4-2.2.4 - - disable_strategy - - low_complexity - - low_disruption - - low_severity - - no_reboot_needed - - package_telnet_removed - - include remove_telnet - -class remove_telnet { - package { 'telnet': - ensure => 'purged', - } -} - - -package --remove=telnet - - - - - - - - - - Disable telnet Service - Make sure that the activation of the telnet service on system boot is disabled. - -The telnet socket can be disabled with the following command: -$ sudo systemctl mask --now telnet.socket - If the system relies on xinetd to manage telnet sessions, ensure the telnet service -is disabled by the following line: disable = yes. Note that the xinetd file for -telnet is not created automatically, therefore it might have different names. - 1 - 11 - 12 - 14 - 15 - 16 - 3 - 5 - 8 - 9 - APO13.01 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS01.04 - DSS05.02 - DSS05.03 - DSS05.04 - DSS05.05 - DSS05.07 - DSS05.10 - DSS06.03 - DSS06.06 - DSS06.10 - 3.1.13 - 3.4.7 - 164.308(a)(4)(i) - 164.308(b)(1) - 164.308(b)(3) - 164.310(b) - 164.312(e)(1) - 164.312(e)(2)(ii) - 4.3.3.2.2 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 7.1 - SR 7.6 - A.11.2.6 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.18.1.4 - A.6.2.1 - A.6.2.2 - A.7.1.1 - A.9.1.2 - A.9.2.1 - A.9.2.2 - A.9.2.3 - A.9.2.4 - A.9.2.6 - A.9.3.1 - A.9.4.2 - A.9.4.3 - CM-7(a) - CM-7(b) - CM-6(a) - IA-5(1)(c) - PR.AC-1 - PR.AC-3 - PR.AC-6 - PR.AC-7 - PR.IP-1 - PR.PT-3 - PR.PT-4 - The telnet protocol uses unencrypted network communication, which means that data from the -login session, including passwords and all other information transmitted during the session, -can be stolen by eavesdroppers on the network. The telnet protocol is also subject to -man-in-the-middle attacks. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -SYSTEMCTL_EXEC='/usr/bin/systemctl' -"$SYSTEMCTL_EXEC" stop 'telnet.service' -"$SYSTEMCTL_EXEC" disable 'telnet.service' -"$SYSTEMCTL_EXEC" mask 'telnet.service' -# Disable socket activation if we have a unit file for it -if "$SYSTEMCTL_EXEC" -q list-unit-files telnet.socket; then - "$SYSTEMCTL_EXEC" stop 'telnet.socket' - "$SYSTEMCTL_EXEC" mask 'telnet.socket' -fi -# The service may not be running because it has been started and failed, -# so let's reset the state so OVAL checks pass. -# Service should be 'inactive', not 'failed' after reboot though. -"$SYSTEMCTL_EXEC" reset-failed 'telnet.service' || true - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Block Disable service telnet - block: - - - name: Disable service telnet - block: - - - name: Disable service telnet - systemd: - name: telnet.service - enabled: 'no' - state: stopped - masked: 'yes' - rescue: - - - name: Intentionally ignored previous 'Disable service telnet' failure, service - was already disabled - meta: noop - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.13 - - NIST-800-171-3.4.7 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-IA-5(1)(c) - - disable_strategy - - high_severity - - low_complexity - - low_disruption - - no_reboot_needed - - service_telnet_disabled - -- name: Unit Socket Exists - telnet.socket - command: systemctl -q list-unit-files telnet.socket - register: socket_file_exists - changed_when: false - failed_when: socket_file_exists.rc not in [0, 1] - check_mode: false - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.13 - - NIST-800-171-3.4.7 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-IA-5(1)(c) - - disable_strategy - - high_severity - - low_complexity - - low_disruption - - no_reboot_needed - - service_telnet_disabled - -- name: Disable socket telnet - systemd: - name: telnet.socket - enabled: 'no' - state: stopped - masked: 'yes' - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - socket_file_exists.stdout_lines is search("telnet.socket",multiline=True) - tags: - - NIST-800-171-3.1.13 - - NIST-800-171-3.4.7 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-IA-5(1)(c) - - disable_strategy - - high_severity - - low_complexity - - low_disruption - - no_reboot_needed - - service_telnet_disabled - - include disable_telnet - -class disable_telnet { - service {'telnet': - enable => false, - ensure => 'stopped', - } -} - - -[customizations.services] -disabled = ["telnet"] - - - - - - - - - - - TFTP Server - TFTP is a lightweight version of the FTP protocol which has -traditionally been used to configure networking equipment. However, -TFTP provides little security, and modern versions of networking -operating systems frequently support configuration via SSH or other -more secure protocols. A TFTP server should be run only if no more -secure method of supporting existing equipment can be -found. - - TFTP server secure directory - Specify the directory which is used by TFTP server as a root directory when running in secure mode. - /var/lib/tftpboot - - - Uninstall tftp-server Package - The tftp-server package can be removed with the following command: $ sudo yum erase tftp-server - BP28(R1) - 11 - 12 - 14 - 15 - 3 - 8 - 9 - APO13.01 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS01.04 - DSS05.02 - DSS05.03 - DSS05.05 - DSS06.06 - CCI-000318 - CCI-000366 - CCI-000368 - CCI-001812 - CCI-001813 - CCI-001814 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 7.1 - SR 7.6 - A.11.2.6 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.6.2.1 - A.6.2.2 - A.9.1.2 - CM-7(a) - CM-7(b) - CM-6(a) - PR.AC-3 - PR.IP-1 - PR.PT-3 - PR.PT-4 - SRG-OS-000480-GPOS-00227 - Removing the tftp-server package decreases the risk of the accidental -(or intentional) activation of tftp services. - -If TFTP is required for operational support (such as transmission of router -configurations), its use must be documented with the Information Systems -Securty Manager (ISSM), restricted to only authorized personnel, and have -access control rules established. - -# CAUTION: This remediation script will remove tftp-server -# from the system, and may remove any packages -# that depend on tftp-server. Execute this -# remediation AFTER testing on a non-production -# system! - -if rpm -q --quiet "tftp-server" ; then - - yum remove -y "tftp-server" - -fi - - - name: Ensure tftp-server is removed - package: - name: tftp-server - state: absent - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - high_severity - - low_complexity - - low_disruption - - no_reboot_needed - - package_tftp-server_removed - - include remove_tftp-server - -class remove_tftp-server { - package { 'tftp-server': - ensure => 'purged', - } -} - - -package --remove=tftp-server - - - - - - - - - - Remove tftp Daemon - Trivial File Transfer Protocol (TFTP) is a simple file transfer protocol, -typically used to automatically transfer configuration or boot files between systems. -TFTP does not support authentication and can be easily hacked. The package -tftp is a client program that allows for connections to a tftp server. - BP28(R1) - It is recommended that TFTP be removed, unless there is a specific need -for TFTP (such as a boot server). In that case, use extreme caution when configuring -the services. - -# CAUTION: This remediation script will remove tftp -# from the system, and may remove any packages -# that depend on tftp. Execute this -# remediation AFTER testing on a non-production -# system! - -if rpm -q --quiet "tftp" ; then - - yum remove -y "tftp" - -fi - - - name: Ensure tftp is removed - package: - name: tftp - state: absent - tags: - - disable_strategy - - low_complexity - - low_disruption - - low_severity - - no_reboot_needed - - package_tftp_removed - - include remove_tftp - -class remove_tftp { - package { 'tftp': - ensure => 'purged', - } -} - - -package --remove=tftp - - - - - - - - - - Ensure tftp Daemon Uses Secure Mode - If running the Trivial File Transfer Protocol (TFTP) service is necessary, -it should be configured to change its root directory at startup. To do so, -find the path for the tftp systemd service: -$ sudo systemctl show tftp | grep FragmentPath= -FragmentPath=/etc/systemd/system/tftp.service - -and ensure the ExecStart line on that file includes the -s option with a subdirectory: -ExecStart=/usr/sbin/in.tftpd -s - 11 - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - 8 - 9 - APO01.06 - APO13.01 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS01.04 - DSS05.02 - DSS05.03 - DSS05.04 - DSS05.05 - DSS05.07 - DSS06.02 - DSS06.06 - CCI-000366 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 7.1 - SR 7.6 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.11.2.6 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.6.1.2 - A.6.2.1 - A.6.2.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CM-6(b) - AC-6 - CM-7(a) - PR.AC-3 - PR.AC-4 - PR.DS-5 - PR.IP-1 - PR.PT-3 - PR.PT-4 - SRG-OS-000480-GPOS-00227 - Using the -s option causes the TFTP service to only serve files from the -given directory. Serving files from an intentionally-specified directory -reduces the risk of sharing files which should remain private. - - # Remediation is applicable only in certain platforms -if rpm --quiet -q tftp-server; then - -var_tftpd_secure_directory='' - - -if grep -q 'server_args' /etc/xinetd.d/tftp; then - sed -i -E "s;^([[:blank:]]*server_args[[:blank:]]+=[[:blank:]]+.*?)(-s[[:blank:]]+[[:graph:]]+)*(.*)$;\1 -s $var_tftpd_secure_directory \3;" /etc/xinetd.d/tftp -else - echo "server_args = -s $var_tftpd_secure_directory" >> /etc/xinetd.d/tftp -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Gather the package facts - package_facts: - manager: auto - tags: - - NIST-800-53-AC-6 - - NIST-800-53-CM-6(b) - - NIST-800-53-CM-7(a) - - configure_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - tftpd_uses_secure_mode -- name: XCCDF Value var_tftpd_secure_directory # promote to variable - set_fact: - var_tftpd_secure_directory: !!str - tags: - - always - -- name: Find out if the file exists and contains the line configuring server arguments - find: - path: /etc/xinetd.d - patterns: tftp - contains: ^[\s]+server_args.*$ - register: tftpd_secure_config_line - when: '"tftp-server" in ansible_facts.packages' - tags: - - NIST-800-53-AC-6 - - NIST-800-53-CM-6(b) - - NIST-800-53-CM-7(a) - - configure_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - tftpd_uses_secure_mode - -- name: Ensure that TFTP server is configured to start with secure directory - lineinfile: - path: /etc/xinetd.d/tftp - regexp: ^[\s]*(server_args[\s]+=[\s]+.*?)(-s[\s]+[/\.\w]+)*(.*)$ - line: \1 -s {{ var_tftpd_secure_directory }} \3 - state: present - backrefs: true - when: - - '"tftp-server" in ansible_facts.packages' - - tftpd_secure_config_line is defined and tftpd_secure_config_line.matched > 0 - tags: - - NIST-800-53-AC-6 - - NIST-800-53-CM-6(b) - - NIST-800-53-CM-7(a) - - configure_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - tftpd_uses_secure_mode - -- name: Insert correct config line to start TFTP server with secure directory - lineinfile: - path: /etc/xinetd.d/tftp - line: server_args = -s {{ var_tftpd_secure_directory }} - state: present - create: true - when: - - '"tftp-server" in ansible_facts.packages' - - tftpd_secure_config_line is defined and tftpd_secure_config_line.matched == 0 - tags: - - NIST-800-53-AC-6 - - NIST-800-53-CM-6(b) - - NIST-800-53-CM-7(a) - - configure_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - tftpd_uses_secure_mode - - - - - - - - - - - - - Print Support - The Common Unix Printing System (CUPS) service provides both local -and network printing support. A system running the CUPS service can accept -print jobs from other systems, process them, and send them to the appropriate -printer. It also provides an interface for remote administration through a web -browser. The CUPS service is installed and activated by default. The project -homepage and more detailed documentation are available at - - http://www.cups.org. - - - Configure the CUPS Service if Necessary - CUPS provides the ability to easily share local printers with -other systems over the network. It does this by allowing systems to share -lists of available printers. Additionally, each system that runs the CUPS -service can potentially act as a print server. Whenever possible, the printer -sharing and print server capabilities of CUPS should be limited or disabled. -The following recommendations should demonstrate how to do just that. - - - - Proxy Server - A proxy server is a very desirable target for a -potential adversary because much (or all) sensitive data for a -given infrastructure may flow through it. Therefore, if one is -required, the system acting as a proxy server should be dedicated -to that purpose alone and be stored in a physically secure -location. The system's default proxy server software is Squid, and -provided in an RPM package of the same name. - - Disable Squid if Possible - If Squid was installed and activated, but the system -does not need to act as a proxy server, then it should be disabled -and removed. - - Uninstall squid Package - The squid package can be removed with the following command: $ sudo yum erase squid - If there is no need to make the proxy server software available, -removing it provides a safeguard against its activation. - -# CAUTION: This remediation script will remove squid -# from the system, and may remove any packages -# that depend on squid. Execute this -# remediation AFTER testing on a non-production -# system! - -if rpm -q --quiet "squid" ; then - - yum remove -y "squid" - -fi - - - name: Ensure squid is removed - package: - name: squid - state: absent - tags: - - disable_strategy - - low_complexity - - low_disruption - - no_reboot_needed - - package_squid_removed - - unknown_severity - - include remove_squid - -class remove_squid { - package { 'squid': - ensure => 'purged', - } -} - - -package --remove=squid - - - - - - - - - - Disable Squid - -The squid service can be disabled with the following command: -$ sudo systemctl mask --now squid.service - Running proxy server software provides a network-based avenue -of attack, and should be removed if not needed. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -SYSTEMCTL_EXEC='/usr/bin/systemctl' -"$SYSTEMCTL_EXEC" stop 'squid.service' -"$SYSTEMCTL_EXEC" disable 'squid.service' -"$SYSTEMCTL_EXEC" mask 'squid.service' -# Disable socket activation if we have a unit file for it -if "$SYSTEMCTL_EXEC" -q list-unit-files squid.socket; then - "$SYSTEMCTL_EXEC" stop 'squid.socket' - "$SYSTEMCTL_EXEC" mask 'squid.socket' -fi -# The service may not be running because it has been started and failed, -# so let's reset the state so OVAL checks pass. -# Service should be 'inactive', not 'failed' after reboot though. -"$SYSTEMCTL_EXEC" reset-failed 'squid.service' || true - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Block Disable service squid - block: - - - name: Disable service squid - block: - - - name: Disable service squid - systemd: - name: squid.service - enabled: 'no' - state: stopped - masked: 'yes' - rescue: - - - name: Intentionally ignored previous 'Disable service squid' failure, service - was already disabled - meta: noop - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - low_disruption - - no_reboot_needed - - service_squid_disabled - - unknown_severity - -- name: Unit Socket Exists - squid.socket - command: systemctl -q list-unit-files squid.socket - register: socket_file_exists - changed_when: false - failed_when: socket_file_exists.rc not in [0, 1] - check_mode: false - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - low_disruption - - no_reboot_needed - - service_squid_disabled - - unknown_severity - -- name: Disable socket squid - systemd: - name: squid.socket - enabled: 'no' - state: stopped - masked: 'yes' - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - socket_file_exists.stdout_lines is search("squid.socket",multiline=True) - tags: - - disable_strategy - - low_complexity - - low_disruption - - no_reboot_needed - - service_squid_disabled - - unknown_severity - - include disable_squid - -class disable_squid { - service {'squid': - enable => false, - ensure => 'stopped', - } -} - - -[customizations.services] -disabled = ["squid"] - - - - - - - - - - - - Remote Authentication Dial-In User Service (RADIUS) - Remote Authentication Dial-In User Service (RADIUS) is a networking -protocol, operating on port 1812 that provides centralized -Authentication, Authorization, and Accounting (AAA or Triple A) -management for users who connect and use a network service. - - - Hardware RNG Entropy Gatherer Daemon - The rngd feeds random data from hardware device to kernel random device. - - - Enable the Hardware RNG Entropy Gatherer Service - The Hardware RNG Entropy Gatherer service should be enabled. - -The rngd service can be enabled with the following command: -$ sudo systemctl enable rngd.service - CCI-000366 - FCS_RBG_EXT.1 - SRG-OS-000480-GPOS-00227 - The rngd service -feeds random data from hardware device to kernel random device. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -SYSTEMCTL_EXEC='/usr/bin/systemctl' -"$SYSTEMCTL_EXEC" unmask 'rngd.service' -"$SYSTEMCTL_EXEC" start 'rngd.service' -"$SYSTEMCTL_EXEC" enable 'rngd.service' - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Enable service rngd - block: - - - name: Gather the package facts - package_facts: - manager: auto - - - name: Enable service rngd - systemd: - name: rngd - enabled: 'yes' - state: started - masked: 'no' - when: - - '"rng-tools" in ansible_facts.packages' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - enable_strategy - - low_complexity - - low_disruption - - low_severity - - no_reboot_needed - - service_rngd_enabled - - include enable_rngd - -class enable_rngd { - service {'rngd': - enable => true, - ensure => 'running', - } -} - - -[customizations.services] -enabled = ["rngd"] - - - - - - - - - - - Network Routing - A router is a very desirable target for a -potential adversary because they fulfill a variety of -infrastructure networking roles such as access to network segments, -gateways to other networks, filtering, etc. Therefore, if one is -required, the system acting as a router should be dedicated -to that purpose alone and be stored in a physically secure -location. The system's default routing software is Quagga, and -provided in an RPM package of the same name. - - Disable Quagga if Possible - If Quagga was installed and activated, but the system -does not need to act as a router, then it should be disabled -and removed. - - Uninstall quagga Package - The quagga package can be removed with the following command: $ sudo yum erase quagga - 12 - 15 - 8 - APO13.01 - DSS05.02 - CCI-000366 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 7.1 - SR 7.6 - A.13.1.1 - A.13.2.1 - A.14.1.3 - CM-7(a) - CM-7(b) - CM-6(a) - PR.PT-4 - SRG-OS-000480-GPOS-00227 - Routing software is typically used on routers to exchange network topology information -with other routers. If routing software is used when not required, system network -information may be unnecessarily transmitted across the network. - -If there is no need to make the router software available, -removing it provides a safeguard against its activation. - -# CAUTION: This remediation script will remove quagga -# from the system, and may remove any packages -# that depend on quagga. Execute this -# remediation AFTER testing on a non-production -# system! - -if rpm -q --quiet "quagga" ; then - - yum remove -y "quagga" - -fi - - - name: Ensure quagga is removed - package: - name: quagga - state: absent - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - low_complexity - - low_disruption - - low_severity - - no_reboot_needed - - package_quagga_removed - - include remove_quagga - -class remove_quagga { - package { 'quagga': - ensure => 'purged', - } -} - - -package --remove=quagga - - - - - - - - - - - - Samba(SMB) Microsoft Windows File Sharing Server - When properly configured, the Samba service allows -Linux systems to provide file and print sharing to Microsoft -Windows systems. There are two software packages that provide -Samba support. The first, samba-client, provides a series of -command line tools that enable a client system to access Samba -shares. The second, simply labeled samba, provides the Samba -service. It is this second package that allows a Linux system to -act as an Active Directory server, a domain controller, or as a -domain member. Only the samba-client package is installed by -default. - - Configure Samba if Necessary - All settings for the Samba daemon can be found in -/etc/samba/smb.conf. Settings are divided between a -[global] configuration section and a series of user -created share definition sections meant to describe file or print -shares on the system. By default, Samba will operate in user mode -and allow client systems to access local home directories and -printers. It is recommended that these settings be changed or that -additional limitations be set in place. - - Restrict Printer Sharing - By default, Samba utilizes the CUPS printing service to enable -printer sharing with Microsoft Windows workstations. If there are no printers -on the local system, or if printer sharing with Microsoft Windows is not -required, disable the printer sharing capability by commenting out the -following lines, found in /etc/samba/smb.conf: -[global] - load printers = yes - cups options = raw -[printers] - comment = All Printers - path = /usr/spool/samba - browseable = no - guest ok = no - writable = no - printable = yes -There may be other options present, but these are the only options enabled and -uncommented by default. Removing the [printers] share should be enough -for most users. If the Samba printer sharing capability is needed, consider -disabling the Samba network browsing capability or restricting access to a -particular set of users or network addresses. Set the valid users -parameter to a small subset of users or restrict it to a particular group of -users with the shorthand @. Separate each user or group of users with -a space. For example, under the [printers] share: -[printers] - valid users = user @printerusers - - - Restrict SMB File Sharing to Configured Networks - Only users with local user accounts will be able to log in to -Samba shares by default. Shares can be limited to particular users or network -addresses. Use the hosts allow and hosts deny directives -accordingly, and consider setting the valid users directive to a limited subset -of users or to a group of users. Separate each address, user, or user group -with a space as follows for a particular share or global: -[share] - hosts allow = 192.168.1. 127.0.0.1 - valid users = userone usertwo @usergroup -It is also possible to limit read and write access to particular users with the -read list and write list options, though the permissions set by the system -itself will override these settings. Set the read only attribute for each share -to ensure that global settings will not accidentally override the individual -share settings. Then, as with the valid users directive, separate each user or -group of users with a space: -[share] - read only = yes - write list = userone usertwo @usergroup - - - - Disable Samba if Possible - Even after the Samba server package has been installed, it -will remain disabled. Do not enable this service unless it is -absolutely necessary to provide Microsoft Windows file and print -sharing functionality. - - - - SNMP Server - The Simple Network Management Protocol allows -administrators to monitor the state of network devices, including -computers. Older versions of SNMP were well-known for weak -security, such as plaintext transmission of the community string -(used for authentication) and usage of easily-guessable -choices for the community string. - - Disable SNMP Server if Possible - The system includes an SNMP daemon that allows for its remote -monitoring, though it not installed by default. If it was installed and -activated but is not needed, the software should be disabled and removed. - - - Configure SNMP Server if Necessary - If it is necessary to run the snmpd agent on the system, some best -practices should be followed to minimize the security risk from the -installation. The multiple security models implemented by SNMP cannot be fully -covered here so only the following general configuration advice can be offered: -use only SNMP version 3 security models and enable the use of authentication and encryptionwrite access to the MIB (Management Information Base) should be allowed only if necessaryall access to the MIB should be restricted following a principle of least privilegenetwork access should be limited to the maximum extent possible including restricting to expected network -addresses both in the configuration files and in the system firewall rulesensure SNMP agents send traps only to, and accept SNMP queries only from, authorized management -stationsensure that permissions on the snmpd.conf configuration file (by default, in /etc/snmp) are 640 or more restrictiveensure that any MIB files' permissions are also 640 or more restrictive - - SNMP read-only community string - Specify the SNMP community string used for read-only access. - changemero - - - SNMP read-write community string - Specify the SNMP community string used for read-write access. - changemerw - - - - - SSH Server - The SSH protocol is recommended for remote login and -remote file transfer. SSH provides confidentiality and integrity -for data exchanged between two systems, as well as server -authentication, through the use of public key cryptography. The -implementation included with the system is called OpenSSH, and more -detailed documentation is available from its website, - - https://www.openssh.com. -Its server program is called sshd and provided by the RPM package -openssh-server. - - - SSH enabled firewalld zone - Specify firewalld zone to enable SSH service. This value is used only for remediation purposes. - block - public - dmz - drop - external - home - internal - public - trusted - work - - - SSH Approved ciphers by FIPS - Specify the FIPS approved ciphers that are used for data integrity protection by the SSH server. - aes256-ctr,aes192-ctr,aes128-ctr - aes128-ctr,aes192-ctr,aes256-ctr,aes128-cbc,3des-cbc,aes192-cbc,aes256-cbc,rijndael-cbc@lysator.liu.se - chacha20-poly1305@openssh.com,aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm@openssh.com,aes256-gcm@openssh.com,aes128-cbc,aes192-cbc,aes256-cbc,blowfish-cbc,cast128-cbc,3des-cbc - chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr - chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr - chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr - chacha20-poly1305@openssh.com,aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm@openssh.com,aes256-gcm@openssh.com - - - SSH Approved MACs by FIPS - Specify the FIPS approved MACs (message authentication code) algorithms - that are used for data integrity protection by the SSH server. - hmac-sha2-512,hmac-sha2-256 - hmac-sha2-512,hmac-sha2-256,hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com - hmac-sha2-512,hmac-sha2-256,hmac-sha1,hmac-sha1-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com - umac-64-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-sha1-etm@openssh.com,umac-64@openssh.com,umac-128@openssh.com,hmac-sha2-256,hmac-sha2-512,hmac-sha1,hmac-sha1-etm@openssh.com - hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512,hmac-sha2-256 - hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512,hmac-sha2-256 - hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512,hmac-sha2-256 - hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512,hmac-sha2-256 - - - SSH session Idle time - Specify duration of allowed idle time. - 600 - 7200 - 840 - 900 - 1800 - 300 - 3600 - 300 - - - SSH Server Listening Port - Specify port the SSH server is listening. - 22 - - - SSH Max authentication attempts - Specify the maximum number of authentication attempts per connection. - 10 - 3 - 4 - 5 - 4 - - - SSH is required to be installed - Specify if the Policy requires SSH to be installed. Used by SSH Rules -to determine if SSH should be uninstalled or configured. -A value of 0 means that the policy doesn't care if OpenSSH server is installed or not. If it is installed, scanner will check for it's configuration, if it's not installed, the check will pass. -A value of 1 indicates that OpenSSH server package is not required by the policy; -A value of 2 indicates that OpenSSH server package is required by the policy. - 0 - 1 - 2 - - - SSH Strong KEX by FIPS - Specify the FIPS approved KEXs (Key Exchange Algorithms) algorithms - that are used for methods in cryptography by which cryptographic keys are exchanged between two parties - 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 - 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 - curve25519-sha256,curve25519-sha256@libssh.org,ecdh-sha2-nistp521,ecdh-sha2-nistp384,ecdh-sha2-nistp256,diffie-hellman-group-exchange-sha256 - 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 - 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 - 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 - - - SSH Max Sessions Count - Specify the maximum number of open sessions permitted. - 10 - 4 - 3 - 2 - 1 - 0 - 10 - - - SSH Max Keep Alive Count - Specify the maximum number of idle message counts before session is terminated. - 10 - 3 - 5 - 0 - 1 - 0 - - - Install OpenSSH client software - The openssh-clients package can be installed with the following command: - -$ sudo yum install openssh-clients - FIA_UAU.5 - FTP_ITC_EXT.1 - FCS_SSH_EXT.1 - FCS_SSHC_EXT.1 - SRG-OS-000480-GPOS-00227 - This package includes utilities to make encrypted connections and transfer -files securely to SSH servers. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -if ! rpm -q --quiet "openssh-clients" ; then - yum install -y "openssh-clients" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Ensure openssh-clients is installed - package: - name: openssh-clients - state: present - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - enable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - package_openssh-clients_installed - - include install_openssh-clients - -class install_openssh-clients { - package { 'openssh-clients': - ensure => 'installed', - } -} - - -package --add=openssh-clients - - -[[packages]] -name = "openssh-clients" -version = "*" - - - - - - - - - - Install the OpenSSH Server Package - The openssh-server package should be installed. -The openssh-server package can be installed with the following command: - -$ sudo yum install openssh-server - 13 - 14 - APO01.06 - DSS05.02 - DSS05.04 - DSS05.07 - DSS06.02 - DSS06.06 - CCI-002418 - CCI-002420 - CCI-002421 - CCI-002422 - SR 3.1 - SR 3.8 - SR 4.1 - SR 4.2 - SR 5.2 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CM-6(a) - PR.DS-2 - PR.DS-5 - FIA_UAU.5 - FTP_ITC_EXT.1 - FCS_SSH_EXT.1 - FCS_SSHS_EXT.1 - SRG-OS-000423-GPOS-00187 - SRG-OS-000424-GPOS-00188 - SRG-OS-000425-GPOS-00189 - SRG-OS-000426-GPOS-00190 - Without protection of the transmitted information, confidentiality, and -integrity may be compromised because unprotected communications can be -intercepted and either read or altered. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -if ! rpm -q --quiet "openssh-server" ; then - yum install -y "openssh-server" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Ensure openssh-server is installed - package: - name: openssh-server - state: present - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-CM-6(a) - - enable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - package_openssh-server_installed - - include install_openssh-server - -class install_openssh-server { - package { 'openssh-server': - ensure => 'installed', - } -} - - -package --add=openssh-server - - -[[packages]] -name = "openssh-server" -version = "*" - - - - - - - - - - Remove the OpenSSH Server Package - The openssh-server package should be removed. -The openssh-server package can be removed with the following command: - -$ sudo yum erase openssh-server - Without protection of the transmitted information, confidentiality, and -integrity may be compromised because unprotected communications can be -intercepted and either read or altered. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# CAUTION: This remediation script will remove openssh-server -# from the system, and may remove any packages -# that depend on openssh-server. Execute this -# remediation AFTER testing on a non-production -# system! - -if rpm -q --quiet "openssh-server" ; then - - yum remove -y "openssh-server" - -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Ensure openssh-server is removed - package: - name: openssh-server - state: absent - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - package_openssh-server_removed - - include remove_openssh-server - -class remove_openssh-server { - package { 'openssh-server': - ensure => 'purged', - } -} - - -package --remove=openssh-server - - - - - - - - - - Enable the OpenSSH Service - The SSH server service, sshd, is commonly needed. - -The sshd service can be enabled with the following command: -$ sudo systemctl enable sshd.service - 13 - 14 - APO01.06 - DSS05.02 - DSS05.04 - DSS05.07 - DSS06.02 - DSS06.06 - 3.1.13 - 3.5.4 - 3.13.8 - CCI-002418 - CCI-002420 - CCI-002421 - CCI-002422 - SR 3.1 - SR 3.8 - SR 4.1 - SR 4.2 - SR 5.2 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CM-6(a) - SC-8 - SC-8(1) - SC-8(2) - SC-8(3) - SC-8(4) - PR.DS-2 - PR.DS-5 - SRG-OS-000423-GPOS-00187 - SRG-OS-000424-GPOS-00188 - SRG-OS-000425-GPOS-00189 - SRG-OS-000426-GPOS-00190 - Without protection of the transmitted information, confidentiality, and -integrity may be compromised because unprotected communications can be -intercepted and either read or altered. - -This checklist item applies to both internal and external networks and all types -of information system components from which information can be transmitted (e.g., servers, -mobile devices, notebook computers, printers, copiers, scanners, etc). Communication paths -outside the physical protection of a controlled boundary are exposed to the possibility -of interception and modification. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -SYSTEMCTL_EXEC='/usr/bin/systemctl' -"$SYSTEMCTL_EXEC" unmask 'sshd.service' -"$SYSTEMCTL_EXEC" start 'sshd.service' -"$SYSTEMCTL_EXEC" enable 'sshd.service' - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Enable service sshd - block: - - - name: Gather the package facts - package_facts: - manager: auto - - - name: Enable service sshd - systemd: - name: sshd - enabled: 'yes' - state: started - masked: 'no' - when: - - '"openssh-server" in ansible_facts.packages' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.13 - - NIST-800-171-3.13.8 - - NIST-800-171-3.5.4 - - NIST-800-53-CM-6(a) - - NIST-800-53-SC-8 - - NIST-800-53-SC-8(1) - - NIST-800-53-SC-8(2) - - NIST-800-53-SC-8(3) - - NIST-800-53-SC-8(4) - - enable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_sshd_enabled - - include enable_sshd - -class enable_sshd { - service {'sshd': - enable => true, - ensure => 'running', - } -} - - -[customizations.services] -enabled = ["sshd"] - - - - - - - - - - Disable SSH Server If Possible - -The SSH server service, sshd, is commonly needed. -However, if it can be disabled, do so. -This is unusual, as SSH is a common method for encrypted and authenticated -remote access. - CM-3(6) - IA-2(4) - SRG-APP-000185-CTR-000490 - SRG-APP-000141-CTR-000315 - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -SYSTEMCTL_EXEC='/usr/bin/systemctl' -"$SYSTEMCTL_EXEC" stop 'sshd.service' -"$SYSTEMCTL_EXEC" disable 'sshd.service' -"$SYSTEMCTL_EXEC" mask 'sshd.service' -# Disable socket activation if we have a unit file for it -if "$SYSTEMCTL_EXEC" -q list-unit-files sshd.socket; then - "$SYSTEMCTL_EXEC" stop 'sshd.socket' - "$SYSTEMCTL_EXEC" mask 'sshd.socket' -fi -# The service may not be running because it has been started and failed, -# so let's reset the state so OVAL checks pass. -# Service should be 'inactive', not 'failed' after reboot though. -"$SYSTEMCTL_EXEC" reset-failed 'sshd.service' || true - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Block Disable service sshd - block: - - - name: Disable service sshd - block: - - - name: Disable service sshd - systemd: - name: sshd.service - enabled: 'no' - state: stopped - masked: 'yes' - rescue: - - - name: Intentionally ignored previous 'Disable service sshd' failure, service - was already disabled - meta: noop - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-CM-3(6) - - NIST-800-53-IA-2(4) - - disable_strategy - - high_severity - - low_complexity - - low_disruption - - no_reboot_needed - - service_sshd_disabled - -- name: Unit Socket Exists - sshd.socket - command: systemctl -q list-unit-files sshd.socket - register: socket_file_exists - changed_when: false - failed_when: socket_file_exists.rc not in [0, 1] - check_mode: false - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-CM-3(6) - - NIST-800-53-IA-2(4) - - disable_strategy - - high_severity - - low_complexity - - low_disruption - - no_reboot_needed - - service_sshd_disabled - -- name: Disable socket sshd - systemd: - name: sshd.socket - enabled: 'no' - state: stopped - masked: 'yes' - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - socket_file_exists.stdout_lines is search("sshd.socket",multiline=True) - tags: - - NIST-800-53-CM-3(6) - - NIST-800-53-IA-2(4) - - disable_strategy - - high_severity - - low_complexity - - low_disruption - - no_reboot_needed - - service_sshd_disabled - - include disable_sshd - -class disable_sshd { - service {'sshd': - enable => false, - ensure => 'stopped', - } -} - - -[customizations.services] -disabled = ["sshd"] - - - - - - - - - - Verify Group Who Owns SSH Server config file - -To properly set the group owner of /etc/ssh/sshd_config, run the command: -$ sudo chgrp root /etc/ssh/sshd_config - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - APO01.06 - DSS05.04 - DSS05.07 - DSS06.02 - 4.3.3.7.3 - SR 2.1 - SR 5.2 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 - AC-17(a) - CM-6(a) - AC-6(1) - PR.AC-4 - PR.DS-5 - SRG-OS-000480-GPOS-00227 - Service configuration files enable or disable features of their respective -services that if configured incorrectly can lead to insecure and vulnerable -configurations. Therefore, service configuration files should be owned by the -correct group to prevent unauthorized changes. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -chgrp 0 /etc/ssh/sshd_config - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Test for existence /etc/ssh/sshd_config - stat: - path: /etc/ssh/sshd_config - register: file_exists - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-17(a) - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - configure_strategy - - file_groupowner_sshd_config - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Ensure group owner 0 on /etc/ssh/sshd_config - file: - path: /etc/ssh/sshd_config - group: '0' - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - file_exists.stat is defined and file_exists.stat.exists - tags: - - NIST-800-53-AC-17(a) - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - configure_strategy - - file_groupowner_sshd_config - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Verify Group Ownership on SSH Server Private *_key Key Files - SSH server private keys, files that match the /etc/ssh/*_key glob, must be -group-owned by ssh_keys group. - If an unauthorized user obtains the private SSH host key file, the host could be impersonated. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -find /etc/ssh/ -maxdepth 1 -type f ! -group ssh_keys -regex '^.*_key$' -exec chgrp ssh_keys {} \; - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Find /etc/ssh/ file(s) matching ^.*_key$ - command: find -H /etc/ssh/ -maxdepth 1 -type f ! -group ssh_keys -regex "^.*_key$" - register: files_found - changed_when: false - failed_when: false - check_mode: false - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - configure_strategy - - file_groupownership_sshd_private_key - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Ensure group owner on /etc/ssh/ file(s) matching ^.*_key$ - file: - path: '{{ item }}' - group: ssh_keys - state: file - with_items: - - '{{ files_found.stdout_lines }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - configure_strategy - - file_groupownership_sshd_private_key - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Verify Group Ownership on SSH Server Public *.pub Key Files - SSH server public keys, files that match the /etc/ssh/*.pub glob, must be -group-owned by root group. - If a public host key file is modified by an unauthorized user, the SSH service -may be compromised. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -find /etc/ssh/ -maxdepth 1 -type f ! -group 0 -regex '^.*\.pub$' -exec chgrp 0 {} \; - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Find /etc/ssh/ file(s) matching ^.*\.pub$ - command: find -H /etc/ssh/ -maxdepth 1 -type f ! -group 0 -regex "^.*\.pub$" - register: files_found - changed_when: false - failed_when: false - check_mode: false - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - configure_strategy - - file_groupownership_sshd_pub_key - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Ensure group owner on /etc/ssh/ file(s) matching ^.*\.pub$ - file: - path: '{{ item }}' - group: '0' - state: file - with_items: - - '{{ files_found.stdout_lines }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - configure_strategy - - file_groupownership_sshd_pub_key - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Verify Owner on SSH Server config file - -To properly set the owner of /etc/ssh/sshd_config, run the command: -$ sudo chown root /etc/ssh/sshd_config - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - APO01.06 - DSS05.04 - DSS05.07 - DSS06.02 - 4.3.3.7.3 - SR 2.1 - SR 5.2 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 - AC-17(a) - CM-6(a) - AC-6(1) - PR.AC-4 - PR.DS-5 - SRG-OS-000480-GPOS-00227 - Service configuration files enable or disable features of their respective -services that if configured incorrectly can lead to insecure and vulnerable -configurations. Therefore, service configuration files should be owned by the -correct group to prevent unauthorized changes. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -chown 0 /etc/ssh/sshd_config - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Test for existence /etc/ssh/sshd_config - stat: - path: /etc/ssh/sshd_config - register: file_exists - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-17(a) - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - configure_strategy - - file_owner_sshd_config - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Ensure owner 0 on /etc/ssh/sshd_config - file: - path: /etc/ssh/sshd_config - owner: '0' - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - file_exists.stat is defined and file_exists.stat.exists - tags: - - NIST-800-53-AC-17(a) - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - configure_strategy - - file_owner_sshd_config - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Verify Ownership on SSH Server Private *_key Key Files - SSH server private keys, files that match the /etc/ssh/*_key glob, must be owned -by root user. - If an unauthorized user obtains the private SSH host key file, the host could be impersonated. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -find /etc/ssh/ -maxdepth 1 -type f ! -uid 0 -regex '^.*_key$' -exec chown 0 {} \; - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Find /etc/ssh/ file(s) matching ^.*_key$ - command: find -H /etc/ssh/ -maxdepth 1 -type f ! -uid 0 -regex "^.*_key$" - register: files_found - changed_when: false - failed_when: false - check_mode: false - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - configure_strategy - - file_ownership_sshd_private_key - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Ensure owner on /etc/ssh/ file(s) matching ^.*_key$ - file: - path: '{{ item }}' - owner: '0' - state: file - with_items: - - '{{ files_found.stdout_lines }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - configure_strategy - - file_ownership_sshd_private_key - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Verify Ownership on SSH Server Public *.pub Key Files - SSH server public keys, files that match the /etc/ssh/*.pub glob, must be owned -by root user. - If a public host key file is modified by an unauthorized user, the SSH service -may be compromised. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -find /etc/ssh/ -maxdepth 1 -type f ! -uid 0 -regex '^.*\.pub$' -exec chown 0 {} \; - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Find /etc/ssh/ file(s) matching ^.*\.pub$ - command: find -H /etc/ssh/ -maxdepth 1 -type f ! -uid 0 -regex "^.*\.pub$" - register: files_found - changed_when: false - failed_when: false - check_mode: false - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - configure_strategy - - file_ownership_sshd_pub_key - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Ensure owner on /etc/ssh/ file(s) matching ^.*\.pub$ - file: - path: '{{ item }}' - owner: '0' - state: file - with_items: - - '{{ files_found.stdout_lines }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - configure_strategy - - file_ownership_sshd_pub_key - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Verify Permissions on SSH Server config file - -To properly set the permissions of /etc/ssh/sshd_config, run the command: -$ sudo chmod 0600 /etc/ssh/sshd_config - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - APO01.06 - DSS05.04 - DSS05.07 - DSS06.02 - 4.3.3.7.3 - SR 2.1 - SR 5.2 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 - AC-17(a) - CM-6(a) - AC-6(1) - PR.AC-4 - PR.DS-5 - 2.2.6 - SRG-OS-000480-GPOS-00227 - Service configuration files enable or disable features of their respective -services that if configured incorrectly can lead to insecure and vulnerable -configurations. Therefore, service configuration files should be owned by the -correct group to prevent unauthorized changes. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -chmod u-xs,g-xwrs,o-xwrt /etc/ssh/sshd_config - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Test for existence /etc/ssh/sshd_config - stat: - path: /etc/ssh/sshd_config - register: file_exists - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-17(a) - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSSv4-2.2.6 - - configure_strategy - - file_permissions_sshd_config - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Ensure permission u-xs,g-xwrs,o-xwrt on /etc/ssh/sshd_config - file: - path: /etc/ssh/sshd_config - mode: u-xs,g-xwrs,o-xwrt - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - file_exists.stat is defined and file_exists.stat.exists - tags: - - NIST-800-53-AC-17(a) - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSSv4-2.2.6 - - configure_strategy - - file_permissions_sshd_config - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Verify Permissions on SSH Server Private *_key Key Files - SSH server private keys - files that match the /etc/ssh/*_key glob, have to have restricted permissions. -If those files are owned by the root user and the root group, they have to have the 0600 permission or stricter. -If they are owned by the root user, but by a dedicated group ssh_keys, they can have the 0640 permission or stricter. - BP28(R36) - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - APO01.06 - DSS05.04 - DSS05.07 - DSS06.02 - 3.1.13 - 3.13.10 - CCI-000366 - 4.3.3.7.3 - SR 2.1 - SR 5.2 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 - AC-17(a) - CM-6(a) - AC-6(1) - PR.AC-4 - PR.DS-5 - Req-2.2.4 - 2.2.6 - SRG-OS-000480-GPOS-00227 - If an unauthorized user obtains the private SSH host key file, the host could be -impersonated. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -for keyfile in /etc/ssh/*_key; do - test -f "$keyfile" || continue - if test root:root = "$(stat -c "%U:%G" "$keyfile")"; then - - chmod u-xs,g-xwrs,o-xwrt "$keyfile" - - elif test root:ssh_keys = "$(stat -c "%U:%G" "$keyfile")"; then - chmod u-xs,g-xws,o-xwrt "$keyfile" - else - echo "Key-like file '$keyfile' is owned by an unexpected user:group combination" - fi -done - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Find root:root-owned keys - ansible.builtin.command: find -H /etc/ssh/ -maxdepth 1 -user root -regex ".*_key$" - -type f -group root -perm /u+xs,g+xwrs,o+xwrt - register: root_owned_keys - changed_when: false - failed_when: false - check_mode: false - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.13 - - NIST-800-171-3.13.10 - - NIST-800-53-AC-17(a) - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-2.2.4 - - PCI-DSSv4-2.2.6 - - configure_strategy - - file_permissions_sshd_private_key - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Set permissions for root:root-owned keys - ansible.builtin.file: - path: '{{ item }}' - mode: u-xs,g-xwrs,o-xwrt - state: file - with_items: - - '{{ root_owned_keys.stdout_lines }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.13 - - NIST-800-171-3.13.10 - - NIST-800-53-AC-17(a) - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-2.2.4 - - PCI-DSSv4-2.2.6 - - configure_strategy - - file_permissions_sshd_private_key - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Find root:ssh_keys-owned keys - ansible.builtin.command: find -H /etc/ssh/ -maxdepth 1 -user root -regex ".*_key$" - -type f -group ssh_keys -perm /u+xs,g+xws,o+xwrt - register: dedicated_group_owned_keys - changed_when: false - failed_when: false - check_mode: false - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.13 - - NIST-800-171-3.13.10 - - NIST-800-53-AC-17(a) - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-2.2.4 - - PCI-DSSv4-2.2.6 - - configure_strategy - - file_permissions_sshd_private_key - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Set permissions for root:ssh_keys-owned keys - ansible.builtin.file: - path: '{{ item }}' - mode: u-xs,g-xws,o-xwrt - state: file - with_items: - - '{{ dedicated_group_owned_keys.stdout_lines }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.13 - - NIST-800-171-3.13.10 - - NIST-800-53-AC-17(a) - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-2.2.4 - - PCI-DSSv4-2.2.6 - - configure_strategy - - file_permissions_sshd_private_key - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - include ssh_private_key_perms - -class ssh_private_key_perms { - exec { 'sshd_priv_key': - command => "chmod 0640 /etc/ssh/*_key", - path => '/bin:/usr/bin' - } -} - - - - - - - - - - Verify Permissions on SSH Server Public *.pub Key Files - To properly set the permissions of /etc/ssh/*.pub, run the command: $ sudo chmod 0644 /etc/ssh/*.pub - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - APO01.06 - DSS05.04 - DSS05.07 - DSS06.02 - 3.1.13 - 3.13.10 - CCI-000366 - 4.3.3.7.3 - SR 2.1 - SR 5.2 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 - AC-17(a) - CM-6(a) - AC-6(1) - PR.AC-4 - PR.DS-5 - Req-2.2.4 - 2.2.6 - SRG-OS-000480-GPOS-00227 - If a public host key file is modified by an unauthorized user, the SSH service -may be compromised. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -find -H /etc/ssh/ -maxdepth 1 -perm /u+xs,g+xws,o+xwt -type f -regex '^.*\.pub$' -exec chmod u-xs,g-xws,o-xwt {} \; - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Find /etc/ssh/ file(s) - command: find -H /etc/ssh/ -maxdepth 1 -perm /u+xs,g+xws,o+xwt -type f -regex "^.*\.pub$" - register: files_found - changed_when: false - failed_when: false - check_mode: false - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.13 - - NIST-800-171-3.13.10 - - NIST-800-53-AC-17(a) - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-2.2.4 - - PCI-DSSv4-2.2.6 - - configure_strategy - - file_permissions_sshd_pub_key - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Set permissions for /etc/ssh/ file(s) - file: - path: '{{ item }}' - mode: u-xs,g-xws,o-xwt - state: file - with_items: - - '{{ files_found.stdout_lines }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.13 - - NIST-800-171-3.13.10 - - NIST-800-53-AC-17(a) - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-2.2.4 - - PCI-DSSv4-2.2.6 - - configure_strategy - - file_permissions_sshd_pub_key - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - include ssh_public_key_perms - -class ssh_public_key_perms { - exec { 'sshd_pub_key': - command => "chmod 0644 /etc/ssh/*.pub", - path => '/bin:/usr/bin' - } -} - - - - - - - - - - Remove SSH Server iptables Firewall exception (Unusual) - By default, inbound connections to SSH's port are allowed. If the SSH -server is not being used, this exception should be removed from the -firewall configuration. - -Edit the files /etc/sysconfig/iptables and -/etc/sysconfig/ip6tables (if IPv6 is in use). In each file, locate -and delete the line: --A INPUT -m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT -This is unusual, as SSH is a common method for encrypted and authenticated -remote access. - If inbound SSH connections are not expected, disallowing access to the SSH -port will avoid possible exploitation of the port by an attacker. - - - Configure OpenSSH Client if Necessary - The following configuration changes apply to the SSH client. They can -improve security parameters relwevant to the client user, e.g. increasing -entropy while generating initialization vectors. Note that these changes -influence only the default SSH client configuration. Changes in this group -can be overridden by the client user by modifying files within the -~/.ssh directory or by supplying parameters on the command line. - - Configure session renegotiation for SSH client - The RekeyLimit parameter specifies how often -the session key is renegotiated, both in terms of -amount of data that may be transmitted and the time -elapsed. To decrease the default limits, put line -RekeyLimit to file /etc/ssh/ssh_config.d/02-rekey-limit.conf. -Make sure that there is no other RekeyLimit configuration preceding -the include directive in the main config file -/etc/ssh/ssh_config. Check also other files in -/etc/ssh/ssh_config.d directory. Files are processed according to -lexicographical order of file names. Make sure that there is no file -processed before 02-rekey-limit.conf containing definition of -RekeyLimit. - CCI-000068 - FCS_SSH_EXT.1.8 - SRG-OS-000423-GPOS-00187 - SRG-OS-000033-GPOS-00014 - SRG-OS-000424-GPOS-00188 - By decreasing the limit based on the amount of data and enabling -time-based limit, effects of potential attacks against -encryption keys are limited. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -var_ssh_client_rekey_limit_size='' -var_ssh_client_rekey_limit_time='' - - -main_config="/etc/ssh/ssh_config" -include_directory="/etc/ssh/ssh_config.d" - -if grep -q '^[\s]*RekeyLimit.*$' "$main_config"; then - sed -i '/^[\s]*RekeyLimit.*/d' "$main_config" -fi - -for file in "$include_directory"/*.conf; do - if grep -q '^[\s]*RekeyLimit.*$' "$file"; then - sed -i '/^[\s]*RekeyLimit.*/d' "$file" - fi -done - -if [ -e "/etc/ssh/ssh_config.d/02-rekey-limit.conf" ] ; then - - LC_ALL=C sed -i "/^\s*RekeyLimit\s\+/d" "/etc/ssh/ssh_config.d/02-rekey-limit.conf" -else - touch "/etc/ssh/ssh_config.d/02-rekey-limit.conf" -fi -# make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/ssh_config.d/02-rekey-limit.conf" - -cp "/etc/ssh/ssh_config.d/02-rekey-limit.conf" "/etc/ssh/ssh_config.d/02-rekey-limit.conf.bak" -# Insert at the end of the file -printf '%s\n' "RekeyLimit $var_ssh_client_rekey_limit_size $var_ssh_client_rekey_limit_time" >> "/etc/ssh/ssh_config.d/02-rekey-limit.conf" -# Clean up after ourselves. -rm "/etc/ssh/ssh_config.d/02-rekey-limit.conf.bak" - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: XCCDF Value var_ssh_client_rekey_limit_size # promote to variable - set_fact: - var_ssh_client_rekey_limit_size: !!str - tags: - - always -- name: XCCDF Value var_ssh_client_rekey_limit_time # promote to variable - set_fact: - var_ssh_client_rekey_limit_time: !!str - tags: - - always - -- name: Ensure RekeyLimit is not configured in /etc/ssh/ssh_config - lineinfile: - path: /etc/ssh/ssh_config - create: false - regexp: ^\s*RekeyLimit.*$ - state: absent - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - configure_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - ssh_client_rekey_limit - -- name: Collect all include config files for ssh client which configure RekeyLimit - find: - paths: /etc/ssh/ssh_config.d/ - contains: ^[\s]*RekeyLimit.*$ - patterns: '*.config' - register: ssh_config_include_files - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - configure_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - ssh_client_rekey_limit - -- name: Remove all occurences of RekeyLimit configuration from include config files - of ssh client - lineinfile: - path: '{{ item }}' - regexp: ^[\s]*RekeyLimit.*$ - state: absent - loop: '{{ ssh_config_include_files.files }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - configure_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - ssh_client_rekey_limit - -- name: Ensure that rekey limit is set to {{ var_ssh_client_rekey_limit_size }} {{ - var_ssh_client_rekey_limit_time }} in /etc/ssh/ssh_config.d/02-rekey-limit.conf - lineinfile: - path: /etc/ssh/ssh_config.d/02-rekey-limit.conf - create: true - regexp: ^\s*RekeyLimit.*$ - line: RekeyLimit {{ var_ssh_client_rekey_limit_size }} {{ var_ssh_client_rekey_limit_time - }} - state: present - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - configure_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - ssh_client_rekey_limit - - - - - - - - - - - - Verify the SSH Private Key Files Have a Passcode - When creating SSH key pairs, always use a passcode. - -You can create such keys with the following command: -$ sudo ssh-keygen -n [passphrase] -Oracle Linux 9, for certificate-based authentication, must enforce authorized access to the corresponding private key. - SRG-OS-000067-GPOS-00035 - If an unauthorized user obtains access to a private key without a passcode, -that user would have unauthorized access to any system where the associated -public key has been installed. - - - - - - - Configure OpenSSH Server if Necessary - If the system needs to act as an SSH server, then -certain changes should be made to the OpenSSH daemon configuration -file /etc/ssh/sshd_config. The following recommendations can be -applied to this file. See the sshd_config(5) man page for more -detailed information. - - SSH RekeyLimit - size - Specify the size component of the rekey limit. - default - 512M - 512M - 1G - - - SSH RekeyLimit - size - Specify the size component of the rekey limit. - none - 1h - 1h - - - SSH Compression Setting - Specify the compression setting for SSH connections. - no - delayed - no - - - SSH Privilege Separation Setting - Specify whether and how sshd separates privileges when handling incoming network connections. - no - yes - sandbox - sandbox - - - SSH LoginGraceTime setting - Configure parameters for how long the servers stays connected before the user has successfully logged in - 60 - 60 - - - SSH MaxStartups setting - Configure parameters for maximum concurrent unauthenticated connections to the SSH daemon. - 10:30:100 - 10:30:60 - - - Set SSH Client Alive Count Max to zero - The SSH server sends at most ClientAliveCountMax messages -during a SSH session and waits for a response from the SSH client. -The option ClientAliveInterval configures timeout after -each ClientAliveCountMax message. If the SSH server does not -receive a response from the client, then the connection is considered unresponsive -and terminated. - -To ensure the SSH timeout occurs precisely when the -ClientAliveInterval is set, set the ClientAliveCountMax to -value of 0 in - - -/etc/ssh/sshd_config: - 1 - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - 7 - 8 - 5.5.6 - APO13.01 - BAI03.01 - BAI03.02 - BAI03.03 - DSS01.03 - DSS03.05 - DSS05.04 - DSS05.05 - DSS05.07 - DSS05.10 - DSS06.03 - DSS06.10 - 3.1.11 - CCI-000879 - CCI-001133 - CCI-002361 - 164.308(a)(4)(i) - 164.308(b)(1) - 164.308(b)(3) - 164.310(b) - 164.312(e)(1) - 164.312(e)(2)(ii) - 4.3.3.2.2 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.3 - SR 1.1 - SR 1.10 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 6.2 - A.12.4.1 - A.12.4.3 - A.14.1.1 - A.14.2.1 - A.14.2.5 - A.18.1.4 - A.6.1.2 - A.6.1.5 - A.7.1.1 - A.9.1.2 - A.9.2.1 - A.9.2.2 - A.9.2.3 - A.9.2.4 - A.9.2.6 - A.9.3.1 - A.9.4.1 - A.9.4.2 - A.9.4.3 - A.9.4.4 - A.9.4.5 - CIP-004-6 R2.2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.2 - CIP-007-3 R5.3.1 - CIP-007-3 R5.3.2 - CIP-007-3 R5.3.3 - AC-2(5) - AC-12 - AC-17(a) - SC-10 - CM-6(a) - DE.CM-1 - DE.CM-3 - PR.AC-1 - PR.AC-4 - PR.AC-6 - PR.AC-7 - PR.IP-2 - Req-8.1.8 - 8.2.8 - SRG-OS-000126-GPOS-00066 - SRG-OS-000163-GPOS-00072 - SRG-OS-000279-GPOS-00109 - This ensures a user login will be terminated as soon as the ClientAliveInterval -is reached. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Find the include keyword, extract from the line the glob expression representing included files. -# And if it is a relative path prepend '/etc/ssh/' -included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') -for included_file in ${included_files} ; do - - LC_ALL=C sed -i "/^\s*ClientAliveCountMax/Id" "$included_file" -done - -if [ -e "/etc/ssh/sshd_config" ] ; then - - LC_ALL=C sed -i "/^\s*ClientAliveCountMax\s\+/Id" "/etc/ssh/sshd_config" -else - touch "/etc/ssh/sshd_config" -fi -# make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" - -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" -# Insert before the line matching the regex '^Match'. -line_number="$(LC_ALL=C grep -n "^Match" "/etc/ssh/sshd_config.bak" | LC_ALL=C sed 's/:.*//g')" -if [ -z "$line_number" ]; then - # There was no match of '^Match', insert at - # the end of the file. - printf '%s\n' "ClientAliveCountMax 0" >> "/etc/ssh/sshd_config" -else - head -n "$(( line_number - 1 ))" "/etc/ssh/sshd_config.bak" > "/etc/ssh/sshd_config" - printf '%s\n' "ClientAliveCountMax 0" >> "/etc/ssh/sshd_config" - tail -n "+$(( line_number ))" "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" -fi -# Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Find sshd_config included files - shell: |- - included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') - [[ -n $included_files ]] && ls $included_files || true - register: sshd_config_included_files - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - CJIS-5.5.6 - - NIST-800-171-3.1.11 - - NIST-800-53-AC-12 - - NIST-800-53-AC-17(a) - - NIST-800-53-AC-2(5) - - NIST-800-53-CM-6(a) - - NIST-800-53-SC-10 - - PCI-DSS-Req-8.1.8 - - PCI-DSSv4-8.2.8 - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_set_keepalive_0 - -- name: Comment conf from included files - replace: - path: '{{ item }}' - regexp: ^(\s*ClientAliveCountMax.*)$ - replace: '# \1' - loop: '{{ sshd_config_included_files.stdout_lines }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - CJIS-5.5.6 - - NIST-800-171-3.1.11 - - NIST-800-53-AC-12 - - NIST-800-53-AC-17(a) - - NIST-800-53-AC-2(5) - - NIST-800-53-CM-6(a) - - NIST-800-53-SC-10 - - PCI-DSS-Req-8.1.8 - - PCI-DSSv4-8.2.8 - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_set_keepalive_0 - -- name: Set SSH Client Alive Count Max to zero - block: - - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: false - regexp: (?i)^\s*ClientAliveCountMax\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config - create: false - regexp: (?i)^\s*ClientAliveCountMax\s+ - state: absent - when: dupes.found is defined and dupes.found > 1 - - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)^\s*ClientAliveCountMax\s+ - line: ClientAliveCountMax 0 - state: present - insertbefore: ^[#\s]*Match - validate: /usr/sbin/sshd -t -f %s - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - CJIS-5.5.6 - - NIST-800-171-3.1.11 - - NIST-800-53-AC-12 - - NIST-800-53-AC-17(a) - - NIST-800-53-AC-2(5) - - NIST-800-53-CM-6(a) - - NIST-800-53-SC-10 - - PCI-DSS-Req-8.1.8 - - PCI-DSSv4-8.2.8 - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_set_keepalive_0 - - - - - - - - - - - Set SSH Client Alive Count Max - The SSH server sends at most ClientAliveCountMax messages -during a SSH session and waits for a response from the SSH client. -The option ClientAliveInterval configures timeout after -each ClientAliveCountMax message. If the SSH server does not -receive a response from the client, then the connection is considered unresponsive -and terminated. -For SSH earlier than v8.2, a ClientAliveCountMax value of 0 -causes a timeout precisely when the ClientAliveInterval is set. -Starting with v8.2, a value of 0 disables the timeout functionality -completely. If the option is set to a number greater than 0, then -the session will be disconnected after -ClientAliveInterval * ClientAliveCountMax seconds without receiving -a keep alive message. - BP28(R32) - 1 - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - 7 - 8 - 5.5.6 - APO13.01 - BAI03.01 - BAI03.02 - BAI03.03 - DSS01.03 - DSS03.05 - DSS05.04 - DSS05.05 - DSS05.07 - DSS05.10 - DSS06.03 - DSS06.10 - 3.1.11 - CCI-000879 - CCI-001133 - CCI-002361 - 164.308(a)(4)(i) - 164.308(b)(1) - 164.308(b)(3) - 164.310(b) - 164.312(e)(1) - 164.312(e)(2)(ii) - 4.3.3.2.2 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.3 - SR 1.1 - SR 1.10 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 6.2 - A.12.4.1 - A.12.4.3 - A.14.1.1 - A.14.2.1 - A.14.2.5 - A.18.1.4 - A.6.1.2 - A.6.1.5 - A.7.1.1 - A.9.1.2 - A.9.2.1 - A.9.2.2 - A.9.2.3 - A.9.2.4 - A.9.2.6 - A.9.3.1 - A.9.4.1 - A.9.4.2 - A.9.4.3 - A.9.4.4 - A.9.4.5 - CIP-004-6 R2.2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.2 - CIP-007-3 R5.3.1 - CIP-007-3 R5.3.2 - CIP-007-3 R5.3.3 - AC-2(5) - AC-12 - AC-17(a) - SC-10 - CM-6(a) - DE.CM-1 - DE.CM-3 - PR.AC-1 - PR.AC-4 - PR.AC-6 - PR.AC-7 - PR.IP-2 - Req-8.1.8 - 8.2.8 - SRG-OS-000163-GPOS-00072 - SRG-OS-000279-GPOS-00109 - This ensures a user login will be terminated as soon as the ClientAliveInterval -is reached. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -var_sshd_set_keepalive='' - - -if [ -e "/etc/ssh/sshd_config" ] ; then - - LC_ALL=C sed -i "/^\s*ClientAliveCountMax\s\+/Id" "/etc/ssh/sshd_config" -else - touch "/etc/ssh/sshd_config" -fi -# make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" - -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" -# Insert before the line matching the regex '^Match'. -line_number="$(LC_ALL=C grep -n "^Match" "/etc/ssh/sshd_config.bak" | LC_ALL=C sed 's/:.*//g')" -if [ -z "$line_number" ]; then - # There was no match of '^Match', insert at - # the end of the file. - printf '%s\n' "ClientAliveCountMax $var_sshd_set_keepalive" >> "/etc/ssh/sshd_config" -else - head -n "$(( line_number - 1 ))" "/etc/ssh/sshd_config.bak" > "/etc/ssh/sshd_config" - printf '%s\n' "ClientAliveCountMax $var_sshd_set_keepalive" >> "/etc/ssh/sshd_config" - tail -n "+$(( line_number ))" "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" -fi -# Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: XCCDF Value var_sshd_set_keepalive # promote to variable - set_fact: - var_sshd_set_keepalive: !!str - tags: - - always - -- name: Find sshd_config included files - shell: |- - included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') - [[ -n $included_files ]] && ls $included_files || true - register: sshd_config_included_files - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - CJIS-5.5.6 - - NIST-800-171-3.1.11 - - NIST-800-53-AC-12 - - NIST-800-53-AC-17(a) - - NIST-800-53-AC-2(5) - - NIST-800-53-CM-6(a) - - NIST-800-53-SC-10 - - PCI-DSS-Req-8.1.8 - - PCI-DSSv4-8.2.8 - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_set_keepalive - -- name: Comment conf from included files - replace: - path: '{{ item }}' - regexp: ^(\s*ClientAliveCountMax.*)$ - replace: '# \1' - loop: '{{ sshd_config_included_files.stdout_lines }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - CJIS-5.5.6 - - NIST-800-171-3.1.11 - - NIST-800-53-AC-12 - - NIST-800-53-AC-17(a) - - NIST-800-53-AC-2(5) - - NIST-800-53-CM-6(a) - - NIST-800-53-SC-10 - - PCI-DSS-Req-8.1.8 - - PCI-DSSv4-8.2.8 - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_set_keepalive - -- name: Set SSH Client Alive Count Max - block: - - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: false - regexp: (?i)^\s*ClientAliveCountMax\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config - create: false - regexp: (?i)^\s*ClientAliveCountMax\s+ - state: absent - when: dupes.found is defined and dupes.found > 1 - - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)^\s*ClientAliveCountMax\s+ - line: ClientAliveCountMax {{ var_sshd_set_keepalive }} - state: present - insertbefore: ^[#\s]*Match - validate: /usr/sbin/sshd -t -f %s - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - CJIS-5.5.6 - - NIST-800-171-3.1.11 - - NIST-800-53-AC-12 - - NIST-800-53-AC-17(a) - - NIST-800-53-AC-2(5) - - NIST-800-53-CM-6(a) - - NIST-800-53-SC-10 - - PCI-DSS-Req-8.1.8 - - PCI-DSSv4-8.2.8 - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_set_keepalive - - - - - - - - - - - - Set SSH Client Alive Interval - SSH allows administrators to set a network responsiveness timeout interval. -After this interval has passed, the unresponsive client will be automatically logged out. - -To set this timeout interval, edit the following line in /etc/ssh/sshd_config as -follows: -ClientAliveInterval - -The timeout interval is given in seconds. For example, have a timeout -of 10 minutes, set interval to 600. - -If a shorter timeout has already been set for the login shell, that value will -preempt any SSH setting made in /etc/ssh/sshd_config. Keep in mind that -some processes may stop SSH from correctly detecting that the user is idle. - SSH disconnecting unresponsive clients will not have desired effect without also -configuring ClientAliveCountMax in the SSH service configuration. - Following conditions may prevent the SSH session to time out: -Remote processes on the remote machine generates output. As the output has to be transferred over the network to the client, the timeout is reset every time such transfer happens.Any scp or sftp activity by the same user to the host resets the timeout. - BP28(R29) - 1 - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - 7 - 8 - 5.5.6 - APO13.01 - BAI03.01 - BAI03.02 - BAI03.03 - DSS01.03 - DSS03.05 - DSS05.04 - DSS05.05 - DSS05.07 - DSS05.10 - DSS06.03 - DSS06.10 - 3.1.11 - CCI-000879 - CCI-001133 - CCI-002361 - 4.3.3.2.2 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.3 - SR 1.1 - SR 1.10 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 6.2 - A.12.4.1 - A.12.4.3 - A.14.1.1 - A.14.2.1 - A.14.2.5 - A.18.1.4 - A.6.1.2 - A.6.1.5 - A.7.1.1 - A.9.1.2 - A.9.2.1 - A.9.2.2 - A.9.2.3 - A.9.2.4 - A.9.2.6 - A.9.3.1 - A.9.4.1 - A.9.4.2 - A.9.4.3 - A.9.4.4 - A.9.4.5 - CIP-004-6 R2.2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.2 - CIP-007-3 R5.3.1 - CIP-007-3 R5.3.2 - CIP-007-3 R5.3.3 - CM-6(a) - AC-17(a) - AC-2(5) - AC-12 - AC-17(a) - SC-10 - CM-6(a) - DE.CM-1 - DE.CM-3 - PR.AC-1 - PR.AC-4 - PR.AC-6 - PR.AC-7 - PR.IP-2 - Req-8.1.8 - 8.2.8 - SRG-OS-000126-GPOS-00066 - SRG-OS-000163-GPOS-00072 - SRG-OS-000279-GPOS-00109 - SRG-OS-000395-GPOS-00175 - Terminating an idle ssh session within a short time period reduces the window of -opportunity for unauthorized personnel to take control of a management session -enabled on the console or console port that has been let unattended. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -sshd_idle_timeout_value='' - - -if [ -e "/etc/ssh/sshd_config" ] ; then - - LC_ALL=C sed -i "/^\s*ClientAliveInterval\s\+/Id" "/etc/ssh/sshd_config" -else - touch "/etc/ssh/sshd_config" -fi -# make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" - -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" -# Insert before the line matching the regex '^Match'. -line_number="$(LC_ALL=C grep -n "^Match" "/etc/ssh/sshd_config.bak" | LC_ALL=C sed 's/:.*//g')" -if [ -z "$line_number" ]; then - # There was no match of '^Match', insert at - # the end of the file. - printf '%s\n' "ClientAliveInterval $sshd_idle_timeout_value" >> "/etc/ssh/sshd_config" -else - head -n "$(( line_number - 1 ))" "/etc/ssh/sshd_config.bak" > "/etc/ssh/sshd_config" - printf '%s\n' "ClientAliveInterval $sshd_idle_timeout_value" >> "/etc/ssh/sshd_config" - tail -n "+$(( line_number ))" "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" -fi -# Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: XCCDF Value sshd_idle_timeout_value # promote to variable - set_fact: - sshd_idle_timeout_value: !!str - tags: - - always - -- name: Find sshd_config included files - shell: |- - included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') - [[ -n $included_files ]] && ls $included_files || true - register: sshd_config_included_files - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - CJIS-5.5.6 - - NIST-800-171-3.1.11 - - NIST-800-53-AC-12 - - NIST-800-53-AC-17(a) - - NIST-800-53-AC-17(a) - - NIST-800-53-AC-2(5) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-6(a) - - NIST-800-53-SC-10 - - PCI-DSS-Req-8.1.8 - - PCI-DSSv4-8.2.8 - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_set_idle_timeout - -- name: Comment conf from included files - replace: - path: '{{ item }}' - regexp: ^(\s*ClientAliveInterval.*)$ - replace: '# \1' - loop: '{{ sshd_config_included_files.stdout_lines }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - CJIS-5.5.6 - - NIST-800-171-3.1.11 - - NIST-800-53-AC-12 - - NIST-800-53-AC-17(a) - - NIST-800-53-AC-17(a) - - NIST-800-53-AC-2(5) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-6(a) - - NIST-800-53-SC-10 - - PCI-DSS-Req-8.1.8 - - PCI-DSSv4-8.2.8 - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_set_idle_timeout - -- name: Set SSH Client Alive Interval - block: - - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: false - regexp: (?i)^\s*ClientAliveInterval\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config - create: false - regexp: (?i)^\s*ClientAliveInterval\s+ - state: absent - when: dupes.found is defined and dupes.found > 1 - - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)^\s*ClientAliveInterval\s+ - line: ClientAliveInterval {{ sshd_idle_timeout_value }} - state: present - insertbefore: ^[#\s]*Match - validate: /usr/sbin/sshd -t -f %s - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - CJIS-5.5.6 - - NIST-800-171-3.1.11 - - NIST-800-53-AC-12 - - NIST-800-53-AC-17(a) - - NIST-800-53-AC-17(a) - - NIST-800-53-AC-2(5) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-6(a) - - NIST-800-53-SC-10 - - PCI-DSS-Req-8.1.8 - - PCI-DSSv4-8.2.8 - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_set_idle_timeout - - - - - - - - - - - - Disable Host-Based Authentication - SSH's cryptographic host-based authentication is -more secure than .rhosts authentication. However, it is -not recommended that hosts unilaterally trust one another, even -within an organization. - -The default SSH configuration disables host-based authentication. The appropriate -configuration is used if no value is set for HostbasedAuthentication. - -To explicitly disable host-based authentication, add or correct the -following line in - - -/etc/ssh/sshd_config: - -HostbasedAuthentication no - 11 - 12 - 14 - 15 - 16 - 18 - 3 - 5 - 9 - 5.5.6 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS05.02 - DSS05.04 - DSS05.05 - DSS05.07 - DSS06.03 - DSS06.06 - 3.1.12 - CCI-000366 - 164.308(a)(4)(i) - 164.308(b)(1) - 164.308(b)(3) - 164.310(b) - 164.312(e)(1) - 164.312(e)(2)(ii) - 4.3.3.2.2 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 7.6 - 0421 - 0422 - 0431 - 0974 - 1173 - 1401 - 1504 - 1505 - 1546 - 1557 - 1558 - 1559 - 1560 - 1561 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.6.1.2 - A.7.1.1 - A.9.1.2 - A.9.2.1 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.2.3 - CIP-004-6 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.2 - CIP-007-3 R5.2 - CIP-007-3 R5.3.1 - CIP-007-3 R5.3.2 - CIP-007-3 R5.3.3 - AC-3 - AC-17(a) - CM-7(a) - CM-7(b) - CM-6(a) - PR.AC-4 - PR.AC-6 - PR.IP-1 - PR.PT-3 - FIA_UAU.1 - 8.3.1 - SRG-OS-000480-GPOS-00229 - SSH trust relationships mean a compromise on one host -can allow an attacker to move trivially to other hosts. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Find the include keyword, extract from the line the glob expression representing included files. -# And if it is a relative path prepend '/etc/ssh/' -included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') -for included_file in ${included_files} ; do - - LC_ALL=C sed -i "/^\s*HostbasedAuthentication/Id" "$included_file" -done - -if [ -e "/etc/ssh/sshd_config" ] ; then - - LC_ALL=C sed -i "/^\s*HostbasedAuthentication\s\+/Id" "/etc/ssh/sshd_config" -else - touch "/etc/ssh/sshd_config" -fi -# make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" - -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" -# Insert before the line matching the regex '^Match'. -line_number="$(LC_ALL=C grep -n "^Match" "/etc/ssh/sshd_config.bak" | LC_ALL=C sed 's/:.*//g')" -if [ -z "$line_number" ]; then - # There was no match of '^Match', insert at - # the end of the file. - printf '%s\n' "HostbasedAuthentication no" >> "/etc/ssh/sshd_config" -else - head -n "$(( line_number - 1 ))" "/etc/ssh/sshd_config.bak" > "/etc/ssh/sshd_config" - printf '%s\n' "HostbasedAuthentication no" >> "/etc/ssh/sshd_config" - tail -n "+$(( line_number ))" "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" -fi -# Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Find sshd_config included files - shell: |- - included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') - [[ -n $included_files ]] && ls $included_files || true - register: sshd_config_included_files - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - CJIS-5.5.6 - - NIST-800-171-3.1.12 - - NIST-800-53-AC-17(a) - - NIST-800-53-AC-3 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - PCI-DSSv4-8.3.1 - - disable_host_auth - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - -- name: Comment conf from included files - replace: - path: '{{ item }}' - regexp: ^(\s*HostbasedAuthentication.*)$ - replace: '# \1' - loop: '{{ sshd_config_included_files.stdout_lines }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - CJIS-5.5.6 - - NIST-800-171-3.1.12 - - NIST-800-53-AC-17(a) - - NIST-800-53-AC-3 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - PCI-DSSv4-8.3.1 - - disable_host_auth - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - -- name: Disable Host-Based Authentication - block: - - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: false - regexp: (?i)^\s*HostbasedAuthentication\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config - create: false - regexp: (?i)^\s*HostbasedAuthentication\s+ - state: absent - when: dupes.found is defined and dupes.found > 1 - - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)^\s*HostbasedAuthentication\s+ - line: HostbasedAuthentication no - state: present - insertbefore: ^[#\s]*Match - validate: /usr/sbin/sshd -t -f %s - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - CJIS-5.5.6 - - NIST-800-171-3.1.12 - - NIST-800-53-AC-17(a) - - NIST-800-53-AC-3 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - PCI-DSSv4-8.3.1 - - disable_host_auth - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - - - - - - - - - - Enable SSH Server firewalld Firewall Exception - If the SSH server is in use, inbound connections to SSH's port should be allowed to permit -remote access through SSH. In more restrictive firewalld settings, the SSH port should be -added to the proper firewalld zone in order to allow SSH remote access. - - - - -To configure firewalld to allow ssh access, run the following command(s): -firewall-cmd --permanent --add-service=ssh - -Then run the following command to load the newly created rule(s): -firewall-cmd --reload - The remediation for this rule uses firewall-cmd and nmcli tools. -Therefore, it will only be executed if firewalld and NetworkManager -services are running. Otherwise, the remediation will be aborted and a informative message -will be shown in the remediation report. -These respective services will not be started in order to preserve any intentional change -in network components related to firewall and network interfaces. - This rule also checks if the SSH port was modified by the administrator in the firewalld -services definitions and is reflecting the expected port number. Although this is checked, -fixing the custom ssh.xml file placed by the administrator at /etc/firewalld/services it -is not in the scope of the remediation since there is no reliable way to manually change -the respective file. If the default SSH port is modified, it is on the administrator -responsibility to ensure the firewalld customizations in the service port level are -properly configured. - Oracle Linux 9 prefers and recommends to use NetworkManager keyfiles instead of the -ifcfg files stored in /etc/sysconfig/network-scripts. Therefore, if the -system was upgraded from a previous release, make sure the NIC configuration files are -properly migrated from ifcfg format to NetworkManager keyfiles. Otherwise, this -rule won't be able to check the configuration. The migration can be accomplished by -nmcli connection migrate command. - 3.1.12 - 1416 - AC-17(a) - CM-6(b) - CM-7(a) - CM-7(b) - SRG-OS-000096-GPOS-00050 - If inbound SSH connections are expected, adding the SSH port to the proper firewalld zone -will allow remote access through the SSH port. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -if ! rpm -q --quiet "firewalld" ; then - yum install -y "firewalld" -fi -if ! rpm -q --quiet "NetworkManager" ; then - yum install -y "NetworkManager" -fi -firewalld_sshd_zone='' - - -if systemctl is-active NetworkManager && systemctl is-active firewalld; then - # First make sure the SSH service is enabled in run-time for the proper zone. - # This is to avoid connection issues when new interfaces are addeded to this zone. - firewall-cmd --zone="$firewalld_sshd_zone" --add-service=ssh - - # This will collect all NetworkManager connections names - readarray -t nm_connections < <(nmcli -f UUID,TYPE con | grep ethernet | awk '{ print $1 }') - # If the connection is not yet assigned to a firewalld zone, assign it to the proper zone. - # This will not change connections which are already assigned to any firewalld zone. - for connection in "${nm_connections[@]}"; do - current_zone=$(nmcli -f connection.zone connection show "$connection" | awk '{ print $2}') - if [ $current_zone = "--" ]; then - nmcli connection modify "$connection" connection.zone $firewalld_sshd_zone - fi - done - systemctl restart NetworkManager - - # Active zones are zones with at least one interface assigned to it. - # It is possible that traffic is comming by any active interface and consequently any - # active zone. So, this make sure all active zones are permanently allowing SSH service. - readarray -t firewalld_active_zones < <(firewall-cmd --get-active-zones | grep -v interfaces) - for zone in "${firewalld_active_zones[@]}"; do - firewall-cmd --permanent --zone="$zone" --add-service=ssh - done - firewall-cmd --reload -else - echo " - firewalld and NetworkManager services are not active. Remediation aborted! - This remediation could not be applied because it depends on firewalld and NetworkManager services running. - The service is not started by this remediation in order to prevent connection issues." - exit 1 -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: XCCDF Value firewalld_sshd_zone # promote to variable - set_fact: - firewalld_sshd_zone: !!str - tags: - - always - -- name: Enable SSH Server firewalld Firewall Exception - Ensure firewalld and NetworkManager - packages are installed - ansible.builtin.package: - name: '{{ item }}' - state: present - with_items: - - firewalld - - NetworkManager - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.12 - - NIST-800-53-AC-17(a) - - NIST-800-53-CM-6(b) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - configure_strategy - - firewalld_sshd_port_enabled - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Enable SSH Server firewalld Firewall Exception - Collect facts about system - services - ansible.builtin.service_facts: null - register: result_services_states - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.12 - - NIST-800-53-AC-17(a) - - NIST-800-53-CM-6(b) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - configure_strategy - - firewalld_sshd_port_enabled - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Enable SSH Server firewalld Firewall Exception - Remediation is applicable - if firewalld and NetworkManager services are running - block: - - - name: Enable SSH Server firewalld Firewall Exception - Collect NetworkManager - connections names - ansible.builtin.shell: - cmd: nmcli -f UUID,TYPE con | grep ethernet | awk '{ print $1 }' - register: result_nmcli_cmd_connections_names - changed_when: false - - - name: Enable SSH Server firewalld Firewall Exception - Collect NetworkManager - connections zones - ansible.builtin.shell: - cmd: nmcli -f connection.zone connection show {{ item | trim }} | awk '{ print - $2}' - register: result_nmcli_cmd_connections_zones - changed_when: false - with_items: - - '{{ result_nmcli_cmd_connections_names.stdout_lines }}' - - - name: Enable SSH Server firewalld Firewall Exception - Ensure NetworkManager connections - are assigned to a firewalld zone - ansible.builtin.command: - cmd: nmcli connection modify {{ item.0 }} connection.zone {{ firewalld_sshd_zone - }} - register: result_nmcli_cmd_connections_assignment - with_together: - - '{{ result_nmcli_cmd_connections_names.stdout_lines }}' - - '{{ result_nmcli_cmd_connections_zones.results }}' - when: - - item.1.stdout == '--' - - - name: Enable SSH Server firewalld Firewall Exception - Ensure NetworkManager connections - changes are applied - ansible.builtin.service: - name: NetworkManager - state: restarted - when: - - result_nmcli_cmd_connections_assignment is changed - - - name: Enable SSH Server firewalld Firewall Exception - Collect firewalld active - zones - ansible.builtin.shell: - cmd: firewall-cmd --get-active-zones | grep -v interfaces - register: result_firewall_cmd_zones_names - changed_when: false - - - name: Enable SSH Server firewalld Firewall Exception - Ensure firewalld zones - allow SSH - ansible.builtin.command: - cmd: firewall-cmd --permanent --zone={{ item }} --add-service=ssh - register: result_nmcli_cmd_connections_assignment - changed_when: - - '''ALREADY_ENABLED'' not in result_nmcli_cmd_connections_assignment.stderr' - with_items: - - '{{ result_firewall_cmd_zones_names.stdout_lines }}' - - - name: Enable SSH Server firewalld Firewall Exception - Ensure firewalld changes - are applied - ansible.builtin.service: - name: firewalld - state: reloaded - when: - - result_nmcli_cmd_connections_assignment is changed - when: - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - ansible_facts.services['firewalld.service'].state == 'running' - - ansible_facts.services['NetworkManager.service'].state == 'running' - tags: - - NIST-800-171-3.1.12 - - NIST-800-53-AC-17(a) - - NIST-800-53-CM-6(b) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - configure_strategy - - firewalld_sshd_port_enabled - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Enable SSH Server firewalld Firewall Exception - Informative message based - on services states - ansible.builtin.assert: - that: - - ansible_facts.services['firewalld.service'].state == 'running' - - ansible_facts.services['NetworkManager.service'].state == 'running' - fail_msg: - - firewalld and NetworkManager services are not active. Remediation aborted! - - This remediation could not be applied because it depends on firewalld and NetworkManager - services running. - - The service is not started by this remediation in order to prevent connection - issues. - success_msg: - - Enable SSH Server firewalld Firewall Exception remediation successfully executed - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.12 - - NIST-800-53-AC-17(a) - - NIST-800-53-CM-6(b) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - configure_strategy - - firewalld_sshd_port_enabled - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - - Allow Only SSH Protocol 2 - Only SSH protocol version 2 connections should be -permitted. The default setting in -/etc/ssh/sshd_config is correct, and can be -verified by ensuring that the following -line appears: -Protocol 2 - As of openssh-server version 7.4 and above, the only protocol -supported is version 2, and line Protocol 2 in -/etc/ssh/sshd_config is not necessary. - NT007(R1) - 1 - 12 - 15 - 16 - 5 - 8 - 5.5.6 - APO13.01 - DSS01.04 - DSS05.02 - DSS05.03 - DSS05.04 - DSS05.05 - DSS05.07 - DSS05.10 - DSS06.03 - DSS06.10 - 3.1.13 - 3.5.4 - CCI-000197 - CCI-000366 - 164.308(a)(4)(i) - 164.308(b)(1) - 164.308(b)(3) - 164.310(b) - 164.312(e)(1) - 164.312(e)(2)(ii) - 4.3.3.2.2 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.2 - 4.3.3.7.4 - SR 1.1 - SR 1.10 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.6 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 7.1 - SR 7.6 - 0487 - 1449 - 1506 - A.11.2.6 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.18.1.4 - A.6.2.1 - A.6.2.2 - A.7.1.1 - A.9.2.1 - A.9.2.2 - A.9.2.3 - A.9.2.4 - A.9.2.6 - A.9.3.1 - A.9.4.2 - A.9.4.3 - CIP-003-8 R4.2 - CIP-007-3 R5.1 - CIP-007-3 R7.1 - CM-6(a) - AC-17(a) - AC-17(2) - IA-5(1)(c) - SC-13 - MA-4(6) - PR.AC-1 - PR.AC-3 - PR.AC-6 - PR.AC-7 - PR.PT-4 - SRG-OS-000074-GPOS-00042 - SRG-OS-000480-GPOS-00227 - SSH protocol version 1 is an insecure implementation of the SSH protocol and -has many well-known vulnerability exploits. Exploits of the SSH daemon could provide -immediate root access to the system. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Strip any search characters in the key arg so that the key can be replaced without -# adding any search characters to the config file. -stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^Protocol") - -# shellcheck disable=SC2059 -printf -v formatted_output "%s %s" "$stripped_key" "2" - -# If the key exists, change it. Otherwise, add it to the config_file. -# We search for the key string followed by a word boundary (matched by \>), -# so if we search for 'setting', 'setting2' won't match. -if LC_ALL=C grep -q -m 1 -i -e "^Protocol\\>" "/etc/ssh/sshd_config"; then - escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") - LC_ALL=C sed -i --follow-symlinks "s/^Protocol\\>.*/$escaped_formatted_output/gi" "/etc/ssh/sshd_config" -else - if [[ -s "/etc/ssh/sshd_config" ]] && [[ -n "$(tail -c 1 -- "/etc/ssh/sshd_config" || true)" ]]; then - LC_ALL=C sed -i --follow-symlinks '$a'\\ "/etc/ssh/sshd_config" - fi - printf '%s\n' "$formatted_output" >> "/etc/ssh/sshd_config" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Find sshd_config included files - shell: |- - included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') - [[ -n $included_files ]] && ls $included_files || true - register: sshd_config_included_files - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - CJIS-5.5.6 - - NIST-800-171-3.1.13 - - NIST-800-171-3.5.4 - - NIST-800-53-AC-17(2) - - NIST-800-53-AC-17(a) - - NIST-800-53-CM-6(a) - - NIST-800-53-IA-5(1)(c) - - NIST-800-53-MA-4(6) - - NIST-800-53-SC-13 - - high_severity - - low_complexity - - low_disruption - - no_reboot_needed - - restrict_strategy - - sshd_allow_only_protocol2 - -- name: Comment conf from included files - replace: - path: '{{ item }}' - regexp: ^(\s*Protocol.*)$ - replace: '# \1' - loop: '{{ sshd_config_included_files.stdout_lines }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - CJIS-5.5.6 - - NIST-800-171-3.1.13 - - NIST-800-171-3.5.4 - - NIST-800-53-AC-17(2) - - NIST-800-53-AC-17(a) - - NIST-800-53-CM-6(a) - - NIST-800-53-IA-5(1)(c) - - NIST-800-53-MA-4(6) - - NIST-800-53-SC-13 - - high_severity - - low_complexity - - low_disruption - - no_reboot_needed - - restrict_strategy - - sshd_allow_only_protocol2 - -- name: Allow Only SSH Protocol 2 - block: - - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: false - regexp: (?i)^\s*Protocol\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config - create: false - regexp: (?i)^\s*Protocol\s+ - state: absent - when: dupes.found is defined and dupes.found > 1 - - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)^\s*Protocol\s+ - line: Protocol 2 - state: present - insertbefore: ^[#\s]*Match - validate: /usr/sbin/sshd -t -f %s - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - CJIS-5.5.6 - - NIST-800-171-3.1.13 - - NIST-800-171-3.5.4 - - NIST-800-53-AC-17(2) - - NIST-800-53-AC-17(a) - - NIST-800-53-CM-6(a) - - NIST-800-53-IA-5(1)(c) - - NIST-800-53-MA-4(6) - - NIST-800-53-SC-13 - - high_severity - - low_complexity - - low_disruption - - no_reboot_needed - - restrict_strategy - - sshd_allow_only_protocol2 - - - - - - - - - - - Disable Compression Or Set Compression to delayed - Compression is useful for slow network connections over long -distances but can cause performance issues on local LANs. If use of compression -is required, it should be enabled only after a user has authenticated; otherwise, -it should be disabled. To disable compression or delay compression until after -a user has successfully authenticated, add or correct the following line in the -/etc/ssh/sshd_config file: -Compression - 11 - 3 - 9 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - 3.1.12 - CCI-000366 - 164.308(a)(4)(i) - 164.308(b)(1) - 164.308(b)(3) - 164.310(b) - 164.312(e)(1) - 164.312(e)(2)(ii) - 4.3.4.3.2 - 4.3.4.3.3 - SR 7.6 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.14.2.2 - A.14.2.3 - A.14.2.4 - AC-17(a) - CM-7(a) - CM-7(b) - CM-6(a) - PR.IP-1 - SRG-OS-000480-GPOS-00227 - If compression is allowed in an SSH connection prior to authentication, -vulnerabilities in the compression software could result in compromise of the -system from an unauthenticated connection, potentially with root privileges. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -var_sshd_disable_compression='' - - -# Strip any search characters in the key arg so that the key can be replaced without -# adding any search characters to the config file. -stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^Compression") - -# shellcheck disable=SC2059 -printf -v formatted_output "%s %s" "$stripped_key" "$var_sshd_disable_compression" - -# If the key exists, change it. Otherwise, add it to the config_file. -# We search for the key string followed by a word boundary (matched by \>), -# so if we search for 'setting', 'setting2' won't match. -if LC_ALL=C grep -q -m 1 -i -e "^Compression\\>" "/etc/ssh/sshd_config"; then - escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") - LC_ALL=C sed -i --follow-symlinks "s/^Compression\\>.*/$escaped_formatted_output/gi" "/etc/ssh/sshd_config" -else - if [[ -s "/etc/ssh/sshd_config" ]] && [[ -n "$(tail -c 1 -- "/etc/ssh/sshd_config" || true)" ]]; then - LC_ALL=C sed -i --follow-symlinks '$a'\\ "/etc/ssh/sshd_config" - fi - printf '%s\n' "$formatted_output" >> "/etc/ssh/sshd_config" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: XCCDF Value var_sshd_disable_compression # promote to variable - set_fact: - var_sshd_disable_compression: !!str - tags: - - always - -- name: Find sshd_config included files - shell: |- - included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') - [[ -n $included_files ]] && ls $included_files || true - register: sshd_config_included_files - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.12 - - NIST-800-53-AC-17(a) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_disable_compression - -- name: Comment conf from included files - replace: - path: '{{ item }}' - regexp: ^(\s*Compression.*)$ - replace: '# \1' - loop: '{{ sshd_config_included_files.stdout_lines }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.12 - - NIST-800-53-AC-17(a) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_disable_compression - -- name: Disable Compression Or Set Compression to delayed - block: - - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: false - regexp: (?i)^\s*Compression\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config - create: false - regexp: (?i)^\s*Compression\s+ - state: absent - when: dupes.found is defined and dupes.found > 1 - - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)^\s*Compression\s+ - line: Compression {{ var_sshd_disable_compression }} - state: present - insertbefore: ^[#\s]*Match - validate: /usr/sbin/sshd -t -f %s - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.12 - - NIST-800-53-AC-17(a) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_disable_compression - - - - - - - - - - - - Disable SSH Access via Empty Passwords - Disallow SSH login with empty passwords. -The default SSH configuration disables logins with empty passwords. The appropriate -configuration is used if no value is set for PermitEmptyPasswords. - -To explicitly disallow SSH login from accounts with empty passwords, -add or correct the following line in - - -/etc/ssh/sshd_config: - - -PermitEmptyPasswords no -Any accounts with empty passwords should be disabled immediately, and PAM configuration -should prevent users from being able to assign themselves empty passwords. - NT007(R17) - 11 - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - 9 - 5.5.6 - APO01.06 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS05.02 - DSS05.04 - DSS05.05 - DSS05.07 - DSS06.02 - DSS06.03 - DSS06.06 - 3.1.1 - 3.1.5 - CCI-000366 - CCI-000766 - 164.308(a)(4)(i) - 164.308(b)(1) - 164.308(b)(3) - 164.310(b) - 164.312(e)(1) - 164.312(e)(2)(ii) - 4.3.3.2.2 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 5.2 - SR 7.6 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.1 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - AC-17(a) - CM-7(a) - CM-7(b) - CM-6(a) - PR.AC-4 - PR.AC-6 - PR.DS-5 - PR.IP-1 - PR.PT-3 - FIA_UAU.1 - Req-2.2.4 - 2.2.6 - SRG-OS-000106-GPOS-00053 - SRG-OS-000480-GPOS-00229 - SRG-OS-000480-GPOS-00227 - Configuring this setting for the SSH daemon provides additional assurance -that remote login via SSH will require a password, even in the event of -misconfiguration elsewhere. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Find the include keyword, extract from the line the glob expression representing included files. -# And if it is a relative path prepend '/etc/ssh/' -included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') -for included_file in ${included_files} ; do - - LC_ALL=C sed -i "/^\s*PermitEmptyPasswords/Id" "$included_file" -done - -if [ -e "/etc/ssh/sshd_config" ] ; then - - LC_ALL=C sed -i "/^\s*PermitEmptyPasswords\s\+/Id" "/etc/ssh/sshd_config" -else - touch "/etc/ssh/sshd_config" -fi -# make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" - -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" -# Insert before the line matching the regex '^Match'. -line_number="$(LC_ALL=C grep -n "^Match" "/etc/ssh/sshd_config.bak" | LC_ALL=C sed 's/:.*//g')" -if [ -z "$line_number" ]; then - # There was no match of '^Match', insert at - # the end of the file. - printf '%s\n' "PermitEmptyPasswords no" >> "/etc/ssh/sshd_config" -else - head -n "$(( line_number - 1 ))" "/etc/ssh/sshd_config.bak" > "/etc/ssh/sshd_config" - printf '%s\n' "PermitEmptyPasswords no" >> "/etc/ssh/sshd_config" - tail -n "+$(( line_number ))" "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" -fi -# Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Find sshd_config included files - shell: |- - included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') - [[ -n $included_files ]] && ls $included_files || true - register: sshd_config_included_files - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - CJIS-5.5.6 - - NIST-800-171-3.1.1 - - NIST-800-171-3.1.5 - - NIST-800-53-AC-17(a) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - PCI-DSS-Req-2.2.4 - - PCI-DSSv4-2.2.6 - - high_severity - - low_complexity - - low_disruption - - no_reboot_needed - - restrict_strategy - - sshd_disable_empty_passwords - -- name: Comment conf from included files - replace: - path: '{{ item }}' - regexp: ^(\s*PermitEmptyPasswords.*)$ - replace: '# \1' - loop: '{{ sshd_config_included_files.stdout_lines }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - CJIS-5.5.6 - - NIST-800-171-3.1.1 - - NIST-800-171-3.1.5 - - NIST-800-53-AC-17(a) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - PCI-DSS-Req-2.2.4 - - PCI-DSSv4-2.2.6 - - high_severity - - low_complexity - - low_disruption - - no_reboot_needed - - restrict_strategy - - sshd_disable_empty_passwords - -- name: Disable SSH Access via Empty Passwords - block: - - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: false - regexp: (?i)^\s*PermitEmptyPasswords\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config - create: false - regexp: (?i)^\s*PermitEmptyPasswords\s+ - state: absent - when: dupes.found is defined and dupes.found > 1 - - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)^\s*PermitEmptyPasswords\s+ - line: PermitEmptyPasswords no - state: present - insertbefore: ^[#\s]*Match - validate: /usr/sbin/sshd -t -f %s - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - CJIS-5.5.6 - - NIST-800-171-3.1.1 - - NIST-800-171-3.1.5 - - NIST-800-53-AC-17(a) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - PCI-DSS-Req-2.2.4 - - PCI-DSSv4-2.2.6 - - high_severity - - low_complexity - - low_disruption - - no_reboot_needed - - restrict_strategy - - sshd_disable_empty_passwords - - - - - - - - - - - Disable GSSAPI Authentication - Unless needed, SSH should not permit extraneous or unnecessary -authentication mechanisms like GSSAPI. - -The default SSH configuration disallows authentications based on GSSAPI. The appropriate -configuration is used if no value is set for GSSAPIAuthentication. - -To explicitly disable GSSAPI authentication, add or correct the following line in - - -/etc/ssh/sshd_config: - -GSSAPIAuthentication no - 11 - 3 - 9 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - 3.1.12 - CCI-000318 - CCI-000368 - CCI-001812 - CCI-001813 - CCI-001814 - CCI-000366 - 164.308(a)(4)(i) - 164.308(b)(1) - 164.308(b)(3) - 164.310(b) - 164.312(e)(1) - 164.312(e)(2)(ii) - 4.3.4.3.2 - 4.3.4.3.3 - SR 7.6 - 0418 - 1055 - 1402 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.14.2.2 - A.14.2.3 - A.14.2.4 - CM-7(a) - CM-7(b) - CM-6(a) - AC-17(a) - PR.IP-1 - FTP_ITC_EXT.1 - FCS_SSH_EXT.1.2 - SRG-OS-000364-GPOS-00151 - SRG-OS-000480-GPOS-00227 - GSSAPI authentication is used to provide additional authentication mechanisms to -applications. Allowing GSSAPI authentication through SSH exposes the system's -GSSAPI to remote hosts, increasing the attack surface of the system. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Find the include keyword, extract from the line the glob expression representing included files. -# And if it is a relative path prepend '/etc/ssh/' -included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') -for included_file in ${included_files} ; do - - LC_ALL=C sed -i "/^\s*GSSAPIAuthentication/Id" "$included_file" -done - -if [ -e "/etc/ssh/sshd_config" ] ; then - - LC_ALL=C sed -i "/^\s*GSSAPIAuthentication\s\+/Id" "/etc/ssh/sshd_config" -else - touch "/etc/ssh/sshd_config" -fi -# make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" - -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" -# Insert before the line matching the regex '^Match'. -line_number="$(LC_ALL=C grep -n "^Match" "/etc/ssh/sshd_config.bak" | LC_ALL=C sed 's/:.*//g')" -if [ -z "$line_number" ]; then - # There was no match of '^Match', insert at - # the end of the file. - printf '%s\n' "GSSAPIAuthentication no" >> "/etc/ssh/sshd_config" -else - head -n "$(( line_number - 1 ))" "/etc/ssh/sshd_config.bak" > "/etc/ssh/sshd_config" - printf '%s\n' "GSSAPIAuthentication no" >> "/etc/ssh/sshd_config" - tail -n "+$(( line_number ))" "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" -fi -# Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Find sshd_config included files - shell: |- - included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') - [[ -n $included_files ]] && ls $included_files || true - register: sshd_config_included_files - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.12 - - NIST-800-53-AC-17(a) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_disable_gssapi_auth - -- name: Comment conf from included files - replace: - path: '{{ item }}' - regexp: ^(\s*GSSAPIAuthentication.*)$ - replace: '# \1' - loop: '{{ sshd_config_included_files.stdout_lines }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.12 - - NIST-800-53-AC-17(a) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_disable_gssapi_auth - -- name: Disable GSSAPI Authentication - block: - - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: false - regexp: (?i)^\s*GSSAPIAuthentication\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config - create: false - regexp: (?i)^\s*GSSAPIAuthentication\s+ - state: absent - when: dupes.found is defined and dupes.found > 1 - - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)^\s*GSSAPIAuthentication\s+ - line: GSSAPIAuthentication no - state: present - insertbefore: ^[#\s]*Match - validate: /usr/sbin/sshd -t -f %s - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.12 - - NIST-800-53-AC-17(a) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_disable_gssapi_auth - - - - - - - - - - - Disable Kerberos Authentication - Unless needed, SSH should not permit extraneous or unnecessary -authentication mechanisms like Kerberos. - -The default SSH configuration disallows authentication validation through Kerberos. -The appropriate configuration is used if no value is set for KerberosAuthentication. - -To explicitly disable Kerberos authentication, add or correct the following line in - - -/etc/ssh/sshd_config: - -KerberosAuthentication no - 11 - 3 - 9 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - 3.1.12 - CCI-000318 - CCI-000368 - CCI-001812 - CCI-001813 - CCI-001814 - CCI-000366 - 164.308(a)(4)(i) - 164.308(b)(1) - 164.308(b)(3) - 164.310(b) - 164.312(e)(1) - 164.312(e)(2)(ii) - 4.3.4.3.2 - 4.3.4.3.3 - SR 7.6 - 0421 - 0422 - 0431 - 0974 - 1173 - 1401 - 1504 - 1505 - 1546 - 1557 - 1558 - 1559 - 1560 - 1561 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.14.2.2 - A.14.2.3 - A.14.2.4 - AC-17(a) - CM-7(a) - CM-7(b) - CM-6(a) - PR.IP-1 - FTP_ITC_EXT.1 - FCS_SSH_EXT.1.2 - SRG-OS-000364-GPOS-00151 - SRG-OS-000480-GPOS-00227 - Kerberos authentication for SSH is often implemented using GSSAPI. If Kerberos -is enabled through SSH, the SSH daemon provides a means of access to the -system's Kerberos implementation. -Configuring these settings for the SSH daemon provides additional assurance that remote logon via SSH will not use unused methods of authentication, even in the event of misconfiguration elsewhere. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Find the include keyword, extract from the line the glob expression representing included files. -# And if it is a relative path prepend '/etc/ssh/' -included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') -for included_file in ${included_files} ; do - - LC_ALL=C sed -i "/^\s*KerberosAuthentication/Id" "$included_file" -done - -if [ -e "/etc/ssh/sshd_config" ] ; then - - LC_ALL=C sed -i "/^\s*KerberosAuthentication\s\+/Id" "/etc/ssh/sshd_config" -else - touch "/etc/ssh/sshd_config" -fi -# make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" - -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" -# Insert before the line matching the regex '^Match'. -line_number="$(LC_ALL=C grep -n "^Match" "/etc/ssh/sshd_config.bak" | LC_ALL=C sed 's/:.*//g')" -if [ -z "$line_number" ]; then - # There was no match of '^Match', insert at - # the end of the file. - printf '%s\n' "KerberosAuthentication no" >> "/etc/ssh/sshd_config" -else - head -n "$(( line_number - 1 ))" "/etc/ssh/sshd_config.bak" > "/etc/ssh/sshd_config" - printf '%s\n' "KerberosAuthentication no" >> "/etc/ssh/sshd_config" - tail -n "+$(( line_number ))" "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" -fi -# Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Find sshd_config included files - shell: |- - included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') - [[ -n $included_files ]] && ls $included_files || true - register: sshd_config_included_files - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.12 - - NIST-800-53-AC-17(a) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_disable_kerb_auth - -- name: Comment conf from included files - replace: - path: '{{ item }}' - regexp: ^(\s*KerberosAuthentication.*)$ - replace: '# \1' - loop: '{{ sshd_config_included_files.stdout_lines }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.12 - - NIST-800-53-AC-17(a) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_disable_kerb_auth - -- name: Disable Kerberos Authentication - block: - - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: false - regexp: (?i)^\s*KerberosAuthentication\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config - create: false - regexp: (?i)^\s*KerberosAuthentication\s+ - state: absent - when: dupes.found is defined and dupes.found > 1 - - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)^\s*KerberosAuthentication\s+ - line: KerberosAuthentication no - state: present - insertbefore: ^[#\s]*Match - validate: /usr/sbin/sshd -t -f %s - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.12 - - NIST-800-53-AC-17(a) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_disable_kerb_auth - - - - - - - - - - - Disable PubkeyAuthentication Authentication - Unless needed, SSH should not permit extraneous or unnecessary -authentication mechanisms. To disable PubkeyAuthentication authentication, add or -correct the following line in - - -/etc/ssh/sshd_config: - -PubkeyAuthentication no - PubkeyAuthentication authentication is used to provide additional authentication mechanisms to -applications. Allowing PubkeyAuthentication authentication through SSH allows users to -generate their own authentication tokens, increasing the attack surface of the system. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Find the include keyword, extract from the line the glob expression representing included files. -# And if it is a relative path prepend '/etc/ssh/' -included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') -for included_file in ${included_files} ; do - - LC_ALL=C sed -i "/^\s*PubkeyAuthentication/Id" "$included_file" -done - -if [ -e "/etc/ssh/sshd_config" ] ; then - - LC_ALL=C sed -i "/^\s*PubkeyAuthentication\s\+/Id" "/etc/ssh/sshd_config" -else - touch "/etc/ssh/sshd_config" -fi -# make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" - -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" -# Insert before the line matching the regex '^Match'. -line_number="$(LC_ALL=C grep -n "^Match" "/etc/ssh/sshd_config.bak" | LC_ALL=C sed 's/:.*//g')" -if [ -z "$line_number" ]; then - # There was no match of '^Match', insert at - # the end of the file. - printf '%s\n' "PubkeyAuthentication no" >> "/etc/ssh/sshd_config" -else - head -n "$(( line_number - 1 ))" "/etc/ssh/sshd_config.bak" > "/etc/ssh/sshd_config" - printf '%s\n' "PubkeyAuthentication no" >> "/etc/ssh/sshd_config" - tail -n "+$(( line_number ))" "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" -fi -# Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Find sshd_config included files - shell: |- - included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') - [[ -n $included_files ]] && ls $included_files || true - register: sshd_config_included_files - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_disable_pubkey_auth - -- name: Comment conf from included files - replace: - path: '{{ item }}' - regexp: ^(\s*PubkeyAuthentication.*)$ - replace: '# \1' - loop: '{{ sshd_config_included_files.stdout_lines }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_disable_pubkey_auth - -- name: Disable PubkeyAuthentication Authentication - block: - - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: false - regexp: (?i)^\s*PubkeyAuthentication\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config - create: false - regexp: (?i)^\s*PubkeyAuthentication\s+ - state: absent - when: dupes.found is defined and dupes.found > 1 - - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)^\s*PubkeyAuthentication\s+ - line: PubkeyAuthentication no - state: present - insertbefore: ^[#\s]*Match - validate: /usr/sbin/sshd -t -f %s - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_disable_pubkey_auth - - - - - - - - - - - Disable SSH Support for .rhosts Files - SSH can emulate the behavior of the obsolete rsh -command in allowing users to enable insecure access to their -accounts via .rhosts files. - -The default SSH configuration disables support for .rhosts. The appropriate -configuration is used if no value is set for IgnoreRhosts. - -To explicitly disable support for .rhosts files, add or correct the following line in - - -/etc/ssh/sshd_config: - -IgnoreRhosts yes - 11 - 12 - 14 - 15 - 16 - 18 - 3 - 5 - 9 - 5.5.6 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS05.02 - DSS05.04 - DSS05.05 - DSS05.07 - DSS06.03 - DSS06.06 - 3.1.12 - CCI-000366 - 4.3.3.2.2 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 7.6 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.6.1.2 - A.7.1.1 - A.9.1.2 - A.9.2.1 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - AC-17(a) - CM-7(a) - CM-7(b) - CM-6(a) - PR.AC-4 - PR.AC-6 - PR.IP-1 - PR.PT-3 - FIA_UAU.1 - 2.2.6 - SRG-OS-000480-GPOS-00227 - SSH trust relationships mean a compromise on one host -can allow an attacker to move trivially to other hosts. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Find the include keyword, extract from the line the glob expression representing included files. -# And if it is a relative path prepend '/etc/ssh/' -included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') -for included_file in ${included_files} ; do - - LC_ALL=C sed -i "/^\s*IgnoreRhosts/Id" "$included_file" -done - -if [ -e "/etc/ssh/sshd_config" ] ; then - - LC_ALL=C sed -i "/^\s*IgnoreRhosts\s\+/Id" "/etc/ssh/sshd_config" -else - touch "/etc/ssh/sshd_config" -fi -# make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" - -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" -# Insert before the line matching the regex '^Match'. -line_number="$(LC_ALL=C grep -n "^Match" "/etc/ssh/sshd_config.bak" | LC_ALL=C sed 's/:.*//g')" -if [ -z "$line_number" ]; then - # There was no match of '^Match', insert at - # the end of the file. - printf '%s\n' "IgnoreRhosts yes" >> "/etc/ssh/sshd_config" -else - head -n "$(( line_number - 1 ))" "/etc/ssh/sshd_config.bak" > "/etc/ssh/sshd_config" - printf '%s\n' "IgnoreRhosts yes" >> "/etc/ssh/sshd_config" - tail -n "+$(( line_number ))" "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" -fi -# Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Find sshd_config included files - shell: |- - included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') - [[ -n $included_files ]] && ls $included_files || true - register: sshd_config_included_files - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - CJIS-5.5.6 - - NIST-800-171-3.1.12 - - NIST-800-53-AC-17(a) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - PCI-DSSv4-2.2.6 - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_disable_rhosts - -- name: Comment conf from included files - replace: - path: '{{ item }}' - regexp: ^(\s*IgnoreRhosts.*)$ - replace: '# \1' - loop: '{{ sshd_config_included_files.stdout_lines }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - CJIS-5.5.6 - - NIST-800-171-3.1.12 - - NIST-800-53-AC-17(a) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - PCI-DSSv4-2.2.6 - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_disable_rhosts - -- name: Disable SSH Support for .rhosts Files - block: - - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: false - regexp: (?i)^\s*IgnoreRhosts\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config - create: false - regexp: (?i)^\s*IgnoreRhosts\s+ - state: absent - when: dupes.found is defined and dupes.found > 1 - - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)^\s*IgnoreRhosts\s+ - line: IgnoreRhosts yes - state: present - insertbefore: ^[#\s]*Match - validate: /usr/sbin/sshd -t -f %s - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - CJIS-5.5.6 - - NIST-800-171-3.1.12 - - NIST-800-53-AC-17(a) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - PCI-DSSv4-2.2.6 - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_disable_rhosts - - - - - - - - - - - Disable SSH Support for Rhosts RSA Authentication - SSH can allow authentication through the obsolete rsh -command through the use of the authenticating user's SSH keys. This should be disabled. - -To ensure this behavior is disabled, add or correct the -following line in /etc/ssh/sshd_config: -RhostsRSAAuthentication no - As of openssh-server version 7.4 and above, -the RhostsRSAAuthentication option has been deprecated, and the line -RhostsRSAAuthentication no in /etc/ssh/sshd_config is not -necessary. - 11 - 3 - 9 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - 3.1.12 - CCI-000366 - 164.308(a)(4)(i) - 164.308(b)(1) - 164.308(b)(3) - 164.310(b) - 164.312(e)(1) - 164.312(e)(2)(ii) - 4.3.4.3.2 - 4.3.4.3.3 - SR 7.6 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.14.2.2 - A.14.2.3 - A.14.2.4 - AC-17(a) - CM-7(a) - CM-7(b) - CM-6(a) - PR.IP-1 - FIA_UAU.1 - SRG-OS-000480-GPOS-00227 - Configuring this setting for the SSH daemon provides additional -assurance that remote login via SSH will require a password, even -in the event of misconfiguration elsewhere. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Strip any search characters in the key arg so that the key can be replaced without -# adding any search characters to the config file. -stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^RhostsRSAAuthentication") - -# shellcheck disable=SC2059 -printf -v formatted_output "%s %s" "$stripped_key" "no" - -# If the key exists, change it. Otherwise, add it to the config_file. -# We search for the key string followed by a word boundary (matched by \>), -# so if we search for 'setting', 'setting2' won't match. -if LC_ALL=C grep -q -m 1 -i -e "^RhostsRSAAuthentication\\>" "/etc/ssh/sshd_config"; then - escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") - LC_ALL=C sed -i --follow-symlinks "s/^RhostsRSAAuthentication\\>.*/$escaped_formatted_output/gi" "/etc/ssh/sshd_config" -else - if [[ -s "/etc/ssh/sshd_config" ]] && [[ -n "$(tail -c 1 -- "/etc/ssh/sshd_config" || true)" ]]; then - LC_ALL=C sed -i --follow-symlinks '$a'\\ "/etc/ssh/sshd_config" - fi - printf '%s\n' "$formatted_output" >> "/etc/ssh/sshd_config" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Find sshd_config included files - shell: |- - included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') - [[ -n $included_files ]] && ls $included_files || true - register: sshd_config_included_files - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.12 - - NIST-800-53-AC-17(a) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_disable_rhosts_rsa - -- name: Comment conf from included files - replace: - path: '{{ item }}' - regexp: ^(\s*RhostsRSAAuthentication.*)$ - replace: '# \1' - loop: '{{ sshd_config_included_files.stdout_lines }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.12 - - NIST-800-53-AC-17(a) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_disable_rhosts_rsa - -- name: Disable SSH Support for Rhosts RSA Authentication - block: - - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: false - regexp: (?i)^\s*RhostsRSAAuthentication\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config - create: false - regexp: (?i)^\s*RhostsRSAAuthentication\s+ - state: absent - when: dupes.found is defined and dupes.found > 1 - - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)^\s*RhostsRSAAuthentication\s+ - line: RhostsRSAAuthentication no - state: present - insertbefore: ^[#\s]*Match - validate: /usr/sbin/sshd -t -f %s - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.12 - - NIST-800-53-AC-17(a) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_disable_rhosts_rsa - - - - - - - - - - - Disable SSH Root Login - The root user should never be allowed to login to a -system directly over a network. -To disable root login via SSH, add or correct the following line in - - -/etc/ssh/sshd_config: - -PermitRootLogin no - BP28(R19) - NT007(R21) - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - 5.5.6 - APO01.06 - DSS05.02 - DSS05.04 - DSS05.05 - DSS05.07 - DSS05.10 - DSS06.02 - DSS06.03 - DSS06.06 - DSS06.10 - 3.1.1 - 3.1.5 - CCI-000366 - CCI-000770 - 164.308(a)(4)(i) - 164.308(b)(1) - 164.308(b)(3) - 164.310(b) - 164.312(e)(1) - 164.312(e)(2)(ii) - 4.3.3.2.2 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 5.2 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.18.1.4 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.1 - A.9.2.2 - A.9.2.3 - A.9.2.4 - A.9.2.6 - A.9.3.1 - A.9.4.1 - A.9.4.2 - A.9.4.3 - A.9.4.4 - A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.2.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 - CIP-007-3 R5.2 - CIP-007-3 R5.3.1 - CIP-007-3 R5.3.2 - CIP-007-3 R5.3.3 - AC-6(2) - AC-17(a) - IA-2 - IA-2(5) - CM-7(a) - CM-7(b) - CM-6(a) - PR.AC-1 - PR.AC-4 - PR.AC-6 - PR.AC-7 - PR.DS-5 - PR.PT-3 - FAU_GEN.1 - Req-2.2.4 - 2.2.6 - SRG-OS-000109-GPOS-00056 - SRG-OS-000480-GPOS-00227 - SRG-APP-000148-CTR-000335 - SRG-APP-000190-CTR-000500 - Even though the communications channel may be encrypted, an additional layer of -security is gained by extending the policy of not logging directly on as root. -In addition, logging in with a user-specific account provides individual -accountability of actions performed on the system and also helps to minimize -direct attack attempts on root's password. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Find the include keyword, extract from the line the glob expression representing included files. -# And if it is a relative path prepend '/etc/ssh/' -included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') -for included_file in ${included_files} ; do - - LC_ALL=C sed -i "/^\s*PermitRootLogin/Id" "$included_file" -done - -if [ -e "/etc/ssh/sshd_config" ] ; then - - LC_ALL=C sed -i "/^\s*PermitRootLogin\s\+/Id" "/etc/ssh/sshd_config" -else - touch "/etc/ssh/sshd_config" -fi -# make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" - -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" -# Insert before the line matching the regex '^Match'. -line_number="$(LC_ALL=C grep -n "^Match" "/etc/ssh/sshd_config.bak" | LC_ALL=C sed 's/:.*//g')" -if [ -z "$line_number" ]; then - # There was no match of '^Match', insert at - # the end of the file. - printf '%s\n' "PermitRootLogin no" >> "/etc/ssh/sshd_config" -else - head -n "$(( line_number - 1 ))" "/etc/ssh/sshd_config.bak" > "/etc/ssh/sshd_config" - printf '%s\n' "PermitRootLogin no" >> "/etc/ssh/sshd_config" - tail -n "+$(( line_number ))" "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" -fi -# Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Find sshd_config included files - shell: |- - included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') - [[ -n $included_files ]] && ls $included_files || true - register: sshd_config_included_files - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - CJIS-5.5.6 - - NIST-800-171-3.1.1 - - NIST-800-171-3.1.5 - - NIST-800-53-AC-17(a) - - NIST-800-53-AC-6(2) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-IA-2 - - NIST-800-53-IA-2(5) - - PCI-DSS-Req-2.2.4 - - PCI-DSSv4-2.2.6 - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_disable_root_login - -- name: Comment conf from included files - replace: - path: '{{ item }}' - regexp: ^(\s*PermitRootLogin.*)$ - replace: '# \1' - loop: '{{ sshd_config_included_files.stdout_lines }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - CJIS-5.5.6 - - NIST-800-171-3.1.1 - - NIST-800-171-3.1.5 - - NIST-800-53-AC-17(a) - - NIST-800-53-AC-6(2) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-IA-2 - - NIST-800-53-IA-2(5) - - PCI-DSS-Req-2.2.4 - - PCI-DSSv4-2.2.6 - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_disable_root_login - -- name: Disable SSH Root Login - block: - - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: false - regexp: (?i)^\s*PermitRootLogin\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config - create: false - regexp: (?i)^\s*PermitRootLogin\s+ - state: absent - when: dupes.found is defined and dupes.found > 1 - - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)^\s*PermitRootLogin\s+ - line: PermitRootLogin no - state: present - insertbefore: ^[#\s]*Match - validate: /usr/sbin/sshd -t -f %s - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - CJIS-5.5.6 - - NIST-800-171-3.1.1 - - NIST-800-171-3.1.5 - - NIST-800-53-AC-17(a) - - NIST-800-53-AC-6(2) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-IA-2 - - NIST-800-53-IA-2(5) - - PCI-DSS-Req-2.2.4 - - PCI-DSSv4-2.2.6 - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_disable_root_login - - - - - - - - - - - Disable SSH root Login with a Password (Insecure) - To disable password-based root logins over SSH, add or correct the following line in - - -/etc/ssh/sshd_config: - -PermitRootLogin prohibit-password - While this disables password-based root logins, direct root logins -through other means such as through SSH keys or GSSAPI will still be -permitted. Permitting any sort of root login remotely opens up the -root account to attack. -To fully disable direct root logins over SSH (which is considered a -best practice) and prevent remote attacks against the root account, -see CCE-27100-7, CCE-27445-6, CCE-80901-2, and similar. - Even though the communications channel may be encrypted, an additional -layer of security is gained by preventing use of a password. -This also helps to minimize direct attack attempts on root's password. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Find the include keyword, extract from the line the glob expression representing included files. -# And if it is a relative path prepend '/etc/ssh/' -included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') -for included_file in ${included_files} ; do - - LC_ALL=C sed -i "/^\s*PermitRootLogin/Id" "$included_file" -done - -if [ -e "/etc/ssh/sshd_config" ] ; then - - LC_ALL=C sed -i "/^\s*PermitRootLogin\s\+/Id" "/etc/ssh/sshd_config" -else - touch "/etc/ssh/sshd_config" -fi -# make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" - -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" -# Insert before the line matching the regex '^Match'. -line_number="$(LC_ALL=C grep -n "^Match" "/etc/ssh/sshd_config.bak" | LC_ALL=C sed 's/:.*//g')" -if [ -z "$line_number" ]; then - # There was no match of '^Match', insert at - # the end of the file. - printf '%s\n' "PermitRootLogin prohibit-password" >> "/etc/ssh/sshd_config" -else - head -n "$(( line_number - 1 ))" "/etc/ssh/sshd_config.bak" > "/etc/ssh/sshd_config" - printf '%s\n' "PermitRootLogin prohibit-password" >> "/etc/ssh/sshd_config" - tail -n "+$(( line_number ))" "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" -fi -# Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Find sshd_config included files - shell: |- - included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') - [[ -n $included_files ]] && ls $included_files || true - register: sshd_config_included_files - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_disable_root_password_login - -- name: Comment conf from included files - replace: - path: '{{ item }}' - regexp: ^(\s*PermitRootLogin.*)$ - replace: '# \1' - loop: '{{ sshd_config_included_files.stdout_lines }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_disable_root_password_login - -- name: Disable SSH root Login with a Password (Insecure) - block: - - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: false - regexp: (?i)^\s*PermitRootLogin\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config - create: false - regexp: (?i)^\s*PermitRootLogin\s+ - state: absent - when: dupes.found is defined and dupes.found > 1 - - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)^\s*PermitRootLogin\s+ - line: PermitRootLogin prohibit-password - state: present - insertbefore: ^[#\s]*Match - validate: /usr/sbin/sshd -t -f %s - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_disable_root_password_login - - - - - - - - - - - Disable SSH TCP Forwarding - The AllowTcpForwarding parameter specifies whether TCP forwarding is permitted. -To disable TCP forwarding, add or correct the following line in - - -/etc/ssh/sshd_config: - -AllowTcpForwarding no - 2.2.6 - Leaving port forwarding enabled can expose the organization to security risks and back-doors. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Find the include keyword, extract from the line the glob expression representing included files. -# And if it is a relative path prepend '/etc/ssh/' -included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') -for included_file in ${included_files} ; do - - LC_ALL=C sed -i "/^\s*AllowTcpForwarding/Id" "$included_file" -done - -if [ -e "/etc/ssh/sshd_config" ] ; then - - LC_ALL=C sed -i "/^\s*AllowTcpForwarding\s\+/Id" "/etc/ssh/sshd_config" -else - touch "/etc/ssh/sshd_config" -fi -# make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" - -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" -# Insert before the line matching the regex '^Match'. -line_number="$(LC_ALL=C grep -n "^Match" "/etc/ssh/sshd_config.bak" | LC_ALL=C sed 's/:.*//g')" -if [ -z "$line_number" ]; then - # There was no match of '^Match', insert at - # the end of the file. - printf '%s\n' "AllowTcpForwarding no" >> "/etc/ssh/sshd_config" -else - head -n "$(( line_number - 1 ))" "/etc/ssh/sshd_config.bak" > "/etc/ssh/sshd_config" - printf '%s\n' "AllowTcpForwarding no" >> "/etc/ssh/sshd_config" - tail -n "+$(( line_number ))" "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" -fi -# Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Find sshd_config included files - shell: |- - included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') - [[ -n $included_files ]] && ls $included_files || true - register: sshd_config_included_files - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - PCI-DSSv4-2.2.6 - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_disable_tcp_forwarding - -- name: Comment conf from included files - replace: - path: '{{ item }}' - regexp: ^(\s*AllowTcpForwarding.*)$ - replace: '# \1' - loop: '{{ sshd_config_included_files.stdout_lines }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - PCI-DSSv4-2.2.6 - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_disable_tcp_forwarding - -- name: Disable SSH TCP Forwarding - block: - - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: false - regexp: (?i)^\s*AllowTcpForwarding\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config - create: false - regexp: (?i)^\s*AllowTcpForwarding\s+ - state: absent - when: dupes.found is defined and dupes.found > 1 - - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)^\s*AllowTcpForwarding\s+ - line: AllowTcpForwarding no - state: present - insertbefore: ^[#\s]*Match - validate: /usr/sbin/sshd -t -f %s - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - PCI-DSSv4-2.2.6 - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_disable_tcp_forwarding - - - - - - - - - - - Disable SSH Support for User Known Hosts - SSH can allow system users to connect to systems if a cache of the remote -systems public keys is available. This should be disabled. - -To ensure this behavior is disabled, add or correct the following line in - - -/etc/ssh/sshd_config: - -IgnoreUserKnownHosts yes - 11 - 3 - 9 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - 3.1.12 - CCI-000366 - 164.308(a)(4)(i) - 164.308(b)(1) - 164.308(b)(3) - 164.310(b) - 164.312(e)(1) - 164.312(e)(2)(ii) - 4.3.4.3.2 - 4.3.4.3.3 - SR 7.6 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.14.2.2 - A.14.2.3 - A.14.2.4 - AC-17(a) - CM-7(a) - CM-7(b) - CM-6(a) - PR.IP-1 - FIA_UAU.1 - SRG-OS-000480-GPOS-00227 - Configuring this setting for the SSH daemon provides additional -assurance that remote login via SSH will require a password, even -in the event of misconfiguration elsewhere. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Find the include keyword, extract from the line the glob expression representing included files. -# And if it is a relative path prepend '/etc/ssh/' -included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') -for included_file in ${included_files} ; do - - LC_ALL=C sed -i "/^\s*IgnoreUserKnownHosts/Id" "$included_file" -done - -if [ -e "/etc/ssh/sshd_config" ] ; then - - LC_ALL=C sed -i "/^\s*IgnoreUserKnownHosts\s\+/Id" "/etc/ssh/sshd_config" -else - touch "/etc/ssh/sshd_config" -fi -# make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" - -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" -# Insert before the line matching the regex '^Match'. -line_number="$(LC_ALL=C grep -n "^Match" "/etc/ssh/sshd_config.bak" | LC_ALL=C sed 's/:.*//g')" -if [ -z "$line_number" ]; then - # There was no match of '^Match', insert at - # the end of the file. - printf '%s\n' "IgnoreUserKnownHosts yes" >> "/etc/ssh/sshd_config" -else - head -n "$(( line_number - 1 ))" "/etc/ssh/sshd_config.bak" > "/etc/ssh/sshd_config" - printf '%s\n' "IgnoreUserKnownHosts yes" >> "/etc/ssh/sshd_config" - tail -n "+$(( line_number ))" "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" -fi -# Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Find sshd_config included files - shell: |- - included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') - [[ -n $included_files ]] && ls $included_files || true - register: sshd_config_included_files - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.12 - - NIST-800-53-AC-17(a) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_disable_user_known_hosts - -- name: Comment conf from included files - replace: - path: '{{ item }}' - regexp: ^(\s*IgnoreUserKnownHosts.*)$ - replace: '# \1' - loop: '{{ sshd_config_included_files.stdout_lines }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.12 - - NIST-800-53-AC-17(a) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_disable_user_known_hosts - -- name: Disable SSH Support for User Known Hosts - block: - - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: false - regexp: (?i)^\s*IgnoreUserKnownHosts\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config - create: false - regexp: (?i)^\s*IgnoreUserKnownHosts\s+ - state: absent - when: dupes.found is defined and dupes.found > 1 - - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)^\s*IgnoreUserKnownHosts\s+ - line: IgnoreUserKnownHosts yes - state: present - insertbefore: ^[#\s]*Match - validate: /usr/sbin/sshd -t -f %s - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.12 - - NIST-800-53-AC-17(a) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_disable_user_known_hosts - - - - - - - - - - - Disable X11 Forwarding - The X11Forwarding parameter provides the ability to tunnel X11 traffic -through the connection to enable remote graphic connections. -SSH has the capability to encrypt remote X11 connections when SSH's -X11Forwarding option is enabled. - -The default SSH configuration disables X11Forwarding. The appropriate -configuration is used if no value is set for X11Forwarding. - -To explicitly disable X11 Forwarding, add or correct the following line in - - -/etc/ssh/sshd_config: - -X11Forwarding no - CCI-000366 - CM-6(b) - 2.2.4 - SRG-OS-000480-GPOS-00227 - Disable X11 forwarding unless there is an operational requirement to use X11 -applications directly. There is a small risk that the remote X11 servers of -users who are logged in via SSH with X11 forwarding could be compromised by -other users on the X11 server. Note that even if X11 forwarding is disabled, -users can always install their own forwarders. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Find the include keyword, extract from the line the glob expression representing included files. -# And if it is a relative path prepend '/etc/ssh/' -included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') -for included_file in ${included_files} ; do - - LC_ALL=C sed -i "/^\s*X11Forwarding/Id" "$included_file" -done - -if [ -e "/etc/ssh/sshd_config" ] ; then - - LC_ALL=C sed -i "/^\s*X11Forwarding\s\+/Id" "/etc/ssh/sshd_config" -else - touch "/etc/ssh/sshd_config" -fi -# make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" - -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" -# Insert before the line matching the regex '^Match'. -line_number="$(LC_ALL=C grep -n "^Match" "/etc/ssh/sshd_config.bak" | LC_ALL=C sed 's/:.*//g')" -if [ -z "$line_number" ]; then - # There was no match of '^Match', insert at - # the end of the file. - printf '%s\n' "X11Forwarding no" >> "/etc/ssh/sshd_config" -else - head -n "$(( line_number - 1 ))" "/etc/ssh/sshd_config.bak" > "/etc/ssh/sshd_config" - printf '%s\n' "X11Forwarding no" >> "/etc/ssh/sshd_config" - tail -n "+$(( line_number ))" "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" -fi -# Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Find sshd_config included files - shell: |- - included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') - [[ -n $included_files ]] && ls $included_files || true - register: sshd_config_included_files - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-CM-6(b) - - PCI-DSSv4-2.2.4 - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_disable_x11_forwarding - -- name: Comment conf from included files - replace: - path: '{{ item }}' - regexp: ^(\s*X11Forwarding.*)$ - replace: '# \1' - loop: '{{ sshd_config_included_files.stdout_lines }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-CM-6(b) - - PCI-DSSv4-2.2.4 - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_disable_x11_forwarding - -- name: Disable X11 Forwarding - block: - - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: false - regexp: (?i)^\s*X11Forwarding\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config - create: false - regexp: (?i)^\s*X11Forwarding\s+ - state: absent - when: dupes.found is defined and dupes.found > 1 - - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)^\s*X11Forwarding\s+ - line: X11Forwarding no - state: present - insertbefore: ^[#\s]*Match - validate: /usr/sbin/sshd -t -f %s - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-CM-6(b) - - PCI-DSSv4-2.2.4 - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_disable_x11_forwarding - - - - - - - - - - - Do Not Allow SSH Environment Options - Ensure that users are not able to override environment variables of the SSH daemon. - -The default SSH configuration disables environment processing. The appropriate -configuration is used if no value is set for PermitUserEnvironment. - -To explicitly disable Environment options, add or correct the following - - -/etc/ssh/sshd_config: - -PermitUserEnvironment no - 11 - 3 - 9 - 5.5.6 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - 3.1.12 - CCI-000366 - 164.308(a)(4)(i) - 164.308(b)(1) - 164.308(b)(3) - 164.310(b) - 164.312(e)(1) - 164.312(e)(2)(ii) - 4.3.4.3.2 - 4.3.4.3.3 - SR 7.6 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.14.2.2 - A.14.2.3 - A.14.2.4 - AC-17(a) - CM-7(a) - CM-7(b) - CM-6(a) - PR.IP-1 - Req-2.2.4 - 2.2.6 - SRG-OS-000480-GPOS-00229 - SSH environment options potentially allow users to bypass -access restriction in some configurations. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Find the include keyword, extract from the line the glob expression representing included files. -# And if it is a relative path prepend '/etc/ssh/' -included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') -for included_file in ${included_files} ; do - - LC_ALL=C sed -i "/^\s*PermitUserEnvironment/Id" "$included_file" -done - -if [ -e "/etc/ssh/sshd_config" ] ; then - - LC_ALL=C sed -i "/^\s*PermitUserEnvironment\s\+/Id" "/etc/ssh/sshd_config" -else - touch "/etc/ssh/sshd_config" -fi -# make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" - -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" -# Insert before the line matching the regex '^Match'. -line_number="$(LC_ALL=C grep -n "^Match" "/etc/ssh/sshd_config.bak" | LC_ALL=C sed 's/:.*//g')" -if [ -z "$line_number" ]; then - # There was no match of '^Match', insert at - # the end of the file. - printf '%s\n' "PermitUserEnvironment no" >> "/etc/ssh/sshd_config" -else - head -n "$(( line_number - 1 ))" "/etc/ssh/sshd_config.bak" > "/etc/ssh/sshd_config" - printf '%s\n' "PermitUserEnvironment no" >> "/etc/ssh/sshd_config" - tail -n "+$(( line_number ))" "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" -fi -# Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Find sshd_config included files - shell: |- - included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') - [[ -n $included_files ]] && ls $included_files || true - register: sshd_config_included_files - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - CJIS-5.5.6 - - NIST-800-171-3.1.12 - - NIST-800-53-AC-17(a) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - PCI-DSS-Req-2.2.4 - - PCI-DSSv4-2.2.6 - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_do_not_permit_user_env - -- name: Comment conf from included files - replace: - path: '{{ item }}' - regexp: ^(\s*PermitUserEnvironment.*)$ - replace: '# \1' - loop: '{{ sshd_config_included_files.stdout_lines }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - CJIS-5.5.6 - - NIST-800-171-3.1.12 - - NIST-800-53-AC-17(a) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - PCI-DSS-Req-2.2.4 - - PCI-DSSv4-2.2.6 - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_do_not_permit_user_env - -- name: Do Not Allow SSH Environment Options - block: - - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: false - regexp: (?i)^\s*PermitUserEnvironment\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config - create: false - regexp: (?i)^\s*PermitUserEnvironment\s+ - state: absent - when: dupes.found is defined and dupes.found > 1 - - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)^\s*PermitUserEnvironment\s+ - line: PermitUserEnvironment no - state: present - insertbefore: ^[#\s]*Match - validate: /usr/sbin/sshd -t -f %s - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - CJIS-5.5.6 - - NIST-800-171-3.1.12 - - NIST-800-53-AC-17(a) - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - PCI-DSS-Req-2.2.4 - - PCI-DSSv4-2.2.6 - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_do_not_permit_user_env - - - - - - - - - - - Enable GSSAPI Authentication - Sites setup to use Kerberos or other GSSAPI Authenticaion require setting -sshd to accept this authentication. -To enable GSSAPI authentication, add or correct the following line in - - -/etc/ssh/sshd_config: - -GSSAPIAuthentication yes - Kerberos authentication for SSH is often implemented using GSSAPI. If -Kerberos is enabled through SSH, the SSH daemon provides a means of access -to the system's Kerberos implementation. Vulnerabilities in the system's -Kerberos implementations may be subject to exploitation. - -For enterprises, Kerberos is often enabled and used with GSSAPI for -centralized user account management which may necessitate enabling of -GSSAPI functionality in SSH. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Find the include keyword, extract from the line the glob expression representing included files. -# And if it is a relative path prepend '/etc/ssh/' -included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') -for included_file in ${included_files} ; do - - LC_ALL=C sed -i "/^\s*GSSAPIAuthentication/Id" "$included_file" -done - -if [ -e "/etc/ssh/sshd_config" ] ; then - - LC_ALL=C sed -i "/^\s*GSSAPIAuthentication\s\+/Id" "/etc/ssh/sshd_config" -else - touch "/etc/ssh/sshd_config" -fi -# make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" - -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" -# Insert before the line matching the regex '^Match'. -line_number="$(LC_ALL=C grep -n "^Match" "/etc/ssh/sshd_config.bak" | LC_ALL=C sed 's/:.*//g')" -if [ -z "$line_number" ]; then - # There was no match of '^Match', insert at - # the end of the file. - printf '%s\n' "GSSAPIAuthentication yes" >> "/etc/ssh/sshd_config" -else - head -n "$(( line_number - 1 ))" "/etc/ssh/sshd_config.bak" > "/etc/ssh/sshd_config" - printf '%s\n' "GSSAPIAuthentication yes" >> "/etc/ssh/sshd_config" - tail -n "+$(( line_number ))" "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" -fi -# Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Find sshd_config included files - shell: |- - included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') - [[ -n $included_files ]] && ls $included_files || true - register: sshd_config_included_files - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_enable_gssapi_auth - -- name: Comment conf from included files - replace: - path: '{{ item }}' - regexp: ^(\s*GSSAPIAuthentication.*)$ - replace: '# \1' - loop: '{{ sshd_config_included_files.stdout_lines }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_enable_gssapi_auth - -- name: Enable GSSAPI Authentication - block: - - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: false - regexp: (?i)^\s*GSSAPIAuthentication\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config - create: false - regexp: (?i)^\s*GSSAPIAuthentication\s+ - state: absent - when: dupes.found is defined and dupes.found > 1 - - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)^\s*GSSAPIAuthentication\s+ - line: GSSAPIAuthentication yes - state: present - insertbefore: ^[#\s]*Match - validate: /usr/sbin/sshd -t -f %s - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_enable_gssapi_auth - - - - - - - - - - - Enable PAM - UsePAM Enables the Pluggable Authentication Module interface. If set to “yes” this will -enable PAM authentication using ChallengeResponseAuthentication and -PasswordAuthentication in addition to PAM account and session module processing for all -authentication types. - -To enable PAM authentication, add or correct the following line in - - -/etc/ssh/sshd_config: - -UsePAM yes - CCI-000877 - 2.2.4 - SRG-OS-000125-GPOS-00065 - When UsePAM is set to yes, PAM runs through account and session types properly. This is -important if you want to restrict access to services based off of IP, time or other factors of -the account. Additionally, you can make sure users inherit certain environment variables -on login or disallow access to the server. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Find the include keyword, extract from the line the glob expression representing included files. -# And if it is a relative path prepend '/etc/ssh/' -included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') -for included_file in ${included_files} ; do - - LC_ALL=C sed -i "/^\s*UsePAM/Id" "$included_file" -done - -if [ -e "/etc/ssh/sshd_config" ] ; then - - LC_ALL=C sed -i "/^\s*UsePAM\s\+/Id" "/etc/ssh/sshd_config" -else - touch "/etc/ssh/sshd_config" -fi -# make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" - -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" -# Insert before the line matching the regex '^Match'. -line_number="$(LC_ALL=C grep -n "^Match" "/etc/ssh/sshd_config.bak" | LC_ALL=C sed 's/:.*//g')" -if [ -z "$line_number" ]; then - # There was no match of '^Match', insert at - # the end of the file. - printf '%s\n' "UsePAM yes" >> "/etc/ssh/sshd_config" -else - head -n "$(( line_number - 1 ))" "/etc/ssh/sshd_config.bak" > "/etc/ssh/sshd_config" - printf '%s\n' "UsePAM yes" >> "/etc/ssh/sshd_config" - tail -n "+$(( line_number ))" "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" -fi -# Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Find sshd_config included files - shell: |- - included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') - [[ -n $included_files ]] && ls $included_files || true - register: sshd_config_included_files - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - PCI-DSSv4-2.2.4 - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_enable_pam - -- name: Comment conf from included files - replace: - path: '{{ item }}' - regexp: ^(\s*UsePAM.*)$ - replace: '# \1' - loop: '{{ sshd_config_included_files.stdout_lines }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - PCI-DSSv4-2.2.4 - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_enable_pam - -- name: Enable PAM - block: - - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: false - regexp: (?i)^\s*UsePAM\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config - create: false - regexp: (?i)^\s*UsePAM\s+ - state: absent - when: dupes.found is defined and dupes.found > 1 - - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)^\s*UsePAM\s+ - line: UsePAM yes - state: present - insertbefore: ^[#\s]*Match - validate: /usr/sbin/sshd -t -f %s - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - PCI-DSSv4-2.2.4 - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_enable_pam - - - - - - - - - - - Enable Public Key Authentication - Enable SSH login with public keys. - -The default SSH configuration enables authentication based on public keys. The appropriate -configuration is used if no value is set for PubkeyAuthentication. - -To explicitly enable Public Key Authentication, add or correct the following - - -/etc/ssh/sshd_config: - -PubkeyAuthentication yes - CCI-000765 - CCI-000766 - CCI-000767 - CCI-000768 - SRG-OS-000105-GPOS-00052 - SRG-OS-000106-GPOS-00053 - SRG-OS-000107-GPOS-00054 - SRG-OS-000108-GPOS-00055 - Without the use of multifactor authentication, the ease of access to -privileged functions is greatly increased. Multifactor authentication -requires using two or more factors to achieve authentication. -A privileged account is defined as an information system account with -authorizations of a privileged user. -The DoD CAC with DoD-approved PKI is an example of multifactor -authentication. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Find the include keyword, extract from the line the glob expression representing included files. -# And if it is a relative path prepend '/etc/ssh/' -included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') -for included_file in ${included_files} ; do - - LC_ALL=C sed -i "/^\s*PubkeyAuthentication/Id" "$included_file" -done - -if [ -e "/etc/ssh/sshd_config" ] ; then - - LC_ALL=C sed -i "/^\s*PubkeyAuthentication\s\+/Id" "/etc/ssh/sshd_config" -else - touch "/etc/ssh/sshd_config" -fi -# make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" - -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" -# Insert before the line matching the regex '^Match'. -line_number="$(LC_ALL=C grep -n "^Match" "/etc/ssh/sshd_config.bak" | LC_ALL=C sed 's/:.*//g')" -if [ -z "$line_number" ]; then - # There was no match of '^Match', insert at - # the end of the file. - printf '%s\n' "PubkeyAuthentication yes" >> "/etc/ssh/sshd_config" -else - head -n "$(( line_number - 1 ))" "/etc/ssh/sshd_config.bak" > "/etc/ssh/sshd_config" - printf '%s\n' "PubkeyAuthentication yes" >> "/etc/ssh/sshd_config" - tail -n "+$(( line_number ))" "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" -fi -# Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Find sshd_config included files - shell: |- - included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') - [[ -n $included_files ]] && ls $included_files || true - register: sshd_config_included_files - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_enable_pubkey_auth - -- name: Comment conf from included files - replace: - path: '{{ item }}' - regexp: ^(\s*PubkeyAuthentication.*)$ - replace: '# \1' - loop: '{{ sshd_config_included_files.stdout_lines }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_enable_pubkey_auth - -- name: Enable Public Key Authentication - block: - - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: false - regexp: (?i)^\s*PubkeyAuthentication\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config - create: false - regexp: (?i)^\s*PubkeyAuthentication\s+ - state: absent - when: dupes.found is defined and dupes.found > 1 - - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)^\s*PubkeyAuthentication\s+ - line: PubkeyAuthentication yes - state: present - insertbefore: ^[#\s]*Match - validate: /usr/sbin/sshd -t -f %s - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_enable_pubkey_auth - - - - - - - - - - - Enable Use of Strict Mode Checking - SSHs StrictModes option checks file and ownership permissions in -the user's home directory .ssh folder before accepting login. If world- -writable permissions are found, logon is rejected. - -The default SSH configuration has StrictModes enabled. The appropriate -configuration is used if no value is set for StrictModes. - -To explicitly enable StrictModes in SSH, add or correct the following line in - - -/etc/ssh/sshd_config: - -StrictModes yes - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - APO01.06 - DSS05.04 - DSS05.07 - DSS06.02 - 3.1.12 - CCI-000366 - 164.308(a)(4)(i) - 164.308(b)(1) - 164.308(b)(3) - 164.310(b) - 164.312(e)(1) - 164.312(e)(2)(ii) - 4.3.3.7.3 - SR 2.1 - SR 5.2 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 - AC-6 - AC-17(a) - CM-6(a) - PR.AC-4 - PR.DS-5 - SRG-OS-000480-GPOS-00227 - If other users have access to modify user-specific SSH configuration files, they -may be able to log into the system as another user. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Find the include keyword, extract from the line the glob expression representing included files. -# And if it is a relative path prepend '/etc/ssh/' -included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') -for included_file in ${included_files} ; do - - LC_ALL=C sed -i "/^\s*StrictModes/Id" "$included_file" -done - -if [ -e "/etc/ssh/sshd_config" ] ; then - - LC_ALL=C sed -i "/^\s*StrictModes\s\+/Id" "/etc/ssh/sshd_config" -else - touch "/etc/ssh/sshd_config" -fi -# make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" - -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" -# Insert before the line matching the regex '^Match'. -line_number="$(LC_ALL=C grep -n "^Match" "/etc/ssh/sshd_config.bak" | LC_ALL=C sed 's/:.*//g')" -if [ -z "$line_number" ]; then - # There was no match of '^Match', insert at - # the end of the file. - printf '%s\n' "StrictModes yes" >> "/etc/ssh/sshd_config" -else - head -n "$(( line_number - 1 ))" "/etc/ssh/sshd_config.bak" > "/etc/ssh/sshd_config" - printf '%s\n' "StrictModes yes" >> "/etc/ssh/sshd_config" - tail -n "+$(( line_number ))" "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" -fi -# Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Find sshd_config included files - shell: |- - included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') - [[ -n $included_files ]] && ls $included_files || true - register: sshd_config_included_files - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.12 - - NIST-800-53-AC-17(a) - - NIST-800-53-AC-6 - - NIST-800-53-CM-6(a) - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_enable_strictmodes - -- name: Comment conf from included files - replace: - path: '{{ item }}' - regexp: ^(\s*StrictModes.*)$ - replace: '# \1' - loop: '{{ sshd_config_included_files.stdout_lines }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.12 - - NIST-800-53-AC-17(a) - - NIST-800-53-AC-6 - - NIST-800-53-CM-6(a) - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_enable_strictmodes - -- name: Enable Use of Strict Mode Checking - block: - - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: false - regexp: (?i)^\s*StrictModes\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config - create: false - regexp: (?i)^\s*StrictModes\s+ - state: absent - when: dupes.found is defined and dupes.found > 1 - - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)^\s*StrictModes\s+ - line: StrictModes yes - state: present - insertbefore: ^[#\s]*Match - validate: /usr/sbin/sshd -t -f %s - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.12 - - NIST-800-53-AC-17(a) - - NIST-800-53-AC-6 - - NIST-800-53-CM-6(a) - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_enable_strictmodes - - - - - - - - - - - Enable SSH Warning Banner - To enable the warning banner and ensure it is consistent -across the system, add or correct the following line in - - -/etc/ssh/sshd_config: - -Banner /etc/issue -Another section contains information on how to create an -appropriate system-wide warning banner. - 1 - 12 - 15 - 16 - 5.5.6 - DSS05.04 - DSS05.10 - DSS06.10 - 3.1.9 - CCI-000048 - CCI-000050 - CCI-001384 - CCI-001385 - CCI-001386 - CCI-001387 - CCI-001388 - 164.308(a)(4)(i) - 164.308(b)(1) - 164.308(b)(3) - 164.310(b) - 164.312(e)(1) - 164.312(e)(2)(ii) - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - SR 1.1 - SR 1.10 - SR 1.2 - SR 1.5 - SR 1.7 - SR 1.8 - SR 1.9 - A.18.1.4 - A.9.2.1 - A.9.2.4 - A.9.3.1 - A.9.4.2 - A.9.4.3 - AC-8(a) - AC-8(c) - AC-17(a) - CM-6(a) - PR.AC-7 - FTA_TAB.1 - Req-2.2.4 - 2.2.6 - SRG-OS-000023-GPOS-00006 - SRG-OS-000228-GPOS-00088 - The warning message reinforces policy awareness during the logon process and -facilitates possible legal action against attackers. Alternatively, systems -whose ownership should not be obvious should ensure usage of a banner that does -not provide easy attribution. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Find the include keyword, extract from the line the glob expression representing included files. -# And if it is a relative path prepend '/etc/ssh/' -included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') -for included_file in ${included_files} ; do - - LC_ALL=C sed -i "/^\s*Banner/Id" "$included_file" -done - -if [ -e "/etc/ssh/sshd_config" ] ; then - - LC_ALL=C sed -i "/^\s*Banner\s\+/Id" "/etc/ssh/sshd_config" -else - touch "/etc/ssh/sshd_config" -fi -# make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" - -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" -# Insert before the line matching the regex '^Match'. -line_number="$(LC_ALL=C grep -n "^Match" "/etc/ssh/sshd_config.bak" | LC_ALL=C sed 's/:.*//g')" -if [ -z "$line_number" ]; then - # There was no match of '^Match', insert at - # the end of the file. - printf '%s\n' "Banner /etc/issue" >> "/etc/ssh/sshd_config" -else - head -n "$(( line_number - 1 ))" "/etc/ssh/sshd_config.bak" > "/etc/ssh/sshd_config" - printf '%s\n' "Banner /etc/issue" >> "/etc/ssh/sshd_config" - tail -n "+$(( line_number ))" "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" -fi -# Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Find sshd_config included files - shell: |- - included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') - [[ -n $included_files ]] && ls $included_files || true - register: sshd_config_included_files - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - CJIS-5.5.6 - - NIST-800-171-3.1.9 - - NIST-800-53-AC-17(a) - - NIST-800-53-AC-8(a) - - NIST-800-53-AC-8(c) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-2.2.4 - - PCI-DSSv4-2.2.6 - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_enable_warning_banner - -- name: Comment conf from included files - replace: - path: '{{ item }}' - regexp: ^(\s*Banner.*)$ - replace: '# \1' - loop: '{{ sshd_config_included_files.stdout_lines }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - CJIS-5.5.6 - - NIST-800-171-3.1.9 - - NIST-800-53-AC-17(a) - - NIST-800-53-AC-8(a) - - NIST-800-53-AC-8(c) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-2.2.4 - - PCI-DSSv4-2.2.6 - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_enable_warning_banner - -- name: Enable SSH Warning Banner - block: - - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: false - regexp: (?i)^\s*Banner\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config - create: false - regexp: (?i)^\s*Banner\s+ - state: absent - when: dupes.found is defined and dupes.found > 1 - - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)^\s*Banner\s+ - line: Banner /etc/issue - state: present - insertbefore: ^[#\s]*Match - validate: /usr/sbin/sshd -t -f %s - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - CJIS-5.5.6 - - NIST-800-171-3.1.9 - - NIST-800-53-AC-17(a) - - NIST-800-53-AC-8(a) - - NIST-800-53-AC-8(c) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-2.2.4 - - PCI-DSSv4-2.2.6 - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_enable_warning_banner - - - - - - - - - - - Enable SSH Warning Banner - To enable the warning banner and ensure it is consistent -across the system, add or correct the following line in - -/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf: - -Banner /etc/issue.net -Another section contains information on how to create an -appropriate system-wide warning banner. - 5.5.6 - DSS05.04 - DSS05.10 - DSS06.10 - 3.1.9 - CCI-000048 - CCI-000050 - CCI-001384 - CCI-001385 - CCI-001386 - CCI-001387 - CCI-001388 - 164.308(a)(4)(i) - 164.308(b)(1) - 164.308(b)(3) - 164.310(b) - 164.312(e)(1) - 164.312(e)(2)(ii) - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - SR 1.1 - SR 1.10 - SR 1.2 - SR 1.5 - SR 1.7 - SR 1.8 - SR 1.9 - A.18.1.4 - A.9.2.1 - A.9.2.4 - A.9.3.1 - A.9.4.2 - A.9.4.3 - AC-8(a) - AC-8(c) - AC-17(a) - CM-6(a) - PR.AC-7 - FTA_TAB.1 - SRG-OS-000023-GPOS-00006 - SRG-OS-000228-GPOS-00088 - The warning message reinforces policy awareness during the logon process and -facilitates possible legal action against attackers. Alternatively, systems -whose ownership should not be obvious should ensure usage of a banner that does -not provide easy attribution. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Find the include keyword, extract from the line the glob expression representing included files. -# And if it is a relative path prepend '/etc/ssh/' -included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') -for included_file in ${included_files} ; do - - LC_ALL=C sed -i "/^\s*Banner/Id" "$included_file" -done - -if [ -e "/etc/ssh/sshd_config" ] ; then - - LC_ALL=C sed -i "/^\s*Banner\s\+/Id" "/etc/ssh/sshd_config" -else - touch "/etc/ssh/sshd_config" -fi -# make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" - -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" -# Insert before the line matching the regex '^Match'. -line_number="$(LC_ALL=C grep -n "^Match" "/etc/ssh/sshd_config.bak" | LC_ALL=C sed 's/:.*//g')" -if [ -z "$line_number" ]; then - # There was no match of '^Match', insert at - # the end of the file. - printf '%s\n' "Banner /etc/issue.net" >> "/etc/ssh/sshd_config" -else - head -n "$(( line_number - 1 ))" "/etc/ssh/sshd_config.bak" > "/etc/ssh/sshd_config" - printf '%s\n' "Banner /etc/issue.net" >> "/etc/ssh/sshd_config" - tail -n "+$(( line_number ))" "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" -fi -# Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Find sshd_config included files - shell: |- - included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') - [[ -n $included_files ]] && ls $included_files || true - register: sshd_config_included_files - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - CJIS-5.5.6 - - NIST-800-171-3.1.9 - - NIST-800-53-AC-17(a) - - NIST-800-53-AC-8(a) - - NIST-800-53-AC-8(c) - - NIST-800-53-CM-6(a) - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_enable_warning_banner_net - -- name: Comment conf from included files - replace: - path: '{{ item }}' - regexp: ^(\s*Banner.*)$ - replace: '# \1' - loop: '{{ sshd_config_included_files.stdout_lines }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - CJIS-5.5.6 - - NIST-800-171-3.1.9 - - NIST-800-53-AC-17(a) - - NIST-800-53-AC-8(a) - - NIST-800-53-AC-8(c) - - NIST-800-53-CM-6(a) - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_enable_warning_banner_net - -- name: Enable SSH Warning Banner - block: - - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: false - regexp: (?i)^\s*Banner\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config - create: false - regexp: (?i)^\s*Banner\s+ - state: absent - when: dupes.found is defined and dupes.found > 1 - - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)^\s*Banner\s+ - line: Banner /etc/issue.net - state: present - insertbefore: ^[#\s]*Match - validate: /usr/sbin/sshd -t -f %s - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - CJIS-5.5.6 - - NIST-800-171-3.1.9 - - NIST-800-53-AC-17(a) - - NIST-800-53-AC-8(a) - - NIST-800-53-AC-8(c) - - NIST-800-53-CM-6(a) - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_enable_warning_banner_net - - - - - - - - - - - Enable Encrypted X11 Forwarding - By default, remote X11 connections are not encrypted when initiated -by users. SSH has the capability to encrypt remote X11 connections when SSH's -X11Forwarding option is enabled. - -To enable X11 Forwarding, add or correct the following line in - - -/etc/ssh/sshd_config: - -X11Forwarding yes - 1 - 11 - 12 - 13 - 15 - 16 - 18 - 20 - 3 - 4 - 6 - 9 - BAI03.08 - BAI07.04 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS03.01 - 3.1.13 - CCI-000366 - 4.3.4.3.2 - 4.3.4.3.3 - 4.4.3.3 - SR 7.6 - A.12.1.1 - A.12.1.2 - A.12.1.4 - A.12.5.1 - A.12.6.2 - A.13.1.1 - A.13.1.2 - A.14.2.2 - A.14.2.3 - A.14.2.4 - CIP-007-3 R7.1 - CM-6(a) - AC-17(a) - AC-17(2) - DE.AE-1 - PR.DS-7 - PR.IP-1 - SRG-OS-000480-GPOS-00227 - Non-encrypted X displays allow an attacker to capture keystrokes and to execute commands -remotely. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Find the include keyword, extract from the line the glob expression representing included files. -# And if it is a relative path prepend '/etc/ssh/' -included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') -for included_file in ${included_files} ; do - - LC_ALL=C sed -i "/^\s*X11Forwarding/Id" "$included_file" -done - -if [ -e "/etc/ssh/sshd_config" ] ; then - - LC_ALL=C sed -i "/^\s*X11Forwarding\s\+/Id" "/etc/ssh/sshd_config" -else - touch "/etc/ssh/sshd_config" -fi -# make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" - -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" -# Insert before the line matching the regex '^Match'. -line_number="$(LC_ALL=C grep -n "^Match" "/etc/ssh/sshd_config.bak" | LC_ALL=C sed 's/:.*//g')" -if [ -z "$line_number" ]; then - # There was no match of '^Match', insert at - # the end of the file. - printf '%s\n' "X11Forwarding yes" >> "/etc/ssh/sshd_config" -else - head -n "$(( line_number - 1 ))" "/etc/ssh/sshd_config.bak" > "/etc/ssh/sshd_config" - printf '%s\n' "X11Forwarding yes" >> "/etc/ssh/sshd_config" - tail -n "+$(( line_number ))" "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" -fi -# Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Find sshd_config included files - shell: |- - included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') - [[ -n $included_files ]] && ls $included_files || true - register: sshd_config_included_files - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.13 - - NIST-800-53-AC-17(2) - - NIST-800-53-AC-17(a) - - NIST-800-53-CM-6(a) - - high_severity - - low_complexity - - low_disruption - - no_reboot_needed - - restrict_strategy - - sshd_enable_x11_forwarding - -- name: Comment conf from included files - replace: - path: '{{ item }}' - regexp: ^(\s*X11Forwarding.*)$ - replace: '# \1' - loop: '{{ sshd_config_included_files.stdout_lines }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.13 - - NIST-800-53-AC-17(2) - - NIST-800-53-AC-17(a) - - NIST-800-53-CM-6(a) - - high_severity - - low_complexity - - low_disruption - - no_reboot_needed - - restrict_strategy - - sshd_enable_x11_forwarding - -- name: Enable Encrypted X11 Forwarding - block: - - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: false - regexp: (?i)^\s*X11Forwarding\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config - create: false - regexp: (?i)^\s*X11Forwarding\s+ - state: absent - when: dupes.found is defined and dupes.found > 1 - - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)^\s*X11Forwarding\s+ - line: X11Forwarding yes - state: present - insertbefore: ^[#\s]*Match - validate: /usr/sbin/sshd -t -f %s - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.13 - - NIST-800-53-AC-17(2) - - NIST-800-53-AC-17(a) - - NIST-800-53-CM-6(a) - - high_severity - - low_complexity - - low_disruption - - no_reboot_needed - - restrict_strategy - - sshd_enable_x11_forwarding - - - - - - - - - - - Limit Users' SSH Access - By default, the SSH configuration allows any user with an account -to access the system. There are several options available to limit -which users and group can access the system via SSH. It is -recommended that at least one of the following options be leveraged: -- AllowUsers variable gives the system administrator the option of - allowing specific users to ssh into the system. The list consists of - space separated user names. Numeric user IDs are not recognized with - this variable. If a system administrator wants to restrict user - access further by specifically allowing a user's access only from a - particular host, the entry can be specified in the form of user@host. -- AllowGroups variable gives the system administrator the option of - allowing specific groups of users to ssh into the system. The list - consists of space separated group names. Numeric group IDs are not - recognized with this variable. -- DenyUsers variable gives the system administrator the option of - denying specific users to ssh into the system. The list consists of - space separated user names. Numeric user IDs are not recognized with - this variable. If a system administrator wants to restrict user - access further by specifically denying a user's access from a - particular host, the entry can be specified in the form of user@host. -- DenyGroups variable gives the system administrator the option of - denying specific groups of users to ssh into the system. The list - consists of space separated group names. Numeric group IDs are not - recognized with this variable. - 11 - 12 - 14 - 15 - 16 - 18 - 3 - 5 - DSS05.02 - DSS05.04 - DSS05.05 - DSS05.07 - DSS06.03 - DSS06.06 - 3.1.12 - 4.3.3.2.2 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - A.6.1.2 - A.7.1.1 - A.9.1.2 - A.9.2.1 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.2.3 - CIP-004-6 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.2 - CIP-007-3 R5.2 - CIP-007-3 R5.3.1 - CIP-007-3 R5.3.2 - CIP-007-3 R5.3.3 - AC-3 - CM-6(a) - PR.AC-4 - PR.AC-6 - PR.PT-3 - Req-2.2.4 - 2.2.6 - Specifying which accounts are allowed SSH access into the system reduces the -possibility of unauthorized access to the system. - - - - - - - - - Enable SSH Print Last Log - Ensure that SSH will display the date and time of the last successful account logon. - -The default SSH configuration enables print of the date and time of the last login. -The appropriate configuration is used if no value is set for PrintLastLog. - -To explicitly enable LastLog in SSH, add or correct the following line in - - -/etc/ssh/sshd_config: - -PrintLastLog yes - 1 - 12 - 15 - 16 - DSS05.04 - DSS05.10 - DSS06.10 - CCI-000052 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - SR 1.1 - SR 1.10 - SR 1.2 - SR 1.5 - SR 1.7 - SR 1.8 - SR 1.9 - A.18.1.4 - A.9.2.1 - A.9.2.4 - A.9.3.1 - A.9.4.2 - A.9.4.3 - AC-9 - AC-9(1) - PR.AC-7 - SRG-OS-000480-GPOS-00227 - Providing users feedback on when account accesses last occurred facilitates user -recognition and reporting of unauthorized account use. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Find the include keyword, extract from the line the glob expression representing included files. -# And if it is a relative path prepend '/etc/ssh/' -included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') -for included_file in ${included_files} ; do - - LC_ALL=C sed -i "/^\s*PrintLastLog/Id" "$included_file" -done - -if [ -e "/etc/ssh/sshd_config" ] ; then - - LC_ALL=C sed -i "/^\s*PrintLastLog\s\+/Id" "/etc/ssh/sshd_config" -else - touch "/etc/ssh/sshd_config" -fi -# make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" - -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" -# Insert before the line matching the regex '^Match'. -line_number="$(LC_ALL=C grep -n "^Match" "/etc/ssh/sshd_config.bak" | LC_ALL=C sed 's/:.*//g')" -if [ -z "$line_number" ]; then - # There was no match of '^Match', insert at - # the end of the file. - printf '%s\n' "PrintLastLog yes" >> "/etc/ssh/sshd_config" -else - head -n "$(( line_number - 1 ))" "/etc/ssh/sshd_config.bak" > "/etc/ssh/sshd_config" - printf '%s\n' "PrintLastLog yes" >> "/etc/ssh/sshd_config" - tail -n "+$(( line_number ))" "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" -fi -# Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Find sshd_config included files - shell: |- - included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') - [[ -n $included_files ]] && ls $included_files || true - register: sshd_config_included_files - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-9 - - NIST-800-53-AC-9(1) - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_print_last_log - -- name: Comment conf from included files - replace: - path: '{{ item }}' - regexp: ^(\s*PrintLastLog.*)$ - replace: '# \1' - loop: '{{ sshd_config_included_files.stdout_lines }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-9 - - NIST-800-53-AC-9(1) - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_print_last_log - -- name: Enable SSH Print Last Log - block: - - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: false - regexp: (?i)^\s*PrintLastLog\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config - create: false - regexp: (?i)^\s*PrintLastLog\s+ - state: absent - when: dupes.found is defined and dupes.found > 1 - - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)^\s*PrintLastLog\s+ - line: PrintLastLog yes - state: present - insertbefore: ^[#\s]*Match - validate: /usr/sbin/sshd -t -f %s - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-9 - - NIST-800-53-AC-9(1) - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_print_last_log - - - - - - - - - - - Force frequent session key renegotiation - The RekeyLimit parameter specifies how often -the session key of the is renegotiated, both in terms of -amount of data that may be transmitted and the time -elapsed. -To decrease the default limits, add or correct the following line in - - -/etc/ssh/sshd_config: - -RekeyLimit - CCI-000068 - FCS_SSH_EXT.1.8 - SRG-OS-000480-GPOS-00227 - SRG-OS-000033-GPOS-00014 - By decreasing the limit based on the amount of data and enabling -time-based limit, effects of potential attacks against -encryption keys are limited. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -var_rekey_limit_size='' -var_rekey_limit_time='' - - - - -# Find the include keyword, extract from the line the glob expression representing included files. -# And if it is a relative path prepend '/etc/ssh/' -included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') -for included_file in ${included_files} ; do - - LC_ALL=C sed -i "/^\s*RekeyLimit/Id" "$included_file" -done - -if [ -e "/etc/ssh/sshd_config" ] ; then - - LC_ALL=C sed -i "/^\s*RekeyLimit\s\+/Id" "/etc/ssh/sshd_config" -else - touch "/etc/ssh/sshd_config" -fi -# make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" - -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" -# Insert before the line matching the regex '^Match'. -line_number="$(LC_ALL=C grep -n "^Match" "/etc/ssh/sshd_config.bak" | LC_ALL=C sed 's/:.*//g')" -if [ -z "$line_number" ]; then - # There was no match of '^Match', insert at - # the end of the file. - printf '%s\n' "RekeyLimit $var_rekey_limit_size $var_rekey_limit_time" >> "/etc/ssh/sshd_config" -else - head -n "$(( line_number - 1 ))" "/etc/ssh/sshd_config.bak" > "/etc/ssh/sshd_config" - printf '%s\n' "RekeyLimit $var_rekey_limit_size $var_rekey_limit_time" >> "/etc/ssh/sshd_config" - tail -n "+$(( line_number ))" "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" -fi -# Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: XCCDF Value var_rekey_limit_size # promote to variable - set_fact: - var_rekey_limit_size: !!str - tags: - - always -- name: XCCDF Value var_rekey_limit_time # promote to variable - set_fact: - var_rekey_limit_time: !!str - tags: - - always - -- name: Find sshd_config included files - shell: |- - included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') - [[ -n $included_files ]] && ls $included_files || true - register: sshd_config_included_files - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - configure_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - sshd_rekey_limit - -- name: Comment conf from included files - replace: - path: '{{ item }}' - regexp: ^(\s*RekeyLimit.*)$ - replace: '# \1' - loop: '{{ sshd_config_included_files.stdout_lines }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - configure_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - sshd_rekey_limit - -- name: Force frequent session key renegotiation - block: - - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: false - regexp: (?i)^\s*RekeyLimit\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config - create: false - regexp: (?i)^\s*RekeyLimit\s+ - state: absent - when: dupes.found is defined and dupes.found > 1 - - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)^\s*RekeyLimit\s+ - line: RekeyLimit {{ var_rekey_limit_size }} {{ var_rekey_limit_time }} - state: present - insertbefore: ^[#\s]*Match - validate: /usr/sbin/sshd -t -f %s - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - configure_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - sshd_rekey_limit - - - - - - - - - - - - - Ensure SSH LoginGraceTime is configured - The LoginGraceTime parameter to the SSH server specifies the time allowed for successful authentication to -the SSH server. The longer the Grace period is the more open unauthenticated connections -can exist. Like other session controls in this session the Grace Period should be limited to -appropriate limits to ensure the service is available for needed access. - Setting the LoginGraceTime parameter to a low number will minimize the risk of successful -brute force attacks to the SSH server. It will also limit the number of concurrent -unauthenticated connections. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -var_sshd_set_login_grace_time='' - - -if [ -e "/etc/ssh/sshd_config" ] ; then - - LC_ALL=C sed -i "/^\s*LoginGraceTime\s\+/Id" "/etc/ssh/sshd_config" -else - touch "/etc/ssh/sshd_config" -fi -# make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" - -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" -# Insert before the line matching the regex '^Match'. -line_number="$(LC_ALL=C grep -n "^Match" "/etc/ssh/sshd_config.bak" | LC_ALL=C sed 's/:.*//g')" -if [ -z "$line_number" ]; then - # There was no match of '^Match', insert at - # the end of the file. - printf '%s\n' "LoginGraceTime $var_sshd_set_login_grace_time" >> "/etc/ssh/sshd_config" -else - head -n "$(( line_number - 1 ))" "/etc/ssh/sshd_config.bak" > "/etc/ssh/sshd_config" - printf '%s\n' "LoginGraceTime $var_sshd_set_login_grace_time" >> "/etc/ssh/sshd_config" - tail -n "+$(( line_number ))" "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" -fi -# Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: XCCDF Value var_sshd_set_login_grace_time # promote to variable - set_fact: - var_sshd_set_login_grace_time: !!str - tags: - - always - -- name: Find sshd_config included files - shell: |- - included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') - [[ -n $included_files ]] && ls $included_files || true - register: sshd_config_included_files - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_set_login_grace_time - -- name: Comment conf from included files - replace: - path: '{{ item }}' - regexp: ^(\s*LoginGraceTime.*)$ - replace: '# \1' - loop: '{{ sshd_config_included_files.stdout_lines }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_set_login_grace_time - -- name: Ensure SSH LoginGraceTime is configured - block: - - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: false - regexp: (?i)^\s*LoginGraceTime\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config - create: false - regexp: (?i)^\s*LoginGraceTime\s+ - state: absent - when: dupes.found is defined and dupes.found > 1 - - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)^\s*LoginGraceTime\s+ - line: LoginGraceTime {{ var_sshd_set_login_grace_time }} - state: present - insertbefore: ^[#\s]*Match - validate: /usr/sbin/sshd -t -f %s - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_set_login_grace_time - - - - - - - - - - - - Set LogLevel to INFO - The INFO parameter specifices that record login and logout activity will be logged. - -The default SSH configuration sets the log level to INFO. The appropriate -configuration is used if no value is set for LogLevel. - -To explicitly specify the log level in SSH, add or correct the following line in - - -/etc/ssh/sshd_config: - -LogLevel INFO - AC-17(a) - CM-6(a) - SSH provides several logging levels with varying amounts of verbosity. DEBUG is specifically -not recommended other than strictly for debugging SSH communications since it provides -so much data that it is difficult to identify important security information. INFO level is the -basic level that only records login activity of SSH users. In many situations, such as Incident -Response, it is important to determine when a particular user was active on a system. The -logout record can eliminate those users who disconnected, which helps narrow the field. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Find the include keyword, extract from the line the glob expression representing included files. -# And if it is a relative path prepend '/etc/ssh/' -included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') -for included_file in ${included_files} ; do - - LC_ALL=C sed -i "/^\s*LogLevel/Id" "$included_file" -done - -if [ -e "/etc/ssh/sshd_config" ] ; then - - LC_ALL=C sed -i "/^\s*LogLevel\s\+/Id" "/etc/ssh/sshd_config" -else - touch "/etc/ssh/sshd_config" -fi -# make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" - -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" -# Insert before the line matching the regex '^Match'. -line_number="$(LC_ALL=C grep -n "^Match" "/etc/ssh/sshd_config.bak" | LC_ALL=C sed 's/:.*//g')" -if [ -z "$line_number" ]; then - # There was no match of '^Match', insert at - # the end of the file. - printf '%s\n' "LogLevel INFO" >> "/etc/ssh/sshd_config" -else - head -n "$(( line_number - 1 ))" "/etc/ssh/sshd_config.bak" > "/etc/ssh/sshd_config" - printf '%s\n' "LogLevel INFO" >> "/etc/ssh/sshd_config" - tail -n "+$(( line_number ))" "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" -fi -# Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Find sshd_config included files - shell: |- - included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') - [[ -n $included_files ]] && ls $included_files || true - register: sshd_config_included_files - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-17(a) - - NIST-800-53-CM-6(a) - - low_complexity - - low_disruption - - low_severity - - no_reboot_needed - - restrict_strategy - - sshd_set_loglevel_info - -- name: Comment conf from included files - replace: - path: '{{ item }}' - regexp: ^(\s*LogLevel.*)$ - replace: '# \1' - loop: '{{ sshd_config_included_files.stdout_lines }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-17(a) - - NIST-800-53-CM-6(a) - - low_complexity - - low_disruption - - low_severity - - no_reboot_needed - - restrict_strategy - - sshd_set_loglevel_info - -- name: Set LogLevel to INFO - block: - - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: false - regexp: (?i)^\s*LogLevel\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config - create: false - regexp: (?i)^\s*LogLevel\s+ - state: absent - when: dupes.found is defined and dupes.found > 1 - - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)^\s*LogLevel\s+ - line: LogLevel INFO - state: present - insertbefore: ^[#\s]*Match - validate: /usr/sbin/sshd -t -f %s - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-17(a) - - NIST-800-53-CM-6(a) - - low_complexity - - low_disruption - - low_severity - - no_reboot_needed - - restrict_strategy - - sshd_set_loglevel_info - - - - - - - - - - - Set SSH Daemon LogLevel to VERBOSE - The VERBOSE parameter configures the SSH daemon to record login and logout activity. -To specify the log level in -SSH, add or correct the following line in - - -/etc/ssh/sshd_config: - -LogLevel VERBOSE - CCI-000067 - CIP-007-3 R7.1 - AC-17(a) - AC-17(1) - CM-6(a) - Req-2.2.4 - 2.2.6 - SRG-OS-000032-GPOS-00013 - SSH provides several logging levels with varying amounts of verbosity. DEBUG is specifically -not recommended other than strictly for debugging SSH communications since it provides -so much data that it is difficult to identify important security information. INFO or -VERBOSE level is the basic level that only records login activity of SSH users. In many -situations, such as Incident Response, it is important to determine when a particular user was active -on a system. The logout record can eliminate those users who disconnected, which helps narrow the -field. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Find the include keyword, extract from the line the glob expression representing included files. -# And if it is a relative path prepend '/etc/ssh/' -included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') -for included_file in ${included_files} ; do - - LC_ALL=C sed -i "/^\s*LogLevel/Id" "$included_file" -done - -if [ -e "/etc/ssh/sshd_config" ] ; then - - LC_ALL=C sed -i "/^\s*LogLevel\s\+/Id" "/etc/ssh/sshd_config" -else - touch "/etc/ssh/sshd_config" -fi -# make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" - -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" -# Insert before the line matching the regex '^Match'. -line_number="$(LC_ALL=C grep -n "^Match" "/etc/ssh/sshd_config.bak" | LC_ALL=C sed 's/:.*//g')" -if [ -z "$line_number" ]; then - # There was no match of '^Match', insert at - # the end of the file. - printf '%s\n' "LogLevel VERBOSE" >> "/etc/ssh/sshd_config" -else - head -n "$(( line_number - 1 ))" "/etc/ssh/sshd_config.bak" > "/etc/ssh/sshd_config" - printf '%s\n' "LogLevel VERBOSE" >> "/etc/ssh/sshd_config" - tail -n "+$(( line_number ))" "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" -fi -# Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Find sshd_config included files - shell: |- - included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') - [[ -n $included_files ]] && ls $included_files || true - register: sshd_config_included_files - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-17(1) - - NIST-800-53-AC-17(a) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-2.2.4 - - PCI-DSSv4-2.2.6 - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_set_loglevel_verbose - -- name: Comment conf from included files - replace: - path: '{{ item }}' - regexp: ^(\s*LogLevel.*)$ - replace: '# \1' - loop: '{{ sshd_config_included_files.stdout_lines }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-17(1) - - NIST-800-53-AC-17(a) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-2.2.4 - - PCI-DSSv4-2.2.6 - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_set_loglevel_verbose - -- name: Set SSH Daemon LogLevel to VERBOSE - block: - - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: false - regexp: (?i)^\s*LogLevel\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config - create: false - regexp: (?i)^\s*LogLevel\s+ - state: absent - when: dupes.found is defined and dupes.found > 1 - - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)^\s*LogLevel\s+ - line: LogLevel VERBOSE - state: present - insertbefore: ^[#\s]*Match - validate: /usr/sbin/sshd -t -f %s - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-AC-17(1) - - NIST-800-53-AC-17(a) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-2.2.4 - - PCI-DSSv4-2.2.6 - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_set_loglevel_verbose - - - - - - - - - - - Set SSH authentication attempt limit - The MaxAuthTries parameter specifies the maximum number of authentication attempts -permitted per connection. Once the number of failures reaches half this value, additional failures are logged. -to set MaxAUthTries edit /etc/ssh/sshd_config as follows: -MaxAuthTries - 0421 - 0422 - 0431 - 0974 - 1173 - 1401 - 1504 - 1505 - 1546 - 1557 - 1558 - 1559 - 1560 - 1561 - 2.2.6 - Setting the MaxAuthTries parameter to a low number will minimize the risk of successful -brute force attacks to the SSH server. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -sshd_max_auth_tries_value='' - - -if [ -e "/etc/ssh/sshd_config" ] ; then - - LC_ALL=C sed -i "/^\s*MaxAuthTries\s\+/Id" "/etc/ssh/sshd_config" -else - touch "/etc/ssh/sshd_config" -fi -# make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" - -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" -# Insert before the line matching the regex '^Match'. -line_number="$(LC_ALL=C grep -n "^Match" "/etc/ssh/sshd_config.bak" | LC_ALL=C sed 's/:.*//g')" -if [ -z "$line_number" ]; then - # There was no match of '^Match', insert at - # the end of the file. - printf '%s\n' "MaxAuthTries $sshd_max_auth_tries_value" >> "/etc/ssh/sshd_config" -else - head -n "$(( line_number - 1 ))" "/etc/ssh/sshd_config.bak" > "/etc/ssh/sshd_config" - printf '%s\n' "MaxAuthTries $sshd_max_auth_tries_value" >> "/etc/ssh/sshd_config" - tail -n "+$(( line_number ))" "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" -fi -# Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: XCCDF Value sshd_max_auth_tries_value # promote to variable - set_fact: - sshd_max_auth_tries_value: !!str - tags: - - always - -- name: Find sshd_config included files - shell: |- - included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') - [[ -n $included_files ]] && ls $included_files || true - register: sshd_config_included_files - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - PCI-DSSv4-2.2.6 - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_set_max_auth_tries - -- name: Comment conf from included files - replace: - path: '{{ item }}' - regexp: ^(\s*MaxAuthTries.*)$ - replace: '# \1' - loop: '{{ sshd_config_included_files.stdout_lines }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - PCI-DSSv4-2.2.6 - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_set_max_auth_tries - -- name: Set SSH authentication attempt limit - block: - - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: false - regexp: (?i)^\s*MaxAuthTries\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config - create: false - regexp: (?i)^\s*MaxAuthTries\s+ - state: absent - when: dupes.found is defined and dupes.found > 1 - - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)^\s*MaxAuthTries\s+ - line: MaxAuthTries {{ sshd_max_auth_tries_value }} - state: present - insertbefore: ^[#\s]*Match - validate: /usr/sbin/sshd -t -f %s - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - PCI-DSSv4-2.2.6 - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_set_max_auth_tries - - - - - - - - - - - - Set SSH MaxSessions limit - The MaxSessions parameter specifies the maximum number of open sessions permitted -from a given connection. To set MaxSessions edit -/etc/ssh/sshd_config as follows: MaxSessions - 2.2.6 - To protect a system from denial of service due to a large number of concurrent -sessions, use the rate limiting function of MaxSessions to protect availability -of sshd logins and prevent overwhelming the daemon. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -var_sshd_max_sessions='' - - -if [ -e "/etc/ssh/sshd_config" ] ; then - - LC_ALL=C sed -i "/^\s*MaxSessions\s\+/Id" "/etc/ssh/sshd_config" -else - touch "/etc/ssh/sshd_config" -fi -# make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" - -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" -# Insert before the line matching the regex '^Match'. -line_number="$(LC_ALL=C grep -n "^Match" "/etc/ssh/sshd_config.bak" | LC_ALL=C sed 's/:.*//g')" -if [ -z "$line_number" ]; then - # There was no match of '^Match', insert at - # the end of the file. - printf '%s\n' "MaxSessions $var_sshd_max_sessions" >> "/etc/ssh/sshd_config" -else - head -n "$(( line_number - 1 ))" "/etc/ssh/sshd_config.bak" > "/etc/ssh/sshd_config" - printf '%s\n' "MaxSessions $var_sshd_max_sessions" >> "/etc/ssh/sshd_config" - tail -n "+$(( line_number ))" "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" -fi -# Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: XCCDF Value var_sshd_max_sessions # promote to variable - set_fact: - var_sshd_max_sessions: !!str - tags: - - always - -- name: Find sshd_config included files - shell: |- - included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') - [[ -n $included_files ]] && ls $included_files || true - register: sshd_config_included_files - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - PCI-DSSv4-2.2.6 - - configure_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - sshd_set_max_sessions - -- name: Comment conf from included files - replace: - path: '{{ item }}' - regexp: ^(\s*MaxSessions.*)$ - replace: '# \1' - loop: '{{ sshd_config_included_files.stdout_lines }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - PCI-DSSv4-2.2.6 - - configure_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - sshd_set_max_sessions - -- name: Set SSH MaxSessions limit - block: - - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: false - regexp: (?i)^\s*MaxSessions\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config - create: false - regexp: (?i)^\s*MaxSessions\s+ - state: absent - when: dupes.found is defined and dupes.found > 1 - - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)^\s*MaxSessions\s+ - line: MaxSessions {{ var_sshd_max_sessions }} - state: present - insertbefore: ^[#\s]*Match - validate: /usr/sbin/sshd -t -f %s - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - PCI-DSSv4-2.2.6 - - configure_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - sshd_set_max_sessions - - - - - - - - - - - - Ensure SSH MaxStartups is configured - The MaxStartups parameter specifies the maximum number of concurrent -unauthenticated connections to the SSH daemon. Additional connections will be -dropped until authentication succeeds or the LoginGraceTime expires for a -connection. To confgure MaxStartups, you should add or correct the following -line in the -/etc/ssh/sshd_config file: -MaxStartups -CIS recommends a MaxStartups value of '10:30:60', or more restrictive where -dictated by site policy. - 2.2.6 - To protect a system from denial of service due to a large number of pending -authentication connection attempts, use the rate limiting function of MaxStartups -to protect availability of sshd logins and prevent overwhelming the daemon. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -var_sshd_set_maxstartups='' - - -if [ -e "/etc/ssh/sshd_config" ] ; then - - LC_ALL=C sed -i "/^\s*MaxStartups\s\+/Id" "/etc/ssh/sshd_config" -else - touch "/etc/ssh/sshd_config" -fi -# make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" - -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" -# Insert before the line matching the regex '^Match'. -line_number="$(LC_ALL=C grep -n "^Match" "/etc/ssh/sshd_config.bak" | LC_ALL=C sed 's/:.*//g')" -if [ -z "$line_number" ]; then - # There was no match of '^Match', insert at - # the end of the file. - printf '%s\n' "MaxStartups $var_sshd_set_maxstartups" >> "/etc/ssh/sshd_config" -else - head -n "$(( line_number - 1 ))" "/etc/ssh/sshd_config.bak" > "/etc/ssh/sshd_config" - printf '%s\n' "MaxStartups $var_sshd_set_maxstartups" >> "/etc/ssh/sshd_config" - tail -n "+$(( line_number ))" "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" -fi -# Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: XCCDF Value var_sshd_set_maxstartups # promote to variable - set_fact: - var_sshd_set_maxstartups: !!str - tags: - - always - -- name: Find sshd_config included files - shell: |- - included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') - [[ -n $included_files ]] && ls $included_files || true - register: sshd_config_included_files - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - PCI-DSSv4-2.2.6 - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_set_maxstartups - -- name: Comment conf from included files - replace: - path: '{{ item }}' - regexp: ^(\s*MaxStartups.*)$ - replace: '# \1' - loop: '{{ sshd_config_included_files.stdout_lines }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - PCI-DSSv4-2.2.6 - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_set_maxstartups - -- name: Ensure SSH MaxStartups is configured - block: - - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: false - regexp: (?i)^\s*MaxStartups\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config - create: false - regexp: (?i)^\s*MaxStartups\s+ - state: absent - when: dupes.found is defined and dupes.found > 1 - - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)^\s*MaxStartups\s+ - line: MaxStartups {{ var_sshd_set_maxstartups }} - state: present - insertbefore: ^[#\s]*Match - validate: /usr/sbin/sshd -t -f %s - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - PCI-DSSv4-2.2.6 - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_set_maxstartups - - - - - - - - - - - Distribute the SSH Server configuration to multiple files in a config directory. - Make sure to have the Include /etc/ssh/sshd_config.d/*.conf line in the /etc/ssh/sshd_config file. -Ideally, don't have any active configuration directives in that file, and distribute the service configuration -to several files in the /etc/ssh/sshd_config.d directory. - This form of distributed configuration is considered as a good practice, and as other sshd rules assume that directives in files in the /etc/ssh/sshd_config.d config directory are effective, there has to be a rule that ensures this. -Aside from that, having multiple configuration files makes the SSH Server configuration changes easier to partition according to the reason that they were introduced, and therefore it should help to perform merges of hardening updates. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -if test -f /etc/ssh/sshd_config.d/sshd_config_original.conf; then - printf '%s\n' "Remediation probably already happened, '/etc/ssh/sshd_config.d/sshd_config_original.conf' already exists, not doing anything." >&2 -false 1 -elif grep -Eq '^\s*Include\s+/etc/ssh/sshd_config\.d/\*\.conf' /etc/ssh/sshd_config && ! grep -Eq '^\s*Match\s' /etc/ssh/sshd_config; then - printf '%s\n' "Remediation probably already happened, '/etc/ssh/sshd_config' already contains the include directive." >&2 -false 1 -else - mkdir -p /etc/ssh/sshd_config.d - mv /etc/ssh/sshd_config /etc/ssh/sshd_config.d/sshd_config_original.conf -cat > /etc/ssh/sshd_config << EOF -# To modify the system-wide sshd configuration, create a *.conf file under -# /etc/ssh/sshd_config.d/ which will be automatically included below - -Include /etc/ssh/sshd_config.d/*.conf -EOF -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - - - - - - - - - Enable Use of Privilege Separation - When enabled, SSH will create an unprivileged child process that -has the privilege of the authenticated user. To enable privilege separation in -SSH, add or correct the following line in the /etc/ssh/sshd_config file: -UsePrivilegeSeparation - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - APO01.06 - DSS05.04 - DSS05.07 - DSS06.02 - 3.1.12 - CCI-000366 - 164.308(a)(4)(i) - 164.308(b)(1) - 164.308(b)(3) - 164.310(b) - 164.312(e)(1) - 164.312(e)(2)(ii) - 4.3.3.7.3 - SR 2.1 - SR 5.2 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 - CM-6(a) - AC-17(a) - AC-6 - PR.AC-4 - PR.DS-5 - SRG-OS-000480-GPOS-00227 - SSH daemon privilege separation causes the SSH process to drop root privileges -when not needed which would decrease the impact of software vulnerabilities in -the unprivileged section. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -var_sshd_priv_separation='' - - -if [ -e "/etc/ssh/sshd_config" ] ; then - - LC_ALL=C sed -i "/^\s*UsePrivilegeSeparation\s\+/Id" "/etc/ssh/sshd_config" -else - touch "/etc/ssh/sshd_config" -fi -# make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" - -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" -# Insert before the line matching the regex '^Match'. -line_number="$(LC_ALL=C grep -n "^Match" "/etc/ssh/sshd_config.bak" | LC_ALL=C sed 's/:.*//g')" -if [ -z "$line_number" ]; then - # There was no match of '^Match', insert at - # the end of the file. - printf '%s\n' "UsePrivilegeSeparation $var_sshd_priv_separation" >> "/etc/ssh/sshd_config" -else - head -n "$(( line_number - 1 ))" "/etc/ssh/sshd_config.bak" > "/etc/ssh/sshd_config" - printf '%s\n' "UsePrivilegeSeparation $var_sshd_priv_separation" >> "/etc/ssh/sshd_config" - tail -n "+$(( line_number ))" "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" -fi -# Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: XCCDF Value var_sshd_priv_separation # promote to variable - set_fact: - var_sshd_priv_separation: !!str - tags: - - always - -- name: Find sshd_config included files - shell: |- - included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') - [[ -n $included_files ]] && ls $included_files || true - register: sshd_config_included_files - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.12 - - NIST-800-53-AC-17(a) - - NIST-800-53-AC-6 - - NIST-800-53-CM-6(a) - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_use_priv_separation - -- name: Comment conf from included files - replace: - path: '{{ item }}' - regexp: ^(\s*UsePrivilegeSeparation.*)$ - replace: '# \1' - loop: '{{ sshd_config_included_files.stdout_lines }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.12 - - NIST-800-53-AC-17(a) - - NIST-800-53-AC-6 - - NIST-800-53-CM-6(a) - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_use_priv_separation - -- name: Enable Use of Privilege Separation - block: - - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: false - regexp: (?i)^\s*UsePrivilegeSeparation\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config - create: false - regexp: (?i)^\s*UsePrivilegeSeparation\s+ - state: absent - when: dupes.found is defined and dupes.found > 1 - - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)^\s*UsePrivilegeSeparation\s+ - line: UsePrivilegeSeparation {{ var_sshd_priv_separation }} - state: present - insertbefore: ^[#\s]*Match - validate: /usr/sbin/sshd -t -f %s - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-171-3.1.12 - - NIST-800-53-AC-17(a) - - NIST-800-53-AC-6 - - NIST-800-53-CM-6(a) - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_use_priv_separation - - - - - - - - - - - - Prevent remote hosts from connecting to the proxy display - The SSH daemon should prevent remote hosts from connecting to the proxy -display. - -The default SSH configuration for X11UseLocalhost is yes, -which prevents remote hosts from connecting to the proxy display. - -To explicitly prevent remote connections to the proxy display, add or correct -the following line in - - -/etc/ssh/sshd_config: - -X11UseLocalhost yes - CCI-000366 - CM-6(b) - SRG-OS-000480-GPOS-00227 - When X11 forwarding is enabled, there may be additional exposure to the -server and client displays if the sshd proxy display is configured to listen -on the wildcard address. By default, sshd binds the forwarding server to the -loopback address and sets the hostname part of the DISPLAY -environment variable to localhost. This prevents remote hosts from -connecting to the proxy display. - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -# Find the include keyword, extract from the line the glob expression representing included files. -# And if it is a relative path prepend '/etc/ssh/' -included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') -for included_file in ${included_files} ; do - - LC_ALL=C sed -i "/^\s*X11UseLocalhost/Id" "$included_file" -done - -if [ -e "/etc/ssh/sshd_config" ] ; then - - LC_ALL=C sed -i "/^\s*X11UseLocalhost\s\+/Id" "/etc/ssh/sshd_config" -else - touch "/etc/ssh/sshd_config" -fi -# make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" - -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" -# Insert before the line matching the regex '^Match'. -line_number="$(LC_ALL=C grep -n "^Match" "/etc/ssh/sshd_config.bak" | LC_ALL=C sed 's/:.*//g')" -if [ -z "$line_number" ]; then - # There was no match of '^Match', insert at - # the end of the file. - printf '%s\n' "X11UseLocalhost yes" >> "/etc/ssh/sshd_config" -else - head -n "$(( line_number - 1 ))" "/etc/ssh/sshd_config.bak" > "/etc/ssh/sshd_config" - printf '%s\n' "X11UseLocalhost yes" >> "/etc/ssh/sshd_config" - tail -n "+$(( line_number ))" "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" -fi -# Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Find sshd_config included files - shell: |- - included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') - [[ -n $included_files ]] && ls $included_files || true - register: sshd_config_included_files - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-CM-6(b) - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_x11_use_localhost - -- name: Comment conf from included files - replace: - path: '{{ item }}' - regexp: ^(\s*X11UseLocalhost.*)$ - replace: '# \1' - loop: '{{ sshd_config_included_files.stdout_lines }}' - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-CM-6(b) - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_x11_use_localhost - -- name: Prevent remote hosts from connecting to the proxy display - block: - - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: false - regexp: (?i)^\s*X11UseLocalhost\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config - create: false - regexp: (?i)^\s*X11UseLocalhost\s+ - state: absent - when: dupes.found is defined and dupes.found > 1 - - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)^\s*X11UseLocalhost\s+ - line: X11UseLocalhost yes - state: present - insertbefore: ^[#\s]*Match - validate: /usr/sbin/sshd -t -f %s - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-CM-6(b) - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_x11_use_localhost - - - - - - - - - - - Strengthen Firewall Configuration if Possible - If the SSH server is expected to only receive connections from -the local network, then strengthen the default firewall rule for the SSH service -to only accept connections from the appropriate network segment(s). - -Determine an appropriate network block, netwk, network mask, mask, and -network protocol, ip_protocol, representing the systems on your network which will -be allowed to access this SSH server. - -Run the following command: -firewall-cmd --permanent --add-rich-rule='rule family="ip_protocol" source address="netwk/mask" service name="ssh" accept' - - - - - System Security Services Daemon - The System Security Services Daemon (SSSD) is a system daemon that provides access -to different identity and authentication providers such as Red Hat's IdM, Microsoft's AD, -openLDAP, MIT Kerberos, etc. It uses a common framework that can provide caching and offline -support to systems utilizing SSSD. SSSD using caching to reduce load on authentication -servers permit offline authentication as well as store extended user data. - -For more information, see - https://docs.oracle.com/en/operating-systems/oracle-linux/9/userauth/userauth-UsingtheSystemSecurityServicesDaemon.html - - - SSSD certificate_verification option - Value of the certificate_verification option in -the SSSD config. - sha1 - sha256 - sha384 - sha512 - sha1 - - - SSSD memcache_timeout option - Value of the memcache_timeout option in the [nss] section -of SSSD config /etc/sssd/sssd.conf. - 180 - 300 - 600 - 900 - 1800 - 86400 - 300 - - - SSSD ssh_known_hosts_timeout option - Value of the ssh_known_hosts_timeout option in the [ssh] section -of SSSD configuration file /etc/sssd/sssd.conf. - 180 - 300 - 600 - 900 - 1800 - 86400 - 180 - - - Certificate status checking in SSSD - Multifactor solutions that require devices separate from information systems gaining access include, -for example, hardware tokens providing time-based or challenge-response authenticators and smart cards. -Configuring certificate_verification to ocsp_dgst= ensures that certificates for -multifactor solutions are checked via Online Certificate Status Protocol (OCSP). - CCI-001948 - CCI-001954 - IA-2(11) - SRG-OS-000375-GPOS-00160 - SRG-OS-000377-GPOS-00162 - Ensuring that multifactor solutions certificates are checked via Online Certificate Status Protocol (OCSP) -ensures the security of the system. - # Remediation is applicable only in certain platforms -if rpm --quiet -q sssd-common; then - -var_sssd_certificate_verification_digest_function='' - - -# sssd configuration files must be created with 600 permissions if they don't exist -# otherwise the sssd module fails to start -OLD_UMASK=$(umask) -umask u=rw,go= - -MAIN_CONF="/etc/sssd/conf.d/certificate_verification.conf" - -found=false - -# set value in all files if they contain section or key -for f in $(echo -n "$MAIN_CONF /etc/sssd/sssd.conf /etc/sssd/conf.d/*.conf"); do - if [ ! -e "$f" ]; then - continue - fi - - # find key in section and change value - if grep -qzosP "[[:space:]]*\[sssd\]([^\n\[]*\n+)+?[[:space:]]*certificate_verification" "$f"; then - sed -i "s/certificate_verification[^(\n)]*/certificate_verification = ocsp_dgst = $var_sssd_certificate_verification_digest_function/" "$f" - found=true - - # find section and add key = value to it - elif grep -qs "[[:space:]]*\[sssd\]" "$f"; then - sed -i "/[[:space:]]*\[sssd\]/a certificate_verification = ocsp_dgst = $var_sssd_certificate_verification_digest_function" "$f" - found=true - fi -done - -# if section not in any file, append section with key = value to FIRST file in files parameter -if ! $found ; then - file=$(echo "$MAIN_CONF /etc/sssd/sssd.conf /etc/sssd/conf.d/*.conf" | cut -f1 -d ' ') - mkdir -p "$(dirname "$file")" - echo -e "[sssd]\ncertificate_verification = ocsp_dgst = $var_sssd_certificate_verification_digest_function" >> "$file" -fi - -umask $OLD_UMASK - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Gather the package facts - package_facts: - manager: auto - tags: - - NIST-800-53-IA-2(11) - - configure_strategy - - low_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - - sssd_certificate_verification -- name: XCCDF Value var_sssd_certificate_verification_digest_function # promote to variable - set_fact: - var_sssd_certificate_verification_digest_function: !!str - tags: - - always - -- name: Ensure that "certificate_verification" is not set in /etc/sssd/sssd.conf - ini_file: - path: /etc/sssd/sssd.conf - section: sssd - option: certificate_verification - state: absent - mode: 384 - when: '"sssd-common" in ansible_facts.packages' - tags: - - NIST-800-53-IA-2(11) - - configure_strategy - - low_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - - sssd_certificate_verification - -- name: Ensure that "certificate_verification" is not set in /etc/sssd/conf.d/*.conf - ini_file: - path: /etc/sssd/conf.d/*.conf - section: sssd - option: certificate_verification - state: absent - mode: 384 - when: '"sssd-common" in ansible_facts.packages' - tags: - - NIST-800-53-IA-2(11) - - configure_strategy - - low_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - - sssd_certificate_verification - -- name: Ensure that "certificate_verification" is set - ini_file: - path: /etc/sssd/conf.d/certificate_verification.conf - section: sssd - option: certificate_verification - value: ocsp_dgst = {{ var_sssd_certificate_verification_digest_function }} - state: present - mode: 384 - when: '"sssd-common" in ansible_facts.packages' - tags: - - NIST-800-53-IA-2(11) - - configure_strategy - - low_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - - sssd_certificate_verification - - - - - - - - - - - Enable Certmap in SSSD - SSSD should be configured to verify the certificate of the user or group. To set this up - ensure that section like certmap/testing.test/rule_name is setup in -/etc/sssd/sssd.conf. For example - -[certmap/testing.test/rule_name] -matchrule =<SAN>.*EDIPI@mil -maprule = (userCertificate;binary={cert!bin}) -domains = testing.test - - Automatic remediation of this control is not available, since all of the settings in -in the certmap need to be customized. - CCI-000187 - IA-5 (2) (c) - SRG-OS-000068-GPOS-00036 - Without mapping the certificate used to authenticate to the user account, the ability to -determine the identity of the individual user or group will not be available for forensic -analysis. - - - - - - - - - Enable Smartcards in SSSD - SSSD should be configured to authenticate access to the system using smart cards. -To enable smart cards in SSSD, set pam_cert_auth to True under the -[pam] section in /etc/sssd/sssd.conf. For example: -[pam] -pam_cert_auth = True - - -Add or update "pam_sss.so" line in auth section of "/etc/pam.d/system-auth" file to include -"try_cert_auth" or "require_cert_auth" option, like in the following example: - -/etc/pam.d/system-auth:auth [success=done authinfo_unavail=ignore ignore=ignore default=die] pam_sss.so try_cert_auth - -Also add or update "pam_sss.so" line in auth section of "/etc/pam.d/smartcard-auth" file to -include the "allow_missing_name" option, like in the following example: -/etc/pam.d/smartcard-auth:auth sufficient pam_sss.so allow_missing_name - CCI-001954 - CCI-000765 - CCI-000766 - CCI-000767 - CCI-000768 - 0421 - 0422 - 0431 - 0974 - 1173 - 1401 - 1504 - 1505 - 1546 - 1557 - 1558 - 1559 - 1560 - 1561 - Req-8.3 - 8.4 - SRG-OS-000375-GPOS-00160 - SRG-OS-000105-GPOS-00052 - SRG-OS-000106-GPOS-00053 - SRG-OS-000107-GPOS-00054 - SRG-OS-000108-GPOS-00055 - Using an authentication device, such as a CAC or token that is separate from -the information system, ensures that even if the information system is -compromised, that compromise will not affect credentials stored on the -authentication device. - -Multi-Factor Authentication (MFA) solutions that require devices separate from -information systems gaining access include, for example, hardware tokens -providing time-based or challenge-response authenticators and smart cards such -as the U.S. Government Personal Identity Verification card and the DoD Common -Access Card. - - # Remediation is applicable only in certain platforms -if rpm --quiet -q sssd-common && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then - -# sssd configuration files must be created with 600 permissions if they don't exist -# otherwise the sssd module fails to start -OLD_UMASK=$(umask) -umask u=rw,go= - -found=false - -# set value in all files if they contain section or key -for f in $(echo -n "/etc/sssd/sssd.conf"); do - if [ ! -e "$f" ]; then - continue - fi - - # find key in section and change value - if grep -qzosP "[[:space:]]*\[pam\]([^\n\[]*\n+)+?[[:space:]]*pam_cert_auth" "$f"; then - sed -i "s/pam_cert_auth[^(\n)]*/pam_cert_auth = True/" "$f" - found=true - - # find section and add key = value to it - elif grep -qs "[[:space:]]*\[pam\]" "$f"; then - sed -i "/[[:space:]]*\[pam\]/a pam_cert_auth = True" "$f" - found=true - fi -done - -# if section not in any file, append section with key = value to FIRST file in files parameter -if ! $found ; then - file=$(echo "/etc/sssd/sssd.conf" | cut -f1 -d ' ') - mkdir -p "$(dirname "$file")" - echo -e "[pam]\npam_cert_auth = True" >> "$file" -fi - -umask $OLD_UMASK - - -if [ -f /usr/bin/authselect ]; then - if authselect check; then - if ! authselect check; then - echo " - authselect integrity check failed. Remediation aborted! - This remediation could not be applied because an authselect profile was not selected or the selected profile is not intact. - It is not recommended to manually edit the PAM files when authselect tool is available. - In cases where the default authselect profile does not cover a specific demand, a custom authselect profile is recommended." - exit 1 - fi - authselect enable-feature with-smartcard - - authselect apply-changes -b - fi -else - if ! grep -qP '^\s*auth\s+'"sufficient"'\s+pam_sss.so\s*.*' "/etc/pam.d/smartcard-auth"; then - # Line matching group + control + module was not found. Check group + module. - if [ "$(grep -cP '^\s*auth\s+.*\s+pam_sss.so\s*' "/etc/pam.d/smartcard-auth")" -eq 1 ]; then - # The control is updated only if one single line matches. - sed -i -E --follow-symlinks 's/^(\s*auth\s+).*(\bpam_sss.so.*)/\1'"sufficient"' \2/' "/etc/pam.d/smartcard-auth" - else - echo 'auth '"sufficient"' pam_sss.so' >> "/etc/pam.d/smartcard-auth" - fi - fi - # Check the option - if ! grep -qP '^\s*auth\s+'"sufficient"'\s+pam_sss.so\s*.*\sallow_missing_name\b' "/etc/pam.d/smartcard-auth"; then - sed -i -E --follow-symlinks '/\s*auth\s+'"sufficient"'\s+pam_sss.so.*/ s/$/ allow_missing_name/' "/etc/pam.d/smartcard-auth" - fi - if ! grep -qP '^\s*auth\s+'"\[success=done authinfo_unavail=ignore ignore=ignore default=die\]"'\s+pam_sss.so\s*.*' "/etc/pam.d/system-auth"; then - # Line matching group + control + module was not found. Check group + module. - if [ "$(grep -cP '^\s*auth\s+.*\s+pam_sss.so\s*' "/etc/pam.d/system-auth")" -eq 1 ]; then - # The control is updated only if one single line matches. - sed -i -E --follow-symlinks 's/^(\s*auth\s+).*(\bpam_sss.so.*)/\1'"\[success=done authinfo_unavail=ignore ignore=ignore default=die\]"' \2/' "/etc/pam.d/system-auth" - else - echo 'auth '"\[success=done authinfo_unavail=ignore ignore=ignore default=die\]"' pam_sss.so' >> "/etc/pam.d/system-auth" - fi - fi - # Check the option - if ! grep -qP '^\s*auth\s+'"\[success=done authinfo_unavail=ignore ignore=ignore default=die\]"'\s+pam_sss.so\s*.*\stry_cert_auth\b' "/etc/pam.d/system-auth"; then - sed -i -E --follow-symlinks '/\s*auth\s+'"\[success=done authinfo_unavail=ignore ignore=ignore default=die\]"'\s+pam_sss.so.*/ s/$/ try_cert_auth/' "/etc/pam.d/system-auth" - fi -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Gather the package facts - package_facts: - manager: auto - tags: - - PCI-DSS-Req-8.3 - - PCI-DSSv4-8.4 - - configure_strategy - - low_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - - sssd_enable_smartcards - -- name: Test for domain group - command: grep '^\s*\[domain\/[^]]*]' /etc/sssd/sssd.conf - register: test_grep_domain - ignore_errors: true - changed_when: false - check_mode: false - when: - - '"sssd-common" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - PCI-DSS-Req-8.3 - - PCI-DSSv4-8.4 - - configure_strategy - - low_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - - sssd_enable_smartcards - -- name: Add default domain group (if no domain there) - ini_file: - path: /etc/sssd/sssd.conf - section: '{{ item.section }}' - option: '{{ item.option }}' - value: '{{ item.value }}' - create: true - mode: 384 - with_items: - - section: sssd - option: domains - value: default - - section: domain/default - option: id_provider - value: files - when: - - '"sssd-common" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - test_grep_domain.stdout is defined - - test_grep_domain.stdout | length < 1 - tags: - - PCI-DSS-Req-8.3 - - PCI-DSSv4-8.4 - - configure_strategy - - low_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - - sssd_enable_smartcards - -- name: Enable Smartcards in SSSD - ini_file: - dest: /etc/sssd/sssd.conf - section: pam - option: pam_cert_auth - value: 'True' - create: true - mode: 384 - when: - - '"sssd-common" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - PCI-DSS-Req-8.3 - - PCI-DSSv4-8.4 - - configure_strategy - - low_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - - sssd_enable_smartcards - -- name: Enable Smartcards in SSSD - Check if system relies on authselect - ansible.builtin.stat: - path: /usr/bin/authselect - register: result_authselect_present - when: - - '"sssd-common" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - PCI-DSS-Req-8.3 - - PCI-DSSv4-8.4 - - configure_strategy - - low_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - - sssd_enable_smartcards - -- name: Enable Smartcards in SSSD - Remediate using authselect - block: - - - name: Enable Smartcards in SSSD - Check integrity of authselect current profile - ansible.builtin.command: - cmd: authselect check - register: result_authselect_check_cmd - changed_when: false - failed_when: false - - - name: Enable Smartcards in SSSD - Informative message based on the authselect - integrity check result - ansible.builtin.assert: - that: - - result_authselect_check_cmd.rc == 0 - fail_msg: - - authselect integrity check failed. Remediation aborted! - - This remediation could not be applied because an authselect profile was not - selected or the selected profile is not intact. - - It is not recommended to manually edit the PAM files when authselect tool - is available. - - In cases where the default authselect profile does not cover a specific demand, - a custom authselect profile is recommended. - success_msg: - - authselect integrity check passed - - - name: Enable Smartcards in SSSD - Get authselect current features - ansible.builtin.shell: - cmd: authselect current | tail -n+3 | awk '{ print $2 }' - register: result_authselect_features - changed_when: false - when: - - result_authselect_check_cmd is success - - - name: Enable Smartcards in SSSD - Ensure "with-smartcard" feature is enabled using - authselect tool - ansible.builtin.command: - cmd: authselect enable-feature with-smartcard - register: result_authselect_enable_feature_cmd - when: - - result_authselect_check_cmd is success - - result_authselect_features.stdout is not search("with-smartcard") - - - name: Enable Smartcards in SSSD - Ensure authselect changes are applied - ansible.builtin.command: - cmd: authselect apply-changes -b - when: - - result_authselect_enable_feature_cmd is not skipped - - result_authselect_enable_feature_cmd is success - when: - - '"sssd-common" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - result_authselect_present.stat.exists - tags: - - PCI-DSS-Req-8.3 - - PCI-DSSv4-8.4 - - configure_strategy - - low_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - - sssd_enable_smartcards - -- name: Enable Smartcards in SSSD - Remediate by directly editing PAM files - block: - - - name: Enable Smartcards in SSSD - Check if expected PAM module line is present - in /etc/pam.d/smartcard-auth - ansible.builtin.lineinfile: - path: /etc/pam.d/smartcard-auth - regexp: ^\s*auth\s+sufficient\s+pam_sss.so\s*.* - state: absent - check_mode: true - changed_when: false - register: result_pam_line_present - - - name: Enable Smartcards in SSSD - Include or update the PAM module line in /etc/pam.d/smartcard-auth - block: - - - name: Enable Smartcards in SSSD - Check if required PAM module line is present - in /etc/pam.d/smartcard-auth with different control - ansible.builtin.lineinfile: - path: /etc/pam.d/smartcard-auth - regexp: ^\s*auth\s+.*\s+pam_sss.so\s* - state: absent - check_mode: true - changed_when: false - register: result_pam_line_other_control_present - - - name: Enable Smartcards in SSSD - Ensure the correct control for the required - PAM module line in /etc/pam.d/smartcard-auth - ansible.builtin.replace: - dest: /etc/pam.d/smartcard-auth - regexp: ^(\s*auth\s+).*(\bpam_sss.so.*) - replace: \1sufficient \2 - register: result_pam_module_edit - when: - - result_pam_line_other_control_present.found == 1 - - - name: Enable Smartcards in SSSD - Ensure the required PAM module line is included - in /etc/pam.d/smartcard-auth - ansible.builtin.lineinfile: - dest: /etc/pam.d/smartcard-auth - line: auth sufficient pam_sss.so - register: result_pam_module_add - when: - - result_pam_line_other_control_present.found == 0 or result_pam_line_other_control_present.found - > 1 - - - name: Enable Smartcards in SSSD - Ensure authselect changes are applied - ansible.builtin.command: - cmd: authselect apply-changes -b - when: - - result_authselect_present is defined - - result_authselect_present.stat.exists - - |- - (result_pam_module_add is defined and result_pam_module_add.changed) - or (result_pam_module_edit is defined and result_pam_module_edit.changed) - when: - - result_pam_line_present.found is defined - - result_pam_line_present.found == 0 - - - name: Enable Smartcards in SSSD - Check if the required PAM module option is present - in /etc/pam.d/smartcard-auth - ansible.builtin.lineinfile: - path: /etc/pam.d/smartcard-auth - regexp: ^\s*auth\s+sufficient\s+pam_sss.so\s*.*\sallow_missing_name\b - state: absent - check_mode: true - changed_when: false - register: result_pam_module_allow_missing_name_option_present - - - name: Enable Smartcards in SSSD - Ensure the "allow_missing_name" PAM option for - "pam_sss.so" is included in /etc/pam.d/smartcard-auth - ansible.builtin.lineinfile: - path: /etc/pam.d/smartcard-auth - backrefs: true - regexp: ^(\s*auth\s+sufficient\s+pam_sss.so.*) - line: \1 allow_missing_name - state: present - register: result_pam_allow_missing_name_add - when: - - result_pam_module_allow_missing_name_option_present.found == 0 - - - name: Enable Smartcards in SSSD - Check if expected PAM module line is present - in /etc/pam.d/system-auth - ansible.builtin.lineinfile: - path: /etc/pam.d/system-auth - regexp: ^\s*auth\s+\[success=done authinfo_unavail=ignore ignore=ignore default=die\]\s+pam_sss.so\s*.* - state: absent - check_mode: true - changed_when: false - register: result_pam_line_present - - - name: Enable Smartcards in SSSD - Include or update the PAM module line in /etc/pam.d/system-auth - block: - - - name: Enable Smartcards in SSSD - Check if required PAM module line is present - in /etc/pam.d/system-auth with different control - ansible.builtin.lineinfile: - path: /etc/pam.d/system-auth - regexp: ^\s*auth\s+.*\s+pam_sss.so\s* - state: absent - check_mode: true - changed_when: false - register: result_pam_line_other_control_present - - - name: Enable Smartcards in SSSD - Ensure the correct control for the required - PAM module line in /etc/pam.d/system-auth - ansible.builtin.replace: - dest: /etc/pam.d/system-auth - regexp: ^(\s*auth\s+).*(\bpam_sss.so.*) - replace: \1\[success=done authinfo_unavail=ignore ignore=ignore default=die\] - \2 - register: result_pam_module_edit - when: - - result_pam_line_other_control_present.found == 1 - - - name: Enable Smartcards in SSSD - Ensure the required PAM module line is included - in /etc/pam.d/system-auth - ansible.builtin.lineinfile: - dest: /etc/pam.d/system-auth - line: auth \[success=done authinfo_unavail=ignore ignore=ignore default=die\] pam_sss.so - register: result_pam_module_add - when: - - result_pam_line_other_control_present.found == 0 or result_pam_line_other_control_present.found - > 1 - - - name: Enable Smartcards in SSSD - Ensure authselect changes are applied - ansible.builtin.command: - cmd: authselect apply-changes -b - when: - - result_authselect_present is defined - - result_authselect_present.stat.exists - - |- - (result_pam_module_add is defined and result_pam_module_add.changed) - or (result_pam_module_edit is defined and result_pam_module_edit.changed) - when: - - result_pam_line_present.found is defined - - result_pam_line_present.found == 0 - - - name: Enable Smartcards in SSSD - Check if the required PAM module option is present - in /etc/pam.d/system-auth - ansible.builtin.lineinfile: - path: /etc/pam.d/system-auth - regexp: ^\s*auth\s+\[success=done authinfo_unavail=ignore ignore=ignore default=die\]\s+pam_sss.so\s*.*\stry_cert_auth\b - state: absent - check_mode: true - changed_when: false - register: result_pam_module_try_cert_auth_option_present - - - name: Enable Smartcards in SSSD - Ensure the "try_cert_auth" PAM option for "pam_sss.so" - is included in /etc/pam.d/system-auth - ansible.builtin.lineinfile: - path: /etc/pam.d/system-auth - backrefs: true - regexp: ^(\s*auth\s+\[success=done authinfo_unavail=ignore ignore=ignore default=die\]\s+pam_sss.so.*) - line: \1 try_cert_auth - state: present - register: result_pam_try_cert_auth_add - when: - - result_pam_module_try_cert_auth_option_present.found == 0 - when: - - '"sssd-common" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - not result_authselect_present.stat.exists - tags: - - PCI-DSS-Req-8.3 - - PCI-DSSv4-8.4 - - configure_strategy - - low_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - - sssd_enable_smartcards - - - - - - - - - - SSSD Has a Correct Trust Anchor - SSSD must have acceptable trust anchor present. - Automatic remediation of this control is not available. - CCI-000185 - IA-5 (2) (a) - SRG-OS-000066-GPOS-00034 - SRG-OS-000384-GPOS-00167 - Without path validation, an informed trust decision by the relying party cannot be made when -presented with any certificate not already explicitly trusted. - -A trust anchor is an authoritative entity represented via a public key and associated data. It -is used in the context of public key infrastructures, X.509 digital certificates, and DNSSEC. - -When there is a chain of trust, usually the top entity to be trusted becomes the trust anchor; -it can be, for example, a Certification Authority (CA). A certification path starts with the -subject certificate and proceeds through a number of intermediate certificates up to a trusted -root certificate, typically issued by a trusted CA. - -This requirement verifies that a certification path to an accepted trust anchor is used for -certificate validation and that the path includes status information. Path validation is -necessary for a relying party to make an informed trust decision when presented with any -certificate not already explicitly trusted. Status information for certification paths includes -certificate revocation lists or online certificate status protocol responses. -Validation of the certificate status information is out of scope for this requirement. - - - - - - Configure SSSD to Expire Offline Credentials - SSSD should be configured to expire offline credentials after 1 day. - -To configure SSSD to expire offline credentials, set -offline_credentials_expiration to 1 under the [pam] -section in /etc/sssd/sssd.conf. For example: -[pam] -offline_credentials_expiration = 1 - - 1 - 12 - 15 - 16 - 5 - DSS05.04 - DSS05.05 - DSS05.07 - DSS05.10 - DSS06.03 - DSS06.10 - CCI-002007 - 4.3.3.2.2 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.2 - 4.3.3.7.4 - SR 1.1 - SR 1.10 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - A.18.1.4 - A.7.1.1 - A.9.2.1 - A.9.2.2 - A.9.2.3 - A.9.2.4 - A.9.2.6 - A.9.3.1 - A.9.4.2 - A.9.4.3 - CM-6(a) - IA-5(13) - PR.AC-1 - PR.AC-6 - PR.AC-7 - SRG-OS-000383-GPOS-00166 - If cached authentication information is out-of-date, the validity of the -authentication information may be questionable. - - # Remediation is applicable only in certain platforms -if rpm --quiet -q sssd-common && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then - -# sssd configuration files must be created with 600 permissions if they don't exist -# otherwise the sssd module fails to start -OLD_UMASK=$(umask) -umask u=rw,go= - -found=false - -# set value in all files if they contain section or key -for f in $(echo -n "/etc/sssd/sssd.conf"); do - if [ ! -e "$f" ]; then - continue - fi - - # find key in section and change value - if grep -qzosP "[[:space:]]*\[pam\]([^\n\[]*\n+)+?[[:space:]]*offline_credentials_expiration" "$f"; then - sed -i "s/offline_credentials_expiration[^(\n)]*/offline_credentials_expiration = 1/" "$f" - found=true - - # find section and add key = value to it - elif grep -qs "[[:space:]]*\[pam\]" "$f"; then - sed -i "/[[:space:]]*\[pam\]/a offline_credentials_expiration = 1" "$f" - found=true - fi -done - -# if section not in any file, append section with key = value to FIRST file in files parameter -if ! $found ; then - file=$(echo "/etc/sssd/sssd.conf" | cut -f1 -d ' ') - mkdir -p "$(dirname "$file")" - echo -e "[pam]\noffline_credentials_expiration = 1" >> "$file" -fi - -umask $OLD_UMASK - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Gather the package facts - package_facts: - manager: auto - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-IA-5(13) - - configure_strategy - - low_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - - sssd_offline_cred_expiration - -- name: Test for domain group - command: grep '\s*\[domain\/[^]]*]' /etc/sssd/sssd.conf - register: test_grep_domain - ignore_errors: true - changed_when: false - check_mode: false - when: - - '"sssd-common" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-IA-5(13) - - configure_strategy - - low_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - - sssd_offline_cred_expiration - -- name: Add default domain group (if no domain there) - ini_file: - path: /etc/sssd/sssd.conf - section: '{{ item.section }}' - option: '{{ item.option }}' - value: '{{ item.value }}' - create: true - mode: 384 - with_items: - - section: sssd - option: domains - value: default - - section: domain/default - option: id_provider - value: files - when: - - '"sssd-common" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - test_grep_domain.stdout is defined - - test_grep_domain.stdout | length < 1 - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-IA-5(13) - - configure_strategy - - low_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - - sssd_offline_cred_expiration - -- name: Configure SSD to Expire Offline Credentials - ini_file: - dest: /etc/sssd/sssd.conf - section: pam - option: offline_credentials_expiration - value: 1 - create: true - mode: 384 - when: - - '"sssd-common" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-IA-5(13) - - configure_strategy - - low_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - - sssd_offline_cred_expiration - - - - - - - - - - System Security Services Daemon (SSSD) - LDAP - The System Security Services Daemon (SSSD) is a system daemon that provides access -to different identity and authentication providers such as Red Hat's IdM, Microsoft's AD, -openLDAP, MIT Kerberos, etc. It uses a common framework that can provide caching and offline -support to systems utilizing SSSD. SSSD using caching to reduce load on authentication -servers permit offline authentication as well as store extended user data. - -SSSD can support many backends including LDAP. The sssd-ldap backend -allows SSSD to fetch identity information from an LDAP server. - - - SSSD LDAP Backend Client CA Certificate Location - Path of a directory that contains Certificate Authority certificates. - /etc/openldap/cacerts - - - - - USBGuard daemon - The USBGuard daemon enforces the USB device authorization policy for all USB devices. - - - Install usbguard Package - -The usbguard package can be installed with the following command: - -$ sudo yum install usbguard - CCI-001958 - 1418 - CM-8(3) - IA-3 - SRG-OS-000378-GPOS-00163 - usbguard is a software framework that helps to protect -against rogue USB devices by implementing basic whitelisting/blacklisting -capabilities based on USB device attributes. - # Remediation is applicable only in certain platforms -if ( [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && ! grep -q s390x /proc/sys/kernel/osrelease ); then - -if ! rpm -q --quiet "usbguard" ; then - yum install -y "usbguard" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Ensure usbguard is installed - package: - name: usbguard - state: present - when: ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", - "container"] and ansible_architecture != "s390x" ) - tags: - - NIST-800-53-CM-8(3) - - NIST-800-53-IA-3 - - enable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - package_usbguard_installed - - include install_usbguard - -class install_usbguard { - package { 'usbguard': - ensure => 'installed', - } -} - - -package --add=usbguard - - --- -apiVersion: machineconfiguration.openshift.io/v1 -kind: MachineConfig -spec: - config: - ignition: - version: 3.1.0 - extensions: - - usbguard - - -[[packages]] -name = "usbguard" -version = "*" - - - - - - - - - - Enable the USBGuard Service - The USBGuard service should be enabled. - -The usbguard service can be enabled with the following command: -$ sudo systemctl enable usbguard.service - CCI-000416 - CCI-001958 - 1418 - CM-8(3)(a) - IA-3 - FMT_SMF_EXT.1 - SRG-OS-000378-GPOS-00163 - The usbguard service must be running in order to -enforce the USB device authorization policy for all USB devices. - # Remediation is applicable only in certain platforms -if ( [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && ! grep -q s390x /proc/sys/kernel/osrelease ); then - -SYSTEMCTL_EXEC='/usr/bin/systemctl' -"$SYSTEMCTL_EXEC" unmask 'usbguard.service' -"$SYSTEMCTL_EXEC" start 'usbguard.service' -"$SYSTEMCTL_EXEC" enable 'usbguard.service' - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Enable service usbguard - block: - - - name: Gather the package facts - package_facts: - manager: auto - - - name: Enable service usbguard - systemd: - name: usbguard - enabled: 'yes' - state: started - masked: 'no' - when: - - '"usbguard" in ansible_facts.packages' - when: ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", - "container"] and ansible_architecture != "s390x" ) - tags: - - NIST-800-53-CM-8(3)(a) - - NIST-800-53-IA-3 - - enable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_usbguard_enabled - - include enable_usbguard - -class enable_usbguard { - service {'usbguard': - enable => true, - ensure => 'running', - } -} - - --- -apiVersion: machineconfiguration.openshift.io/v1 -kind: MachineConfig -metadata: - annotations: - complianceascode.io/depends-on: xccdf_org.ssgproject.content_rule_package_usbguard_installed -spec: - config: - ignition: - version: 3.1.0 - systemd: - units: - - name: usbguard.service - enabled: true - - -[customizations.services] -enabled = ["usbguard"] - - - - - - - - - - Log USBGuard daemon audit events using Linux Audit - To configure USBGuard daemon to log via Linux Audit -(as opposed directly to a file), -AuditBackend option in /etc/usbguard/usbguard-daemon.conf -needs to be set to LinuxAudit. - CCI-000169 - CCI-000172 - AU-2 - CM-8(3) - IA-3 - FMT_SMF_EXT.1 - SRG-OS-000062-GPOS-00031 - SRG-OS-000471-GPOS-00215 - SRG-APP-000141-CTR-000315 - Using the Linux Audit logging allows for centralized trace -of events. - - # Remediation is applicable only in certain platforms -if ( [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && ! grep -q s390x /proc/sys/kernel/osrelease ) && { rpm --quiet -q usbguard; }; then - -if [ -e "/etc/usbguard/usbguard-daemon.conf" ] ; then - - LC_ALL=C sed -i "/^\s*AuditBackend=/d" "/etc/usbguard/usbguard-daemon.conf" -else - touch "/etc/usbguard/usbguard-daemon.conf" -fi -# make sure file has newline at the end -sed -i -e '$a\' "/etc/usbguard/usbguard-daemon.conf" - -cp "/etc/usbguard/usbguard-daemon.conf" "/etc/usbguard/usbguard-daemon.conf.bak" -# Insert at the end of the file -printf '%s\n' "AuditBackend=LinuxAudit" >> "/etc/usbguard/usbguard-daemon.conf" -# Clean up after ourselves. -rm "/etc/usbguard/usbguard-daemon.conf.bak" - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - --- -apiVersion: machineconfiguration.openshift.io/v1 -kind: MachineConfig -metadata: - annotations: - complianceascode.io/depends-on: xccdf_org.ssgproject.content_rule_package_usbguard_installed - complianceascode.io/ocp-version: '>=4.7.0' -spec: - config: - ignition: - version: 3.1.0 - storage: - files: - - contents: - source: data:,{{ %0A%23%0A%23%20Rule%20set%20file%20path.%0A%23%0A%23%20The%20USBGuard%20daemon%20will%20use%20this%20file%20to%20load%20the%20policy%0A%23%20rule%20set%20from%20it%20and%20to%20write%20new%20rules%20received%20via%20the%0A%23%20IPC%20interface.%0A%23%0A%23%20RuleFile%3D/path/to/rules.conf%0A%23%0ARuleFile%3D/etc/usbguard/rules.conf%0A%0A%23%0A%23%20Rule%20set%20folder%20path.%0A%23%0A%23%20The%20USBGuard%20daemon%20will%20use%20this%20folder%20to%20load%20the%20policy%0A%23%20rule%20set%20from%20it%20and%20to%20write%20new%20rules%20received%20via%20the%0A%23%20IPC%20interface.%20Usually%2C%20we%20set%20the%20option%20to%0A%23%20/etc/usbguard/rules.d/.%20The%20USBGuard%20daemon%20is%20supposed%20to%0A%23%20behave%20like%20any%20other%20standard%20Linux%20daemon%20therefore%20it%0A%23%20loads%20rule%20files%20in%20alpha-numeric%20order.%20File%20names%20inside%0A%23%20RuleFolder%20directory%20should%20start%20with%20a%20two-digit%20number%0A%23%20prefix%20indicating%20the%20position%2C%20in%20which%20the%20rules%20are%0A%23%20scanned%20by%20the%20daemon.%0A%23%0A%23%20RuleFolder%3D/path/to/rulesfolder/%0A%23%0ARuleFolder%3D/etc/usbguard/rules.d/%0A%0A%23%0A%23%20Implicit%20policy%20target.%0A%23%0A%23%20How%20to%20treat%20devices%20that%20don%27t%20match%20any%20rule%20in%20the%0A%23%20policy.%20One%20of%3A%0A%23%0A%23%20%2A%20allow%20%20-%20authorize%20the%20device%0A%23%20%2A%20block%20%20-%20block%20the%20device%0A%23%20%2A%20reject%20-%20remove%20the%20device%0A%23%0AImplicitPolicyTarget%3Dblock%0A%0A%23%0A%23%20Present%20device%20policy.%0A%23%0A%23%20How%20to%20treat%20devices%20that%20are%20already%20connected%20when%20the%0A%23%20daemon%20starts.%20One%20of%3A%0A%23%0A%23%20%2A%20allow%20%20%20%20%20%20%20%20-%20authorize%20every%20present%20device%0A%23%20%2A%20block%20%20%20%20%20%20%20%20-%20deauthorize%20every%20present%20device%0A%23%20%2A%20reject%20%20%20%20%20%20%20-%20remove%20every%20present%20device%0A%23%20%2A%20keep%20%20%20%20%20%20%20%20%20-%20just%20sync%20the%20internal%20state%20and%20leave%20it%0A%23%20%2A%20apply-policy%20-%20evaluate%20the%20ruleset%20for%20every%20present%0A%23%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20device%0A%23%0APresentDevicePolicy%3Dapply-policy%0A%0A%23%0A%23%20Present%20controller%20policy.%0A%23%0A%23%20How%20to%20treat%20USB%20controllers%20that%20are%20already%20connected%0A%23%20when%20the%20daemon%20starts.%20One%20of%3A%0A%23%0A%23%20%2A%20allow%20%20%20%20%20%20%20%20-%20authorize%20every%20present%20device%0A%23%20%2A%20block%20%20%20%20%20%20%20%20-%20deauthorize%20every%20present%20device%0A%23%20%2A%20reject%20%20%20%20%20%20%20-%20remove%20every%20present%20device%0A%23%20%2A%20keep%20%20%20%20%20%20%20%20%20-%20just%20sync%20the%20internal%20state%20and%20leave%20it%0A%23%20%2A%20apply-policy%20-%20evaluate%20the%20ruleset%20for%20every%20present%0A%23%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20device%0A%23%0APresentControllerPolicy%3Dkeep%0A%0A%23%0A%23%20Inserted%20device%20policy.%0A%23%0A%23%20How%20to%20treat%20USB%20devices%20that%20are%20already%20connected%0A%23%20%2Aafter%2A%20the%20daemon%20starts.%20One%20of%3A%0A%23%0A%23%20%2A%20block%20%20%20%20%20%20%20%20-%20deauthorize%20every%20present%20device%0A%23%20%2A%20reject%20%20%20%20%20%20%20-%20remove%20every%20present%20device%0A%23%20%2A%20apply-policy%20-%20evaluate%20the%20ruleset%20for%20every%20present%0A%23%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20device%0A%23%0AInsertedDevicePolicy%3Dapply-policy%0A%0A%23%0A%23%20Control%20which%20devices%20are%20authorized%20by%20default.%0A%23%0A%23%20The%20USBGuard%20daemon%20modifies%20some%20the%20default%20authorization%20state%20attributes%0A%23%20of%20controller%20devices.%20This%20setting%2C%20enables%20you%20to%20define%20what%20value%20the%0A%23%20default%20authorization%20is%20set%20to.%0A%23%0A%23%20%2A%20keep%20%20%20%20%20%20%20%20%20-%20do%20not%20change%20the%20authorization%20state%0A%23%20%2A%20none%20%20%20%20%20%20%20%20%20-%20every%20new%20device%20starts%20out%20deauthorized%0A%23%20%2A%20all%20%20%20%20%20%20%20%20%20%20-%20every%20new%20device%20starts%20out%20authorized%0A%23%20%2A%20internal%20%20%20%20%20-%20internal%20devices%20start%20out%20authorized%2C%20external%20devices%20start%0A%23%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20out%20deauthorized%20%28this%20requires%20the%20ACPI%20tables%20to%20properly%0A%23%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20label%20internal%20devices%2C%20and%20kernel%20support%29%0A%23%0A%23AuthorizedDefault%3Dnone%0A%0A%23%0A%23%20Restore%20controller%20device%20state.%0A%23%0A%23%20The%20USBGuard%20daemon%20modifies%20some%20attributes%20of%20controller%0A%23%20devices%20like%20the%20default%20authorization%20state%20of%20new%20child%20device%0A%23%20instances.%20Using%20this%20setting%2C%20you%20can%20control%20whether%20the%0A%23%20daemon%20will%20try%20to%20restore%20the%20attribute%20values%20to%20the%20state%0A%23%20before%20modification%20on%20shutdown.%0A%23%0A%23%20SECURITY%20CONSIDERATIONS%3A%20If%20set%20to%20true%2C%20the%20USB%20authorization%0A%23%20policy%20could%20be%20bypassed%20by%20performing%20some%20sort%20of%20attack%20on%20the%0A%23%20daemon%20%28via%20a%20local%20exploit%20or%20via%20a%20USB%20device%29%20to%20make%20it%20shutdown%0A%23%20and%20restore%20to%20the%20operating-system%20default%20state%20%28known%20to%20be%20permissive%29.%0A%23%0ARestoreControllerDeviceState%3Dfalse%0A%0A%23%0A%23%20Device%20manager%20backend%0A%23%0A%23%20Which%20device%20manager%20backend%20implementation%20to%20use.%20One%20of%3A%0A%23%0A%23%20%2A%20uevent%20%20%20-%20Netlink%20based%20implementation%20which%20uses%20sysfs%20to%20scan%20for%20present%0A%23%20%20%20%20%20%20%20%20%20%20%20%20%20%20devices%20and%20an%20uevent%20netlink%20socket%20for%20receiving%20USB%20device%0A%23%20%20%20%20%20%20%20%20%20%20%20%20%20%20related%20events.%0A%23%20%2A%20umockdev%20-%20umockdev%20based%20device%20manager%20capable%20of%20simulating%20devices%20based%0A%23%20%20%20%20%20%20%20%20%20%20%20%20%20%20on%20umockdev-record%20files.%20Useful%20for%20testing.%0A%23%0ADeviceManagerBackend%3Duevent%0A%0A%23%21%21%21%20WARNING%3A%20It%27s%20good%20practice%20to%20set%20at%20least%20one%20of%20the%20%21%21%21%0A%23%21%21%21%20%20%20%20%20%20%20%20%20%20two%20options%20bellow.%20If%20none%20of%20them%20are%20set%2C%20%20%21%21%21%0A%23%21%21%21%20%20%20%20%20%20%20%20%20%20the%20daemon%20will%20accept%20IPC%20connections%20from%20%20%20%21%21%21%0A%23%21%21%21%20%20%20%20%20%20%20%20%20%20anyone%2C%20thus%20allowing%20anyone%20to%20modify%20the%20%20%20%20%21%21%21%0A%23%21%21%21%20%20%20%20%20%20%20%20%20%20rule%20set%20and%20%28de%29authorize%20USB%20devices.%20%20%20%20%20%20%20%21%21%21%0A%0A%23%0A%23%20Users%20allowed%20to%20use%20the%20IPC%20interface.%0A%23%0A%23%20A%20space%20delimited%20list%20of%20usernames%20that%20the%20daemon%20will%0A%23%20accept%20IPC%20connections%20from.%0A%23%0A%23%20IPCAllowedUsers%3Dusername1%20username2%20...%0A%23%0AIPCAllowedUsers%3Droot%0A%0A%23%0A%23%20Groups%20allowed%20to%20use%20the%20IPC%20interface.%0A%23%0A%23%20A%20space%20delimited%20list%20of%20groupnames%20that%20the%20daemon%20will%0A%23%20accept%20IPC%20connections%20from.%0A%23%0A%23%20IPCAllowedGroups%3Dgroupname1%20groupname2%20...%0A%23%0AIPCAllowedGroups%3Dwheel%0A%0A%23%0A%23%20IPC%20access%20control%20definition%20files%20path.%0A%23%0A%23%20The%20files%20at%20this%20location%20will%20be%20interpreted%20by%20the%20daemon%0A%23%20as%20access%20control%20definition%20files.%20The%20%28base%29name%20of%20a%20file%0A%23%20should%20be%20in%20the%20form%3A%0A%23%0A%23%20%20%20%5Buser%5D%5B%3A%3Cgroup%3E%5D%0A%23%0A%23%20and%20should%20contain%20lines%20in%20the%20form%3A%0A%23%0A%23%20%20%20%3Csection%3E%3D%5Bprivilege%5D%20...%0A%23%0A%23%20This%20way%20each%20file%20defines%20who%20is%20able%20to%20connect%20to%20the%20IPC%0A%23%20bus%20and%20what%20privileges%20he%20has.%0A%23%0AIPCAccessControlFiles%3D/etc/usbguard/IPCAccessControl.d/%0A%0A%23%0A%23%20Generate%20device%20specific%20rules%20including%20the%20%22via-port%22%0A%23%20attribute.%0A%23%0A%23%20This%20option%20modifies%20the%20behavior%20of%20the%20allowDevice%0A%23%20action.%20When%20instructed%20to%20generate%20a%20permanent%20rule%2C%0A%23%20the%20action%20can%20generate%20a%20port%20specific%20rule.%20Because%0A%23%20some%20systems%20have%20unstable%20port%20numbering%2C%20the%20generated%0A%23%20rule%20might%20not%20match%20the%20device%20after%20rebooting%20the%20system.%0A%23%0A%23%20If%20set%20to%20false%2C%20the%20generated%20rule%20will%20still%20contain%0A%23%20the%20%22parent-hash%22%20attribute%20which%20also%20defines%20an%20association%0A%23%20to%20the%20parent%20device.%20See%20usbguard-rules.conf%285%29%20for%20more%0A%23%20details.%0A%23%0ADeviceRulesWithPort%3Dfalse%0A%0A%23%0A%23%20USBGuard%20Audit%20events%20log%20backend%0A%23%0A%23%20One%20of%3A%0A%23%0A%23%20%2A%20FileAudit%20-%20Log%20audit%20events%20into%20a%20file%20specified%20by%0A%23%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20AuditFilePath%20setting%20%28see%20below%29%0A%23%20%2A%20LinuxAudit%20-%20Log%20audit%20events%20using%20the%20Linux%20Audit%0A%23%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20subsystem%20%28using%20audit_log_user_message%29%0A%23%0AAuditBackend%3DLinuxAudit%0A%0A%23%0A%23%20USBGuard%20audit%20events%20log%20file%20path.%0A%23%0A%23AuditFilePath%3D/var/log/usbguard/usbguard-audit.log%0A%0A%23%0A%23%20Hides%20personally%20identifiable%20information%20such%20as%20device%20serial%20numbers%20and%0A%23%20hashes%20of%20descriptors%20%28which%20include%20the%20serial%20number%29%20from%20audit%20entries.%0A%23%0A%23HidePII%3Dfalse }} - mode: 0600 - path: /etc/usbguard/usbguard-daemon.conf - overwrite: true - - - - - - - - - - Authorize Human Interface Devices and USB hubs in USBGuard daemon - To allow authorization of USB devices combining human interface device and hub capabilities -by USBGuard daemon, -add the line -allow with-interface match-all { 03:*:* 09:00:* } -to /etc/usbguard/rules.conf. - This rule should be understood primarily as a convenience administration feature. This rule ensures that if the USBGuard default rules.conf file is present, it will alter it so that USB human interface devices and hubs are allowed. However, if the rules.conf file is altered by system administrator, the rule does not check if USB human interface devices and hubs are allowed. This assumes that an administrator modified the file with some purpose in mind. - CM-8(3) - IA-3 - FMT_SMF_EXT.1 - SRG-OS-000114-GPOS-00059 - Without allowing Human Interface Devices, it might not be possible -to interact with the system. Without allowing hubs, it might not be possible to use any -USB devices on the system. - # Remediation is applicable only in certain platforms -if ( [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && ! grep -q s390x /proc/sys/kernel/osrelease ); then - -echo "allow with-interface match-all { 03:*:* 09:00:* }" >> /etc/usbguard/rules.conf - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Allow HID devices and hubs - lineinfile: - path: /etc/usbguard/rules.conf - create: true - line: allow with-interface match-all { 03:*:* 09:00:* } - state: present - when: ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", - "container"] and ansible_architecture != "s390x" ) - tags: - - NIST-800-53-CM-8(3) - - NIST-800-53-IA-3 - - configure_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - usbguard_allow_hid_and_hub - - --- -apiVersion: machineconfiguration.openshift.io/v1 -kind: MachineConfig -metadata: - annotations: - complianceascode.io/depends-on: xccdf_org.ssgproject.content_rule_package_usbguard_installed -spec: - config: - ignition: - version: 3.1.0 - storage: - files: - - contents: - source: data:,{{ %0Aallow%20with-interface%20match-all%20%7B%2003%3A%2A%3A%2A%2009%3A00%3A%2A%20%7D }} - mode: 0600 - path: /etc/usbguard/rules.d/75-hid-and-hub.conf - overwrite: true - - - - - - - - - - Generate USBGuard Policy - By default USBGuard when enabled prevents access to all USB devices and this lead -to inaccessible system if they use USB mouse/keyboard. To prevent this scenario, -the initial policy configuration must be generated based on current connected USB -devices. - CCI-000416 - CCI-001958 - CM-8(3)(a) - IA-3 - FMT_SMF_EXT.1 - SRG-OS-000378-GPOS-00163 - The usbguard must be configured to allow connected USB devices to work -properly, avoiding the system to become inaccessible. - # Remediation is applicable only in certain platforms -if ( [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && ! grep -q s390x /proc/sys/kernel/osrelease ); then - -if rpm --quiet -q usbguard -then - USBGUARD_CONF=/etc/usbguard/rules.conf - if [ ! -f "$USBGUARD_CONF" ] || [ ! -s "$USBGUARD_CONF" ]; then - usbguard generate-policy > $USBGUARD_CONF - if [ ! -s "$USBGUARD_CONF" ]; then - # make sure OVAL check doesn't fail on systems where - # generate-policy doesn't find any USB devices (for - # example a system might not have a USB bus) - echo "# No USB devices found" > $USBGUARD_CONF - fi - # make sure it has correct permissions - chmod 600 $USBGUARD_CONF - - SYSTEMCTL_EXEC='/usr/bin/systemctl' - "$SYSTEMCTL_EXEC" unmask 'usbguard.service' - "$SYSTEMCTL_EXEC" restart 'usbguard.service' - "$SYSTEMCTL_EXEC" enable 'usbguard.service' - fi -else - echo "USBGuard is not installed. No remediation was applied!" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Gather the package facts - package_facts: - manager: auto - tags: - - NIST-800-53-CM-8(3)(a) - - NIST-800-53-IA-3 - - configure_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - usbguard_generate_policy - -- name: Generate USBGuard Policy - block: - - - name: Gather the package facts - package_facts: - manager: auto - - - name: Check that the /etc/usbguard/rules.conf exists - stat: - path: /etc/usbguard/rules.conf - register: policy_file - - - name: Create USBGuard Policy configuration - command: usbguard generate-policy - register: policy - when: not policy_file.stat.exists or policy_file.stat.size == 0 - - - name: Copy the Generated Policy configuration to a persistent file - copy: - content: '{{ policy.stdout }}' - dest: /etc/usbguard/rules.conf - mode: 384 - when: not policy_file.stat.exists or policy_file.stat.size == 0 - - - name: Add comment into /etc/usbguard/rules.conf when system has no USB devices - lineinfile: - path: /etc/usbguard/rules.conf - line: '# No USB devices found' - state: present - when: not policy_file.stat.exists or policy_file.stat.size == 0 - - - name: Enable service usbguard - systemd: - name: usbguard - enabled: 'yes' - state: started - masked: 'no' - when: - - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - and ansible_architecture != "s390x" ) - - '"usbguard" in ansible_facts.packages' - tags: - - NIST-800-53-CM-8(3)(a) - - NIST-800-53-IA-3 - - configure_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - usbguard_generate_policy - - - - - - - - - - - X Window System - The X Window System implementation included with the -system is called X.org. - - Disable X Windows - Unless there is a mission-critical reason for the -system to run a graphical user interface, ensure X is not set to start -automatically at boot and remove the X Windows software packages. -There is usually no reason to run X Windows -on a dedicated server system, as it increases the system's attack surface and consumes -system resources. Administrators of server systems should instead login via -SSH or on the text console. - - Remove the X Windows Package Group - By removing the xorg-x11-server-common package, the system no longer has X Windows -installed. If X Windows is not installed then the system cannot boot into graphical user mode. -This prevents the system from being accidentally or maliciously booted into a graphical.target -mode. To do so, run the following command:$ sudo yum groupremove base-x -$ sudo yum remove xorg-x11-server-common - The installation and use of a Graphical User Interface (GUI) increases your attack vector and decreases your -overall security posture. Removing the package xorg-x11-server-common package will remove the graphical target -which might bring your system to an inconsistent state requiring additional configuration to access the system -again. If a GUI is an operational requirement, a tailored profile that removes this rule should used before -continuing installation. - 12 - 15 - 8 - APO13.01 - DSS01.04 - DSS05.02 - DSS05.03 - CCI-000366 - 4.3.3.6.6 - SR 1.13 - SR 2.6 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 7.1 - SR 7.6 - A.11.2.6 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.6.2.1 - A.6.2.2 - CM-7(a) - CM-7(b) - CM-6(a) - PR.AC-3 - PR.PT-4 - SRG-OS-000480-GPOS-00227 - Unnecessary service packages must not be installed to decrease the attack surface of the system. X windows has a long history of security -vulnerabilities and should not be installed unless approved and documented. - -# CAUTION: This remediation script will remove xorg-x11-server-common -# from the system, and may remove any packages -# that depend on xorg-x11-server-common. Execute this -# remediation AFTER testing on a non-production -# system! - -if rpm -q --quiet "xorg-x11-server-common" ; then - - yum remove -y "xorg-x11-server-common" - -fi - - - name: Ensure xorg-x11-server-common is removed - package: - name: xorg-x11-server-common - state: absent - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - package_xorg-x11-server-common_removed - - include remove_xorg-x11-server-common - -class remove_xorg-x11-server-common { - package { 'xorg-x11-server-common': - ensure => 'purged', - } -} - - -package --remove=xorg-x11-server-common - - - - - - - - - - Disable graphical user interface - By removing the following packages, the system no longer has X Windows installed. - -xorg-x11-server-Xorg xorg-x11-server-common xorg-x11-server-utils xorg-x11-server-Xwayland - -If X Windows is not installed then the system cannot boot into graphical user mode. -This prevents the system from being accidentally or maliciously booted into a graphical.target -mode. To do so, run the following command: - -sudo yum remove xorg-x11-server-Xorg xorg-x11-server-common xorg-x11-server-utils xorg-x11-server-Xwayland - The installation and use of a Graphical User Interface (GUI) increases your attack vector and decreases your -overall security posture. Removing the package xorg-x11-server-common package will remove the graphical target -which might bring your system to an inconsistent state requiring additional configuration to access the system -again. -The rule xwindows_runlevel_target can be used to configure the system to boot into the multi-user.target. -If a GUI is an operational requirement, a tailored profile that removes this rule should be used before -continuing installation. - CCI-000366 - CM-6(b) - SRG-OS-000480-GPOS-00227 - Unnecessary service packages must not be installed to decrease the attack surface of the system. X windows has a long history of security -vulnerabilities and should not be installed unless approved and documented. - - -# remove packages -if rpm -q --quiet "xorg-x11-server-Xorg" ; then - - yum remove -y "xorg-x11-server-Xorg" - -fi -if rpm -q --quiet "xorg-x11-server-utils" ; then - - yum remove -y "xorg-x11-server-utils" - -fi -if rpm -q --quiet "xorg-x11-server-common" ; then - - yum remove -y "xorg-x11-server-common" - -fi - -if rpm -q --quiet "xorg-x11-server-Xwayland" ; then - - yum remove -y "xorg-x11-server-Xwayland" - -fi - - -package --remove=xorg-x11-server-Xorg --remove=xorg-x11-server-common --remove=xorg-x11-server-utils --remove=xorg-x11-server-Xwayland - - - - - - - - - - Disable X Windows Startup By Setting Default Target - Systems that do not require a graphical user interface should only boot by -default into multi-user.target mode. This prevents accidental booting of the system -into a graphical.target mode. Setting the system's default target to -multi-user.target will prevent automatic startup of the X server. To do so, run: -$ systemctl set-default multi-user.target -You should see the following output: -Removed symlink /etc/systemd/system/default.target. -Created symlink from /etc/systemd/system/default.target to /usr/lib/systemd/system/multi-user.target. - 12 - 15 - 8 - APO13.01 - DSS01.04 - DSS05.02 - DSS05.03 - CCI-000366 - 4.3.3.6.6 - SR 1.13 - SR 2.6 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 7.1 - SR 7.6 - A.11.2.6 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.6.2.1 - A.6.2.2 - CM-7(a) - CM-7(b) - CM-6(a) - PR.AC-3 - PR.PT-4 - SRG-OS-000480-GPOS-00227 - Services that are not required for system and application processes -must not be active to decrease the attack surface of the system. X windows has a -long history of security vulnerabilities and should not be used unless approved -and documented. - - # Remediation is applicable only in certain platforms -if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then - -systemctl set-default multi-user.target - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Switch to multi-user runlevel - file: - src: /usr/lib/systemd/system/multi-user.target - dest: /etc/systemd/system/default.target - state: link - force: true - when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - low_complexity - - low_disruption - - medium_severity - - reboot_required - - restrict_strategy - - xwindows_runlevel_target - - - - - - - - - - - - - Introduction - The purpose of this guidance is to provide security configuration -recommendations and baselines for the Oracle Linux 9 operating -system. Recommended settings for the basic operating system are provided, -as well as for many network services that the system can provide to other systems. -The guide is intended for system administrators. Readers are assumed to -possess basic system administration skills for Unix-like systems, as well -as some familiarity with the product's documentation and administration -conventions. Some instructions within this guide are complex. -All directions should be followed completely and with understanding of -their effects in order to avoid serious adverse effects on the system -and its security. - - General Principles - The following general principles motivate much of the advice in this -guide and should also influence any configuration decisions that are -not explicitly covered. - - Encrypt Transmitted Data Whenever Possible - Data transmitted over a network, whether wired or wireless, is susceptible -to passive monitoring. Whenever practical solutions for encrypting -such data exist, they should be applied. Even if data is expected to -be transmitted only over a local network, it should still be encrypted. -Encrypting authentication data, such as passwords, is particularly -important. Networks of Oracle Linux 9 machines can and should be configured -so that no unencrypted authentication data is ever transmitted between -machines. - - - Least Privilege - Grant the least privilege necessary for user accounts and software to perform tasks. -For example, sudo can be implemented to limit authorization to super user -accounts on the system only to designated personnel. Another example is to limit -logins on server systems to only those administrators who need to log into them in -order to perform administration tasks. Using SELinux also follows the principle of -least privilege: SELinux policy can confine software to perform only actions on the -system that are specifically allowed. This can be far more restrictive than the -actions permissible by the traditional Unix permissions model. - - - Minimize Software to Minimize Vulnerability - The simplest way to avoid vulnerabilities in software is to avoid -installing that software. On Oracle Linux 9,the RPM Package Manager (originally Red Hat Package Manager, abbreviated RPM) -allows for careful management of -the set of software packages installed on a system. Installed software -contributes to system vulnerability in several ways. Packages that -include setuid programs may provide local attackers a potential path to -privilege escalation. Packages that include network services may give -this opportunity to network-based attackers. Packages that include -programs which are predictably executed by local users (e.g. after -graphical login) may provide opportunities for trojan horses or other -attack code to be run undetected. The number of software packages -installed on a system can almost always be significantly pruned to include -only the software for which there is an environmental or operational need. - - - Run Different Network Services on Separate Systems - Whenever possible, a server should be dedicated to serving exactly one -network service. This limits the number of other services that can -be compromised in the event that an attacker is able to successfully -exploit a software flaw in one network service. - - - Configure Security Tools to Improve System Robustness - Several tools exist which can be effectively used to improve a system's -resistance to and detection of unknown attacks. These tools can improve -robustness against attack at the cost of relatively little configuration -effort. In particular, this guide recommends and discusses the use of -host-based firewalling, SELinux for protection against -vulnerable services, and a logging and auditing infrastructure for -detection of problems. - - - - How to Use This Guide - Readers should heed the following points when using the guide. - - Formatting Conventions - Commands intended for shell execution, as well as configuration file text, -are featured in a monospace font. Italics are used -to indicate instances where the system administrator must substitute -the appropriate information into a command or configuration file. - - - Read Sections Completely and in Order - Each section may build on information and recommendations discussed in -prior sections. Each section should be read and understood completely; -instructions should never be blindly applied. Relevant discussion may -occur after instructions for an action. - - - Reboot Required - A system reboot is implicitly required after some actions in order to -complete the reconfiguration of the system. In many cases, the changes -will not take effect until a reboot is performed. In order to ensure -that changes are applied properly and to test functionality, always -reboot the system after applying a set of recommendations from this guide. - - - Root Shell Environment Assumed - Most of the actions listed in this document are written with the -assumption that they will be executed by the root user running the -/bin/bash shell. Commands preceded with a hash mark (#) -assume that the administrator will execute the commands as root, i.e. -apply the command via sudo whenever possible, or use -su to gain root privileges if sudo cannot be -used. Commands which can be executed as a non-root user are are preceded -by a dollar sign ($) prompt. - - - Test in Non-Production Environment - This guidance should always be tested in a non-production environment -before deployment. This test environment should simulate the setup in -which the system will be deployed as closely as possible. - - - - - - - - - combine_ovals.py from SCAP Security Guide - ssg: [0, 1, 69], python: 3.9.16 - 5.11 - 2023-09-14T00:00:00 - - - - - Configure Fapolicy Module to Employ a Deny-all, Permit-by-exception Policy to Allow the Execution of Authorized Software Programs. - - Oracle Linux 9 - - Configure Fapolicy Module to Employ a Deny-all, Permit-by-exception Policy - - - - - - - - - - - - - Configure System to Forward All Mail For The Root Account - - Oracle Linux 9 - - Check if root has the correct mail alias. - - - - - - - - - Configure System to Forward All Mail From Postmaster to The Root Account - - Oracle Linux 9 - - Check if postmaster has the correct mail alias. - - - - - - - - - Disable Postfix Network Listening - - Oracle Linux 9 - - Postfix network listening should be disabled - - - - - - - - - - Prevent Unrestricted Mail Relaying - - Oracle Linux 9 - - Ensure 'smtpd_client_restrictions' is configured with value 'permit_mynetworks[ \t]*[, \t][ \t]*reject' in /etc/postfix/main.cf - - - - - - - - - - - - Use Kerberos Security on All Exports - - Oracle Linux 9 - - Using Kerberos Security allows to cryptography authenticate a - valid user to an NFS share. - - - - - - - - - - Disable chrony daemon from acting as server - - Oracle Linux 9 - - Configure the port setting in /etc/chrony.conf to disable - server operation. - - - - - - - - - - Disable network management of chrony daemon - - Oracle Linux 9 - - Configure the cmdport setting in /etc/chrony.conf to disable - chronyc management connections over network. - - - - - - - - - - Configure Time Service Maxpoll Interval - - Oracle Linux 9 - - Configure the maxpoll setting in /etc/ntp.conf or chrony.conf - to continuously poll the time source servers. - - - - - - - - - - - - - - - - - - - - - - Ensure Chrony is only configured with the server directive - - Oracle Linux 9 - - Ensure Chrony has time sources configured with server directive - - - - - - - - - - A remote time server for Chrony is configured - - Oracle Linux 9 - - A remote NTP Server for time synchronization should be - specified (and dependencies are met) - - - - - - - - - Specify Additional Remote NTP Servers - - Oracle Linux 9 - - Multiple ntpd NTP Servers for time synchronization should be specified. - - - - - - - - - Specify a Remote NTP Server - - Oracle Linux 9 - - A remote ntpd NTP Server for time synchronization should be - specified (and dependencies are met) - - - - - - - - - Remove Host-Based Authentication Files - - Oracle Linux 9 - - There should not be any shosts.equiv files on the system. - - - - - - - - - Remove Rsh Trust Files - - Oracle Linux 9 - - There should not be any .rhosts or hosts.equiv files on the system. - - - - - - - - - - - Remove User Host-Based Authentication Files - - Oracle Linux 9 - - There should not be any .shosts files on the system. - - - - - - - - - Ensure tftp Daemon Uses Secure Mode - - Oracle Linux 9 - - The TFTP daemon should use secure mode. - - - - - - - - - - Verify Permissions on SSH Server Private *_key Key Files - - Oracle Linux 9 - - The system sshd key is owned by root:root and has the 0600 permission, or by a root:ssh_keys with the 0640 permission - - - - - - - - - Configure session renegotiation for SSH client - - Oracle Linux 9 - - Ensure 'RekeyLimit' is configured with the correct value in /etc/ssh/ssh_config and /etc/ssh/ssh_config.d/*.conf - - - - - - - - - - Enable SSH Server firewalld Firewall Exception - - Oracle Linux 9 - - If inbound SSH access is needed, the firewall should allow access to - the SSH service. - - - - - - - - - - - - - - - - - - - - Allow Only SSH Protocol 2 - - Oracle Linux 9 - - The OpenSSH daemon should be running protocol 2. - - - - - - - - - - - - - - - - - - - - Disable Compression Or Set Compression to delayed - - Oracle Linux 9 - - SSH should either have compression disabled or set to delayed. - - - - - - - - - - - - - - - - - Disable SSH Support for Rhosts RSA Authentication - - Oracle Linux 9 - - SSH can allow authentication through the obsolete rsh command - through the use of the authenticating user's SSH keys. This should be disabled. - - - - - - - - - - - - - - - - - - - - Limit Users' SSH Access - - Oracle Linux 9 - - One of the following parameters of the sshd configuration file is set: AllowUsers, DenyUsers, AllowGroups, DenyGroups. - - - - - - - - - - - - Force frequent session key renegotiation - - Oracle Linux 9 - - Ensure RekeyLimit is configured with the appropriate value in /etc/ssh/sshd_config - - - - - - - - - - - - - - - - - - - Set SSH Client Alive Interval - - Oracle Linux 9 - - The SSH idle timeout interval should be set to an - appropriate value. - - - - - - - - - - - - - - - - - - - Set SSH Client Alive Count Max - - Oracle Linux 9 - - The SSH ClientAliveCountMax should be set to an appropriate value (and - dependencies are met) - - - - - - - - - - - - - - - - - - - Ensure SSH LoginGraceTime is configured - - Oracle Linux 9 - - The SSH number seconds for login grace time should be set to an - appropriate value. - - - - - - - - - - - - - - - - - Set SSH authentication attempt limit - - Oracle Linux 9 - - The SSH MaxAuthTries should be set to an - appropriate value. - - - - - - - - - - - - - - - - - Set SSH MaxSessions limit - - Oracle Linux 9 - - The SSH number of max sessions should be set to an - appropriate value. - - - - - - - - - - - - - - - - - Ensure SSH MaxStartups is configured - - Oracle Linux 9 - - Ensure 'MaxStartups' is configured in - '/etc/ssh/sshd_config' - - - - - - - - - - - - - - - - - Distribute the SSH Server configuration to multiple files in a config directory. - - Oracle Linux 9 - - foo - - - - - - - - - - - - - - - - - - - - Enable Use of Privilege Separation - - Oracle Linux 9 - - Ensure 'UsePrivilegeSeparation' is configured with value 'sandbox' in '/etc/ssh/sshd_config' - - - - - - - - - - - - - Certificate status checking in SSSD - - Oracle Linux 9 - - SSSD should be configured with the correct ocsp_dgst - digest function - - - - - - - - - Enable Smartcards in SSSD - - Oracle Linux 9 - - SSSD should be configured to authenticate access to the system - using smart cards. - - - - - - - - - - - Configure SSSD to Expire Offline Credentials - - Oracle Linux 9 - - SSSD should be configured to expire offline credentials after 1 day. - - - - - - - - - Log USBGuard daemon audit events using Linux Audit - - Oracle Linux 9 - - Ensure 'AuditBackend' is configured with value 'LinuxAudit' in /etc/usbguard/usbguard-daemon.conf - - - - - - - - - - - - Authorize Human Interface Devices and USB hubs in USBGuard daemon - - Oracle Linux 9 - - Check that /etc/usbguard/rules.conf contains at least one non whitespace character and exists. - - - - - - - - - Generate USBGuard Policy - - Oracle Linux 9 - - Check that /etc/usbguard/rules.conf contains at least one non whitespace character and exists. - - - - - - - - - Disable graphical user interface - - Oracle Linux 9 - - Ensure that the default runlevel target is set to multi-user.target. - - - - - - - - - - - - Disable X Windows Startup By Setting Default Target - - Oracle Linux 9 - - Ensure that the default runlevel target is set to multi-user.target. - - - - - - - - - Enable authselect - - Oracle Linux 9 - - Check that authselect is enabled - - - - - - - - - - - - - Modify the System Login Banner - - Oracle Linux 9 - - The system login banner text should be set correctly. - - - - - - - - - Modify the System Login Banner for Remote Connections - - Oracle Linux 9 - - The system login banner text should be set correctly. - - - - - - - - - Enable GNOME3 Login Warning Banner - - Oracle Linux 9 - - Enable the GNOME3 Login warning banner. - - - - - - - - - - - - - - Set the GNOME3 Login Warning Banner Text - - Oracle Linux 9 - - Enable the GUI warning banner. - - - - - - - - - - - - - - Disallow Configuration to Bypass Password Requirements for Privilege Escalation - - Oracle Linux 9 - - Disallow Configuration to Bypass Password Requirements for Privilege Escalation. - - - - - - - - - Ensure PAM Displays Last Logon/Access Notification - - Oracle Linux 9 - - Configure the system to notify users of last login/access using pam_lastlog. - - - - - - - - - - An SELinux Context must be configured for the pam_faillock.so records directory - - Oracle Linux 9 - - An SELinux Context must be configured for the Faillock directory. - - - - - - - - - - Account Lockouts Must Be Logged - - Oracle Linux 9 - - Account Lockouts Must Be Logged - - - - - - - - - - - - - - - - - - Limit Password Reuse: password-auth - - Oracle Linux 9 - - The passwords to remember should be set correctly. - - - - - - - - - - - - - - - - - - - Limit Password Reuse: system-auth - - Oracle Linux 9 - - The passwords to remember should be set correctly. - - - - - - - - - - - - - - - - - - - Limit Password Reuse - - Oracle Linux 9 - - The passwords to remember should be set correctly. - - - - - - - - - - - - - - - - - - - - - - Account Lockouts Must Be Logged - - Oracle Linux 9 - - Account Lockouts Must Be Logged - - - - - - - - - - - - - - - - - - Lock Accounts After Failed Password Attempts - - Oracle Linux 9 - - Lockout account after failed login attempts - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Configure the root Account for Failed Password Attempts - - Oracle Linux 9 - - The root account should be configured to deny access after the number of - defined failed attempts has been reached. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Lock Accounts Must Persist - - Oracle Linux 9 - - Persist lockout account after reboot - - - - - - - - - - - - - - - - - - Set Interval For Counting Failed Password Attempts - - Oracle Linux 9 - - The number of allowed failed logins should be set correctly. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Set Lockout Time for Failed Password Attempts - - Oracle Linux 9 - - The unlock time after number of failed logins should be set correctly. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Ensure PAM password complexity module is enabled in password-auth - - Oracle Linux 9 - - The PAM module pam_pwquality is used in password-auth - - - - - - - - - Ensure PAM password complexity module is enabled in system-auth - - Oracle Linux 9 - - The PAM module pam_pwquality is used in system-auth - - - - - - - - - Ensure PAM Enforces Password Requirements - Authentication Retry Prompts Permitted Per-Session - - Oracle Linux 9 - - The password retry should meet minimum requirements - - - - - - - - - - - - - - - - - Set Password Hashing Algorithm in /etc/libuser.conf - - Oracle Linux 9 - - The password hashing algorithm should be set correctly in /etc/libuser.conf. - - - - - - - - - Set Password Hashing Algorithm in /etc/login.defs - - Oracle Linux 9 - - The password hashing algorithm should be set correctly in /etc/login.defs. - - - - - - - - - Set PAM''s Password Hashing Algorithm - password-auth - - Oracle Linux 9 - - The password hashing algorithm should be set correctly in /etc/pam.d/password-auth. - - - - - - - - - Set PAM''s Password Hashing Algorithm - - Oracle Linux 9 - - The password hashing algorithm should be set correctly in /etc/pam.d/system-auth. - - - - - - - - - Set Password Hashing Minimum Rounds in /etc/login.defs - - Oracle Linux 9 - - The password hashing minimum rounds should be set correctly in /etc/login.defs. - - - - - - - - - - - - - - - - - Disable Ctrl-Alt-Del Burst Action - - Oracle Linux 9 - - Configure the CtrlAltDelBurstAction setting in /etc/systemd/system.conf - or /etc/systemd/system.conf.d/* to none to prevent a reboot if Ctrl-Alt-Delete is - pressed more than 7 times in 2 seconds. - - - - - - - - - Disable Ctrl-Alt-Del Reboot Activation - - Oracle Linux 9 - - By default, the system will reboot when the - Ctrl-Alt-Del key sequence is pressed. - - - - - - - - - Verify that Interactive Boot is Disabled - - Oracle Linux 9 - - The ability for users to perform interactive startups should - be disabled. - - - - - - - - - - - - - Require Authentication for Emergency Systemd Target - - Oracle Linux 9 - - The requirement for a password to boot into emergency mode - should be configured correctly. - - - - - - - - - - - - Require Authentication for Single User Mode - - Oracle Linux 9 - - The requirement for a password to boot into single-user mode - should be configured correctly. - - - - - - - - - - - - Support session locking with tmux - - Oracle Linux 9 - - Check if tmux is configured to exec at the end of bashrc. - - - - - - - - - Configure tmux to lock session after inactivity - - Oracle Linux 9 - - Check if tmux is configured to lock sessions after period of inactivity. - - - - - - - - - - Configure the tmux Lock Command - - Oracle Linux 9 - - Check if the vlock command is configured to be used as a locking mechanism in tmux. - - - - - - - - - - Prevent user from disabling the screen lock - - Oracle Linux 9 - - Check that tmux is not listed in /etc/shells - - - - - - - - - Configure opensc Smart Card Drivers - - Oracle Linux 9 - - Configure the organization's smart card driver so that only - the smart card in use by the organization will be recognized by the system. - - - - - - - - - Force opensc To Use Defined Smart Card Driver - - Oracle Linux 9 - - Force opensc to use the organization's smart card driver so that only - the smart card in use by the organization will be recognized by the system. - - - - - - - - - Ensure All Accounts on the System Have Unique User IDs - - Oracle Linux 9 - - All accounts on the system should have unique IDs for proper accountability. - - - - - - - - - Only Authorized Local User Accounts Exist on Operating System - - Oracle Linux 9 - - Besides the default operating system user, there should be no other users - except the users that are authorized to exist locally on the operating system. - - - - - - - - - Ensure All Groups on the System Have Unique Group ID - - Oracle Linux 9 - - All groups on the system should have unique names for proper accountability. - - - - - - - - - Set Account Expiration Following Inactivity in password-auth - - Oracle Linux 9 - - The accounts should be configured to expire automatically following password expiration. - - - - - - - - - Set Account Expiration Following Inactivity in system-auth - - Oracle Linux 9 - - The accounts should be configured to expire automatically following password expiration. - - - - - - - - - Set Account Expiration Following Inactivity - - Oracle Linux 9 - - The accounts should be configured to expire automatically following password expiration. - - - - - - - - - Ensure All Accounts on the System Have Unique Names - - Oracle Linux 9 - - All accounts on the system should have unique names for proper accountability. - - - - - - - - - Set Password Maximum Age - - Oracle Linux 9 - - The maximum password age policy should meet minimum requirements. - - - - - - - - - Set Password Minimum Age - - Oracle Linux 9 - - The minimum password age policy should be set appropriately. - - - - - - - - - Set Password Minimum Length in login.defs - - Oracle Linux 9 - - The password minimum length should be set appropriately. - - - - - - - - - Set Existing Passwords Maximum Age - - Oracle Linux 9 - - Set Existing Passwords Maximum Age - - - - - - - - - - - Set Existing Passwords Minimum Age - - Oracle Linux 9 - - Set Existing Passwords Maximum Age - - - - - - - - - - - Set Password Warning Age - - Oracle Linux 9 - - The password expiration warning age should be set appropriately. - - - - - - - - - Verify All Account Password Hashes are Shadowed - - Oracle Linux 9 - - All password hashes should be shadowed. - - - - - - - - - Verify All Account Password Hashes are Shadowed with SHA512 - - Oracle Linux 9 - - All password hashes should be shadowed. - - - - - - - - - Ensure all users last password change date is in the past - - Oracle Linux 9 - - All passwords last change date is in the past. - - - - - - - - - - Set number of Password Hashing Rounds - password-auth - - Oracle Linux 9 - - The number of rounds for password hashing should be set correctly. - - - - - - - - - - - - - Set number of Password Hashing Rounds - system-auth - - Oracle Linux 9 - - The number of rounds for password hashing should be set correctly. - - - - - - - - - - - - - All GIDs referenced in /etc/passwd must be defined in /etc/group - - Oracle Linux 9 - - All GIDs referenced in /etc/passwd must be defined in /etc/group. - - - - - - - - - Prevent Login to Accounts With Empty Password - - Oracle Linux 9 - - The file /etc/pam.d/system-auth should not contain the nullok option - - - - - - - - - Ensure There Are No Accounts With Blank or Null Passwords - - Oracle Linux 9 - - The file /etc/shadow shows that there aren't empty passwords - - - - - - - - - Verify No netrc Files Exist - - Oracle Linux 9 - - The .netrc files contain login information used to auto-login into FTP servers and reside in the user's home directory. Any .netrc files should be removed. - - - - - - - - - Verify Only Root Has UID 0 - - Oracle Linux 9 - - Only the root account should be assigned a user id of 0. - - - - - - - - - Verify Root Has A Primary GID 0 - - Oracle Linux 9 - - The root account should have primary group of 0 - - - - - - - - - Direct root Logins Not Allowed - - Oracle Linux 9 - - Preventing direct root logins help ensure accountability for actions - taken on the system using the root account. - - - - - - - - - - Ensure that System Accounts Are Locked - - Oracle Linux 9 - - Ensure that System Accounts Are Locked - - - - - - - - - Ensure that System Accounts Do Not Run a Shell Upon Login - - Oracle Linux 9 - - The root account is the only system account that should have - a login shell. - - - - - - - - - - - - - - - - - - - Restrict Serial Port Root Logins - - Oracle Linux 9 - - Preventing direct root login to serial port interfaces helps - ensure accountability for actions taken on the system using the root - account. - - - - - - - - - Restrict Virtual Console Root Logins - - Oracle Linux 9 - - Preventing direct root login to virtual console devices - helps ensure accountability for actions taken on the system using the - root account. - - - - - - - - - Enforce usage of pam_wheel for su authentication - - Oracle Linux 9 - - Only members of the wheel group should be able to authenticate through the su command. - - - - - - - - - Ensure Home Directories are Created for New Users - - Oracle Linux 9 - - CREATE_HOME should be enabled - - - - - - - - - Ensure the Logon Failure Delay is Set Correctly in login.defs - - Oracle Linux 9 - - The delay between failed authentication attempts should be - set for all users specified in /etc/login.defs - - - - - - - - - Limit the Number of Concurrent Login Sessions Allowed Per User - - Oracle Linux 9 - - The maximum number of concurrent login sessions per user should meet - minimum requirements. - - - - - - - - - - - - - Configure Polyinstantiation of /tmp Directories - - Oracle Linux 9 - - - - - - - - - - - - Configure Polyinstantiation of /var/tmp Directories - - Oracle Linux 9 - - - - - - - - - - - - Set Interactive Session Timeout - - Oracle Linux 9 - - Checks interactive shell timeout - - - - - - - - - - - User Initialization Files Must Not Run World-Writable Programs - - Oracle Linux 9 - - User Initialization Files Must Not Execute World-Writable Programs - - - - - - - - - All Interactive Users Must Have A Home Directory Defined - - Oracle Linux 9 - - All Interactive Users Must Have A Home Directory Defined - - - - - - - - - All Interactive Users Home Directories Must Exist - - Oracle Linux 9 - - All Interactive Users Home Directories Must Exist - - - - - - - - - - All Interactive User Home Directories Must Be Group-Owned By The Primary Group - - Oracle Linux 9 - - All interactive user's Home Directories must be group-owned by its user - - - - - - - - - Ensure All User Initialization Files Have Mode 0740 Or Less Permissive - - Oracle Linux 9 - - User initialization files have mode 0740 or less permissive - - - - - - - - - All Interactive User Home Directories Must Have mode 0750 Or Less Permissive - - Oracle Linux 9 - - All Interactive User Home Directories Must Have mode 0750 Or Less Permissive - - - - - - - - - Ensure that User Home Directories are not Group-Writable or World-Readable - - Oracle Linux 9 - - Ensure that User Home Directories are not Group-Writable or World-Readable - - - - - - - - - Ensure that Root's Path Does Not Include World or Group-Writable Directories - - Oracle Linux 9 - - Check each directory in root's path and make use it does - not grant write permission to group and other - - - - - - - - - Ensure that Root's Path Does Not Include Relative Paths or Null Directories - - Oracle Linux 9 - - The environment variable PATH should be set correctly for - the root user. - - - - - - - - - - - - - - Ensure the Default Bash Umask is Set Correctly - - Oracle Linux 9 - - The default umask for users of the bash shell - - - - - - - - - - Ensure the Default C Shell Umask is Set Correctly - - Oracle Linux 9 - - The default umask for users of the csh shell - - - - - - - - - - Ensure the Default Umask is Set Correctly in login.defs - - Oracle Linux 9 - - The default umask for all users specified in /etc/login.defs - - - - - - - - - - Ensure the Default Umask is Set Correctly in /etc/profile - - Oracle Linux 9 - - The default umask for all users should be set correctly - - - - - - - - - - Ensure the Default Umask is Set Correctly For Interactive Users - - Oracle Linux 9 - - Ensure the Default Umask is Set Correctly For Interactive Users - - - - - - - - - Enable Syscall Auditing - - Oracle Linux 9 - - Syscall auditing should not be disabled. - - - - - - - - - - - - - - - - Make the auditd Configuration Immutable - - Oracle Linux 9 - - Force a reboot to change audit rules is enabled - - - - - - - - - - - - - - - - Record Events that Modify the System's Mandatory Access Controls - - Oracle Linux 9 - - Audit rules that detect changes to the system's mandatory access controls (SELinux) are enabled. - - - - - - - - - - - - - - - - Record Events that Modify the System's Mandatory Access Controls in usr/share - - Oracle Linux 9 - - Audit rules that detect changes to the system's - mandatory access controls (SELinux) in usr/share/selinux are enabled. - - - - - - - - - - - - - - - - Record Events that Modify the System's Network Environment - - Oracle Linux 9 - - The network environment should not be modified by anything other than - administrator action. Any change to network parameters should be audited. - - - - - - - - - - - - - - - - - - - - - - - - - - Record Attempts to Alter Process and Session Initiation Information - - Oracle Linux 9 - - Audit rules should capture information about session initiation. - - - - - - - - - - - - - - - - - - - - Ensure auditd Collects System Administrator Actions - /etc/sudoers - - Oracle Linux 9 - - Audit actions taken by system administrators on the system - /etc/sudoers. - - - - - - - - - - - - - - - - Ensure auditd Collects System Administrator Actions - /etc/sudoers.d/ - - Oracle Linux 9 - - Audit actions taken by system administrators on the system - /etc/sudoers.d/. - - - - - - - - - - - - - - - - Record Events When Privileged Executables Are Run - - Oracle Linux 9 - - Ensure audit rule for all uses of privileged functions is enabled - - - - - - - - - - - - - - - - - - - - - - Ensure auditd Collects System Administrator Actions - - Oracle Linux 9 - - Audit actions taken by system administrators on the system. - - - - - - - - - - - - - - - - - - Shutdown System When Auditing Failures Occur - - Oracle Linux 9 - - The system will shutdown when auditing fails. - - - - - - - - - - - - - - - - Record Events that Modify User/Group Information - - Oracle Linux 9 - - Audit rules should detect modification to system files that hold information about users and groups. - - - - - - - - - - - - - - - - - - - - - - - - Record Access Events to Audit Log Directory - - Oracle Linux 9 - - Audit rules about the read events to /var/log/audit - - - - - - - - - - - - - - - - System Audit Directories Must Be Group Owned By Root - - Oracle Linux 9 - - Checks that all /var/log/audit directories are group owned by the root user. - - - - - - - - - - - - - - - - - - - - System Audit Directories Must Be Owned By Root - - Oracle Linux 9 - - Checks that all /var/log/audit directories are owned by the root user. - - - - - - - - - - - - - - - - System Audit Logs Must Have Mode 0750 or Less Permissive - - Oracle Linux 9 - - Checks for correct permissions for audit logs. - - - - - - - - - - - - - - - - - - - - - System Audit Logs Must Be Group Owned By Root - - Oracle Linux 9 - - Checks that all audit log files are group owned by the root user. - - - - - - - - - - - - - - - - - - - - - - System Audit Logs Must Be Owned By Root - - Oracle Linux 9 - - Checks that all /var/log/audit files and directories are owned by the root user and group. - - - - - - - - - - - - - - - - - System Audit Logs Must Be Owned By Root - - Oracle Linux 9 - - Checks that all audit log files are owned by the root user. - - - - - - - - - - - - - System Audit Logs Must Have Mode 0640 or Less Permissive - - Oracle Linux 9 - - Checks for correct permissions for all audit log files. - - - - - - - - - - - - - - - - Record Events that Modify the System's Discretionary Access Controls - umount - - Oracle Linux 9 - - The changing of file permissions and attributes should be audited. - - - - - - - - - - - - - - - - Ensure auditd Collects File Deletion Events by User - - Oracle Linux 9 - - Audit files deletion events. - - - - - - - - - - - - - Ensure auditd Collects Unauthorized Access Attempts to Files (unsuccessful) - - Oracle Linux 9 - - Audit rules about the unauthorized access attempts to files (unsuccessful) are enabled. - - - - - - - - - - - - - - Ensure auditd Collects Information on Kernel Module Loading and Unloading - - Oracle Linux 9 - - The audit rules should be configured to log information about kernel module loading and unloading. - - - - - - - - - - - Ensure auditd Collects Information on Kernel Module Unloading - delete_module - - Oracle Linux 9 - - The audit rules should be configured to log information about kernel module loading and unloading. - - - - - - - - - - - - - - - - - - - - - - - - Ensure auditd Collects Information on Kernel Module Loading and Unloading - finit_module - - Oracle Linux 9 - - The audit rules should be configured to log information about kernel module loading and unloading. - - - - - - - - - - - - - - - - - - - - - - - - Ensure auditd Collects Information on Kernel Module Loading - init_module - - Oracle Linux 9 - - The audit rules should be configured to log information about kernel module loading and unloading. - - - - - - - - - - - - - - - - - - - - - - - - Record Attempts to Alter Logon and Logout Events - - Oracle Linux 9 - - Audit rules should be configured to log successful and unsuccessful login and logout events. - - - - - - - - - - - Ensure auditd Collects Information on the Use of Privileged Commands - - Oracle Linux 9 - - Audit rules about the information on the use of privileged commands are enabled. - - - - - - - - - - - - - - - - - - Record attempts to alter time through adjtimex - - Oracle Linux 9 - - Record attempts to alter time through adjtimex. - - - - - - - - - - - - - - - - - - - - - - - - Record Attempts to Alter Time Through clock_settime - - Oracle Linux 9 - - Record attempts to alter time through clock_settime. - - - - - - - - - - - - - - - - - - - - - - - - Record attempts to alter time through settimeofday - - Oracle Linux 9 - - Record attempts to alter time through settimeofday. - - - - - - - - - - - - - - - - - - - - - - - - Record Attempts to Alter Time Through stime - - Oracle Linux 9 - - Record attempts to alter time through stime. Note that on + + + + + + + + + + + + + + + + OVALFileLinker from SCAP Security Guide + ssg: [0, 1, 76], python: 3.9.21 + 5.11 + 2025-05-06T00:00:00 + + + + + Make the auditd Configuration Immutable + + Oracle Linux 9 + + + Force a reboot to change audit rules is enabled + + + + + + + + + + + + + + + Configure immutable Audit login UIDs + + Oracle Linux 9 + + + Check if system is configured to make login UIDs immutable + + + + + + + + + + + + + + + Record Events that Modify the System's Mandatory Access Controls + + Oracle Linux 9 + + + Audit rules that detect changes to the system's mandatory access controls (SELinux) are enabled. + + + + + + + + + + + + + + + Record Events that Modify the System's Mandatory Access Controls in usr/share + + Oracle Linux 9 + + + Audit rules that detect changes to the system's + mandatory access controls (SELinux) in usr/share/selinux are enabled. + + + + + + + + + + + + + + + Record Events that Modify the System's Network Environment + + Oracle Linux 9 + + + The network environment should not be modified by anything other than + administrator action. Any change to network parameters should be audited. + + + + + + + + + + + + + + + + + + + + + + + + + Record Attempts to Alter Process and Session Initiation Information + + Oracle Linux 9 + + + Audit rules should capture information about session initiation. + + + + + + + + + + + + + + + + + + + Ensure auditd Collects System Administrator Actions - /etc/sudoers + + Oracle Linux 9 + + + Audit actions taken by system administrators on the system - /etc/sudoers. + + + + + + + + + + + + + + + Ensure auditd Collects System Administrator Actions - /etc/sudoers.d/ + + Oracle Linux 9 + + + Audit actions taken by system administrators on the system - /etc/sudoers.d/. + + + + + + + + + + + + + + + Record Events When Privileged Executables Are Run + + Oracle Linux 9 + + + Ensure audit rule for all uses of privileged functions is enabled + + + + + + + + + + + + + + + + + + + + + Ensure auditd Collects System Administrator Actions + + Oracle Linux 9 + + + Audit actions taken by system administrators on the system. + + + + + + + + + + + + + + + + + Shutdown System When Auditing Failures Occur + + Oracle Linux 9 + + + The system will shutdown when auditing fails. + + + + + + + + + + + + + + + Record Events that Modify User/Group Information + + Oracle Linux 9 + + + Audit rules should detect modification to system files that hold information about users and groups. + + + + + + + + + + + + + + + + + + + + + + + Record Access Events to Audit Log Directory + + Oracle Linux 9 + + + Audit rules about the read events to /var/log/audit + + + + + + + + + + + + + + + System Audit Directories Must Be Group Owned By Root + + Oracle Linux 9 + + + Checks that all /var/log/audit directories are group owned by the root user. + + + + + + + + + + + + + + + + + + + System Audit Directories Must Be Owned By Root + + Oracle Linux 9 + + + Checks that all /var/log/audit directories are owned by the root user. + + + + + + + + + + + + + + + System Audit Logs Must Have Mode 0750 or Less Permissive + + Oracle Linux 9 + + + Checks for correct permissions for audit logs. + + + + + + + + + + + + + + + + + + + + System Audit Logs Must Be Group Owned By Root + + Oracle Linux 9 + + + Checks that all audit log files are group owned by the root user. + + + + + + + + + + + + + + + + + + + + + System Audit Logs Must Be Owned By Root + + Oracle Linux 9 + + + Checks that all /var/log/audit files and directories are owned by the root user and group. + + + + + + + + + + + + + + + + System Audit Logs Must Have Mode 0640 or Less Permissive + + Oracle Linux 9 + + + Checks for correct permissions for all audit log files. + + + + + + + + + + + + + + + Record Events that Modify the System's Discretionary Access Controls - umount + + Oracle Linux 9 + + + The changing of file permissions and attributes should be audited. + + + + + + + + + + + + + + + Ensure auditd Collects File Deletion Events by User + + Oracle Linux 9 + + + Audit files deletion events. + + + + + + + + + + + + Ensure auditd Collects Unauthorized Access Attempts to Files (unsuccessful) + + Oracle Linux 9 + + + Audit rules about the unauthorized access attempts to files (unsuccessful) are enabled. + + + + + + + + + + + + + Ensure auditd Collects Information on Kernel Module Loading and Unloading + + Oracle Linux 9 + + + The audit rules should be configured to log information about kernel module loading and unloading. + + + + + + + + + + Ensure auditd Collects Information on Kernel Module Unloading - delete_module + + Oracle Linux 9 + + + The audit rules should be configured to log information about kernel module loading and unloading. + + + + + + + + + + + + + + + + + + + + + + + Ensure auditd Collects Information on Kernel Module Loading and Unloading - finit_module + + Oracle Linux 9 + + + The audit rules should be configured to log information about kernel module loading and unloading. + + + + + + + + + + + + + + + + + + + + + + + Ensure auditd Collects Information on Kernel Module Loading - init_module + + Oracle Linux 9 + + + The audit rules should be configured to log information about kernel module loading and unloading. + + + + + + + + + + + + + + + + + + + + + + + Record Attempts to Alter Logon and Logout Events + + Oracle Linux 9 + + + Audit rules should be configured to log successful and unsuccessful login and logout events. + + + + + + + + + + Ensure auditd Collects Information on the Use of Privileged Commands + + Oracle Linux 9 + + + Audit rules about the information on the use of privileged commands are enabled. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Record attempts to alter time through adjtimex + + Oracle Linux 9 + + + Record attempts to alter time through adjtimex. + + + + + + + + + + + + + + + + + + + + + + + Record Attempts to Alter Time Through clock_settime + + Oracle Linux 9 + + + Record attempts to alter time through clock_settime. + + + + + + + + + + + + + + + + + + + + + + + Record attempts to alter time through settimeofday + + Oracle Linux 9 + + + Record attempts to alter time through settimeofday. + + + + + + + + + + + + + + + + + + + + + + + Record Attempts to Alter Time Through stime + + Oracle Linux 9 + + + Record attempts to alter time through stime. Note that on 64-bit architectures the stime system call is not defined in the audit - system calls lookup table. - - - - - - - - - - - - - - - - - - - - - - Record Attempts to Alter the localtime File - - Oracle Linux 9 - - Record attempts to alter time through /etc/localtime. - - - - - - - - - - - - - - - - Configure auditd to use audispd's syslog plugin - - Oracle Linux 9 - - active setting in /etc/audit/plugins.d/syslog.conf is set to 'yes' - - - - - - - - - Configure auditd Disk Error Action on Disk Error - - Oracle Linux 9 - - disk_error_action setting in /etc/audit/auditd.conf is set to a certain action - - - - - - - - - Configure auditd Disk Error Action on Disk Error - - Oracle Linux 9 - - disk_error_action setting in /etc/audit/auditd.conf is set to SYSLOG, SINGLE or HALT - - - - - - - - - - - Configure auditd Disk Full Action when Disk Space Is Full - - Oracle Linux 9 - - disk_full_action setting in /etc/audit/auditd.conf is set to a certain action - - - - - - - - - Configure auditd Disk Full Action when Disk Space Is Full - - Oracle Linux 9 - - disk_full_action setting in /etc/audit/auditd.conf is set to SYSLOG, SINGLE or HALT - - - - - - - - - - - Configure auditd mail_acct Action on Low Disk Space - - Oracle Linux 9 - - action_mail_acct setting in /etc/audit/auditd.conf is set to a certain account - - - - - - - - - Configure auditd admin_space_left Action on Low Disk Space - - Oracle Linux 9 - - admin_space_left_action setting in /etc/audit/auditd.conf is set to a certain action - - - - - - - - - Configure auditd admin_space_left on Low Disk Space - - Oracle Linux 9 - - admin_space_left setting in /etc/audit/auditd.conf is set to at least a certain value - - - - - - - - - Configure auditd flush priority - - Oracle Linux 9 - - The setting for flush in /etc/audit/auditd.conf - - - - - - - - - Configure auditd Max Log File Size - - Oracle Linux 9 - - max_log_file setting in /etc/audit/auditd.conf is set to at least a certain value - - - - - - - - - Configure auditd max_log_file_action Upon Reaching Maximum Log Size - - Oracle Linux 9 - - max_log_file_action setting in /etc/audit/auditd.conf is set to a certain action - - - - - - - - - Configure auditd max_log_file_action Upon Reaching Maximum Log Size - - Oracle Linux 9 - - max_log_file_action setting in /etc/audit/auditd.conf is set to a certain action - - - - - - - - - - Configure auditd Number of Logs Retained - - Oracle Linux 9 - - num_logs setting in /etc/audit/auditd.conf is set to at least a certain value - - - - - - - - - Configure auditd space_left Action on Low Disk Space - - Oracle Linux 9 - - space_left_action setting in /etc/audit/auditd.conf is set to a certain action - - - - - - - - - Configure auditd space_left on Low Disk Space - - Oracle Linux 9 - - space_left setting in /etc/audit/auditd.conf is set to at least a certain value - - - - - - - - - Set hostname as computer node name in audit logs - - Oracle Linux 9 - - Ensure 'name_format' is configured with value 'hostname' in /etc/audit/auditd.conf - - - - - - - - - Appropriate Action Must be Setup When the Internal Audit Event Queue is Full - - Oracle Linux 9 - - Ensure 'overflow_action' is configured with value '(syslog|single|halt)' in /etc/audit/auditd.conf - - - - - - - - - Disable Recovery Booting - - Oracle Linux 9 - - Recovery mode should be disabled. - - - - - - - - - Set the Boot Loader Admin Username to a Non-Default Value - - Oracle Linux 9 - - The grub2 boot loader superuser should have a username that is hard to guess. - - - - - - - - - Set Boot Loader Password in grub2 - - Oracle Linux 9 - - The grub2 boot loader should have password protection enabled. - - - - - - - - - Set the UEFI Boot Loader Admin Username to a Non-Default Value - - Oracle Linux 9 - - The grub2 boot loader superuser should have a username that is hard to guess. - - - - - - - - - Set the UEFI Boot Loader Password - - Oracle Linux 9 - - The UEFI grub2 boot loader should have password protection enabled. - - - - - - - - - Ensure cron Is Logging To Rsyslog - - Oracle Linux 9 - - Rsyslog should be configured to capture cron messages. - - - - - - - - - - Ensure Rsyslog Authenticates Off-Loaded Audit Records - - Oracle Linux 9 - - Rsyslogd must authenticate remote system its sending logs to. - - - - - - - - - - - - Ensure Rsyslog Encrypts Off-Loaded Audit Records - - Oracle Linux 9 - - Rsyslogd must encrypt the off-loading of logs off of the system. - - - - - - - - - - - - Ensure Rsyslog Encrypts Off-Loaded Audit Records - - Oracle Linux 9 - - Rsyslogd must encrypt the off-loading of logs off of the system. - - - - - - - - - - - - Ensure remote access methods are monitored in Rsyslog - - Oracle Linux 9 - - Rsyslog should be configured to monitor remote access methods. - - - - - - - - - - - Ensure Logrotate Runs Periodically - - Oracle Linux 9 - - + system calls lookup table. + + + + + + + + + + + + + + + + + + + + + Record Attempts to Alter the localtime File + + Oracle Linux 9 + + + Record attempts to alter time through /etc/localtime. + + + + + + + + + + + + + + + Configure auditd to use audispd's syslog plugin + + Oracle Linux 9 + + + active setting in /etc/audit/plugins.d/syslog.conf is set to 'yes' + + + + + + + + Configure auditd Disk Error Action on Disk Error + + Oracle Linux 9 + + + disk_error_action setting in /etc/audit/auditd.conf is set to a certain action + + + + + + + + Configure auditd Disk Error Action on Disk Error + + Oracle Linux 9 + + + disk_error_action setting in /etc/audit/auditd.conf is set to SYSLOG, SINGLE or HALT + + + + + + + + + + Configure auditd Disk Full Action when Disk Space Is Full + + Oracle Linux 9 + + + disk_full_action setting in /etc/audit/auditd.conf is set to a certain action + + + + + + + + Configure auditd Disk Full Action when Disk Space Is Full + + Oracle Linux 9 + + + disk_full_action setting in /etc/audit/auditd.conf is set to SYSLOG, SINGLE or HALT + + + + + + + + + + Configure auditd mail_acct Action on Low Disk Space + + Oracle Linux 9 + + + action_mail_acct setting in /etc/audit/auditd.conf is set to a certain account + + + + + + + + Configure auditd admin_space_left Action on Low Disk Space + + Oracle Linux 9 + + + admin_space_left_action setting in /etc/audit/auditd.conf is set to a certain action + + + + + + + + Configure auditd flush priority + + Oracle Linux 9 + + + The setting for flush in /etc/audit/auditd.conf + + + + + + + + Configure auditd max_log_file_action Upon Reaching Maximum Log Size + + Oracle Linux 9 + + + max_log_file_action setting in /etc/audit/auditd.conf is set to a certain action + + + + + + + + Configure auditd max_log_file_action Upon Reaching Maximum Log Size + + Oracle Linux 9 + + + max_log_file_action setting in /etc/audit/auditd.conf is set to a certain action + + + + + + + + + Configure auditd space_left on Low Disk Space + + Oracle Linux 9 + + + space_left setting in /etc/audit/auditd.conf is set to at least a certain value + + + + + + + + Configure auditd space_left Action on Low Disk Space + + Oracle Linux 9 + + + space_left_action setting in /etc/audit/auditd.conf is set to a certain action + + + + + + + + Configure auditd space_left on Low Disk Space + + Oracle Linux 9 + + + space_left setting in /etc/audit/auditd.conf is set to at least a certain value + + + + + + + + Set type of computer node name logging in audit logs + + Oracle Linux 9 + + + Ensure 'name_format' is configured with value 'hostname|fdq|numeric' in /etc/audit/auditd.conf + + + + + + + + Appropriate Action Must be Setup When the Internal Audit Event Queue is Full + + Oracle Linux 9 + + + Ensure 'overflow_action' is configured with value '(syslog|single|halt)' in /etc/audit/auditd.conf + + + + + + + + Configure Fapolicy Module to Employ a Deny-all, Permit-by-exception Policy to Allow the Execution of Authorized Software Programs. + + Oracle Linux 9 + + + Configure Fapolicy Module to Employ a Deny-all, Permit-by-exception Policy + + + + + + + + + + + + Configure System to Forward All Mail For The Root Account + + Oracle Linux 9 + + + Check if root has the correct mail alias. + + + + + + + + Configure System to Forward All Mail From Postmaster to The Root Account + + Oracle Linux 9 + + + Check if postmaster has the correct mail alias. + + + + + + + + Disable Postfix Network Listening + + Oracle Linux 9 + + + Postfix network listening should be disabled + + + + + + + + + Prevent Unrestricted Mail Relaying + + Oracle Linux 9 + + + Ensure 'smtpd_client_restrictions' is configured with value 'permit_mynetworks[ \t]*[, \t][ \t]*reject' in /etc/postfix/main.cf + + + + + + + + + + + Use Kerberos Security on All Exports + + Oracle Linux 9 + + + Using Kerberos Security allows to cryptography authenticate a + valid user to an NFS share. + + + + + + + + + Disable chrony daemon from acting as server + + Oracle Linux 9 + + + Configure the port setting in /etc/chrony.conf to disable + server operation. + + + + + + + + Chrony Configure Pool and Server + + Oracle Linux 9 + + + A remote NTP Server for time synchronization should be specified (and dependencies are met) + + + + + + + + + Disable network management of chrony daemon + + Oracle Linux 9 + + + Configure the cmdport setting in /etc/chrony.conf to disable + chronyc management connections over network. + + + + + + + + Configure Time Service Maxpoll Interval + + Oracle Linux 9 + + + Configure the maxpoll setting in /etc/ntp.conf or chrony.conf + to continuously poll the time source servers. + + + + + + + + + + + + + + + Specify Additional Remote NTP Servers + + Oracle Linux 9 + + + Multiple remote chronyd or ntpd NTP Servers for time synchronization should be specified (and dependencies are met) + + + + + + + + + Ensure that chronyd is running under chrony user account + + Oracle Linux 9 + + + Ensure that no other user than chrony is configured to run the chrony service + + + + + + + + Ensure Chrony is only configured with the server directive + + Oracle Linux 9 + + + Ensure Chrony has time sources configured with server directive + + + + + + + + + A remote time server for Chrony is configured + + Oracle Linux 9 + + + A remote NTP Server for time synchronization should be + specified (and dependencies are met) + + + + + + + + Verify Group Who Owns /etc/chrony.keys File + + Oracle Linux 9 + + + /etc/chrony.keys should be owned by chrony group + + + + + + + + + + + + + + + Specify Additional Remote NTP Servers + + Oracle Linux 9 + + + Multiple ntpd NTP Servers for time synchronization should be specified. + + + + + + + + Remove Host-Based Authentication Files + + Oracle Linux 9 + + + There should not be any shosts.equiv files on the system. + + + + + + + + Remove Rsh Trust Files + + Oracle Linux 9 + + + There should not be any .rhosts or hosts.equiv files on the system. + + + + + + + + + + Remove User Host-Based Authentication Files + + Oracle Linux 9 + + + There should not be any .shosts files on the system. + + + + + + + + Ensure tftp Daemon Uses Secure Mode + + Oracle Linux 9 + + + The TFTP daemon should use secure mode. + + + + + + + + + Configure SNMP Service to Use Only SNMPv3 or Newer + + Oracle Linux 9 + + + SNMP version 1 and 2c must not be enabled. + + + + + + + + + Verify Permissions on SSH Server Private *_key Key Files + + Oracle Linux 9 + + + The system sshd key is owned by root:root and has the 0600 permission, or by a root:ssh_keys with the 0640 permission + + + + + + + + Configure session renegotiation for SSH client + + Oracle Linux 9 + + + Ensure 'RekeyLimit' is configured with the correct value in /etc/ssh/ssh_config and /etc/ssh/ssh_config.d/*.conf + + + + + + + + + Enable SSH Server firewalld Firewall Exception + + Oracle Linux 9 + + + If inbound SSH access is needed, the firewall should allow access to + the SSH service. + + + + + + + + + + + + + + + + + + SSHD Must Include System Crypto Policy Config File + + Oracle Linux 9 + + + Ensure SSHD to include the system crypto policy + + + + + + + + + Limit Users' SSH Access + + Oracle Linux 9 + + + One of the following parameters of the sshd configuration file is set: AllowUsers, DenyUsers, AllowGroups, DenyGroups. + + + + + + + + + + + Force frequent session key renegotiation + + Oracle Linux 9 + + + Ensure RekeyLimit is configured with the appropriate value in /etc/ssh/sshd_config + + + + + + + + + + + + + + + + + + Set SSH Client Alive Interval + + Oracle Linux 9 + + + The SSH idle timeout interval should be set to an + appropriate value. + + + + + + + + + + + + + + + + + + + Ensure SSH LoginGraceTime is configured + + Oracle Linux 9 + + + The SSH number seconds for login grace time should be set to an + appropriate value. + + + + + + + + + + + + + + + + + Set SSH authentication attempt limit + + Oracle Linux 9 + + + The SSH MaxAuthTries should be set to an + appropriate value. + + + + + + + + + + + + + + + + + Set SSH MaxSessions limit + + Oracle Linux 9 + + + The SSH number of max sessions should be set to an + appropriate value. + + + + + + + + + + + + + + + + + Ensure SSH MaxStartups is configured + + Oracle Linux 9 + + + Ensure 'MaxStartups' is properly configured in SSH configuration files. + + + + + + + + + + + + + + + + Distribute the SSH Server configuration to multiple files in a config directory. + + Oracle Linux 9 + + + foo + + + + + + + + + + + + + + + + + + + Use Only Strong MACs + + Oracle Linux 9 + + + Ensure only strong MAC algorithms are used + + + + + + + + + + + + + + + + + + Certificate status checking in SSSD + + Oracle Linux 9 + + + SSSD should be configured with the correct ocsp_dgst + digest function + + + + + + + + Configure PAM in SSSD Services + + Oracle Linux 9 + + + SSSD should be configured to run SSSD PAM services. + + + + + + + + + Enable Smartcards in SSSD + + Oracle Linux 9 + + + SSSD should be configured to authenticate access to the system + using smart cards. + + + + + + + + + + Configure SSSD to Expire Offline Credentials + + Oracle Linux 9 + + + SSSD should be configured to expire offline credentials after 1 day. + + + + + + + + + Configure SSSD LDAP Backend Client to Demand a Valid Certificate from the Server + + Oracle Linux 9 + + + Configure SSSD to request a valid certificate from the server to protect LDAP remote access sessions. + + + + + + + + Configure SSSD LDAP Backend to Use TLS For All Transactions + + Oracle Linux 9 + + + LDAP should be used for authentication and use STARTTLS + + + + + + + + Log USBGuard daemon audit events using Linux Audit + + Oracle Linux 9 + + + Ensure 'AuditBackend' is configured with value 'LinuxAudit' in /etc/usbguard/usbguard-daemon.conf + + + + + + + + + + + Authorize Human Interface Devices and USB hubs in USBGuard daemon + + Oracle Linux 9 + + + Check that /etc/usbguard/rules.conf contains at least one non whitespace character and exists. + + + + + + + + Generate USBGuard Policy + + Oracle Linux 9 + + + Check that /etc/usbguard/rules.conf contains at least one non whitespace character and exists. + + + + + + + + Disable graphical user interface + + Oracle Linux 9 + + + Ensure that the default runlevel target is set to multi-user.target. + + + + + + + + + + + Disable Graphical Environment Startup By Setting Default Target + + Oracle Linux 9 + + + Ensure that the default runlevel target is set to multi-user.target. + + + + + + + + Enable authselect + + Oracle Linux 9 + + + Check that authselect is enabled + + + + + + + + + + + + Modify the System Login Banner + + Oracle Linux 9 + + + The system login banner text should be set correctly. + + + + + + + + Modify the System Login Banner for Remote Connections + + Oracle Linux 9 + + + The system login banner text should be set correctly. + + + + + + + + Modify the System Message of the Day Banner + + Oracle Linux 9 + + + The system motd banner text should be set correctly. + + + + + + + + + Enable GNOME3 Login Warning Banner + + Oracle Linux 9 + + + Enable the GNOME3 Login warning banner. + + + + + + + + + + + + + Set the GNOME3 Login Warning Banner Text + + Oracle Linux 9 + + + Enable the GUI warning banner. + + + + + + + + + + + + + Disallow Configuration to Bypass Password Requirements for Privilege Escalation + + Oracle Linux 9 + + + Disallow Configuration to Bypass Password Requirements for Privilege Escalation. + + + + + + + + Ensure PAM Displays Last Logon/Access Notification + + Oracle Linux 9 + + + Configure the system to notify users of last login/access using pam_lastlog. + + + + + + + + Configure the Use of the pam_faillock.so Module in the /etc/pam.d/password-auth File. + + Oracle Linux 9 + + + Configure the use of the pam_faillock.so module in the /etc/pam.d/password-auth file. + + + + + + + + + + Configure the Use of the pam_faillock.so Module in the /etc/pam.d/system-auth File. + + Oracle Linux 9 + + + Configure the use of the pam_faillock.so module in the /etc/pam.d/system-auth file. + + + + + + + + + + An SELinux Context must be configured for the pam_faillock.so records directory + + Oracle Linux 9 + + + An SELinux Context must be configured for the Faillock directory. + + + + + + + + + Account Lockouts Must Be Logged + + Oracle Linux 9 + + + Account Lockouts Must Be Logged + + + + + + + + + + + + + + + + + Limit Password Reuse: password-auth + + Oracle Linux 9 + + + The passwords to remember should be set correctly. + + + + + + + + + + + + + + + + + + Limit Password Reuse: system-auth + + Oracle Linux 9 + + + The passwords to remember should be set correctly. + + + + + + + + + + + + + + + + + + Limit Password Reuse + + Oracle Linux 9 + + + The passwords to remember should be set correctly. + + + + + + + + + + + + + + + + + + + + + Account Lockouts Must Be Logged + + Oracle Linux 9 + + + Account Lockouts Must Be Logged + + + + + + + + + + + + + + + + + Configure the root Account for Failed Password Attempts + + Oracle Linux 9 + + + The root account should be configured to deny access after the number of + defined failed attempts has been reached. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Lock Accounts Must Persist + + Oracle Linux 9 + + + Persist lockout account after reboot + + + + + + + + + + + + + + + + + Ensure PAM Enforces Password Requirements - Enforce for root User + + Oracle Linux 9 + + + The password policy should also be enforced for root. + + + + + + + + + Ensure PAM password complexity module is enabled in password-auth + + Oracle Linux 9 + + + The PAM module pam_pwquality is used in password-auth + + + + + + + + Ensure PAM password complexity module is enabled in system-auth + + Oracle Linux 9 + + + The PAM module pam_pwquality is used in system-auth + + + + + + + + Ensure PAM Enforces Password Requirements - Authentication Retry Prompts Permitted Per-Session + + Oracle Linux 9 + + + The password retry should meet minimum requirements + + + + + + + + + + + + + + + + Set Password Hashing Algorithm in /etc/libuser.conf + + Oracle Linux 9 + + + The password hashing algorithm should be set correctly in /etc/libuser.conf. + + + + + + + + Set Password Hashing Algorithm in /etc/login.defs + + Oracle Linux 9 + + + The password hashing algorithm should be set correctly in /etc/login.defs. + + + + + + + + Set PAM''s Password Hashing Algorithm - password-auth + + Oracle Linux 9 + + + The password hashing algorithm should be set correctly in /etc/pam.d/password-auth. + + + + + + + + Set PAM''s Password Hashing Algorithm + + Oracle Linux 9 + + + The password hashing algorithm should be set correctly in {{{ pam_file }}}. + + + + + + + + Set Password Hashing Minimum Rounds in /etc/login.defs + + Oracle Linux 9 + + + The password hashing minimum rounds should be set correctly in /etc/login.defs. + + + + + + + + + + + + + + + + + + + + + + Disable Ctrl-Alt-Del Burst Action + + Oracle Linux 9 + + + Configure the CtrlAltDelBurstAction setting in /etc/systemd/system.conf + or /etc/systemd/system.conf.d/* to none to prevent a reboot if Ctrl-Alt-Delete is + pressed more than 7 times in 2 seconds. + + + + + + + + Disable Ctrl-Alt-Del Reboot Activation + + Oracle Linux 9 + + + By default, the system will reboot when the + Ctrl-Alt-Del key sequence is pressed. + + + + + + + + Verify that Interactive Boot is Disabled + + Oracle Linux 9 + + + The ability for users to perform interactive startups should + be disabled. + + + + + + + + + + + + Configure Logind to terminate idle sessions after certain time of inactivity + + Oracle Linux 9 + + + Ensure 'StopIdleSessionSec' is configured with desired value in section 'Login' in /etc/systemd/logind.conf + + + + + + + + + Require Authentication for Emergency Systemd Target + + Oracle Linux 9 + + + The requirement for a password to boot into emergency mode + should be configured correctly. + + + + + + + + + + + + Require Authentication for Single User Mode + + Oracle Linux 9 + + + The requirement for a password to boot into single-user mode + should be configured correctly. + + + + + + + + + + + + + + Configure opensc Smart Card Drivers + + Oracle Linux 9 + + + Configure the organization's smart card driver so that only + the smart card in use by the organization will be recognized by the system. + + + + + + + + Ensure All Accounts on the System Have Unique User IDs + + Oracle Linux 9 + + + All accounts on the system should have unique IDs for proper accountability. + + + + + + + + Only Authorized Local User Accounts Exist on Operating System + + Oracle Linux 9 + + + Besides the default operating system user, there should be no other users + except the users that are authorized to exist locally on the operating system. + + + + + + + + Ensure All Groups on the System Have Unique Group ID + + Oracle Linux 9 + + + All groups on the system should have unique names for proper accountability. + + + + + + + + Set Account Expiration Following Inactivity in password-auth + + Oracle Linux 9 + + + The accounts should be configured to expire automatically following password expiration. + + + + + + + + Set Account Expiration Following Inactivity in system-auth + + Oracle Linux 9 + + + The accounts should be configured to expire automatically following password expiration. + + + + + + + + Set Account Expiration Following Inactivity + + Oracle Linux 9 + + + The accounts should be configured to expire automatically following password expiration. + + + + + + + + Ensure All Accounts on the System Have Unique Names + + Oracle Linux 9 + + + All accounts on the system should have unique names for proper accountability. + + + + + + + + Set Password Maximum Age + + Oracle Linux 9 + + + The maximum password age policy should meet minimum requirements. + + + + + + + + Set Password Minimum Age + + Oracle Linux 9 + + + The minimum password age policy should be set appropriately. + + + + + + + + Set Password Minimum Length in login.defs + + Oracle Linux 9 + + + The password minimum length should be set appropriately. + + + + + + + + Set Existing Passwords Maximum Age + + Oracle Linux 9 + + + Set Existing Passwords Maximum Age + + + + + + + + + + Set Root Account Password Maximum Age + + Oracle Linux 9 + + + A maximum password age should be set for the root account + + + + + + + + Set Existing Passwords Minimum Age + + Oracle Linux 9 + + + Set Existing Passwords Maximum Age + + + + + + + + + + Set Existing Passwords Warning Age + + Oracle Linux 9 + + + Set Existing Passwords Warning Age + + + + + + + + + Set Password Warning Age + + Oracle Linux 9 + + + The password expiration warning age should be set appropriately. + + + + + + + + Set existing passwords a period of inactivity before they been locked + + Oracle Linux 9 + + + Set existing passwords a period of inactivity before they been locked + + + + + + + + + Verify All Account Password Hashes are Shadowed + + Oracle Linux 9 + + + All password hashes should be shadowed. + + + + + + + + Verify All Account Password Hashes are Shadowed with SHA512 + + Oracle Linux 9 + + + All password hashes should be shadowed. + + + + + + + + Ensure all users last password change date is in the past + + Oracle Linux 9 + + + All passwords last change date is in the past. + + + + + + + + + Set number of Password Hashing Rounds - password-auth + + Oracle Linux 9 + + + The number of rounds for password hashing should be set correctly. + + + + + + + + Set number of Password Hashing Rounds - system-auth + + Oracle Linux 9 + + + The number of rounds for password hashing should be set correctly. + + + + + + + + All GIDs referenced in /etc/passwd must be defined in /etc/group + + Oracle Linux 9 + + + All GIDs referenced in /etc/passwd must be defined in /etc/group. + + + + + + + + Prevent Login to Accounts With Empty Password + + Oracle Linux 9 + + + The file /etc/pam.d/system-auth should not contain the nullok option + + + + + + + + Ensure There Are No Accounts With Blank or Null Passwords + + Oracle Linux 9 + + + The file /etc/shadow shows that there aren't empty passwords + + + + + + + + Verify No netrc Files Exist + + Oracle Linux 9 + + + The .netrc files contain login information used to auto-login into FTP servers and reside in the user's home directory. Any .netrc files should be removed. + + + + + + + + Verify Only Root Has UID 0 + + Oracle Linux 9 + + + Only the root account should be assigned a user id of 0. + + + + + + + + Verify Root Has A Primary GID 0 + + Oracle Linux 9 + + + The root account should have primary group of 0 + + + + + + + + Ensure the Group Used by pam_wheel.so Module Exists on System and is Empty + + Oracle Linux 9 + + + Group referred by var_pam_wheel_group_for_su variable exists and has no members. + + + + + + + + + Ensure Authentication Required for Single User Mode + + Oracle Linux 9 + + + Ensure root password is configured + + + + + + + + Direct root Logins Not Allowed + + Oracle Linux 9 + + + Preventing direct root logins help ensure accountability for actions + taken on the system using the root account. + + + + + + + + + Ensure that System Accounts Are Locked + + Oracle Linux 9 + + + Ensure that System Accounts Are Locked + + + + + + + + Ensure that System Accounts Do Not Run a Shell Upon Login + + Oracle Linux 9 + + + The root account is the only system account that should have + a login shell. + + + + + + + + + + + + + + + + + + Restrict Serial Port Root Logins + + Oracle Linux 9 + + + Preventing direct root login to serial port interfaces helps + ensure accountability for actions taken on the system using the root + account. + + + + + + + + Restrict Virtual Console Root Logins + + Oracle Linux 9 + + + Preventing direct root login to virtual console devices + helps ensure accountability for actions taken on the system using the + root account. + + + + + + + + Enforce usage of pam_wheel for su authentication + + Oracle Linux 9 + + + Only members of the wheel group should be able to authenticate through the su command. + + + + + + + + Enforce Usage of pam_wheel with Group Parameter for su Authentication + + Oracle Linux 9 + + + Only members of the group set in variable 'var_pam_wheel_group_for_su' should be able to authenticate through the su command. + + + + + + + + Ensure Home Directories are Created for New Users + + Oracle Linux 9 + + + CREATE_HOME should be enabled + + + + + + + + Ensure the Logon Failure Delay is Set Correctly in login.defs + + Oracle Linux 9 + + + The delay between failed authentication attempts should be + set for all users specified in /etc/login.defs + + + + + + + + Limit the Number of Concurrent Login Sessions Allowed Per User + + Oracle Linux 9 + + + The maximum number of concurrent login sessions per user should meet + minimum requirements. + + + + + + + + + + + + Configure Polyinstantiation of /tmp Directories + + Oracle Linux 9 + + + + + + + + + + + + Configure Polyinstantiation of /var/tmp Directories + + Oracle Linux 9 + + + + + + + + + + + + Set Interactive Session Timeout + + Oracle Linux 9 + + + Checks interactive shell timeout + + + + + + + + + + User Initialization Files Must Be Group-Owned By The Primary Group + + Oracle Linux 9 + + + User Initialization Files Must Be Group-Owned By The Primary Group + + + + + + + + User Initialization Files Must Not Run World-Writable Programs + + Oracle Linux 9 + + + User Initialization Files Must Not Execute World-Writable Programs + + + + + + + + User Initialization Files Must Be Owned By the Primary User + + Oracle Linux 9 + + + User Initialization Files Must Be Owned By the Primary User + + + + + + + + All Interactive Users Must Have A Home Directory Defined + + Oracle Linux 9 + + + All Interactive Users Must Have A Home Directory Defined + + + + + + + + All Interactive Users Home Directories Must Exist + + Oracle Linux 9 + + + All Interactive Users Home Directories Must Exist + + + + + + + + + All User Files and Directories In The Home Directory Must Be Group-Owned By The Primary Group + + Oracle Linux 9 + + + All User Files and Directories In The Home Directory Must Be Group-Owned By The Primary Group + + + + + + + + All User Files and Directories In The Home Directory Must Have a Valid Owner + + Oracle Linux 9 + + + All User Files and Directories In The Home Directory Must Have a Valid Owner + + + + + + + + All User Files and Directories In The Home Directory Must Have Mode 0750 Or Less Permissive + + Oracle Linux 9 + + + All User Files and Directories In The Home Directory Must Have Mode 0750 Or Less Permissive + + + + + + + + + All Interactive User Home Directories Must Be Group-Owned By The Primary Group + + Oracle Linux 9 + + + All interactive user's Home Directories must be group-owned by its user + + + + + + + + Ensure All User Initialization Files Have Mode 0740 Or Less Permissive + + Oracle Linux 9 + + + User initialization files have mode 0740 or less permissive + + + + + + + + All Interactive User Home Directories Must Have mode 0750 Or Less Permissive + + Oracle Linux 9 + + + All Interactive User Home Directories Must Have mode 0750 Or Less Permissive + + + + + + + + Ensure that User Home Directories are not Group-Writable or World-Readable + + Oracle Linux 9 + + + Ensure that User Home Directories are not Group-Writable or World-Readable + + + + + + + + Ensure that Root's Path Does Not Include World or Group-Writable Directories + + Oracle Linux 9 + + + Check each directory in root's path and make use it does + not grant write permission to group and other + + + + + + + + Ensure that Root's Path Does Not Include Relative Paths or Null Directories + + Oracle Linux 9 + + + The environment variable PATH should be set correctly for + the root user. + + + + + + + + + + + + + Ensure the Default Bash Umask is Set Correctly + + Oracle Linux 9 + + + The default umask for users of the bash shell + + + + + + + + + Ensure the Default C Shell Umask is Set Correctly + + Oracle Linux 9 + + + The default umask for users of the csh shell + + + + + + + + + Ensure the Default Umask is Set Correctly in login.defs + + Oracle Linux 9 + + + The default umask for all users specified in /etc/login.defs + + + + + + + + + Ensure the Default Umask is Set Correctly in /etc/profile + + Oracle Linux 9 + + + The default umask for all users should be set correctly + + + + + + + + + Ensure the Default Umask is Set Correctly For Interactive Users + + Oracle Linux 9 + + + Ensure the Default Umask is Set Correctly For Interactive Users + + + + + + + + Disable Recovery Booting + + Oracle Linux 9 + + + Recovery mode should be disabled. + + + + + + + + Set the Boot Loader Admin Username to a Non-Default Value + + Oracle Linux 9 + + + The grub2 boot loader superuser should have a username that is hard to guess. + + + + + + + + Set Boot Loader Password in grub2 + + Oracle Linux 9 + + + The grub2 boot loader should have password protection enabled. + + + + + + + + Set the UEFI Boot Loader Password + + Oracle Linux 9 + + + The UEFI grub2 boot loader should have password protection enabled. + + + + + + + + Configure Low Address Space To Protect From User Allocation + + Oracle Linux 9 + + + The kernel config CONFIG_DEFAULT_MMAP_MIN_ADDR should have value 65536 on x86_64 and 32768 on aarch64 + + + + + + + + + + + + + + + + + + Ensure cron Is Logging To Rsyslog + + Oracle Linux 9 + + + Rsyslog should be configured to capture cron messages. + + + + + + + + + + + + + Ensure Rsyslog Authenticates Off-Loaded Audit Records + + Oracle Linux 9 + + + Rsyslogd must authenticate remote system its sending logs to. + + + + + + + + + + + + + Ensure Rsyslog Encrypts Off-Loaded Audit Records + + Oracle Linux 9 + + + Rsyslogd must encrypt the off-loading of logs off of the system. + + + + + + + + + + + + + Ensure Rsyslog Encrypts Off-Loaded Audit Records + + Oracle Linux 9 + + + Rsyslogd must encrypt the off-loading of logs off of the system. + + + + + + + + + + + + + Ensure remote access methods are monitored in Rsyslog + + Oracle Linux 9 + + + Rsyslog should be configured to monitor remote access methods. + + + + + + + + + + Ensure Logrotate Runs Periodically + + Oracle Linux 9 + + + The frequency of automatic log files rotation performed by the logrotate utility should be configured to run daily - - - - - - - - - - - - - - - Ensure rsyslog Does Not Accept Remote Messages Unless Acting As Log Server - - Oracle Linux 9 - - rsyslogd should reject remote messages - - - - - - - - - - Ensure Logs Sent To Remote Host - - Oracle Linux 9 - - Syslog logs should be sent to a remote loghost - - - - - - - - - - Configure TLS for rsyslog remote logging - - Oracle Linux 9 - - Check that all needed TLS-related options are present - - - - - - - - - Configure CA certificate for rsyslog remote logging - - Oracle Linux 9 - - Check that the CA certificate path is set - - - - - - - - - Configure Multiple DNS Servers in /etc/resolv.conf - - Oracle Linux 9 - - Multiple Domain Name System (DNS) Servers should be configured - in /etc/resolv.conf. - - - - - - - - - - - - - - - - Ensure System is Not Acting as a Network Sniffer - - Oracle Linux 9 - - Disable the network sniffer - - - - - - - - - Set Default firewalld Zone for Incoming Packets - - Oracle Linux 9 - - Change the default firewalld zone to drop. - - - - - - - - - Disable IPv6 Networking Support Automatic Loading - - Oracle Linux 9 - - The disable option will allow the IPv6 module to be inserted, but prevent address assignment and activation of the network stack. - - - - - - - - - Deactivate Wireless Network Interfaces - - Oracle Linux 9 - - All wireless interfaces should be disabled. - - - - - - - - - Ensure All World-Writable Directories Are Owned by root User - - Oracle Linux 9 - - All world writable directories should be owned by root. - - - - - - - - - Verify that All World-Writable Directories Have Sticky Bits Set - - Oracle Linux 9 - - The sticky bit should be set for all world-writable directories. - - - - - - - - - Verify that local System.map file (if exists) is readable only by root - - Oracle Linux 9 - - - Checks that /boot/System.map-* are only readable by root. - - - - - - - - - - Ensure All SGID Executables Are Authorized - - Oracle Linux 9 - - Evaluates to true if all files with SGID set are owned by RPM packages. - - - - - - - - - Ensure All SUID Executables Are Authorized - - Oracle Linux 9 - - Evaluates to true if all files with SUID set are owned by RPM packages. - - - - - - - - - Ensure No World-Writable Files Exist - - Oracle Linux 9 - - The world-write permission should be disabled for all files. - - - - - - - - - Ensure All Files Are Owned by a Group - - Oracle Linux 9 - - All files should be owned by a group - - - - - - - - - Ensure All Files Are Owned by a User - - Oracle Linux 9 - - All files should be owned by a user - - - - - - - - - Verify that system commands files are group owned by root or a system account - - Oracle Linux 9 - - + + + + + + + + + + + + + + + Ensure rsyslog Does Not Accept Remote Messages Unless Acting As Log Server + + Oracle Linux 9 + + + rsyslogd should reject remote messages + + + + + + + + + Ensure Logs Sent To Remote Host + + Oracle Linux 9 + + + Syslog logs should be sent to a remote loghost + + + + + + + + + Configure TLS for rsyslog remote logging + + Oracle Linux 9 + + + Check that all needed TLS-related options are present + + + + + + + + Configure CA certificate for rsyslog remote logging + + Oracle Linux 9 + + + Check that the CA certificate path is set + + + + + + + + Configure Multiple DNS Servers in /etc/resolv.conf + + Oracle Linux 9 + + + Multiple Domain Name System (DNS) Servers should be configured + in /etc/resolv.conf. + + + + + + + + + + + + + + + Prevent non-Privileged Users from Modifying Network Interfaces using nmcli + + Oracle Linux 9 + + + polkit is properly configured to prevent non-privileged users from changing networking settings + + + + + + + + Ensure System is Not Acting as a Network Sniffer + + Oracle Linux 9 + + + Disable the network sniffer + + + + + + + + Configure Firewalld to Restrict Loopback Traffic + + Oracle Linux 9 + + + Configure Firewalld to Restrict Loopback Traffic + + + + + + + + + + + + + + + + + + Configure Firewalld to Trust Loopback Traffic + + Oracle Linux 9 + + + Configure Firewalld to Trust Loopback Traffic + + + + + + + + + + + + Disable IPv6 Networking Support Automatic Loading + + Oracle Linux 9 + + + The disable option will allow the IPv6 module to be inserted, but prevent address assignment and activation of the network stack. + + + + + + + + Deactivate Wireless Network Interfaces + + Oracle Linux 9 + + + All wireless interfaces should be disabled. + + + + + + + + NetworkManager DNS Mode Must Be Must Configured + + Oracle Linux 9 + + + Ensure 'dns' is configured with value 'default|none in section 'main' in /etc/NetworkManager/NetworkManager.conf + + + + + + + + + + + Ensure All World-Writable Directories Are Owned by root User + + Oracle Linux 9 + + + All world writable directories should be owned by root. + + + + + + + + Verify that All World-Writable Directories Have Sticky Bits Set + + Oracle Linux 9 + + + The sticky bit should be set for all world-writable directories. + + + + + + + + Verify that system commands directories have root as a group owner + + Oracle Linux 9 + + + + Checks that directories /bin /sbin /usr/bin /usr/sbin /usr/local/bin /usr/local/sbin + have root as a group owner + + + + + + + + + Verify that system commands directories have root ownership + + Oracle Linux 9 + + + + Checks that directories /bin /sbin /usr/bin /usr/sbin /usr/local/bin /usr/local/sbin + are owned by root. + + + + + + + + + + + + + + Ensure All SGID Executables Are Authorized + + Oracle Linux 9 + + + Evaluates to true if all files with SGID set are owned by RPM packages. + + + + + + + + Ensure All SUID Executables Are Authorized + + Oracle Linux 9 + + + Evaluates to true if all files with SUID set are owned by RPM packages. + + + + + + + + Ensure No World-Writable Files Exist + + Oracle Linux 9 + + + The world-write permission should be disabled for all files. + + + + + + + + Ensure All Files Are Owned by a Group + + Oracle Linux 9 + + + All files should be owned by a group + + + + + + + + + + + + + + + Ensure All Files Are Owned by a User + + Oracle Linux 9 + + + All files should be owned by a user + + + + + + + + Verify that system commands files are group owned by root or a system account + + Oracle Linux 9 + + + Checks that system commands in /bin /sbin /usr/bin /usr/sbin /usr/local/bin /usr/local/sbin are owned by root group or a system account. - - - - - - - - - - Verify that System Executables Have Root Ownership - - Oracle Linux 9 - - + + + + + + + + + Verify that System Executables Have Root Ownership + + Oracle Linux 9 + + + Checks that /bin, /sbin, /usr/bin, /usr/sbin, /usr/local/bin, /usr/local/sbin, /usr/libexec, and objects therein, are owned by root. - - - - - - - - - - - Verify that System Executables Have Restrictive Permissions - - Oracle Linux 9 - - + + + + + + + + + + Verify that System Executables Have Restrictive Permissions + + Oracle Linux 9 + + + Checks that binary files under /bin, /sbin, /usr/bin, /usr/sbin, /usr/local/bin, /usr/local/sbin, and /usr/libexec are not group-writable or world-writable. - - - - - - - - - - Add nodev Option to Non-Root Local Partitions - - Oracle Linux 9 - - The nodev mount option prevents files from being interpreted + + + + + + + + + Add nodev Option to Non-Root Local Partitions + + Oracle Linux 9 + + + The nodev mount option prevents files from being interpreted as character or block devices. Legitimate character and block devices should exist in the /dev directory on the root partition or within chroot jails built for system services. All other locations should not allow - character and block devices. - - - - - - - - - Disable core dump backtraces - - Oracle Linux 9 - - Ensure 'ProcessSizeMax' is configured with value '0 in section 'Coredump' in /etc/systemd/coredump.conf - - - - - - - - - - Disable storing core dump - - Oracle Linux 9 - - Ensure 'Storage' is configured with value 'none in section 'Coredump' in /etc/systemd/coredump.conf - - - - - - - - - - Disable Core Dumps for All Users - - Oracle Linux 9 - - Core dumps for all users should be disabled - - - - - - - - - - - - - Enable NX or XD Support in the BIOS - - Oracle Linux 9 - - The NX (no-execution) bit flag should be set on the system. - - - - - - - - - - Ensure SELinux Not Disabled in /etc/default/grub - - Oracle Linux 9 - - + character and block devices. + + + + + + + + + Disable storing core dumps + + Oracle Linux 9 + + + The kernel 'kernel.core_pattern' parameter should be set to the appropriate value in both system configuration and system runtime. + + + + + + + + + Disable storing core dumps + + Oracle Linux 9 + + + The kernel 'kernel.core_pattern' parameter should be set to an empty string in the system runtime. + + + + + + + + Disable storing core dumps + + Oracle Linux 9 + + + The kernel 'kernel.core_pattern' parameter should be set to an empty string in the system configuration. + + + + + + + + + + + + + Disable core dump backtraces + + Oracle Linux 9 + + + Ensure 'ProcessSizeMax' is configured with value '0 in section 'Coredump' in /etc/systemd/coredump.conf + + + + + + + + + Disable storing core dump + + Oracle Linux 9 + + + Ensure 'Storage' is configured with value 'none in section 'Coredump' in /etc/systemd/coredump.conf + + + + + + + + + Disable Core Dumps for All Users + + Oracle Linux 9 + + + Core dumps for all users should be disabled + + + + + + + + + + + + Enable ExecShield via sysctl + + Oracle Linux 9 + + + The kernel runtime parameter 'kernel.exec-shield' should not be disabled and set to 1 on 32-bit systems. + + + + + + + + + + + Enable NX or XD Support in the BIOS + + Oracle Linux 9 + + + The NX (no-execution) bit flag should be set on the system. + + + + + + + + + Ensure SELinux Not Disabled in /etc/default/grub + + Oracle Linux 9 + + + Check if selinux=0 OR enforcing=0 within the GRUB2 configuration files, fail if found. - - - - - - - - - - - - Ensure No Daemons are Unconfined by SELinux - - Oracle Linux 9 - - All pids in /proc should be assigned an SELinux security context other than 'unconfined_service_t'. - - - - - - - - - Ensure SELinux is Not Disabled - - Oracle Linux 9 - - SELinux is not Disabled. - - - - - - - - - Configure SELinux Policy - - Oracle Linux 9 - - The SELinux policy should be set appropriately. - - - - - - - - - Ensure SELinux State is Enforcing - - Oracle Linux 9 - - The SELinux state should be enforcing the local policy. - - - - - - - - - Prefer to use a 64-bit Operating System when supported - - Oracle Linux 9 - - Check if the system supports a 64-bit Operating System - - - - - - - - - - - - - Make sure that the dconf databases are up-to-date with regards to respective keyfiles - - Oracle Linux 9 - - Make sure that the dconf databases are up-to-date with regards to respective keyfiles. - - - - - - - - - - - - - - - - - - - Configure GNOME3 DConf User Profile - - Oracle Linux 9 - - The DConf User profile should have the local DB configured. - - - - - - - - - - Disable the GNOME3 Login Restart and Shutdown Buttons - - Oracle Linux 9 - - Disable the GNOME3 Login GUI Restart and Shutdown buttons to all users on the login screen. - - - - - - - - - - - - - - Disable the GNOME3 Login User List - - Oracle Linux 9 - - Disable the GNOME3 GUI listing of all known users on the login screen. - - - - - - - - - - - - - - Disable GDM Automatic Login - - Oracle Linux 9 - - Disable the GNOME Display Manager (GDM) ability to allow users to - automatically login. - - - - - - - - - - Disable XDMCP in GDM - - Oracle Linux 9 - - Ensure 'Enable' is configured with value 'false in section 'xdmcp' in /etc/gdm/custom.conf - - - - - - - - - - - - Disable GNOME3 automount-open - - Oracle Linux 9 - - The system's default desktop environment, GNOME3, will mount + + + + + + + + + + + Ensure No Device Files are Unlabeled by SELinux + + Oracle Linux 9 + + + All device files in /dev should be assigned an SELinux security context other than 'device_t' and 'unlabeled_t'. + + + + + + + + + Ensure No Daemons are Unconfined by SELinux + + Oracle Linux 9 + + + All pids in /proc should be assigned an SELinux security context other than 'unconfined_service_t'. + + + + + + + + Ensure SELinux is Not Disabled + + Oracle Linux 9 + + + SELinux is not Disabled. + + + + + + + + Configure SELinux Policy + + Oracle Linux 9 + + + The SELinux policy should be set appropriately. + + + + + + + + Ensure SELinux State is Enforcing + + Oracle Linux 9 + + + The SELinux state should be enforcing the local policy. + + + + + + + + Prefer to use a 64-bit Operating System when supported + + Oracle Linux 9 + + + Check if the system supports a 64-bit Operating System + + + + + + + + + + + + Make sure that the dconf databases are up-to-date with regards to respective keyfiles + + Oracle Linux 9 + + + Make sure that the dconf databases are up-to-date with regards to respective keyfiles. + + + + + + + + + + + + + + Configure GNOME3 DConf User Profile + + Oracle Linux 9 + + + The DConf User profile should have the local DB configured. + + + + + + + + + Disable the GNOME3 Login Restart and Shutdown Buttons + + Oracle Linux 9 + + + Disable the GNOME3 Login GUI Restart and Shutdown buttons to all users on the login screen. + + + + + + + + + + + + + Disable the GNOME3 Login User List + + Oracle Linux 9 + + + Disable the GNOME3 GUI listing of all known users on the login screen. + + + + + + + + + + + + + Disable GDM Automatic Login + + Oracle Linux 9 + + + Disable the GNOME Display Manager (GDM) ability to allow users to + automatically login. + + + + + + + + + Disable XDMCP in GDM + + Oracle Linux 9 + + + Ensure 'Enable' is configured with value 'false in section 'xdmcp' in /etc/gdm/custom.conf + + + + + + + + + + + Disable GNOME3 automount + + Oracle Linux 9 + + + The system's default desktop environment, GNOME3, will mount + devices and removable media (such as DVDs, CDs and USB flash drives) + whenever they are inserted into the system. Disable automount within GNOME3. + + + + + + + + + + + + + Disable GNOME3 automount-open + + Oracle Linux 9 + + + The system's default desktop environment, GNOME3, will mount devices and removable media (such as DVDs, CDs and USB flash drives) - whenever they are inserted into the system. Disable automount-open within GNOME3. - - - - - - - - - - - - - - Disable GNOME3 autorun - - Oracle Linux 9 - - The system's default desktop environment, GNOME3, will mount + whenever they are inserted into the system. Disable automount-open within GNOME3. + + + + + + + + + + + + + Disable GNOME3 autorun + + Oracle Linux 9 + + + The system's default desktop environment, GNOME3, will mount devices and removable media (such as DVDs, CDs and USB flash drives) - whenever they are inserted into the system. Disable autorun within GNOME3. - - - - - - - - - - - - - - Require Credential Prompting for Remote Access in GNOME3 - - Oracle Linux 9 - - Configure GNOME3 to require credential prompting for remote access. - - - - - - - - - - - - - - Require Encryption for Remote Access in GNOME3 - - Oracle Linux 9 - - Configure GNOME3 to require encryption for remote access connections. - - - - - - - - - - - - - - Enable GNOME3 Screensaver Idle Activation - - Oracle Linux 9 - - Idle activation of the screen saver should be enabled. - - - - - - - - - - - - - - Set GNOME3 Screensaver Inactivity Timeout - - Oracle Linux 9 - - The allowed period of inactivity before the screensaver is activated. - - - - - - - - - - - - - - Set GNOME3 Screensaver Lock Delay After Activation Period - - Oracle Linux 9 - - Idle activation of the screen lock should be enabled immediately or - after a delay. - - - - - - - - - - - - - - Enable GNOME3 Screensaver Lock After Idle Period - - Oracle Linux 9 - - Idle activation of the screen lock should be enabled. - - - - - - - - - - - - - - Ensure Users Cannot Change GNOME3 Screensaver Lock After Idle Period - - Oracle Linux 9 - - Idle activation of the screen lock should not be changed by users. - - - - - - - - - - - - - Implement Blank Screensaver - - Oracle Linux 9 - - The GNOME3 screensaver should be blank. - - - - - - - - - - - - - - Ensure Users Cannot Change GNOME3 Screensaver Settings - - Oracle Linux 9 - - Ensure that users cannot change GNOME3 screensaver idle and lock settings. - - - - - - - - - - - - - Ensure Users Cannot Change GNOME3 Session Idle Settings - - Oracle Linux 9 - - Ensure that users cannot change GNOME3 session idle settings. - - - - - - - - - - - - - Disable Ctrl-Alt-Del Reboot Key Sequence in GNOME3 - - Oracle Linux 9 - - Disable the GNOME3 ctrl-alt-del reboot key sequence in GNOME3. - - - - - - - - - - - - - - The Installed Operating System Is Vendor Supported - - Oracle Linux 9 - - + whenever they are inserted into the system. Disable autorun within GNOME3. + + + + + + + + + + + + + Require Credential Prompting for Remote Access in GNOME3 + + Oracle Linux 9 + + + Configure GNOME3 to require credential prompting for remote access. + + + + + + + + + + + + + Require Encryption for Remote Access in GNOME3 + + Oracle Linux 9 + + + Configure GNOME3 to require encryption for remote access connections. + + + + + + + + + + + + + Enable GNOME3 Screensaver Idle Activation + + Oracle Linux 9 + + + Idle activation of the screen saver should be enabled. + + + + + + + + + + + + + Set GNOME3 Screensaver Inactivity Timeout + + Oracle Linux 9 + + + The allowed period of inactivity before the screensaver is activated. + + + + + + + + + + + + + Set GNOME3 Screensaver Lock Delay After Activation Period + + Oracle Linux 9 + + + Idle activation of the screen lock should be enabled immediately or + after a delay. + + + + + + + + + + + + + Enable GNOME3 Screensaver Lock After Idle Period + + Oracle Linux 9 + + + Idle activation of the screen lock should be enabled. + + + + + + + + + + + + + Implement Blank Screensaver + + Oracle Linux 9 + + + The GNOME3 screensaver should be blank. + + + + + + + + + + + + + Ensure Users Cannot Change GNOME3 Screensaver Settings + + Oracle Linux 9 + + + Ensure that users cannot change GNOME3 screensaver idle and lock settings. + + + + + + + + + + + + Ensure Users Cannot Change GNOME3 Session Idle Settings + + Oracle Linux 9 + + + Ensure that users cannot change GNOME3 session idle settings. + + + + + + + + + + + + Disable Ctrl-Alt-Del Reboot Key Sequence in GNOME3 + + Oracle Linux 9 + + + Disable the GNOME3 ctrl-alt-del reboot key sequence in GNOME3. + + + + + + + + + + + + + The Installed Operating System Is FIPS 140-2 Certified + + Oracle Linux 9 + + + + The operating system installed on the system is a certified operating system that meets FIPS 140-2 requirements. + + + + + + + + + + + + + + + + + + + The Installed Operating System Is Vendor Supported + + Oracle Linux 9 + + + The operating system installed on the system is supported by a vendor that provides security patches. - - - - - - - - - - - - - - - - Configure BIND to use System Crypto Policy - - Oracle Linux 9 - - BIND should be configured to use the system-wide crypto policy setting. - - - - - - - - - - Configure System Cryptography Policy - - Oracle Linux 9 - - Ensure crypto policy is correctly configured in /etc/crypto-policies/config, and the policy is current. - - - - - - - - - - - - Configure Kerberos to use System Crypto Policy - - Oracle Linux 9 - - Kerberos should be configured to use the system-wide crypto policy setting. - - - - - - - - - - Configure Libreswan to use System Crypto Policy - - Oracle Linux 9 - - Libreswan should be configured to use the system-wide crypto policy setting. - - - - - - - - - - Configure OpenSSL library to use System Crypto Policy - - Oracle Linux 9 - - OpenSSL should be configured to use the system-wide crypto policy setting. - - - - - - - - - Configure OpenSSL library to use TLS Encryption - - Oracle Linux 9 - - Configure OpenSSL library to use TLS Encryption - - - - - - - - - - - - - Configure SSH to use System Crypto Policy - - Oracle Linux 9 - - SSH should be configured to use the system-wide crypto policy setting. - - - - - - - - - Harden SSH client Crypto Policy - - Oracle Linux 9 - - Ensure the ssh client ciphers are configured correctly in /etc/ssh/ssh_config.d/02-ospp.conf - - - - - - - - - - - - - - - Configure SSH Client to Use FIPS 140-2 Validated Ciphers: openssh.config - - Oracle Linux 9 - - Limit the Ciphers to those which are FIPS-approved. - - - - - - - - - Configure SSH Server to Use FIPS 140-2 Validated Ciphers: opensshserver.config - - Oracle Linux 9 - - Limit the Ciphers to those which are FIPS-approved. - - - - - - - - - Configure SSH Client to Use FIPS 140-2 Validated MACs: openssh.config - - Oracle Linux 9 - - Limit the Message Authentication Codes (MACs) to those which are FIPS-approved. - - - - - - - - - Configure SSH Server to Use FIPS 140-2 Validated MACs: opensshserver.config - - Oracle Linux 9 - - Limit the Message Authentication Codes (MACs) to those which are FIPS-approved. - - - - - - - - - Install Intrusion Detection Software - - Oracle Linux 9 - - Intrusion detection software or SELinux should be installed and enabled. - - - - - - - - - - Install McAfee Virus Scanning Software - - Oracle Linux 9 - - McAfee Antivirus software should be installed. - - - - - - - - - - Install the McAfee Runtime Libraries and Linux Agent - - Oracle Linux 9 - - Install the McAfee Runtime Libraries (MFErt) and Linux Agent (MFEcma). - - - - - - - - - - Ensure McAfee Endpoint Security for Linux (ENSL) is running - - Oracle Linux 9 - - Ensure that McAfee Endpoint Security for Linux (ENSL) is running. - - - - - - - - - Install the Asset Configuration Compliance Module (ACCM) - - Oracle Linux 9 - - Install the Asset Configuration Compliance Module (ACCM). - - - - - - - - - Install the Policy Auditor (PA) Module - - Oracle Linux 9 - - Install the Policy Auditor (PA) Module. - - - - - - - - - Enable Dracut FIPS Module - - Oracle Linux 9 - - fips module should be enabled in Dracut configuration - - - - - - - - - Enable FIPS Mode - - Oracle Linux 9 - - Check if FIPS mode is enabled on the system - - - - - - - - - - - - - - - - - - - - - - - - - Ensure '/etc/system-fips' exists - - Oracle Linux 9 - - Check /etc/system-fips exists - - - - - - - - - Set kernel parameter 'crypto.fips_enabled' to 1 - - Oracle Linux 9 - - The kernel 'crypto.fips_enabled' parameter should be set to '1' in system runtime. - - - - - - - - - Build and Test AIDE Database - - Oracle Linux 9 - - The aide database must be initialized. - - - - - - - - - - Configure AIDE to Verify the Audit Tools - - Oracle Linux 9 - - The Oracle Linux 9 operating system file integrity tool must be configured to protect the integrity of the audit tools. - - - - - - - - - - - - - - - - Configure Periodic Execution of AIDE - - Oracle Linux 9 - - By default, AIDE does not install itself for periodic + + + + + + + + + + + + + + + + Configure BIND to use System Crypto Policy + + Oracle Linux 9 + + + BIND should be configured to use the system-wide crypto policy setting. + + + + + + + + + Configure System Cryptography Policy + + Oracle Linux 9 + + + Ensure crypto policy is correctly configured in /etc/crypto-policies/config, and the policy is current. + + + + + + + + + + + Configure Kerberos to use System Crypto Policy + + Oracle Linux 9 + + + Kerberos should be configured to use the system-wide crypto policy setting. + + + + + + + + + Configure Libreswan to use System Crypto Policy + + Oracle Linux 9 + + + Libreswan should be configured to use the system-wide crypto policy setting. + + + + + + + + + Configure OpenSSL library to use System Crypto Policy + + Oracle Linux 9 + + + OpenSSL should be configured to use the system-wide crypto policy setting. + + + + + + + + Configure SSH to use System Crypto Policy + + Oracle Linux 9 + + + SSH should be configured to use the system-wide crypto policy setting. + + + + + + + + Harden SSH client Crypto Policy + + Oracle Linux 9 + + + Ensure the ssh client ciphers are configured correctly in /etc/ssh/ssh_config.d/02-ospp.conf + + + + + + + + + + + + + + Configure SSH Client to Use FIPS 140 Validated Ciphers: openssh.config + + Oracle Linux 9 + + + Limit the Ciphers to those which are FIPS-approved. + + + + + + + + Configure SSH Server to Use FIPS 140-2 Validated Ciphers: opensshserver.config + + Oracle Linux 9 + + + Limit the Ciphers to those which are FIPS-approved. + + + + + + + + Configure SSH Client to Use FIPS 140-2 Validated MACs: openssh.config + + Oracle Linux 9 + + + Limit the Message Authentication Codes (MACs) to those which are FIPS-approved. + + + + + + + + Configure SSH Server to Use FIPS 140-2 Validated MACs: opensshserver.config + + Oracle Linux 9 + + + Limit the Message Authentication Codes (MACs) to those which are FIPS-approved. + + + + + + + + Ensure McAfee Endpoint Security for Linux (ENSL) is running + + Oracle Linux 9 + + + Ensure that McAfee Endpoint Security for Linux (ENSL) is running. + + + + + + + + Enable Dracut FIPS Module + + Oracle Linux 9 + + + fips module should be enabled in Dracut configuration + + + + + + + + Enable FIPS Mode + + Oracle Linux 9 + + + Check if FIPS mode is enabled on the system + + + + + + + + + + + + + + + + + + + + + + + + Ensure '/etc/system-fips' exists + + Oracle Linux 9 + + + Check /etc/system-fips exists + + + + + + + + Set kernel parameter 'crypto.fips_enabled' to 1 + + Oracle Linux 9 + + + The kernel 'crypto.fips_enabled' parameter should be set to '1' in system runtime. + + + + + + + + Build and Test AIDE Database + + Oracle Linux 9 + + + The aide database must be initialized. + + + + + + + + + Configure AIDE to Verify the Audit Tools + + Oracle Linux 9 + + + The Oracle Linux 9 operating system file integrity tool must be configured to protect the integrity of the audit tools. + + + + + + + + + + + + + + + Configure Periodic Execution of AIDE + + Oracle Linux 9 + + + By default, AIDE does not install itself for periodic execution. Periodically running AIDE is necessary to reveal unexpected changes in installed files. - - - - - - - - - - - - - - - - Configure Notification of Post-AIDE Scan Details - - Oracle Linux 9 - - AIDE should notify appropriate personnel of the details - of a scan after the scan has been run. - - - - - - - - - - - - - - Configure AIDE to Verify Access Control Lists (ACLs) - - Oracle Linux 9 - - AIDE should be configured to verify Access Control Lists (ACLs). - - - - - - - - - - Configure AIDE to Verify Extended Attributes - - Oracle Linux 9 - - AIDE should be configured to verify extended file attributes. - - - - - - - - - - Verify File Hashes with RPM - - Oracle Linux 9 - - Verify the RPM digests of system binaries using the RPM database. - - - - - - - - - Verify and Correct Ownership with RPM - - Oracle Linux 9 - - Verify ownership of installed packages - by comparing the installed files with information about the - files taken from the package metadata stored in the RPM - database. - - - - - - - - - - Verify and Correct File Permissions with RPM - - Oracle Linux 9 - - Verify the permissions of installed packages - by comparing the installed files with information about the - files taken from the package metadata stored in the RPM - database. - - - - - - - - - Ensure Users Re-Authenticate for Privilege Escalation - sudo !authenticate - - Oracle Linux 9 - - Checks sudo usage without authentication - - - - - - - - - - Ensure Users Re-Authenticate for Privilege Escalation - sudo NOPASSWD - - Oracle Linux 9 - - Checks sudo usage without password - - - - - - - - - - Ensure Users Re-Authenticate for Privilege Escalation - sudo - - Oracle Linux 9 - - Checks sudo usage without password - - - - - - - - - - Require Re-Authentication When Using the sudo Command - - Oracle Linux 9 - - 'Ensure sudo timestamp_timeout is appropriate - sudo timestamp_timeout - - - - - - - - - - The operating system must restrict privilege elevation to authorized personnel - - Oracle Linux 9 - - Check that sudoers doesn't allow all users to run commands via sudo - - - - - - - - - - Only the VDSM User Can Use sudo NOPASSWD - - Oracle Linux 9 - - Checks sudo usage for the vdsm user without a password - - - - - - - - - - Explicit arguments in sudo specifications - - Oracle Linux 9 - - Check that sudoers doesn't contain commands without arguments specified - - - - - - - - - Don't define allowed commands in sudoers by means of exclusion - - Oracle Linux 9 - - Check that sudoers doesn't contain command negations - - - - - - - - - Don't target root user in the sudoers file - - Oracle Linux 9 - - Check that sudoers doesn't allow users to run commands as root - - - - - - - - - - Ensure invoking users password for privilege escalation when using sudo - - Oracle Linux 9 - - Ensure invoking user's password for privilege escalation when using sudo - - - - - - - - - - - - - - Ensure yum Removes Previous Package Versions - - Oracle Linux 9 - - The clean_requirements_on_remove option should be used to ensure that old - versions of software components are removed after updating. - - - - - - - - - Configure dnf-automatic to Install Available Updates Automatically - - Oracle Linux 9 - - Ensure 'apply_updates' is configured with value 'yes in section 'commands' in /etc/dnf/automatic.conf - - - - - - - - - - - - Configure dnf-automatic to Install Only Security Updates - - Oracle Linux 9 - - Ensure 'upgrade_type' is configured with value 'security in section 'commands' in /etc/dnf/automatic.conf - - - - - - - - - - - - Ensure gpgcheck Enabled In Main yum Configuration - - Oracle Linux 9 - - The gpgcheck option should be used to ensure that checking + + + + + + + + + + + + + + + Configure Notification of Post-AIDE Scan Details + + Oracle Linux 9 + + + AIDE should notify appropriate personnel of the details + of a scan after the scan has been run. + + + + + + + + + + + + + Configure AIDE to Use FIPS 140-2 for Validating Hashes + + Oracle Linux 9 + + + AIDE should be configured to use the FIPS 140-2 + cryptographic hashes. + + + + + + + + + + + Configure AIDE to Verify Access Control Lists (ACLs) + + Oracle Linux 9 + + + AIDE should be configured to verify Access Control Lists (ACLs). + + + + + + + + + Configure AIDE to Verify Extended Attributes + + Oracle Linux 9 + + + AIDE should be configured to verify extended file attributes. + + + + + + + + + Verify File Hashes with RPM + + Oracle Linux 9 + + + Verify the RPM digests of system binaries using the RPM database. + + + + + + + + Verify and Correct Ownership with RPM + + Oracle Linux 9 + + + Verify ownership of installed packages by comparing the installed files + with information about the files taken from the package metadata stored in the RPM + database. + + + + + + + + Verify and Correct File Permissions with RPM + + Oracle Linux 9 + + + Verify the permissions of installed packages by comparing the installed + files with information about the files taken from the package metadata stored in the RPM + database. + + + + + + + + Ensure a dedicated group owns sudo + + Oracle Linux 9 + + + This test makes sure that /usr/bin/sudo is owned by the group set in var_sudo_dedicated_group + + + + + + + + + Ensure Users Re-Authenticate for Privilege Escalation - sudo !authenticate + + Oracle Linux 9 + + + Checks sudo usage without authentication + + + + + + + + + Ensure Users Re-Authenticate for Privilege Escalation - sudo NOPASSWD + + Oracle Linux 9 + + + Checks sudo usage without password + + + + + + + + + Ensure Users Re-Authenticate for Privilege Escalation - sudo + + Oracle Linux 9 + + + Checks sudo usage without password + + + + + + + + + Require Re-Authentication When Using the sudo Command + + Oracle Linux 9 + + + 'Ensure sudo timestamp_timeout is appropriate - sudo timestamp_timeout + + + + + + + + + The operating system must restrict privilege elevation to authorized personnel + + Oracle Linux 9 + + + Check that sudoers doesn't allow all users to run commands via sudo + + + + + + + + + Only the VDSM User Can Use sudo NOPASSWD + + Oracle Linux 9 + + + Checks sudo usage for the vdsm user without a password + + + + + + + + + Explicit arguments in sudo specifications + + Oracle Linux 9 + + + Check that sudoers doesn't contain commands without arguments specified + + + + + + + + Don't define allowed commands in sudoers by means of exclusion + + Oracle Linux 9 + + + Check that sudoers doesn't contain command negations + + + + + + + + Don't target root user in the sudoers file + + Oracle Linux 9 + + + Check that sudoers doesn't allow users to run commands as root + + + + + + + + + Ensure invoking users password for privilege escalation when using sudo + + Oracle Linux 9 + + + Ensure invoking user's password for privilege escalation when using sudo + + + + + + + + + + + + + Ensure yum Removes Previous Package Versions + + Oracle Linux 9 + + + The clean_requirements_on_remove option should be used to ensure that old + versions of software components are removed after updating. + + + + + + + + Configure dnf-automatic to Install Available Updates Automatically + + Oracle Linux 9 + + + Ensure 'apply_updates' is configured with value 'yes in section 'commands' in /etc/dnf/automatic.conf + + + + + + + + + + + Configure dnf-automatic to Install Only Security Updates + + Oracle Linux 9 + + + Ensure 'upgrade_type' is configured with value 'security in section 'commands' in /etc/dnf/automatic.conf + + + + + + + + + + + Ensure gpgcheck Enabled In Main yum Configuration + + Oracle Linux 9 + + + The gpgcheck option should be used to ensure that checking of an RPM package's signature always occurs prior to its - installation. - - - - - - - - - Ensure gpgcheck Enabled for Local Packages - - Oracle Linux 9 - - The localpkg_gpgcheck option should be used to ensure that checking + installation. + + + + + + + + Ensure gpgcheck Enabled for Local Packages + + Oracle Linux 9 + + + The localpkg_gpgcheck option should be used to ensure that checking of an RPM package's signature always occurs prior to its - installation. - - - - - - - - - Ensure gpgcheck Enabled for All yum Package Repositories - - Oracle Linux 9 - - Ensure all yum or dnf repositories utilize signature checking. - - - - - - - - - Ensure Oracle Linux GPG Key Installed - - Oracle Linux 9 - - The Oracle Linux key packages are required to be installed. - - - - - - - - - - - - - - - Ensure PAM Enforces Password Requirements - Minimum Digit Characters - - Oracle Linux 9 - - The password dcredit should meet minimum requirements - - - - - - - - - - - - - Ensure PAM Enforces Password Requirements - Prevent the Use of Dictionary Words - - Oracle Linux 9 - - The password dictcheck should meet minimum requirements - - - - - - - - - - - - - Ensure PAM Enforces Password Requirements - Minimum Different Characters - - Oracle Linux 9 - - The password difok should meet minimum requirements - - - - - - - - - - - - - Ensure PAM Enforces Password Requirements - Enforce for root User - - Oracle Linux 9 - - Check presence of enforce_for_root in /etc/security/pwquality.conf - - - - - - - - - - Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters - - Oracle Linux 9 - - The password lcredit should meet minimum requirements - - - - - - - - - - - - - Ensure PAM Enforces Password Requirements - Maximum Consecutive Repeating Characters from Same Character Class - - Oracle Linux 9 - - The password maxclassrepeat should meet minimum requirements - - - - - - - - - - - - - Set Password Maximum Consecutive Repeating Characters - - Oracle Linux 9 - - The password maxrepeat should meet minimum requirements - - - - - - - - - - - - - Ensure PAM Enforces Password Requirements - Minimum Different Categories - - Oracle Linux 9 - - The password minclass should meet minimum requirements - - - - - - - - - - - - - Ensure PAM Enforces Password Requirements - Minimum Length - - Oracle Linux 9 - - The password minlen should meet minimum requirements - - - - - - - - - - - - - Ensure PAM Enforces Password Requirements - Minimum Special Characters - - Oracle Linux 9 - - The password ocredit should meet minimum requirements - - - - - - - - - - - - - Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters - - Oracle Linux 9 - - The password ucredit should meet minimum requirements - - - - - - - - - - - - - Configure auditing of unsuccessful file accesses - - Oracle Linux 9 - - Inspect the contents of /etc/audit/rules.d/30-ospp-v42-3-access-failed.rules - - - - - - - - - Configure auditing of successful file accesses - - Oracle Linux 9 - - Inspect the contents of /etc/audit/rules.d/30-ospp-v42-3-access-success.rules - - - - - - - - - Configure basic parameters of Audit system - - Oracle Linux 9 - - Inspect the contents of /etc/audit/rules.d/10-base-config.rules - - - - - - - - - Configure auditing of unsuccessful file creations - - Oracle Linux 9 - - Inspect the contents of /etc/audit/rules.d/30-ospp-v42-1-create-failed.rules - - - - - - - - - Configure auditing of successful file creations - - Oracle Linux 9 - - Inspect the contents of /etc/audit/rules.d/30-ospp-v42-1-create-success.rules - - - - - - - - - Configure auditing of unsuccessful file deletions - - Oracle Linux 9 - - Inspect the contents of /etc/audit/rules.d/30-ospp-v42-4-delete-failed.rules - - - - - - - - - Configure auditing of successful file deletions - - Oracle Linux 9 - - Inspect the contents of /etc/audit/rules.d/30-ospp-v42-4-delete-success.rules - - - - - - - - - Configure immutable Audit login UIDs - - Oracle Linux 9 - - Inspect the contents of /etc/audit/rules.d/11-loginuid.rules - - - - - - - - - Configure auditing of unsuccessful file modifications - - Oracle Linux 9 - - Inspect the contents of /etc/audit/rules.d/30-ospp-v42-2-modify-failed.rules - - - - - - - - - Configure auditing of successful file modifications - - Oracle Linux 9 - - Inspect the contents of /etc/audit/rules.d/30-ospp-v42-2-modify-success.rules - - - - - - - - - Configure auditing of loading and unloading of kernel modules - - Oracle Linux 9 - - Inspect the contents of /etc/audit/rules.d/43-module-load.rules - - - - - - - - - Perform general configuration of Audit for OSPP - - Oracle Linux 9 - - Inspect the contents of /etc/audit/rules.d/30-ospp-v42.rules - - - - - - - - - Configure auditing of unsuccessful ownership changes - - Oracle Linux 9 - - Inspect the contents of /etc/audit/rules.d/30-ospp-v42-6-owner-change-failed.rules - - - - - - - - - Configure auditing of successful ownership changes - - Oracle Linux 9 - - Inspect the contents of /etc/audit/rules.d/30-ospp-v42-6-owner-change-success.rules - - - - - - - - - Configure auditing of unsuccessful permission changes - - Oracle Linux 9 - - Inspect the contents of /etc/audit/rules.d/30-ospp-v42-5-perm-change-failed.rules - - - - - - - - - Configure auditing of successful permission changes - - Oracle Linux 9 - - Inspect the contents of /etc/audit/rules.d/30-ospp-v42-5-perm-change-success.rules - - - - - - - - - Ensure auditd Collects Information on the Use of Privileged Commands - init - - Oracle Linux 9 - - Audit rules about the information on the use of init is enabled. - - - - - - - - - - - - - - - - Ensure auditd Collects Information on the Use of Privileged Commands - poweroff - - Oracle Linux 9 - - Audit rules about the information on the use of poweroff is enabled. - - - - - - - - - - - - - - - - Ensure auditd Collects Information on the Use of Privileged Commands - reboot - - Oracle Linux 9 - - Audit rules about the information on the use of reboot is enabled. - - - - - - - - - - - - - - - - Ensure auditd Collects Information on the Use of Privileged Commands - shutdown - - Oracle Linux 9 - - Audit rules about the information on the use of shutdown is enabled. - - - - - - - - - - - - - - - - Record Events that Modify the System's Discretionary Access Controls - chmod - - Oracle Linux 9 - - The changing of file permissions and attributes should be audited. - - - - - - - - - - - - - - - - - - - - - - - - Record Events that Modify the System's Discretionary Access Controls - chown - - Oracle Linux 9 - - The changing of file permissions and attributes should be audited. - - - - - - - - - - - - - - - - - - - - - - - - Record Events that Modify the System's Discretionary Access Controls - fchmod - - Oracle Linux 9 - - The changing of file permissions and attributes should be audited. - - - - - - - - - - - - - - - - - - - - - - - - Record Events that Modify the System's Discretionary Access Controls - fchmodat - - Oracle Linux 9 - - The changing of file permissions and attributes should be audited. - - - - - - - - - - - - - - - - - - - - - - - - Record Events that Modify the System's Discretionary Access Controls - fchown - - Oracle Linux 9 - - The changing of file permissions and attributes should be audited. - - - - - - - - - - - - - - - - - - - - - - - - Record Events that Modify the System's Discretionary Access Controls - fchownat - - Oracle Linux 9 - - The changing of file permissions and attributes should be audited. - - - - - - - - - - - - - - - - - - - - - - - - Record Events that Modify the System's Discretionary Access Controls - fremovexattr - - Oracle Linux 9 - - The changing of file permissions and attributes should be audited. - - - - - - - - - - - - - - - - - - - - - - - - Record Events that Modify the System's Discretionary Access Controls - fsetxattr - - Oracle Linux 9 - - The changing of file permissions and attributes should be audited. - - - - - - - - - - - - - - - - - - - - - - - - Record Events that Modify the System's Discretionary Access Controls - lchown - - Oracle Linux 9 - - The changing of file permissions and attributes should be audited. - - - - - - - - - - - - - - - - - - - - - - - - Record Events that Modify the System's Discretionary Access Controls - lremovexattr - - Oracle Linux 9 - - The changing of file permissions and attributes should be audited. - - - - - - - - - - - - - - - - - - - - - - - - Record Events that Modify the System's Discretionary Access Controls - lsetxattr - - Oracle Linux 9 - - The changing of file permissions and attributes should be audited. - - - - - - - - - - - - - - - - - - - - - - - - Record Events that Modify the System's Discretionary Access Controls - removexattr - - Oracle Linux 9 - - The changing of file permissions and attributes should be audited. - - - - - - - - - - - - - - - - - - - - - - - - Record Events that Modify the System's Discretionary Access Controls - setxattr - - Oracle Linux 9 - - The changing of file permissions and attributes should be audited. - - - - - - - - - - - - - - - - - - - - - - - - Record Events that Modify the System's Discretionary Access Controls - umount2 - - Oracle Linux 9 - - The changing of file permissions and attributes should be audited. - - - - - - - - - - - - - - - - - - - - - - - - Record Any Attempts to Run chacl - - Oracle Linux 9 - - Audit rules about the information on the use of chacl is enabled. - - - - - - - - - - - - - - - - Record Any Attempts to Run chcon - - Oracle Linux 9 - - Audit rules about the information on the use of chcon is enabled. - - - - - - - - - - - - - - - - Record Any Attempts to Run restorecon - - Oracle Linux 9 - - Audit rules about the information on the use of restorecon is enabled. - - - - - - - - - - - - - - - - Record Any Attempts to Run semanage - - Oracle Linux 9 - - Audit rules about the information on the use of semanage is enabled. - - - - - - - - - - - - - - - - Record Any Attempts to Run setfacl - - Oracle Linux 9 - - Audit rules about the information on the use of setfacl is enabled. - - - - - - - - - - - - - - - - Record Any Attempts to Run setfiles - - Oracle Linux 9 - - Audit rules about the information on the use of setfiles is enabled. - - - - - - - - - - - - - - - - Record Any Attempts to Run setsebool - - Oracle Linux 9 - - Audit rules about the information on the use of setsebool is enabled. - - - - - - - - - - - - - - - - Record Any Attempts to Run seunshare - - Oracle Linux 9 - - Audit rules about the information on the use of seunshare is enabled. - - - - - - - - - - - - - - - - Ensure auditd Collects File Deletion Events by User - rename - - Oracle Linux 9 - - The deletion of files should be audited. - - - - - - - - - - - - - - - - - - - - - - - - Ensure auditd Collects File Deletion Events by User - renameat - - Oracle Linux 9 - - The deletion of files should be audited. - - - - - - - - - - - - - - - - - - - - - - - - Ensure auditd Collects File Deletion Events by User - rmdir - - Oracle Linux 9 - - The deletion of files should be audited. - - - - - - - - - - - - - - - - - - - - - - - - Ensure auditd Collects File Deletion Events by User - unlink - - Oracle Linux 9 - - The deletion of files should be audited. - - - - - - - - - - - - - - - - - - - - - - - - Ensure auditd Collects File Deletion Events by User - unlinkat - - Oracle Linux 9 - - The deletion of files should be audited. - - - - - - - - - - - - - - - - - - - - - - - - Record Attempts to Alter Logon and Logout Events - faillock - - Oracle Linux 9 - - Audit rules should be configured to log successful and unsuccessful login and logout events. - - - - - - - - - - - - - - - - Record Attempts to Alter Logon and Logout Events - lastlog - - Oracle Linux 9 - - Audit rules should be configured to log successful and unsuccessful login and logout events. - - - - - - - - - - - - - - - - Record Attempts to Alter Logon and Logout Events - tallylog - - Oracle Linux 9 - - Audit rules should be configured to log successful and unsuccessful login and logout events. - - - - - - - - - - - - - - - - Ensure auditd Collects Information on Exporting to Media (successful) - - Oracle Linux 9 - - The changing of file permissions and attributes should be audited. - - - - - - - - - - - - - - - - - - - - - - - - Ensure auditd Collects Information on the Use of Privileged Commands - at - - Oracle Linux 9 - - Audit rules about the information on the use of at is enabled. - - - - - - - - - - - - - - - - Ensure auditd Collects Information on the Use of Privileged Commands - chage - - Oracle Linux 9 - - Audit rules about the information on the use of chage is enabled. - - - - - - - - - - - - - - - - Ensure auditd Collects Information on the Use of Privileged Commands - chsh - - Oracle Linux 9 - - Audit rules about the information on the use of chsh is enabled. - - - - - - - - - - - - - - - - Ensure auditd Collects Information on the Use of Privileged Commands - crontab - - Oracle Linux 9 - - Audit rules about the information on the use of crontab is enabled. - - - - - - - - - - - - - - - - Ensure auditd Collects Information on the Use of Privileged Commands - gpasswd - - Oracle Linux 9 - - Audit rules about the information on the use of gpasswd is enabled. - - - - - - - - - - - - - - - - Ensure auditd Collects Information on the Use of Privileged Commands - kmod - - Oracle Linux 9 - - Audit rules about the information on the use of kmod is enabled. - - - - - - - - - - - - - - - - Ensure auditd Collects Information on the Use of Privileged Commands - mount - - Oracle Linux 9 - - Audit rules about the information on the use of mount is enabled. - - - - - - - - - - - - - - - - Ensure auditd Collects Information on the Use of Privileged Commands - newgrp - - Oracle Linux 9 - - Audit rules about the information on the use of newgrp is enabled. - - - - - - - - - - - - - - - - Ensure auditd Collects Information on the Use of Privileged Commands - pam_timestamp_check - - Oracle Linux 9 - - Audit rules about the information on the use of pam_timestamp_check is enabled. - - - - - - - - - - - - - - - - Ensure auditd Collects Information on the Use of Privileged Commands - passwd - - Oracle Linux 9 - - Audit rules about the information on the use of passwd is enabled. - - - - - - - - - - - - - - - - Ensure auditd Collects Information on the Use of Privileged Commands - postdrop - - Oracle Linux 9 - - Audit rules about the information on the use of postdrop is enabled. - - - - - - - - - - - - - - - - Ensure auditd Collects Information on the Use of Privileged Commands - postqueue - - Oracle Linux 9 - - Audit rules about the information on the use of postqueue is enabled. - - - - - - - - - - - - - - - - Ensure auditd Collects Information on the Use of Privileged Commands - pt_chown - - Oracle Linux 9 - - Audit rules about the information on the use of pt_chown is enabled. - - - - - - - - - - - - - - - - Record Any Attempts to Run ssh-agent - - Oracle Linux 9 - - Audit rules about the information on the use of ssh_agent is enabled. - - - - - - - - - - - - - - - - Ensure auditd Collects Information on the Use of Privileged Commands - ssh-keysign - - Oracle Linux 9 - - Audit rules about the information on the use of ssh_keysign is enabled. - - - - - - - - - - - - - - - - Ensure auditd Collects Information on the Use of Privileged Commands - su - - Oracle Linux 9 - - Audit rules about the information on the use of su is enabled. - - - - - - - - - - - - - - - - Ensure auditd Collects Information on the Use of Privileged Commands - sudo - - Oracle Linux 9 - - Audit rules about the information on the use of sudo is enabled. - - - - - - - - - - - - - - - - Ensure auditd Collects Information on the Use of Privileged Commands - sudoedit - - Oracle Linux 9 - - Audit rules about the information on the use of sudoedit is enabled. - - - - - - - - - - - - - - - - Ensure auditd Collects Information on the Use of Privileged Commands - umount - - Oracle Linux 9 - - Audit rules about the information on the use of umount is enabled. - - - - - - - - - - - - - - - - Ensure auditd Collects Information on the Use of Privileged Commands - unix_chkpwd - - Oracle Linux 9 - - Audit rules about the information on the use of unix_chkpwd is enabled. - - - - - - - - - - - - - - - - Ensure auditd Collects Information on the Use of Privileged Commands - unix_update - - Oracle Linux 9 - - Audit rules about the information on the use of unix_update is enabled. - - - - - - - - - - - - - - - - Ensure auditd Collects Information on the Use of Privileged Commands - userhelper - - Oracle Linux 9 - - Audit rules about the information on the use of userhelper is enabled. - - - - - - - - - - - - - - - - Ensure auditd Collects Information on the Use of Privileged Commands - usermod - - Oracle Linux 9 - - Audit rules about the information on the use of usermod is enabled. - - - - - - - - - - - - - - - - Ensure auditd Collects Information on the Use of Privileged Commands - usernetctl - - Oracle Linux 9 - - Audit rules about the information on the use of usernetctl is enabled. - - - - - - - - - - - - - - - - Record Unsuccessful Access Attempts to Files - creat - - Oracle Linux 9 - - Audit rules about the unauthorized access attempts to files (unsuccessful) are enabled. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Record Unsuccessful Access Attempts to Files - ftruncate - - Oracle Linux 9 - - Audit rules about the unauthorized access attempts to files (unsuccessful) are enabled. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Record Unsuccessful Access Attempts to Files - open - - Oracle Linux 9 - - Audit rules about the unauthorized access attempts to files (unsuccessful) are enabled. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Record Unsuccessful Access Attempts to Files - open_by_handle_at - - Oracle Linux 9 - - Audit rules about the unauthorized access attempts to files (unsuccessful) are enabled. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Record Unsuccessful Access Attempts to Files - openat - - Oracle Linux 9 - - Audit rules about the unauthorized access attempts to files (unsuccessful) are enabled. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Record Unsuccessful Delete Attempts to Files - rename - - Oracle Linux 9 - - Audit rules about the unauthorized access attempts to files (unsuccessful) are enabled. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Record Unsuccessful Delete Attempts to Files - renameat - - Oracle Linux 9 - - Audit rules about the unauthorized access attempts to files (unsuccessful) are enabled. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Record Unsuccessful Access Attempts to Files - truncate - - Oracle Linux 9 - - Audit rules about the unauthorized access attempts to files (unsuccessful) are enabled. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Record Unsuccessful Delete Attempts to Files - unlink - - Oracle Linux 9 - - Audit rules about the unauthorized access attempts to files (unsuccessful) are enabled. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Record Unsuccessful Delete Attempts to Files - unlinkat - - Oracle Linux 9 - - Audit rules about the unauthorized access attempts to files (unsuccessful) are enabled. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Record Events that Modify User/Group Information - /etc/group - - Oracle Linux 9 - - Audit user/group modification. - - - - - - - - - - - - - - - - Record Events that Modify User/Group Information - /etc/gshadow - - Oracle Linux 9 - - Audit user/group modification. - - - - - - - - - - - - - - - - Record Events that Modify User/Group Information - /etc/security/opasswd - - Oracle Linux 9 - - Audit user/group modification. - - - - - - - - - - - - - - - - Record Events that Modify User/Group Information - /etc/passwd - - Oracle Linux 9 - - Audit user/group modification. - - - - - - - - - - - - - - - - Record Events that Modify User/Group Information - /etc/shadow - - Oracle Linux 9 - - Audit user/group modification. - - - - - - - - - - - - - - - - Set number of records to cause an explicit flush to audit logs - - Oracle Linux 9 - - Ensure 'freq' is configured with value '50' in /etc/audit/auditd.conf - - - - - - - - - Include Local Events in Audit Logs - - Oracle Linux 9 - - Ensure 'local_events' is configured with value 'yes' in /etc/audit/auditd.conf - - - - - - - - - Resolve information before writing to audit logs - - Oracle Linux 9 - - Ensure 'log_format' is configured with value 'ENRICHED' in /etc/audit/auditd.conf - - - - - - - - - Write Audit Logs to the Disk - - Oracle Linux 9 - - Ensure 'write_logs' is configured with value 'yes' in /etc/audit/auditd.conf - - - - - - - - - - Enable the GNOME3 Screen Locking On Smartcard Removal - - Oracle Linux 9 - - Ensure 'removal-action' is configured with value ''lock-screen' in section 'org/gnome/settings-daemon/peripherals/smartcard' in /etc/dconf/db/local.d/ - - - - - - - - - - Verify that Shared Library Directories Have Root Group Ownership - - Oracle Linux 9 - - This test makes sure that /lib/, /lib64/, /usr/lib/, /usr/lib64/ is group owned by 0. - - - - - - - - - - - - Verify that System Executable Have Root Ownership - - Oracle Linux 9 - - This test makes sure that /bin/, /sbin/, /usr/bin/, /usr/sbin/, /usr/local/bin/, /usr/local/sbin/ is owned by 0. - - - - - - - - - - - - - - Verify that Shared Library Directories Have Root Ownership - - Oracle Linux 9 - - This test makes sure that /lib/, /lib64/, /usr/lib/, /usr/lib64/ is owned by 0. - - - - - - - - - - - - Verify that System Executable Directories Have Restrictive Permissions - - Oracle Linux 9 - - This test makes sure that /bin/, /sbin/, /usr/bin/, /usr/sbin/, /usr/local/bin/, /usr/local/sbin/ has mode 0755. + installation. + + + + + + + + Ensure gpgcheck Enabled for All yum Package Repositories + + Oracle Linux 9 + + + Ensure all yum or dnf repositories utilize signature checking. + + + + + + + + Ensure Oracle Linux GPG Key Installed + + Oracle Linux 9 + + + The Oracle Linux key packages are required to be installed. + + + + + + + + + + + + + + Ensure PAM Enforces Password Requirements - Minimum Digit Characters + + Oracle Linux 9 + + + The password dcredit should meet minimum requirements + + + + + + + + + + + + Ensure PAM Enforces Password Requirements - Prevent the Use of Dictionary Words + + Oracle Linux 9 + + + The password dictcheck should meet minimum requirements + + + + + + + + + + + + Ensure PAM Enforces Password Requirements - Minimum Different Characters + + Oracle Linux 9 + + + The password difok should meet minimum requirements + + + + + + + + + + + + Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters + + Oracle Linux 9 + + + The password lcredit should meet minimum requirements + + + + + + + + + + + + Ensure PAM Enforces Password Requirements - Maximum Consecutive Repeating Characters from Same Character Class + + Oracle Linux 9 + + + The password maxclassrepeat should meet minimum requirements + + + + + + + + + + + + Set Password Maximum Consecutive Repeating Characters + + Oracle Linux 9 + + + The password maxrepeat should meet minimum requirements + + + + + + + + + + + + Ensure PAM Enforces Password Requirements - Minimum Different Categories + + Oracle Linux 9 + + + The password minclass should meet minimum requirements + + + + + + + + + + + + Ensure PAM Enforces Password Requirements - Minimum Length + + Oracle Linux 9 + + + The password minlen should meet minimum requirements + + + + + + + + + + + + Ensure PAM Enforces Password Requirements - Minimum Special Characters + + Oracle Linux 9 + + + The password ocredit should meet minimum requirements + + + + + + + + + + + + Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters + + Oracle Linux 9 + + + The password ucredit should meet minimum requirements + + + + + + + + + + + + Lock Accounts After Failed Password Attempts + + Oracle Linux 9 + + + Lockout account after failed login attempts. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Set Interval For Counting Failed Password Attempts + + Oracle Linux 9 + + + The number of allowed failed logins should be set correctly. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Set Lockout Time for Failed Password Attempts + + Oracle Linux 9 + + + The unlock time after number of failed logins should be set correctly. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Configure auditing of unsuccessful file accesses + + Oracle Linux 9 + + + Inspect the contents of /etc/audit/rules.d/30-ospp-v42-3-access-failed.rules + + + + + + + + Configure auditing of successful file accesses + + Oracle Linux 9 + + + Inspect the contents of /etc/audit/rules.d/30-ospp-v42-3-access-success.rules + + + + + + + + Configure basic parameters of Audit system + + Oracle Linux 9 + + + Inspect the contents of /etc/audit/rules.d/10-base-config.rules + + + + + + + + Configure auditing of unsuccessful file creations + + Oracle Linux 9 + + + Inspect the contents of /etc/audit/rules.d/30-ospp-v42-1-create-failed.rules + + + + + + + + Configure auditing of successful file creations + + Oracle Linux 9 + + + Inspect the contents of /etc/audit/rules.d/30-ospp-v42-1-create-success.rules + + + + + + + + Configure auditing of unsuccessful file deletions + + Oracle Linux 9 + + + Inspect the contents of /etc/audit/rules.d/30-ospp-v42-4-delete-failed.rules + + + + + + + + Configure auditing of successful file deletions + + Oracle Linux 9 + + + Inspect the contents of /etc/audit/rules.d/30-ospp-v42-4-delete-success.rules + + + + + + + + Configure immutable Audit login UIDs + + Oracle Linux 9 + + + Inspect the contents of /etc/audit/rules.d/11-loginuid.rules + + + + + + + + Configure auditing of unsuccessful file modifications + + Oracle Linux 9 + + + Inspect the contents of /etc/audit/rules.d/30-ospp-v42-2-modify-failed.rules + + + + + + + + Configure auditing of successful file modifications + + Oracle Linux 9 + + + Inspect the contents of /etc/audit/rules.d/30-ospp-v42-2-modify-success.rules + + + + + + + + Configure auditing of loading and unloading of kernel modules + + Oracle Linux 9 + + + Inspect the contents of /etc/audit/rules.d/43-module-load.rules + + + + + + + + Perform general configuration of Audit for OSPP + + Oracle Linux 9 + + + Inspect the contents of /etc/audit/rules.d/30-ospp-v42.rules + + + + + + + + Configure auditing of unsuccessful ownership changes + + Oracle Linux 9 + + + Inspect the contents of /etc/audit/rules.d/30-ospp-v42-6-owner-change-failed.rules + + + + + + + + Configure auditing of successful ownership changes + + Oracle Linux 9 + + + Inspect the contents of /etc/audit/rules.d/30-ospp-v42-6-owner-change-success.rules + + + + + + + + Configure auditing of unsuccessful permission changes + + Oracle Linux 9 + + + Inspect the contents of /etc/audit/rules.d/30-ospp-v42-5-perm-change-failed.rules + + + + + + + + Configure auditing of successful permission changes + + Oracle Linux 9 + + + Inspect the contents of /etc/audit/rules.d/30-ospp-v42-5-perm-change-success.rules + + + + + + + + Ensure auditd Collects Information on the Use of Privileged Commands - init + + Oracle Linux 9 + + + Audit rules about the information on the use of init is enabled. + + + + + + + + + + + + + + + Ensure auditd Collects Information on the Use of Privileged Commands - poweroff + + Oracle Linux 9 + + + Audit rules about the information on the use of poweroff is enabled. + + + + + + + + + + + + + + + Ensure auditd Collects Information on the Use of Privileged Commands - reboot + + Oracle Linux 9 + + + Audit rules about the information on the use of reboot is enabled. + + + + + + + + + + + + + + + Ensure auditd Collects Information on the Use of Privileged Commands - shutdown + + Oracle Linux 9 + + + Audit rules about the information on the use of shutdown is enabled. + + + + + + + + + + + + + + + Record Events that Modify the System's Discretionary Access Controls - chmod + + Oracle Linux 9 + + + The changing of file permissions and attributes should be audited. + + + + + + + + + + + + + + + + + + + + + + + Record Events that Modify the System's Discretionary Access Controls - chown + + Oracle Linux 9 + + + The changing of file permissions and attributes should be audited. + + + + + + + + + + + + + + + + + + + + + + + Record Events that Modify the System's Discretionary Access Controls - fchmod + + Oracle Linux 9 + + + The changing of file permissions and attributes should be audited. + + + + + + + + + + + + + + + + + + + + + + + Record Events that Modify the System's Discretionary Access Controls - fchmodat + + Oracle Linux 9 + + + The changing of file permissions and attributes should be audited. + + + + + + + + + + + + + + + + + + + + + + + Record Events that Modify the System's Discretionary Access Controls - fchown + + Oracle Linux 9 + + + The changing of file permissions and attributes should be audited. + + + + + + + + + + + + + + + + + + + + + + + Record Events that Modify the System's Discretionary Access Controls - fchownat + + Oracle Linux 9 + + + The changing of file permissions and attributes should be audited. + + + + + + + + + + + + + + + + + + + + + + + Record Events that Modify the System's Discretionary Access Controls - fremovexattr + + Oracle Linux 9 + + + The changing of file permissions and attributes should be audited. + + + + + + + + + + + + + + + + + + + + + + + Record Events that Modify the System's Discretionary Access Controls - fsetxattr + + Oracle Linux 9 + + + The changing of file permissions and attributes should be audited. + + + + + + + + + + + + + + + + + + + + + + + Record Events that Modify the System's Discretionary Access Controls - lchown + + Oracle Linux 9 + + + The changing of file permissions and attributes should be audited. + + + + + + + + + + + + + + + + + + + + + + + Record Events that Modify the System's Discretionary Access Controls - lremovexattr + + Oracle Linux 9 + + + The changing of file permissions and attributes should be audited. + + + + + + + + + + + + + + + + + + + + + + + Record Events that Modify the System's Discretionary Access Controls - lsetxattr + + Oracle Linux 9 + + + The changing of file permissions and attributes should be audited. + + + + + + + + + + + + + + + + + + + + + + + Record Events that Modify the System's Discretionary Access Controls - removexattr + + Oracle Linux 9 + + + The changing of file permissions and attributes should be audited. + + + + + + + + + + + + + + + + + + + + + + + Record Events that Modify the System's Discretionary Access Controls - setxattr + + Oracle Linux 9 + + + The changing of file permissions and attributes should be audited. + + + + + + + + + + + + + + + + + + + + + + + Record Events that Modify the System's Discretionary Access Controls - umount2 + + Oracle Linux 9 + + + The changing of file permissions and attributes should be audited. + + + + + + + + + + + + + + + + + + + + + + + Record Any Attempts to Run chacl + + Oracle Linux 9 + + + Audit rules about the information on the use of chacl is enabled. + + + + + + + + + + + + + + + Record Any Attempts to Run chcon + + Oracle Linux 9 + + + Audit rules about the information on the use of chcon is enabled. + + + + + + + + + + + + + + + Record Any Attempts to Run restorecon + + Oracle Linux 9 + + + Audit rules about the information on the use of restorecon is enabled. + + + + + + + + + + + + + + + Record Any Attempts to Run semanage + + Oracle Linux 9 + + + Audit rules about the information on the use of semanage is enabled. + + + + + + + + + + + + + + + Record Any Attempts to Run setfacl + + Oracle Linux 9 + + + Audit rules about the information on the use of setfacl is enabled. + + + + + + + + + + + + + + + Record Any Attempts to Run setfiles + + Oracle Linux 9 + + + Audit rules about the information on the use of setfiles is enabled. + + + + + + + + + + + + + + + Record Any Attempts to Run setsebool + + Oracle Linux 9 + + + Audit rules about the information on the use of setsebool is enabled. + + + + + + + + + + + + + + + Record Any Attempts to Run seunshare + + Oracle Linux 9 + + + Audit rules about the information on the use of seunshare is enabled. + + + + + + + + + + + + + + + Ensure auditd Collects File Deletion Events by User - rename + + Oracle Linux 9 + + + The deletion of files should be audited. + + + + + + + + + + + + + + + + + + + + + + + Ensure auditd Collects File Deletion Events by User - renameat + + Oracle Linux 9 + + + The deletion of files should be audited. + + + + + + + + + + + + + + + + + + + + + + + Ensure auditd Collects File Deletion Events by User - rmdir + + Oracle Linux 9 + + + The deletion of files should be audited. + + + + + + + + + + + + + + + + + + + + + + + Ensure auditd Collects File Deletion Events by User - unlink + + Oracle Linux 9 + + + The deletion of files should be audited. + + + + + + + + + + + + + + + + + + + + + + + Ensure auditd Collects File Deletion Events by User - unlinkat + + Oracle Linux 9 + + + The deletion of files should be audited. + + + + + + + + + + + + + + + + + + + + + + + Record Attempts to Alter Logon and Logout Events - faillock + + Oracle Linux 9 + + + Audit rules should be configured to log successful and unsuccessful login and logout events. + + + + + + + + + + + + + + + Record Attempts to Alter Logon and Logout Events - lastlog + + Oracle Linux 9 + + + Audit rules should be configured to log successful and unsuccessful login and logout events. + + + + + + + + + + + + + + + Record Attempts to Alter Logon and Logout Events - tallylog + + Oracle Linux 9 + + + Audit rules should be configured to log successful and unsuccessful login and logout events. + + + + + + + + + + + + + + + Ensure auditd Collects Information on Exporting to Media (successful) + + Oracle Linux 9 + + + The changing of file permissions and attributes should be audited. + + + + + + + + + + + + + + + + + + + + + + + Ensure auditd Collects Information on the Use of Privileged Commands - at + + Oracle Linux 9 + + + Audit rules about the information on the use of at is enabled. + + + + + + + + + + + + + + + Ensure auditd Collects Information on the Use of Privileged Commands - chage + + Oracle Linux 9 + + + Audit rules about the information on the use of chage is enabled. + + + + + + + + + + + + + + + Ensure auditd Collects Information on the Use of Privileged Commands - chsh + + Oracle Linux 9 + + + Audit rules about the information on the use of chsh is enabled. + + + + + + + + + + + + + + + Ensure auditd Collects Information on the Use of Privileged Commands - crontab + + Oracle Linux 9 + + + Audit rules about the information on the use of crontab is enabled. + + + + + + + + + + + + + + + Ensure auditd Collects Information on the Use of Privileged Commands - gpasswd + + Oracle Linux 9 + + + Audit rules about the information on the use of gpasswd is enabled. + + + + + + + + + + + + + + + Ensure auditd Collects Information on the Use of Privileged Commands - kmod + + Oracle Linux 9 + + + Audit rules about the information on the use of kmod is enabled. + + + + + + + + + + + + + + + Ensure auditd Collects Information on the Use of Privileged Commands - mount + + Oracle Linux 9 + + + Audit rules about the information on the use of mount is enabled. + + + + + + + + + + + + + + + Ensure auditd Collects Information on the Use of Privileged Commands - newgrp + + Oracle Linux 9 + + + Audit rules about the information on the use of newgrp is enabled. + + + + + + + + + + + + + + + Ensure auditd Collects Information on the Use of Privileged Commands - pam_timestamp_check + + Oracle Linux 9 + + + Audit rules about the information on the use of pam_timestamp_check is enabled. + + + + + + + + + + + + + + + Ensure auditd Collects Information on the Use of Privileged Commands - passwd + + Oracle Linux 9 + + + Audit rules about the information on the use of passwd is enabled. + + + + + + + + + + + + + + + Ensure auditd Collects Information on the Use of Privileged Commands - postdrop + + Oracle Linux 9 + + + Audit rules about the information on the use of postdrop is enabled. + + + + + + + + + + + + + + + Ensure auditd Collects Information on the Use of Privileged Commands - postqueue + + Oracle Linux 9 + + + Audit rules about the information on the use of postqueue is enabled. + + + + + + + + + + + + + + + Record Any Attempts to Run ssh-agent + + Oracle Linux 9 + + + Audit rules about the information on the use of ssh_agent is enabled. + + + + + + + + + + + + + + + Ensure auditd Collects Information on the Use of Privileged Commands - ssh-keysign + + Oracle Linux 9 + + + Audit rules about the information on the use of ssh_keysign is enabled. + + + + + + + + + + + + + + + Ensure auditd Collects Information on the Use of Privileged Commands - su + + Oracle Linux 9 + + + Audit rules about the information on the use of su is enabled. + + + + + + + + + + + + + + + Ensure auditd Collects Information on the Use of Privileged Commands - sudo + + Oracle Linux 9 + + + Audit rules about the information on the use of sudo is enabled. + + + + + + + + + + + + + + + Ensure auditd Collects Information on the Use of Privileged Commands - sudoedit + + Oracle Linux 9 + + + Audit rules about the information on the use of sudoedit is enabled. + + + + + + + + + + + + + + + Ensure auditd Collects Information on the Use of Privileged Commands - umount + + Oracle Linux 9 + + + Audit rules about the information on the use of umount is enabled. + + + + + + + + + + + + + + + Ensure auditd Collects Information on the Use of Privileged Commands - unix_chkpwd + + Oracle Linux 9 + + + Audit rules about the information on the use of unix_chkpwd is enabled. + + + + + + + + + + + + + + + Ensure auditd Collects Information on the Use of Privileged Commands - unix_update + + Oracle Linux 9 + + + Audit rules about the information on the use of unix_update is enabled. + + + + + + + + + + + + + + + Ensure auditd Collects Information on the Use of Privileged Commands - userhelper + + Oracle Linux 9 + + + Audit rules about the information on the use of userhelper is enabled. + + + + + + + + + + + + + + + Ensure auditd Collects Information on the Use of Privileged Commands - usermod + + Oracle Linux 9 + + + Audit rules about the information on the use of usermod is enabled. + + + + + + + + + + + + + + + Ensure auditd Collects Information on the Use of Privileged Commands - usernetctl + + Oracle Linux 9 + + + Audit rules about the information on the use of usernetctl is enabled. + + + + + + + + + + + + + + + Record Unsuccessful Access Attempts to Files - creat + + Oracle Linux 9 + + + Audit rules about the unauthorized access attempts to files (unsuccessful) are enabled. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Record Unsuccessful Access Attempts to Files - ftruncate + + Oracle Linux 9 + + + Audit rules about the unauthorized access attempts to files (unsuccessful) are enabled. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Record Unsuccessful Access Attempts to Files - open + + Oracle Linux 9 + + + Audit rules about the unauthorized access attempts to files (unsuccessful) are enabled. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Record Unsuccessful Access Attempts to Files - open_by_handle_at + + Oracle Linux 9 + + + Audit rules about the unauthorized access attempts to files (unsuccessful) are enabled. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Record Unsuccessful Access Attempts to Files - openat + + Oracle Linux 9 + + + Audit rules about the unauthorized access attempts to files (unsuccessful) are enabled. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Record Unsuccessful Access Attempts to Files - truncate + + Oracle Linux 9 + + + Audit rules about the unauthorized access attempts to files (unsuccessful) are enabled. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Record Events that Modify User/Group Information - /etc/group + + Oracle Linux 9 + + + Audit user/group modification. + + + + + + + + + + + + + + + Record Events that Modify User/Group Information - /etc/gshadow + + Oracle Linux 9 + + + Audit user/group modification. + + + + + + + + + + + + + + + Record Events that Modify User/Group Information - /etc/security/opasswd + + Oracle Linux 9 + + + Audit user/group modification. + + + + + + + + + + + + + + + Record Events that Modify User/Group Information - /etc/passwd + + Oracle Linux 9 + + + Audit user/group modification. + + + + + + + + + + + + + + + Record Events that Modify User/Group Information - /etc/shadow + + Oracle Linux 9 + + + Audit user/group modification. + + + + + + + + + + + + + + + Record Attempts to perform maintenance activities + + Oracle Linux 9 + + + Audit rules should be configured to log successful and unsuccessful login and logout events. + + + + + + + + + + + + + + + Set number of records to cause an explicit flush to audit logs + + Oracle Linux 9 + + + Ensure 'freq' is configured with value '50' in /etc/audit/auditd.conf + + + + + + + + Include Local Events in Audit Logs + + Oracle Linux 9 + + + Ensure 'local_events' is configured with value 'yes' in /etc/audit/auditd.conf + + + + + + + + Resolve information before writing to audit logs + + Oracle Linux 9 + + + Ensure 'log_format' is configured with value 'ENRICHED' in /etc/audit/auditd.conf + + + + + + + + Write Audit Logs to the Disk + + Oracle Linux 9 + + + Ensure 'write_logs' is configured with value 'yes' in /etc/audit/auditd.conf + + + + + + + + + Enable the GNOME3 Screen Locking On Smartcard Removal + + Oracle Linux 9 + + + Ensure 'removal-action' is configured with value ''lock-screen' in section 'org/gnome/settings-daemon/peripherals/smartcard' in /etc/dconf/db/local.d/ + + + + + + + + + Verify that Shared Library Directories Have Root Group Ownership + + Oracle Linux 9 + + + This test makes sure that /lib/, /lib64/, /usr/lib/, /usr/lib64/ is group owned by 0. + + + + + + + + + + + Verify that System Executable Have Root Ownership + + Oracle Linux 9 + + + This test makes sure that /bin/, /sbin/, /usr/bin/, /usr/sbin/, /usr/local/bin/, /usr/local/sbin/ is owned by 0. + + + + + + + + + + + + + Verify that Shared Library Directories Have Root Ownership + + Oracle Linux 9 + + + This test makes sure that /lib/, /lib64/, /usr/lib/, /usr/lib64/ is owned by 0. + + + + + + + + + + + Verify that System Executable Directories Have Restrictive Permissions + + Oracle Linux 9 + + + This test makes sure that /bin/, /sbin/, /usr/bin/, /usr/sbin/, /usr/local/bin/, /usr/local/sbin/ has mode 0755. If the target file or directory has an extended ACL, then it will fail the mode check. - - - - - - - - - - - - - - - Verify that Shared Library Directories Have Restrictive Permissions - - Oracle Linux 9 - - This test makes sure that /lib/, /lib64/, /usr/lib/, /usr/lib64/ has mode 7755. + + + + + + + + + + + + + + Verify that Shared Library Directories Have Restrictive Permissions + + Oracle Linux 9 + + + This test makes sure that /lib/, /lib64/, /usr/lib/, /usr/lib64/ has mode 7755. If the target file or directory has an extended ACL, then it will fail the mode check. - - - - - - - - - - - - - Disable Host-Based Authentication - - Oracle Linux 9 - - Ensure 'HostbasedAuthentication' is configured with value 'no' in /etc/ssh/sshd_config - - - - - - - - - - - - - - - - - - - - - - - Audit Tools Must Be Group-owned by Root - - Oracle Linux 9 - - This test makes sure that /sbin/auditctl, /sbin/aureport, /sbin/ausearch, /sbin/autrace, /sbin/auditd, /sbin/rsyslogd, /sbin/augenrules is group owned by 0. - - - - - - - - - - - - - - - Audit Tools Must Be Owned by Root - - Oracle Linux 9 - - This test makes sure that /sbin/auditctl, /sbin/aureport, /sbin/ausearch, /sbin/autrace, /sbin/auditd, /sbin/rsyslogd, /sbin/augenrules is owned by 0. - - - - - - - - - - - - - - - Audit Tools Must Have a Mode of 0755 or Less Permissive - - Oracle Linux 9 - - This test makes sure that /sbin/auditctl, /sbin/aureport, /sbin/ausearch, /sbin/autrace, /sbin/auditd, /sbin/rsyslogd, /sbin/augenrules has mode 0755. + + + + + + + + + + + + Verify Group Who Owns /etc/ipsec.d Directory + + Oracle Linux 9 + + + This test makes sure that /etc/ipsec.d/ is group owned by root. + + + + + + + + Verify Group Who Owns /etc/iptables Directory + + Oracle Linux 9 + + + This test makes sure that /etc/iptables/ is group owned by root. + + + + + + + + Verify Group Who Owns /etc/nftables Directory + + Oracle Linux 9 + + + This test makes sure that /etc/nftables/ is group owned by root. + + + + + + + + Verify Group Who Owns /etc/selinux Directory + + Oracle Linux 9 + + + This test makes sure that /etc/selinux/ is group owned by root. + + + + + + + + Verify Group Who Owns /etc/sudoers.d Directory + + Oracle Linux 9 + + + This test makes sure that /etc/sudoers.d/ is group owned by root. + + + + + + + + Verify Group Who Owns /etc/sysctl.d Directory + + Oracle Linux 9 + + + This test makes sure that /etc/sysctl.d/ is group owned by root. + + + + + + + + Verify User Who Owns /etc/ipsec.d Directory + + Oracle Linux 9 + + + This test makes sure that /etc/ipsec.d/ is owned by 0. + + + + + + + + Verify User Who Owns /etc/iptables Directory + + Oracle Linux 9 + + + This test makes sure that /etc/iptables/ is owned by 0. + + + + + + + + Verify User Who Owns /etc/nftables Directory + + Oracle Linux 9 + + + This test makes sure that /etc/nftables/ is owned by 0. + + + + + + + + Verify User Who Owns /etc/selinux Directory + + Oracle Linux 9 + + + This test makes sure that /etc/selinux/ is owned by 0. + + + + + + + + Verify User Who Owns /etc/sudoers.d Directory + + Oracle Linux 9 + + + This test makes sure that /etc/sudoers.d/ is owned by 0. + + + + + + + + Verify User Who Owns /etc/sysctl.d Directory + + Oracle Linux 9 + + + This test makes sure that /etc/sysctl.d/ is owned by 0. + + + + + + + + Verify Permissions On /etc/ipsec.d Directory + + Oracle Linux 9 + + + This test makes sure that /etc/ipsec.d/ has mode 0700. If the target file or directory has an extended ACL, then it will fail the mode check. - - - - - - - - - - - - - - - - Verify Group Who Owns Backup group File - - Oracle Linux 9 - - This test makes sure that /etc/group- is group owned by 0. - - - - - - - - - Verify Group Who Owns Backup gshadow File - - Oracle Linux 9 - - This test makes sure that /etc/gshadow- is group owned by 0. - - - - - - - - - Verify Group Who Owns Backup passwd File - - Oracle Linux 9 - - This test makes sure that /etc/passwd- is group owned by 0. - - - - - - - - - Verify User Who Owns Backup shadow File - - Oracle Linux 9 - - This test makes sure that /etc/shadow- is group owned by 0. - - - - - - - - - Verify Group Who Owns /etc/cron.allow file - - Oracle Linux 9 - - This test makes sure that /etc/cron.allow is group owned by 0. - - - - - - - - - Verify Group Who Owns cron.d - - Oracle Linux 9 - - This test makes sure that /etc/cron.d/ is group owned by 0. - - - - - - - - - Verify Group Who Owns cron.daily - - Oracle Linux 9 - - This test makes sure that /etc/cron.daily/ is group owned by 0. - - - - - - - - - Verify Group Who Owns cron.hourly - - Oracle Linux 9 - - This test makes sure that /etc/cron.hourly/ is group owned by 0. - - - - - - - - - Verify Group Who Owns cron.monthly - - Oracle Linux 9 - - This test makes sure that /etc/cron.monthly/ is group owned by 0. - - - - - - - - - Verify Group Who Owns cron.weekly - - Oracle Linux 9 - - This test makes sure that /etc/cron.weekly/ is group owned by 0. - - - - - - - - - Verify Group Who Owns Crontab - - Oracle Linux 9 - - This test makes sure that /etc/crontab is group owned by 0. - - - - - - - - - Verify /boot/grub2/user.cfg Group Ownership - - Oracle Linux 9 - - This test makes sure that /boot/grub2/user.cfg is group owned by 0. - - - - - - - - - Verify Group Who Owns group File - - Oracle Linux 9 - - This test makes sure that /etc/group is group owned by 0. - - - - - - - - - Verify Group Who Owns gshadow File - - Oracle Linux 9 - - This test makes sure that /etc/gshadow is group owned by 0. - - - - - - - - - Verify Group Who Owns passwd File - - Oracle Linux 9 - - This test makes sure that /etc/passwd is group owned by 0. - - - - - - - - - Verify Group Who Owns shadow File - - Oracle Linux 9 - - This test makes sure that /etc/shadow is group owned by 0. - - - - - - - - - Verify /boot/grub2/grub.cfg Group Ownership - - Oracle Linux 9 - - This test makes sure that /boot/grub2/grub.cfg is group owned by 0. - - - - - - - - - Verify Group Who Owns SSH Server config file - - Oracle Linux 9 - - This test makes sure that /etc/ssh/sshd_config is group owned by 0. - - - - - - - - - Verify /boot/grub2/user.cfg Group Ownership - - Oracle Linux 9 - - This test makes sure that /boot/grub2/user.cfg is group owned by 0. - - - - - - - - - Verify Group Who Owns /var/log Directory - - Oracle Linux 9 - - This test makes sure that /var/log/ is group owned by 0. - - - - - - - - - Verify Group Who Owns /var/log/messages File - - Oracle Linux 9 - - This test makes sure that /var/log/messages is group owned by 0. - - - - - - - - - Verify Group Who Owns /var/log/syslog File - - Oracle Linux 9 - - This test makes sure that /var/log/syslog is group owned by 4. - - - - - - - - - Audit Configuration Files Must Be Owned By Group root - - Oracle Linux 9 - - This test makes sure that /etc/audit/, /etc/audit/rules.d/ is group owned by 0. - - - - - - - - - - Verify Group Ownership on SSH Server Private *_key Key Files - - Oracle Linux 9 - - This test makes sure that /etc/ssh/ is group owned by ssh_keys. - - - - - - - - - Verify Group Ownership on SSH Server Public *.pub Key Files - - Oracle Linux 9 - - This test makes sure that /etc/ssh/ is group owned by 0. - - - - - - - - - Verify User Who Owns Backup group File - - Oracle Linux 9 - - This test makes sure that /etc/group- is owned by 0. - - - - - - - - - Verify User Who Owns Backup gshadow File - - Oracle Linux 9 - - This test makes sure that /etc/gshadow- is owned by 0. - - - - - - - - - Verify User Who Owns Backup passwd File - - Oracle Linux 9 - - This test makes sure that /etc/passwd- is owned by 0. - - - - - - - - - Verify Group Who Owns Backup shadow File - - Oracle Linux 9 - - This test makes sure that /etc/shadow- is owned by 0. - - - - - - - - - Verify User Who Owns /etc/cron.allow file - - Oracle Linux 9 - - This test makes sure that /etc/cron.allow is owned by 0. - - - - - - - - - Verify Owner on cron.d - - Oracle Linux 9 - - This test makes sure that /etc/cron.d/ is owned by 0. - - - - - - - - - Verify Owner on cron.daily - - Oracle Linux 9 - - This test makes sure that /etc/cron.daily/ is owned by 0. - - - - - - - - - Verify Owner on cron.hourly - - Oracle Linux 9 - - This test makes sure that /etc/cron.hourly/ is owned by 0. - - - - - - - - - Verify Owner on cron.monthly - - Oracle Linux 9 - - This test makes sure that /etc/cron.monthly/ is owned by 0. - - - - - - - - - Verify Owner on cron.weekly - - Oracle Linux 9 - - This test makes sure that /etc/cron.weekly/ is owned by 0. - - - - - - - - - Verify Owner on crontab - - Oracle Linux 9 - - This test makes sure that /etc/crontab is owned by 0. - - - - - - - - - Verify User Who Owns group File - - Oracle Linux 9 - - This test makes sure that /etc/group is owned by 0. - - - - - - - - - Verify User Who Owns gshadow File - - Oracle Linux 9 - - This test makes sure that /etc/gshadow is owned by 0. - - - - - - - - - Verify User Who Owns passwd File - - Oracle Linux 9 - - This test makes sure that /etc/passwd is owned by 0. - - - - - - - - - Verify User Who Owns shadow File - - Oracle Linux 9 - - This test makes sure that /etc/shadow is owned by 0. - - - - - - - - - Verify /boot/grub2/grub.cfg User Ownership - - Oracle Linux 9 - - This test makes sure that /boot/grub2/grub.cfg is owned by 0. - - - - - - - - - Verify Owner on SSH Server config file - - Oracle Linux 9 - - This test makes sure that /etc/ssh/sshd_config is owned by 0. - - - - - - - - - Verify /boot/grub2/user.cfg User Ownership - - Oracle Linux 9 - - This test makes sure that /boot/grub2/user.cfg is owned by 0. - - - - - - - - - Verify User Who Owns /var/log Directory - - Oracle Linux 9 - - This test makes sure that /var/log/ is owned by 0. - - - - - - - - - Verify User Who Owns /var/log/messages File - - Oracle Linux 9 - - This test makes sure that /var/log/messages is owned by 0. - - - - - - - - - Verify User Who Owns /var/log/syslog File - - Oracle Linux 9 - - This test makes sure that /var/log/syslog is owned by 104. - - - - - - - - - Audit Configuration Files Must Be Owned By Root - - Oracle Linux 9 - - This test makes sure that /etc/audit/, /etc/audit/rules.d/ is owned by 0. - - - - - - - - - - Verify that Shared Library Files Have Root Ownership - - Oracle Linux 9 - - This test makes sure that /lib/, /lib64/, /usr/lib/, /usr/lib64/ is owned by 0. - - - - - - - - - - - - Verify Ownership on SSH Server Private *_key Key Files - - Oracle Linux 9 - - This test makes sure that /etc/ssh/ is owned by 0. - - - - - - - - - Verify Ownership on SSH Server Public *.pub Key Files - - Oracle Linux 9 - - This test makes sure that /etc/ssh/ is owned by 0. - - - - - - - - - Audit Configuration Files Permissions are 640 or More Restrictive - - Oracle Linux 9 - - This test makes sure that /etc/audit/, /etc/audit/rules.d/ has mode 0640. + + + + + + + + + Verify Permissions On /etc/iptables Directory + + Oracle Linux 9 + + + This test makes sure that /etc/iptables/ has mode 0700. If the target file or directory has an extended ACL, then it will fail the mode check. - - - - - - - - - - - Verify Permissions on Backup group File - - Oracle Linux 9 - - This test makes sure that /etc/group- has mode 0644. + + + + + + + + + Verify Permissions On /etc/nftables Directory + + Oracle Linux 9 + + + This test makes sure that /etc/nftables/ has mode 0700. If the target file or directory has an extended ACL, then it will fail the mode check. - - - - - - - - - - Verify Permissions on Backup gshadow File - - Oracle Linux 9 - - This test makes sure that /etc/gshadow- has mode 0000. + + + + + + + + + Verify Permissions On /etc/selinux Directory + + Oracle Linux 9 + + + This test makes sure that /etc/selinux/ has mode 0755. If the target file or directory has an extended ACL, then it will fail the mode check. - - - - - - - - - - Verify Permissions on Backup passwd File - - Oracle Linux 9 - - This test makes sure that /etc/passwd- has mode 0644. + + + + + + + + + Verify Permissions On /etc/sudoers.d Directory + + Oracle Linux 9 + + + This test makes sure that /etc/sudoers.d/ has mode 0750. If the target file or directory has an extended ACL, then it will fail the mode check. - - - - - - - - - - Verify Permissions on Backup shadow File - - Oracle Linux 9 - - This test makes sure that /etc/shadow- has mode 0000. + + + + + + + + + Verify Permissions On /etc/sysctl.d Directory + + Oracle Linux 9 + + + This test makes sure that /etc/sysctl.d/ has mode 0755. If the target file or directory has an extended ACL, then it will fail the mode check. - - - - - - - - - - Verify Permissions on /etc/cron.allow file - - Oracle Linux 9 - - This test makes sure that /etc/cron.allow has mode 0640. + + + + + + + + + Disable Host-Based Authentication + + Oracle Linux 9 + + + Ensure 'HostbasedAuthentication' is configured with value 'no' in /etc/ssh/sshd_config + + + + + + + + + + + + + + + + + + + + + + Ensure that /etc/at.deny does not exist + + Oracle Linux 9 + + + This test makes sure that/etc/at.deny does not exist. + + + + + + + + Audit Tools Must Be Group-owned by Root + + Oracle Linux 9 + + + This test makes sure that /sbin/auditctl, /sbin/aureport, /sbin/ausearch, /sbin/autrace, /sbin/auditd, /sbin/rsyslogd, /sbin/augenrules is group owned by 0. + + + + + + + + + + + + + + Audit Tools Must Be Owned by Root + + Oracle Linux 9 + + + This test makes sure that /sbin/auditctl, /sbin/aureport, /sbin/ausearch, /sbin/autrace, /sbin/auditd, /sbin/rsyslogd, /sbin/augenrules is owned by 0. + + + + + + + + + + + + + + Audit Tools Must Have a Mode of 0755 or Less Permissive + + Oracle Linux 9 + + + This test makes sure that /sbin/auditctl, /sbin/aureport, /sbin/ausearch, /sbin/autrace, /sbin/auditd, /sbin/rsyslogd, /sbin/augenrules has mode 0755. If the target file or directory has an extended ACL, then it will fail the mode check. - - - - - - - - - - Verify Permissions on cron.d - - Oracle Linux 9 - - This test makes sure that /etc/cron.d/ has mode 0700. + + + + + + + + + + + + + + + Ensure that /etc/cron.deny does not exist + + Oracle Linux 9 + + + This test makes sure that/etc/cron.deny does not exist. + + + + + + + + Verify Group Who Owns /etc/at.allow file + + Oracle Linux 9 + + + This test makes sure that /etc/at.allow is group owned by 0. + + + + + + + + Verify Group Who Owns Backup group File + + Oracle Linux 9 + + + This test makes sure that /etc/group- is group owned by 0. + + + + + + + + Verify Group Who Owns Backup gshadow File + + Oracle Linux 9 + + + This test makes sure that /etc/gshadow- is group owned by 0. + + + + + + + + Verify Group Who Owns Backup passwd File + + Oracle Linux 9 + + + This test makes sure that /etc/passwd- is group owned by 0. + + + + + + + + Verify User Who Owns Backup shadow File + + Oracle Linux 9 + + + This test makes sure that /etc/shadow- is group owned by 0. + + + + + + + + Verify Group Who Owns /etc/cron.allow file + + Oracle Linux 9 + + + This test makes sure that /etc/cron.allow is group owned by 0. + + + + + + + + Verify Group Who Owns cron.d + + Oracle Linux 9 + + + This test makes sure that /etc/cron.d/ is group owned by 0. + + + + + + + + Verify Group Who Owns cron.daily + + Oracle Linux 9 + + + This test makes sure that /etc/cron.daily/ is group owned by 0. + + + + + + + + Verify Group Who Owns cron.deny + + Oracle Linux 9 + + + This test makes sure that /etc/cron.deny is group owned by 0. + + + + + + + + Verify Group Who Owns cron.hourly + + Oracle Linux 9 + + + This test makes sure that /etc/cron.hourly/ is group owned by 0. + + + + + + + + Verify Group Who Owns cron.monthly + + Oracle Linux 9 + + + This test makes sure that /etc/cron.monthly/ is group owned by 0. + + + + + + + + Verify Group Who Owns cron.weekly + + Oracle Linux 9 + + + This test makes sure that /etc/cron.weekly/ is group owned by 0. + + + + + + + + Verify Group Who Owns Crontab + + Oracle Linux 9 + + + This test makes sure that /etc/crontab is group owned by 0. + + + + + + + + Verify the UEFI Boot Loader grub.cfg Group Ownership + + Oracle Linux 9 + + + This test makes sure that /boot/grub2/grub.cfg is group owned by 0. + + + + + + + + Verify /boot/grub2/user.cfg Group Ownership + + Oracle Linux 9 + + + This test makes sure that /boot/grub2/user.cfg is group owned by 0. + + + + + + + + Verify Group Who Owns /etc/crypttab File + + Oracle Linux 9 + + + This test makes sure that /etc/crypttab is group owned by root. + + + + + + + + Verify Group Who Owns group File + + Oracle Linux 9 + + + This test makes sure that /etc/group is group owned by 0. + + + + + + + + Verify Group Who Owns gshadow File + + Oracle Linux 9 + + + This test makes sure that /etc/gshadow is group owned by 0. + + + + + + + + Verify Group Who Owns /etc/ipsec.conf File + + Oracle Linux 9 + + + This test makes sure that /etc/ipsec.conf is group owned by root. + + + + + + + + Verify Group Who Owns /etc/ipsec.secrets File + + Oracle Linux 9 + + + This test makes sure that /etc/ipsec.secrets is group owned by root. + + + + + + + + Verify Group Ownership of System Login Banner for Remote Connections + + Oracle Linux 9 + + + This test makes sure that /etc/issue.net is group owned by 0. + + + + + + + + Verify Group Who Owns passwd File + + Oracle Linux 9 + + + This test makes sure that /etc/passwd is group owned by 0. + + + + + + + + Verify Group Who Owns /etc/sestatus.conf File + + Oracle Linux 9 + + + This test makes sure that /etc/sestatus.conf is group owned by root. + + + + + + + + Verify Group Who Owns shadow File + + Oracle Linux 9 + + + This test makes sure that /etc/shadow is group owned by 0. + + + + + + + + Verify Group Who Owns /etc/shells File + + Oracle Linux 9 + + + This test makes sure that /etc/shells is group owned by 0. + + + + + + + + Verify Group Who Owns /etc/sudoers File + + Oracle Linux 9 + + + This test makes sure that /etc/sudoers is group owned by root. + + + + + + + + Verify /boot/grub2/grub.cfg Group Ownership + + Oracle Linux 9 + + + This test makes sure that /boot/grub2/grub.cfg is group owned by 0. + + + + + + + + Verify Group Who Owns SSH Server config file + + Oracle Linux 9 + + + This test makes sure that /etc/ssh/sshd_config is group owned by 0. + + + + + + + + Verify Group Who Owns System.map Files + + Oracle Linux 9 + + + This test makes sure that /boot/ is group owned by root. + + + + + + + + Verify /boot/grub2/user.cfg Group Ownership + + Oracle Linux 9 + + + This test makes sure that /boot/grub2/user.cfg is group owned by 0. + + + + + + + + Verify Group Who Owns /var/log Directory + + Oracle Linux 9 + + + This test makes sure that /var/log/ is group owned by 0. + + + + + + + + Verify Group Who Owns /var/log/messages File + + Oracle Linux 9 + + + This test makes sure that /var/log/messages is group owned by 0. + + + + + + + + Verify Group Who Owns /var/log/syslog File + + Oracle Linux 9 + + + This test makes sure that /var/log/syslog is group owned by 4. + + + + + + + + Audit Configuration Files Must Be Owned By Group root + + Oracle Linux 9 + + + This test makes sure that /etc/audit/, /etc/audit/rules.d/ is group owned by 0. + + + + + + + + + Verify Group Ownership on SSH Server Private *_key Key Files + + Oracle Linux 9 + + + This test makes sure that /etc/ssh/ is group owned by ssh_keys. + + + + + + + + Verify Group Ownership on SSH Server Public *.pub Key Files + + Oracle Linux 9 + + + This test makes sure that /etc/ssh/ is group owned by 0. + + + + + + + + Verify User Who Owns Backup group File + + Oracle Linux 9 + + + This test makes sure that /etc/group- is owned by 0. + + + + + + + + Verify User Who Owns Backup gshadow File + + Oracle Linux 9 + + + This test makes sure that /etc/gshadow- is owned by 0. + + + + + + + + Verify User Who Owns Backup passwd File + + Oracle Linux 9 + + + This test makes sure that /etc/passwd- is owned by 0. + + + + + + + + Verify Group Who Owns Backup shadow File + + Oracle Linux 9 + + + This test makes sure that /etc/shadow- is owned by 0. + + + + + + + + Verify User Who Owns /etc/cron.allow file + + Oracle Linux 9 + + + This test makes sure that /etc/cron.allow is owned by 0. + + + + + + + + Verify Owner on cron.d + + Oracle Linux 9 + + + This test makes sure that /etc/cron.d/ is owned by 0. + + + + + + + + Verify Owner on cron.daily + + Oracle Linux 9 + + + This test makes sure that /etc/cron.daily/ is owned by 0. + + + + + + + + Verify Owner on cron.deny + + Oracle Linux 9 + + + This test makes sure that /etc/cron.deny is owned by 0. + + + + + + + + Verify Owner on cron.hourly + + Oracle Linux 9 + + + This test makes sure that /etc/cron.hourly/ is owned by 0. + + + + + + + + Verify Owner on cron.monthly + + Oracle Linux 9 + + + This test makes sure that /etc/cron.monthly/ is owned by 0. + + + + + + + + Verify Owner on cron.weekly + + Oracle Linux 9 + + + This test makes sure that /etc/cron.weekly/ is owned by 0. + + + + + + + + Verify Owner on crontab + + Oracle Linux 9 + + + This test makes sure that /etc/crontab is owned by 0. + + + + + + + + Verify the UEFI Boot Loader grub.cfg User Ownership + + Oracle Linux 9 + + + This test makes sure that /boot/grub2/grub.cfg is owned by 0. + + + + + + + + Verify /boot/grub2/user.cfg User Ownership + + Oracle Linux 9 + + + This test makes sure that /boot/grub2/user.cfg is owned by 0. + + + + + + + + Verify User Who Owns /etc/chrony.keys File + + Oracle Linux 9 + + + This test makes sure that /etc/chrony.keys is owned by 0. + + + + + + + + Verify User Who Owns /etc/crypttab File + + Oracle Linux 9 + + + This test makes sure that /etc/crypttab is owned by 0. + + + + + + + + Verify User Who Owns group File + + Oracle Linux 9 + + + This test makes sure that /etc/group is owned by 0. + + + + + + + + Verify User Who Owns gshadow File + + Oracle Linux 9 + + + This test makes sure that /etc/gshadow is owned by 0. + + + + + + + + Verify User Who Owns /etc/ipsec.conf File + + Oracle Linux 9 + + + This test makes sure that /etc/ipsec.conf is owned by 0. + + + + + + + + Verify User Who Owns /etc/ipsec.secrets File + + Oracle Linux 9 + + + This test makes sure that /etc/ipsec.secrets is owned by 0. + + + + + + + + Verify ownership of System Login Banner for Remote Connections + + Oracle Linux 9 + + + This test makes sure that /etc/issue.net is owned by 0. + + + + + + + + Verify User Who Owns passwd File + + Oracle Linux 9 + + + This test makes sure that /etc/passwd is owned by 0. + + + + + + + + Verify User Who Owns /etc/sestatus.conf File + + Oracle Linux 9 + + + This test makes sure that /etc/sestatus.conf is owned by 0. + + + + + + + + Verify User Who Owns shadow File + + Oracle Linux 9 + + + This test makes sure that /etc/shadow is owned by 0. + + + + + + + + Verify Who Owns /etc/shells File + + Oracle Linux 9 + + + This test makes sure that /etc/shells is owned by 0. + + + + + + + + Verify User Who Owns /etc/sudoers File + + Oracle Linux 9 + + + This test makes sure that /etc/sudoers is owned by 0. + + + + + + + + Verify /boot/grub2/grub.cfg User Ownership + + Oracle Linux 9 + + + This test makes sure that /boot/grub2/grub.cfg is owned by 0. + + + + + + + + Verify Owner on SSH Server config file + + Oracle Linux 9 + + + This test makes sure that /etc/ssh/sshd_config is owned by 0. + + + + + + + + Verify User Who Owns System.map Files + + Oracle Linux 9 + + + This test makes sure that /boot/ is owned by 0. + + + + + + + + Verify /boot/grub2/user.cfg User Ownership + + Oracle Linux 9 + + + This test makes sure that /boot/grub2/user.cfg is owned by 0. + + + + + + + + Verify User Who Owns /var/log Directory + + Oracle Linux 9 + + + This test makes sure that /var/log/ is owned by 0. + + + + + + + + Verify User Who Owns /var/log/messages File + + Oracle Linux 9 + + + This test makes sure that /var/log/messages is owned by 0. + + + + + + + + Verify User Who Owns /var/log/syslog File + + Oracle Linux 9 + + + This test makes sure that /var/log/syslog is owned by 104. + + + + + + + + Audit Configuration Files Must Be Owned By Root + + Oracle Linux 9 + + + This test makes sure that /etc/audit/, /etc/audit/rules.d/ is owned by 0. + + + + + + + + + Verify that Shared Library Files Have Root Ownership + + Oracle Linux 9 + + + This test makes sure that /lib/, /lib64/, /usr/lib/, /usr/lib64/ is owned by 0. + + + + + + + + + + + Verify Ownership on SSH Server Private *_key Key Files + + Oracle Linux 9 + + + This test makes sure that /etc/ssh/ is owned by 0. + + + + + + + + Verify Ownership on SSH Server Public *.pub Key Files + + Oracle Linux 9 + + + This test makes sure that /etc/ssh/ is owned by 0. + + + + + + + + Verify Permissions on /etc/at.allow file + + Oracle Linux 9 + + + This test makes sure that /etc/at.allow has mode 0640. If the target file or directory has an extended ACL, then it will fail the mode check. - - - - - - - - - - Verify Permissions on cron.daily - - Oracle Linux 9 - - This test makes sure that /etc/cron.daily/ has mode 0700. + + + + + + + + + Audit Configuration Files Permissions are 640 or More Restrictive + + Oracle Linux 9 + + + This test makes sure that /etc/audit/, /etc/audit/rules.d/ has mode 0640. If the target file or directory has an extended ACL, then it will fail the mode check. - - - - - - - - - - Verify Permissions on cron.hourly - - Oracle Linux 9 - - This test makes sure that /etc/cron.hourly/ has mode 0700. + + + + + + + + + + Verify Permissions on Backup group File + + Oracle Linux 9 + + + This test makes sure that /etc/group- has mode 0644. If the target file or directory has an extended ACL, then it will fail the mode check. - - - - - - - - - - Verify Permissions on cron.monthly - - Oracle Linux 9 - - This test makes sure that /etc/cron.monthly/ has mode 0700. + + + + + + + + + Verify Permissions on Backup gshadow File + + Oracle Linux 9 + + + This test makes sure that /etc/gshadow- has mode 0000. If the target file or directory has an extended ACL, then it will fail the mode check. - - - - - - - - - - Verify Permissions on cron.weekly - - Oracle Linux 9 - - This test makes sure that /etc/cron.weekly/ has mode 0700. + + + + + + + + + Verify Permissions on Backup passwd File + + Oracle Linux 9 + + + This test makes sure that /etc/passwd- has mode 0644. If the target file or directory has an extended ACL, then it will fail the mode check. - - - - - - - - - - Verify Permissions on crontab - - Oracle Linux 9 - - This test makes sure that /etc/crontab has mode 0600. + + + + + + + + + Verify Permissions on Backup shadow File + + Oracle Linux 9 + + + This test makes sure that /etc/shadow- has mode 0000. If the target file or directory has an extended ACL, then it will fail the mode check. - - - - - - - - - - Verify Permissions on /etc/audit/auditd.conf - - Oracle Linux 9 - - This test makes sure that /etc/audit/auditd.conf has mode 0640. + + + + + + + + + Verify Permissions on /etc/cron.allow file + + Oracle Linux 9 + + + This test makes sure that /etc/cron.allow has mode 0640. If the target file or directory has an extended ACL, then it will fail the mode check. - - - - - - - - - - Verify Permissions on /etc/audit/rules.d/*.rules - - Oracle Linux 9 - - This test makes sure that /etc/audit/rules.d/ has mode 0640. + + + + + + + + + Verify Permissions on cron.d + + Oracle Linux 9 + + + This test makes sure that /etc/cron.d/ has mode 0700. If the target file or directory has an extended ACL, then it will fail the mode check. - - - - - - - - - - Verify Permissions on group File - - Oracle Linux 9 - - This test makes sure that /etc/group has mode 0644. + + + + + + + + + Verify Permissions on cron.daily + + Oracle Linux 9 + + + This test makes sure that /etc/cron.daily/ has mode 0700. If the target file or directory has an extended ACL, then it will fail the mode check. - - - - - - - - - - Verify Permissions on gshadow File - - Oracle Linux 9 - - This test makes sure that /etc/gshadow has mode 0000. + + + + + + + + + Verify Permissions on cron.hourly + + Oracle Linux 9 + + + This test makes sure that /etc/cron.hourly/ has mode 0700. If the target file or directory has an extended ACL, then it will fail the mode check. - - - - - - - - - - Verify Permissions on passwd File - - Oracle Linux 9 - - This test makes sure that /etc/passwd has mode 0644. + + + + + + + + + Verify Permissions on cron.monthly + + Oracle Linux 9 + + + This test makes sure that /etc/cron.monthly/ has mode 0700. If the target file or directory has an extended ACL, then it will fail the mode check. - - - - - - - - - - Verify Permissions on shadow File - - Oracle Linux 9 - - This test makes sure that /etc/shadow has mode 0000. + + + + + + + + + Verify Permissions on cron.weekly + + Oracle Linux 9 + + + This test makes sure that /etc/cron.weekly/ has mode 0700. If the target file or directory has an extended ACL, then it will fail the mode check. - - - - - - - - - - Verify that Shared Library Files Have Restrictive Permissions - - Oracle Linux 9 - - This test makes sure that /lib/, /lib64/, /usr/lib/, /usr/lib64/ has mode 7755. + + + + + + + + + Verify Permissions on crontab + + Oracle Linux 9 + + + This test makes sure that /etc/crontab has mode 0600. If the target file or directory has an extended ACL, then it will fail the mode check. - - - - - - - - - - - - - Verify Permissions on SSH Server config file - - Oracle Linux 9 - - This test makes sure that /etc/ssh/sshd_config has mode 0600. + + + + + + + + + Verify the UEFI Boot Loader grub.cfg Permissions + + Oracle Linux 9 + + + This test makes sure that /boot/grub2/grub.cfg has mode 0700. If the target file or directory has an extended ACL, then it will fail the mode check. - - - - - - - - - - Verify Permissions on SSH Server Public *.pub Key Files - - Oracle Linux 9 - - This test makes sure that /etc/ssh/ has mode 0644. + + + + + + + + + Verify /boot/grub2/user.cfg Permissions + + Oracle Linux 9 + + + This test makes sure that /boot/grub2/user.cfg has mode 0700. If the target file or directory has an extended ACL, then it will fail the mode check. - - - - - - - - - - Verify Permissions on /var/log Directory - - Oracle Linux 9 - - This test makes sure that /var/log/ has mode 0755. + + + + + + + + + Verify Permissions on /etc/audit/auditd.conf + + Oracle Linux 9 + + + This test makes sure that /etc/audit/auditd.conf has mode 0640. If the target file or directory has an extended ACL, then it will fail the mode check. - - - - - - - - - - Verify Permissions on /var/log/messages File - - Oracle Linux 9 - - This test makes sure that /var/log/messages has mode 0640. + + + + + + + + + Verify Permissions on /etc/audit/rules.d/*.rules + + Oracle Linux 9 + + + This test makes sure that /etc/audit/rules.d/ has mode 0600. If the target file or directory has an extended ACL, then it will fail the mode check. - - - - - - - - - - Verify Permissions on /var/log/syslog File - - Oracle Linux 9 - - This test makes sure that /var/log/syslog has mode 0640. + + + + + + + + + Verify Permissions On /etc/chrony.keys File + + Oracle Linux 9 + + + This test makes sure that /etc/chrony.keys has mode 0640. If the target file or directory has an extended ACL, then it will fail the mode check. - - - - - - - - - - Configure Firewalld to Use the Nftables Backend - - Oracle Linux 9 - - Ensure 'FirewallBackend' is configured with value 'nftables' in /etc/firewalld/firewalld.conf - - - - - - - - - Enable Auditing for Processes Which Start Prior to the Audit Daemon - - Oracle Linux 9 - - Ensure audit=1 is configured in the kernel line in /etc/default/grub. - - - - - - - - - - - - - - - - Extend Audit Backlog Limit for the Audit Daemon - - Oracle Linux 9 - - Ensure audit_backlog_limit=8192 is configured in the kernel line in /etc/default/grub. - - - - - - - - - - - - - - - - IOMMU configuration directive - - Oracle Linux 9 - - Ensure iommu=force is configured in the kernel line in /etc/default/grub. - - - - - - - - - - - - - - - - Configure kernel to zero out memory before allocation - - Oracle Linux 9 - - Ensure init_on_alloc=1 is configured in the kernel line in /etc/default/grub. - - - - - - - - - - - - - - - - Configure L1 Terminal Fault mitigations - - Oracle Linux 9 - - Ensure l1tf is configured in the kernel line in /etc/default/grub. - - - - - - - - - - - - - - - - Force kernel panic on uncorrected MCEs - - Oracle Linux 9 - - Ensure mce=0 is configured in the kernel line in /etc/default/grub. - - - - - - - - - - - - - - - - Ensure SMAP is not disabled during boot - - Oracle Linux 9 - - Ensure nosmap is not set in the kernel line in /etc/default/grub. - - - - - - - - - - - - - - - - Ensure SMEP is not disabled during boot - - Oracle Linux 9 - - Ensure nosmep is not set in the kernel line in /etc/default/grub. - - - - - - - - - - - - - - - - Enable randomization of the page allocator - - Oracle Linux 9 - - Ensure page_alloc.shuffle=1 is configured in the kernel line in /etc/default/grub. - - - - - - - - - - - - - - - - Enable page allocator poisoning - - Oracle Linux 9 - - Ensure page_poison=1 is configured in the kernel line in /etc/default/grub. - - - - - - - - - - - - - - - - Enable Kernel Page-Table Isolation (KPTI) - - Oracle Linux 9 - - Ensure pti=on is configured in the kernel line in /etc/default/grub. - - - - - - - - - - - - - - - - Configure the confidence in TPM for entropy - - Oracle Linux 9 - - Ensure rng_core.default_quality is configured in the kernel line in /etc/default/grub. - - - - - - - - - - - - - - - - Disable merging of slabs with similar size - - Oracle Linux 9 - - Ensure slab_nomerge=yes is configured in the kernel line in /etc/default/grub. - - - - - - - - - - - - - - - - Enable SLUB/SLAB allocator poisoning - - Oracle Linux 9 - - Ensure slub_debug is configured in the kernel line in /etc/default/grub. - - - - - - - - - - - - - - - - Configure Speculative Store Bypass Mitigation - - Oracle Linux 9 - - Ensure spec_store_bypass_disable is configured in the kernel line in /etc/default/grub. - - - - - - - - - - - - - - - - Enforce Spectre v2 mitigation - - Oracle Linux 9 - - Ensure spectre_v2=on is configured in the kernel line in /etc/default/grub. - - - - - - - - - - - - - - - - Ensure debug-shell service is not enabled during boot - - Oracle Linux 9 - - Ensure systemd.debug-shell is not set in the kernel line in /etc/default/grub. - - - - - - - - - - - - - - - - Disable vsyscalls - - Oracle Linux 9 - - Ensure vsyscall=none is configured in the kernel line in /etc/default/grub. - - - - - - - - - - - - - - - - Install Smart Card Packages For Multifactor Authentication - - Oracle Linux 9 - - The RPM package openssl-pkcs11 should be installed. - - - - - - - - - Do not allow ACPI methods to be inserted/replaced at run time - - Oracle Linux 9 - - The kernel CONFIG_ACPI_CUSTOM_METHOD should have value n - - - - - - - - - - - - - Disable kernel support for MISC binaries - - Oracle Linux 9 - - The kernel CONFIG_BINFMT_MISC should have value n - - - - - - - - - - - - - Enable support for BUG() - - Oracle Linux 9 - - The kernel CONFIG_BUG should have value y - - - - - - - - - - - - Disable compatibility with brk() - - Oracle Linux 9 - - The kernel CONFIG_COMPAT_BRK should have value n - - - - - - - - - - - - - Disable the 32-bit vDSO - - Oracle Linux 9 - - The kernel CONFIG_COMPAT_VDSO should have value n - - - - - - - - - - - - - Enable checks on credential management - - Oracle Linux 9 - - The kernel CONFIG_DEBUG_CREDENTIALS should have value y - - - - - - - - - - - - Disable kernel debugfs - - Oracle Linux 9 - - The kernel CONFIG_DEBUG_FS should have value n - - - - - - - - - - - - - Enable checks on linked list manipulation - - Oracle Linux 9 - - The kernel CONFIG_DEBUG_LIST should have value y - - - - - - - - - - - - Enable checks on notifier call chains - - Oracle Linux 9 - - The kernel CONFIG_DEBUG_NOTIFIERS should have value y - - - - - - - - - - - - Enable checks on scatter-gather (SG) table operations - - Oracle Linux 9 - - The kernel CONFIG_DEBUG_SG should have value y - - - - - - - - - - - - Configure low address space to protect from user allocation - - Oracle Linux 9 - - The kernel CONFIG_DEFAULT_MMAP_MIN_ADDR should have value 65536 - - - - - - - - - - - - Disable /dev/kmem virtual device support - - Oracle Linux 9 - - The kernel CONFIG_DEVKMEM should have value n - - - - - - - - - - - - - Disable hibernation - - Oracle Linux 9 - - The kernel CONFIG_HIBERNATION should have value n - - - - - - - - - - - - - Disable IA32 emulation - - Oracle Linux 9 - - The kernel CONFIG_IA32_EMULATION should have value n - - - - - - - - - - - - - Disable the IPv6 protocol - - Oracle Linux 9 - - The kernel CONFIG_IPV6 should have value n - - - - - - - - - - - - - Disable kexec system call - - Oracle Linux 9 - - The kernel CONFIG_KEXEC should have value n - - - - - - - - - - - - - Disable legacy (BSD) PTY support - - Oracle Linux 9 - - The kernel CONFIG_LEGACY_PTYS should have value n - - - - - - - - - - - - - Enable module signature verification - - Oracle Linux 9 - - The kernel CONFIG_MODULE_SIG should have value y - - - - - - - - - - - - Enable automatic signing of all modules - - Oracle Linux 9 - - The kernel CONFIG_MODULE_SIG_ALL should have value y - - - - - - - - - - - - Require modules to be validly signed - - Oracle Linux 9 - - The kernel CONFIG_MODULE_SIG_FORCE should have value y - - - - - - - - - - - - Specify the hash to use when signing modules - - Oracle Linux 9 - - The kernel CONFIG_MODULE_SIG_HASH should have value according to var_kernel_config_module_sig_hash - - - - - - - - - - - - Specify module signing key to use - - Oracle Linux 9 - - The kernel CONFIG_MODULE_SIG_KEY should have value according to var_kernel_config_module_sig_key - - - - - - - - - - - - Sign kernel modules with SHA-512 - - Oracle Linux 9 - - The kernel CONFIG_MODULE_SIG_SHA512 should have value y - - - - - - - - - - - - Enable poison without sanity check - - Oracle Linux 9 - - The kernel CONFIG_PAGE_POISONING_NO_SANITY should have value y - - - - - - - - - - - - Use zero for poisoning instead of debugging value - - Oracle Linux 9 - - The kernel CONFIG_PAGE_POISONING_ZERO should have value y - - - - - - - - - - - - Remove the kernel mapping in user mode - - Oracle Linux 9 - - The kernel CONFIG_PAGE_TABLE_ISOLATION should have value y - - - - - - - - - - - - Kernel panic oops - - Oracle Linux 9 - - The kernel CONFIG_PANIC_ON_OOPS should have value y - - - - - - - - - - - - Kernel panic timeout - - Oracle Linux 9 - - The kernel CONFIG_PANIC_TIMEOUT should have value according to var_kernel_config_panic_timeout - - - - - - - - - - - - Disable support for /proc/kkcore - - Oracle Linux 9 - - The kernel CONFIG_PROC_KCORE should have value n - - - - - - - - - - - - - Randomize the address of the kernel image (KASLR) - - Oracle Linux 9 - - The kernel CONFIG_RANDOMIZE_BASE should have value y - - - - - - - - - - - - Randomize the kernel memory sections - - Oracle Linux 9 - - The kernel CONFIG_RANDOMIZE_MEMORY should have value y - - - - - - - - - - - - Avoid speculative indirect branches in kernel - - Oracle Linux 9 - - The kernel CONFIG_RETPOLINE should have value y - - - - - - - - - - - - Enable seccomp to safely compute untrusted bytecode - - Oracle Linux 9 - - The kernel CONFIG_SECCOMP should have value y - - - - - - - - - - - - Enable use of Berkeley Packet Filter with seccomp - - Oracle Linux 9 - - The kernel CONFIG_SECCOMP_FILTER should have value y - - - - - - - - - - - - Enable different security models - - Oracle Linux 9 - - The kernel CONFIG_SECURITY should have value y - - - - - - - - - - - - Restrict unprivileged access to the kernel syslog - - Oracle Linux 9 - - The kernel CONFIG_SECURITY_DMESG_RESTRICT should have value n - - - - - - - - - - - - - Disable mutable hooks - - Oracle Linux 9 - - The kernel CONFIG_SECURITY_WRITABLE_HOOKS should have value y - - - - - - - - - - - - Enable Yama support - - Oracle Linux 9 - - The kernel CONFIG_SECURITY_YAMA should have value y - - - - - - - - - - - - Enable SLUB debugging support - - Oracle Linux 9 - - The kernel CONFIG_SLUB_DEBUG should have value y - - - - - - - - - - - - Enable TCP/IP syncookie support - - Oracle Linux 9 - - The kernel CONFIG_SYN_COOKIES should have value y - - - - - - - - - - - - Unmap kernel when running in userspace (aka KAISER) - - Oracle Linux 9 - - The kernel CONFIG_UNMAP_KERNEL_AT_EL0 should have value y - - - - - - - - - - - - Disable x86 vsyscall emulation - - Oracle Linux 9 - - The kernel CONFIG_X86_VSYSCALL_EMULATION should have value n - - - - - - - - - - - - - Disable ATM Support - - Oracle Linux 9 - - The kernel module atm should be disabled. - - - - - - - - - - - - Disable Bluetooth Kernel Module - - Oracle Linux 9 - - The kernel module bluetooth should be disabled. - - - - - - - - - - - - Disable CAN Support - - Oracle Linux 9 - - The kernel module can should be disabled. - - - - - - - - - - - - Disable Mounting of cramfs - - Oracle Linux 9 - - The kernel module cramfs should be disabled. - - - - - - - - - - - - Disable IEEE 1394 (FireWire) Support - - Oracle Linux 9 - - The kernel module firewire-core should be disabled. - - - - - - - - - - - - Disable RDS Support - - Oracle Linux 9 - - The kernel module rds should be disabled. - - - - - - - - - - - - Disable SCTP Support - - Oracle Linux 9 - - The kernel module sctp should be disabled. - - - - - - - - - - - - Disable TIPC Support - - Oracle Linux 9 - - The kernel module tipc should be disabled. - - - - - - - - - - - - Disable Modprobe Loading of USB Storage Driver - - Oracle Linux 9 - - The kernel module usb-storage should be disabled. - - - - - - - - - - - - Disable the uvcvideo module - - Oracle Linux 9 - - The kernel module uvcvideo should be disabled. - - - - - - - - - - - - Add nodev Option to /boot - - Oracle Linux 9 - - /boot should be mounted with mount option nodev. - - - - - - - - - - - - - - - - Add noexec Option to /boot - - Oracle Linux 9 - - /boot should be mounted with mount option noexec. - - - - - - - - - - - - - - - - Add nosuid Option to /boot - - Oracle Linux 9 - - /boot should be mounted with mount option nosuid. - - - - - - - - - - - - - - - - Add nodev Option to /dev/shm - - Oracle Linux 9 - - /dev/shm should be mounted with mount option nodev. - - - - - - - - - - - - - - - Add noexec Option to /dev/shm - - Oracle Linux 9 - - /dev/shm should be mounted with mount option noexec. - - - - - - - - - - - - - - - Add nosuid Option to /dev/shm - - Oracle Linux 9 - - /dev/shm should be mounted with mount option nosuid. - - - - - - - - - - - - - - - Add grpquota Option to /home - - Oracle Linux 9 - - Home mount points should be mounted with mount option grpquota. - - - - - - - - - Add nodev Option to /home - - Oracle Linux 9 - - /home should be mounted with mount option nodev. - - - - - - - - - - - - - - - - Add noexec Option to /home - - Oracle Linux 9 - - Home mount points should be mounted with mount option noexec. - - - - - - - - - Add nosuid Option to /home - - Oracle Linux 9 - - Home mount points should be mounted with mount option nosuid. - - - - - - - - - Add usrquota Option to /home - - Oracle Linux 9 - - Home mount points should be mounted with mount option usrquota. - - - - - - - - - Mount Remote Filesystems with Kerberos Security - - Oracle Linux 9 - - The sec_krb5_krb5i_krb5p option should be enabled for all NFS mounts in /etc/fstab. - - - - - - - - - - Mount Remote Filesystems with nodev - - Oracle Linux 9 - - The nodev option should be enabled for all NFS mounts in /etc/fstab. - - - - - - - - - - Add nodev Option to Removable Media Partitions - - Oracle Linux 9 - - The nodev option should be enabled for all removable devices mounts in /etc/fstab. - - - - - - - - - - - - - - - - - Mount Remote Filesystems with noexec - - Oracle Linux 9 - - The noexec option should be enabled for all NFS mounts in /etc/fstab. - - - - - - - - - - Add noexec Option to Removable Media Partitions - - Oracle Linux 9 - - The noexec option should be enabled for all removable devices mounts in /etc/fstab. - - - - - - - - - - - - - - - - - Mount Remote Filesystems with nosuid - - Oracle Linux 9 - - The nosuid option should be enabled for all NFS mounts in /etc/fstab. - - - - - - - - - - Add nosuid Option to Removable Media Partitions - - Oracle Linux 9 - - The nosuid option should be enabled for all removable devices mounts in /etc/fstab. - - - - - - - - - - - - - - - - - Add nosuid Option to /opt - - Oracle Linux 9 - - /opt should be mounted with mount option nosuid. - - - - - - - - - - - - - - - - Add nosuid Option to /srv - - Oracle Linux 9 - - /srv should be mounted with mount option nosuid. - - - - - - - - - - - - - - - - Add nodev Option to /tmp - - Oracle Linux 9 - - /tmp should be mounted with mount option nodev. - - - - - - - - - - - - - - - - Add noexec Option to /tmp - - Oracle Linux 9 - - /tmp should be mounted with mount option noexec. - - - - - - - - - - - - - - - - Add nosuid Option to /tmp - - Oracle Linux 9 - - /tmp should be mounted with mount option nosuid. - - - - - - - - - - - - - - - - Add nodev Option to /var/log/audit - - Oracle Linux 9 - - /var/log/audit should be mounted with mount option nodev. - - - - - - - - - - - - - - - - Add noexec Option to /var/log/audit - - Oracle Linux 9 - - /var/log/audit should be mounted with mount option noexec. - - - - - - - - - - - - - - - - Add nosuid Option to /var/log/audit - - Oracle Linux 9 - - /var/log/audit should be mounted with mount option nosuid. - - - - - - - - - - - - - - - - Add nodev Option to /var/log - - Oracle Linux 9 - - /var/log should be mounted with mount option nodev. - - - - - - - - - - - - - - - - Add noexec Option to /var/log - - Oracle Linux 9 - - /var/log should be mounted with mount option noexec. - - - - - - - - - - - - - - - - Add nosuid Option to /var/log - - Oracle Linux 9 - - /var/log should be mounted with mount option nosuid. - - - - - - - - - - - - - - - - Add nodev Option to /var - - Oracle Linux 9 - - /var should be mounted with mount option nodev. - - - - - - - - - - - - - - - - Add noexec Option to /var - - Oracle Linux 9 - - /var should be mounted with mount option noexec. - - - - - - - - - - - - - - - - Add nosuid Option to /var - - Oracle Linux 9 - - /var should be mounted with mount option nosuid. - - - - - - - - - - - - - - - - Add nodev Option to /var/tmp - - Oracle Linux 9 - - /var/tmp should be mounted with mount option nodev. - - - - - - - - - - - - - - - - Add noexec Option to /var/tmp - - Oracle Linux 9 - - /var/tmp should be mounted with mount option noexec. - - - - - - - - - - - - - - - - Add nosuid Option to /var/tmp - - Oracle Linux 9 - - /var/tmp should be mounted with mount option nosuid. - - - - - - - - - - - - - - - - package_GConf2_installed - - Oracle Linux 9 - - The RPM package GConf2 should be installed. - - - - - - - - - Install the Host Intrusion Prevention System (HIPS) Module - - Oracle Linux 9 - - The RPM package MFEhiplsm should be installed. - - - - - - - - - Install AIDE - - Oracle Linux 9 - - The RPM package aide should be installed. - - - - - - - - - Install audispd-plugins Package - - Oracle Linux 9 - - The RPM package audispd-plugins should be installed. - - - - - - - - - Ensure the default plugins for the audit dispatcher are Installed - - Oracle Linux 9 - - The RPM package audit-audispd-plugins should be installed. - - - - - - - - - Ensure the audit Subsystem is Installed - - Oracle Linux 9 - - The RPM package audit should be installed. - - - - - - - - - package_avahi_installed - - Oracle Linux 9 - - The RPM package avahi should be installed. - - - - - - - - - Uninstall bind Package - - Oracle Linux 9 - - The RPM package bind should be removed. - - - - - - - - - The Chrony package is installed - - Oracle Linux 9 - - The RPM package chrony should be installed. - - - - - - - - - Install the cron service - - Oracle Linux 9 - - The RPM package cron should be installed. - - - - - - - - - Install crypto-policies package - - Oracle Linux 9 - - The RPM package crypto-policies should be installed. - - - - - - - - - package_dconf_installed - - Oracle Linux 9 - - The RPM package dconf should be installed. - - - - - - - - - Uninstall DHCP Server Package - - Oracle Linux 9 - - The RPM package dhcp should be removed. - - - - - - - - - Install dnf-automatic Package - - Oracle Linux 9 - - The RPM package dnf-automatic should be installed. - - - - - - - - - package_esc_installed - - Oracle Linux 9 - - The RPM package esc should be installed. - - - - - - - - - Install fapolicyd Package - - Oracle Linux 9 - - The RPM package fapolicyd should be installed. - - - - - - - - - Install firewalld Package - - Oracle Linux 9 - - The RPM package firewalld should be installed. - - - - - - - - - package_gdm_installed - - Oracle Linux 9 - - The RPM package gdm should be installed. - - - - - - - - - Ensure gnutls-utils is installed - - Oracle Linux 9 - - The RPM package gnutls-utils should be installed. - - - - - - - - - Uninstall gssproxy Package - - Oracle Linux 9 - - The RPM package gssproxy should be removed. - - - - - - - - - Uninstall the inet-based telnet server - - Oracle Linux 9 - - The RPM package inetutils-telnetd should be removed. - - - - - - - - - Uninstall iprutils Package - - Oracle Linux 9 - - The RPM package iprutils should be removed. - - - - - - - - - Uninstall krb5-workstation Package - - Oracle Linux 9 - - The RPM package krb5-workstation should be removed. - - - - - - - - - Install libreswan Package - - Oracle Linux 9 - - The RPM package libreswan should be installed. - - - - - - - - - Ensure logrotate is Installed - - Oracle Linux 9 - - The RPM package logrotate should be installed. - - - - - - - - - Install McAfee Endpoint Security for Linux (ENSL) - - Oracle Linux 9 - - The RPM package McAfeeTP should be installed. - - - - - - - - - Uninstall nfs-utils Package - - Oracle Linux 9 - - The RPM package nfs-utils should be removed. - - - - - - - - - Uninstall the nis package - - Oracle Linux 9 - - The RPM package nis should be removed. - - - - - - - - - Ensure nss-tools is installed - - Oracle Linux 9 - - The RPM package nss-tools should be installed. - - - - - - - - - Install the ntp service - - Oracle Linux 9 - - The RPM package ntp should be installed. - - - - - - - - - Uninstall the ntpdate package - - Oracle Linux 9 - - The RPM package ntpdate should be removed. - - - - - - - - - Install the opensc Package For Multifactor Authentication - - Oracle Linux 9 - - The RPM package opensc should be installed. - - - - - - - - - Install openscap-scanner Package - - Oracle Linux 9 - - The RPM package openscap-scanner should be installed. - - - - - - - - - Install OpenSSH client software - - Oracle Linux 9 - - The RPM package openssh-clients should be installed. - - - - - - - - - Install the OpenSSH Server Package - - Oracle Linux 9 - - The RPM package openssh-server should be installed. - - - - - - - - - Remove the OpenSSH Server Package - - Oracle Linux 9 - - The RPM package openssh-server should be removed. - - - - - - - - - package_pam_ldap_removed - - Oracle Linux 9 - - The RPM package pam_ldap should be removed. - - - - - - - - - Install the pcsc-lite package - - Oracle Linux 9 - - The RPM package pcsc-lite should be installed. - - - - - - - - - Install policycoreutils-python-utils package - - Oracle Linux 9 - - The RPM package policycoreutils-python-utils should be installed. - - - - - - - - - Install policycoreutils Package - - Oracle Linux 9 - - The RPM package policycoreutils should be installed. - - - - - - - - - The Postfix package is installed - - Oracle Linux 9 - - The RPM package postfix should be installed. - - - - - - - - - package_prelink_removed - - Oracle Linux 9 - - The RPM package prelink should be removed. - - - - - - - - - Uninstall quagga Package - - Oracle Linux 9 - - The RPM package quagga should be removed. - - - - - - - - - Install rear Package - - Oracle Linux 9 - - The RPM package rear should be installed. - - - - - - - - - Install rng-tools Package - - Oracle Linux 9 - - The RPM package rng-tools should be installed. - - - - - - - - - Uninstall rsh-server Package - - Oracle Linux 9 - - The RPM package rsh-server should be removed. - - - - - - - - - Uninstall rsh Package - - Oracle Linux 9 - - The RPM package rsh should be removed. - - - - - - - - - Ensure rsyslog-gnutls is installed - - Oracle Linux 9 - - The RPM package rsyslog-gnutls should be installed. - - - - - - - - - Ensure rsyslog is Installed - - Oracle Linux 9 - - The RPM package rsyslog should be installed. - - - - - - - - - package_samba-common_removed - - Oracle Linux 9 - - The RPM package samba-common should be removed. - - - - - - - - - Install scap-security-guide Package - - Oracle Linux 9 - - The RPM package scap-security-guide should be installed. - - - - - - - - - Uninstall Sendmail Package - - Oracle Linux 9 - - The RPM package sendmail should be removed. - - - - - - - - - Uninstall setroubleshoot-plugins Package - - Oracle Linux 9 - - The RPM package setroubleshoot-plugins should be removed. - - - - - - - - - Uninstall setroubleshoot-server Package - - Oracle Linux 9 - - The RPM package setroubleshoot-server should be removed. - - - - - - - - - Uninstall setroubleshoot Package - - Oracle Linux 9 - - The RPM package setroubleshoot should be removed. - - - - - - - - - Uninstall squid Package - - Oracle Linux 9 - - The RPM package squid should be removed. - - - - - - - - - Install sudo Package - - Oracle Linux 9 - - The RPM package sudo should be installed. - - - - - - - - - Ensure syslog-ng is Installed - - Oracle Linux 9 - - The RPM package syslog-ng should be installed. - - - - - - - - - Uninstall talk-server Package - - Oracle Linux 9 - - The RPM package talk-server should be removed. - - - - - - - - - Uninstall talk Package - - Oracle Linux 9 - - The RPM package talk should be removed. - - - - - - - - - Uninstall telnet-server Package - - Oracle Linux 9 - - The RPM package telnet-server should be removed. - - - - - - - - - Remove telnet Clients - - Oracle Linux 9 - - The RPM package telnet should be removed. - - - - - - - - - Uninstall the ssl compliant telnet server - - Oracle Linux 9 - - The RPM package telnetd-ssl should be removed. - - - - - - - - - Uninstall the telnet server - - Oracle Linux 9 - - The RPM package telnetd should be removed. - - - - - - - - - Uninstall tftp-server Package - - Oracle Linux 9 - - The RPM package tftp-server should be removed. - - - - - - - - - Remove tftp Daemon - - Oracle Linux 9 - - The RPM package tftp should be removed. - - - - - - - - - Install the tmux Package - - Oracle Linux 9 - - The RPM package tmux should be installed. - - - - - - - - - Uninstall tuned Package - - Oracle Linux 9 - - The RPM package tuned should be removed. - - - - - - - - - Install usbguard Package - - Oracle Linux 9 - - The RPM package usbguard should be installed. - - - - - - - - - Uninstall vsftpd Package - - Oracle Linux 9 - - The RPM package vsftpd should be removed. - - - - - - - - - Uninstall xinetd Package - - Oracle Linux 9 - - The RPM package xinetd should be removed. - - - - - - - - - Remove the X Windows Package Group - - Oracle Linux 9 - - The RPM package xorg-x11-server-common should be removed. - - - - - - - - - Ensure /dev/shm is configured - - Oracle Linux 9 - - If stored locally, create a separate partition for + + + + + + + + + Verify Permissions On /etc/crypttab File + + Oracle Linux 9 + + + This test makes sure that /etc/crypttab has mode 0600. + If the target file or directory has an extended ACL, then it will fail the mode check. + + + + + + + + + Verify Permissions on group File + + Oracle Linux 9 + + + This test makes sure that /etc/group has mode 0644. + If the target file or directory has an extended ACL, then it will fail the mode check. + + + + + + + + + Verify Permissions on gshadow File + + Oracle Linux 9 + + + This test makes sure that /etc/gshadow has mode 0000. + If the target file or directory has an extended ACL, then it will fail the mode check. + + + + + + + + + Verify Permissions On /etc/ipsec.conf File + + Oracle Linux 9 + + + This test makes sure that /etc/ipsec.conf has mode 0644. + If the target file or directory has an extended ACL, then it will fail the mode check. + + + + + + + + + Verify Permissions On /etc/ipsec.secrets File + + Oracle Linux 9 + + + This test makes sure that /etc/ipsec.secrets has mode 0644. + If the target file or directory has an extended ACL, then it will fail the mode check. + + + + + + + + + Verify permissions on System Login Banner for Remote Connections + + Oracle Linux 9 + + + This test makes sure that /etc/issue.net has mode 0644. + If the target file or directory has an extended ACL, then it will fail the mode check. + + + + + + + + + Verify Permissions on passwd File + + Oracle Linux 9 + + + This test makes sure that /etc/passwd has mode 0644. + If the target file or directory has an extended ACL, then it will fail the mode check. + + + + + + + + + Verify Permissions On /etc/sestatus.conf File + + Oracle Linux 9 + + + This test makes sure that /etc/sestatus.conf has mode 0644. + If the target file or directory has an extended ACL, then it will fail the mode check. + + + + + + + + + Verify Permissions on shadow File + + Oracle Linux 9 + + + This test makes sure that /etc/shadow has mode 0000. + If the target file or directory has an extended ACL, then it will fail the mode check. + + + + + + + + + Verify Permissions on /etc/shells File + + Oracle Linux 9 + + + This test makes sure that /etc/shells has mode 0644. + If the target file or directory has an extended ACL, then it will fail the mode check. + + + + + + + + + Verify Permissions On /etc/sudoers File + + Oracle Linux 9 + + + This test makes sure that /etc/sudoers has mode 0440. + If the target file or directory has an extended ACL, then it will fail the mode check. + + + + + + + + + Verify /boot/grub2/grub.cfg Permissions + + Oracle Linux 9 + + + This test makes sure that /boot/grub2/grub.cfg has mode 0600. + If the target file or directory has an extended ACL, then it will fail the mode check. + + + + + + + + + Verify that Shared Library Files Have Restrictive Permissions + + Oracle Linux 9 + + + This test makes sure that /lib/, /lib64/, /usr/lib/, /usr/lib64/ has mode 7755. + If the target file or directory has an extended ACL, then it will fail the mode check. + + + + + + + + + + + + Verify Permissions on SSH Server config file + + Oracle Linux 9 + + + This test makes sure that /etc/ssh/sshd_config has mode 0600. + If the target file or directory has an extended ACL, then it will fail the mode check. + + + + + + + + + Verify Permissions on SSH Server Public *.pub Key Files + + Oracle Linux 9 + + + This test makes sure that /etc/ssh/ has mode 0644. + If the target file or directory has an extended ACL, then it will fail the mode check. + + + + + + + + + Ensure That the sudo Binary Has the Correct Permissions + + Oracle Linux 9 + + + This test makes sure that /usr/bin/sudo has mode 4110. + If the target file or directory has an extended ACL, then it will fail the mode check. + + + + + + + + + Verify Permissions on System.map Files + + Oracle Linux 9 + + + This test makes sure that /boot/ has mode 0600. + If the target file or directory has an extended ACL, then it will fail the mode check. + + + + + + + + + Verify /boot/grub2/user.cfg Permissions + + Oracle Linux 9 + + + This test makes sure that /boot/grub2/user.cfg has mode 0600. + If the target file or directory has an extended ACL, then it will fail the mode check. + + + + + + + + + Verify Permissions on /var/log Directory + + Oracle Linux 9 + + + This test makes sure that /var/log/ has mode 0755. + If the target file or directory has an extended ACL, then it will fail the mode check. + + + + + + + + + Verify Permissions on /var/log/messages File + + Oracle Linux 9 + + + This test makes sure that /var/log/messages has mode 0600. + If the target file or directory has an extended ACL, then it will fail the mode check. + + + + + + + + + Verify Permissions on /var/log/syslog File + + Oracle Linux 9 + + + This test makes sure that /var/log/syslog has mode 0640. + If the target file or directory has an extended ACL, then it will fail the mode check. + + + + + + + + + The File /etc/ssh/sshd_config.d/50-redhat.conf Must Exist + + Oracle Linux 9 + + + This test makes sure that/etc/ssh/sshd_config.d/50-redhat.conf does exist. + + + + + + + + Configure Firewalld to Use the Nftables Backend + + Oracle Linux 9 + + + Ensure 'FirewallBackend' is configured with value 'nftables' in /etc/firewalld/firewalld.conf + + + + + + + + Enable Auditing for Processes Which Start Prior to the Audit Daemon + + Oracle Linux 9 + + + Ensure audit=1 is configured in the kernel line in /etc/default/grub. + + + + + + + + + + + + + + + + + + + + + Extend Audit Backlog Limit for the Audit Daemon + + Oracle Linux 9 + + + Ensure audit_backlog_limit=8192 is configured in the kernel line in /etc/default/grub. + + + + + + + + + + + + + + + + + + + + + IOMMU configuration directive + + Oracle Linux 9 + + + Ensure iommu=force is configured in the kernel line in /etc/default/grub. + + + + + + + + + + + + + + + + + + + + + Configure kernel to zero out memory before allocation + + Oracle Linux 9 + + + Ensure init_on_alloc=1 is configured in the kernel line in /etc/default/grub. + + + + + + + + + + + + + + + + + + + + + Configure L1 Terminal Fault mitigations + + Oracle Linux 9 + + + Ensure l1tf is configured in the kernel line in /etc/default/grub. + + + + + + + + + + + + + + + + + + + + + Force kernel panic on uncorrected MCEs + + Oracle Linux 9 + + + Ensure mce=0 is configured in the kernel line in /etc/default/grub. + + + + + + + + + + + + + + + + + + + + + Configure Microarchitectural Data Sampling mitigation + + Oracle Linux 9 + + + Ensure mds is configured in the kernel line in /etc/default/grub. + + + + + + + + + + + + + + + + + + + + + Ensure SMAP is not disabled during boot + + Oracle Linux 9 + + + Ensure nosmap is not set in the kernel line in /etc/default/grub. + + + + + + + + + + + + + + + + + Ensure SMEP is not disabled during boot + + Oracle Linux 9 + + + Ensure nosmep is not set in the kernel line in /etc/default/grub. + + + + + + + + + + + + + + + + + Enable randomization of the page allocator + + Oracle Linux 9 + + + Ensure page_alloc.shuffle=1 is configured in the kernel line in /etc/default/grub. + + + + + + + + + + + + + + + + + + + + + Enable page allocator poisoning + + Oracle Linux 9 + + + Ensure page_poison=1 is configured in the kernel line in /etc/default/grub. + + + + + + + + + + + + + + + + + + + + + Enable Kernel Page-Table Isolation (KPTI) + + Oracle Linux 9 + + + Ensure pti=on is configured in the kernel line in /etc/default/grub. + + + + + + + + + + + + + + + + + + + + + Configure the confidence in TPM for entropy + + Oracle Linux 9 + + + Ensure rng_core.default_quality is configured in the kernel line in /etc/default/grub. + + + + + + + + + + + + + + + + + + + + + Disable merging of slabs with similar size + + Oracle Linux 9 + + + Ensure slab_nomerge=yes is configured in the kernel line in /etc/default/grub. + + + + + + + + + + + + + + + + + + + + + Enable SLUB/SLAB allocator poisoning + + Oracle Linux 9 + + + Ensure slub_debug is configured in the kernel line in /etc/default/grub. + + + + + + + + + + + + + + + + + + + + + Configure Speculative Store Bypass Mitigation + + Oracle Linux 9 + + + Ensure spec_store_bypass_disable is configured in the kernel line in /etc/default/grub. + + + + + + + + + + + + + + + + + + + + + Enforce Spectre v2 mitigation + + Oracle Linux 9 + + + Ensure spectre_v2=on is configured in the kernel line in /etc/default/grub. + + + + + + + + + + + + + + + + + + + + + Ensure debug-shell service is not enabled during boot + + Oracle Linux 9 + + + Ensure systemd.debug-shell is not set in the kernel line in /etc/default/grub. + + + + + + + + + + + + + + + + + Disable vsyscalls + + Oracle Linux 9 + + + Ensure vsyscall=none is configured in the kernel line in /etc/default/grub. + + + + + + + + + + + + + + + + + + + + + Install Smart Card Packages For Multifactor Authentication + + Oracle Linux 9 + + + The RPM package openssl-pkcs11 should be installed. + + + + + + + + Do not allow ACPI methods to be inserted/replaced at run time + + Oracle Linux 9 + + + The kernel CONFIG_ACPI_CUSTOM_METHOD should have value n + + + + + + + + + + + + Emulate Privileged Access Never (PAN) + + Oracle Linux 9 + + + The kernel CONFIG_ARM64_SW_TTBR0_PAN should have value y + + + + + + + + + + + Disable kernel support for MISC binaries + + Oracle Linux 9 + + + The kernel CONFIG_BINFMT_MISC should have value n + + + + + + + + + + + + Enable support for BUG() + + Oracle Linux 9 + + + The kernel CONFIG_BUG should have value y + + + + + + + + + + + Trigger a kernel BUG when data corruption is detected + + Oracle Linux 9 + + + The kernel CONFIG_BUG_ON_DATA_CORRUPTION should have value y + + + + + + + + + + + Disable compatibility with brk() + + Oracle Linux 9 + + + The kernel CONFIG_COMPAT_BRK should have value n + + + + + + + + + + + + Disable the 32-bit vDSO + + Oracle Linux 9 + + + The kernel CONFIG_COMPAT_VDSO should have value n + + + + + + + + + + + + Enable checks on credential management + + Oracle Linux 9 + + + The kernel CONFIG_DEBUG_CREDENTIALS should have value y + + + + + + + + + + + Disable kernel debugfs + + Oracle Linux 9 + + + The kernel CONFIG_DEBUG_FS should have value n + + + + + + + + + + + + Enable checks on linked list manipulation + + Oracle Linux 9 + + + The kernel CONFIG_DEBUG_LIST should have value y + + + + + + + + + + + Enable checks on notifier call chains + + Oracle Linux 9 + + + The kernel CONFIG_DEBUG_NOTIFIERS should have value y + + + + + + + + + + + Enable checks on scatter-gather (SG) table operations + + Oracle Linux 9 + + + The kernel CONFIG_DEBUG_SG should have value y + + + + + + + + + + + Warn on W+X mappings found at boot + + Oracle Linux 9 + + + The kernel CONFIG_DEBUG_WX should have value y + + + + + + + + + + + Disable /dev/kmem virtual device support + + Oracle Linux 9 + + + The kernel CONFIG_DEVKMEM should have value n + + + + + + + + + + + + Harden common str/mem functions against buffer overflows + + Oracle Linux 9 + + + The kernel CONFIG_FORTIFY_SOURCE should have value y + + + + + + + + + + + Generate some entropy during boot and runtime + + Oracle Linux 9 + + + The kernel CONFIG_GCC_PLUGIN_LATENT_ENTROPY should have value y + + + + + + + + + + + Randomize layout of sensitive kernel structures + + Oracle Linux 9 + + + The kernel CONFIG_GCC_PLUGIN_RANDSTRUCT should have value y + + + + + + + + + + + Poison kernel stack before returning from syscalls + + Oracle Linux 9 + + + The kernel CONFIG_GCC_PLUGIN_STACKLEAK should have value y + + + + + + + + + + + Force initialization of variables containing userspace addresses + + Oracle Linux 9 + + + The kernel CONFIG_GCC_PLUGIN_STRUCTLEAK should have value y + + + + + + + + + + + zero-init everything passed by reference + + Oracle Linux 9 + + + The kernel CONFIG_GCC_PLUGIN_STRUCTLEAK_BYREF_ALL should have value y + + + + + + + + + + + Harden memory copies between kernel and userspace + + Oracle Linux 9 + + + The kernel CONFIG_HARDENED_USERCOPY should have value y + + + + + + + + + + + Do not allow usercopy whitelist violations to fallback to object size + + Oracle Linux 9 + + + The kernel CONFIG_HARDENED_USERCOPY_FALLBACK should have value n + + + + + + + + + + + + Disable hibernation + + Oracle Linux 9 + + + The kernel CONFIG_HIBERNATION should have value n + + + + + + + + + + + + Disable IA32 emulation + + Oracle Linux 9 + + + The kernel CONFIG_IA32_EMULATION should have value n + + + + + + + + + + + + Disable the IPv6 protocol + + Oracle Linux 9 + + + The kernel CONFIG_IPV6 should have value n + + + + + + + + + + + + Disable kexec system call + + Oracle Linux 9 + + + The kernel CONFIG_KEXEC should have value n + + + + + + + + + + + + Disable legacy (BSD) PTY support + + Oracle Linux 9 + + + The kernel CONFIG_LEGACY_PTYS should have value n + + + + + + + + + + + + Disable vsyscall emulation + + Oracle Linux 9 + + + The kernel CONFIG_LEGACY_VSYSCALL_EMULATE should have value n + + + + + + + + + + + + Disable vsyscall mapping + + Oracle Linux 9 + + + The kernel CONFIG_LEGACY_VSYSCALL_NONE should have value y + + + + + + + + + + + Disable vsyscall emulate execution only + + Oracle Linux 9 + + + The kernel CONFIG_LEGACY_VSYSCALL_XONLY should have value n + + + + + + + + + + + + Disable the LDT (local descriptor table) + + Oracle Linux 9 + + + The kernel CONFIG_MODIFY_LDT_SYSCALL should have value n + + + + + + + + + + + + Enable module signature verification + + Oracle Linux 9 + + + The kernel CONFIG_MODULE_SIG should have value y + + + + + + + + + + + Enable automatic signing of all modules + + Oracle Linux 9 + + + The kernel CONFIG_MODULE_SIG_ALL should have value y + + + + + + + + + + + Require modules to be validly signed + + Oracle Linux 9 + + + The kernel CONFIG_MODULE_SIG_FORCE should have value y + + + + + + + + + + + Specify the hash to use when signing modules + + Oracle Linux 9 + + + The kernel CONFIG_MODULE_SIG_HASH should have value according to var_kernel_config_module_sig_hash + + + + + + + + + + + Specify module signing key to use + + Oracle Linux 9 + + + The kernel CONFIG_MODULE_SIG_KEY should have value according to var_kernel_config_module_sig_key + + + + + + + + + + + Sign kernel modules with SHA-512 + + Oracle Linux 9 + + + The kernel CONFIG_MODULE_SIG_SHA512 should have value y + + + + + + + + + + + Enable poison of pages after freeing + + Oracle Linux 9 + + + The kernel CONFIG_PAGE_POISONING should have value y + + + + + + + + + + + Enable poison without sanity check + + Oracle Linux 9 + + + The kernel CONFIG_PAGE_POISONING_NO_SANITY should have value y + + + + + + + + + + + Use zero for poisoning instead of debugging value + + Oracle Linux 9 + + + The kernel CONFIG_PAGE_POISONING_ZERO should have value y + + + + + + + + + + + Remove the kernel mapping in user mode + + Oracle Linux 9 + + + The kernel CONFIG_PAGE_TABLE_ISOLATION should have value y + + + + + + + + + + + Kernel panic oops + + Oracle Linux 9 + + + The kernel CONFIG_PANIC_ON_OOPS should have value y + + + + + + + + + + + Kernel panic timeout + + Oracle Linux 9 + + + The kernel CONFIG_PANIC_TIMEOUT should have value according to var_kernel_config_panic_timeout + + + + + + + + + + + Disable support for /proc/kkcore + + Oracle Linux 9 + + + The kernel CONFIG_PROC_KCORE should have value n + + + + + + + + + + + + Randomize the address of the kernel image (KASLR) + + Oracle Linux 9 + + + The kernel CONFIG_RANDOMIZE_BASE should have value y + + + + + + + + + + + Randomize the kernel memory sections + + Oracle Linux 9 + + + The kernel CONFIG_RANDOMIZE_MEMORY should have value y + + + + + + + + + + + Perform full reference count validation + + Oracle Linux 9 + + + The kernel CONFIG_REFCOUNT_FULL should have value y + + + + + + + + + + + Avoid speculative indirect branches in kernel + + Oracle Linux 9 + + + The kernel CONFIG_RETPOLINE should have value y + + + + + + + + + + + Detect stack corruption on calls to schedule() + + Oracle Linux 9 + + + The kernel CONFIG_SCHED_STACK_END_CHECK should have value y + + + + + + + + + + + Enable seccomp to safely compute untrusted bytecode + + Oracle Linux 9 + + + The kernel CONFIG_SECCOMP should have value y + + + + + + + + + + + Enable use of Berkeley Packet Filter with seccomp + + Oracle Linux 9 + + + The kernel CONFIG_SECCOMP_FILTER should have value y + + + + + + + + + + + Enable different security models + + Oracle Linux 9 + + + The kernel CONFIG_SECURITY should have value y + + + + + + + + + + + Restrict unprivileged access to the kernel syslog + + Oracle Linux 9 + + + The kernel CONFIG_SECURITY_DMESG_RESTRICT should have value y + + + + + + + + + + + Disable mutable hooks + + Oracle Linux 9 + + + The kernel CONFIG_SECURITY_WRITABLE_HOOKS should have value n + + + + + + + + + + + + Enable Yama support + + Oracle Linux 9 + + + The kernel CONFIG_SECURITY_YAMA should have value y + + + + + + + + + + + Harden slab freelist metadata + + Oracle Linux 9 + + + The kernel CONFIG_SLAB_FREELIST_HARDENED should have value y + + + + + + + + + + + Randomize slab freelist + + Oracle Linux 9 + + + The kernel CONFIG_SLAB_FREELIST_RANDOM should have value y + + + + + + + + + + + Disallow merge of slab caches + + Oracle Linux 9 + + + The kernel CONFIG_SLAB_MERGE_DEFAULT should have value n + + + + + + + + + + + + Enable SLUB debugging support + + Oracle Linux 9 + + + The kernel CONFIG_SLUB_DEBUG should have value y + + + + + + + + + + + Stack Protector buffer overlow detection + + Oracle Linux 9 + + + The kernel CONFIG_STACKPROTECTOR should have value y + + + + + + + + + + + Strong Stack Protector + + Oracle Linux 9 + + + The kernel CONFIG_STACKPROTECTOR_STRONG should have value y + + + + + + + + + + + Make the kernel text and rodata read-only + + Oracle Linux 9 + + + The kernel CONFIG_STRICT_KERNEL_RWX should have value y + + + + + + + + + + + Make the module text and rodata read-only + + Oracle Linux 9 + + + The kernel CONFIG_STRICT_MODULE_RWX should have value y + + + + + + + + + + + Enable TCP/IP syncookie support + + Oracle Linux 9 + + + The kernel CONFIG_SYN_COOKIES should have value y + + + + + + + + + + + Unmap kernel when running in userspace (aka KAISER) + + Oracle Linux 9 + + + The kernel CONFIG_UNMAP_KERNEL_AT_EL0 should have value y + + + + + + + + + + + User a virtually-mapped stack + + Oracle Linux 9 + + + The kernel CONFIG_VMAP_STACK should have value y + + + + + + + + + + + Disable x86 vsyscall emulation + + Oracle Linux 9 + + + The kernel CONFIG_X86_VSYSCALL_EMULATION should have value n + + + + + + + + + + + + Disable ATM Support + + Oracle Linux 9 + + + The kernel module atm should be disabled. + + + + + + + + + + + Disable Bluetooth Kernel Module + + Oracle Linux 9 + + + The kernel module bluetooth should be disabled. + + + + + + + + + + + Disable CAN Support + + Oracle Linux 9 + + + The kernel module can should be disabled. + + + + + + + + + + + Disable Mounting of cramfs + + Oracle Linux 9 + + + The kernel module cramfs should be disabled. + + + + + + + + + + + Disable DCCP Support + + Oracle Linux 9 + + + The kernel module dccp should be disabled. + + + + + + + + + + + Disable IEEE 1394 (FireWire) Support + + Oracle Linux 9 + + + The kernel module firewire-core should be disabled. + + + + + + + + + + + Disable RDS Support + + Oracle Linux 9 + + + The kernel module rds should be disabled. + + + + + + + + + + + Disable SCTP Support + + Oracle Linux 9 + + + The kernel module sctp should be disabled. + + + + + + + + + + + Disable Mounting of squashfs + + Oracle Linux 9 + + + The kernel module squashfs should be disabled. + + + + + + + + + + + Disable TIPC Support + + Oracle Linux 9 + + + The kernel module tipc should be disabled. + + + + + + + + + + + Disable Mounting of udf + + Oracle Linux 9 + + + The kernel module udf should be disabled. + + + + + + + + + + + Disable Modprobe Loading of USB Storage Driver + + Oracle Linux 9 + + + The kernel module usb-storage should be disabled. + + + + + + + + + + + Disable the uvcvideo module + + Oracle Linux 9 + + + The kernel module uvcvideo should be disabled. + + + + + + + + + + + Add nosuid Option to /boot/efi + + Oracle Linux 9 + + + /boot/efi should be mounted with mount option nosuid. + + + + + + + + + + + + + + + Add nodev Option to /boot + + Oracle Linux 9 + + + /boot should be mounted with mount option nodev. + + + + + + + + + + + + + + + Add noexec Option to /boot + + Oracle Linux 9 + + + /boot should be mounted with mount option noexec. + + + + + + + + + + + + + + + Add nosuid Option to /boot + + Oracle Linux 9 + + + /boot should be mounted with mount option nosuid. + + + + + + + + + + + + + + + Add nodev Option to /dev/shm + + Oracle Linux 9 + + + /dev/shm should be mounted with mount option nodev. + + + + + + + + + + + + + + Add noexec Option to /dev/shm + + Oracle Linux 9 + + + /dev/shm should be mounted with mount option noexec. + + + + + + + + + + + + + + Add nosuid Option to /dev/shm + + Oracle Linux 9 + + + /dev/shm should be mounted with mount option nosuid. + + + + + + + + + + + + + + Add grpquota Option to /home + + Oracle Linux 9 + + + Home mount points should be mounted with mount option grpquota. + + + + + + + + Add nodev Option to /home + + Oracle Linux 9 + + + /home should be mounted with mount option nodev. + + + + + + + + + + + + + + + Add noexec Option to /home + + Oracle Linux 9 + + + Home mount points should be mounted with mount option noexec. + + + + + + + + Add nosuid Option to /home + + Oracle Linux 9 + + + Home mount points should be mounted with mount option nosuid. + + + + + + + + Add usrquota Option to /home + + Oracle Linux 9 + + + Home mount points should be mounted with mount option usrquota. + + + + + + + + Mount Remote Filesystems with Kerberos Security + + Oracle Linux 9 + + + The sec_krb5_krb5i_krb5p option should be enabled for all NFS mounts in /etc/fstab. + + + + + + + + Mount Remote Filesystems with nodev + + Oracle Linux 9 + + + The nodev option should be enabled for all NFS mounts in /etc/fstab. + + + + + + + + Add nodev Option to Removable Media Partitions + + Oracle Linux 9 + + + The nodev option should be enabled for all removable devices mounts in /etc/fstab. + + + + + + + + + + + + + + + + Mount Remote Filesystems with noexec + + Oracle Linux 9 + + + The noexec option should be enabled for all NFS mounts in /etc/fstab. + + + + + + + + Add noexec Option to Removable Media Partitions + + Oracle Linux 9 + + + The noexec option should be enabled for all removable devices mounts in /etc/fstab. + + + + + + + + + + + + + + + + Mount Remote Filesystems with nosuid + + Oracle Linux 9 + + + The nosuid option should be enabled for all NFS mounts in /etc/fstab. + + + + + + + + Add nosuid Option to Removable Media Partitions + + Oracle Linux 9 + + + The nosuid option should be enabled for all removable devices mounts in /etc/fstab. + + + + + + + + + + + + + + + + Add nosuid Option to /opt + + Oracle Linux 9 + + + /opt should be mounted with mount option nosuid. + + + + + + + + + + + + + + + Add nosuid Option to /srv + + Oracle Linux 9 + + + /srv should be mounted with mount option nosuid. + + + + + + + + + + + + + + + Add nodev Option to /tmp + + Oracle Linux 9 + + + /tmp should be mounted with mount option nodev. + + + + + + + + + + + + + + + Add noexec Option to /tmp + + Oracle Linux 9 + + + /tmp should be mounted with mount option noexec. + + + + + + + + + + + + + + + Add nosuid Option to /tmp + + Oracle Linux 9 + + + /tmp should be mounted with mount option nosuid. + + + + + + + + + + + + + + + Add nodev Option to /var/log/audit + + Oracle Linux 9 + + + /var/log/audit should be mounted with mount option nodev. + + + + + + + + + + + + + + + Add noexec Option to /var/log/audit + + Oracle Linux 9 + + + /var/log/audit should be mounted with mount option noexec. + + + + + + + + + + + + + + + Add nosuid Option to /var/log/audit + + Oracle Linux 9 + + + /var/log/audit should be mounted with mount option nosuid. + + + + + + + + + + + + + + + Add nodev Option to /var/log + + Oracle Linux 9 + + + /var/log should be mounted with mount option nodev. + + + + + + + + + + + + + + + Add noexec Option to /var/log + + Oracle Linux 9 + + + /var/log should be mounted with mount option noexec. + + + + + + + + + + + + + + + Add nosuid Option to /var/log + + Oracle Linux 9 + + + /var/log should be mounted with mount option nosuid. + + + + + + + + + + + + + + + Add nodev Option to /var + + Oracle Linux 9 + + + /var should be mounted with mount option nodev. + + + + + + + + + + + + + + + Add noexec Option to /var + + Oracle Linux 9 + + + /var should be mounted with mount option noexec. + + + + + + + + + + + + + + + Add nosuid Option to /var + + Oracle Linux 9 + + + /var should be mounted with mount option nosuid. + + + + + + + + + + + + + + + Add nodev Option to /var/tmp + + Oracle Linux 9 + + + /var/tmp should be mounted with mount option nodev. + + + + + + + + + + + + + + + Add noexec Option to /var/tmp + + Oracle Linux 9 + + + /var/tmp should be mounted with mount option noexec. + + + + + + + + + + + + + + + Add nosuid Option to /var/tmp + + Oracle Linux 9 + + + /var/tmp should be mounted with mount option nosuid. + + + + + + + + + + + + + + + Install AIDE + + Oracle Linux 9 + + + The RPM package aide should be installed. + + + + + + + + Install audispd-plugins Package + + Oracle Linux 9 + + + The RPM package audispd-plugins should be installed. + + + + + + + + Ensure the audit Subsystem is Installed + + Oracle Linux 9 + + + The RPM package audit should be installed. + + + + + + + + Uninstall bind Package + + Oracle Linux 9 + + + The RPM package bind should be removed. + + + + + + + + The Chrony package is installed + + Oracle Linux 9 + + + The RPM package chrony should be installed. + + + + + + + + Install the cron service + + Oracle Linux 9 + + + The RPM package cronie should be installed. + + + + + + + + Install crypto-policies package + + Oracle Linux 9 + + + The RPM package crypto-policies should be installed. + + + + + + + + Install cryptsetup Package + + Oracle Linux 9 + + + The RPM package cryptsetup should be installed. + + + + + + + + Uninstall cyrus-imapd Package + + Oracle Linux 9 + + + The RPM package cyrus-imapd should be removed. + + + + + + + + package_dconf_installed + + Oracle Linux 9 + + + The RPM package dconf should be installed. + + + + + + + + Uninstall DHCP Server Package + + Oracle Linux 9 + + + The RPM package dhcp should be removed. + + + + + + + + Install dnf-automatic Package + + Oracle Linux 9 + + + The RPM package dnf-automatic should be installed. + + + + + + + + Uninstall dovecot Package + + Oracle Linux 9 + + + The RPM package dovecot should be removed. + + + + + + + + Install fapolicyd Package + + Oracle Linux 9 + + + The RPM package fapolicyd should be installed. + + + + + + + + Install firewalld Package + + Oracle Linux 9 + + + The RPM package firewalld should be installed. + + + + + + + + Remove ftp Package + + Oracle Linux 9 + + + The RPM package ftp should be removed. + + + + + + + + package_gdm_installed + + Oracle Linux 9 + + + The RPM package gdm should be installed. + + + + + + + + Ensure gnutls-utils is installed + + Oracle Linux 9 + + + The RPM package gnutls-utils should be installed. + + + + + + + + Uninstall gssproxy Package + + Oracle Linux 9 + + + The RPM package gssproxy should be removed. + + + + + + + + Uninstall the inet-based telnet server + + Oracle Linux 9 + + + The RPM package inetutils-telnetd should be removed. + + + + + + + + Uninstall iprutils Package + + Oracle Linux 9 + + + The RPM package iprutils should be removed. + + + + + + + + Install libreswan Package + + Oracle Linux 9 + + + The RPM package libreswan should be installed. + + + + + + + + Install libselinux Package + + Oracle Linux 9 + + + The RPM package libselinux should be installed. + + + + + + + + Ensure logrotate is Installed + + Oracle Linux 9 + + + The RPM package logrotate should be installed. + + + + + + + + Install McAfee Endpoint Security for Linux (ENSL) + + Oracle Linux 9 + + + The RPM package McAfeeTP should be installed. + + + + + + + + Uninstall net-snmp Package + + Oracle Linux 9 + + + The RPM package net-snmp should be removed. + + + + + + + + Uninstall nfs-utils Package + + Oracle Linux 9 + + + The RPM package nfs-utils should be removed. + + + + + + + + Install nftables Package + + Oracle Linux 9 + + + The RPM package nftables should be installed. + + + + + + + + Uninstall the nis package + + Oracle Linux 9 + + + The RPM package nis should be removed. + + + + + + + + Ensure nss-tools is installed + + Oracle Linux 9 + + + The RPM package nss-tools should be installed. + + + + + + + + Install the opensc Package For Multifactor Authentication + + Oracle Linux 9 + + + The RPM package opensc should be installed. + + + + + + + + Install openscap-scanner Package + + Oracle Linux 9 + + + The RPM package openscap-scanner should be installed. + + + + + + + + Install OpenSSH client software + + Oracle Linux 9 + + + The RPM package openssh-clients should be installed. + + + + + + + + Install the OpenSSH Server Package + + Oracle Linux 9 + + + The RPM package openssh-server should be installed. + + + + + + + + Remove the OpenSSH Server Package + + Oracle Linux 9 + + + The RPM package openssh-server should be removed. + + + + + + + + Install the pcsc-lite package + + Oracle Linux 9 + + + The RPM package pcsc-lite should be installed. + + + + + + + + Install policycoreutils-python-utils package + + Oracle Linux 9 + + + The RPM package policycoreutils-python-utils should be installed. + + + + + + + + Install policycoreutils Package + + Oracle Linux 9 + + + The RPM package policycoreutils should be installed. + + + + + + + + The Postfix package is installed + + Oracle Linux 9 + + + The RPM package postfix should be installed. + + + + + + + + Uninstall quagga Package + + Oracle Linux 9 + + + The RPM package quagga should be removed. + + + + + + + + Install rear Package + + Oracle Linux 9 + + + The RPM package rear should be installed. + + + + + + + + Install rng-tools Package + + Oracle Linux 9 + + + The RPM package rng-tools should be installed. + + + + + + + + Uninstall rsh-server Package + + Oracle Linux 9 + + + The RPM package rsh-server should be removed. + + + + + + + + Uninstall rsh Package + + Oracle Linux 9 + + + The RPM package rsh should be removed. + + + + + + + + Ensure rsyslog-gnutls is installed + + Oracle Linux 9 + + + The RPM package rsyslog-gnutls should be installed. + + + + + + + + Ensure rsyslog is Installed + + Oracle Linux 9 + + + The RPM package rsyslog should be installed. + + + + + + + + The s-nail Package Is Installed + + Oracle Linux 9 + + + The RPM package s-nail should be installed. + + + + + + + + Install scap-security-guide Package + + Oracle Linux 9 + + + The RPM package scap-security-guide should be installed. + + + + + + + + Uninstall Sendmail Package + + Oracle Linux 9 + + + The RPM package sendmail should be removed. + + + + + + + + Uninstall setroubleshoot-plugins Package + + Oracle Linux 9 + + + The RPM package setroubleshoot-plugins should be removed. + + + + + + + + Uninstall setroubleshoot-server Package + + Oracle Linux 9 + + + The RPM package setroubleshoot-server should be removed. + + + + + + + + Uninstall setroubleshoot Package + + Oracle Linux 9 + + + The RPM package setroubleshoot should be removed. + + + + + + + + Uninstall squid Package + + Oracle Linux 9 + + + The RPM package squid should be removed. + + + + + + + + Install the SSSD Package + + Oracle Linux 9 + + + The RPM package sssd should be installed. + + + + + + + + Install sudo Package + + Oracle Linux 9 + + + The RPM package sudo should be installed. + + + + + + + + Ensure syslog-ng is Installed + + Oracle Linux 9 + + + The RPM package syslog-ng should be installed. + + + + + + + + Uninstall talk-server Package + + Oracle Linux 9 + + + The RPM package talk-server should be removed. + + + + + + + + Uninstall talk Package + + Oracle Linux 9 + + + The RPM package talk should be removed. + + + + + + + + Uninstall telnet-server Package + + Oracle Linux 9 + + + The RPM package telnet-server should be removed. + + + + + + + + Remove telnet Clients + + Oracle Linux 9 + + + The RPM package telnet should be removed. + + + + + + + + Uninstall the ssl compliant telnet server + + Oracle Linux 9 + + + The RPM package telnetd-ssl should be removed. + + + + + + + + Uninstall the telnet server + + Oracle Linux 9 + + + The RPM package telnetd should be removed. + + + + + + + + Uninstall tftp-server Package + + Oracle Linux 9 + + + The RPM package tftp-server should be removed. + + + + + + + + Remove tftp Daemon + + Oracle Linux 9 + + + The RPM package tftp should be removed. + + + + + + + + Uninstall tuned Package + + Oracle Linux 9 + + + The RPM package tuned should be removed. + + + + + + + + Install usbguard Package + + Oracle Linux 9 + + + The RPM package usbguard should be installed. + + + + + + + + Uninstall vsftpd Package + + Oracle Linux 9 + + + The RPM package vsftpd should be removed. + + + + + + + + Remove the X Windows Package Group + + Oracle Linux 9 + + + The RPM package xorg-x11-server-common should be removed. + + + + + + + + Ensure /dev/shm is configured + + Oracle Linux 9 + + + If stored locally, create a separate partition for /dev/shm. If /dev/shm will be mounted from another system such as an NFS server, then creating a separate partition is not necessary at this time, and the mountpoint can instead be configured - later. - - - - - - - - - Ensure /home Located On Separate Partition - - Oracle Linux 9 - - If stored locally, create a separate partition for + later. + + + + + + + + Ensure /home Located On Separate Partition + + Oracle Linux 9 + + + If stored locally, create a separate partition for /home. If /home will be mounted from another system such as an NFS server, then creating a separate partition is not necessary at this time, and the mountpoint can instead be configured - later. - - - - - - - - - Ensure /srv Located On Separate Partition - - Oracle Linux 9 - - If stored locally, create a separate partition for + later. + + + + + + + + Ensure /srv Located On Separate Partition + + Oracle Linux 9 + + + If stored locally, create a separate partition for /srv. If /srv will be mounted from another system such as an NFS server, then creating a separate partition is not necessary at this time, and the mountpoint can instead be configured - later. - - - - - - - - - Ensure /tmp Located On Separate Partition - - Oracle Linux 9 - - If stored locally, create a separate partition for + later. + + + + + + + + Ensure /tmp Located On Separate Partition + + Oracle Linux 9 + + + If stored locally, create a separate partition for /tmp. If /tmp will be mounted from another system such as an NFS server, then creating a separate partition is not necessary at this time, and the mountpoint can instead be configured - later. - - - - - - - - - Ensure /var Located On Separate Partition - - Oracle Linux 9 - - If stored locally, create a separate partition for + later. + + + + + + + + Ensure /var Located On Separate Partition + + Oracle Linux 9 + + + If stored locally, create a separate partition for /var. If /var will be mounted from another system such as an NFS server, then creating a separate partition is not necessary at this time, and the mountpoint can instead be configured - later. - - - - - - - - - Ensure /var/log Located On Separate Partition - - Oracle Linux 9 - - If stored locally, create a separate partition for + later. + + + + + + + + Ensure /var/log Located On Separate Partition + + Oracle Linux 9 + + + If stored locally, create a separate partition for /var/log. If /var/log will be mounted from another system such as an NFS server, then creating a separate partition is not necessary at this time, and the mountpoint can instead be configured - later. - - - - - - - - - Ensure /var/log/audit Located On Separate Partition - - Oracle Linux 9 - - If stored locally, create a separate partition for + later. + + + + + + + + Ensure /var/log/audit Located On Separate Partition + + Oracle Linux 9 + + + If stored locally, create a separate partition for /var/log/audit. If /var/log/audit will be mounted from another system such as an NFS server, then creating a separate partition is not necessary at this time, and the mountpoint can instead be configured - later. - - - - - - - - - Ensure /var/tmp Located On Separate Partition - - Oracle Linux 9 - - If stored locally, create a separate partition for + later. + + + + + + + + Ensure /var/tmp Located On Separate Partition + + Oracle Linux 9 + + + If stored locally, create a separate partition for /var/tmp. If /var/tmp will be mounted from another system such as an NFS server, then creating a separate partition is not necessary at this time, and the mountpoint can instead be configured - later. - - - - - - - - - Verify the system-wide library files in directories -"/lib", "/lib64", "/usr/lib/" and "/usr/lib64" are group-owned by root. - - Oracle Linux 9 - - This test makes sure that /lib/, /lib64/, /usr/lib/, /usr/lib64/ is group owned by 0. - - - - - - - - - - - - Ensure Log Files Are Owned By Appropriate Group - - Oracle Linux 9 - - All syslog log files should have appropriate ownership. - - - - - - - - - Ensure Log Files Are Owned By Appropriate User - - Oracle Linux 9 - - All syslog log files should have appropriate ownership. - - - - - - - - - Ensure System Log Files Have Correct Permissions - - Oracle Linux 9 - - All syslog log files should have appropriate ownership. - - - - - - - - - Configure the deny_execmem SELinux Boolean - - Oracle Linux 9 - - The SELinux 'deny_execmem' boolean should be set in the system configuration. - - - - - - - - - Configure the polyinstantiation_enabled SELinux Boolean - - Oracle Linux 9 - - The SELinux 'polyinstantiation_enabled' boolean should be set in the system configuration. - - - - - - - - - Configure the secure_mode_insmod SELinux Boolean - - Oracle Linux 9 - - The SELinux 'secure_mode_insmod' boolean should be set in the system configuration. - - - - - - - - - Disable the selinuxuser_execheap SELinux Boolean - - Oracle Linux 9 - - The SELinux 'selinuxuser_execheap' boolean should be set in the system configuration. - - - - - - - - - Enable the selinuxuser_execmod SELinux Boolean - - Oracle Linux 9 - - The SELinux 'selinuxuser_execmod' boolean should be set in the system configuration. - - - - - - - - - Disable the selinuxuser_execstack SELinux Boolean - - Oracle Linux 9 - - The SELinux 'selinuxuser_execstack' boolean should be set in the system configuration. - - - - - - - - - Disable the ssh_sysadm_login SELinux Boolean - - Oracle Linux 9 - - The SELinux 'ssh_sysadm_login' boolean should be set in the system configuration. - - - - - - - - - Disable Automatic Bug Reporting Tool (abrtd) - - Oracle Linux 9 - - The abrtd service should be disabled if possible. - - - - - - - - - - - - - Disable At Service (atd) - - Oracle Linux 9 - - The atd service should be disabled if possible. - - - - - - - - - - - - - Enable auditd Service - - Oracle Linux 9 - - The auditd service should be enabled if possible. - - - - - - - - - - - - - - - - Disable the Automounter - - Oracle Linux 9 - - The autofs service should be disabled if possible. - - - - - - - - - - - - - Disable Avahi Server Software - - Oracle Linux 9 - - The avahi-daemon service should be disabled if possible. - - - - - - - - - - - - - The Chronyd service is enabled - - Oracle Linux 9 - - The chronyd service should be enabled if possible. - - - - - - - - - - - - - - - - Enable cron Service - - Oracle Linux 9 - - The cron service should be enabled if possible. - - - - - - - - - - - - - - - - Enable cron Service - - Oracle Linux 9 - - The crond service should be enabled if possible. - - - - - - - - - - - - - - - - Disable debug-shell SystemD Service - - Oracle Linux 9 - - The debug-shell service should be disabled if possible. - - - - - - - - - - - - - Enable the File Access Policy Service - - Oracle Linux 9 - - The fapolicyd service should be enabled if possible. - - - - - - - - - - - - - - - - Verify firewalld Enabled - - Oracle Linux 9 - - The firewalld service should be enabled if possible. - - - - - - - - - - - - - - - - Verify ip6tables Enabled if Using IPv6 - - Oracle Linux 9 - - The ip6tables service should be enabled if possible. - - - - - - - - - - - - - - - - Verify iptables Enabled - - Oracle Linux 9 - - The iptables service should be enabled if possible. - - - - - - - - - - - - - - - - Disable KDump Kernel Crash Analyzer (kdump) - - Oracle Linux 9 - - The kdump service should be disabled if possible. - - - - - - - - - - - - - Disable Network File Systems (netfs) - - Oracle Linux 9 - - The netfs service should be disabled if possible. - - - - - - - - - - - - - Enable the NTP Daemon - - Oracle Linux 9 - - The ntp service should be enabled if possible. - - - - - - - - - - - - - - - - Enable the NTP Daemon - - Oracle Linux 9 - - The ntpd service should be enabled if possible. - - - - - - - - - - - - - - - - Disable ntpdate Service (ntpdate) - - Oracle Linux 9 - - The ntpdate service should be disabled if possible. - - - - - - - - - - - - - Disable Odd Job Daemon (oddjobd) - - Oracle Linux 9 - - The oddjobd service should be disabled if possible. - - - - - - - - - - - - - Enable the pcscd Service - - Oracle Linux 9 - - The pcscd service should be enabled if possible. - - - - - - - - - - - - - - - - Enable Postfix Service - - Oracle Linux 9 - - The postfix service should be enabled if possible. - - - - - - - - - - - - - - - - Disable Apache Qpid (qpidd) - - Oracle Linux 9 - - The qpidd service should be disabled if possible. - - - - - - - - - - - - - Disable Network Router Discovery Daemon (rdisc) - - Oracle Linux 9 - - The rdisc service should be disabled if possible. - - - - - - - - - - - - - Disable rlogin Service - - Oracle Linux 9 - - The rlogin service should be disabled if possible. - - - - - - - - - - - - - Enable the Hardware RNG Entropy Gatherer Service - - Oracle Linux 9 - - The rngd service should be enabled if possible. - - - - - - - - - - - - - - - - Enable rsyslog Service - - Oracle Linux 9 - - The rsyslog service should be enabled if possible. - - - - - - - - - - - - - - - - Disable Squid - - Oracle Linux 9 - - The squid service should be disabled if possible. - - - - - - - - - - - - - Disable SSH Server If Possible - - Oracle Linux 9 - - The sshd service should be disabled if possible. - - - - - - - - - - - - - Enable the OpenSSH Service - - Oracle Linux 9 - - The sshd service should be enabled if possible. - - - - - - - - - - - - - - - - service_syslog_disabled - - Oracle Linux 9 - - The syslog service should be disabled if possible. - - - - - - - - - - - - - Enable syslog-ng Service - - Oracle Linux 9 - - The syslog-ng service should be enabled if possible. - - - - - - - - - - - - - - - - Disable acquiring, saving, and processing core dumps - - Oracle Linux 9 - - Disable {{{ SOCKETNAME }}}.socket - - - - - - - - - Enable systemd-journald Service - - Oracle Linux 9 - - The systemd-journald service should be enabled if possible. - - - - - - - - - - - - - - - - Disable telnet Service - - Oracle Linux 9 - - The telnet service should be disabled if possible. - - - - - - - - - - - - - Verify ufw Enabled - - Oracle Linux 9 - - The ufw service should be enabled if possible. - - - - - - - - - - - - - - - - Enable the USBGuard Service - - Oracle Linux 9 - - The usbguard service should be enabled if possible. - - - - - - - - - - - - - - - - Disable xinetd Service - - Oracle Linux 9 - - The xinetd service should be disabled if possible. - - - - - - - - - - - - - Disable SSH Access via Empty Passwords - - Oracle Linux 9 - - Ensure 'PermitEmptyPasswords' is configured with value 'no' in /etc/ssh/sshd_config - - - - - - - - - - - - - - - - - - - - - - - Disable GSSAPI Authentication - - Oracle Linux 9 - - Ensure 'GSSAPIAuthentication' is configured with value 'no' in /etc/ssh/sshd_config - - - - - - - - - - - - - - - - - - - - - - - Disable Kerberos Authentication - - Oracle Linux 9 - - Ensure 'KerberosAuthentication' is configured with value 'no' in /etc/ssh/sshd_config - - - - - - - - - - - - - - - - - - - - - - - Disable PubkeyAuthentication Authentication - - Oracle Linux 9 - - Ensure 'PubkeyAuthentication' is configured with value 'no' in /etc/ssh/sshd_config - - - - - - - - - - - - - - - - - - - - - - - Disable SSH Support for .rhosts Files - - Oracle Linux 9 - - Ensure 'IgnoreRhosts' is configured with value 'yes' in /etc/ssh/sshd_config - - - - - - - - - - - - - - - - - - - - - - - Disable SSH Root Login - - Oracle Linux 9 - - Ensure 'PermitRootLogin' is configured with value 'no' in /etc/ssh/sshd_config - - - - - - - - - - - - - - - - - - - - - - - Disable SSH root Login with a Password (Insecure) - - Oracle Linux 9 - - Ensure 'PermitRootLogin' is configured with value 'prohibit-password' in /etc/ssh/sshd_config - - - - - - - - - - - - - - - - - - - - - - - Disable SSH TCP Forwarding - - Oracle Linux 9 - - Ensure 'AllowTcpForwarding' is configured with value 'no' in /etc/ssh/sshd_config - - - - - - - - - - - - - - - - - - - - - - - Disable SSH Support for User Known Hosts - - Oracle Linux 9 - - Ensure 'IgnoreUserKnownHosts' is configured with value 'yes' in /etc/ssh/sshd_config - - - - - - - - - - - - - - - - - - - - - - - Disable X11 Forwarding - - Oracle Linux 9 - - Ensure 'X11Forwarding' is configured with value 'no' in /etc/ssh/sshd_config - - - - - - - - - - - - - - - - - - - - - - - Do Not Allow SSH Environment Options - - Oracle Linux 9 - - Ensure 'PermitUserEnvironment' is configured with value 'no' in /etc/ssh/sshd_config - - - - - - - - - - - - - - - - - - - - - - - Enable GSSAPI Authentication - - Oracle Linux 9 - - Ensure 'GSSAPIAuthentication' is configured with value 'yes' in /etc/ssh/sshd_config - - - - - - - - - - - - - - - - - - - - - - - Enable PAM - - Oracle Linux 9 - - Ensure 'UsePAM' is configured with value 'yes' in /etc/ssh/sshd_config - - - - - - - - - - - - - - - - - - - - - - - Enable Public Key Authentication - - Oracle Linux 9 - - Ensure 'PubkeyAuthentication' is configured with value 'yes' in /etc/ssh/sshd_config - - - - - - - - - - - - - - - - - - - - - - - Enable Use of Strict Mode Checking - - Oracle Linux 9 - - Ensure 'StrictModes' is configured with value 'yes' in /etc/ssh/sshd_config - - - - - - - - - - - - - - - - - - - - - - - Enable SSH Warning Banner - - Oracle Linux 9 - - Ensure 'Banner' is configured with value '/etc/issue' in /etc/ssh/sshd_config - - - - - - - - - - - - - - - - - - - - - - - Enable SSH Warning Banner - - Oracle Linux 9 - - Ensure 'Banner' is configured with value '/etc/issue.net' in /etc/ssh/sshd_config - - - - - - - - - - - - - - - - - - - - - - - Enable Encrypted X11 Forwarding - - Oracle Linux 9 - - Ensure 'X11Forwarding' is configured with value 'yes' in /etc/ssh/sshd_config - - - - - - - - - - - - - - - - - - - - - - - sshd_includes_config_files - - Oracle Linux 9 - - Check presence of Include /etc/ssh/sshd_config.d/*.conf in /etc/ssh/sshd_config - - - - - - - - - Enable SSH Print Last Log - - Oracle Linux 9 - - Ensure 'PrintLastLog' is configured with value 'yes' in /etc/ssh/sshd_config - - - - - - - - - - - - - - - - - - - - - - - Set SSH Client Alive Count Max to zero - - Oracle Linux 9 - - Ensure 'ClientAliveCountMax' is configured with value '0' in /etc/ssh/sshd_config - - - - - - - - - - - - - - - - - - - - - - - Set LogLevel to INFO - - Oracle Linux 9 - - Ensure 'LogLevel' is configured with value 'INFO' in /etc/ssh/sshd_config - - - - - - - - - - - - - - - - - - - - - - - Set SSH Daemon LogLevel to VERBOSE - - Oracle Linux 9 - - Ensure 'LogLevel' is configured with value 'VERBOSE' in /etc/ssh/sshd_config - - - - - - - - - - - - - - - - - - - - - - - Prevent remote hosts from connecting to the proxy display - - Oracle Linux 9 - - Ensure 'X11UseLocalhost' is configured with value 'yes' in /etc/ssh/sshd_config - - - - - - - - - - - - - - - - - - - - - - - Enable Certmap in SSSD - - Oracle Linux 9 - - Check presence of \[certmap\/.+\/.+\] in /etc/sssd/sssd.conf - - - - - - - - - Ensure Privileged Escalated Commands Cannot Execute Other Commands - sudo NOEXEC - - Oracle Linux 9 - - Checks sudoers Defaults {{ OPTION }} configuration - - - - - - - - - Ensure Only Users Logged In To Real tty Can Execute Sudo - sudo requiretty - - Oracle Linux 9 - - Checks sudoers Defaults {{ OPTION }} configuration - - - - - - - - - Ensure Only Users Logged In To Real tty Can Execute Sudo - sudo use_pty - - Oracle Linux 9 - - Checks sudoers Defaults {{ OPTION }} configuration - - - - - - - - - Ensure Sudo Logfile Exists - sudo logfile - - Oracle Linux 9 - - Checks sudoers Defaults {{ OPTION }} configuration - - - - - - - - - Enable Kernel Parameter to Enforce DAC on Hardlinks - - Oracle Linux 9 - - The 'fs.protected_hardlinks' kernel parameter should be set to the appropriate value in both system configuration and system runtime. - - - - - - - - - - Enable Kernel Parameter to Enforce DAC on Hardlinks - - Oracle Linux 9 - - The kernel 'fs.protected_hardlinks' parameter should be set to 1 in the system runtime. - - - - - - - - - Enable Kernel Parameter to Enforce DAC on Hardlinks - - Oracle Linux 9 - - The kernel 'fs.protected_hardlinks' parameter should be set to 1 in the system configuration. - - - - - - - - - - - - - Enable Kernel Parameter to Enforce DAC on Symlinks - - Oracle Linux 9 - - The 'fs.protected_symlinks' kernel parameter should be set to the appropriate value in both system configuration and system runtime. - - - - - - - - - - Enable Kernel Parameter to Enforce DAC on Symlinks - - Oracle Linux 9 - - The kernel 'fs.protected_symlinks' parameter should be set to 1 in the system runtime. - - - - - - - - - Enable Kernel Parameter to Enforce DAC on Symlinks - - Oracle Linux 9 - - The kernel 'fs.protected_symlinks' parameter should be set to 1 in the system configuration. - - - - - - - - - - - - - Disable Core Dumps for SUID programs - - Oracle Linux 9 - - The 'fs.suid_dumpable' kernel parameter should be set to the appropriate value in both system configuration and system runtime. - - - - - - - - - - Disable Core Dumps for SUID programs - - Oracle Linux 9 - - The kernel 'fs.suid_dumpable' parameter should be set to 0 in the system runtime. - - - - - - - - - Disable Core Dumps for SUID programs - - Oracle Linux 9 - - The kernel 'fs.suid_dumpable' parameter should be set to 0 in the system configuration. - - - - - - - - - - - - - Disable storing core dumps - - Oracle Linux 9 - - The 'kernel.core_pattern' kernel parameter should be set to the appropriate value in both system configuration and system runtime. - - - - - - - - - - Disable storing core dumps - - Oracle Linux 9 - - The kernel 'kernel.core_pattern' parameter should be set to |/bin/false in the system runtime. - - - - - - - - - Disable storing core dumps - - Oracle Linux 9 - - The kernel 'kernel.core_pattern' parameter should be set to |/bin/false in the system configuration. - - - - - - - - - - - - - Configure file name of core dumps - - Oracle Linux 9 - - The 'kernel.core_uses_pid' kernel parameter should be set to the appropriate value in both system configuration and system runtime. - - - - - - - - - - Configure file name of core dumps - - Oracle Linux 9 - - The kernel 'kernel.core_uses_pid' parameter should be set to 0 in the system runtime. - - - - - - - - - Configure file name of core dumps - - Oracle Linux 9 - - The kernel 'kernel.core_uses_pid' parameter should be set to 0 in the system configuration. - - - - - - - - - - - - - Restrict Access to Kernel Message Buffer - - Oracle Linux 9 - - The 'kernel.dmesg_restrict' kernel parameter should be set to the appropriate value in both system configuration and system runtime. - - - - - - - - - - Restrict Access to Kernel Message Buffer - - Oracle Linux 9 - - The kernel 'kernel.dmesg_restrict' parameter should be set to 1 in the system runtime. - - - - - - - - - Restrict Access to Kernel Message Buffer - - Oracle Linux 9 - - The kernel 'kernel.dmesg_restrict' parameter should be set to 1 in the system configuration. - - - - - - - - - - - - - Disable Kernel Image Loading - - Oracle Linux 9 - - The 'kernel.kexec_load_disabled' kernel parameter should be set to the appropriate value in both system configuration and system runtime. - - - - - - - - - - Disable Kernel Image Loading - - Oracle Linux 9 - - The kernel 'kernel.kexec_load_disabled' parameter should be set to 1 in the system runtime. - - - - - - - - - Disable Kernel Image Loading - - Oracle Linux 9 - - The kernel 'kernel.kexec_load_disabled' parameter should be set to 1 in the system configuration. - - - - - - - - - - - - - Restrict Exposed Kernel Pointer Addresses Access - - Oracle Linux 9 - - The 'kernel.kptr_restrict' kernel parameter should be set to the appropriate value in both system configuration and system runtime. - - - - - - - - - - Restrict Exposed Kernel Pointer Addresses Access - - Oracle Linux 9 - - The kernel 'kernel.kptr_restrict' parameter should be set to 1 or 2 in the system runtime. - - - - - - - - - Restrict Exposed Kernel Pointer Addresses Access - - Oracle Linux 9 - - The kernel 'kernel.kptr_restrict' parameter should be set to 1 or 2 in the system configuration. - - - - - - - - - - - - - Disable loading and unloading of kernel modules - - Oracle Linux 9 - - The 'kernel.modules_disabled' kernel parameter should be set to the appropriate value in both system configuration and system runtime. - - - - - - - - - - Disable loading and unloading of kernel modules - - Oracle Linux 9 - - The kernel 'kernel.modules_disabled' parameter should be set to 1 in the system runtime. - - - - - - - - - Disable loading and unloading of kernel modules - - Oracle Linux 9 - - The kernel 'kernel.modules_disabled' parameter should be set to 1 in the system configuration. - - - - - - - - - - - - - Kernel panic on oops - - Oracle Linux 9 - - The 'kernel.panic_on_oops' kernel parameter should be set to the appropriate value in both system configuration and system runtime. - - - - - - - - - - Kernel panic on oops - - Oracle Linux 9 - - The kernel 'kernel.panic_on_oops' parameter should be set to 1 in the system runtime. - - - - - - - - - Kernel panic on oops - - Oracle Linux 9 - - The kernel 'kernel.panic_on_oops' parameter should be set to 1 in the system configuration. - - - - - - - - - - - - - Limit CPU consumption of the Perf system - - Oracle Linux 9 - - The 'kernel.perf_cpu_time_max_percent' kernel parameter should be set to the appropriate value in both system configuration and system runtime. - - - - - - - - - - Limit CPU consumption of the Perf system - - Oracle Linux 9 - - The kernel 'kernel.perf_cpu_time_max_percent' parameter should be set to 1 in the system runtime. - - - - - - - - - Limit CPU consumption of the Perf system - - Oracle Linux 9 - - The kernel 'kernel.perf_cpu_time_max_percent' parameter should be set to 1 in the system configuration. - - - - - - - - - - - - - Limit sampling frequency of the Perf system - - Oracle Linux 9 - - The 'kernel.perf_event_max_sample_rate' kernel parameter should be set to the appropriate value in both system configuration and system runtime. - - - - - - - - - - Limit sampling frequency of the Perf system - - Oracle Linux 9 - - The kernel 'kernel.perf_event_max_sample_rate' parameter should be set to 1 in the system runtime. - - - - - - - - - Limit sampling frequency of the Perf system - - Oracle Linux 9 - - The kernel 'kernel.perf_event_max_sample_rate' parameter should be set to 1 in the system configuration. - - - - - - - - - - - - - Disallow kernel profiling by unprivileged users - - Oracle Linux 9 - - The 'kernel.perf_event_paranoid' kernel parameter should be set to the appropriate value in both system configuration and system runtime. - - - - - - - - - - Disallow kernel profiling by unprivileged users - - Oracle Linux 9 - - The kernel 'kernel.perf_event_paranoid' parameter should be set to 2 in the system runtime. - - - - - - - - - Disallow kernel profiling by unprivileged users - - Oracle Linux 9 - - The kernel 'kernel.perf_event_paranoid' parameter should be set to 2 in the system configuration. - - - - - - - - - - - - - Configure maximum number of process identifiers - - Oracle Linux 9 - - The 'kernel.pid_max' kernel parameter should be set to the appropriate value in both system configuration and system runtime. - - - - - - - - - - Configure maximum number of process identifiers - - Oracle Linux 9 - - The kernel 'kernel.pid_max' parameter should be set to 65536 in the system runtime. - - - - - - - - - Configure maximum number of process identifiers - - Oracle Linux 9 - - The kernel 'kernel.pid_max' parameter should be set to 65536 in the system configuration. - - - - - - - - - - - - - Enable Randomized Layout of Virtual Address Space - - Oracle Linux 9 - - The 'kernel.randomize_va_space' kernel parameter should be set to the appropriate value in both system configuration and system runtime. - - - - - - - - - - Enable Randomized Layout of Virtual Address Space - - Oracle Linux 9 - - The kernel 'kernel.randomize_va_space' parameter should be set to 2 in the system runtime. - - - - - - - - - Enable Randomized Layout of Virtual Address Space - - Oracle Linux 9 - - The kernel 'kernel.randomize_va_space' parameter should be set to 2 in the system configuration. - - - - - - - - - - - - - Disallow magic SysRq key - - Oracle Linux 9 - - The 'kernel.sysrq' kernel parameter should be set to the appropriate value in both system configuration and system runtime. - - - - - - - - - - Disallow magic SysRq key - - Oracle Linux 9 - - The kernel 'kernel.sysrq' parameter should be set to 0 in the system runtime. - - - - - - - - - Disallow magic SysRq key - - Oracle Linux 9 - - The kernel 'kernel.sysrq' parameter should be set to 0 in the system configuration. - - - - - - - - - - - - - Disable Access to Network bpf() Syscall From Unprivileged Processes - - Oracle Linux 9 - - The 'kernel.unprivileged_bpf_disabled' kernel parameter should be set to the appropriate value in both system configuration and system runtime. - - - - - - - - - - Disable Access to Network bpf() Syscall From Unprivileged Processes - - Oracle Linux 9 - - The kernel 'kernel.unprivileged_bpf_disabled' parameter should be set to 1 in the system runtime. - - - - - - - - - Disable Access to Network bpf() Syscall From Unprivileged Processes - - Oracle Linux 9 - - The kernel 'kernel.unprivileged_bpf_disabled' parameter should be set to 1 in the system configuration. - - - - - - - - - - - - - Restrict usage of ptrace to descendant processes - - Oracle Linux 9 - - The 'kernel.yama.ptrace_scope' kernel parameter should be set to the appropriate value in both system configuration and system runtime. - - - - - - - - - - Restrict usage of ptrace to descendant processes - - Oracle Linux 9 - - The kernel 'kernel.yama.ptrace_scope' parameter should be set to 1 in the system runtime. - - - - - - - - - Restrict usage of ptrace to descendant processes - - Oracle Linux 9 - - The kernel 'kernel.yama.ptrace_scope' parameter should be set to 1 in the system configuration. - - - - - - - - - - - - - Harden the operation of the BPF just-in-time compiler - - Oracle Linux 9 - - The 'net.core.bpf_jit_harden' kernel parameter should be set to the appropriate value in both system configuration and system runtime. - - - - - - - - - - Harden the operation of the BPF just-in-time compiler - - Oracle Linux 9 - - The kernel 'net.core.bpf_jit_harden' parameter should be set to 2 in the system runtime. - - - - - - - - - Harden the operation of the BPF just-in-time compiler - - Oracle Linux 9 - - The kernel 'net.core.bpf_jit_harden' parameter should be set to 2 in the system configuration. - - - - - - - - - - - - - Disable Accepting Packets Routed Between Local Interfaces - - Oracle Linux 9 - - The 'net.ipv4.conf.all.accept_local' kernel parameter should be set to the appropriate value in both system configuration and system runtime. - - - - - - - - - - Disable Accepting Packets Routed Between Local Interfaces - - Oracle Linux 9 - - The kernel 'net.ipv4.conf.all.accept_local' parameter should be set to 0 in the system runtime. - - - - - - - - - Disable Accepting Packets Routed Between Local Interfaces - - Oracle Linux 9 - - The kernel 'net.ipv4.conf.all.accept_local' parameter should be set to 0 in the system configuration. - - - - - - - - - - - - - Disable Accepting ICMP Redirects for All IPv4 Interfaces - - Oracle Linux 9 - - The 'net.ipv4.conf.all.accept_redirects' kernel parameter should be set to the appropriate value in both system configuration and system runtime. - - - - - - - - - - Disable Accepting ICMP Redirects for All IPv4 Interfaces - - Oracle Linux 9 - - The kernel 'net.ipv4.conf.all.accept_redirects' parameter should be set to the appropriate value in the system runtime. - - - - - - - - - Disable Accepting ICMP Redirects for All IPv4 Interfaces - - Oracle Linux 9 - - The kernel 'net.ipv4.conf.all.accept_redirects' parameter should be set to the appropriate value in the system configuration. - - - - - - - - - - - - - Disable Kernel Parameter for Accepting Source-Routed Packets on all IPv4 Interfaces - - Oracle Linux 9 - - The 'net.ipv4.conf.all.accept_source_route' kernel parameter should be set to the appropriate value in both system configuration and system runtime. - - - - - - - - - - Disable Kernel Parameter for Accepting Source-Routed Packets on all IPv4 Interfaces - - Oracle Linux 9 - - The kernel 'net.ipv4.conf.all.accept_source_route' parameter should be set to the appropriate value in the system runtime. - - - - - - - - - Disable Kernel Parameter for Accepting Source-Routed Packets on all IPv4 Interfaces - - Oracle Linux 9 - - The kernel 'net.ipv4.conf.all.accept_source_route' parameter should be set to the appropriate value in the system configuration. - - - - - - - - - - - - - Configure ARP filtering for All IPv4 Interfaces - - Oracle Linux 9 - - The 'net.ipv4.conf.all.arp_filter' kernel parameter should be set to the appropriate value in both system configuration and system runtime. - - - - - - - - - - Configure ARP filtering for All IPv4 Interfaces - - Oracle Linux 9 - - The kernel 'net.ipv4.conf.all.arp_filter' parameter should be set to the appropriate value in the system runtime. - - - - - - - - - Configure ARP filtering for All IPv4 Interfaces - - Oracle Linux 9 - - The kernel 'net.ipv4.conf.all.arp_filter' parameter should be set to the appropriate value in the system configuration. - - - - - - - - - - - - - Configure Response Mode of ARP Requests for All IPv4 Interfaces - - Oracle Linux 9 - - The 'net.ipv4.conf.all.arp_ignore' kernel parameter should be set to the appropriate value in both system configuration and system runtime. - - - - - - - - - - Configure Response Mode of ARP Requests for All IPv4 Interfaces - - Oracle Linux 9 - - The kernel 'net.ipv4.conf.all.arp_ignore' parameter should be set to the appropriate value in the system runtime. - - - - - - - - - Configure Response Mode of ARP Requests for All IPv4 Interfaces - - Oracle Linux 9 - - The kernel 'net.ipv4.conf.all.arp_ignore' parameter should be set to the appropriate value in the system configuration. - - - - - - - - - - - - - Drop Gratuitious ARP frames on All IPv4 Interfaces - - Oracle Linux 9 - - The 'net.ipv4.conf.all.drop_gratuitous_arp' kernel parameter should be set to the appropriate value in both system configuration and system runtime. - - - - - - - - - - Drop Gratuitious ARP frames on All IPv4 Interfaces - - Oracle Linux 9 - - The kernel 'net.ipv4.conf.all.drop_gratuitous_arp' parameter should be set to 1 in the system runtime. - - - - - - - - - Drop Gratuitious ARP frames on All IPv4 Interfaces - - Oracle Linux 9 - - The kernel 'net.ipv4.conf.all.drop_gratuitous_arp' parameter should be set to 1 in the system configuration. - - - - - - - - - - - - - Enable Kernel Parameter to Log Martian Packets on all IPv4 Interfaces - - Oracle Linux 9 - - The 'net.ipv4.conf.all.log_martians' kernel parameter should be set to the appropriate value in both system configuration and system runtime. - - - - - - - - - - Enable Kernel Parameter to Log Martian Packets on all IPv4 Interfaces - - Oracle Linux 9 - - The kernel 'net.ipv4.conf.all.log_martians' parameter should be set to the appropriate value in the system runtime. - - - - - - - - - Enable Kernel Parameter to Log Martian Packets on all IPv4 Interfaces - - Oracle Linux 9 - - The kernel 'net.ipv4.conf.all.log_martians' parameter should be set to the appropriate value in the system configuration. - - - - - - - - - - - - - Prevent Routing External Traffic to Local Loopback on All IPv4 Interfaces - - Oracle Linux 9 - - The 'net.ipv4.conf.all.route_localnet' kernel parameter should be set to the appropriate value in both system configuration and system runtime. - - - - - - - - - - Prevent Routing External Traffic to Local Loopback on All IPv4 Interfaces - - Oracle Linux 9 - - The kernel 'net.ipv4.conf.all.route_localnet' parameter should be set to 0 in the system runtime. - - - - - - - - - Prevent Routing External Traffic to Local Loopback on All IPv4 Interfaces - - Oracle Linux 9 - - The kernel 'net.ipv4.conf.all.route_localnet' parameter should be set to 0 in the system configuration. - - - - - - - - - - - - - Enable Kernel Parameter to Use Reverse Path Filtering on all IPv4 Interfaces - - Oracle Linux 9 - - The 'net.ipv4.conf.all.rp_filter' kernel parameter should be set to the appropriate value in both system configuration and system runtime. - - - - - - - - - - Enable Kernel Parameter to Use Reverse Path Filtering on all IPv4 Interfaces - - Oracle Linux 9 - - The kernel 'net.ipv4.conf.all.rp_filter' parameter should be set to 1 or 2 in the system runtime. - - - - - - - - - Enable Kernel Parameter to Use Reverse Path Filtering on all IPv4 Interfaces - - Oracle Linux 9 - - The kernel 'net.ipv4.conf.all.rp_filter' parameter should be set to 1 or 2 in the system configuration. - - - - - - - - - - - - - Disable Kernel Parameter for Accepting Secure ICMP Redirects on all IPv4 Interfaces - - Oracle Linux 9 - - The 'net.ipv4.conf.all.secure_redirects' kernel parameter should be set to the appropriate value in both system configuration and system runtime. - - - - - - - - - - Disable Kernel Parameter for Accepting Secure ICMP Redirects on all IPv4 Interfaces - - Oracle Linux 9 - - The kernel 'net.ipv4.conf.all.secure_redirects' parameter should be set to the appropriate value in the system runtime. - - - - - - - - - Disable Kernel Parameter for Accepting Secure ICMP Redirects on all IPv4 Interfaces - - Oracle Linux 9 - - The kernel 'net.ipv4.conf.all.secure_redirects' parameter should be set to the appropriate value in the system configuration. - - - - - - - - - - - - - Disable Kernel Parameter for Sending ICMP Redirects on all IPv4 Interfaces - - Oracle Linux 9 - - The 'net.ipv4.conf.all.send_redirects' kernel parameter should be set to the appropriate value in both system configuration and system runtime. - - - - - - - - - - Disable Kernel Parameter for Sending ICMP Redirects on all IPv4 Interfaces - - Oracle Linux 9 - - The kernel 'net.ipv4.conf.all.send_redirects' parameter should be set to 0 in the system runtime. - - - - - - - - - Disable Kernel Parameter for Sending ICMP Redirects on all IPv4 Interfaces - - Oracle Linux 9 - - The kernel 'net.ipv4.conf.all.send_redirects' parameter should be set to 0 in the system configuration. - - - - - - - - - - - - - Configure Sending and Accepting Shared Media Redirects for All IPv4 Interfaces - - Oracle Linux 9 - - The 'net.ipv4.conf.all.shared_media' kernel parameter should be set to the appropriate value in both system configuration and system runtime. - - - - - - - - - - Configure Sending and Accepting Shared Media Redirects for All IPv4 Interfaces - - Oracle Linux 9 - - The kernel 'net.ipv4.conf.all.shared_media' parameter should be set to the appropriate value in the system runtime. - - - - - - - - - Configure Sending and Accepting Shared Media Redirects for All IPv4 Interfaces - - Oracle Linux 9 - - The kernel 'net.ipv4.conf.all.shared_media' parameter should be set to the appropriate value in the system configuration. - - - - - - - - - - - - - Disable Kernel Parameter for Accepting ICMP Redirects by Default on IPv4 Interfaces - - Oracle Linux 9 - - The 'net.ipv4.conf.default.accept_redirects' kernel parameter should be set to the appropriate value in both system configuration and system runtime. - - - - - - - - - - Disable Kernel Parameter for Accepting ICMP Redirects by Default on IPv4 Interfaces - - Oracle Linux 9 - - The kernel 'net.ipv4.conf.default.accept_redirects' parameter should be set to the appropriate value in the system runtime. - - - - - - - - - Disable Kernel Parameter for Accepting ICMP Redirects by Default on IPv4 Interfaces - - Oracle Linux 9 - - The kernel 'net.ipv4.conf.default.accept_redirects' parameter should be set to the appropriate value in the system configuration. - - - - - - - - - - - - - Disable Kernel Parameter for Accepting Source-Routed Packets on IPv4 Interfaces by Default - - Oracle Linux 9 - - The 'net.ipv4.conf.default.accept_source_route' kernel parameter should be set to the appropriate value in both system configuration and system runtime. - - - - - - - - - - Disable Kernel Parameter for Accepting Source-Routed Packets on IPv4 Interfaces by Default - - Oracle Linux 9 - - The kernel 'net.ipv4.conf.default.accept_source_route' parameter should be set to the appropriate value in the system runtime. - - - - - - - - - Disable Kernel Parameter for Accepting Source-Routed Packets on IPv4 Interfaces by Default - - Oracle Linux 9 - - The kernel 'net.ipv4.conf.default.accept_source_route' parameter should be set to the appropriate value in the system configuration. - - - - - - - - - - - - - Enable Kernel Paremeter to Log Martian Packets on all IPv4 Interfaces by Default - - Oracle Linux 9 - - The 'net.ipv4.conf.default.log_martians' kernel parameter should be set to the appropriate value in both system configuration and system runtime. - - - - - - - - - - Enable Kernel Paremeter to Log Martian Packets on all IPv4 Interfaces by Default - - Oracle Linux 9 - - The kernel 'net.ipv4.conf.default.log_martians' parameter should be set to the appropriate value in the system runtime. - - - - - - - - - Enable Kernel Paremeter to Log Martian Packets on all IPv4 Interfaces by Default - - Oracle Linux 9 - - The kernel 'net.ipv4.conf.default.log_martians' parameter should be set to the appropriate value in the system configuration. - - - - - - - - - - - - - Enable Kernel Parameter to Use Reverse Path Filtering on all IPv4 Interfaces by Default - - Oracle Linux 9 - - The 'net.ipv4.conf.default.rp_filter' kernel parameter should be set to the appropriate value in both system configuration and system runtime. - - - - - - - - - - Enable Kernel Parameter to Use Reverse Path Filtering on all IPv4 Interfaces by Default - - Oracle Linux 9 - - The kernel 'net.ipv4.conf.default.rp_filter' parameter should be set to the appropriate value in the system runtime. - - - - - - - - - Enable Kernel Parameter to Use Reverse Path Filtering on all IPv4 Interfaces by Default - - Oracle Linux 9 - - The kernel 'net.ipv4.conf.default.rp_filter' parameter should be set to the appropriate value in the system configuration. - - - - - - - - - - - - - Configure Kernel Parameter for Accepting Secure Redirects By Default - - Oracle Linux 9 - - The 'net.ipv4.conf.default.secure_redirects' kernel parameter should be set to the appropriate value in both system configuration and system runtime. - - - - - - - - - - Configure Kernel Parameter for Accepting Secure Redirects By Default - - Oracle Linux 9 - - The kernel 'net.ipv4.conf.default.secure_redirects' parameter should be set to the appropriate value in the system runtime. - - - - - - - - - Configure Kernel Parameter for Accepting Secure Redirects By Default - - Oracle Linux 9 - - The kernel 'net.ipv4.conf.default.secure_redirects' parameter should be set to the appropriate value in the system configuration. - - - - - - - - - - - - - Disable Kernel Parameter for Sending ICMP Redirects on all IPv4 Interfaces by Default - - Oracle Linux 9 - - The 'net.ipv4.conf.default.send_redirects' kernel parameter should be set to the appropriate value in both system configuration and system runtime. - - - - - - - - - - Disable Kernel Parameter for Sending ICMP Redirects on all IPv4 Interfaces by Default - - Oracle Linux 9 - - The kernel 'net.ipv4.conf.default.send_redirects' parameter should be set to 0 in the system runtime. - - - - - - - - - Disable Kernel Parameter for Sending ICMP Redirects on all IPv4 Interfaces by Default - - Oracle Linux 9 - - The kernel 'net.ipv4.conf.default.send_redirects' parameter should be set to 0 in the system configuration. - - - - - - - - - - - - - Configure Sending and Accepting Shared Media Redirects by Default - - Oracle Linux 9 - - The 'net.ipv4.conf.default.shared_media' kernel parameter should be set to the appropriate value in both system configuration and system runtime. - - - - - - - - - - Configure Sending and Accepting Shared Media Redirects by Default - - Oracle Linux 9 - - The kernel 'net.ipv4.conf.default.shared_media' parameter should be set to the appropriate value in the system runtime. - - - - - - - - - Configure Sending and Accepting Shared Media Redirects by Default - - Oracle Linux 9 - - The kernel 'net.ipv4.conf.default.shared_media' parameter should be set to the appropriate value in the system configuration. - - - - - - - - - - - - - Enable Kernel Parameter to Ignore ICMP Broadcast Echo Requests on IPv4 Interfaces - - Oracle Linux 9 - - The 'net.ipv4.icmp_echo_ignore_broadcasts' kernel parameter should be set to the appropriate value in both system configuration and system runtime. - - - - - - - - - - Enable Kernel Parameter to Ignore ICMP Broadcast Echo Requests on IPv4 Interfaces - - Oracle Linux 9 - - The kernel 'net.ipv4.icmp_echo_ignore_broadcasts' parameter should be set to the appropriate value in the system runtime. - - - - - - - - - Enable Kernel Parameter to Ignore ICMP Broadcast Echo Requests on IPv4 Interfaces - - Oracle Linux 9 - - The kernel 'net.ipv4.icmp_echo_ignore_broadcasts' parameter should be set to the appropriate value in the system configuration. - - - - - - - - - - - - - Enable Kernel Parameter to Ignore Bogus ICMP Error Responses on IPv4 Interfaces - - Oracle Linux 9 - - The 'net.ipv4.icmp_ignore_bogus_error_responses' kernel parameter should be set to the appropriate value in both system configuration and system runtime. - - - - - - - - - - Enable Kernel Parameter to Ignore Bogus ICMP Error Responses on IPv4 Interfaces - - Oracle Linux 9 - - The kernel 'net.ipv4.icmp_ignore_bogus_error_responses' parameter should be set to the appropriate value in the system runtime. - - - - - - - - - Enable Kernel Parameter to Ignore Bogus ICMP Error Responses on IPv4 Interfaces - - Oracle Linux 9 - - The kernel 'net.ipv4.icmp_ignore_bogus_error_responses' parameter should be set to the appropriate value in the system configuration. - - - - - - - - - - - - - Disable Kernel Parameter for IP Forwarding on IPv4 Interfaces - - Oracle Linux 9 - - The 'net.ipv4.ip_forward' kernel parameter should be set to the appropriate value in both system configuration and system runtime. - - - - - - - - - - Disable Kernel Parameter for IP Forwarding on IPv4 Interfaces - - Oracle Linux 9 - - The kernel 'net.ipv4.ip_forward' parameter should be set to 0 in the system runtime. - - - - - - - - - Disable Kernel Parameter for IP Forwarding on IPv4 Interfaces - - Oracle Linux 9 - - The kernel 'net.ipv4.ip_forward' parameter should be set to 0 in the system configuration. - - - - - - - - - - - - - Set Kernel Parameter to Increase Local Port Range - - Oracle Linux 9 - - The 'net.ipv4.ip_local_port_range' kernel parameter should be set to the appropriate value in both system configuration and system runtime. - - - - - - - - - - Set Kernel Parameter to Increase Local Port Range - - Oracle Linux 9 - - The kernel 'net.ipv4.ip_local_port_range' parameter should be set to 32768 65535 in the system runtime. - - - - - - - - - Set Kernel Parameter to Increase Local Port Range - - Oracle Linux 9 - - The kernel 'net.ipv4.ip_local_port_range' parameter should be set to 32768 65535 in the system configuration. - - - - - - - - - - - - - Configure Kernel to Rate Limit Sending of Duplicate TCP Acknowledgments - - Oracle Linux 9 - - The 'net.ipv4.tcp_invalid_ratelimit' kernel parameter should be set to the appropriate value in both system configuration and system runtime. - - - - - - - - - - Configure Kernel to Rate Limit Sending of Duplicate TCP Acknowledgments - - Oracle Linux 9 - - The kernel 'net.ipv4.tcp_invalid_ratelimit' parameter should be set to the appropriate value in the system runtime. - - - - - - - - - Configure Kernel to Rate Limit Sending of Duplicate TCP Acknowledgments - - Oracle Linux 9 - - The kernel 'net.ipv4.tcp_invalid_ratelimit' parameter should be set to the appropriate value in the system configuration. - - - - - - - - - - - - - Enable Kernel Parameter to Use TCP RFC 1337 on IPv4 Interfaces - - Oracle Linux 9 - - The 'net.ipv4.tcp_rfc1337' kernel parameter should be set to the appropriate value in both system configuration and system runtime. - - - - - - - - - - Enable Kernel Parameter to Use TCP RFC 1337 on IPv4 Interfaces - - Oracle Linux 9 - - The kernel 'net.ipv4.tcp_rfc1337' parameter should be set to the appropriate value in the system runtime. - - - - - - - - - Enable Kernel Parameter to Use TCP RFC 1337 on IPv4 Interfaces - - Oracle Linux 9 - - The kernel 'net.ipv4.tcp_rfc1337' parameter should be set to the appropriate value in the system configuration. - - - - - - - - - - - - - Enable Kernel Parameter to Use TCP Syncookies on Network Interfaces - - Oracle Linux 9 - - The 'net.ipv4.tcp_syncookies' kernel parameter should be set to the appropriate value in both system configuration and system runtime. - - - - - - - - - - Enable Kernel Parameter to Use TCP Syncookies on Network Interfaces - - Oracle Linux 9 - - The kernel 'net.ipv4.tcp_syncookies' parameter should be set to the appropriate value in the system runtime. - - - - - - - - - Enable Kernel Parameter to Use TCP Syncookies on Network Interfaces - - Oracle Linux 9 - - The kernel 'net.ipv4.tcp_syncookies' parameter should be set to the appropriate value in the system configuration. - - - - - - - - - - - - - Configure Accepting Router Advertisements on All IPv6 Interfaces - - Oracle Linux 9 - - The kernel 'net.ipv6.conf.all.accept_ra' parameter should be set to the appropriate value in both system configuration and system runtime. - - - - - - - - - - - - - Configure Accepting Router Advertisements on All IPv6 Interfaces - - Oracle Linux 9 - - The kernel 'net.ipv6.conf.all.accept_ra' parameter should be set to the appropriate value in the system runtime. - - - - - - - - - Configure Accepting Router Advertisements on All IPv6 Interfaces - - Oracle Linux 9 - - The kernel 'net.ipv6.conf.all.accept_ra' parameter should be set to the appropriate value in the system configuration. - - - - - - - - - - - - - Configure Accepting Default Router in Router Advertisements on All IPv6 Interfaces - - Oracle Linux 9 - - The kernel 'net.ipv6.conf.all.accept_ra_defrtr' parameter should be set to the appropriate value in both system configuration and system runtime. - - - - - - - - - - - - - Configure Accepting Default Router in Router Advertisements on All IPv6 Interfaces - - Oracle Linux 9 - - The kernel 'net.ipv6.conf.all.accept_ra_defrtr' parameter should be set to the appropriate value in the system runtime. - - - - - - - - - Configure Accepting Default Router in Router Advertisements on All IPv6 Interfaces - - Oracle Linux 9 - - The kernel 'net.ipv6.conf.all.accept_ra_defrtr' parameter should be set to the appropriate value in the system configuration. - - - - - - - - - - - - - Configure Accepting Prefix Information in Router Advertisements on All IPv6 Interfaces - - Oracle Linux 9 - - The kernel 'net.ipv6.conf.all.accept_ra_pinfo' parameter should be set to the appropriate value in both system configuration and system runtime. - - - - - - - - - - - - - Configure Accepting Prefix Information in Router Advertisements on All IPv6 Interfaces - - Oracle Linux 9 - - The kernel 'net.ipv6.conf.all.accept_ra_pinfo' parameter should be set to the appropriate value in the system runtime. - - - - - - - - - Configure Accepting Prefix Information in Router Advertisements on All IPv6 Interfaces - - Oracle Linux 9 - - The kernel 'net.ipv6.conf.all.accept_ra_pinfo' parameter should be set to the appropriate value in the system configuration. - - - - - - - - - - - - - Configure Accepting Router Preference in Router Advertisements on All IPv6 Interfaces - - Oracle Linux 9 - - The kernel 'net.ipv6.conf.all.accept_ra_rtr_pref' parameter should be set to the appropriate value in both system configuration and system runtime. - - - - - - - - - - - - - Configure Accepting Router Preference in Router Advertisements on All IPv6 Interfaces - - Oracle Linux 9 - - The kernel 'net.ipv6.conf.all.accept_ra_rtr_pref' parameter should be set to the appropriate value in the system runtime. - - - - - - - - - Configure Accepting Router Preference in Router Advertisements on All IPv6 Interfaces - - Oracle Linux 9 - - The kernel 'net.ipv6.conf.all.accept_ra_rtr_pref' parameter should be set to the appropriate value in the system configuration. - - - - - - - - - - - - - Disable Accepting ICMP Redirects for All IPv6 Interfaces - - Oracle Linux 9 - - The kernel 'net.ipv6.conf.all.accept_redirects' parameter should be set to the appropriate value in both system configuration and system runtime. - - - - - - - - - - - - - Disable Accepting ICMP Redirects for All IPv6 Interfaces - - Oracle Linux 9 - - The kernel 'net.ipv6.conf.all.accept_redirects' parameter should be set to the appropriate value in the system runtime. - - - - - - - - - Disable Accepting ICMP Redirects for All IPv6 Interfaces - - Oracle Linux 9 - - The kernel 'net.ipv6.conf.all.accept_redirects' parameter should be set to the appropriate value in the system configuration. - - - - - - - - - - - - - Disable Kernel Parameter for Accepting Source-Routed Packets on all IPv6 Interfaces - - Oracle Linux 9 - - The kernel 'net.ipv6.conf.all.accept_source_route' parameter should be set to the appropriate value in both system configuration and system runtime. - - - - - - - - - - - - - Disable Kernel Parameter for Accepting Source-Routed Packets on all IPv6 Interfaces - - Oracle Linux 9 - - The kernel 'net.ipv6.conf.all.accept_source_route' parameter should be set to the appropriate value in the system runtime. - - - - - - - - - Disable Kernel Parameter for Accepting Source-Routed Packets on all IPv6 Interfaces - - Oracle Linux 9 - - The kernel 'net.ipv6.conf.all.accept_source_route' parameter should be set to the appropriate value in the system configuration. - - - - - - - - - - - - - Configure Auto Configuration on All IPv6 Interfaces - - Oracle Linux 9 - - The kernel 'net.ipv6.conf.all.autoconf' parameter should be set to the appropriate value in both system configuration and system runtime. - - - - - - - - - - - - - Configure Auto Configuration on All IPv6 Interfaces - - Oracle Linux 9 - - The kernel 'net.ipv6.conf.all.autoconf' parameter should be set to the appropriate value in the system runtime. - - - - - - - - - Configure Auto Configuration on All IPv6 Interfaces - - Oracle Linux 9 - - The kernel 'net.ipv6.conf.all.autoconf' parameter should be set to the appropriate value in the system configuration. - - - - - - - - - - - - - Disable IPv6 Addressing on All IPv6 Interfaces - - Oracle Linux 9 - - The kernel 'net.ipv6.conf.all.disable_ipv6' parameter should be set to the appropriate value in both system configuration and system runtime. - - - - - - - - - - - - - Disable IPv6 Addressing on All IPv6 Interfaces - - Oracle Linux 9 - - The kernel 'net.ipv6.conf.all.disable_ipv6' parameter should be set to 1 in the system runtime. - - - - - - - - - Disable IPv6 Addressing on All IPv6 Interfaces - - Oracle Linux 9 - - The kernel 'net.ipv6.conf.all.disable_ipv6' parameter should be set to 1 in the system configuration. - - - - - - - - - - - - - Disable Kernel Parameter for IPv6 Forwarding - - Oracle Linux 9 - - The kernel 'net.ipv6.conf.all.forwarding' parameter should be set to the appropriate value in both system configuration and system runtime. - - - - - - - - - - - - - Disable Kernel Parameter for IPv6 Forwarding - - Oracle Linux 9 - - The kernel 'net.ipv6.conf.all.forwarding' parameter should be set to the appropriate value in the system runtime. - - - - - - - - - Disable Kernel Parameter for IPv6 Forwarding - - Oracle Linux 9 - - The kernel 'net.ipv6.conf.all.forwarding' parameter should be set to the appropriate value in the system configuration. - - - - - - - - - - - - - Configure Maximum Number of Autoconfigured Addresses on All IPv6 Interfaces - - Oracle Linux 9 - - The kernel 'net.ipv6.conf.all.max_addresses' parameter should be set to the appropriate value in both system configuration and system runtime. - - - - - - - - - - - - - Configure Maximum Number of Autoconfigured Addresses on All IPv6 Interfaces - - Oracle Linux 9 - - The kernel 'net.ipv6.conf.all.max_addresses' parameter should be set to the appropriate value in the system runtime. - - - - - - - - - Configure Maximum Number of Autoconfigured Addresses on All IPv6 Interfaces - - Oracle Linux 9 - - The kernel 'net.ipv6.conf.all.max_addresses' parameter should be set to the appropriate value in the system configuration. - - - - - - - - - - - - - Configure Denying Router Solicitations on All IPv6 Interfaces - - Oracle Linux 9 - - The kernel 'net.ipv6.conf.all.router_solicitations' parameter should be set to the appropriate value in both system configuration and system runtime. - - - - - - - - - - - - - Configure Denying Router Solicitations on All IPv6 Interfaces - - Oracle Linux 9 - - The kernel 'net.ipv6.conf.all.router_solicitations' parameter should be set to the appropriate value in the system runtime. - - - - - - - - - Configure Denying Router Solicitations on All IPv6 Interfaces - - Oracle Linux 9 - - The kernel 'net.ipv6.conf.all.router_solicitations' parameter should be set to the appropriate value in the system configuration. - - - - - - - - - - - - - Disable Accepting Router Advertisements on all IPv6 Interfaces by Default - - Oracle Linux 9 - - The kernel 'net.ipv6.conf.default.accept_ra' parameter should be set to the appropriate value in both system configuration and system runtime. - - - - - - - - - - - - - Disable Accepting Router Advertisements on all IPv6 Interfaces by Default - - Oracle Linux 9 - - The kernel 'net.ipv6.conf.default.accept_ra' parameter should be set to the appropriate value in the system runtime. - - - - - - - - - Disable Accepting Router Advertisements on all IPv6 Interfaces by Default - - Oracle Linux 9 - - The kernel 'net.ipv6.conf.default.accept_ra' parameter should be set to the appropriate value in the system configuration. - - - - - - - - - - - - - Configure Accepting Default Router in Router Advertisements on All IPv6 Interfaces By Default - - Oracle Linux 9 - - The kernel 'net.ipv6.conf.default.accept_ra_defrtr' parameter should be set to the appropriate value in both system configuration and system runtime. - - - - - - - - - - - - - Configure Accepting Default Router in Router Advertisements on All IPv6 Interfaces By Default - - Oracle Linux 9 - - The kernel 'net.ipv6.conf.default.accept_ra_defrtr' parameter should be set to the appropriate value in the system runtime. - - - - - - - - - Configure Accepting Default Router in Router Advertisements on All IPv6 Interfaces By Default - - Oracle Linux 9 - - The kernel 'net.ipv6.conf.default.accept_ra_defrtr' parameter should be set to the appropriate value in the system configuration. - - - - - - - - - - - - - Configure Accepting Prefix Information in Router Advertisements on All IPv6 Interfaces By Default - - Oracle Linux 9 - - The kernel 'net.ipv6.conf.default.accept_ra_pinfo' parameter should be set to the appropriate value in both system configuration and system runtime. - - - - - - - - - - - - - Configure Accepting Prefix Information in Router Advertisements on All IPv6 Interfaces By Default - - Oracle Linux 9 - - The kernel 'net.ipv6.conf.default.accept_ra_pinfo' parameter should be set to the appropriate value in the system runtime. - - - - - - - - - Configure Accepting Prefix Information in Router Advertisements on All IPv6 Interfaces By Default - - Oracle Linux 9 - - The kernel 'net.ipv6.conf.default.accept_ra_pinfo' parameter should be set to the appropriate value in the system configuration. - - - - - - - - - - - - - Configure Accepting Router Preference in Router Advertisements on All IPv6 Interfaces By Default - - Oracle Linux 9 - - The kernel 'net.ipv6.conf.default.accept_ra_rtr_pref' parameter should be set to the appropriate value in both system configuration and system runtime. - - - - - - - - - - - - - Configure Accepting Router Preference in Router Advertisements on All IPv6 Interfaces By Default - - Oracle Linux 9 - - The kernel 'net.ipv6.conf.default.accept_ra_rtr_pref' parameter should be set to the appropriate value in the system runtime. - - - - - - - - - Configure Accepting Router Preference in Router Advertisements on All IPv6 Interfaces By Default - - Oracle Linux 9 - - The kernel 'net.ipv6.conf.default.accept_ra_rtr_pref' parameter should be set to the appropriate value in the system configuration. - - - - - - - - - - - - - Disable Kernel Parameter for Accepting ICMP Redirects by Default on IPv6 Interfaces - - Oracle Linux 9 - - The kernel 'net.ipv6.conf.default.accept_redirects' parameter should be set to the appropriate value in both system configuration and system runtime. - - - - - - - - - - - - - Disable Kernel Parameter for Accepting ICMP Redirects by Default on IPv6 Interfaces - - Oracle Linux 9 - - The kernel 'net.ipv6.conf.default.accept_redirects' parameter should be set to the appropriate value in the system runtime. - - - - - - - - - Disable Kernel Parameter for Accepting ICMP Redirects by Default on IPv6 Interfaces - - Oracle Linux 9 - - The kernel 'net.ipv6.conf.default.accept_redirects' parameter should be set to the appropriate value in the system configuration. - - - - - - - - - - - - - Disable Kernel Parameter for Accepting Source-Routed Packets on IPv6 Interfaces by Default - - Oracle Linux 9 - - The kernel 'net.ipv6.conf.default.accept_source_route' parameter should be set to the appropriate value in both system configuration and system runtime. - - - - - - - - - - - - - Disable Kernel Parameter for Accepting Source-Routed Packets on IPv6 Interfaces by Default - - Oracle Linux 9 - - The kernel 'net.ipv6.conf.default.accept_source_route' parameter should be set to the appropriate value in the system runtime. - - - - - - - - - Disable Kernel Parameter for Accepting Source-Routed Packets on IPv6 Interfaces by Default - - Oracle Linux 9 - - The kernel 'net.ipv6.conf.default.accept_source_route' parameter should be set to the appropriate value in the system configuration. - - - - - - - - - - - - - Configure Auto Configuration on All IPv6 Interfaces By Default - - Oracle Linux 9 - - The kernel 'net.ipv6.conf.default.autoconf' parameter should be set to the appropriate value in both system configuration and system runtime. - - - - - - - - - - - - - Configure Auto Configuration on All IPv6 Interfaces By Default - - Oracle Linux 9 - - The kernel 'net.ipv6.conf.default.autoconf' parameter should be set to the appropriate value in the system runtime. - - - - - - - - - Configure Auto Configuration on All IPv6 Interfaces By Default - - Oracle Linux 9 - - The kernel 'net.ipv6.conf.default.autoconf' parameter should be set to the appropriate value in the system configuration. - - - - - - - - - - - - - Disable IPv6 Addressing on IPv6 Interfaces by Default - - Oracle Linux 9 - - The kernel 'net.ipv6.conf.default.disable_ipv6' parameter should be set to the appropriate value in both system configuration and system runtime. - - - - - - - - - - - - - Disable IPv6 Addressing on IPv6 Interfaces by Default - - Oracle Linux 9 - - The kernel 'net.ipv6.conf.default.disable_ipv6' parameter should be set to 1 in the system runtime. - - - - - - - - - Disable IPv6 Addressing on IPv6 Interfaces by Default - - Oracle Linux 9 - - The kernel 'net.ipv6.conf.default.disable_ipv6' parameter should be set to 1 in the system configuration. - - - - - - - - - - - - - Configure Maximum Number of Autoconfigured Addresses on All IPv6 Interfaces By Default - - Oracle Linux 9 - - The kernel 'net.ipv6.conf.default.max_addresses' parameter should be set to the appropriate value in both system configuration and system runtime. - - - - - - - - - - - - - Configure Maximum Number of Autoconfigured Addresses on All IPv6 Interfaces By Default - - Oracle Linux 9 - - The kernel 'net.ipv6.conf.default.max_addresses' parameter should be set to the appropriate value in the system runtime. - - - - - - - - - Configure Maximum Number of Autoconfigured Addresses on All IPv6 Interfaces By Default - - Oracle Linux 9 - - The kernel 'net.ipv6.conf.default.max_addresses' parameter should be set to the appropriate value in the system configuration. - - - - - - - - - - - - - Configure Denying Router Solicitations on All IPv6 Interfaces By Default - - Oracle Linux 9 - - The kernel 'net.ipv6.conf.default.router_solicitations' parameter should be set to the appropriate value in both system configuration and system runtime. - - - - - - - - - - - - - Configure Denying Router Solicitations on All IPv6 Interfaces By Default - - Oracle Linux 9 - - The kernel 'net.ipv6.conf.default.router_solicitations' parameter should be set to the appropriate value in the system runtime. - - - - - - - - - Configure Denying Router Solicitations on All IPv6 Interfaces By Default - - Oracle Linux 9 - - The kernel 'net.ipv6.conf.default.router_solicitations' parameter should be set to the appropriate value in the system configuration. - - - - - - - - - - - - - Disable the use of user namespaces - - Oracle Linux 9 - - The 'user.max_user_namespaces' kernel parameter should be set to the appropriate value in both system configuration and system runtime. - - - - - - - - - - Disable the use of user namespaces - - Oracle Linux 9 - - The kernel 'user.max_user_namespaces' parameter should be set to 0 in the system runtime. - - - - - - - - - Disable the use of user namespaces - - Oracle Linux 9 - - The kernel 'user.max_user_namespaces' parameter should be set to 0 in the system configuration. - - - - - - - - - - - - - Prevent applications from mapping low portion of virtual memory - - Oracle Linux 9 - - The 'vm.mmap_min_addr' kernel parameter should be set to the appropriate value in both system configuration and system runtime. - - - - - - - - - - Prevent applications from mapping low portion of virtual memory - - Oracle Linux 9 - - The kernel 'vm.mmap_min_addr' parameter should be set to 65536 in the system runtime. - - - - - - - - - Prevent applications from mapping low portion of virtual memory - - Oracle Linux 9 - - The kernel 'vm.mmap_min_addr' parameter should be set to 65536 in the system configuration. - - - - - - - - - - - - - Enable dnf-automatic Timer - - Oracle Linux 9 - - The dnf-automatic timer should be enabled if possible. - - - - - - - - - - - - - Enable logrotate Timer - - Oracle Linux 9 - - The logrotate timer should be enabled if possible. - - - - - - - - - - - - - Check pam_faillock Existence in system-auth - - Oracle Linux 9 - - Check that pam_faillock.so exists in system-auth - - - - - - - - - Check pam_pwquality Existence in system-auth - - Oracle Linux 9 - - Check that pam_pwquality.so exists in system-auth - - - - - - - - - Record Any Attempts to Run semanage - - Oracle Linux 9 - - Test if auditctl is in use for audit rules. - - - - - - - - - Record Any Attempts to Run semanage - - Oracle Linux 9 - - Test if augenrules is enabled for audit rules. - - - - - - - - - Record Events that Modify the System's Network Environment - - Oracle Linux 9 - - The network environment should not be modified by anything other than - administrator action. Any change to network parameters should be audited. - - - - - - - - - - - - - - - - - - - - - - - - Record Events that Modify the System's Network Environment - - Oracle Linux 9 - - The network environment should not be modified by anything other than - administrator action. Any change to network parameters should be audited. - - - - - - - - - - - - - - - - - - - - - - - - 'log_file' Not Set In /etc/audit/auditd.conf - - Oracle Linux 9 - - Verify 'log_file' is not set in /etc/audit/auditd.conf. - - - - - - - - - 'log_group' Not Set To 'root' In /etc/audit/auditd.conf - - Oracle Linux 9 - - Verify 'log_group' is not set to 'root' in - /etc/audit/auditd.conf. - - - - - - - - - - Verify GRUB_DISABLE_RECOVERY Set to true - - Oracle Linux 9 - - GRUB_DISABLE_RECOVERY set to 'true' in - /etc/default/grub - - - - - - - - - Specify Multiple Remote chronyd NTP Servers for Time Data - - Oracle Linux 9 - - Multiple chronyd NTP Servers for time synchronization should be specified. - - - - - - - - - GRUB_CMDLINE_LINUX_DEFAULT existance check - - Oracle Linux 9 - - Check if GRUB_CMDLINE_LINUX_DEFAULT exists in /etc/default/grub. - - - - - - - - - Use $kernelopts in /boot/loader/entries/*.conf - - Oracle Linux 9 - - Ensure that grubenv-defined kernel options are referenced in individual boot loader entries - - - - - - - - - Install McAfee Host-Based Intrusion Detection Software (HBSS) - - Oracle Linux 9 - - McAfee Host-Based Intrusion Detection Software (HBSS) software - should be installed. - - - - - - - - - - - - Anolis OS 23 - - Oracle Linux 9 - - - The operating system installed on the system is Anolis OS 23 - - - - - - - - - - CentOS 7 - - Oracle Linux 9 - - - The operating system installed on the system is - CentOS 7 - - - - - - - - - - CentOS 8 - - Oracle Linux 9 - - - The operating system installed on the system is - CentOS 8 - - - - - - - - - - - CentOS Stream 9 - - Oracle Linux 9 - - - The operating system installed on the system is - CentOS Stream 9 - - - - - - - - - - - Debian - - Oracle Linux 9 - - The operating system installed is a Debian System - - - - - - - - - - Installed operating system is Fedora - - Oracle Linux 9 - - - - - - - The operating system installed on the system is Fedora - - - - - - - - - - - - - Oracle Linux 9 - - Installed OS is OL - - - - - - - - - Oracle Linux 7 - - Oracle Linux 9 - - - The operating system installed on the system is - Oracle Linux 7 - - - - - - - - - - - - Oracle Linux 8 - - Oracle Linux 9 - - - The operating system installed on the system is - Oracle Linux 8 - - - - - - - - - - - - Oracle Linux 9 - - Oracle Linux 9 - - - The operating system installed on the system is - Oracle Linux 9 - - - - - - - - - - - - openSUSE - - Oracle Linux 9 - - The operating system installed on the system is openSUSE. - - - - - - - - - - Installed operating system is part of the Unix family - - Oracle Linux 9 - - The operating system installed on the system is part of the Unix OS family - - - - - - - - - Red Hat Enterprise Linux CoreOS - - Oracle Linux 9 - - - The operating system installed on the system is - Red Hat Enterprise Linux CoreOS release 4 - - - - - - - - - - - - Red Hat Enterprise Linux CoreOS RHEL9 Based - - Oracle Linux 9 - - - The operating system installed on the system is - Red Hat Enterprise Linux CoreOS RHEL9 Based - - - - - - - - - - - Oracle Linux 9 - - Installed OS is RHEL - - - - - - - - - Red Hat Enterprise Linux 7 - - Oracle Linux 9 - - - The operating system installed on the system is - Red Hat Enterprise Linux 7 - - - - - - - - - - - - - - - - - - - Red Hat Enterprise Linux 8 - - Oracle Linux 9 - - - The operating system installed on the system is - Red Hat Enterprise Linux 8 - - - - - - - - - - - - - - - - Red Hat Enterprise Linux 8.0 - - Oracle Linux 9 - - - The operating system installed on the system is Red Hat Enterprise Linux 8.0 - - - - - - - - - Red Hat Enterprise Linux 8.1 - - Oracle Linux 9 - - - The operating system installed on the system is Red Hat Enterprise Linux 8.1 - - - - - - - - - Red Hat Enterprise Linux 8.2 - - Oracle Linux 9 - - - The operating system installed on the system is Red Hat Enterprise Linux 8.2 - - - - - - - - - Red Hat Enterprise Linux 8.3 - - Oracle Linux 9 - - - The operating system installed on the system is Red Hat Enterprise Linux 8.3 - - - - - - - - - Red Hat Enterprise Linux 8.4 - - Oracle Linux 9 - - - The operating system installed on the system is Red Hat Enterprise Linux 8.4 - - - - - - - - - Red Hat Enterprise Linux 8.5 - - Oracle Linux 9 - - - The operating system installed on the system is Red Hat Enterprise Linux 8.5 - - - - - - - - - Red Hat Enterprise Linux 8.6 - - Oracle Linux 9 - - - The operating system installed on the system is Red Hat Enterprise Linux 8.6 - - - - - - - - - Red Hat Enterprise Linux 8.7 - - Oracle Linux 9 - - - The operating system installed on the system is Red Hat Enterprise Linux 8.7 - - - - - - - - - Red Hat Enterprise Linux 8.8 - - Oracle Linux 9 - - - The operating system installed on the system is Red Hat Enterprise Linux 8.8 - - - - - - - - - Red Hat Enterprise Linux 8.9 - - Oracle Linux 9 - - - The operating system installed on the system is Red Hat Enterprise Linux 8.9 - - - - - - - - - Red Hat Enterprise Linux 8.10 - - Oracle Linux 9 - - - The operating system installed on the system is Red Hat Enterprise Linux 8.10 - - - - - - - - - Red Hat Enterprise Linux 9 - - Oracle Linux 9 - - - The operating system installed on the system is - Red Hat Enterprise Linux 9 - - - - - - - - - - - - - - - - Red Hat Virtualization 4 - - Oracle Linux 9 - - - The operating system installed on the system is - Red Hat Virtualization Host 4.4+ or Red Hat Enterprise Host. - - - - - - - - - - Scientific Linux 7 - - Oracle Linux 9 - - - The operating system installed on the system is - Scientific Linux 7 - - - - - - - - - - SUSE Linux Enterprise 12 - - Oracle Linux 9 - - - - The operating system installed on the system is - SUSE Linux Enterprise 12. - - - - - - - - - - - - - - SUSE Linux Enterprise 15 - - Oracle Linux 9 - - - - The operating system installed on the system is - SUSE Linux Enterprise 15. - - - - - - - - - - - - - - - - Ubuntu - - Oracle Linux 9 - - The operating system installed is an Ubuntu System - - - - - - - - - - - Ubuntu 16.04 LTS - - Oracle Linux 9 - - - The operating system installed on the system is Ubuntu 16.04 LTS - - - - - - - - - - Ubuntu 18.04 LTS - - Oracle Linux 9 - - - The operating system installed on the system is Ubuntu 18.04 LTS - - - - - - - - - - Ubuntu 20.04 LTS - - Oracle Linux 9 - - - The operating system installed on the system is Ubuntu 20.04 LTS - - - - - - - - - - System uses zIPL - - Oracle Linux 9 - - Checks if system uses zIPL bootloader. - - - - - - - - - - Check if the environment is a OSBuild pipeline - - Oracle Linux 9 - - Check the value of environment variable container. - - - - - - - - - - No CD/DVD drive is configured to automount in /etc/fstab - - Oracle Linux 9 - - Check the /etc/fstab and check if a CD/DVD drive - is not configured for automount. - - - - - - - - - Device Files for Removable Media Partitions Does Not Exist on the System - - Oracle Linux 9 - - Verify if device file representing removable partitions - exist on the system - - - - - - - - - SSHD is not required to be installed or requirement not set - - Oracle Linux 9 - - If SSHD is not required, we check it is not installed. If SSH requirement is unset, we are good. - - - - - - - - - - SSHD is required to be installed or requirement not set - - Oracle Linux 9 - - If SSHD is required, we check it is installed. If SSH requirement is unset, we are good. - - - - - - - - - - It doesn't matter if sshd is installed or not - - Oracle Linux 9 - - Test if value sshd_required is 0. - - - - - - - - - OpenSSH Server is 7.4 or newer - - Oracle Linux 9 - - Check if version of OpenSSH Server is equal or higher than 7.4 - - - - - - - - - Kernel Runtime Parameter IPv6 Check - - Oracle Linux 9 - - Disables IPv6 for all network interfaces. - - - - - - - - - - - - Test for 64-bit Architecture - - Oracle Linux 9 - - Generic test for 64-bit architectures to be used by other tests - - - - - - - - - - - - Test for aarch_64 Architecture - - Oracle Linux 9 - - Generic test for aarch_64 architecture to be used by other tests - - - - - - - - - Test for PPC and PPCLE Architecture - - Oracle Linux 9 - - Generic test for PPC PPC64LE architecture to be used by other tests - - - - - - - - - - Test for s390_64 Architecture - - Oracle Linux 9 - - Generic test for s390_64 architecture to be used by other tests - - - - - - - - - Test for x86 Architecture - - Oracle Linux 9 - - Generic test for x86 architecture to be used by other tests - - - - - - - - - Test for x86_64 Architecture - - Oracle Linux 9 - - Generic test for x86_64 architecture to be used by other tests - - - - - - - - - - - Oracle Linux 9 - - Check /etc/tmux.conf is readable by others - - - - - - - - - Check that file storing USBGuard rules exists and is not empty - - Oracle Linux 9 - - Check that file storing USBGuard rules at /etc/usbguard/rules.conf exists and is not empty - - - - - - - - - Value of 'var_accounts_user_umask' variable represented as octal number - - Oracle Linux 9 - - Value of 'var_accounts_user_umask' variable represented as octal number - - - - - - - - - Value of 'var_removable_partition' variable is set to '/dev/cdrom' - - Oracle Linux 9 - - Verify if value of 'var_removable_partition' variable is set - to '/dev/cdrom' - - - - - - - - - Value of 'var_umask_for_daemons' variable represented as octal number - - Oracle Linux 9 - - Value of 'var_umask_for_daemons' variable represented as octal number - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /etc/fapolicyd/compiled.rules - ^\s*deny\s*perm=any\s*all\s*:\s*all\s*\z - 1 - - - /etc/fapolicyd/fapolicyd.rules - ^\s*deny\s*perm=any\s*all\s*:\s*all\s*\z - 1 - - - /etc/fapolicyd/fapolicyd.conf - ^\s*permissive\s*=\s*(\d+) - 1 - - - /etc/aliases - ^(?:[rR][oO][oO][tT]|"[rR][oO][oO][tT]")\s*:\s*(.+)$ - 1 - - - /etc/aliases - ^(?i)postmaster\s*:\s*(.+)$ - 1 - - - /etc/postfix/main.cf - ^[\s]*inet_interfaces[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /etc/postfix/main.cf - ^[ \t]*smtpd_client_restrictions = (.+?)[ \t]*(?:$|#) - 1 - - - ^/etc/postfix/main.cf - - - /etc/exports - ^\/.*\((\S+)\)$ - 0 - - - /etc/exports - ^\/.*$ - 0 - - - /etc/chrony.conf - ^\s*port[\s]+(\S+) - 1 - - - /etc/chrony.conf - ^\s*cmdport[\s]+(\S+) - 1 - - - /etc/ntp.conf - ^server[\s]+[\S]+.*maxpoll[\s]+(\d+) - 1 - - - ^/etc/chrony\.(conf|d/.+\.conf)$ - ^(?:server|pool|peer)[\s]+[\S]+.*maxpoll[\s]+(\d+) - 1 - - - /etc/ntp.conf - ^server[\s]+[\S]+[\s]+(.*) - 1 - - - ^/etc/chrony\.(conf|d/.+\.conf)$ - ^(?:server|pool|peer)[\s]+[\S]+[\s]+(.*) - 1 - - - ^/etc/chrony\.(conf|d/.+\.conf)$ - ^(?:server|pool).* - 1 - - - /etc/ntp.conf - ^server.* - 1 - - - ^/etc/chrony\.(conf|d/.+\.conf)$ - ^[\s]*server.*$ - 1 - - - ^/etc/chrony\.(conf|d/.+\.conf)$ - ^[\s]+pool.*$ - 1 - - - ^/etc/chrony\.(conf|d/.+\.conf)$ - ^[\s]*(?:server|pool)[\s]+.+$ - 1 - - - /etc/ntp.conf - ^([\s]*server[\s]+.+$){2,}$ - 1 - - - /etc/ntp.conf - ^[\s]*server[\s]+.+$ - 1 - - - - / - shosts.equiv - - - /root - ^\.rhosts$ - - - - /home - ^\.rhosts$ - - - /etc - ^hosts\.equiv$ - - - - / - .shosts - - - /etc/xinetd.d/tftp - ^[\s]*server_args[\s]+=[\s]+.*?-s[\s]+([/\.\w]+).*$ - 1 - - - /etc/ssh - .*_key$ - oval:ssg-exclude_symlinks__sshd_private_key:ste:1 - oval:ssg-filter_ssh_key_owner_root:ste:1 - oval:ssg-filter_ssh_key_owner_ssh_keys:ste:1 - - - /etc/group - ^ssh_keys:\w+:(\w+):.* - 1 - - - /etc/ssh/ssh_config - ^[\s]*RekeyLimit.*$ - 1 - - - ^/etc/ssh/ssh_config\.d/.*\.conf$ - - 1 - - - oval:ssg-var_firewalld_sshd_port_enabled_network_conf_files_with_zone_count:var:1 - - - /etc/NetworkManager/system-connections - .*\.nmconnection - ^zone=(.*)$ - 1 - - - - /etc/NetworkManager/system-connections - .*\.nmconnection - - - /usr/lib/firewalld/zones - - /zone/service[@name='ssh'] - - - - /etc/firewalld/zones - - - - oval:ssg-var_firewalld_sshd_port_enabled_custom_zone_files_with_ssh_count:var:1 - - - /etc/firewalld/zones - ^.*\.xml$ - /zone/service[@name='ssh'] - - - - /etc/firewalld/zones - ^.*\.xml$ - - - /usr/lib/firewalld/services/ssh.xml - /service/port[@port='22'] - - - /etc/firewalld/services/ssh.xml - <port.*port="(\d+)" - 1 - - - /etc/ssh/sshd_config - ^[\s]*(?i)Protocol[\s]+2[\s]*(?:|(?:#.*))?$ - 1 - - - /etc/ssh/sshd_config - ^[ \t]*(?i)Compression(?-i)[ \t]+(.+?)[ \t]*(?:$|#) - 1 - - - /etc/ssh/sshd_config - ^[\s]*(?i)RhostsRSAAuthentication(?-i)[\s]+no[\s]*(?:#.*)?$ - 1 - - - ^\/etc\/ssh\/sshd_config.*$ - (?i)^[ ]*AllowUsers[ ]+((?:[^ \n]+[ ]*)+)$ - 1 - - - ^/etc/ssh/sshd_config.*$ - (?i)^[ ]*AllowGroups[ ]+((?:[^ \n]+[ ]*)+)$ - 1 - - - ^/etc/ssh/sshd_config.*$ - (?i)^[ ]*DenyUsers[ ]+((?:[^ \n]+[ ]*)+)$ - 1 - - - ^/etc/ssh/sshd_config.*$ - (?i)^[ ]*DenyGroups[ ]+((?:[^ \n]+[ ]*)+)$ - 1 - - - /etc/ssh/sshd_config - ^[\s]*RekeyLimit[\s]+(.*)$ - 1 - - - /etc/ssh/sshd_config - ^[\s]*(?i)ClientAliveInterval[\s]+(\d+)[\s]*(?:#.*)?$ - 1 - - - /etc/ssh/sshd_config - ^[ \t]*(?i)ClientAliveCountMax(?-i)[ \t]+(.+?)[ \t]*(?:$|#) - 1 - - - /etc/ssh/sshd_config - ^[\s]*(?i)LoginGraceTime[\s]+(\d+)[\s]*(?:#.*)?$ - 1 - - - /etc/ssh/sshd_config - ^[\s]*(?i)MaxAuthTries[\s]+(\d+)[\s]*(?:#.*)?$ - 1 - - - /etc/ssh/sshd_config - ^[\s]*(?i)MaxSessions[\s]+(\d+)[\s]*(?:#.*)?$ - 1 - - - /etc/ssh/sshd_config - (?i)^\s*MaxStartups\s+(\d+):\d+:\d+\s*$ - 1 - - - /etc/ssh/sshd_config - (?i)^\s*MaxStartups\s+\d+:(\d+):\d+\s*$ - 1 - - - /etc/ssh/sshd_config - (?i)^\s*MaxStartups\s+\d+:\d+:(\d+)\s*$ - 1 - - - /etc/ssh/sshd_config - ^[ \t]*(?i)match(?-i)\s+\S+ - 1 - - - /etc/ssh/sshd_config - ^[ \t]*(?i)UsePrivilegeSeparation(?-i)[ \t]+(.+?)[ \t]*(?:$|#) - 1 - - - ^/etc/sssd/(sssd|conf\.d/.*)\.conf$ - ^[\s]*\[sssd](?:[^\n\[]*\n+)+?[\s]*certificate_verification\s*=\s*ocsp_dgst\s*=\s*(\w+)$ - 1 - - - /etc/sssd/sssd.conf - ^[\s]*\[pam](?:[^\n\[]*\n+)+?[\s]*pam_cert_auth[\s]*=[\s]*(?i)true\s*$ - 1 - - - /etc/pam.d/smartcard-auth - ^\s*auth.*?pam_sss\.so(.*) - 1 - - - /etc/pam.d/system-auth - ^\s*auth.*?pam_sss\.so(.*) - 1 - - - /etc/sssd/sssd.conf - ^[\s]*\[pam](?:[^\n\[]*\n+)+?[\s]*offline_credentials_expiration[\s]*=[\s]*1\s*(?:#.*)?$ - 1 - - - /etc/usbguard/usbguard-daemon.conf - ^[ \t]*AuditBackend=(.+?)[ \t]*(?:$|#) - 1 - - - ^/etc/usbguard/usbguard-daemon.conf - - - xorg-x11-server-Xorg - - - xorg-x11-server-utils - - - xorg-x11-server-Xwayland - - - /etc/systemd/system/default.target - - - /etc/pam.d/fingerprint-auth - - - /etc/pam.d/password-auth - - - /etc/pam.d/postlogin - - - /etc/pam.d/smartcard-auth - - - /etc/pam.d/system-auth - - - - ^/etc/issue(\.d/.*)?$ - ^(.*)$ - 1 - - - - ^/etc/issue\.net$ - ^(.*)$ - 1 - - - /etc/dconf/db/gdm.d/ - ^.*$ - ^\[org/gnome/login-screen\]([^\n]*\n+)+?banner-message-enable=true$ - 1 - - - /etc/dconf/db/gdm.d/locks/ - ^.*$ - ^/org/gnome/login-screen/banner-message-enable$ - 1 - - - /etc/dconf/db/gdm.d/locks/ - ^.*$ - ^/org/gnome/login-screen/banner-message-text$ - 1 - - - /etc/dconf/db/gdm.d/ - ^.*$ - ^banner-message-text=[\s]*'*(.*?)'$ - 1 - - - /etc/pam.d/sudo - ^.*pam_succeed_if.*$ - 1 - - - /etc/pam.d/postlogin - ^\s*session\s+required\s+pam_lastlog\.so(?:\s+[\w=]+)*\s+showfailed(\s|$) - 1 - - - /etc/pam.d/postlogin - ^\s*session\s+.*\s+pam_lastlog\.so(?:\s+[\w=]+)*\s+silent(\s|$) - 1 - - - /etc/pam.d/password-auth|/etc/pam.d/system-auth|/etc/security/faillock.conf - ^\s*(?:auth.*pam_faillock\.so.*)?dir\s*=\s*(\S+) - 1 - - - - - - - oval:ssg-var_account_password_selinux_faillock_dir_collector:var:1 - - - /etc/pam.d/system-auth - - 1 - - - /etc/pam.d/password-auth - - 1 - - - /etc/security/faillock.conf - ^\s*audit - 1 - - - /etc/pam.d/password-auth - - 1 - - - /etc/pam.d/password-auth - - 1 - - - ^/etc/security/pwhistory.conf$ - - 1 - - - /etc/pam.d/system-auth - - 1 - - - /etc/pam.d/system-auth - - 1 - - - ^/etc/security/pwhistory.conf$ - - 1 - - - /etc/pam.d/system-auth - - 1 - - - /etc/pam.d/system-auth - - 1 - - - ^/etc/security/pwhistory.conf$ - - 1 - - - /etc/pam.d/system-auth - ^\s*password\s+(?:(?:sufficient)|(?:required))\s+pam_unix\.so.*remember=([0-9]*).*$ - 1 - - - /etc/pam.d/system-auth - - 1 - - - /etc/pam.d/password-auth - - 1 - - - /etc/security/faillock.conf - ^\s*audit - 1 - - - ^/etc/pam.d/system-auth$ - - 1 - - - ^/etc/pam.d/password-auth$ - - 1 - - - ^/etc/pam.d/system-auth$ - - 1 - - - ^/etc/pam.d/system-auth$ - - 1 - - - ^/etc/pam.d/password-auth$ - - 1 - - - ^/etc/pam.d/password-auth$ - - 1 - - - ^/etc/pam.d/system-auth$ - - 1 - - - ^/etc/pam.d/password-auth$ - - 1 - - - ^/etc/security/faillock.conf$ - - 1 - - - ^/etc/pam.d/system-auth$ - - 1 - - - ^/etc/pam.d/password-auth$ - - 1 - - - ^/etc/pam.d/system-auth$ - - 1 - - - ^/etc/pam.d/system-auth$ - - 1 - - - ^/etc/pam.d/password-auth$ - - 1 - - - ^/etc/pam.d/password-auth$ - - 1 - - - ^/etc/pam.d/system-auth$ - - 1 - - - ^/etc/pam.d/password-auth$ - - 1 - - - ^/etc/security/faillock.conf$ - - 1 - - - /etc/pam.d/system-auth - - 1 - oval:ssg-state_pam_faillock_dir_parameter_not_default_value:ste:1 - - - /etc/pam.d/password-auth - - 1 - oval:ssg-state_pam_faillock_dir_parameter_not_default_value:ste:1 - - - /etc/pam.d/system-auth - - 1 - - - oval:ssg-var_faillock_dir_set_both_preauth_authfail_system_auth:var:1 - - - oval:ssg-var_faillock_dir_set_both_preauth_authfail_password_auth:var:1 - - - /etc/security/faillock.conf - - 1 - - - ^/etc/pam.d/system-auth$ - - 1 - - - ^/etc/pam.d/password-auth$ - - 1 - - - ^/etc/pam.d/system-auth$ - - 1 - - - ^/etc/pam.d/system-auth$ - - 1 - - - ^/etc/pam.d/password-auth$ - - 1 - - - ^/etc/pam.d/password-auth$ - - 1 - - - ^/etc/pam.d/system-auth$ - - 1 - - - ^/etc/pam.d/password-auth$ - - 1 - - - ^/etc/security/faillock.conf$ - - 1 - - - ^/etc/pam.d/system-auth$ - - 1 - - - ^/etc/pam.d/password-auth$ - - 1 - - - ^/etc/pam.d/system-auth$ - - 1 - - - ^/etc/pam.d/system-auth$ - - 1 - - - ^/etc/pam.d/password-auth$ - - 1 - - - ^/etc/pam.d/password-auth$ - - 1 - - - ^/etc/pam.d/system-auth$ - - 1 - - - ^/etc/pam.d/password-auth$ - - 1 - - - ^/etc/security/faillock.conf$ - - 1 - - - /etc/pam.d/password-auth - ^password[\s]*requisite[\s]*pam_pwquality\.so - 1 - - - /etc/pam.d/system-auth - ^password[\s]*requisite[\s]*pam_pwquality\.so - 1 - - - /etc/pam.d/password-auth - ^\s*password\s+(?:(?:required)|(?:requisite))\s+pam_pwquality\.so.*retry=([0-9]*).*$ - 1 - - - /etc/pam.d/system-auth - ^\s*password\s+(?:(?:required)|(?:requisite))\s+pam_pwquality\.so.*retry=([0-9]*).*$ - 1 - - - /etc/security/pwquality.conf - ^[\s]*retry[\s]*=[\s]*(\d+)(?:[\s]|$) - 1 - - - /etc/libuser.conf - ^[\s]*crypt_style[\s]+=[\s]+(?i)sha512[\s]*$ - 1 - - - - /etc/login.defs - .*\n[^#]*(ENCRYPT_METHOD\s+\w+)\s*\n - 1 - - - oval:ssg-variable_last_encrypt_method_instance_value:var:1 - - - /etc/pam.d/password-auth - ^[\s]*password[\s]+(?:(?:required)|(?:sufficient))[\s]+pam_unix\.so[\s]+.*sha512.*$ - 1 - - - /etc/pam.d/system-auth - ^[\s]*password[\s]+(?:(?:required)|(?:sufficient))[\s]+pam_unix\.so[\s]+.*sha512.*$ - 1 - - - /etc/login.defs - ^\s*SHA_CRYPT_MIN_ROUNDS\s* - 1 - - - /etc/login.defs - ^\s*SHA_CRYPT_MIN_ROUNDS\s+(\d+)\s*$ - 1 - - - /etc/login.defs - ^\s*SHA_CRYPT_MAX_ROUNDS\s* - 1 - - - /etc/login.defs - ^\s*SHA_CRYPT_MAX_ROUNDS\s+(\d+)\s*$ - 1 - - - ^/etc/systemd/system.conf(\.d/.*\.conf)?$ - ^[\s]*CtrlAltDelBurstAction[\s]*=[\s]*none$ - 1 - - - /etc/systemd/system/ctrl-alt-del.target - - - /etc/default/grub - ^\s*GRUB_CMDLINE_LINUX="(?:.*\s)?systemd\.confirm_spawn(?:=(?:1|yes|true|on))?(?:\s.*)?"$ - 1 - - - /etc/default/grub - ^\s*GRUB_CMDLINE_LINUX_DEFAULT=".*systemd\.confirm_spawn=(?:1|yes|true|on).*$ - 1 - - - /usr/lib/systemd/system/emergency.service - ^ExecStart=\-/usr/lib/systemd/systemd-sulogin-shell[\s]+emergency - 1 - - - /usr/lib/systemd/system/emergency.target - ^Requires=.*emergency\.service - 1 - - - - /etc/systemd/system - ^emergency.service$ - - - - /etc/systemd/system - ^emergency.target$ - - - /usr/lib/systemd/system/rescue.service - ^ExecStart=\-.*/usr/lib/systemd/systemd-sulogin-shell[ ]+rescue - 1 - - - /usr/lib/systemd/system/runlevel1.target - ^Requires=.*rescue\.service - 1 - - - - /etc/systemd/system - ^rescue.service$ - - - - /etc/systemd/system - ^runlevel1.target$ - - - - ^/etc/bashrc$|^/etc/profile\.d/.*$ - if \[ "\$PS1" \]; then\n\s+parent=\$\(ps -o ppid= -p \$\$\)\n\s+name=\$\(ps -o comm= -p \$parent\)\n\s+case "\$name" in sshd\|login\) exec tmux ;; esac\nfi - 1 - - - /etc/tmux.conf - ^\s*set\s+-g\s+lock-after-time\s+(\d+)\s*(?:#.*)?$ - 1 - - - /etc/tmux.conf - ^\s*set\s+-g\s+lock-command\s+vlock\s*(?:#.*)?$ - 1 - - - /etc/shells - tmux\s*$ - 1 - - - ^/etc/opensc.*\.conf$ - ^[\s]+card_drivers[\s]+=[\s]+(\S+);$ - 1 - - - ^/etc/opensc.*\.conf$ - ^[\s]+force_card_driver[\s]+=[\s]+(\S+);$ - 1 - - - .* - - - oval:ssg-variable_count_of_all_uids:var:1 - - - /etc/passwd - ^([a-zA-Z0-9_.-]+?): - 1 - oval:ssg-state_default_os_user:ste:1 - - - /etc/group - ^.+:.+:(\d+):.*$ - 1 - - - oval:ssg-variable_count_of_all_group_ids:var:1 - - - /etc/pam.d/password-auth - ^auth\s*(?:required|requisite)\s*pam_lastlog\.so[^#]*inactive=(\d+)[\s\S]*^\s*auth\s*sufficient\s*pam_unix\.so - 1 - - - /etc/pam.d/system-auth - ^auth\s*(?:required|requisite)\s*pam_lastlog\.so[^#]*inactive=(\d+)[\s\S]*^\s*auth\s*sufficient\s*pam_unix\.so - 1 - - - /etc/default/useradd - ^\s*INACTIVE\s*=\s*(\d+)\s*$ - 1 - - - /etc/passwd - ^([^:]+):.*$ - 1 - - - oval:ssg-variable_count_of_all_usernames_from_etc_passwd:var:1 - - - /etc/login.defs - ^(?:.*\n)*\s*[^#]*(PASS_MAX_DAYS\s+\d+)\s*\n - 1 - - - oval:ssg-variable_last_pass_max_days_instance_value:var:1 - - - - /etc/login.defs - .*\n[^#]*(PASS_MIN_DAYS\s+\d+)\s*\n - 1 - - - oval:ssg-variable_last_pass_min_days_instance_value:var:1 - - - - /etc/login.defs - .*\n[^#]*(PASS_MIN_LEN\s+\d+)\s*\n - 1 - - - oval:ssg-variable_last_pass_min_len_instance_value:var:1 - - - /etc/shadow - ^(?:[^:]*:)(?:[^\!\*:]*:)(?:[^:]*:){2}(\d+):(?:[^:]*:){3}(?:[^:]*)$ - 1 - - - /etc/shadow - ^(?:[^:]*:)(?:[^\!\*:]*:)(?:[^:]*:){2}(\d+):(?:[^:]*:){3}(?:[^:]*)$ - 1 - - - /etc/shadow - ^(?:[^:]*:)(?:[^\!\*:]+:)(?:[^:]*:){2}():(?:[^:]*:){3}(?:[^:]*)$ - 1 - - - /etc/shadow - ^(?:[^:]*:)(?:[^\!\*:]*:)(?:[^:]*:)(\d+):(?:[^:]*:){4}(?:[^:]*)$ - 1 - - - /etc/shadow - ^(?:[^:]*:)(?:[^\!\*:]*:)(?:[^:]*:)(\d+):(?:[^:]*:){4}(?:[^:]*)$ - 1 - - - /etc/shadow - ^(?:[^:]*:)(?:[^\!\*:]+:)(?:[^:]*:)():(?:[^:]*:){4}(?:[^:]*)$ - 1 - - - - /etc/login.defs - .*\n[^#]*(PASS_WARN_AGE\s+\d+)\s*\n - 1 - - - oval:ssg-variable_last_pass_warn_age_instance_value:var:1 - - - .* - - - .* - oval:ssg-state_accounts_password_all_shadowed_has_no_password:ste:1 - oval:ssg-state_accounts_password_all_shadowed_has_locked_password:ste:1 - oval:ssg-state_accounts_password_all_shadowed_sha512:ste:1 - - - .* - oval:ssg-state_accounts_password_all_chage_past_has_no_password:ste:1 - - - oval:ssg-var_accounts_password_last_change_time_diff:var:1 - - - ^/etc/pam.d/password-auth$ - ^\s*password\s+(?:(?:sufficient)|(?:required))\s+pam_unix\.so.*rounds=([0-9]*).*$ - 1 - - - oval:ssg-var_password_pam_unix_rounds:var:1 - - - ^/etc/pam.d/system-auth$ - ^\s*password\s+(?:(?:sufficient)|(?:required))\s+pam_unix\.so.*rounds=([0-9]*).*$ - 1 - - - oval:ssg-var_password_pam_unix_rounds:var:1 - - - /etc/group - ^[^:]+:[^:]+:([0-9]+): - 1 - - - /etc/passwd - ^[^:]+:[^:]+:[0-9]+:([0-9]+): - 1 - - - ^/etc/pam.d/(system|password)-auth$ - ^[^#]*\bnullok\b.*$ - 1 - - - /etc/shadow - ^[^:]+::.*$ - 1 - - - - /home - ^\.netrc$ - - - /etc/passwd - ^(?!root:)[^:]*:[^:]*:0 - 1 - - - /etc/passwd - ^root:.+:\d+:(\d+).+ - 1 - - - /etc/securetty - ^.*$ - 1 - - - /etc/securetty - ^$ - 1 - - - .* - oval:ssg-state_no_password_auth_for_systemaccounts_users_uids:ste:1 - oval:ssg-state_no_password_auth_for_systemaccounts_users_ignored:ste:1 - - - - oval:ssg-filter_no_password_auth_for_systemaccounts_no_passwords_or_locked_accounts:ste:1 - - - - /etc/login.defs - .*(?:^|\n)\s*(UID_MIN[\s]+[\d]+)\s*(?:$|\n) - 1 - - - - /etc/login.defs - .*(?:^|\n)\s*(SYS_UID_MIN[\s]+[\d]+)\s*(?:$|\n) - 1 - - - - /etc/login.defs - .*(?:^|\n)\s*(SYS_UID_MAX[\s]+[\d]+)\s*(?:$|\n) - 1 - - - /etc/passwd - ^(?!root).*:x:([\d]+):[\d]+:[^:]*:[^:]*:(?!\/usr\/sbin\/nologin|\/sbin\/nologin|\/bin\/sync|\/sbin\/shutdown|\/sbin\/halt|\/bin\/false|\/usr\/bin\/false).*$ - 1 - - - /etc/securetty - ^ttyS[0-9]+$ - 1 - - - /etc/securetty - ^vc/[0-9]+$ - 1 - - - /etc/pam.d/su - ^[\s]*auth[\s]+required[\s]+pam_wheel\.so[\s]+use_uid$ - 1 - - - /etc/login.defs - ^[\s]*(?i)CREATE_HOME(?-i)[\s]+yes[\s]*(?:#.*)?$ - 1 - - - /etc/login.defs - ^[\s]*(?i)FAIL_DELAY(?-i)[\s]+([^#\s]*) - 1 - - - /etc/security/limits.conf - ^[\s]*\*[\s]+(?:(?:hard)|(?:-))[\s]+maxlogins[\s]+(\d+)\s*$ - 1 - - - /etc/security/limits.d - ^.*\.conf$ - ^[\s]*\*[\s]+(?:(?:hard)|(?:-))[\s]+maxlogins[\s]+(\d+)\s*$ - 1 - - - /etc/security/limits.d - ^.*\.conf$ - ^[\s]*\*[\s]+(?:(?:hard)|(?:-))[\s]+maxlogins - 1 - - - /tmp/tmp-inst - - - - /etc/security/namespace.conf - ^\s*/tmp\s+/tmp/tmp-inst/\s+level\s+root,adm$ - 1 - - - /var/tmp/tmp-inst - - - - /etc/security/namespace.conf - ^\s*/var/tmp\s+/var/tmp/tmp-inst/\s+level\s+root,adm$ - 1 - - - /etc/profile - ^[\s]*declare[\s]+-xr[\s]+TMOUT=([\w$]+).*$ - 1 - - - /etc/profile.d - ^.*\.sh$ - ^[\s]*declare[\s]+-xr[\s]+TMOUT=([\w$]+).*$ - 1 - - - - oval:ssg-object_etc_profile_tmout:obj:1 - oval:ssg-object_etc_profiled_tmout:obj:1 - - - - oval:ssg-variable_count_of_tmout_instances:var:1 - - - .* - oval:ssg-state_accounts_user_dot_no_world_writable_programs_users_uids:ste:1 - oval:ssg-state_accounts_user_dot_no_world_writable_programs_users_ignored:ste:1 - oval:ssg-state_accounts_user_dot_no_world_writable_programs_users_nologin_shell:ste:1 - - - - / - ^.*$ - oval:ssg-state_world_writable_programs:ste:1 - - - - - - 1 - - - .* - oval:ssg-state_accounts_user_interactive_home_directory_defined_users_uids:ste:1 - oval:ssg-state_accounts_user_interactive_home_directory_defined_users_ignored:ste:1 - oval:ssg-state_accounts_user_interactive_home_directory_defined_users_nologin_shell:ste:1 - - - /etc/passwd - - 1 - - - /etc/passwd - ^([^:]*):[^:]*:\d{4,}:(?:[^:]*:){3}(?!\/sbin\/nologin)[^:]*$ - 1 - oval:ssg-state_object_accounts_user_interactive_home_directory_exists_objects_users_ignored:ste:1 - - - - - - - oval:ssg-var_accounts_user_interactive_home_directory_exists_dirs_count_fs:var:1 - - - oval:ssg-var_accounts_user_interactive_home_directory_exists_dirs_count:var:1 - - - /etc/passwd - - 1 - - - /etc/passwd - ^([^:]*):[^:]*:\d{4,}:(?:[^:]*:){3}(?!\/sbin\/nologin)[^:]*$ - 1 - oval:ssg-state_object_file_groupownership_home_directories_home_dirs_users_ignored:ste:1 - - - /etc/passwd - - 1 - - - /etc/passwd - ^([^:]*):[^:]*:\d{4,}:(?:[^:]*:){3}(?!\/sbin\/nologin)[^:]*$ - 1 - oval:ssg-state_object_file_groupownership_home_directories_gids_users_ignored:ste:1 - - - - - - - - - - - .* - oval:ssg-state_file_permission_user_init_files_users_uids:ste:1 - oval:ssg-state_file_permission_user_init_files_users_ignored:ste:1 - oval:ssg-state_file_permission_user_init_files_users_nologin_shell:ste:1 - - - /etc/passwd - - 1 - - - /etc/passwd - ^([^:]*):[^:]*:\d{4,}:(?:[^:]*:){3}(?!\/sbin\/nologin)[^:]*$ - 1 - oval:ssg-state_object_file_permissions_home_directories_objects_users_ignored:ste:1 - - - - - - - .* - oval:ssg-state_file_permissions_home_dirs_users_uids:ste:1 - oval:ssg-state_file_permissions_home_dirs_users_ignored:ste:1 - oval:ssg-state_file_permissions_home_dirs_users_nologin_shell:ste:1 - - - - - - - - PATH - - - - - oval:ssg-state_accounts_root_path_dirs_wrong_perms:ste:1 - oval:ssg-state_accounts_root_path_dirs_symlink:ste:1 - - - - PATH - - - /etc/bashrc - ^[\s]*umask[\s]+([^#\s]*) - 1 - - - oval:ssg-var_etc_bashrc_umask_as_number:var:1 - - - /etc/csh.cshrc - ^[\s]*(?i)UMASK(?-i)[\s]+([^#\s]*) - 1 - - - oval:ssg-var_etc_csh_cshrc_umask_as_number:var:1 - - - /etc/login.defs - ^[\s]*UMASK[\s]+([^#\s]*) - 1 - - - oval:ssg-var_etc_login_defs_umask_as_number:var:1 - - - ^\/etc\/profile(?:\.d\/.*\.sh|\.d\/sh\.local)?$ - ^[\s]*umask[\s]+([^#\s]*) - 1 - - - oval:ssg-var_etc_profile_umask_as_number:var:1 - - - /etc/passwd - - 1 - - - /etc/passwd - ^([^:]*):[^:]*:\d{4,}:(?:[^:]*:){3}(?!\/sbin\/nologin)[^:]*$ - 1 - oval:ssg-state_object_accounts_umask_interactive_users_objects_users_ignored:ste:1 - - - - ^\..* - ^[\s]*umask\s* - 1 - oval:ssg-state_accounts_umask_interactive_users_bash_history:ste:1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+task,never[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+task,never[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^\-e\s+2\s*$ - 1 - - - /etc/audit/audit.rules - ^\-e\s+2\s*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^\-w[\s]+/etc/selinux/[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ - 1 - - - /etc/audit/audit.rules - ^\-w[\s]+/etc/selinux/[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^\-w[\s]+/usr/share/selinux/[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ - 1 - - - /etc/audit/audit.rules - ^\-w[\s]+/usr/share/selinux/[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^\-w[\s]+/etc/issue[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^\-w[\s]+/etc/issue\.net[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^\-w[\s]+/etc/hosts[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^\-w[\s]+/etc/sysconfig/network[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ - 1 - - - /etc/audit/audit.rules - ^\-w[\s]+/etc/issue[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ - 1 - - - /etc/audit/audit.rules - ^\-w[\s]+/etc/issue\.net[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ - 1 - - - /etc/audit/audit.rules - ^\-w[\s]+/etc/hosts[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ - 1 - - - /etc/audit/audit.rules - ^\-w[\s]+/etc/sysconfig/network[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^\-w\s+/var/run/utmp\s+\-p\s+wa\b.*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^\-w\s+/var/log/btmp\s+\-p\s+wa\b.*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^\-w\s+/var/log/wtmp\s+\-p\s+wa\b.*$ - 1 - - - /etc/audit/audit.rules - ^\-w\s+/var/run/utmp\s+\-p\s+wa\b.*$ - 1 - - - /etc/audit/audit.rules - ^\-w\s+/var/log/btmp\s+\-p\s+wa\b.*$ - 1 - - - /etc/audit/audit.rules - ^\-w\s+/var/log/wtmp\s+\-p\s+wa\b.*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^\-w[\s]+/etc/sudoers[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ - 1 - - - /etc/audit/audit.rules - ^\-w[\s]+/etc/sudoers[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^\-w[\s]+/etc/sudoers\.d/[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ - 1 - - - /etc/audit/audit.rules - ^\-w[\s]+/etc/sudoers\.d/[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+arch=b32[\s]+-S[\s]+execve[\s]+-C[\s]+uid!=euid[\s]+-F[\s]+euid=0[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+arch=b64[\s]+-S[\s]+execve[\s]+-C[\s]+uid!=euid[\s]+-F[\s]+euid=0[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+arch=b32[\s]+-S[\s]+execve[\s]+-C[\s]+uid!=euid[\s]+-F[\s]+euid=0[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+arch=b64[\s]+-S[\s]+execve[\s]+-C[\s]+uid!=euid[\s]+-F[\s]+euid=0[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+arch=b32[\s]+-S[\s]+execve[\s]+-C[\s]+gid!=egid[\s]+-F[\s]+egid=0[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+arch=b64[\s]+-S[\s]+execve[\s]+-C[\s]+gid!=egid[\s]+-F[\s]+egid=0[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+arch=b32[\s]+-S[\s]+execve[\s]+-C[\s]+gid!=egid[\s]+-F[\s]+egid=0[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+arch=b64[\s]+-S[\s]+execve[\s]+-C[\s]+gid!=egid[\s]+-F[\s]+egid=0[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^\-w[\s]+/etc/sudoers[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^\-w[\s]+/etc/sudoers\.d/[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ - 1 - - - /etc/audit/audit.rules - ^\-w[\s]+/etc/sudoers[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ - 1 - - - /etc/audit/audit.rules - ^\-w[\s]+/etc/sudoers\.d/[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^\-f\s+(\d)\s*$ - 1 - - - /etc/audit/audit.rules - ^\-f\s+(\d)\s*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^\-w[\s]+/etc/group[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^\-w[\s]+/etc/passwd[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^\-w[\s]+/etc/gshadow[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^\-w[\s]+/etc/shadow[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^\-w[\s]+/etc/security/opasswd[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ - 1 - - - /etc/audit/audit.rules - ^\-w[\s]+/etc/group[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ - 1 - - - /etc/audit/audit.rules - ^\-w[\s]+/etc/passwd[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ - 1 - - - /etc/audit/audit.rules - ^\-w[\s]+/etc/gshadow[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ - 1 - - - /etc/audit/audit.rules - ^\-w[\s]+/etc/shadow[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ - 1 - - - /etc/audit/audit.rules - ^\-w[\s]+/etc/security/opasswd[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - - 1 - - - /etc/audit/audit.rules - - 1 - - - - /var/log/audit - - oval:ssg-state_group_owner_not_root_var_log_audit_directories:ste:1 - - - - /var/log/audit - - oval:ssg-state_group_owner_not_root_var_log_audit_directories-non_root:ste:1 - - - - - - oval:ssg-state_group_owner_not_root_var_log_audit_directories:ste:1 - - - - - - - - oval:ssg-state_owner_not_root_var_log_audit_directories:ste:1 - - - /var/log/audit - - oval:ssg-state_owner_not_root_var_log_audit_directories:ste:1 - - - - - - oval:ssg-state_not_mode_0700:ste:1 - - - - /var/log/audit - - oval:ssg-state_not_mode_0700:ste:1 - - - - /var/log/audit - - oval:ssg-state_not_mode_0750:ste:1 - - - - - - oval:ssg-state_not_mode_0750:ste:1 - - - - oval:ssg-state_group_owner_not_root_var_log_audit:ste:1 - - - /var/log/audit/audit.log - oval:ssg-state_group_owner_not_root_var_log_audit:ste:1 - - - - /var/log/audit - - oval:ssg-state_owner_not_root_root_var_log_audit:ste:1 - - - - /var/log/audit - ^.*$ - oval:ssg-state_owner_not_root_root_var_log_audit:ste:1 - - - - /var/log/audit - - oval:ssg-state_owner_not_root_var_log_audit-non_root:ste:1 - - - - /var/log/audit - ^.*$ - oval:ssg-state_owner_not_root_var_log_audit-non_root:ste:1 - - - - oval:ssg-state_owner_not_root_var_log_audit:ste:1 - - - - /var/log/audit - ^.*$ - oval:ssg-state_owner_not_root_var_log_audit:ste:1 - - - - oval:ssg-state_not_mode_0600:ste:1 - - - /var/log/audit/audit.log - oval:ssg-state_not_mode_0600:ste:1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+umount[\s]+|([\s]+|[,])umount([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+umount[\s]+|([\s]+|[,])umount([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+delete_module[\s]+|([\s]+|[,])delete_module([\s]+|[,]))).*(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295))\s+(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+delete_module[\s]+|([\s]+|[,])delete_module([\s]+|[,]))).*(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295))\s+(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+delete_module[\s]+|([\s]+|[,])delete_module([\s]+|[,]))).*(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295))\s+(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+delete_module[\s]+|([\s]+|[,])delete_module([\s]+|[,]))).*(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295))\s+(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+finit_module[\s]+|([\s]+|[,])finit_module([\s]+|[,]))).*(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295))\s+(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+finit_module[\s]+|([\s]+|[,])finit_module([\s]+|[,]))).*(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295))\s+(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+finit_module[\s]+|([\s]+|[,])finit_module([\s]+|[,]))).*(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295))\s+(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+finit_module[\s]+|([\s]+|[,])finit_module([\s]+|[,]))).*(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295))\s+(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+init_module[\s]+|([\s]+|[,])init_module([\s]+|[,]))).*(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295))\s+(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+init_module[\s]+|([\s]+|[,])init_module([\s]+|[,]))).*(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295))\s+(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+init_module[\s]+|([\s]+|[,])init_module([\s]+|[,]))).*(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295))\s+(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+init_module[\s]+|([\s]+|[,])init_module([\s]+|[,]))).*(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295))\s+(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^(?!/proc(/.*|$)).*$ - oval:ssg-state_audit_rules_privileged_commands_dev_partitons:ste:1 - oval:ssg-state_audit_rules_privileged_commands_nosuid_partitons:ste:1 - oval:ssg-state_audit_rules_privileged_commands_noexec_partitons:ste:1 - - - - - ^\w+ - oval:ssg-state_setuid_or_setgid_set:ste:1 - - - oval:ssg-var_audit_rules_privileged_commands_priv_cmds_count:var:1 - - - ^/etc/audit/rules\.d/.*\.rules$ - - 1 - oval:ssg-state_unprivileged_commands:ste:1 - - - /etc/audit/audit.rules - - 1 - oval:ssg-state_unprivileged_commands:ste:1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+arch=b32.*(-S[\s]+adjtimex[\s]+|([\s]+|[,])adjtimex([\s]+|[,])).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+arch=b64.*(-S[\s]+adjtimex[\s]+|([\s]+|[,])adjtimex([\s]+|[,])).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+arch=b32.*(-S[\s]+adjtimex[\s]+|([\s]+|[,])adjtimex([\s]+|[,])).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+arch=b64.*(-S[\s]+adjtimex[\s]+|([\s]+|[,])adjtimex([\s]+|[,])).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+arch=b32[\s]+(-S[\s]+clock_settime[\s]+|([\s]+|[,])clock_settime([\s]+|[,]))-F[\s]+a0=(?:0x)?0[\s]+(?:-F[\s]+key=|-k[\s]+)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+arch=b64[\s]+(-S[\s]+clock_settime[\s]+|([\s]+|[,])clock_settime([\s]+|[,]))-F[\s]+a0=(?:0x)?0[\s]+(?:-F[\s]+key=|-k[\s]+)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+arch=b32[\s]+(-S[\s]+clock_settime[\s]+|([\s]+|[,])clock_settime([\s]+|[,]))-F[\s]+a0=(?:0x)?0[\s]+(?:-F[\s]+key=|-k[\s]+)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+arch=b64[\s]+(-S[\s]+clock_settime[\s]+|([\s]+|[,])clock_settime([\s]+|[,]))-F[\s]+a0=(?:0x)?0[\s]+(?:-F[\s]+key=|-k[\s]+)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+arch=b32.*(-S[\s]+settimeofday[\s]+|([\s]+|[,])settimeofday([\s]+|[,])).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+arch=b64.*(-S[\s]+settimeofday[\s]+|([\s]+|[,])settimeofday([\s]+|[,])).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+arch=b32.*(-S[\s]+settimeofday[\s]+|([\s]+|[,])settimeofday([\s]+|[,])).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+arch=b64.*(-S[\s]+settimeofday[\s]+|([\s]+|[,])settimeofday([\s]+|[,])).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+arch=b32.*(-S[\s]+stime[\s]+|([\s]+|[,])stime([\s]+|[,])).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+arch=b32.*(-S[\s]+stime[\s]+|([\s]+|[,])stime([\s]+|[,])).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-w[\s]+\/etc\/localtime[\s]+-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-w[\s]+\/etc\/localtime[\s]+-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ - 1 - - - /etc/audit/plugins.d/syslog.conf - ^[ ]*active[ ]+=[ ]+yes[ ]*$ - 1 - - - /etc/audit/auditd.conf - ^[ ]*disk_error_action[ ]+=[ ]+(\S+)[ ]*$ - 1 - - - /etc/audit/auditd.conf - ^[ ]*disk_error_action[ ]+=[ ]+(\S+)[ ]*$ - 1 - - - /etc/audit/auditd.conf - ^[ ]*disk_full_action[ ]+=[ ]+(\S+)[ ]*$ - 1 - - - /etc/audit/auditd.conf - ^[ ]*disk_full_action[ ]+=[ ]+(\S+)[ ]*$ - 1 - - - /etc/audit/auditd.conf - ^[ ]*action_mail_acct[ ]+=[ ]+(\S+)[ ]*$ - 1 - - - /etc/audit/auditd.conf - ^[ ]*admin_space_left_action[ ]+=[ ]+(\S+)[ ]*$ - 1 - - - /etc/audit/auditd.conf - ^[\s]*admin_space_left[\s]+=[\s]+(\d+)%[\s]*$ - 1 - - - /etc/audit/auditd.conf - ^[ ]*flush[ ]+=[ ]+(\S+)[ ]*$ - 1 - - - /etc/audit/auditd.conf - ^[ ]*max_log_file[ ]+=[ ]+(\d+)[ ]*$ - 1 - - - /etc/audit/auditd.conf - ^[ ]*max_log_file_action[ ]+=[ ]+(\S+)[ ]*$ - 1 - - - /etc/audit/auditd.conf - ^[ ]*max_log_file_action[ ]+=[ ]+(\S+)[ ]*$ - 1 - - - /etc/audit/auditd.conf - ^[ ]*num_logs[ ]+=[ ]+(\d+)[ ]*$ - 1 - - - /etc/audit/auditd.conf - ^[ ]*space_left_action[ ]+=[ ]+(\S+)[ ]*$ - 1 - - - /etc/audit/auditd.conf - ^[\s]*space_left[\s]+=[\s]+(\d+)%[\s]*$ - 1 - - - /etc/audit/auditd.conf - ^[ \t]*(?i)name_format(?-i)[ \t]*=[ \t]*(.+?)[ \t]*(?:$|#) - 1 - - - /etc/audit/auditd.conf - ^[ \t]*(?i)overflow_action(?-i)[ \t]*=[ \t]*(.+?)[ \t]*(?:$|#) - 1 - - - .* - - - /boot/grub2/grub.cfg - ^[\s]*set[\s]+superusers="(?i)\b(?!(?:root|admin|administrator)\b)(\w+)"$ - 1 - - - /boot/grub2/user.cfg - ^[\s]*GRUB2_PASSWORD=grub\.pbkdf2\.sha512.*$ - 1 - - - .* - - - /boot/grub2/grub.cfg - ^[\s]*set[\s]+superusers="(?i)\b(?!(?:root|admin|administrator)\b)(\w+)"$ - 1 - - - /boot/grub2/user.cfg - ^[\s]*GRUB2_PASSWORD=grub\.pbkdf2\.sha512.*$ - 1 - - - /etc/rsyslog.conf - ^[\s]*cron\.\*[\s]+/var/log/cron\s*(?:#.*)?$ - 1 - - - /etc/rsyslog.d - ^.*$ - ^[\s]*cron\.\*[\s]+/var/log/cron\s*(?:#.*)?$ - 1 - - - /etc/rsyslog.conf - ^\$ActionSendStreamDriverAuthMode x509/name$ - 1 - - - /etc/rsyslog.d - ^.*conf$ - ^\$ActionSendStreamDriverAuthMode x509/name$ - 1 - - - /etc/rsyslog.conf - ^\$ActionSendStreamDriverMode 1$ - 1 - - - /etc/rsyslog.d - ^.*conf$ - ^\$ActionSendStreamDriverMode 1$ - 1 - - - /etc/rsyslog.conf - ^\$DefaultNetstreamDriver gtls$ - 1 - - - /etc/rsyslog.d - ^.*conf$ - ^\$DefaultNetstreamDriver gtls$ - 1 - - - ^/etc/rsyslog\.(conf|d/.+\.conf)$ - ^[^#]*auth\.\*.*$ - 1 - - - ^/etc/rsyslog\.(conf|d/.+\.conf)$ - ^[^#]*authpriv\.\*.*$ - 1 - - - ^/etc/rsyslog\.(conf|d/.+\.conf)$ - ^[^#]*daemon\.\*.*$ - 1 - - - /etc/logrotate.conf - ^\s*daily[\s#]*$ - 1 - - - /etc/logrotate.conf - ^\s*(weekly|monthly|yearly)[\s#]*$ - 1 - - - /etc/cron.daily/logrotate - ^[\s]*/usr/sbin/logrotate[\s\S]*/etc/logrotate.conf$ - 1 - - - ^\/etc\/rsyslog(\.conf|\.d\/.*\.conf)$ - ^[\s]*\$((?:Input(?:TCP|RELP)|UDP)ServerRun|ModLoad[\s]+(imtcp|imudp|imrelp)) - 1 - - - ^\/etc\/rsyslog(\.conf|\.d\/.*\.conf)$ - ^\s*(?:module|input)\((?:load|type)="(imtcp|imudp)".*$ - 1 - - - /etc/rsyslog.conf - ^\*\.\*[\s]+(?:@|\:omrelp\:) - 1 - - - /etc/rsyslog.d - ^.+\.conf$ - ^\*\.\*[\s]+(?:@|\:omrelp\:) - 1 - - - - ^/etc/rsyslog\.(conf|d/.+\.conf)$ - ^\s*action\((?i)type(?-i)="omfwd"(.+?)\) - 0 - - - ^/etc/rsyslog\.(conf|d/.+\.conf)$ - ^\s*global\(DefaultNetstreamDriverCAFile="(.+?)"\)\s*\n - 0 - - - /etc/resolv.conf - ^[\s]*nameserver[\s]+([0-9\.]+)$ - 1 - - - /etc/nsswitch.conf - ^\s*hosts\s*:\s*.*dns.*$ - 1 - - - /etc/resolv.conf - - - ^.*$ - oval:ssg-state_promisc:ste:1 - - - /etc/firewalld/firewalld.conf - ^DefaultZone=drop$ - 1 - - - /etc/modprobe.d - ^.*\.conf$ - ^\s*options\s+ipv6\s+.*disable=1.*$ - 1 - - - ^wl.*$ - - - - / - - oval:ssg-state_uid_is_not_root_and_world_writable:ste:1 - - - - / - - oval:ssg-state_world_writable_and_not_sticky:ste:1 - - - /boot - ^System\.map.*$ - - - - / - ^.*$ - oval:ssg-state_file_permissions_unauthorized_sgid_sgid_set:ste:1 - oval:ssg-state_file_permissions_unauthorized_sgid_filepaths:ste:1 - - - - .* - .* - .* - .* - .* - - - - - / - ^.*$ - oval:ssg-state_file_permissions_unauthorized_sgid_sgid_set:ste:1 - - - - / - ^.*$ - oval:ssg-state_file_permissions_unauthorized_suid_suid_set:ste:1 - oval:ssg-state_file_permissions_unauthorized_suid_filepaths:ste:1 - - - - .* - .* - .* - .* - .* - - - - - / - ^.*$ - oval:ssg-state_file_permissions_unauthorized_suid_suid_set:ste:1 - - - - / - ^.*$ - oval:ssg-state_file_permissions_unauthorized_world_write:ste:1 - oval:ssg-state_file_permissions_unauthorized_world_write_exclude_special_selinux_files:ste:1 - oval:ssg-state_file_permissions_unauthorized_world_write_exclude_proc:ste:1 - oval:ssg-state_file_permissions_unauthorized_world_write_exclude_sys:ste:1 - - - - / - .* - oval:ssg-state_file_permissions_ungroupowned:ste:1 - - - /etc/group - ^[^:]+:[^:]*:([\d]+):[^:]*$ - 1 - - - .* - - - - / - .* - oval:ssg-file_permissions_unowned_userid_list_match:ste:1 - - - ^\/s?bin|^\/usr\/s?bin|^\/usr\/local\/s?bin - ^.*$ - oval:ssg-state_groupowner_system_commands_dirs_not_root_or_system_account:ste:1 - - - ^\/(|s)bin|^\/usr\/(|local\/)(|s)bin|^\/usr\/libexec - - oval:ssg-state_owner_binaries_not_root:ste:1 - - - ^\/(|s)bin|^\/usr\/(|local\/)(|s)bin|^\/usr\/libexec - ^.*$ - oval:ssg-state_owner_binaries_not_root:ste:1 - - - ^\/(|s)bin|^\/usr\/(|local\/)(|s)bin|^\/usr\/libexec - ^.*$ - oval:ssg-state_perms_binary_files_nogroupwrite_noworldwrite:ste:1 - oval:ssg-state_perms_binary_files_symlink:ste:1 - - - ^/\w.*$ - oval:ssg-state_local_nodev:ste:1 - - - /etc/systemd/coredump.conf - ^\s*\[Coredump\].*(?:\n\s*[^[\s].*)*\n^[ \t]*(?i)ProcessSizeMax(?-i)[ \t]*=[ \t]*(.+?)[ \t]*(?:$|#) - 1 - - - /etc/systemd/coredump.conf.d - .*\.conf$ - ^\s*\[Coredump\].*(?:\n\s*[^[\s].*)*\n^[ \t]*(?i)ProcessSizeMax(?-i)[ \t]*=[ \t]*(.+?)[ \t]*(?:$|#) - 1 - - - /etc/systemd/coredump.conf - ^\s*\[Coredump\].*(?:\n\s*[^[\s].*)*\n^[ \t]*(?i)Storage(?-i)[ \t]*=[ \t]*(.+?)[ \t]*(?:$|#) - 1 - - - /etc/systemd/coredump.conf.d - .*\.conf$ - ^\s*\[Coredump\].*(?:\n\s*[^[\s].*)*\n^[ \t]*(?i)Storage(?-i)[ \t]*=[ \t]*(.+?)[ \t]*(?:$|#) - 1 - - - /etc/security/limits.conf - ^[\s]*\*[\s]+(?:hard|-)[\s]+core[\s]+([\d]+) - 1 - - - /etc/security/limits.d - ^.*\.conf$ - ^[\s]*\*[\s]+(?:hard|-)[\s]+core[\s]+([\d]+) - 1 - - - /etc/security/limits.d - ^.*\.conf$ - ^[\s]*\*[\s]+(?:hard|-)[\s]+core - 1 - - - /proc/cpuinfo - ^flags[\s]+:.*[\s]+nx[\s]+.*$ - 1 - - - /proc/cmdline - .+noexec[0-9]*=off.+ - 1 - - - /etc/default/grub - ^[\s]*GRUB_CMDLINE_LINUX.*(selinux|enforcing)=0.*$ - 1 - - - /etc/grub2.cfg - ^.*(selinux|enforcing)=0.*$ - 1 - - - /etc/grub.d - ^.*$ - ^.*(selinux|enforcing)=0.*$ - 1 - - - - /proc - ^.*$ - oval:ssg-state_selinux_confinement_of_daemons:ste:1 - - - /etc/selinux/config - ^SELINUX=(.*)$ - 1 - - - /etc/selinux/config - ^SELINUXTYPE=([\w]*)[\s]*$ - 1 - - - /etc/selinux/config - ^SELINUX=(.*)$ - 1 - - - kernel - - - /proc/cpuinfo - ^flags\s+:\s+(.*)$ - 1 - - - /proc/sys/kernel/osrelease - ^.*\.(.*)$ - 1 - - - /etc/dconf/db/gdm - - - ^/etc/dconf/db/gdm.d/.* - - - oval:ssg-var_dconf_gdm_db_modified_time:var:1 - - - /etc/dconf/db/local - - - ^/etc/dconf/db/local.d/.* - - - oval:ssg-var_dconf_local_db_modified_time:var:1 - - - /etc/dconf/profile/user - ^user-db:user\nsystem-db:local$ - 1 - - - /etc/dconf/db/gdm.d/ - ^.*$ - ^\[org/gnome/login-screen\]([^\n]*\n+)+?disable-restart-buttons=true$ - 1 - - - /etc/dconf/db/gdm.d/locks/ - ^.*$ - ^/org/gnome/login-screen/disable-restart-buttons$ - 1 - - - /etc/dconf/db/gdm.d/ - ^.*$ - ^\[org/gnome/login-screen\]([^\n]*\n+)+?disable-user-list=true$ - 1 - - - /etc/dconf/db/gdm.d/locks/ - ^.*$ - ^/org/gnome/login-screen/disable-user-list$ - 1 - - - /etc/gdm/custom.conf - ^\[daemon]([^\n]*\n+)+?AutomaticLoginEnable=[Ff]alse$ - 1 - - - /etc/gdm/custom.conf - ^\s*\[xdmcp\].*(?:\n\s*[^[\s].*)*\n^\s*Enable[ \t]*=[ \t]*(.+?)[ \t]*(?:$|#) - 1 - - - ^/etc/gdm/custom.conf - - - /etc/dconf/db/local.d/ - ^.*$ - ^\[org/gnome/desktop/media-handling\]([^\n]*\n+)+?automount-open=false$ - 1 - - - /etc/dconf/db/local.d/locks/ - ^.*$ - ^/org/gnome/desktop/media-handling/automount-open$ - 1 - - - /etc/dconf/db/local.d/ - ^.*$ - ^\[org/gnome/desktop/media-handling\]([^\n]*\n+)+?autorun-never=true$ - 1 - - - /etc/dconf/db/local.d/locks/ - ^.*$ - ^/org/gnome/desktop/media-handling/autorun-never$ - 1 - - - /etc/dconf/db/local.d/ - ^.*$ - ^\[org/gnome/Vino\]([^\n]*\n+)+?authentication-methods=\['vnc'\]$ - 1 - - - /etc/dconf/db/local.d/locks/ - ^.*$ - ^/org/gnome/Vino/authentication-methods$ - 1 - - - /etc/dconf/db/local.d/ - ^.*$ - ^\[org/gnome/Vino\]([^\n]*\n+)+?require-encryption=true$ - 1 - - - /etc/dconf/db/local.d/locks/ - ^.*$ - ^/org/gnome/Vino/require-encryption$ - 1 - - - /etc/dconf/db/local.d/ - ^.*$ - ^\[org/gnome/desktop/screensaver\]([^\n]*\n+)+?idle-activation-enabled=true$ - 1 - - - /etc/dconf/db/local.d/locks/ - ^.*$ - ^/org/gnome/desktop/screensaver/idle-activation-enabled$ - 1 - - - /etc/dconf/db/local.d/ - ^.*$ - ^\[org/gnome/desktop/session\]([^\n]*\n+)+?idle-delay=uint32[\s][0-9]*$ - 1 - - - /etc/dconf/db/local.d/ - ^.*$ - ^idle-delay[\s=]*uint32[\s]([^=\s]*) - 1 - - - /etc/dconf/db/local.d/ - ^.*$ - ^\[org/gnome/desktop/screensaver\]([^\n]*\n+)+?lock-delay=uint32[\s][0-9]*$ - 1 - - - /etc/dconf/db/local.d/ - ^.*$ - ^lock-delay[\s=]*uint32[\s]([^=\s]*) - 1 - - - /etc/dconf/db/local.d/ - ^.*$ - ^\[org/gnome/desktop/screensaver\]([^\n]*\n+)+?lock-enabled=true$ - 1 - - - /etc/dconf/db/local.d/locks/ - ^.*$ - ^/org/gnome/desktop/screensaver/lock-enabled$ - 1 - - - /etc/dconf/db/local.d/locks/ - ^.*$ - ^/org/gnome/desktop/screensaver/lock-enabled$ - 1 - - - /etc/dconf/db/local.d/ - ^.*$ - ^\[org/gnome/desktop/screensaver\]([^\n]*\n+)+?picture-uri=string \'\'$ - 1 - - - /etc/dconf/db/local.d/locks/ - ^.*$ - ^/org/gnome/desktop/screensaver/picture-uri$ - 1 - - - /etc/dconf/db/local.d/locks/ - ^.*$ - ^/org/gnome/desktop/screensaver/lock-delay$ - 1 - - - /etc/dconf/db/local.d/locks/ - ^.*$ - ^/org/gnome/desktop/session/idle-delay$ - 1 - - - /etc/dconf/db/local.d/ - ^.*$ - ^\[org/gnome/settings-daemon/plugins/media-keys\]([^\n]*\n+)+?logout[\s]*=[\s]*''$ - 1 - - - /etc/dconf/db/local.d/locks/ - ^.*$ - ^/org/gnome/settings-daemon/plugins/media-keys/logout$ - 1 - - - /etc/named.conf - ^\s*include\s+"/etc/crypto-policies/back-ends/bind.config"\s*;\s*$ - 1 - - - /etc/crypto-policies/state/current - - - /etc/crypto-policies/config - - - oval:ssg-variable_crypto_policies_config_file_timestamp:var:1 - - - /etc/crypto-policies/config - ^(?!#)(\S+)$ - 1 - - - /etc/crypto-policies/state/current - ^(?!#)(\S+)$ - 1 - - - /etc/crypto-policies/back-ends/nss.config - - - oval:ssg-var_symlink_kerberos_crypto_policy_configuration:var:1 - - - /etc/krb5.conf.d/crypto-policies - - - /etc/crypto-policies/back-ends/krb5.config - - - /etc/ipsec.conf - ^\s*include\s+/etc/crypto-policies/back-ends/libreswan.config\s*(?:#.*)?$ - 1 - - - /etc/pki/tls/openssl.cnf - ^\s*\[\s*crypto_policy\s*\]\s*\n*\s*\.include\s*(?:=\s*)?/etc/crypto-policies/back-ends/opensslcnf.config\s*$ - 1 - - - /etc/crypto-policies/back-ends/opensslcnf.config - ^\s*(?:TLS\.)?(?i)MinProtocol\s*=\s*TLSv(\S*) - 1 - - - /etc/crypto-policies/back-ends/opensslcnf.config - ^\s*(?:DTLS\.)?(?i)MinProtocol\s*=\s*DTLSv(\S*) - 1 - - - crypto-policies - - - /etc/sysconfig/sshd - ^\s*(?i)CRYPTO_POLICY\s*=.*$ - 1 - - - /etc/ssh/ssh_config.d/02-ospp.conf - ^[ \t]*Match[\s]+(.+?)[ \t]*(?:$|#) - 1 - - - /etc/ssh/ssh_config.d/02-ospp.conf - ^Match final all(?:.* -)*?\s*RekeyLimit[\s]+(.+?)[ \t]*(?:$|#) - 1 - - - /etc/ssh/ssh_config.d/02-ospp.conf - ^Match final all(?:.* -)*?\s*GSSAPIAuthentication[\s]+(.+?)[ \t]*(?:$|#) - 1 - - - /etc/ssh/ssh_config.d/02-ospp.conf - ^Match final all(?:.* -)*?\s*Ciphers[\s]+(.+?)[ \t]*(?:$|#) - 1 - - - /etc/ssh/ssh_config.d/02-ospp.conf - ^Match final all(?:.* -)*?\s*PubkeyAcceptedKeyTypes[\s]+(.+?)[ \t]*(?:$|#) - 1 - - - /etc/ssh/ssh_config.d/02-ospp.conf - ^Match final all(?:.* -)*?\s*MACs[\s]+(.+?)[ \t]*(?:$|#) - 1 - - - /etc/ssh/ssh_config.d/02-ospp.conf - ^Match final all(?:.* -)*?\s*KexAlgorithms[\s]+(.+?)[ \t]*(?:$|#) - 1 - - - /etc/crypto-policies/back-ends/openssh.config - ^Ciphers.*$ - 1 - - - /etc/crypto-policies/back-ends/opensshserver.config - ^(?!#).*(-oCiphers=[^\s']+).*$ - 1 - - - /etc/crypto-policies/back-ends/openssh.config - ^MACs.*$ - 1 - - - /etc/crypto-policies/back-ends/opensshserver.config - ^(?!#).*(-oMACs=\S+).+$ - 1 - - - /etc/selinux/config - ^[\s]*SELINUX[\s]*=[\s]*enforcing[\s]*$ - 1 - - - McAfeeVSEForLinux - - - MFErt - - - MFEcma - - - ^mfetpd.*$ - 0 - - - /opt/McAfee/accm/bin - accm - - - /opt/McAfee/auditengine/bin - auditmanager - - - /etc/dracut.conf.d/40-fips.conf - ^\s*add_dracutmodules\+="\s*(\w*)\s*"\s*(?:#.*)?$ - 1 - - - ^/boot/loader/entries/.*.conf - ^options (.*)$ - 1 - - - oval:ssg-var_system_crypto_policy:var:1 - - - /etc/system-fips - - - crypto.fips_enabled - - - /etc/aide.conf - ^database=file:@@{DBDIR}/([a-z.]+)$ - 1 - - - /etc/aide.conf - ^@@define[\s]DBDIR[\s]+(/.*)$ - 1 - - - - - - /etc/aide.conf - ^\/usr\/sbin\/auditctl\s+([^\n]+)$ - 1 - - - /etc/aide.conf - ^/usr/sbin/auditd\s+([^\n]+)$ - 1 - - - /etc/aide.conf - ^/usr/sbin/ausearch\s+([^\n]+)$ - 1 - - - /etc/aide.conf - ^/usr/sbin/aureport\s+([^\n]+)$ - 1 - - - /etc/aide.conf - ^/usr/sbin/autrace\s+([^\n]+)$ - 1 - - - /etc/aide.conf - ^/usr/sbin/rsyslogd\s+([^\n]+)$ - 1 - - - /etc/aide.conf - ^/usr/sbin/augenrules\s+([^\n]+)$ - 1 - - - /etc/crontab - ^(([0-9]*[\s]*[0-9]*[\s]*\*[\s]*\*[\s]*(\*|([0-7]|mon|tue|wed|thu|fri|sat|sun)|[0-7]-[0-7]))|@(hourly|daily|weekly))[\s]*root[\s]*\/usr\/sbin\/aide[\s]*\-\-check.*$ - 1 - - - /etc/cron.d - ^.*$ - ^(([0-9]*[\s]*[0-9]*[\s]*\*[\s]*\*[\s]*(\*|([0-7]|mon|tue|wed|thu|fri|sat|sun)|[0-7]-[0-7]))|@(hourly|daily|weekly))[\s]*root[\s]*\/usr\/sbin\/aide[\s]*\-\-check.*$ - 1 - - - /var/spool/cron/root - ^(([0-9]*[\s]*[0-9]*[\s]*\*[\s]*\*[\s]*(\*|([0-7]|mon|tue|wed|thu|fri|sat|sun)|[0-7]-[0-7]))|@(hourly|daily|weekly))[\s]*(root)?[\s]*\/usr\/sbin\/aide[\s]*\-\-check.*$ - 1 - - - ^/etc/cron.(daily|weekly)$ - ^.*$ - ^[^#]*\/usr\/sbin\/aide\s+\-\-check\s*$ - 1 - - - /etc/crontab - ^.*/usr/sbin/aide[\s]*\-\-check.*\|.*/bin/mail[\s]*-s[\s]*".*"[\s]*.+@.+$ - 1 - - - /var/spool/cron/root - ^.*/usr/sbin/aide[\s]*\-\-check.*\|.*/bin/mail[\s]*-s[\s]*".*"[\s]*.+@.+$ - 1 - - - ^/etc/cron.(d|daily|weekly|monthly)$ - ^.*$ - ^.*/usr/sbin/aide[\s]*\-\-check.*\|.*/bin/mail[\s]*-s[\s]*".*"[\s]*.+@.+$ - 1 - - - /etc/aide.conf - ^(?!ALLXTRAHASHES)[A-Z][a-zA-Z_]*[\s]*=[\s]*([a-zA-Z0-9\+]*)$ - 1 - - - /etc/aide.conf - ^(?!ALLXTRAHASHES)[A-Z][a-zA-Z_]*[\s]*=[\s]*([a-zA-Z0-9\+]*)$ - 1 - - - - .* - .* - .* - .* - .* - ^/(bin|sbin|lib|lib64|usr)/.+$ - oval:ssg-state_files_fail_md5_hash:ste:1 - - - - .* - .* - .* - .* - .* - .* - oval:ssg-state_files_fail_user_ownership:ste:1 - - - - .* - .* - .* - .* - .* - .* - oval:ssg-state_files_fail_group_ownership:ste:1 - - - - .* - .* - .* - .* - .* - .* - oval:ssg-state_files_fail_mode:ste:1 - - - /etc/sudoers - ^(?!#).*[\s]+\!authenticate.*$ - 1 - - - /etc/sudoers.d - ^.*$ - ^(?!#).*[\s]+\!authenticate.*$ - 1 - - - /etc/sudoers - ^(?!#).*[\s]+NOPASSWD[\s]*\:.*$ - 1 - - - /etc/sudoers.d - ^.*$ - ^(?!#).*[\s]+NOPASSWD[\s]*\:.*$ - 1 - - - ^\/etc\/(sudoers|sudoers\.d\/.*)$ - ^[\s]*Defaults[\s]+timestamp_timeout[\s]*=\s*[+]?(\d*\.\d+|\d+\.\d*|\d+)$ - 1 - - - ^\/etc\/(sudoers|sudoers\.d\/.*)$ - ^[\s]*Defaults[\s]+timestamp_timeout[\s]*=\s*[\-](\d*\.\d+|\d+\.\d*|\d+)$ - 1 - - - ^/etc/sudoers(\.d/.*)?$ - ^\s*ALL\s+ALL\=\(ALL\)\s+ALL\s*$ - 1 - - - ^/etc/sudoers(\.d/.*)?$ - ^\s*ALL\s+ALL\=\(ALL\:ALL\)\s+ALL\s* - 1 - - - /etc/sudoers - ^(?!(#|vdsm.*)).*[\s]+NOPASSWD[\s]*\:.*$ - 1 - - - /etc/sudoers.d - ^.*$ - ^(?!(#|vdsm.*)).*[\s]+NOPASSWD[\s]*\:.*$ - 1 - - - ^/etc/sudoers(\.d/.*)?$ - ^(?:\s*[^#=]+)=(?:\s*(?:\([^\)]+\))?\s*(?!\s*\()[^,\s]+(?:[ \t]+[^,\s]+)+[ \t]*,)*(\s*(?:\([^\)]+\))?\s*(?!\s*\()[^,\s]+[ \t]*(?:,|$)) - 1 - - - ^/etc/sudoers(\.d/.*)?$ - ^(?:\s*[^#=]+)=(?:\s*(?:\([^\)]+\))?\s*(?!\s*\()[^,!\n][^,\n]+,)*\s*(?:\([^\)]+\))?\s*(?!\s*\()(!\S+).* - 1 - - - ^/etc/sudoers(\.d/.*)?$ - ^\s*((?!root\b)[\w]+)\s*(\w+)\s*=\s*(.*,)?\s*\([\w\s]*\b(root|ALL)\b[\w\s]*\) - 1 - - - ^/etc/sudoers(\.d/.*)?$ - ^\s*((?!root\b)[\w]+)\s*(\w+)\s*=\s*(.*,)?\s*[^\(\s] - 1 - - - ^/etc/sudoers(\.d/.*)?$ - ^Defaults !targetpw$\r?\n - 1 - - - ^/etc/sudoers(\.d/.*)?$ - ^Defaults !rootpw$\r?\n - 1 - - - ^/etc/sudoers(\.d/.*)?$ - ^Defaults !runaspw$\r?\n - 1 - - - ^/etc/sudoers(\.d/.*)?$ - ^Defaults targetpw$\r?\n - 1 - - - ^/etc/sudoers(\.d/.*)?$ - ^Defaults rootpw$\r?\n - 1 - - - ^/etc/sudoers(\.d/.*)?$ - ^Defaults runaspw$\r?\n - 1 - - - /etc/yum.conf - ^\s*clean_requirements_on_remove\s*=\s*(1|True|yes)\s*$ - 1 - - - /etc/dnf/automatic.conf - ^\s*\[commands\].*(?:\n\s*[^[\s].*)*\n^\s*apply_updates[ \t]*=[ \t]*(.+?)[ \t]*(?:$|#) - 1 - - - ^/etc/dnf/automatic.conf - - - /etc/dnf/automatic.conf - ^\s*\[commands\].*(?:\n\s*[^[\s].*)*\n^\s*upgrade_type[ \t]*=[ \t]*(.+?)[ \t]*(?:$|#) - 1 - - - ^/etc/dnf/automatic.conf - - - /etc/yum.conf - ^\s*gpgcheck\s*=\s*1\s*$ - 1 - - - /etc/yum.conf - ^\s*localpkg_gpgcheck\s*=\s*(1|True|yes)\s*$ - 1 - - - /etc/yum.repos.d - .* - ^\s*gpgcheck\s*=\s*0\s*$ - 1 - - - gpg-pubkey - - - /etc/pam.d/system-auth - ^\s*password.*pam_pwquality\.so.*\bdcredit\b - 1 - - - ^/etc/security/pwquality\.conf$ - ^\s*dcredit[\s]*=[\s]*(-?\d+)(?:[\s]|$) - 1 - - - /etc/pam.d/system-auth - ^\s*password.*pam_pwquality\.so.*\bdictcheck\b - 1 - - - ^/etc/security/pwquality\.conf$ - ^\s*dictcheck[\s]*=[\s]*(-?\d+)(?:[\s]|$) - 1 - - - /etc/pam.d/system-auth - ^\s*password.*pam_pwquality\.so.*\bdifok\b - 1 - - - ^/etc/security/pwquality\.conf$ - ^\s*difok[\s]*=[\s]*(-?\d+)(?:[\s]|$) - 1 - - - /etc/security/pwquality.conf - ^[\s]*enforce_for_root[\s]*$ - 1 - - - /etc/pam.d/system-auth - ^\s*password.*pam_pwquality\.so.*\blcredit\b - 1 - - - ^/etc/security/pwquality\.conf$ - ^\s*lcredit[\s]*=[\s]*(-?\d+)(?:[\s]|$) - 1 - - - /etc/pam.d/system-auth - ^\s*password.*pam_pwquality\.so.*\bmaxclassrepeat\b - 1 - - - ^/etc/security/pwquality\.conf$ - ^\s*maxclassrepeat[\s]*=[\s]*(-?\d+)(?:[\s]|$) - 1 - - - /etc/pam.d/system-auth - ^\s*password.*pam_pwquality\.so.*\bmaxrepeat\b - 1 - - - ^/etc/security/pwquality\.conf$ - ^\s*maxrepeat[\s]*=[\s]*(-?\d+)(?:[\s]|$) - 1 - - - /etc/pam.d/system-auth - ^\s*password.*pam_pwquality\.so.*\bminclass\b - 1 - - - ^/etc/security/pwquality\.conf$ - ^\s*minclass[\s]*=[\s]*(-?\d+)(?:[\s]|$) - 1 - - - /etc/pam.d/system-auth - ^\s*password.*pam_pwquality\.so.*\bminlen\b - 1 - - - ^/etc/security/pwquality\.conf$ - ^\s*minlen[\s]*=[\s]*(-?\d+)(?:[\s]|$) - 1 - - - /etc/pam.d/system-auth - ^\s*password.*pam_pwquality\.so.*\bocredit\b - 1 - - - ^/etc/security/pwquality\.conf$ - ^\s*ocredit[\s]*=[\s]*(-?\d+)(?:[\s]|$) - 1 - - - /etc/pam.d/system-auth - ^\s*password.*pam_pwquality\.so.*\bucredit\b - 1 - - - ^/etc/security/pwquality\.conf$ - ^\s*ucredit[\s]*=[\s]*(-?\d+)(?:[\s]|$) - 1 - - - - /etc/audit/rules.d/30-ospp-v42-3-access-failed.rules - ^.*$ - 1 - - - - /etc/audit/rules.d/30-ospp-v42-3-access-success.rules - ^.*$ - 1 - - - - /etc/audit/rules.d/10-base-config.rules - ^.*$ - 1 - - - - /etc/audit/rules.d/30-ospp-v42-1-create-failed.rules - ^.*$ - 1 - - - - /etc/audit/rules.d/30-ospp-v42-1-create-success.rules - ^.*$ - 1 - - - - /etc/audit/rules.d/30-ospp-v42-4-delete-failed.rules - ^.*$ - 1 - - - - /etc/audit/rules.d/30-ospp-v42-4-delete-success.rules - ^.*$ - 1 - - - - /etc/audit/rules.d/11-loginuid.rules - ^.*$ - 1 - - - - /etc/audit/rules.d/30-ospp-v42-2-modify-failed.rules - ^.*$ - 1 - - - - /etc/audit/rules.d/30-ospp-v42-2-modify-success.rules - ^.*$ - 1 - - - - /etc/audit/rules.d/43-module-load.rules - ^.*$ - 1 - - - - /etc/audit/rules.d/30-ospp-v42.rules - ^.*$ - 1 - - - - /etc/audit/rules.d/30-ospp-v42-6-owner-change-failed.rules - ^.*$ - 1 - - - - /etc/audit/rules.d/30-ospp-v42-6-owner-change-success.rules - ^.*$ - 1 - - - - /etc/audit/rules.d/30-ospp-v42-5-perm-change-failed.rules - ^.*$ - 1 - - - - /etc/audit/rules.d/30-ospp-v42-5-perm-change-success.rules - ^.*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/init(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/init(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/poweroff(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/poweroff(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/reboot(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/reboot(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/shutdown(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/shutdown(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+chmod[\s]+|([\s]+|[,])chmod([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+chmod[\s]+|([\s]+|[,])chmod([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+chmod[\s]+|([\s]+|[,])chmod([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+chmod[\s]+|([\s]+|[,])chmod([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+chown[\s]+|([\s]+|[,])chown([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+chown[\s]+|([\s]+|[,])chown([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+chown[\s]+|([\s]+|[,])chown([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+chown[\s]+|([\s]+|[,])chown([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+fchmod[\s]+|([\s]+|[,])fchmod([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+fchmod[\s]+|([\s]+|[,])fchmod([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+fchmod[\s]+|([\s]+|[,])fchmod([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+fchmod[\s]+|([\s]+|[,])fchmod([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+fchmodat[\s]+|([\s]+|[,])fchmodat([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+fchmodat[\s]+|([\s]+|[,])fchmodat([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+fchmodat[\s]+|([\s]+|[,])fchmodat([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+fchmodat[\s]+|([\s]+|[,])fchmodat([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+fchown[\s]+|([\s]+|[,])fchown([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+fchown[\s]+|([\s]+|[,])fchown([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+fchown[\s]+|([\s]+|[,])fchown([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+fchown[\s]+|([\s]+|[,])fchown([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+fchownat[\s]+|([\s]+|[,])fchownat([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+fchownat[\s]+|([\s]+|[,])fchownat([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+fchownat[\s]+|([\s]+|[,])fchownat([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+fchownat[\s]+|([\s]+|[,])fchownat([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+fremovexattr[\s]+|([\s]+|[,])fremovexattr([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+fremovexattr[\s]+|([\s]+|[,])fremovexattr([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+fremovexattr[\s]+|([\s]+|[,])fremovexattr([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+fremovexattr[\s]+|([\s]+|[,])fremovexattr([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+fsetxattr[\s]+|([\s]+|[,])fsetxattr([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+fsetxattr[\s]+|([\s]+|[,])fsetxattr([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+fsetxattr[\s]+|([\s]+|[,])fsetxattr([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+fsetxattr[\s]+|([\s]+|[,])fsetxattr([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+lchown[\s]+|([\s]+|[,])lchown([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+lchown[\s]+|([\s]+|[,])lchown([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+lchown[\s]+|([\s]+|[,])lchown([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+lchown[\s]+|([\s]+|[,])lchown([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+lremovexattr[\s]+|([\s]+|[,])lremovexattr([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+lremovexattr[\s]+|([\s]+|[,])lremovexattr([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+lremovexattr[\s]+|([\s]+|[,])lremovexattr([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+lremovexattr[\s]+|([\s]+|[,])lremovexattr([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+lsetxattr[\s]+|([\s]+|[,])lsetxattr([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+lsetxattr[\s]+|([\s]+|[,])lsetxattr([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+lsetxattr[\s]+|([\s]+|[,])lsetxattr([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+lsetxattr[\s]+|([\s]+|[,])lsetxattr([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+removexattr[\s]+|([\s]+|[,])removexattr([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+removexattr[\s]+|([\s]+|[,])removexattr([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+removexattr[\s]+|([\s]+|[,])removexattr([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+removexattr[\s]+|([\s]+|[,])removexattr([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+setxattr[\s]+|([\s]+|[,])setxattr([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+setxattr[\s]+|([\s]+|[,])setxattr([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+setxattr[\s]+|([\s]+|[,])setxattr([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+setxattr[\s]+|([\s]+|[,])setxattr([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+umount2[\s]+|([\s]+|[,])umount2([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+umount2[\s]+|([\s]+|[,])umount2([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+umount2[\s]+|([\s]+|[,])umount2([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+umount2[\s]+|([\s]+|[,])umount2([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/chacl(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/chacl(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/chcon(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/chcon(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/restorecon(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/restorecon(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/semanage(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/semanage(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/setfacl(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/setfacl(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/setfiles(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/setfiles(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/setsebool(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/setsebool(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/seunshare(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/seunshare(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+rename[\s]+|([\s]+|[,])rename([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+rename[\s]+|([\s]+|[,])rename([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+rename[\s]+|([\s]+|[,])rename([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+rename[\s]+|([\s]+|[,])rename([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+renameat[\s]+|([\s]+|[,])renameat([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+renameat[\s]+|([\s]+|[,])renameat([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+renameat[\s]+|([\s]+|[,])renameat([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+renameat[\s]+|([\s]+|[,])renameat([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+rmdir[\s]+|([\s]+|[,])rmdir([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+rmdir[\s]+|([\s]+|[,])rmdir([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+rmdir[\s]+|([\s]+|[,])rmdir([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+rmdir[\s]+|([\s]+|[,])rmdir([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+unlink[\s]+|([\s]+|[,])unlink([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+unlink[\s]+|([\s]+|[,])unlink([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+unlink[\s]+|([\s]+|[,])unlink([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+unlink[\s]+|([\s]+|[,])unlink([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+unlinkat[\s]+|([\s]+|[,])unlinkat([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+unlinkat[\s]+|([\s]+|[,])unlinkat([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+unlinkat[\s]+|([\s]+|[,])unlinkat([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+unlinkat[\s]+|([\s]+|[,])unlinkat([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^\-w[\s]+\/var\/log\/faillock[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ - 1 - - - /etc/audit/audit.rules - ^\-w[\s]+\/var\/log\/faillock[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^\-w[\s]+\/var\/log\/lastlog[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ - 1 - - - /etc/audit/audit.rules - ^\-w[\s]+\/var\/log\/lastlog[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^\-w[\s]+\/var\/log\/tallylog[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ - 1 - - - /etc/audit/audit.rules - ^\-w[\s]+\/var\/log\/tallylog[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+mount[\s]+|([\s]+|[,])mount([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+mount[\s]+|([\s]+|[,])mount([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+mount[\s]+|([\s]+|[,])mount([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+mount[\s]+|([\s]+|[,])mount([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/at(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/at(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/chage(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/chage(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/chsh(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/chsh(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/crontab(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/crontab(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/gpasswd(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/gpasswd(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/kmod(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/kmod(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/mount(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/mount(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/newgrp(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/newgrp(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/pam_timestamp_check(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/pam_timestamp_check(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/passwd(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/passwd(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/postdrop(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/postdrop(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/postqueue(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/postqueue(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/libexec\/pt_chown(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/libexec\/pt_chown(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/ssh-agent(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/ssh-agent(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/libexec\/openssh\/ssh-keysign(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/libexec\/openssh\/ssh-keysign(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/su(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/su(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/sudo(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/sudo(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/sudoedit(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/sudoedit(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/umount(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/umount(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/unix_chkpwd(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/unix_chkpwd(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/unix_update(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/unix_update(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/userhelper(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/userhelper(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/usermod(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/usermod(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/usernetctl(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/usernetctl(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - - 1 - - - /etc/audit/audit.rules - - 1 - - - /etc/audit/audit.rules - - 1 - - - /etc/audit/audit.rules - - 1 - - - /etc/audit/audit.rules - - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - - 1 - - - /etc/audit/audit.rules - - 1 - - - /etc/audit/audit.rules - - 1 - - - /etc/audit/audit.rules - - 1 - - - /etc/audit/audit.rules - - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - - 1 - - - /etc/audit/audit.rules - - 1 - - - /etc/audit/audit.rules - - 1 - - - /etc/audit/audit.rules - - 1 - - - /etc/audit/audit.rules - - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - - 1 - - - /etc/audit/audit.rules - - 1 - - - /etc/audit/audit.rules - - 1 - - - /etc/audit/audit.rules - - 1 - - - /etc/audit/audit.rules - - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - - 1 - - - /etc/audit/audit.rules - - 1 - - - /etc/audit/audit.rules - - 1 - - - /etc/audit/audit.rules - - 1 - - - /etc/audit/audit.rules - - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - - 1 - - - /etc/audit/audit.rules - - 1 - - - /etc/audit/audit.rules - - 1 - - - /etc/audit/audit.rules - - 1 - - - /etc/audit/audit.rules - - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - - 1 - - - /etc/audit/audit.rules - - 1 - - - /etc/audit/audit.rules - - 1 - - - /etc/audit/audit.rules - - 1 - - - /etc/audit/audit.rules - - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - - 1 - - - /etc/audit/audit.rules - - 1 - - - /etc/audit/audit.rules - - 1 - - - /etc/audit/audit.rules - - 1 - - - /etc/audit/audit.rules - - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - - 1 - - - /etc/audit/audit.rules - - 1 - - - /etc/audit/audit.rules - - 1 - - - /etc/audit/audit.rules - - 1 - - - /etc/audit/audit.rules - - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - - 1 - - - /etc/audit/audit.rules - - 1 - - - /etc/audit/audit.rules - - 1 - - - /etc/audit/audit.rules - - 1 - - - /etc/audit/audit.rules - - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^\-w[\s]+\/etc\/group[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ - 1 - - - /etc/audit/audit.rules - ^\-w[\s]+\/etc\/group[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^\-w[\s]+\/etc\/gshadow[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ - 1 - - - /etc/audit/audit.rules - ^\-w[\s]+\/etc\/gshadow[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^\-w[\s]+\/etc\/security\/opasswd[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ - 1 - - - /etc/audit/audit.rules - ^\-w[\s]+\/etc\/security\/opasswd[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^\-w[\s]+\/etc\/passwd[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ - 1 - - - /etc/audit/audit.rules - ^\-w[\s]+\/etc\/passwd[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^\-w[\s]+\/etc\/shadow[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ - 1 - - - /etc/audit/audit.rules - ^\-w[\s]+\/etc\/shadow[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ - 1 - - - /etc/audit/auditd.conf - ^[ \t]*(?i)freq(?-i)[ \t]*=[ \t]*(.+?)[ \t]*(?:$|#) - 1 - - - /etc/audit/auditd.conf - ^[ \t]*(?i)local_events(?-i)[ \t]*=[ \t]*(.+?)[ \t]*(?:$|#) - 1 - - - /etc/audit/auditd.conf - ^[ \t]*(?i)log_format(?-i)[ \t]*=[ \t]*(.+?)[ \t]*(?:$|#) - 1 - - - /etc/audit/auditd.conf - ^[ \t]*(?i)write_logs(?-i)[ \t]*=[ \t]*(.+?)[ \t]*(?:$|#) - 1 - - - /etc/audit/auditd.conf - ^[ \t]*(?i)write_logs(?-i)[ \t]*=[ \t]* - 1 - - - /etc/dconf/db/local.d/ - ^.*$ - ^\s*\[org/gnome/settings-daemon/peripherals/smartcard\].*(?:\n\s*[^[\s].*)*\n^\s*removal-action[ \t]*=[ \t]*(.+?)[ \t]*(?:$|#) - 1 - - - /etc/dconf/db/local.d/locks - ^.*$ - ^/org/gnome/settings-daemon/peripherals/smartcard/removal-action$ - 1 - - - - /lib - - oval:ssg-symlink_file_groupownerdir_group_ownership_library_dirs_uid_0:ste:1 - oval:ssg-state_file_groupownerdir_group_ownership_library_dirs_gid_0_0:ste:1 - - - - /lib64 - - oval:ssg-symlink_file_groupownerdir_group_ownership_library_dirs_uid_0:ste:1 - oval:ssg-state_file_groupownerdir_group_ownership_library_dirs_gid_0_1:ste:1 - - - - /usr/lib - - oval:ssg-symlink_file_groupownerdir_group_ownership_library_dirs_uid_0:ste:1 - oval:ssg-state_file_groupownerdir_group_ownership_library_dirs_gid_0_2:ste:1 - - - - /usr/lib64 - - oval:ssg-symlink_file_groupownerdir_group_ownership_library_dirs_uid_0:ste:1 - oval:ssg-state_file_groupownerdir_group_ownership_library_dirs_gid_0_3:ste:1 - - - - /bin - - oval:ssg-symlink_file_ownerdir_ownership_binary_dirs_uid_0:ste:1 - oval:ssg-state_file_ownerdir_ownership_binary_dirs_uid_0_0:ste:1 - - - - /sbin - - oval:ssg-symlink_file_ownerdir_ownership_binary_dirs_uid_0:ste:1 - oval:ssg-state_file_ownerdir_ownership_binary_dirs_uid_0_1:ste:1 - - - - /usr/bin - - oval:ssg-symlink_file_ownerdir_ownership_binary_dirs_uid_0:ste:1 - oval:ssg-state_file_ownerdir_ownership_binary_dirs_uid_0_2:ste:1 - - - - /usr/sbin - - oval:ssg-symlink_file_ownerdir_ownership_binary_dirs_uid_0:ste:1 - oval:ssg-state_file_ownerdir_ownership_binary_dirs_uid_0_3:ste:1 - - - - /usr/local/bin - - oval:ssg-symlink_file_ownerdir_ownership_binary_dirs_uid_0:ste:1 - oval:ssg-state_file_ownerdir_ownership_binary_dirs_uid_0_4:ste:1 - - - - /usr/local/sbin - - oval:ssg-symlink_file_ownerdir_ownership_binary_dirs_uid_0:ste:1 - oval:ssg-state_file_ownerdir_ownership_binary_dirs_uid_0_5:ste:1 - - - - /lib - - oval:ssg-symlink_file_ownerdir_ownership_library_dirs_uid_0:ste:1 - oval:ssg-state_file_ownerdir_ownership_library_dirs_uid_0_0:ste:1 - - - - /lib64 - - oval:ssg-symlink_file_ownerdir_ownership_library_dirs_uid_0:ste:1 - oval:ssg-state_file_ownerdir_ownership_library_dirs_uid_0_1:ste:1 - - - - /usr/lib - - oval:ssg-symlink_file_ownerdir_ownership_library_dirs_uid_0:ste:1 - oval:ssg-state_file_ownerdir_ownership_library_dirs_uid_0_2:ste:1 - - - - /usr/lib64 - - oval:ssg-symlink_file_ownerdir_ownership_library_dirs_uid_0:ste:1 - oval:ssg-state_file_ownerdir_ownership_library_dirs_uid_0_3:ste:1 - - - - /bin - - oval:ssg-exclude_symlinks_dir_permissions_binary_dirs:ste:1 - oval:ssg-state_file_permissionsdir_permissions_binary_dirs_0_mode_0755or_stricter_:ste:1 - - - - /sbin - - oval:ssg-exclude_symlinks_dir_permissions_binary_dirs:ste:1 - oval:ssg-state_file_permissionsdir_permissions_binary_dirs_1_mode_0755or_stricter_:ste:1 - - - - /usr/bin - - oval:ssg-exclude_symlinks_dir_permissions_binary_dirs:ste:1 - oval:ssg-state_file_permissionsdir_permissions_binary_dirs_2_mode_0755or_stricter_:ste:1 - - - - /usr/sbin - - oval:ssg-exclude_symlinks_dir_permissions_binary_dirs:ste:1 - oval:ssg-state_file_permissionsdir_permissions_binary_dirs_3_mode_0755or_stricter_:ste:1 - - - - /usr/local/bin - - oval:ssg-exclude_symlinks_dir_permissions_binary_dirs:ste:1 - oval:ssg-state_file_permissionsdir_permissions_binary_dirs_4_mode_0755or_stricter_:ste:1 - - - - /usr/local/sbin - - oval:ssg-exclude_symlinks_dir_permissions_binary_dirs:ste:1 - oval:ssg-state_file_permissionsdir_permissions_binary_dirs_5_mode_0755or_stricter_:ste:1 - - - - /lib - - oval:ssg-exclude_symlinks_dir_permissions_library_dirs:ste:1 - oval:ssg-state_file_permissionsdir_permissions_library_dirs_0_mode_7755or_stricter_:ste:1 - - - - /lib64 - - oval:ssg-exclude_symlinks_dir_permissions_library_dirs:ste:1 - oval:ssg-state_file_permissionsdir_permissions_library_dirs_1_mode_7755or_stricter_:ste:1 - - - - /usr/lib - - oval:ssg-exclude_symlinks_dir_permissions_library_dirs:ste:1 - oval:ssg-state_file_permissionsdir_permissions_library_dirs_2_mode_7755or_stricter_:ste:1 - - - - /usr/lib64 - - oval:ssg-exclude_symlinks_dir_permissions_library_dirs:ste:1 - oval:ssg-state_file_permissionsdir_permissions_library_dirs_3_mode_7755or_stricter_:ste:1 - - - /etc/ssh/sshd_config - ^[ \t]*(?i)include(?-i)[ \t]+(.+?)[ \t]*(?:$|#) - 1 - - - - ^[ \t]*(?i)HostbasedAuthentication(?-i)[ \t]+(.+?)[ \t]*(?:$|#) - 1 - - - /etc/ssh/sshd_config - ^[ \t]*(?i)HostbasedAuthentication(?-i)[ \t]+(.+?)[ \t]*(?:$|#) - 1 - - - - oval:ssg-obj_disable_host_auth:obj:1 - oval:ssg-obj_disable_host_auth_sshd_included_files:obj:1 - - - - /sbin/auditctl - oval:ssg-symlink_file_groupownerfile_audit_tools_group_ownership_uid_0:ste:1 - oval:ssg-state_file_groupownerfile_audit_tools_group_ownership_gid_0_0:ste:1 - - - /sbin/aureport - oval:ssg-symlink_file_groupownerfile_audit_tools_group_ownership_uid_0:ste:1 - oval:ssg-state_file_groupownerfile_audit_tools_group_ownership_gid_0_1:ste:1 - - - /sbin/ausearch - oval:ssg-symlink_file_groupownerfile_audit_tools_group_ownership_uid_0:ste:1 - oval:ssg-state_file_groupownerfile_audit_tools_group_ownership_gid_0_2:ste:1 - - - /sbin/autrace - oval:ssg-symlink_file_groupownerfile_audit_tools_group_ownership_uid_0:ste:1 - oval:ssg-state_file_groupownerfile_audit_tools_group_ownership_gid_0_3:ste:1 - - - /sbin/auditd - oval:ssg-symlink_file_groupownerfile_audit_tools_group_ownership_uid_0:ste:1 - oval:ssg-state_file_groupownerfile_audit_tools_group_ownership_gid_0_4:ste:1 - - - /sbin/rsyslogd - oval:ssg-symlink_file_groupownerfile_audit_tools_group_ownership_uid_0:ste:1 - oval:ssg-state_file_groupownerfile_audit_tools_group_ownership_gid_0_5:ste:1 - - - /sbin/augenrules - oval:ssg-symlink_file_groupownerfile_audit_tools_group_ownership_uid_0:ste:1 - oval:ssg-state_file_groupownerfile_audit_tools_group_ownership_gid_0_6:ste:1 - - - /sbin/auditctl - oval:ssg-symlink_file_ownerfile_audit_tools_ownership_uid_0:ste:1 - oval:ssg-state_file_ownerfile_audit_tools_ownership_uid_0_0:ste:1 - - - /sbin/aureport - oval:ssg-symlink_file_ownerfile_audit_tools_ownership_uid_0:ste:1 - oval:ssg-state_file_ownerfile_audit_tools_ownership_uid_0_1:ste:1 - - - /sbin/ausearch - oval:ssg-symlink_file_ownerfile_audit_tools_ownership_uid_0:ste:1 - oval:ssg-state_file_ownerfile_audit_tools_ownership_uid_0_2:ste:1 - - - /sbin/autrace - oval:ssg-symlink_file_ownerfile_audit_tools_ownership_uid_0:ste:1 - oval:ssg-state_file_ownerfile_audit_tools_ownership_uid_0_3:ste:1 - - - /sbin/auditd - oval:ssg-symlink_file_ownerfile_audit_tools_ownership_uid_0:ste:1 - oval:ssg-state_file_ownerfile_audit_tools_ownership_uid_0_4:ste:1 - - - /sbin/rsyslogd - oval:ssg-symlink_file_ownerfile_audit_tools_ownership_uid_0:ste:1 - oval:ssg-state_file_ownerfile_audit_tools_ownership_uid_0_5:ste:1 - - - /sbin/augenrules - oval:ssg-symlink_file_ownerfile_audit_tools_ownership_uid_0:ste:1 - oval:ssg-state_file_ownerfile_audit_tools_ownership_uid_0_6:ste:1 - - - /sbin/auditctl - oval:ssg-exclude_symlinks_file_audit_tools_permissions:ste:1 - oval:ssg-state_file_permissionsfile_audit_tools_permissions_0_mode_0755or_stricter_:ste:1 - - - /sbin/aureport - oval:ssg-exclude_symlinks_file_audit_tools_permissions:ste:1 - oval:ssg-state_file_permissionsfile_audit_tools_permissions_1_mode_0755or_stricter_:ste:1 - - - /sbin/ausearch - oval:ssg-exclude_symlinks_file_audit_tools_permissions:ste:1 - oval:ssg-state_file_permissionsfile_audit_tools_permissions_2_mode_0755or_stricter_:ste:1 - - - /sbin/autrace - oval:ssg-exclude_symlinks_file_audit_tools_permissions:ste:1 - oval:ssg-state_file_permissionsfile_audit_tools_permissions_3_mode_0755or_stricter_:ste:1 - - - /sbin/auditd - oval:ssg-exclude_symlinks_file_audit_tools_permissions:ste:1 - oval:ssg-state_file_permissionsfile_audit_tools_permissions_4_mode_0755or_stricter_:ste:1 - - - /sbin/rsyslogd - oval:ssg-exclude_symlinks_file_audit_tools_permissions:ste:1 - oval:ssg-state_file_permissionsfile_audit_tools_permissions_5_mode_0755or_stricter_:ste:1 - - - /sbin/augenrules - oval:ssg-exclude_symlinks_file_audit_tools_permissions:ste:1 - oval:ssg-state_file_permissionsfile_audit_tools_permissions_6_mode_0755or_stricter_:ste:1 - - - /etc/group- - oval:ssg-symlink_file_groupowner_backup_etc_group_uid_0:ste:1 - oval:ssg-state_file_groupowner_backup_etc_group_gid_0_0:ste:1 - - - /etc/gshadow- - oval:ssg-symlink_file_groupowner_backup_etc_gshadow_uid_0:ste:1 - oval:ssg-state_file_groupowner_backup_etc_gshadow_gid_0_0:ste:1 - - - /etc/passwd- - oval:ssg-symlink_file_groupowner_backup_etc_passwd_uid_0:ste:1 - oval:ssg-state_file_groupowner_backup_etc_passwd_gid_0_0:ste:1 - - - /etc/shadow- - oval:ssg-symlink_file_groupowner_backup_etc_shadow_uid_0:ste:1 - oval:ssg-state_file_groupowner_backup_etc_shadow_gid_0_0:ste:1 - - - /etc/cron.allow - oval:ssg-symlink_file_groupowner_cron_allow_uid_0:ste:1 - oval:ssg-state_file_groupowner_cron_allow_gid_0_0:ste:1 - - - /etc/cron.d - - oval:ssg-symlink_file_groupowner_cron_d_uid_0:ste:1 - oval:ssg-state_file_groupowner_cron_d_gid_0_0:ste:1 - - - /etc/cron.daily - - oval:ssg-symlink_file_groupowner_cron_daily_uid_0:ste:1 - oval:ssg-state_file_groupowner_cron_daily_gid_0_0:ste:1 - - - /etc/cron.hourly - - oval:ssg-symlink_file_groupowner_cron_hourly_uid_0:ste:1 - oval:ssg-state_file_groupowner_cron_hourly_gid_0_0:ste:1 - - - /etc/cron.monthly - - oval:ssg-symlink_file_groupowner_cron_monthly_uid_0:ste:1 - oval:ssg-state_file_groupowner_cron_monthly_gid_0_0:ste:1 - - - /etc/cron.weekly - - oval:ssg-symlink_file_groupowner_cron_weekly_uid_0:ste:1 - oval:ssg-state_file_groupowner_cron_weekly_gid_0_0:ste:1 - - - /etc/crontab - oval:ssg-symlink_file_groupowner_crontab_uid_0:ste:1 - oval:ssg-state_file_groupowner_crontab_gid_0_0:ste:1 - - - /boot/grub2/user.cfg - oval:ssg-symlink_file_groupowner_efi_user_cfg_uid_0:ste:1 - oval:ssg-state_file_groupowner_efi_user_cfg_gid_0_0:ste:1 - - - /etc/group - oval:ssg-symlink_file_groupowner_etc_group_uid_0:ste:1 - oval:ssg-state_file_groupowner_etc_group_gid_0_0:ste:1 - - - /etc/gshadow - oval:ssg-symlink_file_groupowner_etc_gshadow_uid_0:ste:1 - oval:ssg-state_file_groupowner_etc_gshadow_gid_0_0:ste:1 - - - /etc/passwd - oval:ssg-symlink_file_groupowner_etc_passwd_uid_0:ste:1 - oval:ssg-state_file_groupowner_etc_passwd_gid_0_0:ste:1 - - - /etc/shadow - oval:ssg-symlink_file_groupowner_etc_shadow_uid_0:ste:1 - oval:ssg-state_file_groupowner_etc_shadow_gid_0_0:ste:1 - - - /boot/grub2/grub.cfg - oval:ssg-symlink_file_groupowner_grub2_cfg_uid_0:ste:1 - oval:ssg-state_file_groupowner_grub2_cfg_gid_0_0:ste:1 - - - /etc/ssh/sshd_config - oval:ssg-symlink_file_groupowner_sshd_config_uid_0:ste:1 - oval:ssg-state_file_groupowner_sshd_config_gid_0_0:ste:1 - - - /boot/grub2/user.cfg - oval:ssg-symlink_file_groupowner_user_cfg_uid_0:ste:1 - oval:ssg-state_file_groupowner_user_cfg_gid_0_0:ste:1 - - - /var/log - - oval:ssg-symlink_file_groupowner_var_log_uid_0:ste:1 - oval:ssg-state_file_groupowner_var_log_gid_0_0:ste:1 - - - /var/log/messages - oval:ssg-symlink_file_groupowner_var_log_messages_uid_0:ste:1 - oval:ssg-state_file_groupowner_var_log_messages_gid_0_0:ste:1 - - - /var/log/syslog - oval:ssg-symlink_file_groupowner_var_log_syslog_uid_4:ste:1 - oval:ssg-state_file_groupowner_var_log_syslog_gid_4_0:ste:1 - - - /etc/audit - ^audit(\.rules|d\.conf)$ - oval:ssg-symlink_file_groupownership_audit_configuration_uid_0:ste:1 - oval:ssg-state_file_groupownership_audit_configuration_gid_0_0:ste:1 - - - /etc/audit/rules.d - ^.*\.rules$ - oval:ssg-symlink_file_groupownership_audit_configuration_uid_0:ste:1 - oval:ssg-state_file_groupownership_audit_configuration_gid_0_1:ste:1 - - - /etc/ssh - ^.*_key$ - oval:ssg-symlink_file_groupownership_sshd_private_key_uid_ssh_keys:ste:1 - oval:ssg-state_file_groupownership_sshd_private_key_gid_ssh_keys_0:ste:1 - - - /etc/group - ^ssh_keys:\w+:(\w+):.* - 1 - - - /etc/ssh - ^.*\.pub$ - oval:ssg-symlink_file_groupownership_sshd_pub_key_uid_0:ste:1 - oval:ssg-state_file_groupownership_sshd_pub_key_gid_0_0:ste:1 - - - /etc/group- - oval:ssg-symlink_file_owner_backup_etc_group_uid_0:ste:1 - oval:ssg-state_file_owner_backup_etc_group_uid_0_0:ste:1 - - - /etc/gshadow- - oval:ssg-symlink_file_owner_backup_etc_gshadow_uid_0:ste:1 - oval:ssg-state_file_owner_backup_etc_gshadow_uid_0_0:ste:1 - - - /etc/passwd- - oval:ssg-symlink_file_owner_backup_etc_passwd_uid_0:ste:1 - oval:ssg-state_file_owner_backup_etc_passwd_uid_0_0:ste:1 - - - /etc/shadow- - oval:ssg-symlink_file_owner_backup_etc_shadow_uid_0:ste:1 - oval:ssg-state_file_owner_backup_etc_shadow_uid_0_0:ste:1 - - - /etc/cron.allow - oval:ssg-symlink_file_owner_cron_allow_uid_0:ste:1 - oval:ssg-state_file_owner_cron_allow_uid_0_0:ste:1 - - - /etc/cron.d - - oval:ssg-symlink_file_owner_cron_d_uid_0:ste:1 - oval:ssg-state_file_owner_cron_d_uid_0_0:ste:1 - - - /etc/cron.daily - - oval:ssg-symlink_file_owner_cron_daily_uid_0:ste:1 - oval:ssg-state_file_owner_cron_daily_uid_0_0:ste:1 - - - /etc/cron.hourly - - oval:ssg-symlink_file_owner_cron_hourly_uid_0:ste:1 - oval:ssg-state_file_owner_cron_hourly_uid_0_0:ste:1 - - - /etc/cron.monthly - - oval:ssg-symlink_file_owner_cron_monthly_uid_0:ste:1 - oval:ssg-state_file_owner_cron_monthly_uid_0_0:ste:1 - - - /etc/cron.weekly - - oval:ssg-symlink_file_owner_cron_weekly_uid_0:ste:1 - oval:ssg-state_file_owner_cron_weekly_uid_0_0:ste:1 - - - /etc/crontab - oval:ssg-symlink_file_owner_crontab_uid_0:ste:1 - oval:ssg-state_file_owner_crontab_uid_0_0:ste:1 - - - /etc/group - oval:ssg-symlink_file_owner_etc_group_uid_0:ste:1 - oval:ssg-state_file_owner_etc_group_uid_0_0:ste:1 - - - /etc/gshadow - oval:ssg-symlink_file_owner_etc_gshadow_uid_0:ste:1 - oval:ssg-state_file_owner_etc_gshadow_uid_0_0:ste:1 - - - /etc/passwd - oval:ssg-symlink_file_owner_etc_passwd_uid_0:ste:1 - oval:ssg-state_file_owner_etc_passwd_uid_0_0:ste:1 - - - /etc/shadow - oval:ssg-symlink_file_owner_etc_shadow_uid_0:ste:1 - oval:ssg-state_file_owner_etc_shadow_uid_0_0:ste:1 - - - /boot/grub2/grub.cfg - oval:ssg-symlink_file_owner_grub2_cfg_uid_0:ste:1 - oval:ssg-state_file_owner_grub2_cfg_uid_0_0:ste:1 - - - /etc/ssh/sshd_config - oval:ssg-symlink_file_owner_sshd_config_uid_0:ste:1 - oval:ssg-state_file_owner_sshd_config_uid_0_0:ste:1 - - - /boot/grub2/user.cfg - oval:ssg-symlink_file_owner_user_cfg_uid_0:ste:1 - oval:ssg-state_file_owner_user_cfg_uid_0_0:ste:1 - - - /var/log - - oval:ssg-symlink_file_owner_var_log_uid_0:ste:1 - oval:ssg-state_file_owner_var_log_uid_0_0:ste:1 - - - /var/log/messages - oval:ssg-symlink_file_owner_var_log_messages_uid_0:ste:1 - oval:ssg-state_file_owner_var_log_messages_uid_0_0:ste:1 - - - /var/log/syslog - oval:ssg-symlink_file_owner_var_log_syslog_uid_104:ste:1 - oval:ssg-state_file_owner_var_log_syslog_uid_104_0:ste:1 - - - /etc/audit - ^audit(\.rules|d\.conf)$ - oval:ssg-symlink_file_ownership_audit_configuration_uid_0:ste:1 - oval:ssg-state_file_ownership_audit_configuration_uid_0_0:ste:1 - - - /etc/audit/rules.d - ^.*\.rules$ - oval:ssg-symlink_file_ownership_audit_configuration_uid_0:ste:1 - oval:ssg-state_file_ownership_audit_configuration_uid_0_1:ste:1 - - - - /lib - ^.*$ - oval:ssg-symlink_file_ownership_library_dirs_uid_0:ste:1 - oval:ssg-state_file_ownership_library_dirs_uid_0_0:ste:1 - - - - /lib64 - ^.*$ - oval:ssg-symlink_file_ownership_library_dirs_uid_0:ste:1 - oval:ssg-state_file_ownership_library_dirs_uid_0_1:ste:1 - - - - /usr/lib - ^.*$ - oval:ssg-symlink_file_ownership_library_dirs_uid_0:ste:1 - oval:ssg-state_file_ownership_library_dirs_uid_0_2:ste:1 - - - - /usr/lib64 - ^.*$ - oval:ssg-symlink_file_ownership_library_dirs_uid_0:ste:1 - oval:ssg-state_file_ownership_library_dirs_uid_0_3:ste:1 - - - /etc/ssh - ^.*_key$ - oval:ssg-symlink_file_ownership_sshd_private_key_uid_0:ste:1 - oval:ssg-state_file_ownership_sshd_private_key_uid_0_0:ste:1 - - - /etc/ssh - ^.*\.pub$ - oval:ssg-symlink_file_ownership_sshd_pub_key_uid_0:ste:1 - oval:ssg-state_file_ownership_sshd_pub_key_uid_0_0:ste:1 - - - /etc/audit - .*audit\(\.rules\|d\.conf\)$ - oval:ssg-exclude_symlinks__audit_configuration:ste:1 - oval:ssg-state_file_permissions_audit_configuration_0_mode_0640or_stricter_:ste:1 - - - /etc/audit/rules.d - .*\.rules$ - oval:ssg-exclude_symlinks__audit_configuration:ste:1 - oval:ssg-state_file_permissions_audit_configuration_1_mode_0640or_stricter_:ste:1 - - - /etc/group- - oval:ssg-exclude_symlinks__backup_etc_group:ste:1 - oval:ssg-state_file_permissions_backup_etc_group_0_mode_0644or_stricter_:ste:1 - - - /etc/gshadow- - oval:ssg-exclude_symlinks__backup_etc_gshadow:ste:1 - oval:ssg-state_file_permissions_backup_etc_gshadow_0_mode_0000or_stricter_:ste:1 - - - /etc/passwd- - oval:ssg-exclude_symlinks__backup_etc_passwd:ste:1 - oval:ssg-state_file_permissions_backup_etc_passwd_0_mode_0644or_stricter_:ste:1 - - - /etc/shadow- - oval:ssg-exclude_symlinks__backup_etc_shadow:ste:1 - oval:ssg-state_file_permissions_backup_etc_shadow_0_mode_0000or_stricter_:ste:1 - - - /etc/cron.allow - oval:ssg-exclude_symlinks__cron_allow:ste:1 - oval:ssg-state_file_permissions_cron_allow_0_mode_0640or_stricter_:ste:1 - - - /etc/cron.d - - oval:ssg-exclude_symlinks__cron_d:ste:1 - oval:ssg-state_file_permissions_cron_d_0_mode_0700or_stricter_:ste:1 - - - /etc/cron.daily - - oval:ssg-exclude_symlinks__cron_daily:ste:1 - oval:ssg-state_file_permissions_cron_daily_0_mode_0700or_stricter_:ste:1 - - - /etc/cron.hourly - - oval:ssg-exclude_symlinks__cron_hourly:ste:1 - oval:ssg-state_file_permissions_cron_hourly_0_mode_0700or_stricter_:ste:1 - - - /etc/cron.monthly - - oval:ssg-exclude_symlinks__cron_monthly:ste:1 - oval:ssg-state_file_permissions_cron_monthly_0_mode_0700or_stricter_:ste:1 - - - /etc/cron.weekly - - oval:ssg-exclude_symlinks__cron_weekly:ste:1 - oval:ssg-state_file_permissions_cron_weekly_0_mode_0700or_stricter_:ste:1 - - - /etc/crontab - oval:ssg-exclude_symlinks__crontab:ste:1 - oval:ssg-state_file_permissions_crontab_0_mode_0600or_stricter_:ste:1 - - - /etc/audit/auditd.conf - oval:ssg-exclude_symlinks__etc_audit_auditd:ste:1 - oval:ssg-state_file_permissions_etc_audit_auditd_0_mode_0640or_stricter_:ste:1 - - - /etc/audit/rules.d - ^.*rules$ - oval:ssg-exclude_symlinks__etc_audit_rulesd:ste:1 - oval:ssg-state_file_permissions_etc_audit_rulesd_0_mode_0640or_stricter_:ste:1 - - - /etc/group - oval:ssg-exclude_symlinks__etc_group:ste:1 - oval:ssg-state_file_permissions_etc_group_0_mode_0644or_stricter_:ste:1 - - - /etc/gshadow - oval:ssg-exclude_symlinks__etc_gshadow:ste:1 - oval:ssg-state_file_permissions_etc_gshadow_0_mode_0000or_stricter_:ste:1 - - - /etc/passwd - oval:ssg-exclude_symlinks__etc_passwd:ste:1 - oval:ssg-state_file_permissions_etc_passwd_0_mode_0644or_stricter_:ste:1 - - - /etc/shadow - oval:ssg-exclude_symlinks__etc_shadow:ste:1 - oval:ssg-state_file_permissions_etc_shadow_0_mode_0000or_stricter_:ste:1 - - - - /lib - ^.*$ - oval:ssg-exclude_symlinks__library_dirs:ste:1 - oval:ssg-state_file_permissions_library_dirs_0_mode_7755or_stricter_:ste:1 - - - - /lib64 - ^.*$ - oval:ssg-exclude_symlinks__library_dirs:ste:1 - oval:ssg-state_file_permissions_library_dirs_1_mode_7755or_stricter_:ste:1 - - - - /usr/lib - ^.*$ - oval:ssg-exclude_symlinks__library_dirs:ste:1 - oval:ssg-state_file_permissions_library_dirs_2_mode_7755or_stricter_:ste:1 - - - - /usr/lib64 - ^.*$ - oval:ssg-exclude_symlinks__library_dirs:ste:1 - oval:ssg-state_file_permissions_library_dirs_3_mode_7755or_stricter_:ste:1 - - - /etc/ssh/sshd_config - oval:ssg-exclude_symlinks__sshd_config:ste:1 - oval:ssg-state_file_permissions_sshd_config_0_mode_0600or_stricter_:ste:1 - - - /etc/ssh - ^.*\.pub$ - oval:ssg-exclude_symlinks__sshd_pub_key:ste:1 - oval:ssg-state_file_permissions_sshd_pub_key_0_mode_0644or_stricter_:ste:1 - - - /var/log - - oval:ssg-exclude_symlinks__var_log:ste:1 - oval:ssg-state_file_permissions_var_log_0_mode_0755or_stricter_:ste:1 - - - /var/log/messages - oval:ssg-exclude_symlinks__var_log_messages:ste:1 - oval:ssg-state_file_permissions_var_log_messages_0_mode_0640or_stricter_:ste:1 - - - /var/log/syslog - oval:ssg-exclude_symlinks__var_log_syslog:ste:1 - oval:ssg-state_file_permissions_var_log_syslog_0_mode_0640or_stricter_:ste:1 - - - /etc/firewalld/firewalld.conf - ^[ \t]*FirewallBackend=(.+?)[ \t]*(?:$|#) - 1 - - - /etc/default/grub - ^\s*GRUB_CMDLINE_LINUX="(.*)"$ - 1 - - - /etc/default/grub - ^\s*GRUB_CMDLINE_LINUX_DEFAULT="(.*)"$ - 1 - - - /boot/loader/entries/ - ^.*\.conf$ - ^options (.*)$ - 1 - oval:ssg-state_grub2_rescue_entry_for_grub2_audit_argument:ste:1 - - - /etc/default/grub - ^\s*GRUB_CMDLINE_LINUX="(.*)"$ - 1 - - - /etc/default/grub - ^\s*GRUB_CMDLINE_LINUX_DEFAULT="(.*)"$ - 1 - - - /boot/loader/entries/ - ^.*\.conf$ - ^options (.*)$ - 1 - oval:ssg-state_grub2_rescue_entry_for_grub2_audit_backlog_limit_argument:ste:1 - - - /etc/default/grub - ^\s*GRUB_CMDLINE_LINUX="(.*)"$ - 1 - - - /etc/default/grub - ^\s*GRUB_CMDLINE_LINUX_DEFAULT="(.*)"$ - 1 - - - /boot/loader/entries/ - ^.*\.conf$ - ^options (.*)$ - 1 - oval:ssg-state_grub2_rescue_entry_for_grub2_enable_iommu_force:ste:1 - - - /etc/default/grub - ^\s*GRUB_CMDLINE_LINUX="(.*)"$ - 1 - - - /etc/default/grub - ^\s*GRUB_CMDLINE_LINUX_DEFAULT="(.*)"$ - 1 - - - /boot/loader/entries/ - ^.*\.conf$ - ^options (.*)$ - 1 - oval:ssg-state_grub2_rescue_entry_for_grub2_init_on_alloc_argument:ste:1 - - - /etc/default/grub - ^\s*GRUB_CMDLINE_LINUX="(.*)"$ - 1 - - - /etc/default/grub - ^\s*GRUB_CMDLINE_LINUX_DEFAULT="(.*)"$ - 1 - - - /boot/loader/entries/ - ^.*\.conf$ - ^options (.*)$ - 1 - oval:ssg-state_grub2_rescue_entry_for_grub2_l1tf_argument:ste:1 - - - /etc/default/grub - ^\s*GRUB_CMDLINE_LINUX="(.*)"$ - 1 - - - /etc/default/grub - ^\s*GRUB_CMDLINE_LINUX_DEFAULT="(.*)"$ - 1 - - - /boot/loader/entries/ - ^.*\.conf$ - ^options (.*)$ - 1 - oval:ssg-state_grub2_rescue_entry_for_grub2_mce_argument:ste:1 - - - /etc/default/grub - ^\s*GRUB_CMDLINE_LINUX="(?!.*\bnosmap\b.*).*"$ - 1 - - - /etc/default/grub - ^\s*GRUB_CMDLINE_LINUX_DEFAULT="(?!.*\bnosmap\b).*"$ - 1 - - - /boot/loader/entries/ - ^.*\.conf$ - ^options (.*)$ - 1 - oval:ssg-state_grub2_rescue_entry_for_grub2_nosmap_argument_absent:ste:1 - - - /etc/default/grub - ^\s*GRUB_CMDLINE_LINUX="(?!.*\bnosmep\b.*).*"$ - 1 - - - /etc/default/grub - ^\s*GRUB_CMDLINE_LINUX_DEFAULT="(?!.*\bnosmep\b).*"$ - 1 - - - /boot/loader/entries/ - ^.*\.conf$ - ^options (.*)$ - 1 - oval:ssg-state_grub2_rescue_entry_for_grub2_nosmep_argument_absent:ste:1 - - - /etc/default/grub - ^\s*GRUB_CMDLINE_LINUX="(.*)"$ - 1 - - - /etc/default/grub - ^\s*GRUB_CMDLINE_LINUX_DEFAULT="(.*)"$ - 1 - - - /boot/loader/entries/ - ^.*\.conf$ - ^options (.*)$ - 1 - oval:ssg-state_grub2_rescue_entry_for_grub2_page_alloc_shuffle_argument:ste:1 - - - /etc/default/grub - ^\s*GRUB_CMDLINE_LINUX="(.*)"$ - 1 - - - /etc/default/grub - ^\s*GRUB_CMDLINE_LINUX_DEFAULT="(.*)"$ - 1 - - - /boot/loader/entries/ - ^.*\.conf$ - ^options (.*)$ - 1 - oval:ssg-state_grub2_rescue_entry_for_grub2_page_poison_argument:ste:1 - - - /etc/default/grub - ^\s*GRUB_CMDLINE_LINUX="(.*)"$ - 1 - - - /etc/default/grub - ^\s*GRUB_CMDLINE_LINUX_DEFAULT="(.*)"$ - 1 - - - /boot/loader/entries/ - ^.*\.conf$ - ^options (.*)$ - 1 - oval:ssg-state_grub2_rescue_entry_for_grub2_pti_argument:ste:1 - - - /etc/default/grub - ^\s*GRUB_CMDLINE_LINUX="(.*)"$ - 1 - - - /etc/default/grub - ^\s*GRUB_CMDLINE_LINUX_DEFAULT="(.*)"$ - 1 - - - /boot/loader/entries/ - ^.*\.conf$ - ^options (.*)$ - 1 - oval:ssg-state_grub2_rescue_entry_for_grub2_rng_core_default_quality_argument:ste:1 - - - /etc/default/grub - ^\s*GRUB_CMDLINE_LINUX="(.*)"$ - 1 - - - /etc/default/grub - ^\s*GRUB_CMDLINE_LINUX_DEFAULT="(.*)"$ - 1 - - - /boot/loader/entries/ - ^.*\.conf$ - ^options (.*)$ - 1 - oval:ssg-state_grub2_rescue_entry_for_grub2_slab_nomerge_argument:ste:1 - - - /etc/default/grub - ^\s*GRUB_CMDLINE_LINUX="(.*)"$ - 1 - - - /etc/default/grub - ^\s*GRUB_CMDLINE_LINUX_DEFAULT="(.*)"$ - 1 - - - /boot/loader/entries/ - ^.*\.conf$ - ^options (.*)$ - 1 - oval:ssg-state_grub2_rescue_entry_for_grub2_slub_debug_argument:ste:1 - - - /etc/default/grub - ^\s*GRUB_CMDLINE_LINUX="(.*)"$ - 1 - - - /etc/default/grub - ^\s*GRUB_CMDLINE_LINUX_DEFAULT="(.*)"$ - 1 - - - /boot/loader/entries/ - ^.*\.conf$ - ^options (.*)$ - 1 - oval:ssg-state_grub2_rescue_entry_for_grub2_spec_store_bypass_disable_argument:ste:1 - - - /etc/default/grub - ^\s*GRUB_CMDLINE_LINUX="(.*)"$ - 1 - - - /etc/default/grub - ^\s*GRUB_CMDLINE_LINUX_DEFAULT="(.*)"$ - 1 - - - /boot/loader/entries/ - ^.*\.conf$ - ^options (.*)$ - 1 - oval:ssg-state_grub2_rescue_entry_for_grub2_spectre_v2_argument:ste:1 - - - /etc/default/grub - ^\s*GRUB_CMDLINE_LINUX="(?!.*\bsystemd.debug-shell\b.*).*"$ - 1 - - - /etc/default/grub - ^\s*GRUB_CMDLINE_LINUX_DEFAULT="(?!.*\bsystemd.debug-shell\b).*"$ - 1 - - - /boot/loader/entries/ - ^.*\.conf$ - ^options (.*)$ - 1 - oval:ssg-state_grub2_rescue_entry_for_grub2_systemd_debug-shell_argument_absent:ste:1 - - - /etc/default/grub - ^\s*GRUB_CMDLINE_LINUX="(.*)"$ - 1 - - - /etc/default/grub - ^\s*GRUB_CMDLINE_LINUX_DEFAULT="(.*)"$ - 1 - - - /boot/loader/entries/ - ^.*\.conf$ - ^options (.*)$ - 1 - oval:ssg-state_grub2_rescue_entry_for_grub2_vsyscall_argument:ste:1 - - - openssl-pkcs11 - - - ^/boot/config-.*$ - ^CONFIG_ACPI_CUSTOM_METHOD="?(.*?)"?$ - 1 - - - oval:ssg-local_var_config_acpi_custom_method_count_kernels_installed:var:1 - - - /boot - ^config-.*$ - - - ^/boot/config-.*$ - ^CONFIG_BINFMT_MISC="?(.*?)"?$ - 1 - - - oval:ssg-local_var_config_binfmt_misc_count_kernels_installed:var:1 - - - /boot - ^config-.*$ - - - ^/boot/config-.*$ - ^CONFIG_BUG="?(.*?)"?$ - 1 - - - oval:ssg-local_var_config_bug_count_kernels_installed:var:1 - - - /boot - ^config-.*$ - - - ^/boot/config-.*$ - ^CONFIG_COMPAT_BRK="?(.*?)"?$ - 1 - - - oval:ssg-local_var_config_compat_brk_count_kernels_installed:var:1 - - - /boot - ^config-.*$ - - - ^/boot/config-.*$ - ^CONFIG_COMPAT_VDSO="?(.*?)"?$ - 1 - - - oval:ssg-local_var_config_compat_vdso_count_kernels_installed:var:1 - - - /boot - ^config-.*$ - - - ^/boot/config-.*$ - ^CONFIG_DEBUG_CREDENTIALS="?(.*?)"?$ - 1 - - - oval:ssg-local_var_config_debug_credentials_count_kernels_installed:var:1 - - - /boot - ^config-.*$ - - - ^/boot/config-.*$ - ^CONFIG_DEBUG_FS="?(.*?)"?$ - 1 - - - oval:ssg-local_var_config_debug_fs_count_kernels_installed:var:1 - - - /boot - ^config-.*$ - - - ^/boot/config-.*$ - ^CONFIG_DEBUG_LIST="?(.*?)"?$ - 1 - - - oval:ssg-local_var_config_debug_list_count_kernels_installed:var:1 - - - /boot - ^config-.*$ - - - ^/boot/config-.*$ - ^CONFIG_DEBUG_NOTIFIERS="?(.*?)"?$ - 1 - - - oval:ssg-local_var_config_debug_notifiers_count_kernels_installed:var:1 - - - /boot - ^config-.*$ - - - ^/boot/config-.*$ - ^CONFIG_DEBUG_SG="?(.*?)"?$ - 1 - - - oval:ssg-local_var_config_debug_sg_count_kernels_installed:var:1 - - - /boot - ^config-.*$ - - - ^/boot/config-.*$ - ^CONFIG_DEFAULT_MMAP_MIN_ADDR="?(.*?)"?$ - 1 - - - oval:ssg-local_var_config_default_mmap_min_addr_count_kernels_installed:var:1 - - - /boot - ^config-.*$ - - - ^/boot/config-.*$ - ^CONFIG_DEVKMEM="?(.*?)"?$ - 1 - - - oval:ssg-local_var_config_devkmem_count_kernels_installed:var:1 - - - /boot - ^config-.*$ - - - ^/boot/config-.*$ - ^CONFIG_HIBERNATION="?(.*?)"?$ - 1 - - - oval:ssg-local_var_config_hibernation_count_kernels_installed:var:1 - - - /boot - ^config-.*$ - - - ^/boot/config-.*$ - ^CONFIG_IA32_EMULATION="?(.*?)"?$ - 1 - - - oval:ssg-local_var_config_ia32_emulation_count_kernels_installed:var:1 - - - /boot - ^config-.*$ - - - ^/boot/config-.*$ - ^CONFIG_IPV6="?(.*?)"?$ - 1 - - - oval:ssg-local_var_config_ipv6_count_kernels_installed:var:1 - - - /boot - ^config-.*$ - - - ^/boot/config-.*$ - ^CONFIG_KEXEC="?(.*?)"?$ - 1 - - - oval:ssg-local_var_config_kexec_count_kernels_installed:var:1 - - - /boot - ^config-.*$ - - - ^/boot/config-.*$ - ^CONFIG_LEGACY_PTYS="?(.*?)"?$ - 1 - - - oval:ssg-local_var_config_legacy_ptys_count_kernels_installed:var:1 - - - /boot - ^config-.*$ - - - ^/boot/config-.*$ - ^CONFIG_MODULE_SIG="?(.*?)"?$ - 1 - - - oval:ssg-local_var_config_module_sig_count_kernels_installed:var:1 - - - /boot - ^config-.*$ - - - ^/boot/config-.*$ - ^CONFIG_MODULE_SIG_ALL="?(.*?)"?$ - 1 - - - oval:ssg-local_var_config_module_sig_all_count_kernels_installed:var:1 - - - /boot - ^config-.*$ - - - ^/boot/config-.*$ - ^CONFIG_MODULE_SIG_FORCE="?(.*?)"?$ - 1 - - - oval:ssg-local_var_config_module_sig_force_count_kernels_installed:var:1 - - - /boot - ^config-.*$ - - - ^/boot/config-.*$ - ^CONFIG_MODULE_SIG_HASH="?(.*?)"?$ - 1 - - - oval:ssg-local_var_config_module_sig_hash_count_kernels_installed:var:1 - - - /boot - ^config-.*$ - - - ^/boot/config-.*$ - ^CONFIG_MODULE_SIG_KEY="?(.*?)"?$ - 1 - - - oval:ssg-local_var_config_module_sig_key_count_kernels_installed:var:1 - - - /boot - ^config-.*$ - - - ^/boot/config-.*$ - ^CONFIG_MODULE_SIG_SHA512="?(.*?)"?$ - 1 - - - oval:ssg-local_var_config_module_sig_sha512_count_kernels_installed:var:1 - - - /boot - ^config-.*$ - - - ^/boot/config-.*$ - ^CONFIG_PAGE_POISONING_NO_SANITY="?(.*?)"?$ - 1 - - - oval:ssg-local_var_config_page_poisoning_no_sanity_count_kernels_installed:var:1 - - - /boot - ^config-.*$ - - - ^/boot/config-.*$ - ^CONFIG_PAGE_POISONING_ZERO="?(.*?)"?$ - 1 - - - oval:ssg-local_var_config_page_poisoning_zero_count_kernels_installed:var:1 - - - /boot - ^config-.*$ - - - ^/boot/config-.*$ - ^CONFIG_PAGE_TABLE_ISOLATION="?(.*?)"?$ - 1 - - - oval:ssg-local_var_config_page_table_isolation_count_kernels_installed:var:1 - - - /boot - ^config-.*$ - - - ^/boot/config-.*$ - ^CONFIG_PANIC_ON_OOPS="?(.*?)"?$ - 1 - - - oval:ssg-local_var_config_panic_on_oops_count_kernels_installed:var:1 - - - /boot - ^config-.*$ - - - ^/boot/config-.*$ - ^CONFIG_PANIC_TIMEOUT="?(.*?)"?$ - 1 - - - oval:ssg-local_var_config_panic_timeout_count_kernels_installed:var:1 - - - /boot - ^config-.*$ - - - ^/boot/config-.*$ - ^CONFIG_PROC_KCORE="?(.*?)"?$ - 1 - - - oval:ssg-local_var_config_proc_kcore_count_kernels_installed:var:1 - - - /boot - ^config-.*$ - - - ^/boot/config-.*$ - ^CONFIG_RANDOMIZE_BASE="?(.*?)"?$ - 1 - - - oval:ssg-local_var_config_randomize_base_count_kernels_installed:var:1 - - - /boot - ^config-.*$ - - - ^/boot/config-.*$ - ^CONFIG_RANDOMIZE_MEMORY="?(.*?)"?$ - 1 - - - oval:ssg-local_var_config_randomize_memory_count_kernels_installed:var:1 - - - /boot - ^config-.*$ - - - ^/boot/config-.*$ - ^CONFIG_RETPOLINE="?(.*?)"?$ - 1 - - - oval:ssg-local_var_config_retpoline_count_kernels_installed:var:1 - - - /boot - ^config-.*$ - - - ^/boot/config-.*$ - ^CONFIG_SECCOMP="?(.*?)"?$ - 1 - - - oval:ssg-local_var_config_seccomp_count_kernels_installed:var:1 - - - /boot - ^config-.*$ - - - ^/boot/config-.*$ - ^CONFIG_SECCOMP_FILTER="?(.*?)"?$ - 1 - - - oval:ssg-local_var_config_seccomp_filter_count_kernels_installed:var:1 - - - /boot - ^config-.*$ - - - ^/boot/config-.*$ - ^CONFIG_SECURITY="?(.*?)"?$ - 1 - - - oval:ssg-local_var_config_security_count_kernels_installed:var:1 - - - /boot - ^config-.*$ - - - ^/boot/config-.*$ - ^CONFIG_SECURITY_DMESG_RESTRICT="?(.*?)"?$ - 1 - - - oval:ssg-local_var_config_security_dmesg_restrict_count_kernels_installed:var:1 - - - /boot - ^config-.*$ - - - ^/boot/config-.*$ - ^CONFIG_SECURITY_WRITABLE_HOOKS="?(.*?)"?$ - 1 - - - oval:ssg-local_var_config_security_writable_hooks_count_kernels_installed:var:1 - - - /boot - ^config-.*$ - - - ^/boot/config-.*$ - ^CONFIG_SECURITY_YAMA="?(.*?)"?$ - 1 - - - oval:ssg-local_var_config_security_yama_count_kernels_installed:var:1 - - - /boot - ^config-.*$ - - - ^/boot/config-.*$ - ^CONFIG_SLUB_DEBUG="?(.*?)"?$ - 1 - - - oval:ssg-local_var_config_slub_debug_count_kernels_installed:var:1 - - - /boot - ^config-.*$ - - - ^/boot/config-.*$ - ^CONFIG_SYN_COOKIES="?(.*?)"?$ - 1 - - - oval:ssg-local_var_config_syn_cookies_count_kernels_installed:var:1 - - - /boot - ^config-.*$ - - - ^/boot/config-.*$ - ^CONFIG_UNMAP_KERNEL_AT_EL0="?(.*?)"?$ - 1 - - - oval:ssg-local_var_config_unmap_kernel_at_el0_count_kernels_installed:var:1 - - - /boot - ^config-.*$ - - - ^/boot/config-.*$ - ^CONFIG_X86_VSYSCALL_EMULATION="?(.*?)"?$ - 1 - - - oval:ssg-local_var_config_x86_vsyscall_emulation_count_kernels_installed:var:1 - - - /boot - ^config-.*$ - - - - ^.*\.conf$ - ^\s*install\s+atm\s+(/bin/false|/bin/true)$ - 1 - - - - ^.*\.conf$ - ^blacklist\s+atm$ - 1 - - - - ^.*\.conf$ - ^\s*install\s+bluetooth\s+(/bin/false|/bin/true)$ - 1 - - - - ^.*\.conf$ - ^blacklist\s+bluetooth$ - 1 - - - - ^.*\.conf$ - ^\s*install\s+can\s+(/bin/false|/bin/true)$ - 1 - - - - ^.*\.conf$ - ^blacklist\s+can$ - 1 - - - - ^.*\.conf$ - ^\s*install\s+cramfs\s+(/bin/false|/bin/true)$ - 1 - - - - ^.*\.conf$ - ^blacklist\s+cramfs$ - 1 - - - - ^.*\.conf$ - ^\s*install\s+firewire-core\s+(/bin/false|/bin/true)$ - 1 - - - - ^.*\.conf$ - ^blacklist\s+firewire-core$ - 1 - - - - ^.*\.conf$ - ^\s*install\s+rds\s+(/bin/false|/bin/true)$ - 1 - - - - ^.*\.conf$ - ^blacklist\s+rds$ - 1 - - - - ^.*\.conf$ - ^\s*install\s+sctp\s+(/bin/false|/bin/true)$ - 1 - - - - ^.*\.conf$ - ^blacklist\s+sctp$ - 1 - - - - ^.*\.conf$ - ^\s*install\s+tipc\s+(/bin/false|/bin/true)$ - 1 - - - - ^.*\.conf$ - ^blacklist\s+tipc$ - 1 - - - - ^.*\.conf$ - ^\s*install\s+usb-storage\s+(/bin/false|/bin/true)$ - 1 - - - - ^.*\.conf$ - ^blacklist\s+usb-storage$ - 1 - - - - ^.*\.conf$ - ^\s*install\s+uvcvideo\s+(/bin/false|/bin/true)$ - 1 - - - - ^.*\.conf$ - ^blacklist\s+uvcvideo$ - 1 - - - /boot - - - /etc/fstab - ^[\s]*(?!#)[\S]+[\s]+/boot[\s]+[\S]+[\s]+([\S]+) - 1 - - - /boot - - - /etc/fstab - ^[\s]*(?!#)[\S]+[\s]+/boot[\s]+[\S]+[\s]+([\S]+) - 1 - - - /boot - - - /etc/fstab - ^[\s]*(?!#)[\S]+[\s]+/boot[\s]+[\S]+[\s]+([\S]+) - 1 - - - /dev/shm - - - /etc/fstab - ^[\s]*(?!#)[\S]+[\s]+/dev/shm[\s]+[\S]+[\s]+([\S]+) - 1 - - - /dev/shm - - - /etc/fstab - ^[\s]*(?!#)[\S]+[\s]+/dev/shm[\s]+[\S]+[\s]+([\S]+) - 1 - - - /dev/shm - - - /etc/fstab - ^[\s]*(?!#)[\S]+[\s]+/dev/shm[\s]+[\S]+[\s]+([\S]+) - 1 - - - /etc/passwd - - 1 - - - / - - - - - - /home - - - /etc/fstab - ^[\s]*(?!#)[\S]+[\s]+/home[\s]+[\S]+[\s]+([\S]+) - 1 - - - /etc/passwd - - 1 - - - / - - - - - - /etc/passwd - - 1 - - - / - - - - - - /etc/passwd - - 1 - - - / - - - - - - /etc/fstab - ^\s*\[?[\.\w:-]+\]?[:=][/\w-]+\s+[/\w\\-]+\s+nfs[4]?\s+(.*)$ - 0 - - - /etc/fstab - ^\s*\[?[\.\w:-]+\]?[:=][/\w-]+\s+[/\w\\-]+\s+nfs[4]?\s+(.*)$ - 0 - - - /etc/fstab - ^\s*\[?[\.\w:-]+\]?[:=][/\w-]+\s+[/\w\\-]+\s+nfs[4]?\s+(.*)$ - 0 - - - /etc/fstab - ^\s*\[?[\.\w:-]+\]?[:=][/\w-]+\s+[/\w\\-]+\s+nfs[4]?\s+(.*)$ - 0 - - - /etc/fstab - - 1 - - - /etc/fstab - - 1 - - - /etc/fstab - ^\s*\[?[\.\w:-]+\]?[:=][/\w-]+\s+[/\w\\-]+\s+nfs[4]?\s+(.*)$ - 0 - - - /etc/fstab - ^\s*\[?[\.\w:-]+\]?[:=][/\w-]+\s+[/\w\\-]+\s+nfs[4]?\s+(.*)$ - 0 - - - /etc/fstab - - 1 - - - /etc/fstab - - 1 - - - /etc/fstab - ^\s*\[?[\.\w:-]+\]?[:=][/\w-]+\s+[/\w\\-]+\s+nfs[4]?\s+(.*)$ - 0 - - - /etc/fstab - ^\s*\[?[\.\w:-]+\]?[:=][/\w-]+\s+[/\w\\-]+\s+nfs[4]?\s+(.*)$ - 0 - - - /etc/fstab - - 1 - - - /etc/fstab - - 1 - - - /opt - - - /etc/fstab - ^[\s]*(?!#)[\S]+[\s]+/opt[\s]+[\S]+[\s]+([\S]+) - 1 - - - /srv - - - /etc/fstab - ^[\s]*(?!#)[\S]+[\s]+/srv[\s]+[\S]+[\s]+([\S]+) - 1 - - - /tmp - - - /etc/fstab - ^[\s]*(?!#)[\S]+[\s]+/tmp[\s]+[\S]+[\s]+([\S]+) - 1 - - - /tmp - - - /etc/fstab - ^[\s]*(?!#)[\S]+[\s]+/tmp[\s]+[\S]+[\s]+([\S]+) - 1 - - - /tmp - - - /etc/fstab - ^[\s]*(?!#)[\S]+[\s]+/tmp[\s]+[\S]+[\s]+([\S]+) - 1 - - - /var/log/audit - - - /etc/fstab - ^[\s]*(?!#)[\S]+[\s]+/var/log/audit[\s]+[\S]+[\s]+([\S]+) - 1 - - - /var/log/audit - - - /etc/fstab - ^[\s]*(?!#)[\S]+[\s]+/var/log/audit[\s]+[\S]+[\s]+([\S]+) - 1 - - - /var/log/audit - - - /etc/fstab - ^[\s]*(?!#)[\S]+[\s]+/var/log/audit[\s]+[\S]+[\s]+([\S]+) - 1 - - - /var/log - - - /etc/fstab - ^[\s]*(?!#)[\S]+[\s]+/var/log[\s]+[\S]+[\s]+([\S]+) - 1 - - - /var/log - - - /etc/fstab - ^[\s]*(?!#)[\S]+[\s]+/var/log[\s]+[\S]+[\s]+([\S]+) - 1 - - - /var/log - - - /etc/fstab - ^[\s]*(?!#)[\S]+[\s]+/var/log[\s]+[\S]+[\s]+([\S]+) - 1 - - - /var - - - /etc/fstab - ^[\s]*(?!#)[\S]+[\s]+/var[\s]+[\S]+[\s]+([\S]+) - 1 - - - /var - - - /etc/fstab - ^[\s]*(?!#)[\S]+[\s]+/var[\s]+[\S]+[\s]+([\S]+) - 1 - - - /var - - - /etc/fstab - ^[\s]*(?!#)[\S]+[\s]+/var[\s]+[\S]+[\s]+([\S]+) - 1 - - - /var/tmp - - - /etc/fstab - ^[\s]*(?!#)[\S]+[\s]+/var/tmp[\s]+[\S]+[\s]+([\S]+) - 1 - - - /var/tmp - - - /etc/fstab - ^[\s]*(?!#)[\S]+[\s]+/var/tmp[\s]+[\S]+[\s]+([\S]+) - 1 - - - /var/tmp - - - /etc/fstab - ^[\s]*(?!#)[\S]+[\s]+/var/tmp[\s]+[\S]+[\s]+([\S]+) - 1 - - - GConf2 - - - MFEhiplsm - - - aide - - - audispd-plugins - - - audit-audispd-plugins - - - audit - - - avahi - - - bind - - - chrony - - - cron - - - crypto-policies - - - dconf - - - dhcp - - - dnf-automatic - - - esc - - - fapolicyd - - - firewalld - - - gdm - - - gnutls-utils - - - gssproxy - - - inetutils-telnetd - - - iprutils - - - krb5-workstation - - - libreswan - - - logrotate - - - McAfeeTP - - - nfs-utils - - - nis - - - nss-tools - - - ntp - - - ntpdate - - - opensc - - - openscap-scanner - - - openssh-clients - - - openssh-server - - - openssh-server - - - pam_ldap - - - pcsc-lite - - - policycoreutils-python-utils - - - policycoreutils - - - postfix - - - prelink - - - quagga - - - rear - - - rng-tools - - - rsh-server - - - rsh - - - rsyslog-gnutls - - - rsyslog - - - samba-common - - - scap-security-guide - - - sendmail - - - setroubleshoot-plugins - - - setroubleshoot-server - - - setroubleshoot - - - squid - - - sudo - - - syslog-ng - - - talk-server - - - talk - - - telnet-server - - - telnet - - - telnetd-ssl - - - telnetd - - - tftp-server - - - tftp - - - tmux - - - tuned - - - usbguard - - - vsftpd - - - xinetd - - - xorg-x11-server-common - - - /dev/shm - - - /home - - - /srv - - - /tmp - - - /var - - - /var/log - - - /var/log/audit - - - /var/tmp - - - - /lib - ^.*$ - oval:ssg-symlink_file_groupownerroot_permissions_syslibrary_files_uid_0:ste:1 - oval:ssg-state_file_groupownerroot_permissions_syslibrary_files_gid_0_0:ste:1 - - - - /lib64 - ^.*$ - oval:ssg-symlink_file_groupownerroot_permissions_syslibrary_files_uid_0:ste:1 - oval:ssg-state_file_groupownerroot_permissions_syslibrary_files_gid_0_1:ste:1 - - - - /usr/lib - ^.*$ - oval:ssg-symlink_file_groupownerroot_permissions_syslibrary_files_uid_0:ste:1 - oval:ssg-state_file_groupownerroot_permissions_syslibrary_files_gid_0_2:ste:1 - - - - /usr/lib64 - ^.*$ - oval:ssg-symlink_file_groupownerroot_permissions_syslibrary_files_uid_0:ste:1 - oval:ssg-state_file_groupownerroot_permissions_syslibrary_files_gid_0_3:ste:1 - - - /etc/rsyslog.conf - ^(?:include\([\n\s]*file="([^\s;]+)".*|\$IncludeConfig[\s]+([^\s;]+))$ - 1 - - - oval:ssg-var_rsyslog_files_groupownership_include_config_regex:var:1 - - - oval:ssg-var_rsyslog_files_groupownership_syslog_config:var:1 - - - - oval:ssg-object_var_rsyslog_files_groupownership_include_config_regex:obj:1 - oval:ssg-object_var_rsyslog_files_groupownership_syslog_config:obj:1 - - - - - ^\s*[^(\s|#|\$)]+\s+.*\s+-?[\w\(="\s]*(\/[^:;\s"]+)+.*$ - 1 - oval:ssg-state_rsyslog_files_groupownership_ignore_include_paths:ste:1 - - - - - - /etc/rsyslog.conf - ^(?:include\([\n\s]*file="([^\s;]+)".*|\$IncludeConfig[\s]+([^\s;]+))$ - 1 - - - oval:ssg-var_rsyslog_files_ownership_include_config_regex:var:1 - - - oval:ssg-var_rsyslog_files_ownership_syslog_config:var:1 - - - - oval:ssg-object_var_rsyslog_files_ownership_include_config_regex:obj:1 - oval:ssg-object_var_rsyslog_files_ownership_syslog_config:obj:1 - - - - - ^\s*[^(\s|#|\$)]+\s+.*\s+-?[\w\(="\s]*(\/[^:;\s"]+)+.*$ - 1 - oval:ssg-state_rsyslog_files_ownership_ignore_include_paths:ste:1 - - - - - - /etc/rsyslog.conf - ^(?:include\([\n\s]*file="([^\s;]+)".*|\$IncludeConfig[\s]+([^\s;]+))$ - 1 - - - oval:ssg-var_rsyslog_files_permissions_include_config_regex:var:1 - - - oval:ssg-var_rsyslog_files_permissions_syslog_config:var:1 - - - - oval:ssg-object_var_rsyslog_files_permissions_include_config_regex:obj:1 - oval:ssg-object_var_rsyslog_files_permissions_syslog_config:obj:1 - - - - - ^\s*[^(\s|#|\$)]+\s+.*\s+-?[\w\(="\s]*(\/[^:;\s"]+)+.*$ - 1 - oval:ssg-state_rsyslog_files_permissions_ignore_include_paths:ste:1 - - - - - - deny_execmem - - - polyinstantiation_enabled - - - secure_mode_insmod - - - selinuxuser_execheap - - - selinuxuser_execmod - - - selinuxuser_execstack - - - ssh_sysadm_login - - - ^abrtd\.(service|socket)$ - ActiveState - - - ^abrtd\.(service|socket)$ - LoadState - - - abrt - - - ^atd\.(service|socket)$ - ActiveState - - - ^atd\.(service|socket)$ - LoadState - - - at - - - multi-user.target - - - multi-user.target - - - ^auditd\.(socket|service)$ - ActiveState - - - audit - - - ^autofs\.(service|socket)$ - ActiveState - - - ^autofs\.(service|socket)$ - LoadState - - - autofs - - - ^avahi-daemon\.(service|socket)$ - ActiveState - - - ^avahi-daemon\.(service|socket)$ - LoadState - - - avahi - - - multi-user.target - - - multi-user.target - - - ^chronyd\.(socket|service)$ - ActiveState - - - chrony - - - multi-user.target - - - multi-user.target - - - ^cron\.(socket|service)$ - ActiveState - - - cron - - - multi-user.target - - - multi-user.target - - - ^crond\.(socket|service)$ - ActiveState - - - cronie - - - ^debug-shell\.(service|socket)$ - ActiveState - - - ^debug-shell\.(service|socket)$ - LoadState - - - systemd - - - multi-user.target - - - multi-user.target - - - ^fapolicyd\.(socket|service)$ - ActiveState - - - fapolicyd - - - multi-user.target - - - multi-user.target - - - ^firewalld\.(socket|service)$ - ActiveState - - - firewalld - - - multi-user.target - - - multi-user.target - - - ^ip6tables\.(socket|service)$ - ActiveState - - - iptables-ipv6 - - - multi-user.target - - - multi-user.target - - - ^iptables\.(socket|service)$ - ActiveState - - - iptables - - - ^kdump\.(service|socket)$ - ActiveState - - - ^kdump\.(service|socket)$ - LoadState - - - kexec-tools - - - ^netfs\.(service|socket)$ - ActiveState - - - ^netfs\.(service|socket)$ - LoadState - - - netfs - - - multi-user.target - - - multi-user.target - - - ^ntp\.(socket|service)$ - ActiveState - - - ntp - - - multi-user.target - - - multi-user.target - - - ^ntpd\.(socket|service)$ - ActiveState - - - ntp - - - ^ntpdate\.(service|socket)$ - ActiveState - - - ^ntpdate\.(service|socket)$ - LoadState - - - ntpdate - - - ^oddjobd\.(service|socket)$ - ActiveState - - - ^oddjobd\.(service|socket)$ - LoadState - - - oddjob - - - multi-user.target - - - multi-user.target - - - ^pcscd\.(socket|service)$ - ActiveState - - - pcsc-lite - - - multi-user.target - - - multi-user.target - - - ^postfix\.(socket|service)$ - ActiveState - - - postfix - - - ^qpidd\.(service|socket)$ - ActiveState - - - ^qpidd\.(service|socket)$ - LoadState - - - qpid-cpp-server - - - ^rdisc\.(service|socket)$ - ActiveState - - - ^rdisc\.(service|socket)$ - LoadState - - - iputils - - - ^rlogin\.(service|socket)$ - ActiveState - - - ^rlogin\.(service|socket)$ - LoadState - - - rsh-server - - - multi-user.target - - - multi-user.target - - - ^rngd\.(socket|service)$ - ActiveState - - - rng-tools - - - multi-user.target - - - multi-user.target - - - ^rsyslog\.(socket|service)$ - ActiveState - - - rsyslog - - - ^squid\.(service|socket)$ - ActiveState - - - ^squid\.(service|socket)$ - LoadState - - - squid - - - ^sshd\.(service|socket)$ - ActiveState - - - ^sshd\.(service|socket)$ - LoadState - - - openssh-server - - - multi-user.target - - - multi-user.target - - - ^sshd\.(socket|service)$ - ActiveState - - - openssh-server - - - ^syslog\.(service|socket)$ - ActiveState - - - ^syslog\.(service|socket)$ - LoadState - - - rsyslog - - - multi-user.target - - - multi-user.target - - - ^syslog-ng\.(socket|service)$ - ActiveState - - - syslog-ng - - - ^systemd-coredump.socket$ - LoadState - - - multi-user.target - - - multi-user.target - - - ^systemd-journald\.(socket|service)$ - ActiveState - - - systemd - - - ^telnet\.(service|socket)$ - ActiveState - - - ^telnet\.(service|socket)$ - LoadState - - - telnet-server - - - multi-user.target - - - multi-user.target - - - ^ufw\.(socket|service)$ - ActiveState - - - ufw - - - multi-user.target - - - multi-user.target - - - ^usbguard\.(socket|service)$ - ActiveState - - - usbguard - - - ^xinetd\.(service|socket)$ - ActiveState - - - ^xinetd\.(service|socket)$ - LoadState - - - xinetd - - - /etc/ssh/sshd_config - ^[ \t]*(?i)include(?-i)[ \t]+(.+?)[ \t]*(?:$|#) - 1 - - - - ^[ \t]*(?i)PermitEmptyPasswords(?-i)[ \t]+(.+?)[ \t]*(?:$|#) - 1 - - - /etc/ssh/sshd_config - ^[ \t]*(?i)PermitEmptyPasswords(?-i)[ \t]+(.+?)[ \t]*(?:$|#) - 1 - - - - oval:ssg-obj_sshd_disable_empty_passwords:obj:1 - oval:ssg-obj_sshd_disable_empty_passwords_sshd_included_files:obj:1 - - - - /etc/ssh/sshd_config - ^[ \t]*(?i)include(?-i)[ \t]+(.+?)[ \t]*(?:$|#) - 1 - - - - ^[ \t]*(?i)GSSAPIAuthentication(?-i)[ \t]+(.+?)[ \t]*(?:$|#) - 1 - - - /etc/ssh/sshd_config - ^[ \t]*(?i)GSSAPIAuthentication(?-i)[ \t]+(.+?)[ \t]*(?:$|#) - 1 - - - - oval:ssg-obj_sshd_disable_gssapi_auth:obj:1 - oval:ssg-obj_sshd_disable_gssapi_auth_sshd_included_files:obj:1 - - - - /etc/ssh/sshd_config - ^[ \t]*(?i)include(?-i)[ \t]+(.+?)[ \t]*(?:$|#) - 1 - - - - ^[ \t]*(?i)KerberosAuthentication(?-i)[ \t]+(.+?)[ \t]*(?:$|#) - 1 - - - /etc/ssh/sshd_config - ^[ \t]*(?i)KerberosAuthentication(?-i)[ \t]+(.+?)[ \t]*(?:$|#) - 1 - - - - oval:ssg-obj_sshd_disable_kerb_auth:obj:1 - oval:ssg-obj_sshd_disable_kerb_auth_sshd_included_files:obj:1 - - - - /etc/ssh/sshd_config - ^[ \t]*(?i)include(?-i)[ \t]+(.+?)[ \t]*(?:$|#) - 1 - - - - ^[ \t]*(?i)PubkeyAuthentication(?-i)[ \t]+(.+?)[ \t]*(?:$|#) - 1 - - - /etc/ssh/sshd_config - ^[ \t]*(?i)PubkeyAuthentication(?-i)[ \t]+(.+?)[ \t]*(?:$|#) - 1 - - - - oval:ssg-obj_sshd_disable_pubkey_auth:obj:1 - oval:ssg-obj_sshd_disable_pubkey_auth_sshd_included_files:obj:1 - - - - /etc/ssh/sshd_config - ^[ \t]*(?i)include(?-i)[ \t]+(.+?)[ \t]*(?:$|#) - 1 - - - - ^[ \t]*(?i)IgnoreRhosts(?-i)[ \t]+(.+?)[ \t]*(?:$|#) - 1 - - - /etc/ssh/sshd_config - ^[ \t]*(?i)IgnoreRhosts(?-i)[ \t]+(.+?)[ \t]*(?:$|#) - 1 - - - - oval:ssg-obj_sshd_disable_rhosts:obj:1 - oval:ssg-obj_sshd_disable_rhosts_sshd_included_files:obj:1 - - - - /etc/ssh/sshd_config - ^[ \t]*(?i)include(?-i)[ \t]+(.+?)[ \t]*(?:$|#) - 1 - - - - ^[ \t]*(?i)PermitRootLogin(?-i)[ \t]+(.+?)[ \t]*(?:$|#) - 1 - - - /etc/ssh/sshd_config - ^[ \t]*(?i)PermitRootLogin(?-i)[ \t]+(.+?)[ \t]*(?:$|#) - 1 - - - - oval:ssg-obj_sshd_disable_root_login:obj:1 - oval:ssg-obj_sshd_disable_root_login_sshd_included_files:obj:1 - - - - /etc/ssh/sshd_config - ^[ \t]*(?i)include(?-i)[ \t]+(.+?)[ \t]*(?:$|#) - 1 - - - - ^[ \t]*(?i)PermitRootLogin(?-i)[ \t]+(.+?)[ \t]*(?:$|#) - 1 - - - /etc/ssh/sshd_config - ^[ \t]*(?i)PermitRootLogin(?-i)[ \t]+(.+?)[ \t]*(?:$|#) - 1 - - - - oval:ssg-obj_sshd_disable_root_password_login:obj:1 - oval:ssg-obj_sshd_disable_root_password_login_sshd_included_files:obj:1 - - - - /etc/ssh/sshd_config - ^[ \t]*(?i)include(?-i)[ \t]+(.+?)[ \t]*(?:$|#) - 1 - - - - ^[ \t]*(?i)AllowTcpForwarding(?-i)[ \t]+(.+?)[ \t]*(?:$|#) - 1 - - - /etc/ssh/sshd_config - ^[ \t]*(?i)AllowTcpForwarding(?-i)[ \t]+(.+?)[ \t]*(?:$|#) - 1 - - - - oval:ssg-obj_sshd_disable_tcp_forwarding:obj:1 - oval:ssg-obj_sshd_disable_tcp_forwarding_sshd_included_files:obj:1 - - - - /etc/ssh/sshd_config - ^[ \t]*(?i)include(?-i)[ \t]+(.+?)[ \t]*(?:$|#) - 1 - - - - ^[ \t]*(?i)IgnoreUserKnownHosts(?-i)[ \t]+(.+?)[ \t]*(?:$|#) - 1 - - - /etc/ssh/sshd_config - ^[ \t]*(?i)IgnoreUserKnownHosts(?-i)[ \t]+(.+?)[ \t]*(?:$|#) - 1 - - - - oval:ssg-obj_sshd_disable_user_known_hosts:obj:1 - oval:ssg-obj_sshd_disable_user_known_hosts_sshd_included_files:obj:1 - - - - /etc/ssh/sshd_config - ^[ \t]*(?i)include(?-i)[ \t]+(.+?)[ \t]*(?:$|#) - 1 - - - - ^[ \t]*(?i)X11Forwarding(?-i)[ \t]+(.+?)[ \t]*(?:$|#) - 1 - - - /etc/ssh/sshd_config - ^[ \t]*(?i)X11Forwarding(?-i)[ \t]+(.+?)[ \t]*(?:$|#) - 1 - - - - oval:ssg-obj_sshd_disable_x11_forwarding:obj:1 - oval:ssg-obj_sshd_disable_x11_forwarding_sshd_included_files:obj:1 - - - - /etc/ssh/sshd_config - ^[ \t]*(?i)include(?-i)[ \t]+(.+?)[ \t]*(?:$|#) - 1 - - - - ^[ \t]*(?i)PermitUserEnvironment(?-i)[ \t]+(.+?)[ \t]*(?:$|#) - 1 - - - /etc/ssh/sshd_config - ^[ \t]*(?i)PermitUserEnvironment(?-i)[ \t]+(.+?)[ \t]*(?:$|#) - 1 - - - - oval:ssg-obj_sshd_do_not_permit_user_env:obj:1 - oval:ssg-obj_sshd_do_not_permit_user_env_sshd_included_files:obj:1 - - - - /etc/ssh/sshd_config - ^[ \t]*(?i)include(?-i)[ \t]+(.+?)[ \t]*(?:$|#) - 1 - - - - ^[ \t]*(?i)GSSAPIAuthentication(?-i)[ \t]+(.+?)[ \t]*(?:$|#) - 1 - - - /etc/ssh/sshd_config - ^[ \t]*(?i)GSSAPIAuthentication(?-i)[ \t]+(.+?)[ \t]*(?:$|#) - 1 - - - - oval:ssg-obj_sshd_enable_gssapi_auth:obj:1 - oval:ssg-obj_sshd_enable_gssapi_auth_sshd_included_files:obj:1 - - - - /etc/ssh/sshd_config - ^[ \t]*(?i)include(?-i)[ \t]+(.+?)[ \t]*(?:$|#) - 1 - - - - ^[ \t]*(?i)UsePAM(?-i)[ \t]+(.+?)[ \t]*(?:$|#) - 1 - - - /etc/ssh/sshd_config - ^[ \t]*(?i)UsePAM(?-i)[ \t]+(.+?)[ \t]*(?:$|#) - 1 - - - - oval:ssg-obj_sshd_enable_pam:obj:1 - oval:ssg-obj_sshd_enable_pam_sshd_included_files:obj:1 - - - - /etc/ssh/sshd_config - ^[ \t]*(?i)include(?-i)[ \t]+(.+?)[ \t]*(?:$|#) - 1 - - - - ^[ \t]*(?i)PubkeyAuthentication(?-i)[ \t]+(.+?)[ \t]*(?:$|#) - 1 - - - /etc/ssh/sshd_config - ^[ \t]*(?i)PubkeyAuthentication(?-i)[ \t]+(.+?)[ \t]*(?:$|#) - 1 - - - - oval:ssg-obj_sshd_enable_pubkey_auth:obj:1 - oval:ssg-obj_sshd_enable_pubkey_auth_sshd_included_files:obj:1 - - - - /etc/ssh/sshd_config - ^[ \t]*(?i)include(?-i)[ \t]+(.+?)[ \t]*(?:$|#) - 1 - - - - ^[ \t]*(?i)StrictModes(?-i)[ \t]+(.+?)[ \t]*(?:$|#) - 1 - - - /etc/ssh/sshd_config - ^[ \t]*(?i)StrictModes(?-i)[ \t]+(.+?)[ \t]*(?:$|#) - 1 - - - - oval:ssg-obj_sshd_enable_strictmodes:obj:1 - oval:ssg-obj_sshd_enable_strictmodes_sshd_included_files:obj:1 - - - - /etc/ssh/sshd_config - ^[ \t]*(?i)include(?-i)[ \t]+(.+?)[ \t]*(?:$|#) - 1 - - - - ^[ \t]*(?i)Banner(?-i)[ \t]+(.+?)[ \t]*(?:$|#) - 1 - - - /etc/ssh/sshd_config - ^[ \t]*(?i)Banner(?-i)[ \t]+(.+?)[ \t]*(?:$|#) - 1 - - - - oval:ssg-obj_sshd_enable_warning_banner:obj:1 - oval:ssg-obj_sshd_enable_warning_banner_sshd_included_files:obj:1 - - - - /etc/ssh/sshd_config - ^[ \t]*(?i)include(?-i)[ \t]+(.+?)[ \t]*(?:$|#) - 1 - - - - ^[ \t]*(?i)Banner(?-i)[ \t]+(.+?)[ \t]*(?:$|#) - 1 - - - /etc/ssh/sshd_config - ^[ \t]*(?i)Banner(?-i)[ \t]+(.+?)[ \t]*(?:$|#) - 1 - - - - oval:ssg-obj_sshd_enable_warning_banner_net:obj:1 - oval:ssg-obj_sshd_enable_warning_banner_net_sshd_included_files:obj:1 - - - - /etc/ssh/sshd_config - ^[ \t]*(?i)include(?-i)[ \t]+(.+?)[ \t]*(?:$|#) - 1 - - - - ^[ \t]*(?i)X11Forwarding(?-i)[ \t]+(.+?)[ \t]*(?:$|#) - 1 - - - /etc/ssh/sshd_config - ^[ \t]*(?i)X11Forwarding(?-i)[ \t]+(.+?)[ \t]*(?:$|#) - 1 - - - - oval:ssg-obj_sshd_enable_x11_forwarding:obj:1 - oval:ssg-obj_sshd_enable_x11_forwarding_sshd_included_files:obj:1 - - - - /etc/ssh/sshd_config - ^[\s]*Include /etc/ssh/sshd_config\.d/\*\.conf[\s]*$ - 1 - - - /etc/ssh/sshd_config - ^[ \t]*(?i)include(?-i)[ \t]+(.+?)[ \t]*(?:$|#) - 1 - - - - ^[ \t]*(?i)PrintLastLog(?-i)[ \t]+(.+?)[ \t]*(?:$|#) - 1 - - - /etc/ssh/sshd_config - ^[ \t]*(?i)PrintLastLog(?-i)[ \t]+(.+?)[ \t]*(?:$|#) - 1 - - - - oval:ssg-obj_sshd_print_last_log:obj:1 - oval:ssg-obj_sshd_print_last_log_sshd_included_files:obj:1 - - - - /etc/ssh/sshd_config - ^[ \t]*(?i)include(?-i)[ \t]+(.+?)[ \t]*(?:$|#) - 1 - - - - ^[ \t]*(?i)ClientAliveCountMax(?-i)[ \t]+(.+?)[ \t]*(?:$|#) - 1 - - - /etc/ssh/sshd_config - ^[ \t]*(?i)ClientAliveCountMax(?-i)[ \t]+(.+?)[ \t]*(?:$|#) - 1 - - - - oval:ssg-obj_sshd_set_keepalive_0:obj:1 - oval:ssg-obj_sshd_set_keepalive_0_sshd_included_files:obj:1 - - - - /etc/ssh/sshd_config - ^[ \t]*(?i)include(?-i)[ \t]+(.+?)[ \t]*(?:$|#) - 1 - - - - ^[ \t]*(?i)LogLevel(?-i)[ \t]+(.+?)[ \t]*(?:$|#) - 1 - - - /etc/ssh/sshd_config - ^[ \t]*(?i)LogLevel(?-i)[ \t]+(.+?)[ \t]*(?:$|#) - 1 - - - - oval:ssg-obj_sshd_set_loglevel_info:obj:1 - oval:ssg-obj_sshd_set_loglevel_info_sshd_included_files:obj:1 - - - - /etc/ssh/sshd_config - ^[ \t]*(?i)include(?-i)[ \t]+(.+?)[ \t]*(?:$|#) - 1 - - - - ^[ \t]*(?i)LogLevel(?-i)[ \t]+(.+?)[ \t]*(?:$|#) - 1 - - - /etc/ssh/sshd_config - ^[ \t]*(?i)LogLevel(?-i)[ \t]+(.+?)[ \t]*(?:$|#) - 1 - - - - oval:ssg-obj_sshd_set_loglevel_verbose:obj:1 - oval:ssg-obj_sshd_set_loglevel_verbose_sshd_included_files:obj:1 - - - - /etc/ssh/sshd_config - ^[ \t]*(?i)include(?-i)[ \t]+(.+?)[ \t]*(?:$|#) - 1 - - - - ^[ \t]*(?i)X11UseLocalhost(?-i)[ \t]+(.+?)[ \t]*(?:$|#) - 1 - - - /etc/ssh/sshd_config - ^[ \t]*(?i)X11UseLocalhost(?-i)[ \t]+(.+?)[ \t]*(?:$|#) - 1 - - - - oval:ssg-obj_sshd_x11_use_localhost:obj:1 - oval:ssg-obj_sshd_x11_use_localhost_sshd_included_files:obj:1 - - - - /etc/sssd/sssd.conf - ^[\s]*\[certmap\/.+\/.+\][\s]*$ - 1 - - - ^/etc/sudoers(|\.d/.*)$ - ^[\s]*Defaults[\s]*\bnoexec.*$ - 1 - - - ^/etc/sudoers(|\.d/.*)$ - ^[\s]*Defaults[\s]*\brequiretty.*$ - 1 - - - ^/etc/sudoers(|\.d/.*)$ - ^[\s]*Defaults[\s]*\buse_pty.*$ - 1 - - - ^/etc/sudoers(|\.d/.*)$ - ^[\s]*Defaults[\s]*\blogfile=("(?:\\"|\\\\|[^"\\\n])*"\B|[^"](?:(?:\\,|\\"|\\ |\\\\|[^", \\\n])*)\b).*$ - 1 - - - fs.protected_hardlinks - - - - oval:ssg-object_static_etc_sysctls_sysctl_fs_protected_hardlinks:obj:1 - oval:ssg-object_static_run_usr_local_sysctls_sysctl_fs_protected_hardlinks:obj:1 - - - - - oval:ssg-object_static_sysctl_sysctl_fs_protected_hardlinks:obj:1 - oval:ssg-object_static_etc_sysctld_sysctl_fs_protected_hardlinks:obj:1 - - - - - oval:ssg-object_static_usr_local_lib_sysctld_sysctl_fs_protected_hardlinks:obj:1 - oval:ssg-object_static_run_sysctld_sysctl_fs_protected_hardlinks:obj:1 - - - - /etc/sysctl.conf - ^[\s]*fs.protected_hardlinks[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /etc/sysctl.d - ^.*\.conf$ - ^[\s]*fs.protected_hardlinks[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /run/sysctl.d - ^.*\.conf$ - ^[\s]*fs.protected_hardlinks[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/local/lib/sysctl.d - ^.*\.conf$ - ^[\s]*fs.protected_hardlinks[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/lib/sysctl.d - ^.*\.conf$ - ^[\s]*fs.protected_hardlinks[\s]*=[\s]*(.*)[\s]*$ - 1 - - - fs.protected_symlinks - - - - oval:ssg-object_static_etc_sysctls_sysctl_fs_protected_symlinks:obj:1 - oval:ssg-object_static_run_usr_local_sysctls_sysctl_fs_protected_symlinks:obj:1 - - - - - oval:ssg-object_static_sysctl_sysctl_fs_protected_symlinks:obj:1 - oval:ssg-object_static_etc_sysctld_sysctl_fs_protected_symlinks:obj:1 - - - - - oval:ssg-object_static_usr_local_lib_sysctld_sysctl_fs_protected_symlinks:obj:1 - oval:ssg-object_static_run_sysctld_sysctl_fs_protected_symlinks:obj:1 - - - - /etc/sysctl.conf - ^[\s]*fs.protected_symlinks[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /etc/sysctl.d - ^.*\.conf$ - ^[\s]*fs.protected_symlinks[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /run/sysctl.d - ^.*\.conf$ - ^[\s]*fs.protected_symlinks[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/local/lib/sysctl.d - ^.*\.conf$ - ^[\s]*fs.protected_symlinks[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/lib/sysctl.d - ^.*\.conf$ - ^[\s]*fs.protected_symlinks[\s]*=[\s]*(.*)[\s]*$ - 1 - - - fs.suid_dumpable - - - - oval:ssg-object_static_etc_sysctls_sysctl_fs_suid_dumpable:obj:1 - oval:ssg-object_static_run_usr_local_sysctls_sysctl_fs_suid_dumpable:obj:1 - - - - - oval:ssg-object_static_sysctl_sysctl_fs_suid_dumpable:obj:1 - oval:ssg-object_static_etc_sysctld_sysctl_fs_suid_dumpable:obj:1 - - - - - oval:ssg-object_static_usr_local_lib_sysctld_sysctl_fs_suid_dumpable:obj:1 - oval:ssg-object_static_run_sysctld_sysctl_fs_suid_dumpable:obj:1 - - - - /etc/sysctl.conf - ^[\s]*fs.suid_dumpable[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /etc/sysctl.d - ^.*\.conf$ - ^[\s]*fs.suid_dumpable[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /run/sysctl.d - ^.*\.conf$ - ^[\s]*fs.suid_dumpable[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/local/lib/sysctl.d - ^.*\.conf$ - ^[\s]*fs.suid_dumpable[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/lib/sysctl.d - ^.*\.conf$ - ^[\s]*fs.suid_dumpable[\s]*=[\s]*(.*)[\s]*$ - 1 - - - kernel.core_pattern - - - - oval:ssg-object_static_etc_sysctls_sysctl_kernel_core_pattern:obj:1 - oval:ssg-object_static_run_usr_local_sysctls_sysctl_kernel_core_pattern:obj:1 - - - - - oval:ssg-object_static_sysctl_sysctl_kernel_core_pattern:obj:1 - oval:ssg-object_static_etc_sysctld_sysctl_kernel_core_pattern:obj:1 - - - - - oval:ssg-object_static_usr_local_lib_sysctld_sysctl_kernel_core_pattern:obj:1 - oval:ssg-object_static_run_sysctld_sysctl_kernel_core_pattern:obj:1 - - - - /etc/sysctl.conf - ^[\s]*kernel.core_pattern[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /etc/sysctl.d - ^.*\.conf$ - ^[\s]*kernel.core_pattern[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /run/sysctl.d - ^.*\.conf$ - ^[\s]*kernel.core_pattern[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/local/lib/sysctl.d - ^.*\.conf$ - ^[\s]*kernel.core_pattern[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/lib/sysctl.d - ^.*\.conf$ - ^[\s]*kernel.core_pattern[\s]*=[\s]*(.*)[\s]*$ - 1 - - - kernel.core_uses_pid - - - - oval:ssg-object_static_etc_sysctls_sysctl_kernel_core_uses_pid:obj:1 - oval:ssg-object_static_run_usr_local_sysctls_sysctl_kernel_core_uses_pid:obj:1 - - - - - oval:ssg-object_static_sysctl_sysctl_kernel_core_uses_pid:obj:1 - oval:ssg-object_static_etc_sysctld_sysctl_kernel_core_uses_pid:obj:1 - - - - - oval:ssg-object_static_usr_local_lib_sysctld_sysctl_kernel_core_uses_pid:obj:1 - oval:ssg-object_static_run_sysctld_sysctl_kernel_core_uses_pid:obj:1 - - - - /etc/sysctl.conf - ^[\s]*kernel.core_uses_pid[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /etc/sysctl.d - ^.*\.conf$ - ^[\s]*kernel.core_uses_pid[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /run/sysctl.d - ^.*\.conf$ - ^[\s]*kernel.core_uses_pid[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/local/lib/sysctl.d - ^.*\.conf$ - ^[\s]*kernel.core_uses_pid[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/lib/sysctl.d - ^.*\.conf$ - ^[\s]*kernel.core_uses_pid[\s]*=[\s]*(.*)[\s]*$ - 1 - - - kernel.dmesg_restrict - - - - oval:ssg-object_static_etc_sysctls_sysctl_kernel_dmesg_restrict:obj:1 - oval:ssg-object_static_run_usr_local_sysctls_sysctl_kernel_dmesg_restrict:obj:1 - - - - - oval:ssg-object_static_sysctl_sysctl_kernel_dmesg_restrict:obj:1 - oval:ssg-object_static_etc_sysctld_sysctl_kernel_dmesg_restrict:obj:1 - - - - - oval:ssg-object_static_usr_local_lib_sysctld_sysctl_kernel_dmesg_restrict:obj:1 - oval:ssg-object_static_run_sysctld_sysctl_kernel_dmesg_restrict:obj:1 - - - - /etc/sysctl.conf - ^[\s]*kernel.dmesg_restrict[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /etc/sysctl.d - ^.*\.conf$ - ^[\s]*kernel.dmesg_restrict[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /run/sysctl.d - ^.*\.conf$ - ^[\s]*kernel.dmesg_restrict[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/local/lib/sysctl.d - ^.*\.conf$ - ^[\s]*kernel.dmesg_restrict[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/lib/sysctl.d - ^.*\.conf$ - ^[\s]*kernel.dmesg_restrict[\s]*=[\s]*(.*)[\s]*$ - 1 - - - kernel.kexec_load_disabled - - - - oval:ssg-object_static_etc_sysctls_sysctl_kernel_kexec_load_disabled:obj:1 - oval:ssg-object_static_run_usr_local_sysctls_sysctl_kernel_kexec_load_disabled:obj:1 - - - - - oval:ssg-object_static_sysctl_sysctl_kernel_kexec_load_disabled:obj:1 - oval:ssg-object_static_etc_sysctld_sysctl_kernel_kexec_load_disabled:obj:1 - - - - - oval:ssg-object_static_usr_local_lib_sysctld_sysctl_kernel_kexec_load_disabled:obj:1 - oval:ssg-object_static_run_sysctld_sysctl_kernel_kexec_load_disabled:obj:1 - - - - /etc/sysctl.conf - ^[\s]*kernel.kexec_load_disabled[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /etc/sysctl.d - ^.*\.conf$ - ^[\s]*kernel.kexec_load_disabled[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /run/sysctl.d - ^.*\.conf$ - ^[\s]*kernel.kexec_load_disabled[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/local/lib/sysctl.d - ^.*\.conf$ - ^[\s]*kernel.kexec_load_disabled[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/lib/sysctl.d - ^.*\.conf$ - ^[\s]*kernel.kexec_load_disabled[\s]*=[\s]*(.*)[\s]*$ - 1 - - - kernel.kptr_restrict - - - - oval:ssg-object_static_etc_sysctls_sysctl_kernel_kptr_restrict:obj:1 - oval:ssg-object_static_run_usr_local_sysctls_sysctl_kernel_kptr_restrict:obj:1 - - - - - oval:ssg-object_static_sysctl_sysctl_kernel_kptr_restrict:obj:1 - oval:ssg-object_static_etc_sysctld_sysctl_kernel_kptr_restrict:obj:1 - - - - - oval:ssg-object_static_usr_local_lib_sysctld_sysctl_kernel_kptr_restrict:obj:1 - oval:ssg-object_static_run_sysctld_sysctl_kernel_kptr_restrict:obj:1 - - - - /etc/sysctl.conf - ^[\s]*kernel.kptr_restrict[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /etc/sysctl.d - ^.*\.conf$ - ^[\s]*kernel.kptr_restrict[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /run/sysctl.d - ^.*\.conf$ - ^[\s]*kernel.kptr_restrict[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/local/lib/sysctl.d - ^.*\.conf$ - ^[\s]*kernel.kptr_restrict[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/lib/sysctl.d - ^.*\.conf$ - ^[\s]*kernel.kptr_restrict[\s]*=[\s]*(.*)[\s]*$ - 1 - - - kernel.modules_disabled - - - - oval:ssg-object_static_etc_sysctls_sysctl_kernel_modules_disabled:obj:1 - oval:ssg-object_static_run_usr_local_sysctls_sysctl_kernel_modules_disabled:obj:1 - - - - - oval:ssg-object_static_sysctl_sysctl_kernel_modules_disabled:obj:1 - oval:ssg-object_static_etc_sysctld_sysctl_kernel_modules_disabled:obj:1 - - - - - oval:ssg-object_static_usr_local_lib_sysctld_sysctl_kernel_modules_disabled:obj:1 - oval:ssg-object_static_run_sysctld_sysctl_kernel_modules_disabled:obj:1 - - - - /etc/sysctl.conf - ^[\s]*kernel.modules_disabled[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /etc/sysctl.d - ^.*\.conf$ - ^[\s]*kernel.modules_disabled[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /run/sysctl.d - ^.*\.conf$ - ^[\s]*kernel.modules_disabled[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/local/lib/sysctl.d - ^.*\.conf$ - ^[\s]*kernel.modules_disabled[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/lib/sysctl.d - ^.*\.conf$ - ^[\s]*kernel.modules_disabled[\s]*=[\s]*(.*)[\s]*$ - 1 - - - kernel.panic_on_oops - - - - oval:ssg-object_static_etc_sysctls_sysctl_kernel_panic_on_oops:obj:1 - oval:ssg-object_static_run_usr_local_sysctls_sysctl_kernel_panic_on_oops:obj:1 - - - - - oval:ssg-object_static_sysctl_sysctl_kernel_panic_on_oops:obj:1 - oval:ssg-object_static_etc_sysctld_sysctl_kernel_panic_on_oops:obj:1 - - - - - oval:ssg-object_static_usr_local_lib_sysctld_sysctl_kernel_panic_on_oops:obj:1 - oval:ssg-object_static_run_sysctld_sysctl_kernel_panic_on_oops:obj:1 - - - - /etc/sysctl.conf - ^[\s]*kernel.panic_on_oops[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /etc/sysctl.d - ^.*\.conf$ - ^[\s]*kernel.panic_on_oops[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /run/sysctl.d - ^.*\.conf$ - ^[\s]*kernel.panic_on_oops[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/local/lib/sysctl.d - ^.*\.conf$ - ^[\s]*kernel.panic_on_oops[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/lib/sysctl.d - ^.*\.conf$ - ^[\s]*kernel.panic_on_oops[\s]*=[\s]*(.*)[\s]*$ - 1 - - - kernel.perf_cpu_time_max_percent - - - - oval:ssg-object_static_etc_sysctls_sysctl_kernel_perf_cpu_time_max_percent:obj:1 - oval:ssg-object_static_run_usr_local_sysctls_sysctl_kernel_perf_cpu_time_max_percent:obj:1 - - - - - oval:ssg-object_static_sysctl_sysctl_kernel_perf_cpu_time_max_percent:obj:1 - oval:ssg-object_static_etc_sysctld_sysctl_kernel_perf_cpu_time_max_percent:obj:1 - - - - - oval:ssg-object_static_usr_local_lib_sysctld_sysctl_kernel_perf_cpu_time_max_percent:obj:1 - oval:ssg-object_static_run_sysctld_sysctl_kernel_perf_cpu_time_max_percent:obj:1 - - - - /etc/sysctl.conf - ^[\s]*kernel.perf_cpu_time_max_percent[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /etc/sysctl.d - ^.*\.conf$ - ^[\s]*kernel.perf_cpu_time_max_percent[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /run/sysctl.d - ^.*\.conf$ - ^[\s]*kernel.perf_cpu_time_max_percent[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/local/lib/sysctl.d - ^.*\.conf$ - ^[\s]*kernel.perf_cpu_time_max_percent[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/lib/sysctl.d - ^.*\.conf$ - ^[\s]*kernel.perf_cpu_time_max_percent[\s]*=[\s]*(.*)[\s]*$ - 1 - - - kernel.perf_event_max_sample_rate - - - - oval:ssg-object_static_etc_sysctls_sysctl_kernel_perf_event_max_sample_rate:obj:1 - oval:ssg-object_static_run_usr_local_sysctls_sysctl_kernel_perf_event_max_sample_rate:obj:1 - - - - - oval:ssg-object_static_sysctl_sysctl_kernel_perf_event_max_sample_rate:obj:1 - oval:ssg-object_static_etc_sysctld_sysctl_kernel_perf_event_max_sample_rate:obj:1 - - - - - oval:ssg-object_static_usr_local_lib_sysctld_sysctl_kernel_perf_event_max_sample_rate:obj:1 - oval:ssg-object_static_run_sysctld_sysctl_kernel_perf_event_max_sample_rate:obj:1 - - - - /etc/sysctl.conf - ^[\s]*kernel.perf_event_max_sample_rate[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /etc/sysctl.d - ^.*\.conf$ - ^[\s]*kernel.perf_event_max_sample_rate[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /run/sysctl.d - ^.*\.conf$ - ^[\s]*kernel.perf_event_max_sample_rate[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/local/lib/sysctl.d - ^.*\.conf$ - ^[\s]*kernel.perf_event_max_sample_rate[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/lib/sysctl.d - ^.*\.conf$ - ^[\s]*kernel.perf_event_max_sample_rate[\s]*=[\s]*(.*)[\s]*$ - 1 - - - kernel.perf_event_paranoid - - - - oval:ssg-object_static_etc_sysctls_sysctl_kernel_perf_event_paranoid:obj:1 - oval:ssg-object_static_run_usr_local_sysctls_sysctl_kernel_perf_event_paranoid:obj:1 - - - - - oval:ssg-object_static_sysctl_sysctl_kernel_perf_event_paranoid:obj:1 - oval:ssg-object_static_etc_sysctld_sysctl_kernel_perf_event_paranoid:obj:1 - - - - - oval:ssg-object_static_usr_local_lib_sysctld_sysctl_kernel_perf_event_paranoid:obj:1 - oval:ssg-object_static_run_sysctld_sysctl_kernel_perf_event_paranoid:obj:1 - - - - /etc/sysctl.conf - ^[\s]*kernel.perf_event_paranoid[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /etc/sysctl.d - ^.*\.conf$ - ^[\s]*kernel.perf_event_paranoid[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /run/sysctl.d - ^.*\.conf$ - ^[\s]*kernel.perf_event_paranoid[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/local/lib/sysctl.d - ^.*\.conf$ - ^[\s]*kernel.perf_event_paranoid[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/lib/sysctl.d - ^.*\.conf$ - ^[\s]*kernel.perf_event_paranoid[\s]*=[\s]*(.*)[\s]*$ - 1 - - - kernel.pid_max - - - - oval:ssg-object_static_etc_sysctls_sysctl_kernel_pid_max:obj:1 - oval:ssg-object_static_run_usr_local_sysctls_sysctl_kernel_pid_max:obj:1 - - - - - oval:ssg-object_static_sysctl_sysctl_kernel_pid_max:obj:1 - oval:ssg-object_static_etc_sysctld_sysctl_kernel_pid_max:obj:1 - - - - - oval:ssg-object_static_usr_local_lib_sysctld_sysctl_kernel_pid_max:obj:1 - oval:ssg-object_static_run_sysctld_sysctl_kernel_pid_max:obj:1 - - - - /etc/sysctl.conf - ^[\s]*kernel.pid_max[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /etc/sysctl.d - ^.*\.conf$ - ^[\s]*kernel.pid_max[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /run/sysctl.d - ^.*\.conf$ - ^[\s]*kernel.pid_max[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/local/lib/sysctl.d - ^.*\.conf$ - ^[\s]*kernel.pid_max[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/lib/sysctl.d - ^.*\.conf$ - ^[\s]*kernel.pid_max[\s]*=[\s]*(.*)[\s]*$ - 1 - - - kernel.randomize_va_space - - - - oval:ssg-object_static_etc_sysctls_sysctl_kernel_randomize_va_space:obj:1 - oval:ssg-object_static_run_usr_local_sysctls_sysctl_kernel_randomize_va_space:obj:1 - - - - - oval:ssg-object_static_sysctl_sysctl_kernel_randomize_va_space:obj:1 - oval:ssg-object_static_etc_sysctld_sysctl_kernel_randomize_va_space:obj:1 - - - - - oval:ssg-object_static_usr_local_lib_sysctld_sysctl_kernel_randomize_va_space:obj:1 - oval:ssg-object_static_run_sysctld_sysctl_kernel_randomize_va_space:obj:1 - - - - /etc/sysctl.conf - ^[\s]*kernel.randomize_va_space[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /etc/sysctl.d - ^.*\.conf$ - ^[\s]*kernel.randomize_va_space[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /run/sysctl.d - ^.*\.conf$ - ^[\s]*kernel.randomize_va_space[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/local/lib/sysctl.d - ^.*\.conf$ - ^[\s]*kernel.randomize_va_space[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/lib/sysctl.d - ^.*\.conf$ - ^[\s]*kernel.randomize_va_space[\s]*=[\s]*(.*)[\s]*$ - 1 - - - kernel.sysrq - - - - oval:ssg-object_static_etc_sysctls_sysctl_kernel_sysrq:obj:1 - oval:ssg-object_static_run_usr_local_sysctls_sysctl_kernel_sysrq:obj:1 - - - - - oval:ssg-object_static_sysctl_sysctl_kernel_sysrq:obj:1 - oval:ssg-object_static_etc_sysctld_sysctl_kernel_sysrq:obj:1 - - - - - oval:ssg-object_static_usr_local_lib_sysctld_sysctl_kernel_sysrq:obj:1 - oval:ssg-object_static_run_sysctld_sysctl_kernel_sysrq:obj:1 - - - - /etc/sysctl.conf - ^[\s]*kernel.sysrq[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /etc/sysctl.d - ^.*\.conf$ - ^[\s]*kernel.sysrq[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /run/sysctl.d - ^.*\.conf$ - ^[\s]*kernel.sysrq[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/local/lib/sysctl.d - ^.*\.conf$ - ^[\s]*kernel.sysrq[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/lib/sysctl.d - ^.*\.conf$ - ^[\s]*kernel.sysrq[\s]*=[\s]*(.*)[\s]*$ - 1 - - - kernel.unprivileged_bpf_disabled - - - - oval:ssg-object_static_etc_sysctls_sysctl_kernel_unprivileged_bpf_disabled:obj:1 - oval:ssg-object_static_run_usr_local_sysctls_sysctl_kernel_unprivileged_bpf_disabled:obj:1 - - - - - oval:ssg-object_static_sysctl_sysctl_kernel_unprivileged_bpf_disabled:obj:1 - oval:ssg-object_static_etc_sysctld_sysctl_kernel_unprivileged_bpf_disabled:obj:1 - - - - - oval:ssg-object_static_usr_local_lib_sysctld_sysctl_kernel_unprivileged_bpf_disabled:obj:1 - oval:ssg-object_static_run_sysctld_sysctl_kernel_unprivileged_bpf_disabled:obj:1 - - - - /etc/sysctl.conf - ^[\s]*kernel.unprivileged_bpf_disabled[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /etc/sysctl.d - ^.*\.conf$ - ^[\s]*kernel.unprivileged_bpf_disabled[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /run/sysctl.d - ^.*\.conf$ - ^[\s]*kernel.unprivileged_bpf_disabled[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/local/lib/sysctl.d - ^.*\.conf$ - ^[\s]*kernel.unprivileged_bpf_disabled[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/lib/sysctl.d - ^.*\.conf$ - ^[\s]*kernel.unprivileged_bpf_disabled[\s]*=[\s]*(.*)[\s]*$ - 1 - - - kernel.yama.ptrace_scope - - - - oval:ssg-object_static_etc_sysctls_sysctl_kernel_yama_ptrace_scope:obj:1 - oval:ssg-object_static_run_usr_local_sysctls_sysctl_kernel_yama_ptrace_scope:obj:1 - - - - - oval:ssg-object_static_sysctl_sysctl_kernel_yama_ptrace_scope:obj:1 - oval:ssg-object_static_etc_sysctld_sysctl_kernel_yama_ptrace_scope:obj:1 - - - - - oval:ssg-object_static_usr_local_lib_sysctld_sysctl_kernel_yama_ptrace_scope:obj:1 - oval:ssg-object_static_run_sysctld_sysctl_kernel_yama_ptrace_scope:obj:1 - - - - /etc/sysctl.conf - ^[\s]*kernel.yama.ptrace_scope[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /etc/sysctl.d - ^.*\.conf$ - ^[\s]*kernel.yama.ptrace_scope[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /run/sysctl.d - ^.*\.conf$ - ^[\s]*kernel.yama.ptrace_scope[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/local/lib/sysctl.d - ^.*\.conf$ - ^[\s]*kernel.yama.ptrace_scope[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/lib/sysctl.d - ^.*\.conf$ - ^[\s]*kernel.yama.ptrace_scope[\s]*=[\s]*(.*)[\s]*$ - 1 - - - net.core.bpf_jit_harden - - - - oval:ssg-object_static_etc_sysctls_sysctl_net_core_bpf_jit_harden:obj:1 - oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_core_bpf_jit_harden:obj:1 - - - - - oval:ssg-object_static_sysctl_sysctl_net_core_bpf_jit_harden:obj:1 - oval:ssg-object_static_etc_sysctld_sysctl_net_core_bpf_jit_harden:obj:1 - - - - - oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_core_bpf_jit_harden:obj:1 - oval:ssg-object_static_run_sysctld_sysctl_net_core_bpf_jit_harden:obj:1 - - - - /etc/sysctl.conf - ^[\s]*net.core.bpf_jit_harden[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /etc/sysctl.d - ^.*\.conf$ - ^[\s]*net.core.bpf_jit_harden[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /run/sysctl.d - ^.*\.conf$ - ^[\s]*net.core.bpf_jit_harden[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/local/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.core.bpf_jit_harden[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.core.bpf_jit_harden[\s]*=[\s]*(.*)[\s]*$ - 1 - - - net.ipv4.conf.all.accept_local - - - - oval:ssg-object_static_etc_sysctls_sysctl_net_ipv4_conf_all_accept_local:obj:1 - oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv4_conf_all_accept_local:obj:1 - - - - - oval:ssg-object_static_sysctl_sysctl_net_ipv4_conf_all_accept_local:obj:1 - oval:ssg-object_static_etc_sysctld_sysctl_net_ipv4_conf_all_accept_local:obj:1 - - - - - oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv4_conf_all_accept_local:obj:1 - oval:ssg-object_static_run_sysctld_sysctl_net_ipv4_conf_all_accept_local:obj:1 - - - - /etc/sysctl.conf - ^[\s]*net.ipv4.conf.all.accept_local[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /etc/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.conf.all.accept_local[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /run/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.conf.all.accept_local[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/local/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.conf.all.accept_local[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.conf.all.accept_local[\s]*=[\s]*(.*)[\s]*$ - 1 - - - net.ipv4.conf.all.accept_redirects - - - - oval:ssg-object_static_etc_sysctls_sysctl_net_ipv4_conf_all_accept_redirects:obj:1 - oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv4_conf_all_accept_redirects:obj:1 - - - - - oval:ssg-object_static_sysctl_sysctl_net_ipv4_conf_all_accept_redirects:obj:1 - oval:ssg-object_static_etc_sysctld_sysctl_net_ipv4_conf_all_accept_redirects:obj:1 - - - - - oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv4_conf_all_accept_redirects:obj:1 - oval:ssg-object_static_run_sysctld_sysctl_net_ipv4_conf_all_accept_redirects:obj:1 - - - - /etc/sysctl.conf - ^[\s]*net.ipv4.conf.all.accept_redirects[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /etc/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.conf.all.accept_redirects[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /run/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.conf.all.accept_redirects[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/local/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.conf.all.accept_redirects[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.conf.all.accept_redirects[\s]*=[\s]*(.*)[\s]*$ - 1 - - - net.ipv4.conf.all.accept_source_route - - - - oval:ssg-object_static_etc_sysctls_sysctl_net_ipv4_conf_all_accept_source_route:obj:1 - oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv4_conf_all_accept_source_route:obj:1 - - - - - oval:ssg-object_static_sysctl_sysctl_net_ipv4_conf_all_accept_source_route:obj:1 - oval:ssg-object_static_etc_sysctld_sysctl_net_ipv4_conf_all_accept_source_route:obj:1 - - - - - oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv4_conf_all_accept_source_route:obj:1 - oval:ssg-object_static_run_sysctld_sysctl_net_ipv4_conf_all_accept_source_route:obj:1 - - - - /etc/sysctl.conf - ^[\s]*net.ipv4.conf.all.accept_source_route[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /etc/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.conf.all.accept_source_route[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /run/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.conf.all.accept_source_route[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/local/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.conf.all.accept_source_route[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.conf.all.accept_source_route[\s]*=[\s]*(.*)[\s]*$ - 1 - - - net.ipv4.conf.all.arp_filter - - - - oval:ssg-object_static_etc_sysctls_sysctl_net_ipv4_conf_all_arp_filter:obj:1 - oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv4_conf_all_arp_filter:obj:1 - - - - - oval:ssg-object_static_sysctl_sysctl_net_ipv4_conf_all_arp_filter:obj:1 - oval:ssg-object_static_etc_sysctld_sysctl_net_ipv4_conf_all_arp_filter:obj:1 - - - - - oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv4_conf_all_arp_filter:obj:1 - oval:ssg-object_static_run_sysctld_sysctl_net_ipv4_conf_all_arp_filter:obj:1 - - - - /etc/sysctl.conf - ^[\s]*net.ipv4.conf.all.arp_filter[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /etc/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.conf.all.arp_filter[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /run/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.conf.all.arp_filter[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/local/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.conf.all.arp_filter[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.conf.all.arp_filter[\s]*=[\s]*(.*)[\s]*$ - 1 - - - net.ipv4.conf.all.arp_ignore - - - - oval:ssg-object_static_etc_sysctls_sysctl_net_ipv4_conf_all_arp_ignore:obj:1 - oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv4_conf_all_arp_ignore:obj:1 - - - - - oval:ssg-object_static_sysctl_sysctl_net_ipv4_conf_all_arp_ignore:obj:1 - oval:ssg-object_static_etc_sysctld_sysctl_net_ipv4_conf_all_arp_ignore:obj:1 - - - - - oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv4_conf_all_arp_ignore:obj:1 - oval:ssg-object_static_run_sysctld_sysctl_net_ipv4_conf_all_arp_ignore:obj:1 - - - - /etc/sysctl.conf - ^[\s]*net.ipv4.conf.all.arp_ignore[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /etc/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.conf.all.arp_ignore[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /run/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.conf.all.arp_ignore[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/local/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.conf.all.arp_ignore[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.conf.all.arp_ignore[\s]*=[\s]*(.*)[\s]*$ - 1 - - - net.ipv4.conf.all.drop_gratuitous_arp - - - - oval:ssg-object_static_etc_sysctls_sysctl_net_ipv4_conf_all_drop_gratuitous_arp:obj:1 - oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv4_conf_all_drop_gratuitous_arp:obj:1 - - - - - oval:ssg-object_static_sysctl_sysctl_net_ipv4_conf_all_drop_gratuitous_arp:obj:1 - oval:ssg-object_static_etc_sysctld_sysctl_net_ipv4_conf_all_drop_gratuitous_arp:obj:1 - - - - - oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv4_conf_all_drop_gratuitous_arp:obj:1 - oval:ssg-object_static_run_sysctld_sysctl_net_ipv4_conf_all_drop_gratuitous_arp:obj:1 - - - - /etc/sysctl.conf - ^[\s]*net.ipv4.conf.all.drop_gratuitous_arp[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /etc/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.conf.all.drop_gratuitous_arp[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /run/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.conf.all.drop_gratuitous_arp[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/local/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.conf.all.drop_gratuitous_arp[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.conf.all.drop_gratuitous_arp[\s]*=[\s]*(.*)[\s]*$ - 1 - - - net.ipv4.conf.all.log_martians - - - - oval:ssg-object_static_etc_sysctls_sysctl_net_ipv4_conf_all_log_martians:obj:1 - oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv4_conf_all_log_martians:obj:1 - - - - - oval:ssg-object_static_sysctl_sysctl_net_ipv4_conf_all_log_martians:obj:1 - oval:ssg-object_static_etc_sysctld_sysctl_net_ipv4_conf_all_log_martians:obj:1 - - - - - oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv4_conf_all_log_martians:obj:1 - oval:ssg-object_static_run_sysctld_sysctl_net_ipv4_conf_all_log_martians:obj:1 - - - - /etc/sysctl.conf - ^[\s]*net.ipv4.conf.all.log_martians[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /etc/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.conf.all.log_martians[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /run/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.conf.all.log_martians[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/local/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.conf.all.log_martians[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.conf.all.log_martians[\s]*=[\s]*(.*)[\s]*$ - 1 - - - net.ipv4.conf.all.route_localnet - - - - oval:ssg-object_static_etc_sysctls_sysctl_net_ipv4_conf_all_route_localnet:obj:1 - oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv4_conf_all_route_localnet:obj:1 - - - - - oval:ssg-object_static_sysctl_sysctl_net_ipv4_conf_all_route_localnet:obj:1 - oval:ssg-object_static_etc_sysctld_sysctl_net_ipv4_conf_all_route_localnet:obj:1 - - - - - oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv4_conf_all_route_localnet:obj:1 - oval:ssg-object_static_run_sysctld_sysctl_net_ipv4_conf_all_route_localnet:obj:1 - - - - /etc/sysctl.conf - ^[\s]*net.ipv4.conf.all.route_localnet[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /etc/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.conf.all.route_localnet[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /run/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.conf.all.route_localnet[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/local/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.conf.all.route_localnet[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.conf.all.route_localnet[\s]*=[\s]*(.*)[\s]*$ - 1 - - - net.ipv4.conf.all.rp_filter - - - - oval:ssg-object_static_etc_sysctls_sysctl_net_ipv4_conf_all_rp_filter:obj:1 - oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv4_conf_all_rp_filter:obj:1 - - - - - oval:ssg-object_static_sysctl_sysctl_net_ipv4_conf_all_rp_filter:obj:1 - oval:ssg-object_static_etc_sysctld_sysctl_net_ipv4_conf_all_rp_filter:obj:1 - - - - - oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv4_conf_all_rp_filter:obj:1 - oval:ssg-object_static_run_sysctld_sysctl_net_ipv4_conf_all_rp_filter:obj:1 - - - - /etc/sysctl.conf - ^[\s]*net.ipv4.conf.all.rp_filter[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /etc/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.conf.all.rp_filter[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /run/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.conf.all.rp_filter[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/local/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.conf.all.rp_filter[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.conf.all.rp_filter[\s]*=[\s]*(.*)[\s]*$ - 1 - - - net.ipv4.conf.all.secure_redirects - - - - oval:ssg-object_static_etc_sysctls_sysctl_net_ipv4_conf_all_secure_redirects:obj:1 - oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv4_conf_all_secure_redirects:obj:1 - - - - - oval:ssg-object_static_sysctl_sysctl_net_ipv4_conf_all_secure_redirects:obj:1 - oval:ssg-object_static_etc_sysctld_sysctl_net_ipv4_conf_all_secure_redirects:obj:1 - - - - - oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv4_conf_all_secure_redirects:obj:1 - oval:ssg-object_static_run_sysctld_sysctl_net_ipv4_conf_all_secure_redirects:obj:1 - - - - /etc/sysctl.conf - ^[\s]*net.ipv4.conf.all.secure_redirects[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /etc/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.conf.all.secure_redirects[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /run/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.conf.all.secure_redirects[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/local/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.conf.all.secure_redirects[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.conf.all.secure_redirects[\s]*=[\s]*(.*)[\s]*$ - 1 - - - net.ipv4.conf.all.send_redirects - - - - oval:ssg-object_static_etc_sysctls_sysctl_net_ipv4_conf_all_send_redirects:obj:1 - oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv4_conf_all_send_redirects:obj:1 - - - - - oval:ssg-object_static_sysctl_sysctl_net_ipv4_conf_all_send_redirects:obj:1 - oval:ssg-object_static_etc_sysctld_sysctl_net_ipv4_conf_all_send_redirects:obj:1 - - - - - oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv4_conf_all_send_redirects:obj:1 - oval:ssg-object_static_run_sysctld_sysctl_net_ipv4_conf_all_send_redirects:obj:1 - - - - /etc/sysctl.conf - ^[\s]*net.ipv4.conf.all.send_redirects[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /etc/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.conf.all.send_redirects[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /run/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.conf.all.send_redirects[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/local/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.conf.all.send_redirects[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.conf.all.send_redirects[\s]*=[\s]*(.*)[\s]*$ - 1 - - - net.ipv4.conf.all.shared_media - - - - oval:ssg-object_static_etc_sysctls_sysctl_net_ipv4_conf_all_shared_media:obj:1 - oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv4_conf_all_shared_media:obj:1 - - - - - oval:ssg-object_static_sysctl_sysctl_net_ipv4_conf_all_shared_media:obj:1 - oval:ssg-object_static_etc_sysctld_sysctl_net_ipv4_conf_all_shared_media:obj:1 - - - - - oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv4_conf_all_shared_media:obj:1 - oval:ssg-object_static_run_sysctld_sysctl_net_ipv4_conf_all_shared_media:obj:1 - - - - /etc/sysctl.conf - ^[\s]*net.ipv4.conf.all.shared_media[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /etc/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.conf.all.shared_media[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /run/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.conf.all.shared_media[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/local/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.conf.all.shared_media[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.conf.all.shared_media[\s]*=[\s]*(.*)[\s]*$ - 1 - - - net.ipv4.conf.default.accept_redirects - - - - oval:ssg-object_static_etc_sysctls_sysctl_net_ipv4_conf_default_accept_redirects:obj:1 - oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv4_conf_default_accept_redirects:obj:1 - - - - - oval:ssg-object_static_sysctl_sysctl_net_ipv4_conf_default_accept_redirects:obj:1 - oval:ssg-object_static_etc_sysctld_sysctl_net_ipv4_conf_default_accept_redirects:obj:1 - - - - - oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv4_conf_default_accept_redirects:obj:1 - oval:ssg-object_static_run_sysctld_sysctl_net_ipv4_conf_default_accept_redirects:obj:1 - - - - /etc/sysctl.conf - ^[\s]*net.ipv4.conf.default.accept_redirects[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /etc/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.conf.default.accept_redirects[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /run/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.conf.default.accept_redirects[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/local/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.conf.default.accept_redirects[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.conf.default.accept_redirects[\s]*=[\s]*(.*)[\s]*$ - 1 - - - net.ipv4.conf.default.accept_source_route - - - - oval:ssg-object_static_etc_sysctls_sysctl_net_ipv4_conf_default_accept_source_route:obj:1 - oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv4_conf_default_accept_source_route:obj:1 - - - - - oval:ssg-object_static_sysctl_sysctl_net_ipv4_conf_default_accept_source_route:obj:1 - oval:ssg-object_static_etc_sysctld_sysctl_net_ipv4_conf_default_accept_source_route:obj:1 - - - - - oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv4_conf_default_accept_source_route:obj:1 - oval:ssg-object_static_run_sysctld_sysctl_net_ipv4_conf_default_accept_source_route:obj:1 - - - - /etc/sysctl.conf - ^[\s]*net.ipv4.conf.default.accept_source_route[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /etc/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.conf.default.accept_source_route[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /run/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.conf.default.accept_source_route[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/local/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.conf.default.accept_source_route[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.conf.default.accept_source_route[\s]*=[\s]*(.*)[\s]*$ - 1 - - - net.ipv4.conf.default.log_martians - - - - oval:ssg-object_static_etc_sysctls_sysctl_net_ipv4_conf_default_log_martians:obj:1 - oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv4_conf_default_log_martians:obj:1 - - - - - oval:ssg-object_static_sysctl_sysctl_net_ipv4_conf_default_log_martians:obj:1 - oval:ssg-object_static_etc_sysctld_sysctl_net_ipv4_conf_default_log_martians:obj:1 - - - - - oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv4_conf_default_log_martians:obj:1 - oval:ssg-object_static_run_sysctld_sysctl_net_ipv4_conf_default_log_martians:obj:1 - - - - /etc/sysctl.conf - ^[\s]*net.ipv4.conf.default.log_martians[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /etc/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.conf.default.log_martians[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /run/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.conf.default.log_martians[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/local/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.conf.default.log_martians[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.conf.default.log_martians[\s]*=[\s]*(.*)[\s]*$ - 1 - - - net.ipv4.conf.default.rp_filter - - - - oval:ssg-object_static_etc_sysctls_sysctl_net_ipv4_conf_default_rp_filter:obj:1 - oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv4_conf_default_rp_filter:obj:1 - - - - - oval:ssg-object_static_sysctl_sysctl_net_ipv4_conf_default_rp_filter:obj:1 - oval:ssg-object_static_etc_sysctld_sysctl_net_ipv4_conf_default_rp_filter:obj:1 - - - - - oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv4_conf_default_rp_filter:obj:1 - oval:ssg-object_static_run_sysctld_sysctl_net_ipv4_conf_default_rp_filter:obj:1 - - - - /etc/sysctl.conf - ^[\s]*net.ipv4.conf.default.rp_filter[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /etc/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.conf.default.rp_filter[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /run/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.conf.default.rp_filter[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/local/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.conf.default.rp_filter[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.conf.default.rp_filter[\s]*=[\s]*(.*)[\s]*$ - 1 - - - net.ipv4.conf.default.secure_redirects - - - - oval:ssg-object_static_etc_sysctls_sysctl_net_ipv4_conf_default_secure_redirects:obj:1 - oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv4_conf_default_secure_redirects:obj:1 - - - - - oval:ssg-object_static_sysctl_sysctl_net_ipv4_conf_default_secure_redirects:obj:1 - oval:ssg-object_static_etc_sysctld_sysctl_net_ipv4_conf_default_secure_redirects:obj:1 - - - - - oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv4_conf_default_secure_redirects:obj:1 - oval:ssg-object_static_run_sysctld_sysctl_net_ipv4_conf_default_secure_redirects:obj:1 - - - - /etc/sysctl.conf - ^[\s]*net.ipv4.conf.default.secure_redirects[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /etc/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.conf.default.secure_redirects[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /run/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.conf.default.secure_redirects[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/local/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.conf.default.secure_redirects[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.conf.default.secure_redirects[\s]*=[\s]*(.*)[\s]*$ - 1 - - - net.ipv4.conf.default.send_redirects - - - - oval:ssg-object_static_etc_sysctls_sysctl_net_ipv4_conf_default_send_redirects:obj:1 - oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv4_conf_default_send_redirects:obj:1 - - - - - oval:ssg-object_static_sysctl_sysctl_net_ipv4_conf_default_send_redirects:obj:1 - oval:ssg-object_static_etc_sysctld_sysctl_net_ipv4_conf_default_send_redirects:obj:1 - - - - - oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv4_conf_default_send_redirects:obj:1 - oval:ssg-object_static_run_sysctld_sysctl_net_ipv4_conf_default_send_redirects:obj:1 - - - - /etc/sysctl.conf - ^[\s]*net.ipv4.conf.default.send_redirects[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /etc/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.conf.default.send_redirects[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /run/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.conf.default.send_redirects[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/local/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.conf.default.send_redirects[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.conf.default.send_redirects[\s]*=[\s]*(.*)[\s]*$ - 1 - - - net.ipv4.conf.default.shared_media - - - - oval:ssg-object_static_etc_sysctls_sysctl_net_ipv4_conf_default_shared_media:obj:1 - oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv4_conf_default_shared_media:obj:1 - - - - - oval:ssg-object_static_sysctl_sysctl_net_ipv4_conf_default_shared_media:obj:1 - oval:ssg-object_static_etc_sysctld_sysctl_net_ipv4_conf_default_shared_media:obj:1 - - - - - oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv4_conf_default_shared_media:obj:1 - oval:ssg-object_static_run_sysctld_sysctl_net_ipv4_conf_default_shared_media:obj:1 - - - - /etc/sysctl.conf - ^[\s]*net.ipv4.conf.default.shared_media[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /etc/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.conf.default.shared_media[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /run/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.conf.default.shared_media[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/local/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.conf.default.shared_media[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.conf.default.shared_media[\s]*=[\s]*(.*)[\s]*$ - 1 - - - net.ipv4.icmp_echo_ignore_broadcasts - - - - oval:ssg-object_static_etc_sysctls_sysctl_net_ipv4_icmp_echo_ignore_broadcasts:obj:1 - oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv4_icmp_echo_ignore_broadcasts:obj:1 - - - - - oval:ssg-object_static_sysctl_sysctl_net_ipv4_icmp_echo_ignore_broadcasts:obj:1 - oval:ssg-object_static_etc_sysctld_sysctl_net_ipv4_icmp_echo_ignore_broadcasts:obj:1 - - - - - oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv4_icmp_echo_ignore_broadcasts:obj:1 - oval:ssg-object_static_run_sysctld_sysctl_net_ipv4_icmp_echo_ignore_broadcasts:obj:1 - - - - /etc/sysctl.conf - ^[\s]*net.ipv4.icmp_echo_ignore_broadcasts[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /etc/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.icmp_echo_ignore_broadcasts[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /run/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.icmp_echo_ignore_broadcasts[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/local/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.icmp_echo_ignore_broadcasts[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.icmp_echo_ignore_broadcasts[\s]*=[\s]*(.*)[\s]*$ - 1 - - - net.ipv4.icmp_ignore_bogus_error_responses - - - - oval:ssg-object_static_etc_sysctls_sysctl_net_ipv4_icmp_ignore_bogus_error_responses:obj:1 - oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv4_icmp_ignore_bogus_error_responses:obj:1 - - - - - oval:ssg-object_static_sysctl_sysctl_net_ipv4_icmp_ignore_bogus_error_responses:obj:1 - oval:ssg-object_static_etc_sysctld_sysctl_net_ipv4_icmp_ignore_bogus_error_responses:obj:1 - - - - - oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv4_icmp_ignore_bogus_error_responses:obj:1 - oval:ssg-object_static_run_sysctld_sysctl_net_ipv4_icmp_ignore_bogus_error_responses:obj:1 - - - - /etc/sysctl.conf - ^[\s]*net.ipv4.icmp_ignore_bogus_error_responses[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /etc/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.icmp_ignore_bogus_error_responses[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /run/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.icmp_ignore_bogus_error_responses[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/local/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.icmp_ignore_bogus_error_responses[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.icmp_ignore_bogus_error_responses[\s]*=[\s]*(.*)[\s]*$ - 1 - - - net.ipv4.ip_forward - - - - oval:ssg-object_static_etc_sysctls_sysctl_net_ipv4_ip_forward:obj:1 - oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv4_ip_forward:obj:1 - - - - - oval:ssg-object_static_sysctl_sysctl_net_ipv4_ip_forward:obj:1 - oval:ssg-object_static_etc_sysctld_sysctl_net_ipv4_ip_forward:obj:1 - - - - - oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv4_ip_forward:obj:1 - oval:ssg-object_static_run_sysctld_sysctl_net_ipv4_ip_forward:obj:1 - - - - /etc/sysctl.conf - ^[\s]*net.ipv4.ip_forward[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /etc/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.ip_forward[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /run/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.ip_forward[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/local/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.ip_forward[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.ip_forward[\s]*=[\s]*(.*)[\s]*$ - 1 - - - net.ipv4.ip_local_port_range - - - - oval:ssg-object_static_etc_sysctls_sysctl_net_ipv4_ip_local_port_range:obj:1 - oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv4_ip_local_port_range:obj:1 - - - - - oval:ssg-object_static_sysctl_sysctl_net_ipv4_ip_local_port_range:obj:1 - oval:ssg-object_static_etc_sysctld_sysctl_net_ipv4_ip_local_port_range:obj:1 - - - - - oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv4_ip_local_port_range:obj:1 - oval:ssg-object_static_run_sysctld_sysctl_net_ipv4_ip_local_port_range:obj:1 - - - - /etc/sysctl.conf - ^[\s]*net.ipv4.ip_local_port_range[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /etc/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.ip_local_port_range[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /run/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.ip_local_port_range[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/local/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.ip_local_port_range[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.ip_local_port_range[\s]*=[\s]*(.*)[\s]*$ - 1 - - - net.ipv4.tcp_invalid_ratelimit - - - - oval:ssg-object_static_etc_sysctls_sysctl_net_ipv4_tcp_invalid_ratelimit:obj:1 - oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv4_tcp_invalid_ratelimit:obj:1 - - - - - oval:ssg-object_static_sysctl_sysctl_net_ipv4_tcp_invalid_ratelimit:obj:1 - oval:ssg-object_static_etc_sysctld_sysctl_net_ipv4_tcp_invalid_ratelimit:obj:1 - - - - - oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv4_tcp_invalid_ratelimit:obj:1 - oval:ssg-object_static_run_sysctld_sysctl_net_ipv4_tcp_invalid_ratelimit:obj:1 - - - - /etc/sysctl.conf - ^[\s]*net.ipv4.tcp_invalid_ratelimit[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /etc/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.tcp_invalid_ratelimit[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /run/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.tcp_invalid_ratelimit[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/local/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.tcp_invalid_ratelimit[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.tcp_invalid_ratelimit[\s]*=[\s]*(.*)[\s]*$ - 1 - - - net.ipv4.tcp_rfc1337 - - - - oval:ssg-object_static_etc_sysctls_sysctl_net_ipv4_tcp_rfc1337:obj:1 - oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv4_tcp_rfc1337:obj:1 - - - - - oval:ssg-object_static_sysctl_sysctl_net_ipv4_tcp_rfc1337:obj:1 - oval:ssg-object_static_etc_sysctld_sysctl_net_ipv4_tcp_rfc1337:obj:1 - - - - - oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv4_tcp_rfc1337:obj:1 - oval:ssg-object_static_run_sysctld_sysctl_net_ipv4_tcp_rfc1337:obj:1 - - - - /etc/sysctl.conf - ^[\s]*net.ipv4.tcp_rfc1337[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /etc/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.tcp_rfc1337[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /run/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.tcp_rfc1337[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/local/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.tcp_rfc1337[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.tcp_rfc1337[\s]*=[\s]*(.*)[\s]*$ - 1 - - - net.ipv4.tcp_syncookies - - - - oval:ssg-object_static_etc_sysctls_sysctl_net_ipv4_tcp_syncookies:obj:1 - oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv4_tcp_syncookies:obj:1 - - - - - oval:ssg-object_static_sysctl_sysctl_net_ipv4_tcp_syncookies:obj:1 - oval:ssg-object_static_etc_sysctld_sysctl_net_ipv4_tcp_syncookies:obj:1 - - - - - oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv4_tcp_syncookies:obj:1 - oval:ssg-object_static_run_sysctld_sysctl_net_ipv4_tcp_syncookies:obj:1 - - - - /etc/sysctl.conf - ^[\s]*net.ipv4.tcp_syncookies[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /etc/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.tcp_syncookies[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /run/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.tcp_syncookies[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/local/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.tcp_syncookies[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv4.tcp_syncookies[\s]*=[\s]*(.*)[\s]*$ - 1 - - - net.ipv6.conf.all.accept_ra - - - - oval:ssg-object_static_etc_sysctls_sysctl_net_ipv6_conf_all_accept_ra:obj:1 - oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv6_conf_all_accept_ra:obj:1 - - - - - oval:ssg-object_static_sysctl_sysctl_net_ipv6_conf_all_accept_ra:obj:1 - oval:ssg-object_static_etc_sysctld_sysctl_net_ipv6_conf_all_accept_ra:obj:1 - - - - - oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv6_conf_all_accept_ra:obj:1 - oval:ssg-object_static_run_sysctld_sysctl_net_ipv6_conf_all_accept_ra:obj:1 - - - - /etc/sysctl.conf - ^[\s]*net.ipv6.conf.all.accept_ra[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /etc/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.all.accept_ra[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /run/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.all.accept_ra[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/local/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.all.accept_ra[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.all.accept_ra[\s]*=[\s]*(.*)[\s]*$ - 1 - - - net.ipv6.conf.all.accept_ra_defrtr - - - - oval:ssg-object_static_etc_sysctls_sysctl_net_ipv6_conf_all_accept_ra_defrtr:obj:1 - oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv6_conf_all_accept_ra_defrtr:obj:1 - - - - - oval:ssg-object_static_sysctl_sysctl_net_ipv6_conf_all_accept_ra_defrtr:obj:1 - oval:ssg-object_static_etc_sysctld_sysctl_net_ipv6_conf_all_accept_ra_defrtr:obj:1 - - - - - oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv6_conf_all_accept_ra_defrtr:obj:1 - oval:ssg-object_static_run_sysctld_sysctl_net_ipv6_conf_all_accept_ra_defrtr:obj:1 - - - - /etc/sysctl.conf - ^[\s]*net.ipv6.conf.all.accept_ra_defrtr[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /etc/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.all.accept_ra_defrtr[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /run/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.all.accept_ra_defrtr[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/local/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.all.accept_ra_defrtr[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.all.accept_ra_defrtr[\s]*=[\s]*(.*)[\s]*$ - 1 - - - net.ipv6.conf.all.accept_ra_pinfo - - - - oval:ssg-object_static_etc_sysctls_sysctl_net_ipv6_conf_all_accept_ra_pinfo:obj:1 - oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv6_conf_all_accept_ra_pinfo:obj:1 - - - - - oval:ssg-object_static_sysctl_sysctl_net_ipv6_conf_all_accept_ra_pinfo:obj:1 - oval:ssg-object_static_etc_sysctld_sysctl_net_ipv6_conf_all_accept_ra_pinfo:obj:1 - - - - - oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv6_conf_all_accept_ra_pinfo:obj:1 - oval:ssg-object_static_run_sysctld_sysctl_net_ipv6_conf_all_accept_ra_pinfo:obj:1 - - - - /etc/sysctl.conf - ^[\s]*net.ipv6.conf.all.accept_ra_pinfo[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /etc/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.all.accept_ra_pinfo[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /run/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.all.accept_ra_pinfo[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/local/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.all.accept_ra_pinfo[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.all.accept_ra_pinfo[\s]*=[\s]*(.*)[\s]*$ - 1 - - - net.ipv6.conf.all.accept_ra_rtr_pref - - - - oval:ssg-object_static_etc_sysctls_sysctl_net_ipv6_conf_all_accept_ra_rtr_pref:obj:1 - oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv6_conf_all_accept_ra_rtr_pref:obj:1 - - - - - oval:ssg-object_static_sysctl_sysctl_net_ipv6_conf_all_accept_ra_rtr_pref:obj:1 - oval:ssg-object_static_etc_sysctld_sysctl_net_ipv6_conf_all_accept_ra_rtr_pref:obj:1 - - - - - oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv6_conf_all_accept_ra_rtr_pref:obj:1 - oval:ssg-object_static_run_sysctld_sysctl_net_ipv6_conf_all_accept_ra_rtr_pref:obj:1 - - - - /etc/sysctl.conf - ^[\s]*net.ipv6.conf.all.accept_ra_rtr_pref[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /etc/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.all.accept_ra_rtr_pref[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /run/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.all.accept_ra_rtr_pref[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/local/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.all.accept_ra_rtr_pref[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.all.accept_ra_rtr_pref[\s]*=[\s]*(.*)[\s]*$ - 1 - - - net.ipv6.conf.all.accept_redirects - - - - oval:ssg-object_static_etc_sysctls_sysctl_net_ipv6_conf_all_accept_redirects:obj:1 - oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv6_conf_all_accept_redirects:obj:1 - - - - - oval:ssg-object_static_sysctl_sysctl_net_ipv6_conf_all_accept_redirects:obj:1 - oval:ssg-object_static_etc_sysctld_sysctl_net_ipv6_conf_all_accept_redirects:obj:1 - - - - - oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv6_conf_all_accept_redirects:obj:1 - oval:ssg-object_static_run_sysctld_sysctl_net_ipv6_conf_all_accept_redirects:obj:1 - - - - /etc/sysctl.conf - ^[\s]*net.ipv6.conf.all.accept_redirects[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /etc/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.all.accept_redirects[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /run/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.all.accept_redirects[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/local/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.all.accept_redirects[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.all.accept_redirects[\s]*=[\s]*(.*)[\s]*$ - 1 - - - net.ipv6.conf.all.accept_source_route - - - - oval:ssg-object_static_etc_sysctls_sysctl_net_ipv6_conf_all_accept_source_route:obj:1 - oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv6_conf_all_accept_source_route:obj:1 - - - - - oval:ssg-object_static_sysctl_sysctl_net_ipv6_conf_all_accept_source_route:obj:1 - oval:ssg-object_static_etc_sysctld_sysctl_net_ipv6_conf_all_accept_source_route:obj:1 - - - - - oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv6_conf_all_accept_source_route:obj:1 - oval:ssg-object_static_run_sysctld_sysctl_net_ipv6_conf_all_accept_source_route:obj:1 - - - - /etc/sysctl.conf - ^[\s]*net.ipv6.conf.all.accept_source_route[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /etc/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.all.accept_source_route[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /run/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.all.accept_source_route[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/local/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.all.accept_source_route[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.all.accept_source_route[\s]*=[\s]*(.*)[\s]*$ - 1 - - - net.ipv6.conf.all.autoconf - - - - oval:ssg-object_static_etc_sysctls_sysctl_net_ipv6_conf_all_autoconf:obj:1 - oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv6_conf_all_autoconf:obj:1 - - - - - oval:ssg-object_static_sysctl_sysctl_net_ipv6_conf_all_autoconf:obj:1 - oval:ssg-object_static_etc_sysctld_sysctl_net_ipv6_conf_all_autoconf:obj:1 - - - - - oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv6_conf_all_autoconf:obj:1 - oval:ssg-object_static_run_sysctld_sysctl_net_ipv6_conf_all_autoconf:obj:1 - - - - /etc/sysctl.conf - ^[\s]*net.ipv6.conf.all.autoconf[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /etc/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.all.autoconf[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /run/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.all.autoconf[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/local/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.all.autoconf[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.all.autoconf[\s]*=[\s]*(.*)[\s]*$ - 1 - - - net.ipv6.conf.all.disable_ipv6 - - - - oval:ssg-object_static_etc_sysctls_sysctl_net_ipv6_conf_all_disable_ipv6:obj:1 - oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv6_conf_all_disable_ipv6:obj:1 - - - - - oval:ssg-object_static_sysctl_sysctl_net_ipv6_conf_all_disable_ipv6:obj:1 - oval:ssg-object_static_etc_sysctld_sysctl_net_ipv6_conf_all_disable_ipv6:obj:1 - - - - - oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv6_conf_all_disable_ipv6:obj:1 - oval:ssg-object_static_run_sysctld_sysctl_net_ipv6_conf_all_disable_ipv6:obj:1 - - - - /etc/sysctl.conf - ^[\s]*net.ipv6.conf.all.disable_ipv6[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /etc/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.all.disable_ipv6[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /run/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.all.disable_ipv6[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/local/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.all.disable_ipv6[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.all.disable_ipv6[\s]*=[\s]*(.*)[\s]*$ - 1 - - - net.ipv6.conf.all.forwarding - - - - oval:ssg-object_static_etc_sysctls_sysctl_net_ipv6_conf_all_forwarding:obj:1 - oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv6_conf_all_forwarding:obj:1 - - - - - oval:ssg-object_static_sysctl_sysctl_net_ipv6_conf_all_forwarding:obj:1 - oval:ssg-object_static_etc_sysctld_sysctl_net_ipv6_conf_all_forwarding:obj:1 - - - - - oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv6_conf_all_forwarding:obj:1 - oval:ssg-object_static_run_sysctld_sysctl_net_ipv6_conf_all_forwarding:obj:1 - - - - /etc/sysctl.conf - ^[\s]*net.ipv6.conf.all.forwarding[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /etc/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.all.forwarding[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /run/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.all.forwarding[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/local/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.all.forwarding[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.all.forwarding[\s]*=[\s]*(.*)[\s]*$ - 1 - - - net.ipv6.conf.all.max_addresses - - - - oval:ssg-object_static_etc_sysctls_sysctl_net_ipv6_conf_all_max_addresses:obj:1 - oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv6_conf_all_max_addresses:obj:1 - - - - - oval:ssg-object_static_sysctl_sysctl_net_ipv6_conf_all_max_addresses:obj:1 - oval:ssg-object_static_etc_sysctld_sysctl_net_ipv6_conf_all_max_addresses:obj:1 - - - - - oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv6_conf_all_max_addresses:obj:1 - oval:ssg-object_static_run_sysctld_sysctl_net_ipv6_conf_all_max_addresses:obj:1 - - - - /etc/sysctl.conf - ^[\s]*net.ipv6.conf.all.max_addresses[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /etc/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.all.max_addresses[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /run/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.all.max_addresses[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/local/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.all.max_addresses[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.all.max_addresses[\s]*=[\s]*(.*)[\s]*$ - 1 - - - net.ipv6.conf.all.router_solicitations - - - - oval:ssg-object_static_etc_sysctls_sysctl_net_ipv6_conf_all_router_solicitations:obj:1 - oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv6_conf_all_router_solicitations:obj:1 - - - - - oval:ssg-object_static_sysctl_sysctl_net_ipv6_conf_all_router_solicitations:obj:1 - oval:ssg-object_static_etc_sysctld_sysctl_net_ipv6_conf_all_router_solicitations:obj:1 - - - - - oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv6_conf_all_router_solicitations:obj:1 - oval:ssg-object_static_run_sysctld_sysctl_net_ipv6_conf_all_router_solicitations:obj:1 - - - - /etc/sysctl.conf - ^[\s]*net.ipv6.conf.all.router_solicitations[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /etc/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.all.router_solicitations[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /run/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.all.router_solicitations[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/local/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.all.router_solicitations[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.all.router_solicitations[\s]*=[\s]*(.*)[\s]*$ - 1 - - - net.ipv6.conf.default.accept_ra - - - - oval:ssg-object_static_etc_sysctls_sysctl_net_ipv6_conf_default_accept_ra:obj:1 - oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv6_conf_default_accept_ra:obj:1 - - - - - oval:ssg-object_static_sysctl_sysctl_net_ipv6_conf_default_accept_ra:obj:1 - oval:ssg-object_static_etc_sysctld_sysctl_net_ipv6_conf_default_accept_ra:obj:1 - - - - - oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv6_conf_default_accept_ra:obj:1 - oval:ssg-object_static_run_sysctld_sysctl_net_ipv6_conf_default_accept_ra:obj:1 - - - - /etc/sysctl.conf - ^[\s]*net.ipv6.conf.default.accept_ra[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /etc/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.default.accept_ra[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /run/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.default.accept_ra[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/local/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.default.accept_ra[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.default.accept_ra[\s]*=[\s]*(.*)[\s]*$ - 1 - - - net.ipv6.conf.default.accept_ra_defrtr - - - - oval:ssg-object_static_etc_sysctls_sysctl_net_ipv6_conf_default_accept_ra_defrtr:obj:1 - oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv6_conf_default_accept_ra_defrtr:obj:1 - - - - - oval:ssg-object_static_sysctl_sysctl_net_ipv6_conf_default_accept_ra_defrtr:obj:1 - oval:ssg-object_static_etc_sysctld_sysctl_net_ipv6_conf_default_accept_ra_defrtr:obj:1 - - - - - oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv6_conf_default_accept_ra_defrtr:obj:1 - oval:ssg-object_static_run_sysctld_sysctl_net_ipv6_conf_default_accept_ra_defrtr:obj:1 - - - - /etc/sysctl.conf - ^[\s]*net.ipv6.conf.default.accept_ra_defrtr[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /etc/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.default.accept_ra_defrtr[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /run/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.default.accept_ra_defrtr[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/local/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.default.accept_ra_defrtr[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.default.accept_ra_defrtr[\s]*=[\s]*(.*)[\s]*$ - 1 - - - net.ipv6.conf.default.accept_ra_pinfo - - - - oval:ssg-object_static_etc_sysctls_sysctl_net_ipv6_conf_default_accept_ra_pinfo:obj:1 - oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv6_conf_default_accept_ra_pinfo:obj:1 - - - - - oval:ssg-object_static_sysctl_sysctl_net_ipv6_conf_default_accept_ra_pinfo:obj:1 - oval:ssg-object_static_etc_sysctld_sysctl_net_ipv6_conf_default_accept_ra_pinfo:obj:1 - - - - - oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv6_conf_default_accept_ra_pinfo:obj:1 - oval:ssg-object_static_run_sysctld_sysctl_net_ipv6_conf_default_accept_ra_pinfo:obj:1 - - - - /etc/sysctl.conf - ^[\s]*net.ipv6.conf.default.accept_ra_pinfo[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /etc/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.default.accept_ra_pinfo[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /run/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.default.accept_ra_pinfo[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/local/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.default.accept_ra_pinfo[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.default.accept_ra_pinfo[\s]*=[\s]*(.*)[\s]*$ - 1 - - - net.ipv6.conf.default.accept_ra_rtr_pref - - - - oval:ssg-object_static_etc_sysctls_sysctl_net_ipv6_conf_default_accept_ra_rtr_pref:obj:1 - oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv6_conf_default_accept_ra_rtr_pref:obj:1 - - - - - oval:ssg-object_static_sysctl_sysctl_net_ipv6_conf_default_accept_ra_rtr_pref:obj:1 - oval:ssg-object_static_etc_sysctld_sysctl_net_ipv6_conf_default_accept_ra_rtr_pref:obj:1 - - - - - oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv6_conf_default_accept_ra_rtr_pref:obj:1 - oval:ssg-object_static_run_sysctld_sysctl_net_ipv6_conf_default_accept_ra_rtr_pref:obj:1 - - - - /etc/sysctl.conf - ^[\s]*net.ipv6.conf.default.accept_ra_rtr_pref[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /etc/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.default.accept_ra_rtr_pref[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /run/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.default.accept_ra_rtr_pref[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/local/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.default.accept_ra_rtr_pref[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.default.accept_ra_rtr_pref[\s]*=[\s]*(.*)[\s]*$ - 1 - - - net.ipv6.conf.default.accept_redirects - - - - oval:ssg-object_static_etc_sysctls_sysctl_net_ipv6_conf_default_accept_redirects:obj:1 - oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv6_conf_default_accept_redirects:obj:1 - - - - - oval:ssg-object_static_sysctl_sysctl_net_ipv6_conf_default_accept_redirects:obj:1 - oval:ssg-object_static_etc_sysctld_sysctl_net_ipv6_conf_default_accept_redirects:obj:1 - - - - - oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv6_conf_default_accept_redirects:obj:1 - oval:ssg-object_static_run_sysctld_sysctl_net_ipv6_conf_default_accept_redirects:obj:1 - - - - /etc/sysctl.conf - ^[\s]*net.ipv6.conf.default.accept_redirects[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /etc/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.default.accept_redirects[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /run/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.default.accept_redirects[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/local/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.default.accept_redirects[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.default.accept_redirects[\s]*=[\s]*(.*)[\s]*$ - 1 - - - net.ipv6.conf.default.accept_source_route - - - - oval:ssg-object_static_etc_sysctls_sysctl_net_ipv6_conf_default_accept_source_route:obj:1 - oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv6_conf_default_accept_source_route:obj:1 - - - - - oval:ssg-object_static_sysctl_sysctl_net_ipv6_conf_default_accept_source_route:obj:1 - oval:ssg-object_static_etc_sysctld_sysctl_net_ipv6_conf_default_accept_source_route:obj:1 - - - - - oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv6_conf_default_accept_source_route:obj:1 - oval:ssg-object_static_run_sysctld_sysctl_net_ipv6_conf_default_accept_source_route:obj:1 - - - - /etc/sysctl.conf - ^[\s]*net.ipv6.conf.default.accept_source_route[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /etc/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.default.accept_source_route[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /run/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.default.accept_source_route[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/local/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.default.accept_source_route[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.default.accept_source_route[\s]*=[\s]*(.*)[\s]*$ - 1 - - - net.ipv6.conf.default.autoconf - - - - oval:ssg-object_static_etc_sysctls_sysctl_net_ipv6_conf_default_autoconf:obj:1 - oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv6_conf_default_autoconf:obj:1 - - - - - oval:ssg-object_static_sysctl_sysctl_net_ipv6_conf_default_autoconf:obj:1 - oval:ssg-object_static_etc_sysctld_sysctl_net_ipv6_conf_default_autoconf:obj:1 - - - - - oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv6_conf_default_autoconf:obj:1 - oval:ssg-object_static_run_sysctld_sysctl_net_ipv6_conf_default_autoconf:obj:1 - - - - /etc/sysctl.conf - ^[\s]*net.ipv6.conf.default.autoconf[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /etc/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.default.autoconf[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /run/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.default.autoconf[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/local/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.default.autoconf[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.default.autoconf[\s]*=[\s]*(.*)[\s]*$ - 1 - - - net.ipv6.conf.default.disable_ipv6 - - - - oval:ssg-object_static_etc_sysctls_sysctl_net_ipv6_conf_default_disable_ipv6:obj:1 - oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv6_conf_default_disable_ipv6:obj:1 - - - - - oval:ssg-object_static_sysctl_sysctl_net_ipv6_conf_default_disable_ipv6:obj:1 - oval:ssg-object_static_etc_sysctld_sysctl_net_ipv6_conf_default_disable_ipv6:obj:1 - - - - - oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv6_conf_default_disable_ipv6:obj:1 - oval:ssg-object_static_run_sysctld_sysctl_net_ipv6_conf_default_disable_ipv6:obj:1 - - - - /etc/sysctl.conf - ^[\s]*net.ipv6.conf.default.disable_ipv6[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /etc/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.default.disable_ipv6[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /run/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.default.disable_ipv6[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/local/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.default.disable_ipv6[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.default.disable_ipv6[\s]*=[\s]*(.*)[\s]*$ - 1 - - - net.ipv6.conf.default.max_addresses - - - - oval:ssg-object_static_etc_sysctls_sysctl_net_ipv6_conf_default_max_addresses:obj:1 - oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv6_conf_default_max_addresses:obj:1 - - - - - oval:ssg-object_static_sysctl_sysctl_net_ipv6_conf_default_max_addresses:obj:1 - oval:ssg-object_static_etc_sysctld_sysctl_net_ipv6_conf_default_max_addresses:obj:1 - - - - - oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv6_conf_default_max_addresses:obj:1 - oval:ssg-object_static_run_sysctld_sysctl_net_ipv6_conf_default_max_addresses:obj:1 - - - - /etc/sysctl.conf - ^[\s]*net.ipv6.conf.default.max_addresses[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /etc/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.default.max_addresses[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /run/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.default.max_addresses[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/local/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.default.max_addresses[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.default.max_addresses[\s]*=[\s]*(.*)[\s]*$ - 1 - - - net.ipv6.conf.default.router_solicitations - - - - oval:ssg-object_static_etc_sysctls_sysctl_net_ipv6_conf_default_router_solicitations:obj:1 - oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv6_conf_default_router_solicitations:obj:1 - - - - - oval:ssg-object_static_sysctl_sysctl_net_ipv6_conf_default_router_solicitations:obj:1 - oval:ssg-object_static_etc_sysctld_sysctl_net_ipv6_conf_default_router_solicitations:obj:1 - - - - - oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv6_conf_default_router_solicitations:obj:1 - oval:ssg-object_static_run_sysctld_sysctl_net_ipv6_conf_default_router_solicitations:obj:1 - - - - /etc/sysctl.conf - ^[\s]*net.ipv6.conf.default.router_solicitations[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /etc/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.default.router_solicitations[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /run/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.default.router_solicitations[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/local/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.default.router_solicitations[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/lib/sysctl.d - ^.*\.conf$ - ^[\s]*net.ipv6.conf.default.router_solicitations[\s]*=[\s]*(.*)[\s]*$ - 1 - - - user.max_user_namespaces - - - - oval:ssg-object_static_etc_sysctls_sysctl_user_max_user_namespaces:obj:1 - oval:ssg-object_static_run_usr_local_sysctls_sysctl_user_max_user_namespaces:obj:1 - - - - - oval:ssg-object_static_sysctl_sysctl_user_max_user_namespaces:obj:1 - oval:ssg-object_static_etc_sysctld_sysctl_user_max_user_namespaces:obj:1 - - - - - oval:ssg-object_static_usr_local_lib_sysctld_sysctl_user_max_user_namespaces:obj:1 - oval:ssg-object_static_run_sysctld_sysctl_user_max_user_namespaces:obj:1 - - - - /etc/sysctl.conf - ^[\s]*user.max_user_namespaces[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /etc/sysctl.d - ^.*\.conf$ - ^[\s]*user.max_user_namespaces[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /run/sysctl.d - ^.*\.conf$ - ^[\s]*user.max_user_namespaces[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/local/lib/sysctl.d - ^.*\.conf$ - ^[\s]*user.max_user_namespaces[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/lib/sysctl.d - ^.*\.conf$ - ^[\s]*user.max_user_namespaces[\s]*=[\s]*(.*)[\s]*$ - 1 - - - vm.mmap_min_addr - - - - oval:ssg-object_static_etc_sysctls_sysctl_vm_mmap_min_addr:obj:1 - oval:ssg-object_static_run_usr_local_sysctls_sysctl_vm_mmap_min_addr:obj:1 - - - - - oval:ssg-object_static_sysctl_sysctl_vm_mmap_min_addr:obj:1 - oval:ssg-object_static_etc_sysctld_sysctl_vm_mmap_min_addr:obj:1 - - - - - oval:ssg-object_static_usr_local_lib_sysctld_sysctl_vm_mmap_min_addr:obj:1 - oval:ssg-object_static_run_sysctld_sysctl_vm_mmap_min_addr:obj:1 - - - - /etc/sysctl.conf - ^[\s]*vm.mmap_min_addr[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /etc/sysctl.d - ^.*\.conf$ - ^[\s]*vm.mmap_min_addr[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /run/sysctl.d - ^.*\.conf$ - ^[\s]*vm.mmap_min_addr[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/local/lib/sysctl.d - ^.*\.conf$ - ^[\s]*vm.mmap_min_addr[\s]*=[\s]*(.*)[\s]*$ - 1 - - - /usr/lib/sysctl.d - ^.*\.conf$ - ^[\s]*vm.mmap_min_addr[\s]*=[\s]*(.*)[\s]*$ - 1 - - - multi-user.target - - - dnf-automatic\.timer - ActiveState - - - multi-user.target - - - logrotate\.timer - ActiveState - - - /etc/pam.d/system-auth - ^\s*password\s+(?:(?:required)|(?:requisite))\s+pam_faillock\.so.*$ - 1 - - - - ^\s*password\s+(?:(?:required)|(?:requisite))\s+pam_pwquality\.so.*$ - 1 - - - /usr/lib/systemd/system/auditd.service - ^ExecStartPost=\-\/sbin\/auditctl.*$ - 1 - - - /usr/lib/systemd/system/auditd.service - ^(ExecStartPost=\-\/sbin\/augenrules.*$|Requires=augenrules.service) - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+setdomainname[\s]+|([\s]+|[,])setdomainname([\s]+|[,]))).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+setdomainname[\s]+|([\s]+|[,])setdomainname([\s]+|[,]))).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+setdomainname[\s]+|([\s]+|[,])setdomainname([\s]+|[,]))).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+setdomainname[\s]+|([\s]+|[,])setdomainname([\s]+|[,]))).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+sethostname[\s]+|([\s]+|[,])sethostname([\s]+|[,]))).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+sethostname[\s]+|([\s]+|[,])sethostname([\s]+|[,]))).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+sethostname[\s]+|([\s]+|[,])sethostname([\s]+|[,]))).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+sethostname[\s]+|([\s]+|[,])sethostname([\s]+|[,]))).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/auditd.conf - ^(log_file\s*=\s*.*)$ - 1 - - - /etc/audit/auditd.conf - ^[ ]*log_group[ ]+=[ ]+root[ ]*$ - 1 - - - /etc/audit/auditd.conf - ^[ ]*log_group[ ]+=.*$ - 1 - - - /etc/default/grub - ^\s*GRUB_DISABLE_RECOVERY=(.*)$ - 1 - - - ^/etc/chrony\.(conf|d/.+\.conf)$ - ^([\s]*server[\s]+.+$){2,}$ - 1 - - - /etc/default/grub - ^\s*GRUB_CMDLINE_LINUX_DEFAULT=.*$ - 1 - - - /boot/loader/entries/ - ^.*\.conf$ - ^options(?:\s+.*)?\s+\$kernelopts\b.*$ - 1 - - - anolis-release - - - centos-release - - - /etc/os-release - ^ID="(\w+)"$ - 1 - - - /etc/os-release - ^VERSION_ID="(\d)"$ - 1 - - - /etc/os-release - ^ID="(\w+)"$ - 1 - - - /etc/os-release - ^VERSION_ID="(\d)"$ - 1 - - - /etc/debian_version - - - fedora-release.* - - - /etc/system-release-cpe - ^cpe:\/o:fedoraproject:fedora:[\d]+$ - 1 - - - /etc/os-release - ^ID=["']?(\w+)["']?$ - 1 - - - oraclelinux-release - - - oraclelinux-release - - - oraclelinux-release - - - openSUSE-release - - - - /etc/os-release - ^ID="(\w+)"$ - 1 - - - /etc/os-release - ^VERSION_ID="(\d)\.\d+"$ - 1 - - - /etc/os-release - ^RHEL_VERSION="(\d).*"$ - 1 - - - /etc/os-release - ^ID=["']?(\w+)["']?$ - 1 - - - - redhat-release-client - - - redhat-release-workstation - - - redhat-release-server - - - redhat-release-computenode - - - /etc/redhat-release - ^Red Hat Enterprise Linux release (\d)\.\d+$ - 1 - - - - redhat-release - - - redhat-release - - - redhat-release - - - redhat-release - - - redhat-release - - - redhat-release - - - redhat-release - - - redhat-release - - - redhat-release - - - redhat-release - - - redhat-release - - - redhat-release - - - /etc/redhat-release - ^Red Hat Enterprise Linux release (\d)\.\d+$ - 1 - - - - redhat-release - - - /etc/redhat-release - ^Red Hat Enterprise Linux release (\d)\.\d+$ - 1 - - - redhat-release-virtualization-host - - - sl-release - - - - sled-release - - - sles-release - - - SLES_SAP-release - - - - sled-release - - - sles-release - - - SLES_SAP-release - - - SUSE-Manager-Server-release - - - SLE_HPC-release - - - /etc/lsb-release - - - /etc/lsb-release - ^DISTRIB_ID=Ubuntu$ - 1 - - - /etc/lsb-release - ^DISTRIB_CODENAME=xenial$ - 1 - - - /etc/lsb-release - ^DISTRIB_CODENAME=bionic$ - 1 - - - /etc/lsb-release - ^DISTRIB_CODENAME=focal$ - 1 - - - s390utils-base - - - - container - - - /etc/fstab - - 1 - - - - - - oval:ssg-sshd_required:var:1 - - - oval:ssg-sshd_required:var:1 - - - oval:ssg-sshd_required:var:1 - - - openssh-server - - - - - - - - - /etc/tmux.conf - - - ^/etc/usbguard/(rules|rules\.d/.*)\.conf$ - ^.*\S+.*$ - 1 - - - oval:ssg-var_accounts_user_umask_umask_as_number:var:1 - - - oval:ssg-var_removable_partition:var:1 - - - oval:ssg-var_umask_for_daemons_umask_as_number:var:1 - - - - - 0 - - - - - - (?i)root - - - - - - ^permit_mynetworks[ \t]*[, \t][ \t]*reject$ - - - ^.*,sec=krb5\:krb5i\:krb5p.*$ - - - 0 - - - 0 - - - - - - maxpoll \d+ - - - - - - symbolic link - - - /etc/ssh - .*_key$ - 0 - 0 - false - false - false - false - false - false - false - false - false - false - - - /etc/ssh - .*_key$ - - 0 - false - false - false - false - false - false - false - false - false - - - - - - - - - - - - - - - - - - - - - 0 - - - - - - - - - 0 - - - - - - 0 - - - - - - 0 - - - 10 - - - 30 - - - 100 - - - - - - - - - ^.*(try_cert_auth|require_cert_auth).*$ - - - ^.*allow_missing_name.*$ - - - ^LinuxAudit$ - - - /etc/systemd/system/default.target - ^(/usr)?/lib/systemd/system/multi-user.target$ - - - /etc/pam.d/fingerprint-auth - /etc/authselect/fingerprint-auth - - - /etc/pam.d/password-auth - /etc/authselect/password-auth - - - /etc/pam.d/postlogin - /etc/authselect/postlogin - - - /etc/pam.d/smartcard-auth - /etc/authselect/smartcard-auth - - - /etc/pam.d/system-auth - /etc/authselect/system-auth - - - - - - - - - - - - faillog_t - - - - - - - - - - - - - - - 0 - - - /var/run/faillock - - - 2 - - - 2 - - - - - - - - - - - - 0 - - - - - - 5000 - - - /etc/systemd/system/ctrl-alt-del.target - /dev/null - - - 0 - - - 900 - - - - - - - - - - - - ^root$ - - - - - - - - - - - - 0 - - - - - - 0 - - - - - - -1 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ^[x*]$ - - - ^(!|!!|!\*|\*|!locked)$ - - - ^(!\$6\$|!!\$6\$).*$ - - - SHA-512 - - - .* - - - ^(!|!!|!\*|\*|!locked)$ - - - 86400000 - - - - - - - - - - - - - - - - - - 0 - - - 1000 - - - ^(root|halt|sync|shutdown|nfsnobody)$ - - - ^(!|!!|!\*|\*|!locked).*$ - - - 0 - - - - - - - - - - - - - - - - - - - - - directory - false - false - false - false - false - false - false - false - false - - - directory - false - false - false - false - false - false - false - false - false - - - 1 - - - - - - 1000 - - - ^(nobody|nfsnobody)$ - - - ^/sbin/nologin$ - - - regular - true - - - 1000 - - - ^(nobody|nfsnobody)$ - - - ^/sbin/nologin$ - - - ^\/[^\/\n]*\/[^\/\n]{1,}.*$ - - - ^(nobody|nfsnobody)$ - - - - - - ^(nobody|nfsnobody)$ - - - ^(nobody|nfsnobody)$ - - - - - - false - false - false - false - false - false - false - false - - - 1000 - - - ^(nobody|nfsnobody)$ - - - ^/sbin/nologin$ - - - ^(nobody|nfsnobody)$ - - - directory - false - false - false - false - false - false - false - - - 1000 - - - ^(nobody|nfsnobody)$ - - - ^/sbin/nologin$ - - - directory - false - false - false - false - false - false - false - - - true - true - - - symbolic link - - - ^[:\.] - - - :: - - - \.\. - - - [:\.]$ - - - ^[^/] - - - [^\\]:[^/] - - - - - - - - - - - - - - - ^(nobody|nfsnobody)$ - - - ^\.bash_history - - - - - - 0 - - - 0 - - - 0 - - - true - true - true - true - true - true - true - - - true - true - true - true - true - true - true - true - true - - - 0 - - - 0 - 0 - - - 0 - 0 - - - 0 - - - true - true - true - true - true - true - true - true - true - true - - - ^/dev/.*$ - - - nosuid - - - noexec - - - true - true - - - - - - - - - - - - - - - - - - SYSLOG - - - SINGLE - - - HALT - - - - - - SYSLOG - - - SINGLE - - - HALT - - - - - - - - - - - - - - - - - - - - - rotate - - - single - - - - - - - - - - - - ^(?i)hostname(?-i)$ - - - ^(?i)(syslog|single|halt)(?-i)$ - - - - - - - - - (?=[\S\s]*\s(?i)protocol(?-i)="tcp")(?=[\S\s]*\s(?i)Target(?-i)="[^"]+?")(?=[\S\s]*\s(?i)port(?-i)="6514")(?=[\S\s]*\s(?i)StreamDriver(?-i)="gtls")(?=[\S\s]*\s(?i)StreamDriverMode(?-i)="1")(?=[\S\s]*\s(?i)StreamDriverAuthMode(?-i)="x509/name")(?=[\S\s]*\s(?i)StreamDriver\.CheckExtendedKeyPurpose(?-i)="on") - - - 0 - - - PROMISC - - - UP - - - 0 - true - - - false - true - - - 0 - - - false - false - false - false - false - false - false - false - false - false - - - true - - - - - - true - - - - - - regular - true - - - ^/selinux/(?:(?:member)|(?:user)|(?:relabel)|(?:create)|(?:access)|(?:context))$ - - - ^/proc/.*$ - - - ^/sys/.*$ - - - - - - - - - 1000 - - - 0 - - - true - true - - - symbolic link - - - ^/dev/.*$ - nodev - - - ^(?i)0(?-i)$ - - - ^(?i)0(?-i)$ - - - ^(?i)none(?-i)$ - - - ^(?i)none(?-i)$ - - - 0 - - - 0 - - - unconfined_service_t - - - ^(enforcing|permissive)$ - - - - - - - - - x86_64 - - - \blm\b - - - ^(x86_64|aarch64|ppc64le|s390x)$ - - - - - - - - - ^false$ - - - - - - - - - - - - - - - - - - - - - /etc/crypto-policies/back-ends/krb5.config - - - 1.2 - - - - - - - - - 0:20210617-1 - - - ^final all$ - - - ^512M 1h$ - - - ^no$ - - - ^aes256-ctr,aes256-cbc,aes128-ctr,aes128-cbc$ - - - ^ssh-rsa,ecdsa-sha2-nistp384,ecdsa-sha2-nistp256$ - - - ^hmac-sha2-512,hmac-sha2-256$ - - - ^ecdh-sha2-nistp521,ecdh-sha2-nistp384,ecdh-sha2-nistp256,diffie-hellman-group14-sha1$ - - - - - - - - - - - - - - - fips - - - ^(?:.*\s)?fips=1(?:\s.*)?$ - - - ^FIPS(:OSPP)?$ - - - 1 - - - ^p\+i\+n\+u\+g\+s\+b\+acl(|\+selinux)\+xattrs\+sha512$ - - - ^.*acl.*$ - - - ^.*xattrs.*$ - - - fail - false - false - - - fail - - - fail - - - fail - - - ^yes$ - - - ^security$ - - - 629e59ec - 8d8b756f - - - 629ec292 - 8b4efbe6 - - - - - - - - - - - - - - - - - - 0 - - - - - - - - - - - - - - - - - - ## Unsuccessful file access (any other opens) This has to go last. + later. + + + + + + + + Verify the system-wide library files in directories +"/lib", "/lib64", "/usr/lib/" and "/usr/lib64" are group-owned by root. + + Oracle Linux 9 + + + This test makes sure that /lib/, /lib64/, /usr/lib/, /usr/lib64/ is group owned by 0. + + + + + + + + + + + Ensure Log Files Are Owned By Appropriate Group + + Oracle Linux 9 + + + All syslog log files should have appropriate ownership. + + + + + + + + Ensure Log Files Are Owned By Appropriate User + + Oracle Linux 9 + + + All syslog log files should have appropriate ownership. + + + + + + + + Ensure System Log Files Have Correct Permissions + + Oracle Linux 9 + + + All syslog log files should have appropriate ownership. + + + + + + + + Enable the auditadm_exec_content SELinux Boolean + + Oracle Linux 9 + + + The SELinux 'auditadm_exec_content' boolean should be set in the system configuration. + + + + + + + + Disable the authlogin_nsswitch_use_ldap SELinux Boolean + + Oracle Linux 9 + + + The SELinux 'authlogin_nsswitch_use_ldap' boolean should be set in the system configuration. + + + + + + + + Disable the authlogin_radius SELinux Boolean + + Oracle Linux 9 + + + The SELinux 'authlogin_radius' boolean should be set in the system configuration. + + + + + + + + Configure the deny_execmem SELinux Boolean + + Oracle Linux 9 + + + The SELinux 'deny_execmem' boolean should be set in the system configuration. + + + + + + + + Enable the kerberos_enabled SELinux Boolean + + Oracle Linux 9 + + + The SELinux 'kerberos_enabled' boolean should be set in the system configuration. + + + + + + + + Configure the polyinstantiation_enabled SELinux Boolean + + Oracle Linux 9 + + + The SELinux 'polyinstantiation_enabled' boolean should be set in the system configuration. + + + + + + + + Configure the secure_mode_insmod SELinux Boolean + + Oracle Linux 9 + + + The SELinux 'secure_mode_insmod' boolean should be set in the system configuration. + + + + + + + + Disable the selinuxuser_execheap SELinux Boolean + + Oracle Linux 9 + + + The SELinux 'selinuxuser_execheap' boolean should be set in the system configuration. + + + + + + + + Enable the selinuxuser_execmod SELinux Boolean + + Oracle Linux 9 + + + The SELinux 'selinuxuser_execmod' boolean should be set in the system configuration. + + + + + + + + Disable the selinuxuser_execstack SELinux Boolean + + Oracle Linux 9 + + + The SELinux 'selinuxuser_execstack' boolean should be set in the system configuration. + + + + + + + + Disable the ssh_sysadm_login SELinux Boolean + + Oracle Linux 9 + + + The SELinux 'ssh_sysadm_login' boolean should be set in the system configuration. + + + + + + + + Disable At Service (atd) + + Oracle Linux 9 + + + The atd service should be disabled. + + + + + + + + + + + + Enable auditd Service + + Oracle Linux 9 + + + The auditd service should be enabled if possible. + + + + + + + + + + + + + + + Disable the Automounter + + Oracle Linux 9 + + + The autofs service should be disabled. + + + + + + + + + + + + Disable Avahi Server Software + + Oracle Linux 9 + + + The avahi-daemon service should be disabled. + + + + + + + + + + + + The Chronyd service is enabled + + Oracle Linux 9 + + + The chronyd service should be enabled if possible. + + + + + + + + + + + + + + + Enable cron Service + + Oracle Linux 9 + + + The crond service should be enabled if possible. + + + + + + + + + + + + + + + Disable debug-shell SystemD Service + + Oracle Linux 9 + + + The debug-shell service should be disabled. + + + + + + + + + + + + Enable the File Access Policy Service + + Oracle Linux 9 + + + The fapolicyd service should be enabled if possible. + + + + + + + + + + + + + + + Verify firewalld Enabled + + Oracle Linux 9 + + + The firewalld service should be enabled if possible. + + + + + + + + + + + + + + + Verify iptables Enabled + + Oracle Linux 9 + + + The iptables service should be enabled if possible. + + + + + + + + + + + + + + + Disable KDump Kernel Crash Analyzer (kdump) + + Oracle Linux 9 + + + The kdump service should be disabled. + + + + + + + + + + + + Verify nftables Service is Disabled + + Oracle Linux 9 + + + The nftables service should be disabled. + + + + + + + + + + + + Disable Odd Job Daemon (oddjobd) + + Oracle Linux 9 + + + The oddjobd service should be disabled. + + + + + + + + + + + + Enable the pcscd Service + + Oracle Linux 9 + + + The pcscd service should be enabled if possible. + + + + + + + + + + + + + + + Enable Postfix Service + + Oracle Linux 9 + + + The postfix service should be enabled if possible. + + + + + + + + + + + + + + + Disable Network Router Discovery Daemon (rdisc) + + Oracle Linux 9 + + + The rdisc service should be disabled. + + + + + + + + + + + + Disable rlogin Service + + Oracle Linux 9 + + + The rlogin service should be disabled. + + + + + + + + + + + + Enable the Hardware RNG Entropy Gatherer Service + + Oracle Linux 9 + + + The rngd service should be enabled if possible. + + + + + + + + + + + + + + + Ensure rsyncd service is disabled + + Oracle Linux 9 + + + The rsyncd service should be disabled. + + + + + + + + + + + + Enable rsyslog Service + + Oracle Linux 9 + + + The rsyslog service should be enabled if possible. + + + + + + + + + + + + + + + Disable snmpd Service + + Oracle Linux 9 + + + The snmpd service should be disabled. + + + + + + + + + + + + Disable Squid + + Oracle Linux 9 + + + The squid service should be disabled. + + + + + + + + + + + + Disable SSH Server If Possible + + Oracle Linux 9 + + + The sshd service should be disabled. + + + + + + + + + + + + Enable the OpenSSH Service + + Oracle Linux 9 + + + The sshd service should be enabled if possible. + + + + + + + + + + + + + + + Enable the SSSD Service + + Oracle Linux 9 + + + The sssd service should be enabled if possible. + + + + + + + + + + + + + + + Enable syslog-ng Service + + Oracle Linux 9 + + + The syslog-ng service should be enabled if possible. + + + + + + + + + + + + + + + Disable acquiring, saving, and processing core dumps + + Oracle Linux 9 + + + Disable systemd-coredump.socket + + + + + + + + Enable systemd-journald Service + + Oracle Linux 9 + + + The systemd-journald service should be enabled if possible. + + + + + + + + + + + + + + + Disable telnet Service + + Oracle Linux 9 + + + The telnet service should be disabled. + + + + + + + + + + + + Verify ufw Enabled + + Oracle Linux 9 + + + The ufw service should be enabled if possible. + + + + + + + + + + + + + + + Enable the USBGuard Service + + Oracle Linux 9 + + + The usbguard service should be enabled if possible. + + + + + + + + + + + + + + + Set Default firewalld Zone for Incoming Packets + + Oracle Linux 9 + + + Check presence of DefaultZone=drop in /etc/firewalld/firewalld.conf + + + + + + + + Allow Only SSH Protocol 2 + + Oracle Linux 9 + + + Ensure 'Protocol' is configured with value '2' in /etc/ssh/sshd_config + + + + + + + + + + + + + + + + + + + + + + Disable Compression Or Set Compression to delayed + + Oracle Linux 9 + + + Ensure 'Compression' is configured with value configured in var_sshd_disable_compression variable in /etc/ssh/sshd_config + + + + + + + + + + + + + + + + + + + + + + Disable SSH Access via Empty Passwords + + Oracle Linux 9 + + + Ensure 'PermitEmptyPasswords' is configured with value 'no' in /etc/ssh/sshd_config + + + + + + + + + + + + + + + + + + + + + + Disable GSSAPI Authentication + + Oracle Linux 9 + + + Ensure 'GSSAPIAuthentication' is configured with value 'no' in /etc/ssh/sshd_config + + + + + + + + + + + + + + + + + + + + + + Disable Kerberos Authentication + + Oracle Linux 9 + + + Ensure 'KerberosAuthentication' is configured with value 'no' in /etc/ssh/sshd_config + + + + + + + + + + + + + + + + + + + + + + Disable PubkeyAuthentication Authentication + + Oracle Linux 9 + + + Ensure 'PubkeyAuthentication' is configured with value 'no' in /etc/ssh/sshd_config + + + + + + + + + + + + + + + + + + + + + + Disable SSH Support for .rhosts Files + + Oracle Linux 9 + + + Ensure 'IgnoreRhosts' is configured with value 'yes' in /etc/ssh/sshd_config + + + + + + + + + + + + + + + + + + + + + + Disable SSH Support for Rhosts RSA Authentication + + Oracle Linux 9 + + + Ensure 'RhostsRSAAuthentication' is configured with value 'no' in /etc/ssh/sshd_config + + + + + + + + + + + + + + + + + + + + + + Disable SSH Root Login + + Oracle Linux 9 + + + Ensure 'PermitRootLogin' is configured with value 'no' in /etc/ssh/sshd_config + + + + + + + + + + + + + + + + + + + + + + Disable SSH root Login with a Password (Insecure) + + Oracle Linux 9 + + + Ensure 'PermitRootLogin' is configured with value 'prohibit-password' in /etc/ssh/sshd_config + + + + + + + + + + + + + + + + + + + + + + Disable SSH TCP Forwarding + + Oracle Linux 9 + + + Ensure 'AllowTcpForwarding' is configured with value 'no' in /etc/ssh/sshd_config + + + + + + + + + + + + + + + + + + + + + + Disable SSH Support for User Known Hosts + + Oracle Linux 9 + + + Ensure 'IgnoreUserKnownHosts' is configured with value 'yes' in /etc/ssh/sshd_config + + + + + + + + + + + + + + + + + + + + + + Disable X11 Forwarding + + Oracle Linux 9 + + + Ensure 'X11Forwarding' is configured with value 'no' in /etc/ssh/sshd_config + + + + + + + + + + + + + + + + + + + + + + Do Not Allow SSH Environment Options + + Oracle Linux 9 + + + Ensure 'PermitUserEnvironment' is configured with value 'no' in /etc/ssh/sshd_config + + + + + + + + + + + + + + + + + + + + + + Enable GSSAPI Authentication + + Oracle Linux 9 + + + Ensure 'GSSAPIAuthentication' is configured with value 'yes' in /etc/ssh/sshd_config + + + + + + + + + + + + + + + + + + + + + + Enable PAM + + Oracle Linux 9 + + + Ensure 'UsePAM' is configured with value 'yes' in /etc/ssh/sshd_config + + + + + + + + + + + + + + + + + + + + + + Enable Public Key Authentication + + Oracle Linux 9 + + + Ensure 'PubkeyAuthentication' is configured with value 'yes' in /etc/ssh/sshd_config + + + + + + + + + + + + + + + + + + + + + + Enable Use of Strict Mode Checking + + Oracle Linux 9 + + + Ensure 'StrictModes' is configured with value 'yes' in /etc/ssh/sshd_config + + + + + + + + + + + + + + + + + + + + + + Enable SSH Warning Banner + + Oracle Linux 9 + + + Ensure 'Banner' is configured with value '/etc/issue' in /etc/ssh/sshd_config + + + + + + + + + + + + + + + + + + + + + + Enable SSH Warning Banner + + Oracle Linux 9 + + + Ensure 'Banner' is configured with value '/etc/issue.net' in /etc/ssh/sshd_config + + + + + + + + + + + + + + + + + + + + + + Enable Encrypted X11 Forwarding + + Oracle Linux 9 + + + Ensure 'X11Forwarding' is configured with value 'yes' in /etc/ssh/sshd_config + + + + + + + + + + + + + + + + + + + + + + sshd_includes_config_files + + Oracle Linux 9 + + + Check presence of Include /etc/ssh/sshd_config.d/*.conf in /etc/ssh/sshd_config + + + + + + + + Enable SSH Print Last Log + + Oracle Linux 9 + + + Ensure 'PrintLastLog' is configured with value 'yes' in /etc/ssh/sshd_config + + + + + + + + + + + + + + + + + + + + + + Set SSH Client Alive Count Max + + Oracle Linux 9 + + + Ensure 'ClientAliveCountMax' is configured with value configured in var_sshd_set_keepalive variable in /etc/ssh/sshd_config + + + + + + + + + + + + + + + + + + + + + + Set SSH Client Alive Count Max to zero + + Oracle Linux 9 + + + Ensure 'ClientAliveCountMax' is configured with value '0' in /etc/ssh/sshd_config + + + + + + + + + + + + + + + + + + + + + + Set LogLevel to INFO + + Oracle Linux 9 + + + Ensure 'LogLevel' is configured with value 'INFO' in /etc/ssh/sshd_config + + + + + + + + + + + + + + + + + + + + + + Set SSH Daemon LogLevel to VERBOSE + + Oracle Linux 9 + + + Ensure 'LogLevel' is configured with value 'VERBOSE' in /etc/ssh/sshd_config + + + + + + + + + + + + + + + + + + + + + + Enable Use of Privilege Separation + + Oracle Linux 9 + + + Ensure 'UsePrivilegeSeparation' is configured with value configured in var_sshd_priv_separation variable in /etc/ssh/sshd_config + + + + + + + + + + + + + + + + + + + + + + Prevent remote hosts from connecting to the proxy display + + Oracle Linux 9 + + + Ensure 'X11UseLocalhost' is configured with value 'yes' in /etc/ssh/sshd_config + + + + + + + + + + + + + + + + + + + + + + Enable Certmap in SSSD + + Oracle Linux 9 + + + Check presence of \[certmap\/.+\/.+\] in /etc/sssd/sssd.conf + + + + + + + + Ensure Privileged Escalated Commands Cannot Execute Other Commands - sudo NOEXEC + + Oracle Linux 9 + + + Checks sudoers Defaults {{ OPTION }} configuration + + + + + + + + Ensure Only Users Logged In To Real tty Can Execute Sudo - sudo requiretty + + Oracle Linux 9 + + + Checks sudoers Defaults {{ OPTION }} configuration + + + + + + + + Ensure Only Users Logged In To Real tty Can Execute Sudo - sudo use_pty + + Oracle Linux 9 + + + Checks sudoers Defaults {{ OPTION }} configuration + + + + + + + + Ensure Sudo Logfile Exists - sudo logfile + + Oracle Linux 9 + + + Checks sudoers Defaults {{ OPTION }} configuration + + + + + + + + Enable Kernel Parameter to Enforce DAC on FIFOs + + Oracle Linux 9 + + + The 'fs.protected_fifos' kernel parameter should be set to the appropriate value in system configuration and system runtime. + + + + + + + + + Enable Kernel Parameter to Enforce DAC on FIFOs + + Oracle Linux 9 + + + The kernel 'fs.protected_fifos' parameter should be set to 2 in the system runtime. + + + + + + + + Enable Kernel Parameter to Enforce DAC on FIFOs + + Oracle Linux 9 + + + The kernel 'fs.protected_fifos' parameter should be set to 2 in the system configuration. + + + + + + + + + + + + Enable Kernel Parameter to Enforce DAC on Hardlinks + + Oracle Linux 9 + + + The 'fs.protected_hardlinks' kernel parameter should be set to the appropriate value in system configuration and system runtime. + + + + + + + + + Enable Kernel Parameter to Enforce DAC on Hardlinks + + Oracle Linux 9 + + + The kernel 'fs.protected_hardlinks' parameter should be set to 1 in the system runtime. + + + + + + + + Enable Kernel Parameter to Enforce DAC on Hardlinks + + Oracle Linux 9 + + + The kernel 'fs.protected_hardlinks' parameter should be set to 1 in the system configuration. + + + + + + + + + + + + Enable Kernel Parameter to Enforce DAC on Regular files + + Oracle Linux 9 + + + The 'fs.protected_regular' kernel parameter should be set to the appropriate value in system configuration and system runtime. + + + + + + + + + Enable Kernel Parameter to Enforce DAC on Regular files + + Oracle Linux 9 + + + The kernel 'fs.protected_regular' parameter should be set to 2 in the system runtime. + + + + + + + + Enable Kernel Parameter to Enforce DAC on Regular files + + Oracle Linux 9 + + + The kernel 'fs.protected_regular' parameter should be set to 2 in the system configuration. + + + + + + + + + + + + Enable Kernel Parameter to Enforce DAC on Symlinks + + Oracle Linux 9 + + + The 'fs.protected_symlinks' kernel parameter should be set to the appropriate value in system configuration and system runtime. + + + + + + + + + Enable Kernel Parameter to Enforce DAC on Symlinks + + Oracle Linux 9 + + + The kernel 'fs.protected_symlinks' parameter should be set to 1 in the system runtime. + + + + + + + + Enable Kernel Parameter to Enforce DAC on Symlinks + + Oracle Linux 9 + + + The kernel 'fs.protected_symlinks' parameter should be set to 1 in the system configuration. + + + + + + + + + + + + Disable Core Dumps for SUID programs + + Oracle Linux 9 + + + The 'fs.suid_dumpable' kernel parameter should be set to the appropriate value in system configuration and system runtime. + + + + + + + + + Disable Core Dumps for SUID programs + + Oracle Linux 9 + + + The kernel 'fs.suid_dumpable' parameter should be set to 0 in the system runtime. + + + + + + + + Disable Core Dumps for SUID programs + + Oracle Linux 9 + + + The kernel 'fs.suid_dumpable' parameter should be set to 0 in the system configuration. + + + + + + + + + + + + Disable storing core dumps + + Oracle Linux 9 + + + The 'kernel.core_pattern' kernel parameter should be set to the appropriate value in system configuration and system runtime. + + + + + + + + + Disable storing core dumps + + Oracle Linux 9 + + + The kernel 'kernel.core_pattern' parameter should be set to |/bin/false in the system runtime. + + + + + + + + Disable storing core dumps + + Oracle Linux 9 + + + The kernel 'kernel.core_pattern' parameter should be set to |/bin/false in the system configuration. + + + + + + + + + + + + Configure file name of core dumps + + Oracle Linux 9 + + + The 'kernel.core_uses_pid' kernel parameter should be set to the appropriate value in system configuration and system runtime. + + + + + + + + + Configure file name of core dumps + + Oracle Linux 9 + + + The kernel 'kernel.core_uses_pid' parameter should be set to 0 in the system runtime. + + + + + + + + Configure file name of core dumps + + Oracle Linux 9 + + + The kernel 'kernel.core_uses_pid' parameter should be set to 0 in the system configuration. + + + + + + + + + + + + Restrict Access to Kernel Message Buffer + + Oracle Linux 9 + + + The 'kernel.dmesg_restrict' kernel parameter should be set to the appropriate value in system configuration and system runtime. + + + + + + + + + Restrict Access to Kernel Message Buffer + + Oracle Linux 9 + + + The kernel 'kernel.dmesg_restrict' parameter should be set to 1 in the system runtime. + + + + + + + + Restrict Access to Kernel Message Buffer + + Oracle Linux 9 + + + The kernel 'kernel.dmesg_restrict' parameter should be set to 1 in the system configuration. + + + + + + + + + + + + Disable Kernel Image Loading + + Oracle Linux 9 + + + The 'kernel.kexec_load_disabled' kernel parameter should be set to the appropriate value in system configuration and system runtime. + + + + + + + + + Disable Kernel Image Loading + + Oracle Linux 9 + + + The kernel 'kernel.kexec_load_disabled' parameter should be set to 1 in the system runtime. + + + + + + + + Disable Kernel Image Loading + + Oracle Linux 9 + + + The kernel 'kernel.kexec_load_disabled' parameter should be set to 1 in the system configuration. + + + + + + + + + + + + Restrict Exposed Kernel Pointer Addresses Access + + Oracle Linux 9 + + + The 'kernel.kptr_restrict' kernel parameter should be set to the appropriate value in system configuration and system runtime. + + + + + + + + + Restrict Exposed Kernel Pointer Addresses Access + + Oracle Linux 9 + + + The kernel 'kernel.kptr_restrict' parameter should be set to 1 or 2 in the system runtime. + + + + + + + + Restrict Exposed Kernel Pointer Addresses Access + + Oracle Linux 9 + + + The kernel 'kernel.kptr_restrict' parameter should be set to 1 or 2 in the system configuration. + + + + + + + + + + + + Disable loading and unloading of kernel modules + + Oracle Linux 9 + + + The 'kernel.modules_disabled' kernel parameter should be set to the appropriate value in system configuration and system runtime. + + + + + + + + + Disable loading and unloading of kernel modules + + Oracle Linux 9 + + + The kernel 'kernel.modules_disabled' parameter should be set to 1 in the system runtime. + + + + + + + + Disable loading and unloading of kernel modules + + Oracle Linux 9 + + + The kernel 'kernel.modules_disabled' parameter should be set to 1 in the system configuration. + + + + + + + + + + + + Kernel panic on oops + + Oracle Linux 9 + + + The 'kernel.panic_on_oops' kernel parameter should be set to the appropriate value in system configuration and system runtime. + + + + + + + + + Kernel panic on oops + + Oracle Linux 9 + + + The kernel 'kernel.panic_on_oops' parameter should be set to 1 in the system runtime. + + + + + + + + Kernel panic on oops + + Oracle Linux 9 + + + The kernel 'kernel.panic_on_oops' parameter should be set to 1 in the system configuration. + + + + + + + + + + + + Limit CPU consumption of the Perf system + + Oracle Linux 9 + + + The 'kernel.perf_cpu_time_max_percent' kernel parameter should be set to the appropriate value in system configuration and system runtime. + + + + + + + + + Limit CPU consumption of the Perf system + + Oracle Linux 9 + + + The kernel 'kernel.perf_cpu_time_max_percent' parameter should be set to 1 in the system runtime. + + + + + + + + Limit CPU consumption of the Perf system + + Oracle Linux 9 + + + The kernel 'kernel.perf_cpu_time_max_percent' parameter should be set to 1 in the system configuration. + + + + + + + + + + + + Limit sampling frequency of the Perf system + + Oracle Linux 9 + + + The 'kernel.perf_event_max_sample_rate' kernel parameter should be set to the appropriate value in system configuration and system runtime. + + + + + + + + + Limit sampling frequency of the Perf system + + Oracle Linux 9 + + + The kernel 'kernel.perf_event_max_sample_rate' parameter should be set to 1 in the system runtime. + + + + + + + + Limit sampling frequency of the Perf system + + Oracle Linux 9 + + + The kernel 'kernel.perf_event_max_sample_rate' parameter should be set to 1 in the system configuration. + + + + + + + + + + + + Disallow kernel profiling by unprivileged users + + Oracle Linux 9 + + + The 'kernel.perf_event_paranoid' kernel parameter should be set to the appropriate value in system configuration and system runtime. + + + + + + + + + Disallow kernel profiling by unprivileged users + + Oracle Linux 9 + + + The kernel 'kernel.perf_event_paranoid' parameter should be set to 2 in the system runtime. + + + + + + + + Disallow kernel profiling by unprivileged users + + Oracle Linux 9 + + + The kernel 'kernel.perf_event_paranoid' parameter should be set to 2 in the system configuration. + + + + + + + + + + + + Configure maximum number of process identifiers + + Oracle Linux 9 + + + The 'kernel.pid_max' kernel parameter should be set to the appropriate value in system configuration and system runtime. + + + + + + + + + Configure maximum number of process identifiers + + Oracle Linux 9 + + + The kernel 'kernel.pid_max' parameter should be set to 65536 in the system runtime. + + + + + + + + Configure maximum number of process identifiers + + Oracle Linux 9 + + + The kernel 'kernel.pid_max' parameter should be set to 65536 in the system configuration. + + + + + + + + + + + + Enable Randomized Layout of Virtual Address Space + + Oracle Linux 9 + + + The 'kernel.randomize_va_space' kernel parameter should be set to the appropriate value in system configuration and system runtime. + + + + + + + + + Enable Randomized Layout of Virtual Address Space + + Oracle Linux 9 + + + The kernel 'kernel.randomize_va_space' parameter should be set to 2 in the system runtime. + + + + + + + + Enable Randomized Layout of Virtual Address Space + + Oracle Linux 9 + + + The kernel 'kernel.randomize_va_space' parameter should be set to 2 in the system configuration. + + + + + + + + + + + + Disallow magic SysRq key + + Oracle Linux 9 + + + The 'kernel.sysrq' kernel parameter should be set to the appropriate value in system configuration and system runtime. + + + + + + + + + Disallow magic SysRq key + + Oracle Linux 9 + + + The kernel 'kernel.sysrq' parameter should be set to 0 in the system runtime. + + + + + + + + Disallow magic SysRq key + + Oracle Linux 9 + + + The kernel 'kernel.sysrq' parameter should be set to 0 in the system configuration. + + + + + + + + + + + + Disable Access to Network bpf() Syscall From Unprivileged Processes + + Oracle Linux 9 + + + The 'kernel.unprivileged_bpf_disabled' kernel parameter should be set to the appropriate value in system configuration and system runtime. + + + + + + + + + Disable Access to Network bpf() Syscall From Unprivileged Processes + + Oracle Linux 9 + + + The kernel 'kernel.unprivileged_bpf_disabled' parameter should be set to 1 in the system runtime. + + + + + + + + Disable Access to Network bpf() Syscall From Unprivileged Processes + + Oracle Linux 9 + + + The kernel 'kernel.unprivileged_bpf_disabled' parameter should be set to 1 in the system configuration. + + + + + + + + + + + + Disable Access to Network bpf() Syscall From Unprivileged Processes + + Oracle Linux 9 + + + The 'kernel.unprivileged_bpf_disabled' kernel parameter should be set to the appropriate value in system configuration and system runtime. + + + + + + + + + Disable Access to Network bpf() Syscall From Unprivileged Processes + + Oracle Linux 9 + + + The kernel 'kernel.unprivileged_bpf_disabled' parameter should be set to 1 or 2 in the system runtime. + + + + + + + + Disable Access to Network bpf() Syscall From Unprivileged Processes + + Oracle Linux 9 + + + The kernel 'kernel.unprivileged_bpf_disabled' parameter should be set to 1 or 2 in the system configuration. + + + + + + + + + + + + Restrict usage of ptrace to descendant processes + + Oracle Linux 9 + + + The 'kernel.yama.ptrace_scope' kernel parameter should be set to the appropriate value in system configuration and system runtime. + + + + + + + + + Restrict usage of ptrace to descendant processes + + Oracle Linux 9 + + + The kernel 'kernel.yama.ptrace_scope' parameter should be set to 1 in the system runtime. + + + + + + + + Restrict usage of ptrace to descendant processes + + Oracle Linux 9 + + + The kernel 'kernel.yama.ptrace_scope' parameter should be set to 1 in the system configuration. + + + + + + + + + + + + Harden the operation of the BPF just-in-time compiler + + Oracle Linux 9 + + + The 'net.core.bpf_jit_harden' kernel parameter should be set to the appropriate value in system configuration and system runtime. + + + + + + + + + Harden the operation of the BPF just-in-time compiler + + Oracle Linux 9 + + + The kernel 'net.core.bpf_jit_harden' parameter should be set to 2 in the system runtime. + + + + + + + + Harden the operation of the BPF just-in-time compiler + + Oracle Linux 9 + + + The kernel 'net.core.bpf_jit_harden' parameter should be set to 2 in the system configuration. + + + + + + + + + + + + Disable Accepting Packets Routed Between Local Interfaces + + Oracle Linux 9 + + + The 'net.ipv4.conf.all.accept_local' kernel parameter should be set to the appropriate value in system configuration and system runtime. + + + + + + + + + Disable Accepting Packets Routed Between Local Interfaces + + Oracle Linux 9 + + + The kernel 'net.ipv4.conf.all.accept_local' parameter should be set to 0 in the system runtime. + + + + + + + + Disable Accepting Packets Routed Between Local Interfaces + + Oracle Linux 9 + + + The kernel 'net.ipv4.conf.all.accept_local' parameter should be set to 0 in the system configuration. + + + + + + + + + + + + Disable Accepting ICMP Redirects for All IPv4 Interfaces + + Oracle Linux 9 + + + The 'net.ipv4.conf.all.accept_redirects' kernel parameter should be set to the appropriate value in system configuration and system runtime. + + + + + + + + + Disable Accepting ICMP Redirects for All IPv4 Interfaces + + Oracle Linux 9 + + + The kernel 'net.ipv4.conf.all.accept_redirects' parameter should be set to the appropriate value in the system runtime. + + + + + + + + Disable Accepting ICMP Redirects for All IPv4 Interfaces + + Oracle Linux 9 + + + The kernel 'net.ipv4.conf.all.accept_redirects' parameter should be set to the appropriate value in the system configuration. + + + + + + + + + + + + Disable Kernel Parameter for Accepting Source-Routed Packets on all IPv4 Interfaces + + Oracle Linux 9 + + + The 'net.ipv4.conf.all.accept_source_route' kernel parameter should be set to the appropriate value in system configuration and system runtime. + + + + + + + + + Disable Kernel Parameter for Accepting Source-Routed Packets on all IPv4 Interfaces + + Oracle Linux 9 + + + The kernel 'net.ipv4.conf.all.accept_source_route' parameter should be set to the appropriate value in the system runtime. + + + + + + + + Disable Kernel Parameter for Accepting Source-Routed Packets on all IPv4 Interfaces + + Oracle Linux 9 + + + The kernel 'net.ipv4.conf.all.accept_source_route' parameter should be set to the appropriate value in the system configuration. + + + + + + + + + + + + Configure ARP filtering for All IPv4 Interfaces + + Oracle Linux 9 + + + The 'net.ipv4.conf.all.arp_filter' kernel parameter should be set to the appropriate value in system configuration and system runtime. + + + + + + + + + Configure ARP filtering for All IPv4 Interfaces + + Oracle Linux 9 + + + The kernel 'net.ipv4.conf.all.arp_filter' parameter should be set to the appropriate value in the system runtime. + + + + + + + + Configure ARP filtering for All IPv4 Interfaces + + Oracle Linux 9 + + + The kernel 'net.ipv4.conf.all.arp_filter' parameter should be set to the appropriate value in the system configuration. + + + + + + + + + + + + Configure Response Mode of ARP Requests for All IPv4 Interfaces + + Oracle Linux 9 + + + The 'net.ipv4.conf.all.arp_ignore' kernel parameter should be set to the appropriate value in system configuration and system runtime. + + + + + + + + + Configure Response Mode of ARP Requests for All IPv4 Interfaces + + Oracle Linux 9 + + + The kernel 'net.ipv4.conf.all.arp_ignore' parameter should be set to the appropriate value in the system runtime. + + + + + + + + Configure Response Mode of ARP Requests for All IPv4 Interfaces + + Oracle Linux 9 + + + The kernel 'net.ipv4.conf.all.arp_ignore' parameter should be set to the appropriate value in the system configuration. + + + + + + + + + + + + Drop Gratuitious ARP frames on All IPv4 Interfaces + + Oracle Linux 9 + + + The 'net.ipv4.conf.all.drop_gratuitous_arp' kernel parameter should be set to the appropriate value in system configuration and system runtime. + + + + + + + + + Drop Gratuitious ARP frames on All IPv4 Interfaces + + Oracle Linux 9 + + + The kernel 'net.ipv4.conf.all.drop_gratuitous_arp' parameter should be set to 1 in the system runtime. + + + + + + + + Drop Gratuitious ARP frames on All IPv4 Interfaces + + Oracle Linux 9 + + + The kernel 'net.ipv4.conf.all.drop_gratuitous_arp' parameter should be set to 1 in the system configuration. + + + + + + + + + + + + Disable Kernel Parameter for IPv4 Forwarding on all IPv4 Interfaces + + Oracle Linux 9 + + + The 'net.ipv4.conf.all.forwarding' kernel parameter should be set to the appropriate value in system configuration and system runtime. + + + + + + + + + Disable Kernel Parameter for IPv4 Forwarding on all IPv4 Interfaces + + Oracle Linux 9 + + + The kernel 'net.ipv4.conf.all.forwarding' parameter should be set to the appropriate value in the system runtime. + + + + + + + + Disable Kernel Parameter for IPv4 Forwarding on all IPv4 Interfaces + + Oracle Linux 9 + + + The kernel 'net.ipv4.conf.all.forwarding' parameter should be set to the appropriate value in the system configuration. + + + + + + + + + + + + Enable Kernel Parameter to Log Martian Packets on all IPv4 Interfaces + + Oracle Linux 9 + + + The 'net.ipv4.conf.all.log_martians' kernel parameter should be set to the appropriate value in system configuration and system runtime. + + + + + + + + + Enable Kernel Parameter to Log Martian Packets on all IPv4 Interfaces + + Oracle Linux 9 + + + The kernel 'net.ipv4.conf.all.log_martians' parameter should be set to the appropriate value in the system runtime. + + + + + + + + Enable Kernel Parameter to Log Martian Packets on all IPv4 Interfaces + + Oracle Linux 9 + + + The kernel 'net.ipv4.conf.all.log_martians' parameter should be set to the appropriate value in the system configuration. + + + + + + + + + + + + Prevent Routing External Traffic to Local Loopback on All IPv4 Interfaces + + Oracle Linux 9 + + + The 'net.ipv4.conf.all.route_localnet' kernel parameter should be set to the appropriate value in system configuration and system runtime. + + + + + + + + + Prevent Routing External Traffic to Local Loopback on All IPv4 Interfaces + + Oracle Linux 9 + + + The kernel 'net.ipv4.conf.all.route_localnet' parameter should be set to 0 in the system runtime. + + + + + + + + Prevent Routing External Traffic to Local Loopback on All IPv4 Interfaces + + Oracle Linux 9 + + + The kernel 'net.ipv4.conf.all.route_localnet' parameter should be set to 0 in the system configuration. + + + + + + + + + + + + Enable Kernel Parameter to Use Reverse Path Filtering on all IPv4 Interfaces + + Oracle Linux 9 + + + The 'net.ipv4.conf.all.rp_filter' kernel parameter should be set to the appropriate value in system configuration and system runtime. + + + + + + + + + Enable Kernel Parameter to Use Reverse Path Filtering on all IPv4 Interfaces + + Oracle Linux 9 + + + The kernel 'net.ipv4.conf.all.rp_filter' parameter should be set to 1 or 2 in the system runtime. + + + + + + + + Enable Kernel Parameter to Use Reverse Path Filtering on all IPv4 Interfaces + + Oracle Linux 9 + + + The kernel 'net.ipv4.conf.all.rp_filter' parameter should be set to 1 or 2 in the system configuration. + + + + + + + + + + + + Disable Kernel Parameter for Accepting Secure ICMP Redirects on all IPv4 Interfaces + + Oracle Linux 9 + + + The 'net.ipv4.conf.all.secure_redirects' kernel parameter should be set to the appropriate value in system configuration and system runtime. + + + + + + + + + Disable Kernel Parameter for Accepting Secure ICMP Redirects on all IPv4 Interfaces + + Oracle Linux 9 + + + The kernel 'net.ipv4.conf.all.secure_redirects' parameter should be set to the appropriate value in the system runtime. + + + + + + + + Disable Kernel Parameter for Accepting Secure ICMP Redirects on all IPv4 Interfaces + + Oracle Linux 9 + + + The kernel 'net.ipv4.conf.all.secure_redirects' parameter should be set to the appropriate value in the system configuration. + + + + + + + + + + + + Disable Kernel Parameter for Sending ICMP Redirects on all IPv4 Interfaces + + Oracle Linux 9 + + + The 'net.ipv4.conf.all.send_redirects' kernel parameter should be set to the appropriate value in system configuration and system runtime. + + + + + + + + + Disable Kernel Parameter for Sending ICMP Redirects on all IPv4 Interfaces + + Oracle Linux 9 + + + The kernel 'net.ipv4.conf.all.send_redirects' parameter should be set to 0 in the system runtime. + + + + + + + + Disable Kernel Parameter for Sending ICMP Redirects on all IPv4 Interfaces + + Oracle Linux 9 + + + The kernel 'net.ipv4.conf.all.send_redirects' parameter should be set to 0 in the system configuration. + + + + + + + + + + + + Configure Sending and Accepting Shared Media Redirects for All IPv4 Interfaces + + Oracle Linux 9 + + + The 'net.ipv4.conf.all.shared_media' kernel parameter should be set to the appropriate value in system configuration and system runtime. + + + + + + + + + Configure Sending and Accepting Shared Media Redirects for All IPv4 Interfaces + + Oracle Linux 9 + + + The kernel 'net.ipv4.conf.all.shared_media' parameter should be set to the appropriate value in the system runtime. + + + + + + + + Configure Sending and Accepting Shared Media Redirects for All IPv4 Interfaces + + Oracle Linux 9 + + + The kernel 'net.ipv4.conf.all.shared_media' parameter should be set to the appropriate value in the system configuration. + + + + + + + + + + + + Disable Kernel Parameter for Accepting ICMP Redirects by Default on IPv4 Interfaces + + Oracle Linux 9 + + + The 'net.ipv4.conf.default.accept_redirects' kernel parameter should be set to the appropriate value in system configuration and system runtime. + + + + + + + + + Disable Kernel Parameter for Accepting ICMP Redirects by Default on IPv4 Interfaces + + Oracle Linux 9 + + + The kernel 'net.ipv4.conf.default.accept_redirects' parameter should be set to the appropriate value in the system runtime. + + + + + + + + Disable Kernel Parameter for Accepting ICMP Redirects by Default on IPv4 Interfaces + + Oracle Linux 9 + + + The kernel 'net.ipv4.conf.default.accept_redirects' parameter should be set to the appropriate value in the system configuration. + + + + + + + + + + + + Disable Kernel Parameter for Accepting Source-Routed Packets on IPv4 Interfaces by Default + + Oracle Linux 9 + + + The 'net.ipv4.conf.default.accept_source_route' kernel parameter should be set to the appropriate value in system configuration and system runtime. + + + + + + + + + Disable Kernel Parameter for Accepting Source-Routed Packets on IPv4 Interfaces by Default + + Oracle Linux 9 + + + The kernel 'net.ipv4.conf.default.accept_source_route' parameter should be set to the appropriate value in the system runtime. + + + + + + + + Disable Kernel Parameter for Accepting Source-Routed Packets on IPv4 Interfaces by Default + + Oracle Linux 9 + + + The kernel 'net.ipv4.conf.default.accept_source_route' parameter should be set to the appropriate value in the system configuration. + + + + + + + + + + + + Enable Kernel Paremeter to Log Martian Packets on all IPv4 Interfaces by Default + + Oracle Linux 9 + + + The 'net.ipv4.conf.default.log_martians' kernel parameter should be set to the appropriate value in system configuration and system runtime. + + + + + + + + + Enable Kernel Paremeter to Log Martian Packets on all IPv4 Interfaces by Default + + Oracle Linux 9 + + + The kernel 'net.ipv4.conf.default.log_martians' parameter should be set to the appropriate value in the system runtime. + + + + + + + + Enable Kernel Paremeter to Log Martian Packets on all IPv4 Interfaces by Default + + Oracle Linux 9 + + + The kernel 'net.ipv4.conf.default.log_martians' parameter should be set to the appropriate value in the system configuration. + + + + + + + + + + + + Enable Kernel Parameter to Use Reverse Path Filtering on all IPv4 Interfaces by Default + + Oracle Linux 9 + + + The 'net.ipv4.conf.default.rp_filter' kernel parameter should be set to the appropriate value in system configuration and system runtime. + + + + + + + + + Enable Kernel Parameter to Use Reverse Path Filtering on all IPv4 Interfaces by Default + + Oracle Linux 9 + + + The kernel 'net.ipv4.conf.default.rp_filter' parameter should be set to the appropriate value in the system runtime. + + + + + + + + Enable Kernel Parameter to Use Reverse Path Filtering on all IPv4 Interfaces by Default + + Oracle Linux 9 + + + The kernel 'net.ipv4.conf.default.rp_filter' parameter should be set to the appropriate value in the system configuration. + + + + + + + + + + + + Configure Kernel Parameter for Accepting Secure Redirects By Default + + Oracle Linux 9 + + + The 'net.ipv4.conf.default.secure_redirects' kernel parameter should be set to the appropriate value in system configuration and system runtime. + + + + + + + + + Configure Kernel Parameter for Accepting Secure Redirects By Default + + Oracle Linux 9 + + + The kernel 'net.ipv4.conf.default.secure_redirects' parameter should be set to the appropriate value in the system runtime. + + + + + + + + Configure Kernel Parameter for Accepting Secure Redirects By Default + + Oracle Linux 9 + + + The kernel 'net.ipv4.conf.default.secure_redirects' parameter should be set to the appropriate value in the system configuration. + + + + + + + + + + + + Disable Kernel Parameter for Sending ICMP Redirects on all IPv4 Interfaces by Default + + Oracle Linux 9 + + + The 'net.ipv4.conf.default.send_redirects' kernel parameter should be set to the appropriate value in system configuration and system runtime. + + + + + + + + + Disable Kernel Parameter for Sending ICMP Redirects on all IPv4 Interfaces by Default + + Oracle Linux 9 + + + The kernel 'net.ipv4.conf.default.send_redirects' parameter should be set to 0 in the system runtime. + + + + + + + + Disable Kernel Parameter for Sending ICMP Redirects on all IPv4 Interfaces by Default + + Oracle Linux 9 + + + The kernel 'net.ipv4.conf.default.send_redirects' parameter should be set to 0 in the system configuration. + + + + + + + + + + + + Configure Sending and Accepting Shared Media Redirects by Default + + Oracle Linux 9 + + + The 'net.ipv4.conf.default.shared_media' kernel parameter should be set to the appropriate value in system configuration and system runtime. + + + + + + + + + Configure Sending and Accepting Shared Media Redirects by Default + + Oracle Linux 9 + + + The kernel 'net.ipv4.conf.default.shared_media' parameter should be set to the appropriate value in the system runtime. + + + + + + + + Configure Sending and Accepting Shared Media Redirects by Default + + Oracle Linux 9 + + + The kernel 'net.ipv4.conf.default.shared_media' parameter should be set to the appropriate value in the system configuration. + + + + + + + + + + + + Enable Kernel Parameter to Ignore ICMP Broadcast Echo Requests on IPv4 Interfaces + + Oracle Linux 9 + + + The 'net.ipv4.icmp_echo_ignore_broadcasts' kernel parameter should be set to the appropriate value in system configuration and system runtime. + + + + + + + + + Enable Kernel Parameter to Ignore ICMP Broadcast Echo Requests on IPv4 Interfaces + + Oracle Linux 9 + + + The kernel 'net.ipv4.icmp_echo_ignore_broadcasts' parameter should be set to the appropriate value in the system runtime. + + + + + + + + Enable Kernel Parameter to Ignore ICMP Broadcast Echo Requests on IPv4 Interfaces + + Oracle Linux 9 + + + The kernel 'net.ipv4.icmp_echo_ignore_broadcasts' parameter should be set to the appropriate value in the system configuration. + + + + + + + + + + + + Enable Kernel Parameter to Ignore Bogus ICMP Error Responses on IPv4 Interfaces + + Oracle Linux 9 + + + The 'net.ipv4.icmp_ignore_bogus_error_responses' kernel parameter should be set to the appropriate value in system configuration and system runtime. + + + + + + + + + Enable Kernel Parameter to Ignore Bogus ICMP Error Responses on IPv4 Interfaces + + Oracle Linux 9 + + + The kernel 'net.ipv4.icmp_ignore_bogus_error_responses' parameter should be set to the appropriate value in the system runtime. + + + + + + + + Enable Kernel Parameter to Ignore Bogus ICMP Error Responses on IPv4 Interfaces + + Oracle Linux 9 + + + The kernel 'net.ipv4.icmp_ignore_bogus_error_responses' parameter should be set to the appropriate value in the system configuration. + + + + + + + + + + + + Disable Kernel Parameter for IP Forwarding on IPv4 Interfaces + + Oracle Linux 9 + + + The 'net.ipv4.ip_forward' kernel parameter should be set to the appropriate value in system configuration and system runtime. + + + + + + + + + Disable Kernel Parameter for IP Forwarding on IPv4 Interfaces + + Oracle Linux 9 + + + The kernel 'net.ipv4.ip_forward' parameter should be set to 0 in the system runtime. + + + + + + + + Disable Kernel Parameter for IP Forwarding on IPv4 Interfaces + + Oracle Linux 9 + + + The kernel 'net.ipv4.ip_forward' parameter should be set to 0 in the system configuration. + + + + + + + + + + + + Set Kernel Parameter to Increase Local Port Range + + Oracle Linux 9 + + + The 'net.ipv4.ip_local_port_range' kernel parameter should be set to the appropriate value in system configuration and system runtime. + + + + + + + + + Set Kernel Parameter to Increase Local Port Range + + Oracle Linux 9 + + + The kernel 'net.ipv4.ip_local_port_range' parameter should be set to 32768 65535 in the system runtime. + + + + + + + + Set Kernel Parameter to Increase Local Port Range + + Oracle Linux 9 + + + The kernel 'net.ipv4.ip_local_port_range' parameter should be set to 32768 65535 in the system configuration. + + + + + + + + + + + + Enable Kernel Parameter to Use TCP RFC 1337 on IPv4 Interfaces + + Oracle Linux 9 + + + The 'net.ipv4.tcp_rfc1337' kernel parameter should be set to the appropriate value in system configuration and system runtime. + + + + + + + + + Enable Kernel Parameter to Use TCP RFC 1337 on IPv4 Interfaces + + Oracle Linux 9 + + + The kernel 'net.ipv4.tcp_rfc1337' parameter should be set to the appropriate value in the system runtime. + + + + + + + + Enable Kernel Parameter to Use TCP RFC 1337 on IPv4 Interfaces + + Oracle Linux 9 + + + The kernel 'net.ipv4.tcp_rfc1337' parameter should be set to the appropriate value in the system configuration. + + + + + + + + + + + + Enable Kernel Parameter to Use TCP Syncookies on Network Interfaces + + Oracle Linux 9 + + + The 'net.ipv4.tcp_syncookies' kernel parameter should be set to the appropriate value in system configuration and system runtime. + + + + + + + + + Enable Kernel Parameter to Use TCP Syncookies on Network Interfaces + + Oracle Linux 9 + + + The kernel 'net.ipv4.tcp_syncookies' parameter should be set to the appropriate value in the system runtime. + + + + + + + + Enable Kernel Parameter to Use TCP Syncookies on Network Interfaces + + Oracle Linux 9 + + + The kernel 'net.ipv4.tcp_syncookies' parameter should be set to the appropriate value in the system configuration. + + + + + + + + + + + + Configure Accepting Router Advertisements on All IPv6 Interfaces + + Oracle Linux 9 + + + The kernel 'net.ipv6.conf.all.accept_ra' parameter should be set to the appropriate value in system configuration and system runtime. + + + + + + + + + + + + Configure Accepting Router Advertisements on All IPv6 Interfaces + + Oracle Linux 9 + + + The kernel 'net.ipv6.conf.all.accept_ra' parameter should be set to the appropriate value in the system runtime. + + + + + + + + Configure Accepting Router Advertisements on All IPv6 Interfaces + + Oracle Linux 9 + + + The kernel 'net.ipv6.conf.all.accept_ra' parameter should be set to the appropriate value in the system configuration. + + + + + + + + + + + + Configure Accepting Default Router in Router Advertisements on All IPv6 Interfaces + + Oracle Linux 9 + + + The kernel 'net.ipv6.conf.all.accept_ra_defrtr' parameter should be set to the appropriate value in system configuration and system runtime. + + + + + + + + + + + + Configure Accepting Default Router in Router Advertisements on All IPv6 Interfaces + + Oracle Linux 9 + + + The kernel 'net.ipv6.conf.all.accept_ra_defrtr' parameter should be set to the appropriate value in the system runtime. + + + + + + + + Configure Accepting Default Router in Router Advertisements on All IPv6 Interfaces + + Oracle Linux 9 + + + The kernel 'net.ipv6.conf.all.accept_ra_defrtr' parameter should be set to the appropriate value in the system configuration. + + + + + + + + + + + + Configure Accepting Prefix Information in Router Advertisements on All IPv6 Interfaces + + Oracle Linux 9 + + + The kernel 'net.ipv6.conf.all.accept_ra_pinfo' parameter should be set to the appropriate value in system configuration and system runtime. + + + + + + + + + + + + Configure Accepting Prefix Information in Router Advertisements on All IPv6 Interfaces + + Oracle Linux 9 + + + The kernel 'net.ipv6.conf.all.accept_ra_pinfo' parameter should be set to the appropriate value in the system runtime. + + + + + + + + Configure Accepting Prefix Information in Router Advertisements on All IPv6 Interfaces + + Oracle Linux 9 + + + The kernel 'net.ipv6.conf.all.accept_ra_pinfo' parameter should be set to the appropriate value in the system configuration. + + + + + + + + + + + + Configure Accepting Router Preference in Router Advertisements on All IPv6 Interfaces + + Oracle Linux 9 + + + The kernel 'net.ipv6.conf.all.accept_ra_rtr_pref' parameter should be set to the appropriate value in system configuration and system runtime. + + + + + + + + + + + + Configure Accepting Router Preference in Router Advertisements on All IPv6 Interfaces + + Oracle Linux 9 + + + The kernel 'net.ipv6.conf.all.accept_ra_rtr_pref' parameter should be set to the appropriate value in the system runtime. + + + + + + + + Configure Accepting Router Preference in Router Advertisements on All IPv6 Interfaces + + Oracle Linux 9 + + + The kernel 'net.ipv6.conf.all.accept_ra_rtr_pref' parameter should be set to the appropriate value in the system configuration. + + + + + + + + + + + + Disable Accepting ICMP Redirects for All IPv6 Interfaces + + Oracle Linux 9 + + + The kernel 'net.ipv6.conf.all.accept_redirects' parameter should be set to the appropriate value in system configuration and system runtime. + + + + + + + + + + + + Disable Accepting ICMP Redirects for All IPv6 Interfaces + + Oracle Linux 9 + + + The kernel 'net.ipv6.conf.all.accept_redirects' parameter should be set to the appropriate value in the system runtime. + + + + + + + + Disable Accepting ICMP Redirects for All IPv6 Interfaces + + Oracle Linux 9 + + + The kernel 'net.ipv6.conf.all.accept_redirects' parameter should be set to the appropriate value in the system configuration. + + + + + + + + + + + + Disable Kernel Parameter for Accepting Source-Routed Packets on all IPv6 Interfaces + + Oracle Linux 9 + + + The kernel 'net.ipv6.conf.all.accept_source_route' parameter should be set to the appropriate value in system configuration and system runtime. + + + + + + + + + + + + Disable Kernel Parameter for Accepting Source-Routed Packets on all IPv6 Interfaces + + Oracle Linux 9 + + + The kernel 'net.ipv6.conf.all.accept_source_route' parameter should be set to the appropriate value in the system runtime. + + + + + + + + Disable Kernel Parameter for Accepting Source-Routed Packets on all IPv6 Interfaces + + Oracle Linux 9 + + + The kernel 'net.ipv6.conf.all.accept_source_route' parameter should be set to the appropriate value in the system configuration. + + + + + + + + + + + + Configure Auto Configuration on All IPv6 Interfaces + + Oracle Linux 9 + + + The kernel 'net.ipv6.conf.all.autoconf' parameter should be set to the appropriate value in system configuration and system runtime. + + + + + + + + + + + + Configure Auto Configuration on All IPv6 Interfaces + + Oracle Linux 9 + + + The kernel 'net.ipv6.conf.all.autoconf' parameter should be set to the appropriate value in the system runtime. + + + + + + + + Configure Auto Configuration on All IPv6 Interfaces + + Oracle Linux 9 + + + The kernel 'net.ipv6.conf.all.autoconf' parameter should be set to the appropriate value in the system configuration. + + + + + + + + + + + + Disable IPv6 Addressing on All IPv6 Interfaces + + Oracle Linux 9 + + + The kernel 'net.ipv6.conf.all.disable_ipv6' parameter should be set to the appropriate value in system configuration and system runtime. + + + + + + + + + + + + Disable IPv6 Addressing on All IPv6 Interfaces + + Oracle Linux 9 + + + The kernel 'net.ipv6.conf.all.disable_ipv6' parameter should be set to 1 in the system runtime. + + + + + + + + Disable IPv6 Addressing on All IPv6 Interfaces + + Oracle Linux 9 + + + The kernel 'net.ipv6.conf.all.disable_ipv6' parameter should be set to 1 in the system configuration. + + + + + + + + + + + + Disable Kernel Parameter for IPv6 Forwarding + + Oracle Linux 9 + + + The kernel 'net.ipv6.conf.all.forwarding' parameter should be set to the appropriate value in system configuration and system runtime. + + + + + + + + + + + + Disable Kernel Parameter for IPv6 Forwarding + + Oracle Linux 9 + + + The kernel 'net.ipv6.conf.all.forwarding' parameter should be set to the appropriate value in the system runtime. + + + + + + + + Disable Kernel Parameter for IPv6 Forwarding + + Oracle Linux 9 + + + The kernel 'net.ipv6.conf.all.forwarding' parameter should be set to the appropriate value in the system configuration. + + + + + + + + + + + + Configure Maximum Number of Autoconfigured Addresses on All IPv6 Interfaces + + Oracle Linux 9 + + + The kernel 'net.ipv6.conf.all.max_addresses' parameter should be set to the appropriate value in system configuration and system runtime. + + + + + + + + + + + + Configure Maximum Number of Autoconfigured Addresses on All IPv6 Interfaces + + Oracle Linux 9 + + + The kernel 'net.ipv6.conf.all.max_addresses' parameter should be set to the appropriate value in the system runtime. + + + + + + + + Configure Maximum Number of Autoconfigured Addresses on All IPv6 Interfaces + + Oracle Linux 9 + + + The kernel 'net.ipv6.conf.all.max_addresses' parameter should be set to the appropriate value in the system configuration. + + + + + + + + + + + + Configure Denying Router Solicitations on All IPv6 Interfaces + + Oracle Linux 9 + + + The kernel 'net.ipv6.conf.all.router_solicitations' parameter should be set to the appropriate value in system configuration and system runtime. + + + + + + + + + + + + Configure Denying Router Solicitations on All IPv6 Interfaces + + Oracle Linux 9 + + + The kernel 'net.ipv6.conf.all.router_solicitations' parameter should be set to the appropriate value in the system runtime. + + + + + + + + Configure Denying Router Solicitations on All IPv6 Interfaces + + Oracle Linux 9 + + + The kernel 'net.ipv6.conf.all.router_solicitations' parameter should be set to the appropriate value in the system configuration. + + + + + + + + + + + + Disable Accepting Router Advertisements on all IPv6 Interfaces by Default + + Oracle Linux 9 + + + The kernel 'net.ipv6.conf.default.accept_ra' parameter should be set to the appropriate value in system configuration and system runtime. + + + + + + + + + + + + Disable Accepting Router Advertisements on all IPv6 Interfaces by Default + + Oracle Linux 9 + + + The kernel 'net.ipv6.conf.default.accept_ra' parameter should be set to the appropriate value in the system runtime. + + + + + + + + Disable Accepting Router Advertisements on all IPv6 Interfaces by Default + + Oracle Linux 9 + + + The kernel 'net.ipv6.conf.default.accept_ra' parameter should be set to the appropriate value in the system configuration. + + + + + + + + + + + + Configure Accepting Default Router in Router Advertisements on All IPv6 Interfaces By Default + + Oracle Linux 9 + + + The kernel 'net.ipv6.conf.default.accept_ra_defrtr' parameter should be set to the appropriate value in system configuration and system runtime. + + + + + + + + + + + + Configure Accepting Default Router in Router Advertisements on All IPv6 Interfaces By Default + + Oracle Linux 9 + + + The kernel 'net.ipv6.conf.default.accept_ra_defrtr' parameter should be set to the appropriate value in the system runtime. + + + + + + + + Configure Accepting Default Router in Router Advertisements on All IPv6 Interfaces By Default + + Oracle Linux 9 + + + The kernel 'net.ipv6.conf.default.accept_ra_defrtr' parameter should be set to the appropriate value in the system configuration. + + + + + + + + + + + + Configure Accepting Prefix Information in Router Advertisements on All IPv6 Interfaces By Default + + Oracle Linux 9 + + + The kernel 'net.ipv6.conf.default.accept_ra_pinfo' parameter should be set to the appropriate value in system configuration and system runtime. + + + + + + + + + + + + Configure Accepting Prefix Information in Router Advertisements on All IPv6 Interfaces By Default + + Oracle Linux 9 + + + The kernel 'net.ipv6.conf.default.accept_ra_pinfo' parameter should be set to the appropriate value in the system runtime. + + + + + + + + Configure Accepting Prefix Information in Router Advertisements on All IPv6 Interfaces By Default + + Oracle Linux 9 + + + The kernel 'net.ipv6.conf.default.accept_ra_pinfo' parameter should be set to the appropriate value in the system configuration. + + + + + + + + + + + + Configure Accepting Router Preference in Router Advertisements on All IPv6 Interfaces By Default + + Oracle Linux 9 + + + The kernel 'net.ipv6.conf.default.accept_ra_rtr_pref' parameter should be set to the appropriate value in system configuration and system runtime. + + + + + + + + + + + + Configure Accepting Router Preference in Router Advertisements on All IPv6 Interfaces By Default + + Oracle Linux 9 + + + The kernel 'net.ipv6.conf.default.accept_ra_rtr_pref' parameter should be set to the appropriate value in the system runtime. + + + + + + + + Configure Accepting Router Preference in Router Advertisements on All IPv6 Interfaces By Default + + Oracle Linux 9 + + + The kernel 'net.ipv6.conf.default.accept_ra_rtr_pref' parameter should be set to the appropriate value in the system configuration. + + + + + + + + + + + + Disable Kernel Parameter for Accepting ICMP Redirects by Default on IPv6 Interfaces + + Oracle Linux 9 + + + The kernel 'net.ipv6.conf.default.accept_redirects' parameter should be set to the appropriate value in system configuration and system runtime. + + + + + + + + + + + + Disable Kernel Parameter for Accepting ICMP Redirects by Default on IPv6 Interfaces + + Oracle Linux 9 + + + The kernel 'net.ipv6.conf.default.accept_redirects' parameter should be set to the appropriate value in the system runtime. + + + + + + + + Disable Kernel Parameter for Accepting ICMP Redirects by Default on IPv6 Interfaces + + Oracle Linux 9 + + + The kernel 'net.ipv6.conf.default.accept_redirects' parameter should be set to the appropriate value in the system configuration. + + + + + + + + + + + + Disable Kernel Parameter for Accepting Source-Routed Packets on IPv6 Interfaces by Default + + Oracle Linux 9 + + + The kernel 'net.ipv6.conf.default.accept_source_route' parameter should be set to the appropriate value in system configuration and system runtime. + + + + + + + + + + + + Disable Kernel Parameter for Accepting Source-Routed Packets on IPv6 Interfaces by Default + + Oracle Linux 9 + + + The kernel 'net.ipv6.conf.default.accept_source_route' parameter should be set to the appropriate value in the system runtime. + + + + + + + + Disable Kernel Parameter for Accepting Source-Routed Packets on IPv6 Interfaces by Default + + Oracle Linux 9 + + + The kernel 'net.ipv6.conf.default.accept_source_route' parameter should be set to the appropriate value in the system configuration. + + + + + + + + + + + + Configure Auto Configuration on All IPv6 Interfaces By Default + + Oracle Linux 9 + + + The kernel 'net.ipv6.conf.default.autoconf' parameter should be set to the appropriate value in system configuration and system runtime. + + + + + + + + + + + + Configure Auto Configuration on All IPv6 Interfaces By Default + + Oracle Linux 9 + + + The kernel 'net.ipv6.conf.default.autoconf' parameter should be set to the appropriate value in the system runtime. + + + + + + + + Configure Auto Configuration on All IPv6 Interfaces By Default + + Oracle Linux 9 + + + The kernel 'net.ipv6.conf.default.autoconf' parameter should be set to the appropriate value in the system configuration. + + + + + + + + + + + + Disable IPv6 Addressing on IPv6 Interfaces by Default + + Oracle Linux 9 + + + The kernel 'net.ipv6.conf.default.disable_ipv6' parameter should be set to the appropriate value in system configuration and system runtime. + + + + + + + + + + + + Disable IPv6 Addressing on IPv6 Interfaces by Default + + Oracle Linux 9 + + + The kernel 'net.ipv6.conf.default.disable_ipv6' parameter should be set to 1 in the system runtime. + + + + + + + + Disable IPv6 Addressing on IPv6 Interfaces by Default + + Oracle Linux 9 + + + The kernel 'net.ipv6.conf.default.disable_ipv6' parameter should be set to 1 in the system configuration. + + + + + + + + + + + + Configure Maximum Number of Autoconfigured Addresses on All IPv6 Interfaces By Default + + Oracle Linux 9 + + + The kernel 'net.ipv6.conf.default.max_addresses' parameter should be set to the appropriate value in system configuration and system runtime. + + + + + + + + + + + + Configure Maximum Number of Autoconfigured Addresses on All IPv6 Interfaces By Default + + Oracle Linux 9 + + + The kernel 'net.ipv6.conf.default.max_addresses' parameter should be set to the appropriate value in the system runtime. + + + + + + + + Configure Maximum Number of Autoconfigured Addresses on All IPv6 Interfaces By Default + + Oracle Linux 9 + + + The kernel 'net.ipv6.conf.default.max_addresses' parameter should be set to the appropriate value in the system configuration. + + + + + + + + + + + + Configure Denying Router Solicitations on All IPv6 Interfaces By Default + + Oracle Linux 9 + + + The kernel 'net.ipv6.conf.default.router_solicitations' parameter should be set to the appropriate value in system configuration and system runtime. + + + + + + + + + + + + Configure Denying Router Solicitations on All IPv6 Interfaces By Default + + Oracle Linux 9 + + + The kernel 'net.ipv6.conf.default.router_solicitations' parameter should be set to the appropriate value in the system runtime. + + + + + + + + Configure Denying Router Solicitations on All IPv6 Interfaces By Default + + Oracle Linux 9 + + + The kernel 'net.ipv6.conf.default.router_solicitations' parameter should be set to the appropriate value in the system configuration. + + + + + + + + + + + + Disable the use of user namespaces + + Oracle Linux 9 + + + The 'user.max_user_namespaces' kernel parameter should be set to the appropriate value in system configuration and system runtime. + + + + + + + + + Disable the use of user namespaces + + Oracle Linux 9 + + + The kernel 'user.max_user_namespaces' parameter should be set to 0 in the system runtime. + + + + + + + + Disable the use of user namespaces + + Oracle Linux 9 + + + The kernel 'user.max_user_namespaces' parameter should be set to 0 in the system configuration. + + + + + + + + + + + + Prevent applications from mapping low portion of virtual memory + + Oracle Linux 9 + + + The 'vm.mmap_min_addr' kernel parameter should be set to the appropriate value in system configuration and system runtime. + + + + + + + + + Prevent applications from mapping low portion of virtual memory + + Oracle Linux 9 + + + The kernel 'vm.mmap_min_addr' parameter should be set to 65536 in the system runtime. + + + + + + + + Prevent applications from mapping low portion of virtual memory + + Oracle Linux 9 + + + The kernel 'vm.mmap_min_addr' parameter should be set to 65536 in the system configuration. + + + + + + + + + + + + Ensure tmp.mount Unit Is Enabled + + Oracle Linux 9 + + + The tmp mount should be enabled if possible. + + + + + + + + + Enable dnf-automatic Timer + + Oracle Linux 9 + + + The dnf-automatic timer should be enabled if possible. + + + + + + + + + + + + Enable logrotate Timer + + Oracle Linux 9 + + + The logrotate timer should be enabled if possible. + + + + + + + + + + + + Check pam_pwquality Existence in system-auth + + Oracle Linux 9 + + + Check that pam_pwquality.so exists in system-auth + + + + + + + + Record Any Attempts to Run semanage + + Oracle Linux 9 + + + Test if auditctl is in use for audit rules. + + + + + + + + Record Any Attempts to Run semanage + + Oracle Linux 9 + + + Test if augenrules is enabled for audit rules. + + + + + + + + Record Events that Modify the System's Network Environment + + Oracle Linux 9 + + + The network environment should not be modified by anything other than + administrator action. Any change to network parameters should be audited. + + + + + + + + + + + + + + + + + + + + + + + Record Events that Modify the System's Network Environment + + Oracle Linux 9 + + + The network environment should not be modified by anything other than + administrator action. Any change to network parameters should be audited. + + + + + + + + + + + + + + + + + + + + + + + 'log_file' Not Set In /etc/audit/auditd.conf + + Oracle Linux 9 + + + Verify 'log_file' is not set in /etc/audit/auditd.conf. + + + + + + + + 'log_group' Not Set To 'root' In /etc/audit/auditd.conf + + Oracle Linux 9 + + + Verify 'log_group' is not set to 'root' in + /etc/audit/auditd.conf. + + + + + + + + + + + Oracle Linux 9 + + + Bootable container or bootc system + + + + + + + + + + + Verify GRUB_DISABLE_RECOVERY Set to true + + Oracle Linux 9 + + + GRUB_DISABLE_RECOVERY set to 'true' in + /etc/default/grub + + + + + + + + Specify Multiple Remote chronyd NTP Servers for Time Data + + Oracle Linux 9 + + + Multiple chronyd NTP Servers for time synchronization should be specified. + + + + + + + + Oracle Linux 7 + + Oracle Linux 9 + + + + The operating system installed on the system is + Oracle Linux 7 + + + + + + + + + + + Oracle Linux 8 + + Oracle Linux 9 + + + + The operating system installed on the system is + Oracle Linux 8 + + + + + + + + + + + Oracle Linux 9 + + Oracle Linux 9 + + + + The operating system installed on the system is + Oracle Linux 9 + + + + + + + + + + + Installed operating system is part of the Unix family + + Oracle Linux 9 + + + The operating system installed on the system is part of the Unix OS family + + + + + + + + Red Hat Enterprise Linux CoreOS + + Oracle Linux 9 + + + + The operating system installed on the system is + Red Hat Enterprise Linux CoreOS release 4 + + + + + + + + + + + Red Hat Enterprise Linux 8 + + Oracle Linux 9 + + + + The operating system installed on the system is + Red Hat Enterprise Linux 8 + + + + + + + + + + + + + + + + + + Red Hat Enterprise Linux 9 + + Oracle Linux 9 + + + + The operating system installed on the system is + Red Hat Enterprise Linux 9 + + + + + + + + + + + + + + + + + + SUSE Linux Enterprise 12 + + Oracle Linux 9 + + + + + The operating system installed on the system is + SUSE Linux Enterprise 12. + + + + + + + + + + + + + SUSE Linux Enterprise 15 + + Oracle Linux 9 + + + + + The operating system installed on the system is + SUSE Linux Enterprise 15. + + + + + + + + + + + + + + + SUSE Linux Enterprise Micro + + Oracle Linux 9 + + + + + + + The operating system installed on the system is + SUSE Linux Enterprise Micro. + + + + + + + + + + + + Ubuntu + + Oracle Linux 9 + + + The operating system installed is an Ubuntu System + + + + + + + + + + Ubuntu 16.04 LTS + + Oracle Linux 9 + + + + The operating system installed on the system is Ubuntu 16.04 LTS + + + + + + + + + Ubuntu 18.04 LTS + + Oracle Linux 9 + + + + The operating system installed on the system is Ubuntu 18.04 LTS + + + + + + + + + Ubuntu 20.04 LTS + + Oracle Linux 9 + + + + The operating system installed on the system is Ubuntu 20.04 LTS + + + + + + + + + No CD/DVD drive is configured to automount in /etc/fstab + + Oracle Linux 9 + + + Check the /etc/fstab and check if a CD/DVD drive + is not configured for automount. + + + + + + + + Device Files for Removable Media Partitions Does Not Exist on the System + + Oracle Linux 9 + + + Verify if device file representing removable partitions + exist on the system + + + + + + + + SSHD is not required to be installed or requirement not set + + Oracle Linux 9 + + + If SSHD is not required, we check it is not installed. If SSH requirement is unset, we are good. + + + + + + + + + SSHD is required to be installed or requirement not set + + Oracle Linux 9 + + + If SSHD is required, we check it is installed. If SSH requirement is unset, we are good. + + + + + + + + + It doesn't matter if sshd is installed or not + + Oracle Linux 9 + + + Test if value sshd_required is 0. + + + + + + + + Kernel Runtime Parameter IPv6 Check + + Oracle Linux 9 + + + Disables IPv6 for all network interfaces. + + + + + + + + + + + Test for 64-bit Architecture + + Oracle Linux 9 + + + Generic test for 64-bit architectures to be used by other tests + + + + + + + + + + + Test for aarch_64 Architecture + + Oracle Linux 9 + + + Generic test for aarch_64 architecture to be used by other tests + + + + + + + + Test for PPC and PPCLE Architecture + + Oracle Linux 9 + + + Generic test for PPC PPC64LE architecture to be used by other tests + + + + + + + + + Test for s390_64 Architecture + + Oracle Linux 9 + + + Generic test for s390_64 architecture to be used by other tests + + + + + + + + Test for x86 Architecture + + Oracle Linux 9 + + + Generic test for x86 architecture to be used by other tests + + + + + + + + Test for x86_64 Architecture + + Oracle Linux 9 + + + Generic test for x86_64 architecture to be used by other tests + + + + + + + + Check that file storing USBGuard rules exists and is not empty + + Oracle Linux 9 + + + Check that file storing USBGuard rules at /etc/usbguard/rules.conf exists and is not empty + + + + + + + + Value of 'var_accounts_user_umask' variable represented as octal number + + Oracle Linux 9 + + + Value of 'var_accounts_user_umask' variable represented as octal number + + + + + + + + Value of 'var_removable_partition' variable is set to '/dev/cdrom' + + Oracle Linux 9 + + + Verify if value of 'var_removable_partition' variable is set + to '/dev/cdrom' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ^/etc/audit/rules\.d/.*\.rules$ + ^\-e\s+2\s*$ + 1 + + + /etc/audit/audit.rules + ^\-e\s+2\s*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^\s*--loginuid-immutable\s*$ + 1 + + + /etc/audit/audit.rules + ^\s*--loginuid-immutable\s*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^\-w[\s]+/etc/selinux/[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + 1 + + + /etc/audit/audit.rules + ^\-w[\s]+/etc/selinux/[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^\-w[\s]+/usr/share/selinux/[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + 1 + + + /etc/audit/audit.rules + ^\-w[\s]+/usr/share/selinux/[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^\-w[\s]+/etc/issue[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^\-w[\s]+/etc/issue\.net[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^\-w[\s]+/etc/hosts[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^\-w[\s]+/etc/sysconfig/network[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + 1 + + + /etc/audit/audit.rules + ^\-w[\s]+/etc/issue[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + 1 + + + /etc/audit/audit.rules + ^\-w[\s]+/etc/issue\.net[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + 1 + + + /etc/audit/audit.rules + ^\-w[\s]+/etc/hosts[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + 1 + + + /etc/audit/audit.rules + ^\-w[\s]+/etc/sysconfig/network[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^\-w\s+/var/run/utmp\s+\-p\s+wa\b.*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^\-w\s+/var/log/btmp\s+\-p\s+wa\b.*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^\-w\s+/var/log/wtmp\s+\-p\s+wa\b.*$ + 1 + + + /etc/audit/audit.rules + ^\-w\s+/var/run/utmp\s+\-p\s+wa\b.*$ + 1 + + + /etc/audit/audit.rules + ^\-w\s+/var/log/btmp\s+\-p\s+wa\b.*$ + 1 + + + /etc/audit/audit.rules + ^\-w\s+/var/log/wtmp\s+\-p\s+wa\b.*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^\-w[\s]+/etc/sudoers[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + 1 + + + /etc/audit/audit.rules + ^\-w[\s]+/etc/sudoers[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^\-w[\s]+/etc/sudoers\.d/?[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + 1 + + + /etc/audit/audit.rules + ^\-w[\s]+/etc/sudoers\.d/?[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+arch=b32[\s]+-S[\s]+execve[\s]+-C[\s]+uid!=euid[\s]+-F[\s]+euid=0[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+arch=b64[\s]+-S[\s]+execve[\s]+-C[\s]+uid!=euid[\s]+-F[\s]+euid=0[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+arch=b32[\s]+-S[\s]+execve[\s]+-C[\s]+uid!=euid[\s]+-F[\s]+euid=0[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+arch=b64[\s]+-S[\s]+execve[\s]+-C[\s]+uid!=euid[\s]+-F[\s]+euid=0[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+arch=b32[\s]+-S[\s]+execve[\s]+-C[\s]+gid!=egid[\s]+-F[\s]+egid=0[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+arch=b64[\s]+-S[\s]+execve[\s]+-C[\s]+gid!=egid[\s]+-F[\s]+egid=0[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+arch=b32[\s]+-S[\s]+execve[\s]+-C[\s]+gid!=egid[\s]+-F[\s]+egid=0[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+arch=b64[\s]+-S[\s]+execve[\s]+-C[\s]+gid!=egid[\s]+-F[\s]+egid=0[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^\-w[\s]+/etc/sudoers[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^\-w[\s]+/etc/sudoers\.d/[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + 1 + + + /etc/audit/audit.rules + ^\-w[\s]+/etc/sudoers[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + 1 + + + /etc/audit/audit.rules + ^\-w[\s]+/etc/sudoers\.d/[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^\-f\s+(\d)\s*$ + 1 + + + /etc/audit/audit.rules + ^\-f\s+(\d)\s*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^\-w[\s]+/etc/group[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^\-w[\s]+/etc/passwd[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^\-w[\s]+/etc/gshadow[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^\-w[\s]+/etc/shadow[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^\-w[\s]+/etc/security/opasswd[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + 1 + + + /etc/audit/audit.rules + ^\-w[\s]+/etc/group[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + 1 + + + /etc/audit/audit.rules + ^\-w[\s]+/etc/passwd[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + 1 + + + /etc/audit/audit.rules + ^\-w[\s]+/etc/gshadow[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + 1 + + + /etc/audit/audit.rules + ^\-w[\s]+/etc/shadow[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + 1 + + + /etc/audit/audit.rules + ^\-w[\s]+/etc/security/opasswd[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + + 1 + + + /etc/audit/audit.rules + + 1 + + + + /var/log/audit + + oval:ssg-state_group_owner_not_root_var_log_audit_directories:ste:1 + + + + /var/log/audit + + oval:ssg-state_group_owner_not_root_var_log_audit_directories-non_root:ste:1 + + + + + + oval:ssg-state_group_owner_not_root_var_log_audit_directories:ste:1 + + + + + + + + oval:ssg-state_owner_not_root_var_log_audit_directories:ste:1 + + + /var/log/audit + + oval:ssg-state_owner_not_root_var_log_audit_directories:ste:1 + + + + + + oval:ssg-state_not_mode_0700:ste:1 + + + + /var/log/audit + + oval:ssg-state_not_mode_0700:ste:1 + + + + /var/log/audit + + oval:ssg-state_not_mode_0750:ste:1 + + + + + + oval:ssg-state_not_mode_0750:ste:1 + + + + oval:ssg-state_group_owner_not_root_var_log_audit:ste:1 + + + /var/log/audit/audit.log + oval:ssg-state_group_owner_not_root_var_log_audit:ste:1 + + + + /var/log/audit + + oval:ssg-state_owner_not_root_root_var_log_audit:ste:1 + + + + /var/log/audit + ^.*$ + oval:ssg-state_owner_not_root_root_var_log_audit:ste:1 + + + + /var/log/audit + + oval:ssg-state_owner_not_root_var_log_audit-non_root:ste:1 + + + + /var/log/audit + ^.*$ + oval:ssg-state_owner_not_root_var_log_audit-non_root:ste:1 + + + + oval:ssg-state_not_mode_0600:ste:1 + + + /var/log/audit/audit.log + oval:ssg-state_not_mode_0600:ste:1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+umount[\s]+|([\s]+|[,])umount([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+umount[\s]+|([\s]+|[,])umount([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+delete_module[\s]+|([\s]+|[,])delete_module([\s]+|[,]))).*(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295))\s+(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+delete_module[\s]+|([\s]+|[,])delete_module([\s]+|[,]))).*(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295))\s+(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+delete_module[\s]+|([\s]+|[,])delete_module([\s]+|[,]))).*(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295))\s+(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+delete_module[\s]+|([\s]+|[,])delete_module([\s]+|[,]))).*(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295))\s+(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+finit_module[\s]+|([\s]+|[,])finit_module([\s]+|[,]))).*(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295))\s+(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+finit_module[\s]+|([\s]+|[,])finit_module([\s]+|[,]))).*(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295))\s+(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+finit_module[\s]+|([\s]+|[,])finit_module([\s]+|[,]))).*(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295))\s+(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+finit_module[\s]+|([\s]+|[,])finit_module([\s]+|[,]))).*(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295))\s+(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+init_module[\s]+|([\s]+|[,])init_module([\s]+|[,]))).*(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295))\s+(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+init_module[\s]+|([\s]+|[,])init_module([\s]+|[,]))).*(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295))\s+(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+init_module[\s]+|([\s]+|[,])init_module([\s]+|[,]))).*(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295))\s+(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+init_module[\s]+|([\s]+|[,])init_module([\s]+|[,]))).*(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295))\s+(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^(?!/proc(/.*|$)).*$ + oval:ssg-state_audit_rules_privileged_commands_dev_partitons:ste:1 + oval:ssg-state_audit_rules_privileged_commands_nosuid_partitons:ste:1 + oval:ssg-state_audit_rules_privileged_commands_noexec_partitons:ste:1 + + + + + ^\w+ + oval:ssg-state_setuid_or_setgid_set:ste:1 + oval:ssg-state_dracut_tmp_files:ste:1 + + + + / + ^\w+ + oval:ssg-state_setuid_or_setgid_set:ste:1 + oval:ssg-state_dracut_tmp_files:ste:1 + oval:ssg-state_audit_rules_privileged_commands_sysroot:ste:1 + + + oval:ssg-var_audit_rules_privileged_commands_priv_cmds_count:var:1 + + + oval:ssg-var_audit_rules_privileged_commands_priv_cmds_count_bootc:var:1 + + + ^/etc/audit/rules\.d/.*\.rules$ + + 1 + oval:ssg-state_unprivileged_commands:ste:1 + + + ^/etc/audit/rules\.d/.*\.rules$ + + 1 + oval:ssg-state_unprivileged_commands_bootc:ste:1 + + + /etc/audit/audit.rules + + 1 + oval:ssg-state_unprivileged_commands:ste:1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+arch=b32.*(-S[\s]+adjtimex[\s]+|([\s]+|[,])adjtimex([\s]+|[,])).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+arch=b64.*(-S[\s]+adjtimex[\s]+|([\s]+|[,])adjtimex([\s]+|[,])).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+arch=b32.*(-S[\s]+adjtimex[\s]+|([\s]+|[,])adjtimex([\s]+|[,])).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+arch=b64.*(-S[\s]+adjtimex[\s]+|([\s]+|[,])adjtimex([\s]+|[,])).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+arch=b32[\s]+(-S[\s]+clock_settime[\s]+|([\s]+|[,])clock_settime([\s]+|[,]))-F[\s]+a0=(?:0x)?0[\s]+(?:-F[\s]+key=|-k[\s]+)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+arch=b64[\s]+(-S[\s]+clock_settime[\s]+|([\s]+|[,])clock_settime([\s]+|[,]))-F[\s]+a0=(?:0x)?0[\s]+(?:-F[\s]+key=|-k[\s]+)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+arch=b32[\s]+(-S[\s]+clock_settime[\s]+|([\s]+|[,])clock_settime([\s]+|[,]))-F[\s]+a0=(?:0x)?0[\s]+(?:-F[\s]+key=|-k[\s]+)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+arch=b64[\s]+(-S[\s]+clock_settime[\s]+|([\s]+|[,])clock_settime([\s]+|[,]))-F[\s]+a0=(?:0x)?0[\s]+(?:-F[\s]+key=|-k[\s]+)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+arch=b32.*(-S[\s]+settimeofday[\s]+|([\s]+|[,])settimeofday([\s]+|[,])).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+arch=b64.*(-S[\s]+settimeofday[\s]+|([\s]+|[,])settimeofday([\s]+|[,])).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+arch=b32.*(-S[\s]+settimeofday[\s]+|([\s]+|[,])settimeofday([\s]+|[,])).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+arch=b64.*(-S[\s]+settimeofday[\s]+|([\s]+|[,])settimeofday([\s]+|[,])).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+arch=b32.*(-S[\s]+stime[\s]+|([\s]+|[,])stime([\s]+|[,])).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+arch=b32.*(-S[\s]+stime[\s]+|([\s]+|[,])stime([\s]+|[,])).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-w[\s]+\/etc\/localtime[\s]+-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-w[\s]+\/etc\/localtime[\s]+-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + 1 + + + /etc/audit/plugins.d/syslog.conf + ^[ ]*active[ ]+=[ ]+yes[ ]*$ + 1 + + + /etc/audit/auditd.conf + ^[ ]*disk_error_action[ ]+=[ ]+(\S+)[ ]*$ + 1 + + + /etc/audit/auditd.conf + ^[ ]*disk_error_action[ ]+=[ ]+(\S+)[ ]*$ + 1 + + + /etc/audit/auditd.conf + ^[ ]*disk_full_action[ ]+=[ ]+(\S+)[ ]*$ + 1 + + + /etc/audit/auditd.conf + ^[ ]*disk_full_action[ ]+=[ ]+(\S+)[ ]*$ + 1 + + + /etc/audit/auditd.conf + ^[ ]*action_mail_acct[ ]+=[ ]+(\S+)[ ]*$ + 1 + + + /etc/audit/auditd.conf + ^[ ]*admin_space_left_action[ ]+=[ ]+(\S+)[ ]*$ + 1 + + + /etc/audit/auditd.conf + ^[ ]*flush[ ]+=[ ]+(\S+)[ ]*$ + 1 + + + /etc/audit/auditd.conf + ^[ ]*max_log_file_action[ ]+=[ ]+(\S+)[ ]*$ + 1 + + + /etc/audit/auditd.conf + ^[ ]*max_log_file_action[ ]+=[ ]+(\S+)[ ]*$ + 1 + + + /etc/audit/auditd.conf + ^[\s]*space_left[\s]+=[\s]+(\d+)[\s]*$ + 1 + + + /etc/audit/auditd.conf + ^[ ]*space_left_action[ ]+=[ ]+(\S+)[ ]*$ + 1 + + + /etc/audit/auditd.conf + ^[\s]*space_left[\s]+=[\s]+(\d+)%[\s]*$ + 1 + + + /etc/audit/auditd.conf + ^[ \t]*(?i)name_format(?-i)[ \t]*=[ \t]*(.+?)[ \t]*(?:$|#) + 1 + + + /etc/audit/auditd.conf + ^[ \t]*(?i)overflow_action(?-i)[ \t]*=[ \t]*(.+?)[ \t]*(?:$|#) + 1 + + + /etc/fapolicyd/compiled.rules + ^\s*deny\s*perm=any\s*all\s*:\s*all\s*\z + 1 + + + /etc/fapolicyd/fapolicyd.rules + ^\s*deny\s*perm=any\s*all\s*:\s*all\s*\z + 1 + + + /etc/fapolicyd/fapolicyd.conf + ^\s*permissive\s*=\s*(\d+) + 1 + + + /etc/aliases + ^(?:[rR][oO][oO][tT]|"[rR][oO][oO][tT]")\s*:\s*(.+)$ + 1 + + + /etc/aliases + ^(?i)postmaster\s*:\s*(.+)$ + 1 + + + /etc/postfix/main.cf + ^[\s]*inet_interfaces[\s]*=[\s]*(.*)[\s]*$ + 1 + + + /etc/postfix/main.cf + ^[ \t]*smtpd_client_restrictions = (.+?)[ \t]*(?:$|#) + 1 + + + ^/etc/postfix/main.cf + + + /etc/exports + ^\/.*\((\S+)\)$ + 0 + + + /etc/exports + ^\/.*$ + 0 + + + /etc/chrony.conf + ^\s*port[\s]+(\S+) + 1 + + + /etc/chrony.conf + + 1 + + + /etc/chrony.conf + + 1 + + + /etc/chrony.conf + ^\s*cmdport[\s]+(\S+) + 1 + + + /etc/ntp.conf + ^server[\s]+[\S]+.*maxpoll[\s]+(\d+) + 1 + + + ^(/etc/chrony\.conf|/etc/chrony\.d/.+\.conf)$ + ^(?:server|pool|peer)[\s]+[\S]+.*maxpoll[\s]+(\d+) + 1 + + + /etc/ntp.conf + ^server[\s]+[\S]+[\s]+(.*) + 1 + + + ^(/etc/chrony\.conf|/etc/chrony\.d/.+\.conf)$ + ^(?:server|pool|peer)[\s]+[\S]+[\s]+(.*) + 1 + + + + /etc/sysconfig/chronyd + ^\s*OPTIONS=.*[\s'"]-u(?!\s*chrony\b).* + 0 + + + ^/etc/chrony\.(conf|d/.+\.conf)$ + ^[\s]*server.*$ + 1 + + + ^/etc/chrony\.(conf|d/.+\.conf)$ + ^[\s]+pool.*$ + 1 + + + ^(/etc/chrony.conf|/etc/chrony.d/.+\.conf)$ + ^[\s]*(?:server|pool)[\s]+.+$ + 1 + + + /etc/nsswitch.conf + ^\s*group:\s+(.*)$ + 1 + + + /etc/chrony.keys + oval:ssg-state_file_groupowner_etc_chrony_keys_uid_chrony:ste:1 + oval:ssg-state_file_groupowner_etc_chrony_keys_gid_chrony:ste:1 + + + /etc/group + ^chrony:\w+:(\w+):.* + 1 + + + /etc/chrony.keys + oval:ssg-state_file_groupowner_etc_chrony_keys_uid_chrony:ste:1 + oval:ssg-state_file_groupowner_etc_chrony_keys_gid_chrony_with_usrlib:ste:1 + + + + oval:ssg-object_file_groupowner_etc_chrony_keys_etc_group:obj:1 + oval:ssg-object_file_groupowner_etc_chrony_keys_usr_lib_group:obj:1 + + + + /usr/lib/group + ^chrony:\w+:(\w+):.* + 1 + + + /etc/ntp.conf + ^([\s]*server[\s]+.+$){2,}$ + 1 + + + + / + shosts.equiv + + + /root + ^\.rhosts$ + + + + /home + ^\.rhosts$ + + + /etc + ^hosts\.equiv$ + + + + / + .shosts + + + /etc/xinetd.d/tftp + ^[\s]*server_args[\s]+=[\s]+.*?-s[\s]+([/\.\w]+).*$ + 1 + + + /etc/snmp/snmpd.conf + ^[\s]*(com2se|rocommunity|rwcommunity) + 1 + + + /etc/ssh + .*_key$ + oval:ssg-exclude_symlinks__sshd_private_key:ste:1 + oval:ssg-filter_ssh_key_owner_root:ste:1 + oval:ssg-filter_ssh_key_owner_ssh_keys:ste:1 + + + /etc/group + ^ssh_keys:\w+:(\w+):.* + 1 + + + /etc/ssh/ssh_config + ^[\s]*RekeyLimit.*$ + 1 + + + ^/etc/ssh/ssh_config\.d/.*\.conf$ + + 1 + + + /usr/lib/firewalld/zones + + /zone/service[@name='ssh'] + + + + /etc/firewalld/zones + + + + oval:ssg-var_firewalld_sshd_port_enabled_custom_zone_files_with_ssh_count:var:1 + + + /etc/firewalld/zones + ^.*\.xml$ + /zone/service[@name='ssh'] + + + + /etc/firewalld/zones + ^.*\.xml$ + + + /usr/lib/firewalld/services/ssh.xml + /service/port[@port='22'] + + + /etc/firewalld/services/ssh.xml + <port.*port="(\d+)" + 1 + + + /etc/ssh/sshd_config + ^[ \t]*(?i)Include(?-i)[ \t]+/etc/ssh/sshd_config\.d/\*.conf$ + 1 + + + /etc/ssh/(sshd_config|sshd_config\.d/.*\.conf) + ^[ \t]*(?i)Include(?-i)[ \t]+/etc/crypto-policies/back-ends/opensshserver\.config$ + 1 + + + ^\/etc\/ssh\/sshd_config.*$ + (?i)^[ ]*AllowUsers[ ]+((?:[^ \n]+[ ]*)+)$ + 1 + + + ^/etc/ssh/sshd_config.*$ + (?i)^[ ]*AllowGroups[ ]+((?:[^ \n]+[ ]*)+)$ + 1 + + + ^/etc/ssh/sshd_config.*$ + (?i)^[ ]*DenyUsers[ ]+((?:[^ \n]+[ ]*)+)$ + 1 + + + ^/etc/ssh/sshd_config.*$ + (?i)^[ ]*DenyGroups[ ]+((?:[^ \n]+[ ]*)+)$ + 1 + + + /etc/ssh/sshd_config + ^[\s]*RekeyLimit[\s]+(.*)$ + 1 + + + /etc/ssh/sshd_config + ^[\s]*(?i)ClientAliveInterval[\s]+(\d+)[\s]*(?:#.*)?$ + 1 + + + + oval:ssg-object_sshd_idle_timeout:obj:1 + + + + /etc/ssh/sshd_config + ^[\s]*(?i)LoginGraceTime[\s]+(\d+)[\s]*(?:#.*)?$ + 1 + + + + oval:ssg-object_sshd_login_grace_time:obj:1 + + + + /etc/ssh/sshd_config + ^[\s]*(?i)MaxAuthTries[\s]+(\d+)[\s]*(?:#.*)?$ + 1 + + + + oval:ssg-object_sshd_max_auth_tries:obj:1 + + + + /etc/ssh/sshd_config + ^[\s]*(?i)MaxSessions[\s]+(\d+)[\s]*(?:#.*)?$ + 1 + + + + oval:ssg-object_sshd_max_sessions:obj:1 + + + + /etc/(ssh|ssh/sshd_config.d) + (sshd_config|.*\.conf)$ + (?i)^\s*MaxStartups\s+(\d+):\d+:\d+\s*$ + 1 + + + /etc/(ssh|ssh/sshd_config.d) + (sshd_config|.*\.conf)$ + (?i)^\s*MaxStartups\s+\d+:(\d+):\d+\s*$ + 1 + + + /etc/(ssh|ssh/sshd_config.d) + (sshd_config|.*\.conf)$ + (?i)^\s*MaxStartups\s+\d+:\d+:(\d+)\s*$ + 1 + + + /etc/ssh/sshd_config + ^[ \t]*(?i)match(?-i)\s+\S+ + 1 + + + oval:ssg-var_sshd_config_strong_macs:var:1 + + + /etc/ssh/sshd_config + ^[\s]*(?i)MACs(?-i)[\s]+([\w,-@]+)+[\s]*(?:#.*)?$ + 1 + + + ^/etc/sssd/(sssd|conf\.d/.*)\.conf$ + ^[\s]*\[sssd](?:[^\n\[]*\n+)+?[\s]*certificate_verification\s*=\s*ocsp_dgst=(\w+)$ + 1 + + + ^/etc/sssd/(sssd|conf\.d/.*)\.conf$ + ^\s*\[sssd\].*(?:\n\s*[^[\s].*)*\n\s*services[ \t]*=[ \t]*(.*)$ + 1 + + + /etc/sssd/(sssd\.conf|conf.d/[^/]+\.conf) + ^[\s]*\[pam](?:[^\n\[]*\n+)+?[\s]*pam_cert_auth[\s]*=[\s]*(\w+)\s*$ + 1 + + + /etc/pam.d/smartcard-auth + ^\s*auth.*?pam_sss\.so(.*) + 1 + + + /etc/pam.d/system-auth + ^\s*auth.*?pam_sss\.so(.*) + 1 + + + ^\/etc\/sssd\/(sssd.conf|conf\.d\/.+\.conf)$ + ^[\s]*\[pam](?:[^\n\[]*\n+)+?[\s]*offline_credentials_expiration[\s]*=[\s]*(\d+)\s*(?:#.*)?$ + 1 + + + ^\/etc\/sssd\/(sssd.conf|conf\.d\/.+\.conf)$ + ^[\s]*cache_credentials\s*=\s*(\w+)\s*(?:#.*)?$ + 1 + + + ^\/etc\/sssd\/(sssd.conf|conf\.d\/.+\.conf)$ + ^[\s]*\[domain\/[^]]*](?:[^\n\[\]]*\n+)+?[\s]*ldap_tls_reqcert[ \t]*=[ \t]*(\w+)[ \t]*$ + 1 + + + ^\/etc\/sssd\/(sssd.conf|conf\.d\/.+\.conf)$ + ^[\s]*\[domain\/[^]]*](?:[^\n\[\]]*\n+)+?[\s]*ldap_id_use_start_tls[ \t]*=[ \t]*((?i)\w+)[ \t]*$ + 1 + + + /etc/usbguard/usbguard-daemon.conf + ^[ \t]*AuditBackend=(.+?)[ \t]*(?:$|#) + 1 + + + ^/etc/usbguard/usbguard-daemon.conf + + + xorg-x11-server-Xorg + + + xorg-x11-server-utils + + + xorg-x11-server-Xwayland + + + /etc/systemd/system/default.target + + + /etc/pam.d/fingerprint-auth + + + /etc/pam.d/password-auth + + + /etc/pam.d/postlogin + + + /etc/pam.d/smartcard-auth + + + /etc/pam.d/system-auth + + + + ^/etc/issue(\.d/.*)?$ + ^(.*)$ + 1 + + + + ^/etc/issue\.net$ + ^(.*)$ + 1 + + + /etc/motd + + + + /etc/motd + ^(.*)$ + 1 + + + /etc/dconf/db/local.d/ + ^.*$ + ^\[org/gnome/login-screen\]([^\n]*\n+)+?banner-message-enable=true$ + 1 + + + /etc/dconf/db/local.d/locks/ + ^.*$ + ^/org/gnome/login-screen/banner-message-enable$ + 1 + + + /etc/dconf/db/local.d/locks/ + ^.*$ + ^/org/gnome/login-screen/banner-message-text$ + 1 + + + /etc/dconf/db/local.d/ + ^.*$ + ^banner-message-text=[\s]*'*(.*?)'$ + 1 + + + /etc/pam.d/sudo + ^.*pam_succeed_if.*$ + 1 + + + /etc/pam.d/postlogin + ^\s*session\s+.*\s+pam_lastlog\.so\b(?!.*\ssilent\s).*\sshowfailed\s.*$ + 1 + + + ^/etc/pam.d/password-auth$ + ^[\s]*auth\N+pam_unix\.so + 1 + + + ^/etc/pam.d/password-auth$ + + 1 + + + ^/etc/pam.d/password-auth$ + + 1 + + + ^/etc/pam.d/system-auth$ + ^[\s]*auth\N+pam_unix\.so + 1 + + + ^/etc/pam.d/system-auth$ + + 1 + + + ^/etc/pam.d/system-auth$ + + 1 + + + /etc/pam.d/password-auth|/etc/pam.d/system-auth|/etc/security/faillock.conf + ^\s*(?:auth.*pam_faillock\.so.*)?dir\s*=\s*(\S+) + 1 + + + + + + + oval:ssg-var_account_password_selinux_faillock_dir_collector:var:1 + + + /etc/pam.d/system-auth + + 1 + + + /etc/pam.d/password-auth + + 1 + + + /etc/security/faillock.conf + ^\s*audit + 1 + + + /etc/pam.d/password-auth + + 1 + + + /etc/pam.d/password-auth + + 1 + + + ^/etc/security/pwhistory.conf$ + + 1 + + + /etc/pam.d/system-auth + + 1 + + + /etc/pam.d/system-auth + + 1 + + + ^/etc/security/pwhistory.conf$ + + 1 + + + /etc/pam.d/system-auth + + 1 + + + /etc/pam.d/system-auth + + 1 + + + ^/etc/security/pwhistory.conf$ + + 1 + + + /etc/pam.d/system-auth + ^\s*password\s+(?:(?:sufficient)|(?:required)|(?:\[.*\]))\s+pam_unix\.so.*remember=([0-9]*).*$ + 1 + + + /etc/pam.d/system-auth + + 1 + + + /etc/pam.d/password-auth + + 1 + + + /etc/security/faillock.conf + ^\s*audit + 1 + + + ^/etc/pam.d/system-auth$ + + 1 + + + ^/etc/pam.d/password-auth$ + + 1 + + + ^/etc/pam.d/system-auth$ + + 1 + + + ^/etc/pam.d/system-auth$ + + 1 + + + ^/etc/pam.d/password-auth$ + + 1 + + + ^/etc/pam.d/password-auth$ + + 1 + + + ^/etc/pam.d/system-auth$ + + 1 + + + ^/etc/pam.d/password-auth$ + + 1 + + + ^/etc/security/faillock.conf$ + + 1 + + + /etc/pam.d/system-auth + + 1 + oval:ssg-state_pam_faillock_dir_parameter_not_default_value:ste:1 + + + /etc/pam.d/password-auth + + 1 + oval:ssg-state_pam_faillock_dir_parameter_not_default_value:ste:1 + + + oval:ssg-var_faillock_dir_set_both_preauth_authfail_system_auth:var:1 + + + oval:ssg-var_faillock_dir_set_both_preauth_authfail_password_auth:var:1 + + + /etc/security/faillock.conf + + 1 + + + ^/etc/security/pwquality\.conf$ + ^enforce_for_root$ + 1 + + + /etc/pam.d/password-auth + ^password[\s]*requisite[\s]*pam_pwquality\.so + 1 + + + /etc/pam.d/system-auth + ^password[\s]*requisite[\s]*pam_pwquality\.so + 1 + + + /etc/pam.d/password-auth + ^\s*password\s+(?:(?:required)|(?:requisite))\s+pam_pwquality\.so.*retry=([0-9]*).*$ + 1 + + + /etc/pam.d/system-auth + ^\s*password\s+(?:(?:required)|(?:requisite))\s+pam_pwquality\.so.*retry=([0-9]*).*$ + 1 + + + /etc/security/pwquality.conf + ^[\s]*retry[\s]*=[\s]*(\d+)(?:[\s]|$) + 1 + + + /etc/libuser.conf + ^[\s]*crypt_style[\s]*=[\s]*(\w*)[\s]*$ + 1 + + + + /etc/login.defs + .*\n[^#]*(ENCRYPT_METHOD\s+\w+)\s*\n + 1 + + + oval:ssg-variable_last_encrypt_method_instance_value:var:1 + + + /etc/pam.d/password-auth + ^[\s]*password[\s]+(?:(?:required)|(?:sufficient))[\s]+pam_unix\.so[\s]+(?!.*(sha512|yescrypt|gost_yescrypt|blowfish|sha256|md5|bigcrypt).*(sha512|yescrypt|gost_yescrypt|blowfish|sha256|md5|bigcrypt)).*(sha512|yescrypt|gost_yescrypt|blowfish|sha256|md5|bigcrypt).*$ + 1 + + + /etc/pam.d/system-auth + ^[\s]*password[\s]+(?:(?:required)|(?:sufficient))[\s]+pam_unix\.so[\s]+(?!.*\b(sha512|yescrypt|gost_yescrypt|blowfish|sha256|md5|bigcrypt)\b[^#]*\b(sha512|yescrypt|gost_yescrypt|blowfish|sha256|md5|bigcrypt)\b)[^#]*\b(sha512|yescrypt|gost_yescrypt|blowfish|sha256|md5|bigcrypt)\b.*$ + 1 + + + /etc/login.defs + ^\s*SHA_CRYPT_MIN_ROUNDS\s* + 1 + + + /etc/login.defs + ^\s*SHA_CRYPT_MIN_ROUNDS\s+(\d+)\s*$ + 1 + + + /etc/login.defs + ^\s*SHA_CRYPT_MAX_ROUNDS\s* + 1 + + + /etc/login.defs + ^\s*SHA_CRYPT_MAX_ROUNDS\s+(\d+)\s*$ + 1 + + + oval:ssg-local_var_password_hashing_min_rounds_login_defs:var:1 + + + ^/etc/systemd/system.conf(\.d/.*\.conf)?$ + ^[\s]*CtrlAltDelBurstAction[\s]*=[\s]*none$ + 1 + + + /etc/systemd/system/ctrl-alt-del.target + + + /etc/default/grub + ^\s*GRUB_CMDLINE_LINUX="(?:.*\s)?systemd\.confirm_spawn(?:=(?:1|yes|true|on))?(?:\s.*)?"$ + 1 + + + /etc/default/grub + ^\s*GRUB_CMDLINE_LINUX_DEFAULT=".*systemd\.confirm_spawn=(?:1|yes|true|on).*$ + 1 + + + /etc/systemd/logind.conf + ^\s*\[Login\].*(?:\n\s*[^[\s].*)*\n^\s*StopIdleSessionSec[ \t]*=[ \t]*(.+?)[ \t]*(?:$|#) + 1 + + + ^/etc/systemd/logind.conf + + + /usr/lib/systemd/system/emergency.service + ^ExecStart=\-/usr/lib/systemd/systemd-sulogin-shell[\s]+emergency + 1 + + + /usr/lib/systemd/system/emergency.target + ^Requires=.*emergency\.service + 1 + + + + /etc/systemd/system + ^emergency.service$ + + + + /etc/systemd/system + ^emergency.target$ + + + /etc/systemd/system/emergency.service.d + ^.*\.conf$ + + + /usr/lib/systemd/system/rescue.service + ^ExecStart\s?=\s?\-?(.*)$ + 1 + + + + /etc/systemd/system/rescue.service.d + ^.*\.conf$ + ^.*ExecStart\s?=\s+.*ExecStart\s?=\s?\-?(.*)$ + 1 + + + ^/etc/opensc.*\.conf$ + ^[\s]+card_drivers[\s]+=[\s]+(\S+);$ + 1 + + + .* + + + oval:ssg-variable_count_of_all_uids:var:1 + + + /etc/passwd + ^([a-zA-Z0-9_.-]+?): + 1 + oval:ssg-state_default_os_user:ste:1 + + + /etc/group + ^.+:.+:(\d+):.*$ + 1 + + + oval:ssg-variable_count_of_all_group_ids:var:1 + + + /etc/pam.d/password-auth + ^auth\s*(?:required|requisite)\s*pam_lastlog\.so[^#]*inactive=(\d+)[\s\S]*^\s*auth\s*sufficient\s*pam_unix\.so + 1 + + + /etc/pam.d/system-auth + ^auth\s*(?:required|requisite)\s*pam_lastlog\.so[^#]*inactive=(\d+)[\s\S]*^\s*auth\s*sufficient\s*pam_unix\.so + 1 + + + /etc/default/useradd + ^\s*INACTIVE\s*=\s*(\d+)\s*$ + 1 + + + /etc/passwd + ^([^:]+):.*$ + 1 + + + oval:ssg-variable_count_of_all_usernames_from_etc_passwd:var:1 + + + /etc/login.defs + ^(?:.*\n)*\s*[^#]*(PASS_MAX_DAYS\s+\d+)\s*\n + 1 + + + oval:ssg-variable_last_pass_max_days_instance_value:var:1 + + + + /etc/login.defs + .*\n[^#]*(PASS_MIN_DAYS\s+\d+)\s*\n + 1 + + + oval:ssg-variable_last_pass_min_days_instance_value:var:1 + + + + /etc/login.defs + .*\n[^#]*(PASS_MIN_LEN\s+\d+)\s*\n + 1 + + + oval:ssg-variable_last_pass_min_len_instance_value:var:1 + + + /etc/shadow + ^(?:[^:]*:)(?:[^\!\*:]*:)(?:[^:]*:){2}(\d+):(?:[^:]*:){3}(?:[^:]*)$ + 1 + + + /etc/shadow + ^(?:[^:]*:)(?:[^\!\*:]*:)(?:[^:]*:){2}(\d+):(?:[^:]*:){3}(?:[^:]*)$ + 1 + + + /etc/shadow + ^(?:[^:]*:)(?:[^\!\*:]+:)(?:[^:]*:){2}():(?:[^:]*:){3}(?:[^:]*)$ + 1 + + + root + + + /etc/shadow + ^(?:[^:]*:)(?:[^\!\*:]*:)(?:[^:]*:)(\d+):(?:[^:]*:){4}(?:[^:]*)$ + 1 + + + /etc/shadow + ^(?:[^:]*:)(?:[^\!\*:]*:)(?:[^:]*:)(\d+):(?:[^:]*:){4}(?:[^:]*)$ + 1 + + + /etc/shadow + ^(?:[^:]*:)(?:[^\!\*:]+:)(?:[^:]*:)():(?:[^:]*:){4}(?:[^:]*)$ + 1 + + + /etc/shadow + ^(?:[^:]*:)(?:[^\!\*:]*:)(?:[^:]*:){3}(\d+):(?:[^:]*:){2}(?:[^:]*)$ + 1 + + + /etc/shadow + ^(?:[^:]*:)(?:[^\!\*:]*:)(?:[^:]*:){3}(\d+):(?:[^:]*:){2}(?:[^:]*)$ + 1 + + + + /etc/login.defs + .*\n[^#]*(PASS_WARN_AGE\s+\d+)\s*\n + 1 + + + oval:ssg-variable_last_pass_warn_age_instance_value:var:1 + + + /etc/shadow + ^(?:[^:]*:)(?:[^\!\*:]*:)(?:[^:]*:){4}(\d+):(?:[^:]*:)(?:[^:]*)$ + 1 + + + /etc/shadow + ^(?:[^:]*:)(?:[^\!\*:]*:)(?:[^:]*:){4}(\d+):(?:[^:]*:)(?:[^:]*)$ + 1 + + + .* + + + .* + oval:ssg-state_accounts_password_all_shadowed_has_no_password:ste:1 + oval:ssg-state_accounts_password_all_shadowed_has_locked_password:ste:1 + oval:ssg-state_accounts_password_all_shadowed_sha512:ste:1 + + + .* + oval:ssg-state_accounts_password_all_chage_past_has_no_password:ste:1 + + + oval:ssg-var_accounts_password_last_change_is_in_past_time_diff:var:1 + + + ^/etc/pam.d/password-auth$ + ^\s*password\s+(?:(?:sufficient)|(?:required))\s+pam_unix\.so.*rounds=([0-9]*).*$ + 1 + + + ^/etc/pam.d/system-auth$ + ^\s*password\s+(?:(?:sufficient)|(?:required))\s+pam_unix\.so.*rounds=([0-9]*).*$ + 1 + + + /etc/group + ^[^:]+:[^:]+:([0-9]+): + 1 + + + /etc/passwd + ^[^:]+:[^:]+:[0-9]+:([0-9]+): + 1 + + + ^/etc/pam.d/(system|password)-auth$ + ^[^#]*\bnullok\b.*$ + 1 + + + /etc/shadow + ^[^:]+::.*$ + 1 + + + + /home + ^\.netrc$ + + + /etc/passwd + ^(?!root:)[^:]*:[^:]*:0 + 1 + + + /etc/passwd + ^root:.+:\d+:(\d+).+ + 1 + + + /etc/group + + 1 + + + /etc/shadow + ^root:\$(y|[0-9].+)\$.*$ + 1 + + + /etc/securetty + ^.*$ + 1 + + + /etc/securetty + ^$ + 1 + + + .* + oval:ssg-state_no_password_auth_for_systemaccounts_users_uids:ste:1 + oval:ssg-state_no_password_auth_for_systemaccounts_users_ignored:ste:1 + + + + oval:ssg-filter_no_password_auth_for_systemaccounts_no_passwords_or_locked_accounts:ste:1 + + + + /etc/login.defs + .*(?:^|\n)\s*(UID_MIN[\s]+[\d]+)\s*(?:$|\n) + 1 + + + + /etc/login.defs + .*(?:^|\n)\s*(SYS_UID_MIN[\s]+[\d]+)\s*(?:$|\n) + 1 + + + + /etc/login.defs + .*(?:^|\n)\s*(SYS_UID_MAX[\s]+[\d]+)\s*(?:$|\n) + 1 + + + /etc/passwd + ^(?!root).*:x:([\d]+):[\d]+:[^:]*:[^:]*:(?!\/usr\/sbin\/nologin|\/sbin\/nologin|\/bin\/sync|\/sbin\/shutdown|\/sbin\/halt).*$ + 1 + + + /etc/securetty + ^ttyS[0-9]+$ + 1 + + + /etc/securetty + ^vc/[0-9]+$ + 1 + + + /etc/pam.d/su + ^[\s]*auth[\s]+required[\s]+pam_wheel\.so[\s]+\buse_uid\b + 1 + + + /etc/pam.d/su + ^\s*auth\s+required\s+pam_wheel\.so\s+(?=[^#]*\buse_uid\b)[^#]*\bgroup=([_a-z][-0-9_a-z]*) + 1 + + + /etc/login.defs + ^[\s]*(?i)CREATE_HOME(?-i)[\s]+yes[\s]*(?:#.*)?$ + 1 + + + /etc/login.defs + ^[\s]*(?i)FAIL_DELAY(?-i)[\s]+([^#\s]*) + 1 + + + /etc/security/limits.conf + ^[\s]*\*[\s]+(?:(?:hard)|(?:-))[\s]+maxlogins[\s]+(\d+)\s*$ + 1 + + + /etc/security/limits.d + ^.*\.conf$ + ^[\s]*\*[\s]+(?:(?:hard)|(?:-))[\s]+maxlogins[\s]+(\d+)\s*$ + 1 + + + /etc/security/limits.d + ^.*\.conf$ + ^[\s]*\*[\s]+(?:(?:hard)|(?:-))[\s]+maxlogins + 1 + + + /tmp/tmp-inst + + + + /etc/security/namespace.conf + ^\s*/tmp\s+/tmp/tmp-inst/\s+level\s+root,adm$ + 1 + + + /var/tmp/tmp-inst + + + + /etc/security/namespace.conf + ^\s*/var/tmp\s+/var/tmp/tmp-inst/\s+level\s+root,adm$ + 1 + + + /etc/profile + ^[\s]*(?:typeset|declare)[\s]+-xr[\s]+TMOUT=([\w$]+).*$ + 1 + + + /etc/profile.d + ^.*\.sh$ + ^[\s]*(?:typeset|declare)[\s]+-xr[\s]+TMOUT=([\w$]+).*$ + 1 + + + + oval:ssg-object_etc_profile_tmout:obj:1 + oval:ssg-object_etc_profiled_tmout:obj:1 + + + + oval:ssg-variable_count_of_tmout_instances:var:1 + + + /etc/passwd + + 1 + + + /etc/passwd + ^([^:]*):[^:]*:\d{4,}:(?:[^:]*:){3}(?!(\/usr)?(\/sbin\/nologin|\/bin\/false))[^:]*$ + 1 + oval:ssg-state_object_accounts_user_dot_group_ownership_home_dirs_users_ignored:ste:1 + + + /etc/passwd + + 1 + + + /etc/passwd + ^([^:]*):[^:]*:\d{4,}:(?:[^:]*:){3}(?!(\/usr)?(\/sbin\/nologin|\/bin\/false))[^:]*$ + 1 + oval:ssg-state_object_accounts_user_dot_group_ownership_gids_users_ignored:ste:1 + + + + + ^\..* + + + + oval:ssg-object_accounts_user_dot_no_world_writable_programs_objects_others:obj:1 + + + + .* + oval:ssg-state_accounts_user_dot_no_world_writable_programs_users_uids:ste:1 + oval:ssg-state_accounts_user_dot_no_world_writable_programs_users_ignored:ste:1 + oval:ssg-state_accounts_user_dot_no_world_writable_programs_users_nologin_shell:ste:1 + + + + / + ^.*$ + oval:ssg-state_world_writable_programs:ste:1 + + + + + + 1 + + + /etc/passwd + + 1 + + + /etc/passwd + ^([^:]*):[^:]*:\d{4,}:(?:[^:]*:){3}(?!(\/usr)?(\/sbin\/nologin|\/bin\/false))[^:]*$ + 1 + oval:ssg-state_object_accounts_user_dot_user_ownership_home_dirs_users_ignored:ste:1 + + + /etc/passwd + + 1 + + + /etc/passwd + ^([^:]*):[^:]*:\d{4,}:(?:[^:]*:){3}(?!(\/usr)?(\/sbin\/nologin|\/bin\/false))[^:]*$ + 1 + oval:ssg-state_object_accounts_user_dot_user_ownership_uids_users_ignored:ste:1 + + + + + ^\..* + + + + oval:ssg-object_accounts_user_interactive_home_directory_defined_objects_others:obj:1 + + + + .* + oval:ssg-state_accounts_user_interactive_home_directory_defined_users_uids:ste:1 + oval:ssg-state_accounts_user_interactive_home_directory_defined_users_ignored:ste:1 + oval:ssg-state_accounts_user_interactive_home_directory_defined_users_nologin_shell:ste:1 + + + /etc/passwd + + 1 + + + /etc/passwd + ^([^:]*):[^:]*:\d{4,}:(?:[^:]*:){3}(?!(\/usr)?(\/sbin\/nologin|\/bin\/false))[^:]*$ + 1 + oval:ssg-state_object_accounts_user_interactive_home_directory_exists_objects_users_ignored:ste:1 + + + + + + + oval:ssg-var_accounts_user_interactive_home_directory_exists_dirs_count_fs:var:1 + + + oval:ssg-var_accounts_user_interactive_home_directory_exists_dirs_count:var:1 + + + /etc/passwd + + 1 + + + /etc/passwd + ^([^:]*):[^:]*:\d{4,}:(?:[^:]*:){3}(?!(\/usr)?(\/sbin\/nologin|\/bin\/false))[^:]*$ + 1 + oval:ssg-state_object_accounts_users_home_files_groupownership_home_dirs_users_ignored:ste:1 + + + /etc/passwd + + 1 + + + /etc/passwd + ^([^:]*):[^:]*:\d{4,}:(?:[^:]*:){3}(?!(\/usr)?(\/sbin\/nologin|\/bin\/false))[^:]*$ + 1 + oval:ssg-state_object_accounts_users_home_files_groupownership_gids_users_ignored:ste:1 + + + + + .* + + + /etc/passwd + + 1 + + + /etc/passwd + ^([^:]*):[^:]*:\d{4,}:(?:[^:]*:){3}(?!(\/usr)?(\/sbin\/nologin|\/bin\/false))[^:]*$ + 1 + oval:ssg-state_object_accounts_users_home_files_ownership_home_dirs_users_ignored:ste:1 + + + /etc/passwd + + 1 + + + /etc/passwd + ^([^:]*):[^:]*:\d{4,}:(?:[^:]*:){3}(?!(\/usr)?(\/sbin\/nologin|\/bin\/false))[^:]*$ + 1 + oval:ssg-state_object_accounts_users_home_files_ownership_uids_users_ignored:ste:1 + + + + + .* + + + /etc/passwd + + 1 + + + /etc/passwd + ^([^:]*):[^:]*:\d{4,}:(?:[^:]*:){3}(?!(\/usr)?(\/sbin\/nologin|\/bin\/false))[^:]*$ + 1 + oval:ssg-state_object_accounts_users_home_files_permissions_home_dirs_users_ignored:ste:1 + + + + + + + + + + ^[^\.].* + oval:ssg-state_accounts_users_home_files_permissions_is_symlink:ste:1 + + + /etc/passwd + + 1 + + + /etc/passwd + ^([^:]*):[^:]*:\d{4,}:(?:[^:]*:){3}(?!(\/usr)?(\/sbin\/nologin|\/bin\/false))[^:]*$ + 1 + oval:ssg-state_object_file_groupownership_home_directories_home_dirs_users_ignored:ste:1 + + + /etc/passwd + + 1 + + + /etc/passwd + ^([^:]*):[^:]*:\d{4,}:(?:[^:]*:){3}(?!(\/usr)?(\/sbin\/nologin|\/bin\/false))[^:]*$ + 1 + oval:ssg-state_object_file_groupownership_home_directories_gids_users_ignored:ste:1 + + + + + + + + + + + + oval:ssg-object_file_permission_user_init_files_objects_others:obj:1 + + + + .* + oval:ssg-state_file_permission_user_init_files_users_uids:ste:1 + oval:ssg-state_file_permission_user_init_files_users_ignored:ste:1 + oval:ssg-state_file_permission_user_init_files_users_nologin_shell:ste:1 + + + /etc/passwd + + 1 + + + /etc/passwd + ^([^:]*):[^:]*:\d{4,}:(?:[^:]*:){3}(?!(\/usr)?(\/sbin\/nologin|\/bin\/false))[^:]*$ + 1 + oval:ssg-state_object_file_permissions_home_directories_objects_users_ignored:ste:1 + + + + + + + + oval:ssg-object_file_permissions_home_dirs_objects_others:obj:1 + + + + .* + oval:ssg-state_file_permissions_home_dirs_users_uids:ste:1 + oval:ssg-state_file_permissions_home_dirs_users_ignored:ste:1 + oval:ssg-state_file_permissions_home_dirs_users_nologin_shell:ste:1 + + + + + + + + PATH + + + + + oval:ssg-state_accounts_root_path_dirs_wrong_perms:ste:1 + oval:ssg-state_accounts_root_path_dirs_symlink:ste:1 + + + + PATH + + + /etc/bashrc + ^[^#]*\bumask\s+(\d{3})\s*$ + 1 + + + oval:ssg-var_etc_bashrc_umask_as_number:var:1 + + + /etc/csh.cshrc + ^[\s]*(?i)UMASK(?-i)[\s]+([^#\s]*) + 1 + + + oval:ssg-var_etc_csh_cshrc_umask_as_number:var:1 + + + /etc/login.defs + ^[\s]*UMASK[\s]+([^#\s]*) + 1 + + + oval:ssg-var_etc_login_defs_umask_as_number:var:1 + + + ^\/etc\/profile(?:\.d\/.*\.sh|\.d\/sh\.local)?$ + ^[\s]*umask[\s]+([^#\s]*) + 1 + + + oval:ssg-var_etc_profile_umask_as_number:var:1 + + + /etc/passwd + + 1 + + + /etc/passwd + ^([^:]*):[^:]*:\d{4,}:(?:[^:]*:){3}(?!(\/usr)?(\/sbin\/nologin|\/bin\/false))[^:]*$ + 1 + oval:ssg-state_object_accounts_umask_interactive_users_objects_users_ignored:ste:1 + + + + + ^\..* + ^[\s]*umask\s* + 1 + oval:ssg-state_accounts_umask_interactive_users_bash_history:ste:1 + + + .* + + + /boot/grub2/grub.cfg + ^[\s]*set[\s]+superusers="(?i)\b(?!(?:root|admin|administrator)\b)(\w+)"$ + 1 + + + /boot/grub2/user.cfg + ^[\s]*GRUB2_PASSWORD=grub\.pbkdf2\.sha512.*$ + 1 + + + /boot/grub2/user.cfg + ^[\s]*GRUB2_PASSWORD=grub\.pbkdf2\.sha512.*$ + 1 + + + ^/boot/config-.*$ + ^CONFIG_DEFAULT_MMAP_MIN_ADDR="?(.*?)"?$ + 1 + + + oval:ssg-local_var_kernel_config_default_mmap_min_addr_count_kernels_installed:var:1 + + + /boot + ^config-.*$ + + + /proc/sys/kernel/osrelease + ^.*\.(.*)$ + 1 + + + /proc/sys/kernel/osrelease + ^.*\.(.*)$ + 1 + + + /etc/rsyslog.conf + ^[\s]*cron\.\*[\s]+/var/log/cron\s*(?:#.*)?$ + 1 + + + /etc/rsyslog.conf + (?m)^\s*cron\.\*\s+action\(\s*.*(?i)\btype\b(?-i)="omfile"\s*.*(?i)\bfile\b(?-i)="/var/log/cron"\s*.*\)\s*$ + 1 + + + /etc/rsyslog.d + ^.*$ + ^[\s]*cron\.\*[\s]+/var/log/cron\s*(?:#.*)?$ + 1 + + + /etc/rsyslog.d + ^.*$ + (?m)^\s*cron\.\*\s+action\(\s*.*(?i)\btype\b(?-i)="omfile"\s*.*(?i)\bfile\b(?-i)="/var/log/cron"\s*.*\)\s*$ + 1 + + + /etc/rsyslog.conf + (?m)^[\s]*\*\.\*[\s]+(/var/log/messages|action\(\s*.*(?i:\btype\b)="omfile"\s*.*(?i:\bfile\b)="/var/log/messages"\s*\))\s*(?:#.*)?$ + 1 + + + /etc/rsyslog.d + ^.*$ + (?m)^[\s]*\*\.\*[\s]+(/var/log/messages|action\(\s*.*(?i:\btype\b)="omfile"\s*.*(?i:\bfile\b)="/var/log/messages"\s*\))\s*(?:#.*)?$ + 1 + + + /etc/rsyslog.conf + ^\$ActionSendStreamDriverAuthMode x509/name$ + 1 + + + /etc/rsyslog.conf + ^\s*action\(.*(?i)\btype\b(?-i)="omfwd".*(?i)\bStreamDriverAuthMode\b(?-i)="x509/name".*\)\s*$ + 1 + + + /etc/rsyslog.d + ^.*conf$ + ^\$ActionSendStreamDriverAuthMode x509/name$ + 1 + + + /etc/rsyslog.d + ^.*conf$ + ^\s*action\(.*(?i)\btype\b(?-i)="omfwd".*(?i)\bStreamDriverAuthMode\b(?-i)="x509/name".*\)\s*$ + 1 + + + /etc/rsyslog.conf + ^\$ActionSendStreamDriverMode 1$ + 1 + + + /etc/rsyslog.conf + ^\s*action\(.*(?i)\btype\b(?-i)="omfwd".*(?i)\bStreamDriverMode\b(?-i)="1".*\)\s*$ + 1 + + + /etc/rsyslog.d + ^.*conf$ + ^\$ActionSendStreamDriverMode 1$ + 1 + + + /etc/rsyslog.d + ^.*conf$ + ^\s*action\(.*(?i)\btype\b(?-i)="omfwd".*(?i)\bStreamDriverMode\b(?-i)="1".*\)\s*$ + 1 + + + /etc/rsyslog.conf + ^\$DefaultNetstreamDriver gtls$ + 1 + + + /etc/rsyslog.conf + ^\s*global\(.*(?i)\bDefaultNetStreamDriver\b(?-i)="gtls".*\)\s*$ + 1 + + + /etc/rsyslog.d + ^.*conf$ + ^\$DefaultNetstreamDriver gtls$ + 1 + + + /etc/rsyslog.d + ^.*conf$ + ^\s*global\(.*(?i)\bDefaultNetStreamDriver\b(?-i)="gtls".*\)\s*$ + 1 + + + ^/etc/rsyslog\.(conf|d/.+\.conf)$ + ^[^#]*auth\.\*.*$ + 1 + + + ^/etc/rsyslog\.(conf|d/.+\.conf)$ + ^[^#]*authpriv\.\*.*$ + 1 + + + ^/etc/rsyslog\.(conf|d/.+\.conf)$ + ^[^#]*daemon\.\*.*$ + 1 + + + /etc/logrotate.conf + ^\s*daily[\s#]*$ + 1 + + + /etc/logrotate.conf + ^\s*(weekly|monthly|yearly)[\s#]*$ + 1 + + + /etc/cron.daily/logrotate + ^[\s]*/usr/sbin/logrotate[\s\S]*/etc/logrotate.conf$ + 1 + + + ^/etc/systemd/system/(multi-user|timers)\.target\.wants/logrotate\.timer$ + oval:ssg-unit_logrotate_state_symlink:ste:1 + + + ^\/etc\/rsyslog(\.conf|\.d\/.*\.conf)$ + ^[\s]*\$((?:Input(?:TCP|RELP)|UDP)ServerRun|ModLoad[\s]+(imtcp|imudp|imrelp)) + 1 + + + ^\/etc\/rsyslog(\.conf|\.d\/.*\.conf)$ + ^\s*(?:module|input)\((?:load|type)="(imtcp|imudp)".*$ + 1 + + + /etc/rsyslog.conf + ^\*\.\*[\s]+(?:@|\:omrelp\:) + 1 + + + /etc/rsyslog.d + ^.+\.conf$ + ^\*\.\*[\s]+(?:@|\:omrelp\:) + 1 + + + + ^/etc/rsyslog\.(conf|d/.+\.conf)$ + ^\s*action\((?i)type(?-i)="omfwd"(.+?)\) + 0 + + + ^/etc/rsyslog\.(conf|d/.+\.conf)$ + ^\s*global\(DefaultNetstreamDriverCAFile="(.+?)"\)\s*\n + 0 + + + /etc/resolv.conf + ^[\s]*nameserver[\s]+([0-9\.]+)$ + 1 + + + /etc/nsswitch.conf + ^\s*hosts\s*:\s*.*dns.*$ + 1 + + + /etc/resolv.conf + + + ^/etc/polkit-1/localauthority/20-org.d/.*$ + ^\[.*\]\n\s*Identity=default\n\s*Action=org\.freedesktop\.NetworkManager\.\*\n\s*ResultAny=no\n\s*ResultInactive=no\n\s*(ResultActive=auth_admin)\n*\s*$ + 1 + + + ^.*$ + oval:ssg-state_promisc:ste:1 + + + /usr/lib/firewalld/zones/trusted.xml + /zone/rule/source[@address='127.0.0.1' or @address='::1'] + + + /usr/lib/firewalld/zones/trusted.xml + /zone/rule/destination[@address='127.0.0.1' or @address='::1' and @invert='True'] + + + /usr/lib/firewalld/zones/trusted.xml + /zone/rule/drop + + + /etc/firewalld/zones/trusted.xml + /zone/rule/source[@address='127.0.0.1' or @address='::1'] + + + /etc/firewalld/zones/trusted.xml + /zone/rule/destination[@address='127.0.0.1' or @address='::1' and @invert='True'] + + + /etc/firewalld/zones/trusted.xml + /zone/rule/drop + + + /usr/lib/firewalld/zones/trusted.xml + /zone/interface[@name='lo'] + + + /etc/firewalld/zones/trusted.xml + /zone/interface[@name='lo'] + + + /etc/firewalld/zones/trusted.xml + + + /etc/modprobe.d + ^.*\.conf$ + ^\s*options\s+ipv6\s+.*disable=1.*$ + 1 + + + ^wl.*$ + + + /etc/NetworkManager/NetworkManager.conf + ^\s*\[main\].*(?:\n\s*[^[\s].*)*\ndns=([^#]*).*$ + 1 + + + ^/etc/NetworkManager/NetworkManager.conf + + + + / + + oval:ssg-state_uid_is_not_root_and_world_writable:ste:1 + + + .* + oval:ssg-state_dir_perms_world_writable_sticky_bits_dev_partitons:ste:1 + + + + + + oval:ssg-state_dir_perms_world_writable_sticky_bits:ste:1 + + + ^\/s?bin|^\/usr\/s?bin|^\/usr\/local\/s?bin + + oval:ssg-state_system_commands_dirs_group_owner_not_root:ste:1 + + + + /bin + + oval:ssg-state_system_commands_directory_bin_owner_not_root:ste:1 + + + + /sbin + + oval:ssg-state_system_commands_directory_sbin_owner_not_root:ste:1 + + + + /usr/bin + + oval:ssg-state_system_commands_directory_usr_bin_owner_not_root:ste:1 + + + + /usr/sbin + + oval:ssg-state_system_commands_directory_usr_sbin_owner_not_root:ste:1 + + + + /usr/local/bin + + oval:ssg-state_system_commands_directory_usr_local_bin_owner_not_root:ste:1 + + + + /usr/local/sbin + + oval:ssg-state_system_commands_directory_usr_local_sbin_owner_not_root:ste:1 + + + .* + oval:ssg-state_file_permissions_unauthorized_sgid_dev_partitons:ste:1 + + + + + ^.*$ + oval:ssg-state_file_permissions_unauthorized_sgid_set:ste:1 + oval:ssg-state_file_permissions_unauthorized_sgid_sysroot:ste:1 + + + + .* + .* + .* + .* + .* + + + + oval:ssg-var_file_permissions_unauthorized_sgid_all_sgid_files:var:1 + oval:ssg-state_file_permissions_unauthorized_sgid_rpm_filepaths:ste:1 + + + .* + oval:ssg-state_file_permissions_unauthorized_suid_dev_partitons:ste:1 + + + + + ^.*$ + oval:ssg-state_file_permissions_unauthorized_suid_set:ste:1 + oval:ssg-state_file_permissions_unauthorized_suid_sysroot:ste:1 + + + + .* + .* + .* + .* + .* + + + + oval:ssg-var_file_permissions_unauthorized_suid_all_suid_files:var:1 + oval:ssg-state_file_permissions_unauthorized_suid_rpm_filepaths:ste:1 + + + .* + oval:ssg-state_file_permissions_unauthorized_world_writable_dev_partitons:ste:1 + + + + + ^.*$ + oval:ssg-state_file_permissions_unauthorized_world_write:ste:1 + oval:ssg-state_file_permissions_unauthorized_world_write_special_selinux_files:ste:1 + oval:ssg-state_file_permissions_unauthorized_world_write_sysroot:ste:1 + + + /etc/group + ^[^:]+:[^:]*:([\d]+):[^:]*$ + 1 + + + /usr/lib/group + ^[^:]+:[^:]*:([\d]+):[^:]*$ + 1 + + + + oval:ssg-object_etc_group:obj:1 + oval:ssg-object_usr_lib_group:obj:1 + + + + .* + oval:ssg-state_file_permissions_ungroupowned_dev_partitons:ste:1 + + + + + .* + oval:ssg-state_file_permissions_ungroupowned_local_group_owner:ste:1 + oval:ssg-state_file_permissions_ungroupowned_sysroot:ste:1 + + + + + .* + oval:ssg-state_file_permissions_ungroupowned_local_group_owner_with_usrlib:ste:1 + oval:ssg-state_file_permissions_ungroupowned_sysroot:ste:1 + + + /etc/nsswitch.conf + ^\s*group:\s+(.*)$ + 1 + + + .* + + + .* + oval:ssg-state_no_files_unowned_by_user_dev_partitons:ste:1 + + + + + .* + oval:ssg-state_no_files_unowned_by_user_uids_list:ste:1 + + + ^\/s?bin|^\/usr\/s?bin|^\/usr\/local\/s?bin + ^.*$ + oval:ssg-state_groupowner_system_commands_dirs_not_root_or_system_account:ste:1 + + + ^\/(|s)bin|^\/usr\/(|local\/)(|s)bin|^\/usr\/libexec + + oval:ssg-state_owner_binaries_not_root:ste:1 + + + ^\/(|s)bin|^\/usr\/(|local\/)(|s)bin|^\/usr\/libexec + ^.*$ + oval:ssg-state_owner_binaries_not_root:ste:1 + + + ^\/(|s)bin|^\/usr\/(|local\/)(|s)bin|^\/usr\/libexec + ^.*$ + oval:ssg-state_perms_binary_files_nogroupwrite_noworldwrite:ste:1 + oval:ssg-state_perms_binary_files_symlink:ste:1 + + + ^/(?!boot|efi)\w.*$ + oval:ssg-state_local_nodev:ste:1 + + + /etc/fstab + ^\s*(?!#)(?:/dev/\S+|UUID=\S+)\s+/\w\S*\s+\S+\s+(\S+) + 1 + + + kernel.core_pattern + + + oval:ssg-local_var_sysctl_kernel_core_pattern_empty_string_counter:var:1 + + + + oval:ssg-object_sysctl_kernel_core_pattern_empty_string_static_set_sysctls_unfiltered:obj:1 + oval:ssg-state_sysctl_kernel_core_pattern_empty_string_filepath_is_symlink:ste:1 + + + + + oval:ssg-var_obj_symlink_sysctl_kernel_core_pattern_empty_string:obj:1 + oval:ssg-var_obj_blank_sysctl_kernel_core_pattern_empty_string:obj:1 + + + + oval:ssg-local_var_blank_path_sysctl_kernel_core_pattern_empty_string:var:1 + + + oval:ssg-local_var_symlinks_sysctl_kernel_core_pattern_empty_string:var:1 + + + + oval:ssg-state_symlink_points_outside_usual_dirs_sysctl_kernel_core_pattern_empty_string:ste:1 + + + + oval:ssg-object_static_etc_sysctls_sysctl_kernel_core_pattern_empty_string:obj:1 + oval:ssg-object_static_run_usr_sysctls_sysctl_kernel_core_pattern_empty_string:obj:1 + + + + + oval:ssg-object_static_sysctl_sysctl_kernel_core_pattern_empty_string:obj:1 + oval:ssg-object_static_etc_sysctld_sysctl_kernel_core_pattern_empty_string:obj:1 + + + + + oval:ssg-object_static_run_sysctld_sysctl_kernel_core_pattern_empty_string:obj:1 + + + + /etc/sysctl.conf + ^[[:blank:]]*kernel.core_pattern[[:blank:]]*=[[:blank:]]*(.*)$ + 1 + + + /etc/sysctl.d + ^.*\.conf$ + ^[[:blank:]]*kernel.core_pattern[[:blank:]]*=[[:blank:]]*(.*)$ + 1 + + + /run/sysctl.d + ^.*\.conf$ + ^[[:blank:]]*kernel.core_pattern[[:blank:]]*=[[:blank:]]*(.*)$ + 1 + + + /etc/systemd/coredump.conf + ^\s*\[Coredump\].*(?:\n\s*[^[\s].*)*\n^[ \t]*(?i)ProcessSizeMax(?-i)[ \t]*=[ \t]*(.+?)[ \t]*(?:$|#) + 1 + + + /etc/systemd/coredump.conf.d + .*\.conf$ + ^\s*\[Coredump\].*(?:\n\s*[^[\s].*)*\n^[ \t]*(?i)ProcessSizeMax(?-i)[ \t]*=[ \t]*(.+?)[ \t]*(?:$|#) + 1 + + + /etc/systemd/coredump.conf + ^\s*\[Coredump\].*(?:\n\s*[^[\s].*)*\n^[ \t]*(?i)Storage(?-i)[ \t]*=[ \t]*(.+?)[ \t]*(?:$|#) + 1 + + + /etc/systemd/coredump.conf.d + .*\.conf$ + ^\s*\[Coredump\].*(?:\n\s*[^[\s].*)*\n^[ \t]*(?i)Storage(?-i)[ \t]*=[ \t]*(.+?)[ \t]*(?:$|#) + 1 + + + /etc/security/limits.conf + ^[\s]*\*[\s]+(?:hard|-)[\s]+core[\s]+([\d]+) + 1 + + + /etc/security/limits.d + ^.*\.conf$ + ^[\s]*\*[\s]+(?:hard|-)[\s]+core[\s]+([\d]+) + 1 + + + /etc/security/limits.d + ^.*\.conf$ + ^[\s]*\*[\s]+(?:hard|-)[\s]+core + 1 + + + /boot/grub2/grub.cfg + [\s]*noexec[\s]*=[\s]*off + 1 + + + /proc/cpuinfo + ^flags[\s]+:.*[\s]+nx[\s]+.*$ + 1 + + + /proc/cmdline + .+noexec[0-9]*=off.+ + 1 + + + /etc/default/grub + ^[\s]*GRUB_CMDLINE_LINUX.*(selinux|enforcing)=0.*$ + 1 + + + /etc/grub2.cfg + ^.*(selinux|enforcing)=0.*$ + 1 + + + /etc/grub.d + ^.*$ + ^.*(selinux|enforcing)=0.*$ + 1 + + + + /dev + ^.*$ + oval:ssg-state_block_or_char_device_file:ste:1 + + + + oval:ssg-state_selinux_dev_device_t:ste:1 + + + + oval:ssg-state_selinux_dev_unlabeled_t:ste:1 + + + + /proc + ^.*$ + oval:ssg-state_selinux_confinement_of_daemons:ste:1 + + + /etc/selinux/config + ^SELINUX=(.*)$ + 1 + + + /etc/selinux/config + ^SELINUXTYPE=([\w]*)[\s]*$ + 1 + + + /etc/selinux/config + ^SELINUX=(.*)$ + 1 + + + kernel + + + /proc/cpuinfo + ^flags\s+:\s+(.*)$ + 1 + + + /proc/sys/kernel/osrelease + ^.*\.(.*)$ + 1 + + + /etc/dconf/db/local + + + ^/etc/dconf/db/local.d/.* + + + oval:ssg-var_dconf_local_db_modified_time:var:1 + + + /etc/dconf/profile/user + ^user-db:user\nsystem-db:local$ + 1 + + + /etc/dconf/db/local.d/ + ^.*$ + ^\[org/gnome/login-screen\]([^\n]*\n+)+?disable-restart-buttons=true$ + 1 + + + /etc/dconf/db/local.d/locks/ + ^.*$ + ^/org/gnome/login-screen/disable-restart-buttons$ + 1 + + + /etc/dconf/db/local.d/ + ^.*$ + ^\[org/gnome/login-screen\]([^\n]*\n+)+?disable-user-list=true$ + 1 + + + /etc/dconf/db/local.d/locks/ + ^.*$ + ^/org/gnome/login-screen/disable-user-list$ + 1 + + + /etc/gdm/custom.conf + ^\[daemon]([^\n]*\n+)+?AutomaticLoginEnable=[Ff]alse$ + 1 + + + /etc/gdm/custom.conf + ^\s*\[xdmcp\].*(?:\n\s*[^[\s].*)*\n^\s*Enable[ \t]*=[ \t]*(.+?)[ \t]*(?:$|#) + 1 + + + ^/etc/gdm/custom.conf + + + /etc/dconf/db/local.d/ + ^.*$ + ^\[org/gnome/desktop/media-handling\]([^\n]*\n+)+?automount=false$ + 1 + + + /etc/dconf/db/local.d/locks/ + ^.*$ + ^/org/gnome/desktop/media-handling/automount$ + 1 + + + /etc/dconf/db/local.d/ + ^.*$ + ^\[org/gnome/desktop/media-handling\]([^\n]*\n+)+?automount-open=false$ + 1 + + + /etc/dconf/db/local.d/locks/ + ^.*$ + ^/org/gnome/desktop/media-handling/automount-open$ + 1 + + + /etc/dconf/db/local.d/ + ^.*$ + ^\[org/gnome/desktop/media-handling\]([^\n]*\n+)+?autorun-never=true$ + 1 + + + /etc/dconf/db/local.d/locks/ + ^.*$ + ^/org/gnome/desktop/media-handling/autorun-never$ + 1 + + + /etc/dconf/db/local.d/ + ^.*$ + ^\[org/gnome/Vino\]([^\n]*\n+)+?authentication-methods=\['vnc'\]$ + 1 + + + /etc/dconf/db/local.d/locks/ + ^.*$ + ^/org/gnome/Vino/authentication-methods$ + 1 + + + /etc/dconf/db/local.d/ + ^.*$ + ^\[org/gnome/Vino\]([^\n]*\n+)+?require-encryption=true$ + 1 + + + /etc/dconf/db/local.d/locks/ + ^.*$ + ^/org/gnome/Vino/require-encryption$ + 1 + + + /etc/dconf/db/local.d/ + ^.*$ + ^\[org/gnome/desktop/screensaver\]([^\n]*\n+)+?idle-activation-enabled=true$ + 1 + + + /etc/dconf/db/local.d/locks/ + ^.*$ + ^/org/gnome/desktop/screensaver/idle-activation-enabled$ + 1 + + + /etc/dconf/db/local.d/ + ^.*$ + ^\[org/gnome/desktop/session\]([^\n]*\n+)+?idle-delay=uint32[\s][0-9]*$ + 1 + + + /etc/dconf/db/local.d/ + ^.*$ + ^idle-delay[\s=]*uint32[\s]([^=\s]*) + 1 + + + /etc/dconf/db/local.d/ + ^.*$ + ^\[org/gnome/desktop/screensaver\]([^\n]*\n+)+?lock-delay=uint32[\s][0-9]*$ + 1 + + + /etc/dconf/db/local.d/ + ^.*$ + ^lock-delay[\s=]*uint32[\s]([^=\s]*) + 1 + + + /etc/dconf/db/local.d/ + ^.*$ + ^\[org/gnome/desktop/screensaver\]([^\n]*\n+)+?lock-enabled=true$ + 1 + + + /etc/dconf/db/local.d/locks/ + ^.*$ + ^/org/gnome/desktop/screensaver/lock-enabled$ + 1 + + + /etc/dconf/db/local.d/ + ^.*$ + ^\[org/gnome/desktop/screensaver\]([^\n]*\n+)+?picture-uri=string \'\'$ + 1 + + + /etc/dconf/db/local.d/locks/ + ^.*$ + ^/org/gnome/desktop/screensaver/picture-uri$ + 1 + + + /etc/dconf/db/local.d/locks/ + ^.*$ + ^/org/gnome/desktop/screensaver/lock-delay$ + 1 + + + /etc/dconf/db/local.d/locks/ + ^.*$ + ^/org/gnome/desktop/session/idle-delay$ + 1 + + + /etc/dconf/db/local.d/ + ^.*$ + ^\[org/gnome/settings-daemon/plugins/media-keys\]([^\n]*\n+)+?logout[\s]*=[\s]*\[''\]$ + 1 + + + /etc/dconf/db/local.d/locks/ + ^.*$ + ^/org/gnome/settings-daemon/plugins/media-keys/logout$ + 1 + + + /etc/named.conf + ^\s*include\s+"/etc/crypto-policies/back-ends/bind.config"\s*;\s*$ + 1 + + + /etc/crypto-policies/state/current + + + /etc/crypto-policies/config + + + oval:ssg-variable_crypto_policies_config_file_timestamp:var:1 + + + /etc/crypto-policies/config + ^(?!#)(\S+)$ + 1 + + + /etc/crypto-policies/state/current + ^(?!#)(\S+)$ + 1 + + + /etc/crypto-policies/back-ends/nss.config + + + oval:ssg-var_symlink_kerberos_crypto_policy_configuration:var:1 + + + /etc/krb5.conf.d/crypto-policies + + + /etc/crypto-policies/back-ends/krb5.config + + + /etc/ipsec.conf + ^\s*include\s+/etc/crypto-policies/back-ends/libreswan.config\s*(?:#.*)?$ + 1 + + + /etc/pki/tls/openssl.cnf + ^\s*\[\s*crypto_policy\s*\]\s*\n*\s*\.include\s*(?:=\s*)?/etc/crypto-policies/back-ends/opensslcnf.config\s*$ + 1 + + + /etc/sysconfig/sshd + ^\s*(?i)CRYPTO_POLICY\s*=.*$ + 1 + + + /etc/ssh/ssh_config.d/02-ospp.conf + ^[ \t]*Match[\s]+(.+?)[ \t]*(?:$|#) + 1 + + + /etc/ssh/ssh_config.d/02-ospp.conf + ^Match final all(?:.* +)*?\s*RekeyLimit[\s]+(.+?)[ \t]*(?:$|#) + 1 + + + /etc/ssh/ssh_config.d/02-ospp.conf + ^Match final all(?:.* +)*?\s*GSSAPIAuthentication[\s]+(.+?)[ \t]*(?:$|#) + 1 + + + /etc/ssh/ssh_config.d/02-ospp.conf + ^Match final all(?:.* +)*?\s*Ciphers[\s]+(.+?)[ \t]*(?:$|#) + 1 + + + /etc/ssh/ssh_config.d/02-ospp.conf + ^Match final all(?:.* +)*?\s*PubkeyAcceptedKeyTypes[\s]+(.+?)[ \t]*(?:$|#) + 1 + + + /etc/ssh/ssh_config.d/02-ospp.conf + ^Match final all(?:.* +)*?\s*MACs[\s]+(.+?)[ \t]*(?:$|#) + 1 + + + /etc/ssh/ssh_config.d/02-ospp.conf + ^Match final all(?:.* +)*?\s*KexAlgorithms[\s]+(.+?)[ \t]*(?:$|#) + 1 + + + /etc/crypto-policies/back-ends/openssh.config + ^Ciphers.*$ + 1 + + + /etc/crypto-policies/back-ends/opensshserver.config + ^(?!#).*Ciphers\s+([^\s']+).*$ + 1 + + + /etc/crypto-policies/back-ends/openssh.config + ^MACs.*$ + 1 + + + /etc/crypto-policies/back-ends/opensshserver.config + ^(?!#).*(-oMACs=\S+).+$ + 1 + + + ^mfetpd.*$ + 0 + + + /etc/dracut.conf.d/40-fips.conf + ^\s*add_dracutmodules\+="\s*(\w*)\s*"\s*(?:#.*)?$ + 1 + + + ^/boot/loader/entries/.*.conf + ^options (.*)$ + 1 + + + oval:ssg-var_system_crypto_policy:var:1 + + + /proc/sys/crypto/fips_enabled + ^1$ + 1 + + + /etc/system-fips + + + crypto.fips_enabled + + + /etc/aide.conf + ^database=file:@@{DBDIR}/([a-z.]+)$ + 1 + + + /etc/aide.conf + ^@@define[\s]DBDIR[\s]+(/.*)$ + 1 + + + + + + /etc/aide.conf + ^\/usr\/sbin\/auditctl\s+([^\n]+)$ + 1 + + + /etc/aide.conf + ^/usr/sbin/auditd\s+([^\n]+)$ + 1 + + + /etc/aide.conf + ^/usr/sbin/ausearch\s+([^\n]+)$ + 1 + + + /etc/aide.conf + ^/usr/sbin/aureport\s+([^\n]+)$ + 1 + + + /etc/aide.conf + ^/usr/sbin/autrace\s+([^\n]+)$ + 1 + + + /etc/aide.conf + ^/usr/sbin/rsyslogd\s+([^\n]+)$ + 1 + + + /etc/aide.conf + ^/usr/sbin/augenrules\s+([^\n]+)$ + 1 + + + /etc/crontab + ^(([0-9]*[\s]*[0-9]*[\s]*\*[\s]*\*[\s]*(\*|([0-7]|mon|tue|wed|thu|fri|sat|sun)|[0-7]-[0-7]))|@(hourly|daily|weekly))[\s]*root[\s]*\/usr\/sbin\/aide[\s]*\-\-check.*$ + 1 + + + /etc/cron.d + ^.*$ + ^(([0-9]*[\s]*[0-9]*[\s]*\*[\s]*\*[\s]*(\*|([0-7]|mon|tue|wed|thu|fri|sat|sun)|[0-7]-[0-7]))|@(hourly|daily|weekly))[\s]*root[\s]*\/usr\/sbin\/aide[\s]*\-\-check.*$ + 1 + + + /var/spool/cron/root + ^(([0-9]*[\s]*[0-9]*[\s]*\*[\s]*\*[\s]*(\*|([0-7]|mon|tue|wed|thu|fri|sat|sun)|[0-7]-[0-7]))|@(hourly|daily|weekly))[\s]*(root)?[\s]*\/usr\/sbin\/aide[\s]*\-\-check.*$ + 1 + + + ^/etc/cron.(daily|weekly)$ + ^.*$ + ^[^#]*\/usr\/sbin\/aide\s+\-\-check\s*$ + 1 + + + /etc/crontab + ^.*/usr/sbin/aide[\s]*\-\-check.*\|.*/bin/mail[\s]*-s[\s]*".*"[\s]*.+@.+$ + 1 + + + /var/spool/cron/root + ^.*/usr/sbin/aide[\s]*\-\-check.*\|.*/bin/mail[\s]*-s[\s]*".*"[\s]*.+@.+$ + 1 + + + ^/etc/cron.(d|daily|weekly|monthly)$ + ^.*$ + ^.*/usr/sbin/aide[\s]*\-\-check.*\|.*/bin/mail[\s]*-s[\s]*".*"[\s]*.+@.+$ + 1 + + + /etc/aide.conf + ^[A-Z][a-zA-Z_]*[\s]*=[\s]*.*(sha1|rmd160|sha256|whirlpool|tiger|haval|gost|crc32).*$ + 0 + + + /etc/aide.conf + ^[A-Z][A-Za-z_]*[\s]*=[\s]*([a-zA-Z0-9\+]*)$ + 1 + + + /etc/aide.conf + ^(?!ALLXTRAHASHES)[A-Z][a-zA-Z_]*[\s]*=[\s]*([a-zA-Z0-9\+]*)$ + 1 + + + /etc/aide.conf + ^(?!ALLXTRAHASHES)[A-Z][a-zA-Z_]*[\s]*=[\s]*([a-zA-Z0-9\+]*)$ + 1 + + + + .* + .* + .* + .* + .* + ^/(bin|sbin|lib|lib64|usr)/.+$ + oval:ssg-state_rpm_verify_hashes_fail_md5_hash:ste:1 + + + + .* + .* + .* + .* + .* + .* + oval:ssg-state_rpm_verify_ownership_files_fail_ownership:ste:1 + + + + .* + .* + .* + .* + .* + .* + oval:ssg-state_rpm_verify_permissions_files_fail_mode:ste:1 + + + /usr/bin/sudo + + + /etc/group + + 1 + + + /etc/sudoers + ^(?!#).*[\s]+\!authenticate.*$ + 1 + + + /etc/sudoers.d + ^.*$ + ^(?!#).*[\s]+\!authenticate.*$ + 1 + + + /etc/sudoers + ^(?!#).*[\s]+NOPASSWD[\s]*\:.*$ + 1 + + + /etc/sudoers.d + ^.*$ + ^(?!#).*[\s]+NOPASSWD[\s]*\:.*$ + 1 + + + ^\/etc\/(sudoers|sudoers\.d\/.*)$ + ^[\s]*Defaults[\s]+timestamp_timeout[\s]*=\s*[+]?(\d*\.\d+|\d+\.\d*|\d+)$ + 1 + + + ^\/etc\/(sudoers|sudoers\.d\/.*)$ + ^[\s]*Defaults[\s]+timestamp_timeout[\s]*=\s*[\-](\d*\.\d+|\d+\.\d*|\d+)$ + 1 + + + ^/etc/sudoers(\.d/.*)?$ + ^\s*ALL\s+ALL\=\(ALL\)\s+ALL\s*$ + 1 + + + ^/etc/sudoers(\.d/.*)?$ + ^\s*ALL\s+ALL\=\(ALL\:ALL\)\s+ALL\s* + 1 + + + /etc/sudoers + ^(?!(#|vdsm.*)).*[\s]+NOPASSWD[\s]*\:.*$ + 1 + + + /etc/sudoers.d + ^.*$ + ^(?!(#|vdsm.*)).*[\s]+NOPASSWD[\s]*\:.*$ + 1 + + + ^/etc/sudoers(\.d/.*)?$ + ^(?!\s*Defaults)(?:\s*[^#=]+)=(?:\s*(?:\([^\)]+\))?\s*(?!\s*\()[^,\s]+(?:[ \t]+[^,\s]+)+[ \t]*,)*(\s*(?:\([^\)]+\))?\s*(?!\s*\()[^,\s]+[ \t]*(?:,|$)) + 1 + + + ^/etc/sudoers(\.d/.*)?$ + ^(?:\s*[^#=]+)=(?:\s*(?:\([^\)]+\))?\s*(?!\s*\()[^,!\n][^,\n]+,)*\s*(?:\([^\)]+\))?\s*(?!\s*\()(!\S+).* + 1 + + + ^/etc/sudoers(\.d/.*)?$ + ^\s*((?!root\b)[\w]+)\s*(\w+)\s*=\s*(.*,)?\s*\([\w\s]*\b(root|ALL)\b[\w\s]*\) + 1 + + + ^/etc/sudoers(\.d/.*)?$ + ^\s*((?!root\b)[\w]+)\s*(\w+)\s*=\s*(.*,)?\s*[^\(\s] + 1 + + + ^/etc/sudoers(\.d/.*)?$ + ^Defaults !targetpw$\r?\n + 1 + + + ^/etc/sudoers(\.d/.*)?$ + ^Defaults !rootpw$\r?\n + 1 + + + ^/etc/sudoers(\.d/.*)?$ + ^Defaults !runaspw$\r?\n + 1 + + + ^/etc/sudoers(\.d/.*)?$ + ^Defaults targetpw$\r?\n + 1 + + + ^/etc/sudoers(\.d/.*)?$ + ^Defaults rootpw$\r?\n + 1 + + + ^/etc/sudoers(\.d/.*)?$ + ^Defaults runaspw$\r?\n + 1 + + + /etc/yum.conf + ^\s*clean_requirements_on_remove\s*=\s*(1|True|yes)\s*$ + 1 + + + /etc/dnf/automatic.conf + ^\s*\[commands\].*(?:\n\s*[^[\s].*)*\n^\s*apply_updates[ \t]*=[ \t]*(.+?)[ \t]*(?:$|#) + 1 + + + ^/etc/dnf/automatic.conf + + + /etc/dnf/automatic.conf + ^\s*\[commands\].*(?:\n\s*[^[\s].*)*\n^\s*upgrade_type[ \t]*=[ \t]*(.+?)[ \t]*(?:$|#) + 1 + + + ^/etc/dnf/automatic.conf + + + /etc/yum.conf + ^\s*gpgcheck\s*=\s*(1|True|yes)\s*$ + 1 + + + /etc/yum.conf + ^\s*localpkg_gpgcheck\s*=\s*(1|True|yes)\s*$ + 1 + + + /etc/yum.repos.d + .* + ^\s*gpgcheck\s*=\s*0\s*$ + 1 + + + gpg-pubkey + + + /etc/pam.d/system-auth + ^\s*password.*pam_pwquality\.so.*\bdcredit\b + 1 + + + ^/etc/security/pwquality\.conf$ + ^\s*dcredit[\s]*=[\s]*(-?\d+)(?:[\s]|$) + 1 + + + /etc/pam.d/system-auth + ^\s*password.*pam_pwquality\.so.*\bdictcheck\b + 1 + + + ^/etc/security/pwquality\.conf$ + ^\s*dictcheck[\s]*=[\s]*(-?\d+)(?:[\s]|$) + 1 + + + /etc/pam.d/system-auth + ^\s*password.*pam_pwquality\.so.*\bdifok\b + 1 + + + ^/etc/security/pwquality\.conf$ + ^\s*difok[\s]*=[\s]*(-?\d+)(?:[\s]|$) + 1 + + + /etc/pam.d/system-auth + ^\s*password.*pam_pwquality\.so.*\blcredit\b + 1 + + + ^/etc/security/pwquality\.conf$ + ^\s*lcredit[\s]*=[\s]*(-?\d+)(?:[\s]|$) + 1 + + + /etc/pam.d/system-auth + ^\s*password.*pam_pwquality\.so.*\bmaxclassrepeat\b + 1 + + + ^/etc/security/pwquality\.conf$ + ^\s*maxclassrepeat[\s]*=[\s]*(-?\d+)(?:[\s]|$) + 1 + + + /etc/pam.d/system-auth + ^\s*password.*pam_pwquality\.so.*\bmaxrepeat\b + 1 + + + ^/etc/security/pwquality\.conf$ + ^\s*maxrepeat[\s]*=[\s]*(-?\d+)(?:[\s]|$) + 1 + + + /etc/pam.d/system-auth + ^\s*password.*pam_pwquality\.so.*\bminclass\b + 1 + + + ^/etc/security/pwquality\.conf$ + ^\s*minclass[\s]*=[\s]*(-?\d+)(?:[\s]|$) + 1 + + + /etc/pam.d/system-auth + ^\s*password.*pam_pwquality\.so.*\bminlen\b + 1 + + + ^/etc/security/pwquality\.conf$ + ^\s*minlen[\s]*=[\s]*(-?\d+)(?:[\s]|$) + 1 + + + /etc/pam.d/system-auth + ^\s*password.*pam_pwquality\.so.*\bocredit\b + 1 + + + ^/etc/security/pwquality\.conf$ + ^\s*ocredit[\s]*=[\s]*(-?\d+)(?:[\s]|$) + 1 + + + /etc/pam.d/system-auth + ^\s*password.*pam_pwquality\.so.*\bucredit\b + 1 + + + ^/etc/security/pwquality\.conf$ + ^\s*ucredit[\s]*=[\s]*(-?\d+)(?:[\s]|$) + 1 + + + /etc/pam.d/system-auth + + 1 + + + /etc/pam.d/system-auth + + 1 + + + /etc/pam.d/password-auth + + 1 + + + /etc/pam.d/password-auth + + 1 + + + /etc/pam.d/system-auth + + 1 + + + /etc/pam.d/password-auth + + 1 + + + /etc/pam.d/system-auth + + 1 + + + /etc/pam.d/password-auth + + 1 + + + /etc/security/faillock.conf + + 1 + + + /etc/pam.d/system-auth + + 1 + + + /etc/pam.d/system-auth + + 1 + + + /etc/pam.d/password-auth + + 1 + + + /etc/pam.d/password-auth + + 1 + + + /etc/pam.d/system-auth + + 1 + + + /etc/pam.d/password-auth + + 1 + + + /etc/pam.d/system-auth + + 1 + + + /etc/pam.d/password-auth + + 1 + + + /etc/security/faillock.conf + + 1 + + + /etc/pam.d/system-auth + + 1 + + + /etc/pam.d/system-auth + + 1 + + + /etc/pam.d/password-auth + + 1 + + + /etc/pam.d/password-auth + + 1 + + + /etc/pam.d/system-auth + + 1 + + + /etc/pam.d/password-auth + + 1 + + + /etc/pam.d/system-auth + + 1 + + + /etc/pam.d/password-auth + + 1 + + + /etc/security/faillock.conf + + 1 + + + + /etc/audit/rules.d/30-ospp-v42-3-access-failed.rules + ^.*$ + 1 + + + + /etc/audit/rules.d/30-ospp-v42-3-access-success.rules + ^.*$ + 1 + + + + /etc/audit/rules.d/10-base-config.rules + ^.*$ + 1 + + + + /etc/audit/rules.d/30-ospp-v42-1-create-failed.rules + ^.*$ + 1 + + + + /etc/audit/rules.d/30-ospp-v42-1-create-success.rules + ^.*$ + 1 + + + + /etc/audit/rules.d/30-ospp-v42-4-delete-failed.rules + ^.*$ + 1 + + + + /etc/audit/rules.d/30-ospp-v42-4-delete-success.rules + ^.*$ + 1 + + + + /etc/audit/rules.d/11-loginuid.rules + ^.*$ + 1 + + + + /etc/audit/rules.d/30-ospp-v42-2-modify-failed.rules + ^.*$ + 1 + + + + /etc/audit/rules.d/30-ospp-v42-2-modify-success.rules + ^.*$ + 1 + + + + /etc/audit/rules.d/43-module-load.rules + ^.*$ + 1 + + + + /etc/audit/rules.d/30-ospp-v42.rules + ^.*$ + 1 + + + + /etc/audit/rules.d/30-ospp-v42-6-owner-change-failed.rules + ^.*$ + 1 + + + + /etc/audit/rules.d/30-ospp-v42-6-owner-change-success.rules + ^.*$ + 1 + + + + /etc/audit/rules.d/30-ospp-v42-5-perm-change-failed.rules + ^.*$ + 1 + + + + /etc/audit/rules.d/30-ospp-v42-5-perm-change-success.rules + ^.*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/init(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/init(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/poweroff(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/poweroff(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/reboot(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/reboot(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/shutdown(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/shutdown(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+chmod[\s]+|([\s]+|[,])chmod([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+chmod[\s]+|([\s]+|[,])chmod([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+chmod[\s]+|([\s]+|[,])chmod([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+chmod[\s]+|([\s]+|[,])chmod([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+chown[\s]+|([\s]+|[,])chown([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+chown[\s]+|([\s]+|[,])chown([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+chown[\s]+|([\s]+|[,])chown([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+chown[\s]+|([\s]+|[,])chown([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+fchmod[\s]+|([\s]+|[,])fchmod([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+fchmod[\s]+|([\s]+|[,])fchmod([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+fchmod[\s]+|([\s]+|[,])fchmod([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+fchmod[\s]+|([\s]+|[,])fchmod([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+fchmodat[\s]+|([\s]+|[,])fchmodat([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+fchmodat[\s]+|([\s]+|[,])fchmodat([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+fchmodat[\s]+|([\s]+|[,])fchmodat([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+fchmodat[\s]+|([\s]+|[,])fchmodat([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+fchown[\s]+|([\s]+|[,])fchown([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+fchown[\s]+|([\s]+|[,])fchown([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+fchown[\s]+|([\s]+|[,])fchown([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+fchown[\s]+|([\s]+|[,])fchown([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+fchownat[\s]+|([\s]+|[,])fchownat([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+fchownat[\s]+|([\s]+|[,])fchownat([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+fchownat[\s]+|([\s]+|[,])fchownat([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+fchownat[\s]+|([\s]+|[,])fchownat([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+fremovexattr[\s]+|([\s]+|[,])fremovexattr([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+fremovexattr[\s]+|([\s]+|[,])fremovexattr([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+fremovexattr[\s]+|([\s]+|[,])fremovexattr([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+fremovexattr[\s]+|([\s]+|[,])fremovexattr([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+fsetxattr[\s]+|([\s]+|[,])fsetxattr([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+fsetxattr[\s]+|([\s]+|[,])fsetxattr([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+fsetxattr[\s]+|([\s]+|[,])fsetxattr([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+fsetxattr[\s]+|([\s]+|[,])fsetxattr([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+lchown[\s]+|([\s]+|[,])lchown([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+lchown[\s]+|([\s]+|[,])lchown([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+lchown[\s]+|([\s]+|[,])lchown([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+lchown[\s]+|([\s]+|[,])lchown([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+lremovexattr[\s]+|([\s]+|[,])lremovexattr([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+lremovexattr[\s]+|([\s]+|[,])lremovexattr([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+lremovexattr[\s]+|([\s]+|[,])lremovexattr([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+lremovexattr[\s]+|([\s]+|[,])lremovexattr([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+lsetxattr[\s]+|([\s]+|[,])lsetxattr([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+lsetxattr[\s]+|([\s]+|[,])lsetxattr([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+lsetxattr[\s]+|([\s]+|[,])lsetxattr([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+lsetxattr[\s]+|([\s]+|[,])lsetxattr([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+removexattr[\s]+|([\s]+|[,])removexattr([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+removexattr[\s]+|([\s]+|[,])removexattr([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+removexattr[\s]+|([\s]+|[,])removexattr([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+removexattr[\s]+|([\s]+|[,])removexattr([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+setxattr[\s]+|([\s]+|[,])setxattr([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+setxattr[\s]+|([\s]+|[,])setxattr([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+setxattr[\s]+|([\s]+|[,])setxattr([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+setxattr[\s]+|([\s]+|[,])setxattr([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+umount2[\s]+|([\s]+|[,])umount2([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+umount2[\s]+|([\s]+|[,])umount2([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+umount2[\s]+|([\s]+|[,])umount2([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+umount2[\s]+|([\s]+|[,])umount2([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/chacl(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/chacl(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/chcon(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/chcon(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/restorecon(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/restorecon(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/semanage(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/semanage(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/setfacl(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/setfacl(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/setfiles(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/setfiles(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/setsebool(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/setsebool(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/seunshare(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/seunshare(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+rename[\s]+|([\s]+|[,])rename([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+rename[\s]+|([\s]+|[,])rename([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+rename[\s]+|([\s]+|[,])rename([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+rename[\s]+|([\s]+|[,])rename([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+renameat[\s]+|([\s]+|[,])renameat([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+renameat[\s]+|([\s]+|[,])renameat([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+renameat[\s]+|([\s]+|[,])renameat([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+renameat[\s]+|([\s]+|[,])renameat([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+rmdir[\s]+|([\s]+|[,])rmdir([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+rmdir[\s]+|([\s]+|[,])rmdir([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+rmdir[\s]+|([\s]+|[,])rmdir([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+rmdir[\s]+|([\s]+|[,])rmdir([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+unlink[\s]+|([\s]+|[,])unlink([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+unlink[\s]+|([\s]+|[,])unlink([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+unlink[\s]+|([\s]+|[,])unlink([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+unlink[\s]+|([\s]+|[,])unlink([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+unlinkat[\s]+|([\s]+|[,])unlinkat([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+unlinkat[\s]+|([\s]+|[,])unlinkat([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+unlinkat[\s]+|([\s]+|[,])unlinkat([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+unlinkat[\s]+|([\s]+|[,])unlinkat([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + + 1 + + + /etc/audit/audit.rules + + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + + 1 + + + /etc/audit/audit.rules + + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + + 1 + + + /etc/audit/audit.rules + + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+mount[\s]+|([\s]+|[,])mount([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+mount[\s]+|([\s]+|[,])mount([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+mount[\s]+|([\s]+|[,])mount([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+mount[\s]+|([\s]+|[,])mount([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/at(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/at(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/chage(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/chage(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/chsh(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/chsh(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/crontab(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/crontab(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/gpasswd(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/gpasswd(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/kmod(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/kmod(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/mount(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/mount(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/newgrp(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/newgrp(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/pam_timestamp_check(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/pam_timestamp_check(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/passwd(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/passwd(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/postdrop(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/postdrop(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/postqueue(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/postqueue(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/ssh-agent(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/ssh-agent(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/libexec\/openssh\/ssh-keysign(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/libexec\/openssh\/ssh-keysign(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/su(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/su(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/sudo(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/sudo(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/sudoedit(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/sudoedit(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/umount(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/umount(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/unix_chkpwd(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/unix_chkpwd(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/unix_update(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/unix_update(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/userhelper(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/userhelper(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/usermod(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/usermod(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/usernetctl(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/usernetctl(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + + 1 + + + /etc/audit/audit.rules + + 1 + + + /etc/audit/audit.rules + + 1 + + + /etc/audit/audit.rules + + 1 + + + /etc/audit/audit.rules + + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + + 1 + + + /etc/audit/audit.rules + + 1 + + + /etc/audit/audit.rules + + 1 + + + /etc/audit/audit.rules + + 1 + + + /etc/audit/audit.rules + + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + + 1 + + + /etc/audit/audit.rules + + 1 + + + /etc/audit/audit.rules + + 1 + + + /etc/audit/audit.rules + + 1 + + + /etc/audit/audit.rules + + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + + 1 + + + /etc/audit/audit.rules + + 1 + + + /etc/audit/audit.rules + + 1 + + + /etc/audit/audit.rules + + 1 + + + /etc/audit/audit.rules + + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + + 1 + + + /etc/audit/audit.rules + + 1 + + + /etc/audit/audit.rules + + 1 + + + /etc/audit/audit.rules + + 1 + + + /etc/audit/audit.rules + + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + + 1 + + + /etc/audit/audit.rules + + 1 + + + /etc/audit/audit.rules + + 1 + + + /etc/audit/audit.rules + + 1 + + + /etc/audit/audit.rules + + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^\-w[\s]+\/etc\/group[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + 1 + + + /etc/audit/audit.rules + ^\-w[\s]+\/etc\/group[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^\-w[\s]+\/etc\/gshadow[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + 1 + + + /etc/audit/audit.rules + ^\-w[\s]+\/etc\/gshadow[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^\-w[\s]+\/etc\/security\/opasswd[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + 1 + + + /etc/audit/audit.rules + ^\-w[\s]+\/etc\/security\/opasswd[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^\-w[\s]+\/etc\/passwd[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + 1 + + + /etc/audit/audit.rules + ^\-w[\s]+\/etc\/passwd[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^\-w[\s]+\/etc\/shadow[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + 1 + + + /etc/audit/audit.rules + ^\-w[\s]+\/etc\/shadow[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + + 1 + + + /etc/audit/audit.rules + + 1 + + + /etc/audit/auditd.conf + ^[ \t]*(?i)freq(?-i)[ \t]*=[ \t]*(.+?)[ \t]*(?:$|#) + 1 + + + /etc/audit/auditd.conf + ^[ \t]*(?i)local_events(?-i)[ \t]*=[ \t]*(.+?)[ \t]*(?:$|#) + 1 + + + /etc/audit/auditd.conf + ^[ \t]*(?i)log_format(?-i)[ \t]*=[ \t]*(.+?)[ \t]*(?:$|#) + 1 + + + /etc/audit/auditd.conf + ^[ \t]*(?i)write_logs(?-i)[ \t]*=[ \t]*(.+?)[ \t]*(?:$|#) + 1 + + + /etc/audit/auditd.conf + ^[ \t]*(?i)write_logs(?-i)[ \t]*=[ \t]* + 1 + + + /etc/dconf/db/local.d/ + ^.*$ + ^\s*\[org/gnome/settings-daemon/peripherals/smartcard\].*(?:\n\s*[^[\s].*)*\n^\s*removal-action[ \t]*=[ \t]*(.+?)[ \t]*(?:$|#) + 1 + + + /etc/dconf/db/local.d/locks + ^.*$ + ^/org/gnome/settings-daemon/peripherals/smartcard/removal-action$ + 1 + + + + /lib + + oval:ssg-symlink_file_groupownerdir_group_ownership_library_dirs_uid_0:ste:1 + oval:ssg-state_file_groupownerdir_group_ownership_library_dirs_gid_0_0:ste:1 + + + + /lib64 + + oval:ssg-symlink_file_groupownerdir_group_ownership_library_dirs_uid_0:ste:1 + oval:ssg-state_file_groupownerdir_group_ownership_library_dirs_gid_0_1:ste:1 + + + + /usr/lib + + oval:ssg-symlink_file_groupownerdir_group_ownership_library_dirs_uid_0:ste:1 + oval:ssg-state_file_groupownerdir_group_ownership_library_dirs_gid_0_2:ste:1 + + + + /usr/lib64 + + oval:ssg-symlink_file_groupownerdir_group_ownership_library_dirs_uid_0:ste:1 + oval:ssg-state_file_groupownerdir_group_ownership_library_dirs_gid_0_3:ste:1 + + + + /bin + + oval:ssg-symlink_file_ownerdir_ownership_binary_dirs_uid_0:ste:1 + oval:ssg-state_file_ownerdir_ownership_binary_dirs_uid_0_0:ste:1 + + + + /sbin + + oval:ssg-symlink_file_ownerdir_ownership_binary_dirs_uid_0:ste:1 + oval:ssg-state_file_ownerdir_ownership_binary_dirs_uid_0_1:ste:1 + + + + /usr/bin + + oval:ssg-symlink_file_ownerdir_ownership_binary_dirs_uid_0:ste:1 + oval:ssg-state_file_ownerdir_ownership_binary_dirs_uid_0_2:ste:1 + + + + /usr/sbin + + oval:ssg-symlink_file_ownerdir_ownership_binary_dirs_uid_0:ste:1 + oval:ssg-state_file_ownerdir_ownership_binary_dirs_uid_0_3:ste:1 + + + + /usr/local/bin + + oval:ssg-symlink_file_ownerdir_ownership_binary_dirs_uid_0:ste:1 + oval:ssg-state_file_ownerdir_ownership_binary_dirs_uid_0_4:ste:1 + + + + /usr/local/sbin + + oval:ssg-symlink_file_ownerdir_ownership_binary_dirs_uid_0:ste:1 + oval:ssg-state_file_ownerdir_ownership_binary_dirs_uid_0_5:ste:1 + + + + /lib + + oval:ssg-symlink_file_ownerdir_ownership_library_dirs_uid_0:ste:1 + oval:ssg-state_file_ownerdir_ownership_library_dirs_uid_0_0:ste:1 + + + + /lib64 + + oval:ssg-symlink_file_ownerdir_ownership_library_dirs_uid_0:ste:1 + oval:ssg-state_file_ownerdir_ownership_library_dirs_uid_0_1:ste:1 + + + + /usr/lib + + oval:ssg-symlink_file_ownerdir_ownership_library_dirs_uid_0:ste:1 + oval:ssg-state_file_ownerdir_ownership_library_dirs_uid_0_2:ste:1 + + + + /usr/lib64 + + oval:ssg-symlink_file_ownerdir_ownership_library_dirs_uid_0:ste:1 + oval:ssg-state_file_ownerdir_ownership_library_dirs_uid_0_3:ste:1 + + + + /bin + + oval:ssg-exclude_symlinks_dir_permissions_binary_dirs:ste:1 + oval:ssg-state_file_permissionsdir_permissions_binary_dirs_0_mode_0755or_stricter_:ste:1 + + + + /sbin + + oval:ssg-exclude_symlinks_dir_permissions_binary_dirs:ste:1 + oval:ssg-state_file_permissionsdir_permissions_binary_dirs_1_mode_0755or_stricter_:ste:1 + + + + /usr/bin + + oval:ssg-exclude_symlinks_dir_permissions_binary_dirs:ste:1 + oval:ssg-state_file_permissionsdir_permissions_binary_dirs_2_mode_0755or_stricter_:ste:1 + + + + /usr/sbin + + oval:ssg-exclude_symlinks_dir_permissions_binary_dirs:ste:1 + oval:ssg-state_file_permissionsdir_permissions_binary_dirs_3_mode_0755or_stricter_:ste:1 + + + + /usr/local/bin + + oval:ssg-exclude_symlinks_dir_permissions_binary_dirs:ste:1 + oval:ssg-state_file_permissionsdir_permissions_binary_dirs_4_mode_0755or_stricter_:ste:1 + + + + /usr/local/sbin + + oval:ssg-exclude_symlinks_dir_permissions_binary_dirs:ste:1 + oval:ssg-state_file_permissionsdir_permissions_binary_dirs_5_mode_0755or_stricter_:ste:1 + + + + /lib + + oval:ssg-exclude_symlinks_dir_permissions_library_dirs:ste:1 + oval:ssg-state_file_permissionsdir_permissions_library_dirs_0_mode_7755or_stricter_:ste:1 + + + + /lib64 + + oval:ssg-exclude_symlinks_dir_permissions_library_dirs:ste:1 + oval:ssg-state_file_permissionsdir_permissions_library_dirs_1_mode_7755or_stricter_:ste:1 + + + + /usr/lib + + oval:ssg-exclude_symlinks_dir_permissions_library_dirs:ste:1 + oval:ssg-state_file_permissionsdir_permissions_library_dirs_2_mode_7755or_stricter_:ste:1 + + + + /usr/lib64 + + oval:ssg-exclude_symlinks_dir_permissions_library_dirs:ste:1 + oval:ssg-state_file_permissionsdir_permissions_library_dirs_3_mode_7755or_stricter_:ste:1 + + + /etc/ipsec.d + + oval:ssg-symlink_file_groupownerdirectory_groupowner_etc_ipsecd_uid_root:ste:1 + oval:ssg-state_file_groupownerdirectory_groupowner_etc_ipsecd_gid_root_0:ste:1 + + + /etc/group + ^root:\w+:(\w+):.* + 1 + + + /etc/iptables + + oval:ssg-symlink_file_groupownerdirectory_groupowner_etc_iptables_uid_root:ste:1 + oval:ssg-state_file_groupownerdirectory_groupowner_etc_iptables_gid_root_0:ste:1 + + + /etc/group + ^root:\w+:(\w+):.* + 1 + + + /etc/nftables + + oval:ssg-symlink_file_groupownerdirectory_groupowner_etc_nftables_uid_root:ste:1 + oval:ssg-state_file_groupownerdirectory_groupowner_etc_nftables_gid_root_0:ste:1 + + + /etc/group + ^root:\w+:(\w+):.* + 1 + + + /etc/selinux + + oval:ssg-symlink_file_groupownerdirectory_groupowner_etc_selinux_uid_root:ste:1 + oval:ssg-state_file_groupownerdirectory_groupowner_etc_selinux_gid_root_0:ste:1 + + + /etc/group + ^root:\w+:(\w+):.* + 1 + + + /etc/sudoers.d + + oval:ssg-symlink_file_groupownerdirectory_groupowner_etc_sudoersd_uid_root:ste:1 + oval:ssg-state_file_groupownerdirectory_groupowner_etc_sudoersd_gid_root_0:ste:1 + + + /etc/group + ^root:\w+:(\w+):.* + 1 + + + /etc/sysctl.d + + oval:ssg-symlink_file_groupownerdirectory_groupowner_etc_sysctld_uid_root:ste:1 + oval:ssg-state_file_groupownerdirectory_groupowner_etc_sysctld_gid_root_0:ste:1 + + + /etc/group + ^root:\w+:(\w+):.* + 1 + + + /etc/ipsec.d + + oval:ssg-symlink_file_ownerdirectory_owner_etc_ipsecd_uid_0:ste:1 + oval:ssg-state_file_ownerdirectory_owner_etc_ipsecd_uid_0_0:ste:1 + + + /etc/iptables + + oval:ssg-symlink_file_ownerdirectory_owner_etc_iptables_uid_0:ste:1 + oval:ssg-state_file_ownerdirectory_owner_etc_iptables_uid_0_0:ste:1 + + + /etc/nftables + + oval:ssg-symlink_file_ownerdirectory_owner_etc_nftables_uid_0:ste:1 + oval:ssg-state_file_ownerdirectory_owner_etc_nftables_uid_0_0:ste:1 + + + /etc/selinux + + oval:ssg-symlink_file_ownerdirectory_owner_etc_selinux_uid_0:ste:1 + oval:ssg-state_file_ownerdirectory_owner_etc_selinux_uid_0_0:ste:1 + + + /etc/sudoers.d + + oval:ssg-symlink_file_ownerdirectory_owner_etc_sudoersd_uid_0:ste:1 + oval:ssg-state_file_ownerdirectory_owner_etc_sudoersd_uid_0_0:ste:1 + + + /etc/sysctl.d + + oval:ssg-symlink_file_ownerdirectory_owner_etc_sysctld_uid_0:ste:1 + oval:ssg-state_file_ownerdirectory_owner_etc_sysctld_uid_0_0:ste:1 + + + /etc/ipsec.d + + oval:ssg-exclude_symlinks_directory_permissions_etc_ipsecd:ste:1 + oval:ssg-state_file_permissionsdirectory_permissions_etc_ipsecd_0_mode_0700or_stricter_:ste:1 + + + /etc/iptables + + oval:ssg-exclude_symlinks_directory_permissions_etc_iptables:ste:1 + oval:ssg-state_file_permissionsdirectory_permissions_etc_iptables_0_mode_0700or_stricter_:ste:1 + + + /etc/nftables + + oval:ssg-exclude_symlinks_directory_permissions_etc_nftables:ste:1 + oval:ssg-state_file_permissionsdirectory_permissions_etc_nftables_0_mode_0700or_stricter_:ste:1 + + + /etc/selinux + + oval:ssg-exclude_symlinks_directory_permissions_etc_selinux:ste:1 + oval:ssg-state_file_permissionsdirectory_permissions_etc_selinux_0_mode_0755or_stricter_:ste:1 + + + /etc/sudoers.d + + oval:ssg-exclude_symlinks_directory_permissions_etc_sudoersd:ste:1 + oval:ssg-state_file_permissionsdirectory_permissions_etc_sudoersd_0_mode_0750or_stricter_:ste:1 + + + /etc/sysctl.d + + oval:ssg-exclude_symlinks_directory_permissions_etc_sysctld:ste:1 + oval:ssg-state_file_permissionsdirectory_permissions_etc_sysctld_0_mode_0755or_stricter_:ste:1 + + + /etc/ssh/sshd_config + ^[ \t]*(?i)include(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + + ^[ \t]*(?i)HostbasedAuthentication(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + /etc/ssh/sshd_config + ^[ \t]*(?i)HostbasedAuthentication(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + + oval:ssg-obj_disable_host_auth:obj:1 + oval:ssg-obj_disable_host_auth_sshd_included_files:obj:1 + + + + /etc/at.deny + + + /sbin/auditctl + oval:ssg-symlink_file_groupownerfile_audit_tools_group_ownership_uid_0:ste:1 + oval:ssg-state_file_groupownerfile_audit_tools_group_ownership_gid_0_0:ste:1 + + + /sbin/aureport + oval:ssg-symlink_file_groupownerfile_audit_tools_group_ownership_uid_0:ste:1 + oval:ssg-state_file_groupownerfile_audit_tools_group_ownership_gid_0_1:ste:1 + + + /sbin/ausearch + oval:ssg-symlink_file_groupownerfile_audit_tools_group_ownership_uid_0:ste:1 + oval:ssg-state_file_groupownerfile_audit_tools_group_ownership_gid_0_2:ste:1 + + + /sbin/autrace + oval:ssg-symlink_file_groupownerfile_audit_tools_group_ownership_uid_0:ste:1 + oval:ssg-state_file_groupownerfile_audit_tools_group_ownership_gid_0_3:ste:1 + + + /sbin/auditd + oval:ssg-symlink_file_groupownerfile_audit_tools_group_ownership_uid_0:ste:1 + oval:ssg-state_file_groupownerfile_audit_tools_group_ownership_gid_0_4:ste:1 + + + /sbin/rsyslogd + oval:ssg-symlink_file_groupownerfile_audit_tools_group_ownership_uid_0:ste:1 + oval:ssg-state_file_groupownerfile_audit_tools_group_ownership_gid_0_5:ste:1 + + + /sbin/augenrules + oval:ssg-symlink_file_groupownerfile_audit_tools_group_ownership_uid_0:ste:1 + oval:ssg-state_file_groupownerfile_audit_tools_group_ownership_gid_0_6:ste:1 + + + /sbin/auditctl + oval:ssg-symlink_file_ownerfile_audit_tools_ownership_uid_0:ste:1 + oval:ssg-state_file_ownerfile_audit_tools_ownership_uid_0_0:ste:1 + + + /sbin/aureport + oval:ssg-symlink_file_ownerfile_audit_tools_ownership_uid_0:ste:1 + oval:ssg-state_file_ownerfile_audit_tools_ownership_uid_0_1:ste:1 + + + /sbin/ausearch + oval:ssg-symlink_file_ownerfile_audit_tools_ownership_uid_0:ste:1 + oval:ssg-state_file_ownerfile_audit_tools_ownership_uid_0_2:ste:1 + + + /sbin/autrace + oval:ssg-symlink_file_ownerfile_audit_tools_ownership_uid_0:ste:1 + oval:ssg-state_file_ownerfile_audit_tools_ownership_uid_0_3:ste:1 + + + /sbin/auditd + oval:ssg-symlink_file_ownerfile_audit_tools_ownership_uid_0:ste:1 + oval:ssg-state_file_ownerfile_audit_tools_ownership_uid_0_4:ste:1 + + + /sbin/rsyslogd + oval:ssg-symlink_file_ownerfile_audit_tools_ownership_uid_0:ste:1 + oval:ssg-state_file_ownerfile_audit_tools_ownership_uid_0_5:ste:1 + + + /sbin/augenrules + oval:ssg-symlink_file_ownerfile_audit_tools_ownership_uid_0:ste:1 + oval:ssg-state_file_ownerfile_audit_tools_ownership_uid_0_6:ste:1 + + + /sbin/auditctl + oval:ssg-exclude_symlinks_file_audit_tools_permissions:ste:1 + oval:ssg-state_file_permissionsfile_audit_tools_permissions_0_mode_0755or_stricter_:ste:1 + + + /sbin/aureport + oval:ssg-exclude_symlinks_file_audit_tools_permissions:ste:1 + oval:ssg-state_file_permissionsfile_audit_tools_permissions_1_mode_0755or_stricter_:ste:1 + + + /sbin/ausearch + oval:ssg-exclude_symlinks_file_audit_tools_permissions:ste:1 + oval:ssg-state_file_permissionsfile_audit_tools_permissions_2_mode_0755or_stricter_:ste:1 + + + /sbin/autrace + oval:ssg-exclude_symlinks_file_audit_tools_permissions:ste:1 + oval:ssg-state_file_permissionsfile_audit_tools_permissions_3_mode_0755or_stricter_:ste:1 + + + /sbin/auditd + oval:ssg-exclude_symlinks_file_audit_tools_permissions:ste:1 + oval:ssg-state_file_permissionsfile_audit_tools_permissions_4_mode_0755or_stricter_:ste:1 + + + /sbin/rsyslogd + oval:ssg-exclude_symlinks_file_audit_tools_permissions:ste:1 + oval:ssg-state_file_permissionsfile_audit_tools_permissions_5_mode_0755or_stricter_:ste:1 + + + /sbin/augenrules + oval:ssg-exclude_symlinks_file_audit_tools_permissions:ste:1 + oval:ssg-state_file_permissionsfile_audit_tools_permissions_6_mode_0755or_stricter_:ste:1 + + + /etc/cron.deny + + + /etc/at.allow + oval:ssg-symlink_file_groupowner_at_allow_uid_0:ste:1 + oval:ssg-state_file_groupowner_at_allow_gid_0_0:ste:1 + + + /etc/group- + oval:ssg-symlink_file_groupowner_backup_etc_group_uid_0:ste:1 + oval:ssg-state_file_groupowner_backup_etc_group_gid_0_0:ste:1 + + + /etc/gshadow- + oval:ssg-symlink_file_groupowner_backup_etc_gshadow_uid_0:ste:1 + oval:ssg-state_file_groupowner_backup_etc_gshadow_gid_0_0:ste:1 + + + /etc/passwd- + oval:ssg-symlink_file_groupowner_backup_etc_passwd_uid_0:ste:1 + oval:ssg-state_file_groupowner_backup_etc_passwd_gid_0_0:ste:1 + + + /etc/shadow- + oval:ssg-symlink_file_groupowner_backup_etc_shadow_uid_0:ste:1 + oval:ssg-state_file_groupowner_backup_etc_shadow_gid_0_0:ste:1 + + + /etc/cron.allow + oval:ssg-symlink_file_groupowner_cron_allow_uid_0:ste:1 + oval:ssg-state_file_groupowner_cron_allow_gid_0_0:ste:1 + + + /etc/cron.d + + oval:ssg-symlink_file_groupowner_cron_d_uid_0:ste:1 + oval:ssg-state_file_groupowner_cron_d_gid_0_0:ste:1 + + + /etc/cron.daily + + oval:ssg-symlink_file_groupowner_cron_daily_uid_0:ste:1 + oval:ssg-state_file_groupowner_cron_daily_gid_0_0:ste:1 + + + /etc/cron.deny + oval:ssg-symlink_file_groupowner_cron_deny_uid_0:ste:1 + oval:ssg-state_file_groupowner_cron_deny_gid_0_0:ste:1 + + + /etc/cron.hourly + + oval:ssg-symlink_file_groupowner_cron_hourly_uid_0:ste:1 + oval:ssg-state_file_groupowner_cron_hourly_gid_0_0:ste:1 + + + /etc/cron.monthly + + oval:ssg-symlink_file_groupowner_cron_monthly_uid_0:ste:1 + oval:ssg-state_file_groupowner_cron_monthly_gid_0_0:ste:1 + + + /etc/cron.weekly + + oval:ssg-symlink_file_groupowner_cron_weekly_uid_0:ste:1 + oval:ssg-state_file_groupowner_cron_weekly_gid_0_0:ste:1 + + + /etc/crontab + oval:ssg-symlink_file_groupowner_crontab_uid_0:ste:1 + oval:ssg-state_file_groupowner_crontab_gid_0_0:ste:1 + + + /boot/grub2/grub.cfg + oval:ssg-symlink_file_groupowner_efi_grub2_cfg_uid_0:ste:1 + oval:ssg-state_file_groupowner_efi_grub2_cfg_gid_0_0:ste:1 + + + /boot/grub2/user.cfg + oval:ssg-symlink_file_groupowner_efi_user_cfg_uid_0:ste:1 + oval:ssg-state_file_groupowner_efi_user_cfg_gid_0_0:ste:1 + + + /etc/crypttab + oval:ssg-symlink_file_groupowner_etc_crypttab_uid_root:ste:1 + oval:ssg-state_file_groupowner_etc_crypttab_gid_root_0:ste:1 + + + /etc/group + ^root:\w+:(\w+):.* + 1 + + + /etc/group + oval:ssg-symlink_file_groupowner_etc_group_uid_0:ste:1 + oval:ssg-state_file_groupowner_etc_group_gid_0_0:ste:1 + + + /etc/gshadow + oval:ssg-symlink_file_groupowner_etc_gshadow_uid_0:ste:1 + oval:ssg-state_file_groupowner_etc_gshadow_gid_0_0:ste:1 + + + /etc/ipsec.conf + oval:ssg-symlink_file_groupowner_etc_ipsec_conf_uid_root:ste:1 + oval:ssg-state_file_groupowner_etc_ipsec_conf_gid_root_0:ste:1 + + + /etc/group + ^root:\w+:(\w+):.* + 1 + + + /etc/ipsec.secrets + oval:ssg-symlink_file_groupowner_etc_ipsec_secrets_uid_root:ste:1 + oval:ssg-state_file_groupowner_etc_ipsec_secrets_gid_root_0:ste:1 + + + /etc/group + ^root:\w+:(\w+):.* + 1 + + + /etc/issue.net + oval:ssg-symlink_file_groupowner_etc_issue_net_uid_0:ste:1 + oval:ssg-state_file_groupowner_etc_issue_net_gid_0_0:ste:1 + + + /etc/passwd + oval:ssg-symlink_file_groupowner_etc_passwd_uid_0:ste:1 + oval:ssg-state_file_groupowner_etc_passwd_gid_0_0:ste:1 + + + /etc/sestatus.conf + oval:ssg-symlink_file_groupowner_etc_sestatus_conf_uid_root:ste:1 + oval:ssg-state_file_groupowner_etc_sestatus_conf_gid_root_0:ste:1 + + + /etc/group + ^root:\w+:(\w+):.* + 1 + + + /etc/shadow + oval:ssg-symlink_file_groupowner_etc_shadow_uid_0:ste:1 + oval:ssg-state_file_groupowner_etc_shadow_gid_0_0:ste:1 + + + /etc/shells + oval:ssg-symlink_file_groupowner_etc_shells_uid_0:ste:1 + oval:ssg-state_file_groupowner_etc_shells_gid_0_0:ste:1 + + + /etc/sudoers + oval:ssg-symlink_file_groupowner_etc_sudoers_uid_root:ste:1 + oval:ssg-state_file_groupowner_etc_sudoers_gid_root_0:ste:1 + + + /etc/group + ^root:\w+:(\w+):.* + 1 + + + /boot/grub2/grub.cfg + oval:ssg-symlink_file_groupowner_grub2_cfg_uid_0:ste:1 + oval:ssg-state_file_groupowner_grub2_cfg_gid_0_0:ste:1 + + + /etc/ssh/sshd_config + oval:ssg-symlink_file_groupowner_sshd_config_uid_0:ste:1 + oval:ssg-state_file_groupowner_sshd_config_gid_0_0:ste:1 + + + /boot + ^.*System\.map.*$ + oval:ssg-symlink_file_groupowner_systemmap_uid_root:ste:1 + oval:ssg-state_file_groupowner_systemmap_gid_root_0:ste:1 + + + /etc/group + ^root:\w+:(\w+):.* + 1 + + + /boot/grub2/user.cfg + oval:ssg-symlink_file_groupowner_user_cfg_uid_0:ste:1 + oval:ssg-state_file_groupowner_user_cfg_gid_0_0:ste:1 + + + /var/log + + oval:ssg-symlink_file_groupowner_var_log_uid_0:ste:1 + oval:ssg-state_file_groupowner_var_log_gid_0_0:ste:1 + + + /var/log/messages + oval:ssg-symlink_file_groupowner_var_log_messages_uid_0:ste:1 + oval:ssg-state_file_groupowner_var_log_messages_gid_0_0:ste:1 + + + /var/log/syslog + oval:ssg-symlink_file_groupowner_var_log_syslog_uid_4:ste:1 + oval:ssg-state_file_groupowner_var_log_syslog_gid_4_0:ste:1 + + + /etc/audit + ^.*audit(\.rules|d\.conf)$ + oval:ssg-symlink_file_groupownership_audit_configuration_uid_0:ste:1 + oval:ssg-state_file_groupownership_audit_configuration_gid_0_0:ste:1 + + + /etc/audit/rules.d + ^.*\.rules$ + oval:ssg-symlink_file_groupownership_audit_configuration_uid_0:ste:1 + oval:ssg-state_file_groupownership_audit_configuration_gid_0_1:ste:1 + + + /etc/ssh + ^.*_key$ + oval:ssg-symlink_file_groupownership_sshd_private_key_uid_ssh_keys:ste:1 + oval:ssg-state_file_groupownership_sshd_private_key_gid_ssh_keys_0:ste:1 + + + /etc/group + ^ssh_keys:\w+:(\w+):.* + 1 + + + /etc/ssh + ^.*\.pub$ + oval:ssg-symlink_file_groupownership_sshd_pub_key_uid_0:ste:1 + oval:ssg-state_file_groupownership_sshd_pub_key_gid_0_0:ste:1 + + + /etc/group- + oval:ssg-symlink_file_owner_backup_etc_group_uid_0:ste:1 + oval:ssg-state_file_owner_backup_etc_group_uid_0_0:ste:1 + + + /etc/gshadow- + oval:ssg-symlink_file_owner_backup_etc_gshadow_uid_0:ste:1 + oval:ssg-state_file_owner_backup_etc_gshadow_uid_0_0:ste:1 + + + /etc/passwd- + oval:ssg-symlink_file_owner_backup_etc_passwd_uid_0:ste:1 + oval:ssg-state_file_owner_backup_etc_passwd_uid_0_0:ste:1 + + + /etc/shadow- + oval:ssg-symlink_file_owner_backup_etc_shadow_uid_0:ste:1 + oval:ssg-state_file_owner_backup_etc_shadow_uid_0_0:ste:1 + + + /etc/cron.allow + oval:ssg-symlink_file_owner_cron_allow_uid_0:ste:1 + oval:ssg-state_file_owner_cron_allow_uid_0_0:ste:1 + + + /etc/cron.d + + oval:ssg-symlink_file_owner_cron_d_uid_0:ste:1 + oval:ssg-state_file_owner_cron_d_uid_0_0:ste:1 + + + /etc/cron.daily + + oval:ssg-symlink_file_owner_cron_daily_uid_0:ste:1 + oval:ssg-state_file_owner_cron_daily_uid_0_0:ste:1 + + + /etc/cron.deny + oval:ssg-symlink_file_owner_cron_deny_uid_0:ste:1 + oval:ssg-state_file_owner_cron_deny_uid_0_0:ste:1 + + + /etc/cron.hourly + + oval:ssg-symlink_file_owner_cron_hourly_uid_0:ste:1 + oval:ssg-state_file_owner_cron_hourly_uid_0_0:ste:1 + + + /etc/cron.monthly + + oval:ssg-symlink_file_owner_cron_monthly_uid_0:ste:1 + oval:ssg-state_file_owner_cron_monthly_uid_0_0:ste:1 + + + /etc/cron.weekly + + oval:ssg-symlink_file_owner_cron_weekly_uid_0:ste:1 + oval:ssg-state_file_owner_cron_weekly_uid_0_0:ste:1 + + + /etc/crontab + oval:ssg-symlink_file_owner_crontab_uid_0:ste:1 + oval:ssg-state_file_owner_crontab_uid_0_0:ste:1 + + + /boot/grub2/grub.cfg + oval:ssg-symlink_file_owner_efi_grub2_cfg_uid_0:ste:1 + oval:ssg-state_file_owner_efi_grub2_cfg_uid_0_0:ste:1 + + + /boot/grub2/user.cfg + oval:ssg-symlink_file_owner_efi_user_cfg_uid_0:ste:1 + oval:ssg-state_file_owner_efi_user_cfg_uid_0_0:ste:1 + + + /etc/chrony.keys + oval:ssg-symlink_file_owner_etc_chrony_keys_uid_0:ste:1 + oval:ssg-state_file_owner_etc_chrony_keys_uid_0_0:ste:1 + + + /etc/crypttab + oval:ssg-symlink_file_owner_etc_crypttab_uid_0:ste:1 + oval:ssg-state_file_owner_etc_crypttab_uid_0_0:ste:1 + + + /etc/group + oval:ssg-symlink_file_owner_etc_group_uid_0:ste:1 + oval:ssg-state_file_owner_etc_group_uid_0_0:ste:1 + + + /etc/gshadow + oval:ssg-symlink_file_owner_etc_gshadow_uid_0:ste:1 + oval:ssg-state_file_owner_etc_gshadow_uid_0_0:ste:1 + + + /etc/ipsec.conf + oval:ssg-symlink_file_owner_etc_ipsec_conf_uid_0:ste:1 + oval:ssg-state_file_owner_etc_ipsec_conf_uid_0_0:ste:1 + + + /etc/ipsec.secrets + oval:ssg-symlink_file_owner_etc_ipsec_secrets_uid_0:ste:1 + oval:ssg-state_file_owner_etc_ipsec_secrets_uid_0_0:ste:1 + + + /etc/issue.net + oval:ssg-symlink_file_owner_etc_issue_net_uid_0:ste:1 + oval:ssg-state_file_owner_etc_issue_net_uid_0_0:ste:1 + + + /etc/passwd + oval:ssg-symlink_file_owner_etc_passwd_uid_0:ste:1 + oval:ssg-state_file_owner_etc_passwd_uid_0_0:ste:1 + + + /etc/sestatus.conf + oval:ssg-symlink_file_owner_etc_sestatus_conf_uid_0:ste:1 + oval:ssg-state_file_owner_etc_sestatus_conf_uid_0_0:ste:1 + + + /etc/shadow + oval:ssg-symlink_file_owner_etc_shadow_uid_0:ste:1 + oval:ssg-state_file_owner_etc_shadow_uid_0_0:ste:1 + + + /etc/shells + oval:ssg-symlink_file_owner_etc_shells_uid_0:ste:1 + oval:ssg-state_file_owner_etc_shells_uid_0_0:ste:1 + + + /etc/sudoers + oval:ssg-symlink_file_owner_etc_sudoers_uid_0:ste:1 + oval:ssg-state_file_owner_etc_sudoers_uid_0_0:ste:1 + + + /boot/grub2/grub.cfg + oval:ssg-symlink_file_owner_grub2_cfg_uid_0:ste:1 + oval:ssg-state_file_owner_grub2_cfg_uid_0_0:ste:1 + + + /etc/ssh/sshd_config + oval:ssg-symlink_file_owner_sshd_config_uid_0:ste:1 + oval:ssg-state_file_owner_sshd_config_uid_0_0:ste:1 + + + /boot + ^.*System\.map.*$ + oval:ssg-symlink_file_owner_systemmap_uid_0:ste:1 + oval:ssg-state_file_owner_systemmap_uid_0_0:ste:1 + + + /boot/grub2/user.cfg + oval:ssg-symlink_file_owner_user_cfg_uid_0:ste:1 + oval:ssg-state_file_owner_user_cfg_uid_0_0:ste:1 + + + /var/log + + oval:ssg-symlink_file_owner_var_log_uid_0:ste:1 + oval:ssg-state_file_owner_var_log_uid_0_0:ste:1 + + + /var/log/messages + oval:ssg-symlink_file_owner_var_log_messages_uid_0:ste:1 + oval:ssg-state_file_owner_var_log_messages_uid_0_0:ste:1 + + + /var/log/syslog + oval:ssg-symlink_file_owner_var_log_syslog_uid_104:ste:1 + oval:ssg-state_file_owner_var_log_syslog_uid_104_0:ste:1 + + + /etc/audit + ^.*audit(\.rules|d\.conf)$ + oval:ssg-symlink_file_ownership_audit_configuration_uid_0:ste:1 + oval:ssg-state_file_ownership_audit_configuration_uid_0_0:ste:1 + + + /etc/audit/rules.d + ^.*\.rules$ + oval:ssg-symlink_file_ownership_audit_configuration_uid_0:ste:1 + oval:ssg-state_file_ownership_audit_configuration_uid_0_1:ste:1 + + + + /lib + ^.*$ + oval:ssg-symlink_file_ownership_library_dirs_uid_0:ste:1 + oval:ssg-state_file_ownership_library_dirs_uid_0_0:ste:1 + + + + /lib64 + ^.*$ + oval:ssg-symlink_file_ownership_library_dirs_uid_0:ste:1 + oval:ssg-state_file_ownership_library_dirs_uid_0_1:ste:1 + + + + /usr/lib + ^.*$ + oval:ssg-symlink_file_ownership_library_dirs_uid_0:ste:1 + oval:ssg-state_file_ownership_library_dirs_uid_0_2:ste:1 + + + + /usr/lib64 + ^.*$ + oval:ssg-symlink_file_ownership_library_dirs_uid_0:ste:1 + oval:ssg-state_file_ownership_library_dirs_uid_0_3:ste:1 + + + /etc/ssh + ^.*_key$ + oval:ssg-symlink_file_ownership_sshd_private_key_uid_0:ste:1 + oval:ssg-state_file_ownership_sshd_private_key_uid_0_0:ste:1 + + + /etc/ssh + ^.*\.pub$ + oval:ssg-symlink_file_ownership_sshd_pub_key_uid_0:ste:1 + oval:ssg-state_file_ownership_sshd_pub_key_uid_0_0:ste:1 + + + /etc/at.allow + oval:ssg-exclude_symlinks__at_allow:ste:1 + oval:ssg-state_file_permissions_at_allow_0_mode_0640or_stricter_:ste:1 + + + /etc/audit + ^.*audit(\.rules|d\.conf)$ + oval:ssg-exclude_symlinks__audit_configuration:ste:1 + oval:ssg-state_file_permissions_audit_configuration_0_mode_0640or_stricter_:ste:1 + + + /etc/audit/rules.d + ^.*\.rules$ + oval:ssg-exclude_symlinks__audit_configuration:ste:1 + oval:ssg-state_file_permissions_audit_configuration_1_mode_0640or_stricter_:ste:1 + + + /etc/group- + oval:ssg-exclude_symlinks__backup_etc_group:ste:1 + oval:ssg-state_file_permissions_backup_etc_group_0_mode_0644or_stricter_:ste:1 + + + /etc/gshadow- + oval:ssg-exclude_symlinks__backup_etc_gshadow:ste:1 + oval:ssg-state_file_permissions_backup_etc_gshadow_0_mode_0000or_stricter_:ste:1 + + + /etc/passwd- + oval:ssg-exclude_symlinks__backup_etc_passwd:ste:1 + oval:ssg-state_file_permissions_backup_etc_passwd_0_mode_0644or_stricter_:ste:1 + + + /etc/shadow- + oval:ssg-exclude_symlinks__backup_etc_shadow:ste:1 + oval:ssg-state_file_permissions_backup_etc_shadow_0_mode_0000or_stricter_:ste:1 + + + /etc/cron.allow + oval:ssg-exclude_symlinks__cron_allow:ste:1 + oval:ssg-state_file_permissions_cron_allow_0_mode_0640or_stricter_:ste:1 + + + /etc/cron.d + + oval:ssg-exclude_symlinks__cron_d:ste:1 + oval:ssg-state_file_permissions_cron_d_0_mode_0700or_stricter_:ste:1 + + + /etc/cron.daily + + oval:ssg-exclude_symlinks__cron_daily:ste:1 + oval:ssg-state_file_permissions_cron_daily_0_mode_0700or_stricter_:ste:1 + + + /etc/cron.hourly + + oval:ssg-exclude_symlinks__cron_hourly:ste:1 + oval:ssg-state_file_permissions_cron_hourly_0_mode_0700or_stricter_:ste:1 + + + /etc/cron.monthly + + oval:ssg-exclude_symlinks__cron_monthly:ste:1 + oval:ssg-state_file_permissions_cron_monthly_0_mode_0700or_stricter_:ste:1 + + + /etc/cron.weekly + + oval:ssg-exclude_symlinks__cron_weekly:ste:1 + oval:ssg-state_file_permissions_cron_weekly_0_mode_0700or_stricter_:ste:1 + + + /etc/crontab + oval:ssg-exclude_symlinks__crontab:ste:1 + oval:ssg-state_file_permissions_crontab_0_mode_0600or_stricter_:ste:1 + + + /boot/grub2/grub.cfg + oval:ssg-exclude_symlinks__efi_grub2_cfg:ste:1 + oval:ssg-state_file_permissions_efi_grub2_cfg_0_mode_0700or_stricter_:ste:1 + + + /boot/grub2/user.cfg + oval:ssg-exclude_symlinks__efi_user_cfg:ste:1 + oval:ssg-state_file_permissions_efi_user_cfg_0_mode_0700or_stricter_:ste:1 + + + /etc/audit/auditd.conf + oval:ssg-exclude_symlinks__etc_audit_auditd:ste:1 + oval:ssg-state_file_permissions_etc_audit_auditd_0_mode_0640or_stricter_:ste:1 + + + /etc/audit/rules.d + ^.*rules$ + oval:ssg-exclude_symlinks__etc_audit_rulesd:ste:1 + oval:ssg-state_file_permissions_etc_audit_rulesd_0_mode_0600or_stricter_:ste:1 + + + /etc/chrony.keys + oval:ssg-exclude_symlinks__etc_chrony_keys:ste:1 + oval:ssg-state_file_permissions_etc_chrony_keys_0_mode_0640or_stricter_:ste:1 + + + /etc/crypttab + oval:ssg-exclude_symlinks__etc_crypttab:ste:1 + oval:ssg-state_file_permissions_etc_crypttab_0_mode_0600or_stricter_:ste:1 + + + /etc/group + oval:ssg-exclude_symlinks__etc_group:ste:1 + oval:ssg-state_file_permissions_etc_group_0_mode_0644or_stricter_:ste:1 + + + /etc/gshadow + oval:ssg-exclude_symlinks__etc_gshadow:ste:1 + oval:ssg-state_file_permissions_etc_gshadow_0_mode_0000or_stricter_:ste:1 + + + /etc/ipsec.conf + oval:ssg-exclude_symlinks__etc_ipsec_conf:ste:1 + oval:ssg-state_file_permissions_etc_ipsec_conf_0_mode_0644or_stricter_:ste:1 + + + /etc/ipsec.secrets + oval:ssg-exclude_symlinks__etc_ipsec_secrets:ste:1 + oval:ssg-state_file_permissions_etc_ipsec_secrets_0_mode_0644or_stricter_:ste:1 + + + /etc/issue.net + oval:ssg-exclude_symlinks__etc_issue_net:ste:1 + oval:ssg-state_file_permissions_etc_issue_net_0_mode_0644or_stricter_:ste:1 + + + /etc/passwd + oval:ssg-exclude_symlinks__etc_passwd:ste:1 + oval:ssg-state_file_permissions_etc_passwd_0_mode_0644or_stricter_:ste:1 + + + /etc/sestatus.conf + oval:ssg-exclude_symlinks__etc_sestatus_conf:ste:1 + oval:ssg-state_file_permissions_etc_sestatus_conf_0_mode_0644or_stricter_:ste:1 + + + /etc/shadow + oval:ssg-exclude_symlinks__etc_shadow:ste:1 + oval:ssg-state_file_permissions_etc_shadow_0_mode_0000or_stricter_:ste:1 + + + /etc/shells + oval:ssg-exclude_symlinks__etc_shells:ste:1 + oval:ssg-state_file_permissions_etc_shells_0_mode_0644or_stricter_:ste:1 + + + /etc/sudoers + oval:ssg-exclude_symlinks__etc_sudoers:ste:1 + oval:ssg-state_file_permissions_etc_sudoers_0_mode_0440or_stricter_:ste:1 + + + /boot/grub2/grub.cfg + oval:ssg-exclude_symlinks__grub2_cfg:ste:1 + oval:ssg-state_file_permissions_grub2_cfg_0_mode_0600or_stricter_:ste:1 + + + + /lib + ^.*$ + oval:ssg-exclude_symlinks__library_dirs:ste:1 + oval:ssg-state_file_permissions_library_dirs_0_mode_7755or_stricter_:ste:1 + + + + /lib64 + ^.*$ + oval:ssg-exclude_symlinks__library_dirs:ste:1 + oval:ssg-state_file_permissions_library_dirs_1_mode_7755or_stricter_:ste:1 + + + + /usr/lib + ^.*$ + oval:ssg-exclude_symlinks__library_dirs:ste:1 + oval:ssg-state_file_permissions_library_dirs_2_mode_7755or_stricter_:ste:1 + + + + /usr/lib64 + ^.*$ + oval:ssg-exclude_symlinks__library_dirs:ste:1 + oval:ssg-state_file_permissions_library_dirs_3_mode_7755or_stricter_:ste:1 + + + /etc/ssh/sshd_config + oval:ssg-exclude_symlinks__sshd_config:ste:1 + oval:ssg-state_file_permissions_sshd_config_0_mode_0600or_stricter_:ste:1 + + + /etc/ssh + ^.*\.pub$ + oval:ssg-exclude_symlinks__sshd_pub_key:ste:1 + oval:ssg-state_file_permissions_sshd_pub_key_0_mode_0644or_stricter_:ste:1 + + + /usr/bin/sudo + oval:ssg-exclude_symlinks__sudo:ste:1 + oval:ssg-state_file_permissions_sudo_0_mode_4110:ste:1 + + + /boot + ^.*System\.map.*$ + oval:ssg-exclude_symlinks__systemmap:ste:1 + oval:ssg-state_file_permissions_systemmap_0_mode_0600or_stricter_:ste:1 + + + /boot/grub2/user.cfg + oval:ssg-exclude_symlinks__user_cfg:ste:1 + oval:ssg-state_file_permissions_user_cfg_0_mode_0600or_stricter_:ste:1 + + + /var/log + + oval:ssg-exclude_symlinks__var_log:ste:1 + oval:ssg-state_file_permissions_var_log_0_mode_0755or_stricter_:ste:1 + + + /var/log/messages + oval:ssg-exclude_symlinks__var_log_messages:ste:1 + oval:ssg-state_file_permissions_var_log_messages_0_mode_0600or_stricter_:ste:1 + + + /var/log/syslog + oval:ssg-exclude_symlinks__var_log_syslog:ste:1 + oval:ssg-state_file_permissions_var_log_syslog_0_mode_0640or_stricter_:ste:1 + + + /etc/ssh/sshd_config.d/50-redhat.conf + + + /etc/firewalld/firewalld.conf + ^[ \t]*FirewallBackend=(.+?)[ \t]*(?:$|#) + 1 + + + /etc/default/grub + ^\s*GRUB_CMDLINE_LINUX="(.*)"$ + 1 + + + /etc/default/grub + ^\s*GRUB_CMDLINE_LINUX_DEFAULT="(.*)"$ + 1 + + + /boot/loader/entries/ + ^.*\.conf$ + ^options (.*)$ + 1 + oval:ssg-state_grub2_rescue_entry_for_grub2_audit_argument:ste:1 + + + /etc/default/grub + ^\s*GRUB_CMDLINE_LINUX="(.*)"$ + 1 + + + /etc/default/grub + ^\s*GRUB_CMDLINE_LINUX_DEFAULT="(.*)"$ + 1 + + + /boot/loader/entries/ + ^.*\.conf$ + ^options (.*)$ + 1 + oval:ssg-state_grub2_rescue_entry_for_grub2_audit_backlog_limit_argument:ste:1 + + + /etc/default/grub + ^\s*GRUB_CMDLINE_LINUX="(.*)"$ + 1 + + + /etc/default/grub + ^\s*GRUB_CMDLINE_LINUX_DEFAULT="(.*)"$ + 1 + + + /boot/loader/entries/ + ^.*\.conf$ + ^options (.*)$ + 1 + oval:ssg-state_grub2_rescue_entry_for_grub2_enable_iommu_force:ste:1 + + + /etc/default/grub + ^\s*GRUB_CMDLINE_LINUX="(.*)"$ + 1 + + + /etc/default/grub + ^\s*GRUB_CMDLINE_LINUX_DEFAULT="(.*)"$ + 1 + + + /boot/loader/entries/ + ^.*\.conf$ + ^options (.*)$ + 1 + oval:ssg-state_grub2_rescue_entry_for_grub2_init_on_alloc_argument:ste:1 + + + /etc/default/grub + ^\s*GRUB_CMDLINE_LINUX="(.*)"$ + 1 + + + /etc/default/grub + ^\s*GRUB_CMDLINE_LINUX_DEFAULT="(.*)"$ + 1 + + + /boot/loader/entries/ + ^.*\.conf$ + ^options (.*)$ + 1 + oval:ssg-state_grub2_rescue_entry_for_grub2_l1tf_argument:ste:1 + + + /etc/default/grub + ^\s*GRUB_CMDLINE_LINUX="(.*)"$ + 1 + + + /etc/default/grub + ^\s*GRUB_CMDLINE_LINUX_DEFAULT="(.*)"$ + 1 + + + /boot/loader/entries/ + ^.*\.conf$ + ^options (.*)$ + 1 + oval:ssg-state_grub2_rescue_entry_for_grub2_mce_argument:ste:1 + + + /etc/default/grub + ^\s*GRUB_CMDLINE_LINUX="(.*)"$ + 1 + + + /etc/default/grub + ^\s*GRUB_CMDLINE_LINUX_DEFAULT="(.*)"$ + 1 + + + /boot/loader/entries/ + ^.*\.conf$ + ^options (.*)$ + 1 + oval:ssg-state_grub2_rescue_entry_for_grub2_mds_argument:ste:1 + + + /etc/default/grub + ^\s*GRUB_CMDLINE_LINUX="(?!.*\bnosmap\b.*).*"$ + 1 + + + /etc/default/grub + ^\s*GRUB_CMDLINE_LINUX_DEFAULT="(?!.*\bnosmap\b).*"$ + 1 + + + /boot/loader/entries/ + ^.*\.conf$ + ^options (.*)$ + 1 + oval:ssg-state_grub2_rescue_entry_for_grub2_nosmap_argument_absent:ste:1 + + + /etc/default/grub + ^\s*GRUB_CMDLINE_LINUX="(?!.*\bnosmep\b.*).*"$ + 1 + + + /etc/default/grub + ^\s*GRUB_CMDLINE_LINUX_DEFAULT="(?!.*\bnosmep\b).*"$ + 1 + + + /boot/loader/entries/ + ^.*\.conf$ + ^options (.*)$ + 1 + oval:ssg-state_grub2_rescue_entry_for_grub2_nosmep_argument_absent:ste:1 + + + /etc/default/grub + ^\s*GRUB_CMDLINE_LINUX="(.*)"$ + 1 + + + /etc/default/grub + ^\s*GRUB_CMDLINE_LINUX_DEFAULT="(.*)"$ + 1 + + + /boot/loader/entries/ + ^.*\.conf$ + ^options (.*)$ + 1 + oval:ssg-state_grub2_rescue_entry_for_grub2_page_alloc_shuffle_argument:ste:1 + + + /etc/default/grub + ^\s*GRUB_CMDLINE_LINUX="(.*)"$ + 1 + + + /etc/default/grub + ^\s*GRUB_CMDLINE_LINUX_DEFAULT="(.*)"$ + 1 + + + /boot/loader/entries/ + ^.*\.conf$ + ^options (.*)$ + 1 + oval:ssg-state_grub2_rescue_entry_for_grub2_page_poison_argument:ste:1 + + + /etc/default/grub + ^\s*GRUB_CMDLINE_LINUX="(.*)"$ + 1 + + + /etc/default/grub + ^\s*GRUB_CMDLINE_LINUX_DEFAULT="(.*)"$ + 1 + + + /boot/loader/entries/ + ^.*\.conf$ + ^options (.*)$ + 1 + oval:ssg-state_grub2_rescue_entry_for_grub2_pti_argument:ste:1 + + + /etc/default/grub + ^\s*GRUB_CMDLINE_LINUX="(.*)"$ + 1 + + + /etc/default/grub + ^\s*GRUB_CMDLINE_LINUX_DEFAULT="(.*)"$ + 1 + + + /boot/loader/entries/ + ^.*\.conf$ + ^options (.*)$ + 1 + oval:ssg-state_grub2_rescue_entry_for_grub2_rng_core_default_quality_argument:ste:1 + + + /etc/default/grub + ^\s*GRUB_CMDLINE_LINUX="(.*)"$ + 1 + + + /etc/default/grub + ^\s*GRUB_CMDLINE_LINUX_DEFAULT="(.*)"$ + 1 + + + /boot/loader/entries/ + ^.*\.conf$ + ^options (.*)$ + 1 + oval:ssg-state_grub2_rescue_entry_for_grub2_slab_nomerge_argument:ste:1 + + + /etc/default/grub + ^\s*GRUB_CMDLINE_LINUX="(.*)"$ + 1 + + + /etc/default/grub + ^\s*GRUB_CMDLINE_LINUX_DEFAULT="(.*)"$ + 1 + + + /boot/loader/entries/ + ^.*\.conf$ + ^options (.*)$ + 1 + oval:ssg-state_grub2_rescue_entry_for_grub2_slub_debug_argument:ste:1 + + + /etc/default/grub + ^\s*GRUB_CMDLINE_LINUX="(.*)"$ + 1 + + + /etc/default/grub + ^\s*GRUB_CMDLINE_LINUX_DEFAULT="(.*)"$ + 1 + + + /boot/loader/entries/ + ^.*\.conf$ + ^options (.*)$ + 1 + oval:ssg-state_grub2_rescue_entry_for_grub2_spec_store_bypass_disable_argument:ste:1 + + + /etc/default/grub + ^\s*GRUB_CMDLINE_LINUX="(.*)"$ + 1 + + + /etc/default/grub + ^\s*GRUB_CMDLINE_LINUX_DEFAULT="(.*)"$ + 1 + + + /boot/loader/entries/ + ^.*\.conf$ + ^options (.*)$ + 1 + oval:ssg-state_grub2_rescue_entry_for_grub2_spectre_v2_argument:ste:1 + + + /etc/default/grub + ^\s*GRUB_CMDLINE_LINUX="(?!.*\bsystemd.debug-shell\b.*).*"$ + 1 + + + /etc/default/grub + ^\s*GRUB_CMDLINE_LINUX_DEFAULT="(?!.*\bsystemd.debug-shell\b).*"$ + 1 + + + /boot/loader/entries/ + ^.*\.conf$ + ^options (.*)$ + 1 + oval:ssg-state_grub2_rescue_entry_for_grub2_systemd_debug-shell_argument_absent:ste:1 + + + /etc/default/grub + ^\s*GRUB_CMDLINE_LINUX="(.*)"$ + 1 + + + /etc/default/grub + ^\s*GRUB_CMDLINE_LINUX_DEFAULT="(.*)"$ + 1 + + + /boot/loader/entries/ + ^.*\.conf$ + ^options (.*)$ + 1 + oval:ssg-state_grub2_rescue_entry_for_grub2_vsyscall_argument:ste:1 + + + openssl-pkcs11 + + + ^/boot/config-.*$ + ^CONFIG_ACPI_CUSTOM_METHOD="?(.*?)"?$ + 1 + + + oval:ssg-local_var_config_acpi_custom_method_count_kernels_installed:var:1 + + + /boot + ^config-.*$ + + + ^/boot/config-.*$ + ^CONFIG_ARM64_SW_TTBR0_PAN="?(.*?)"?$ + 1 + + + oval:ssg-local_var_config_arm64_sw_ttbr0_pan_count_kernels_installed:var:1 + + + /boot + ^config-.*$ + + + ^/boot/config-.*$ + ^CONFIG_BINFMT_MISC="?(.*?)"?$ + 1 + + + oval:ssg-local_var_config_binfmt_misc_count_kernels_installed:var:1 + + + /boot + ^config-.*$ + + + ^/boot/config-.*$ + ^CONFIG_BUG="?(.*?)"?$ + 1 + + + oval:ssg-local_var_config_bug_count_kernels_installed:var:1 + + + /boot + ^config-.*$ + + + ^/boot/config-.*$ + ^CONFIG_BUG_ON_DATA_CORRUPTION="?(.*?)"?$ + 1 + + + oval:ssg-local_var_config_bug_on_data_corruption_count_kernels_installed:var:1 + + + /boot + ^config-.*$ + + + ^/boot/config-.*$ + ^CONFIG_COMPAT_BRK="?(.*?)"?$ + 1 + + + oval:ssg-local_var_config_compat_brk_count_kernels_installed:var:1 + + + /boot + ^config-.*$ + + + ^/boot/config-.*$ + ^CONFIG_COMPAT_VDSO="?(.*?)"?$ + 1 + + + oval:ssg-local_var_config_compat_vdso_count_kernels_installed:var:1 + + + /boot + ^config-.*$ + + + ^/boot/config-.*$ + ^CONFIG_DEBUG_CREDENTIALS="?(.*?)"?$ + 1 + + + oval:ssg-local_var_config_debug_credentials_count_kernels_installed:var:1 + + + /boot + ^config-.*$ + + + ^/boot/config-.*$ + ^CONFIG_DEBUG_FS="?(.*?)"?$ + 1 + + + oval:ssg-local_var_config_debug_fs_count_kernels_installed:var:1 + + + /boot + ^config-.*$ + + + ^/boot/config-.*$ + ^CONFIG_DEBUG_LIST="?(.*?)"?$ + 1 + + + oval:ssg-local_var_config_debug_list_count_kernels_installed:var:1 + + + /boot + ^config-.*$ + + + ^/boot/config-.*$ + ^CONFIG_DEBUG_NOTIFIERS="?(.*?)"?$ + 1 + + + oval:ssg-local_var_config_debug_notifiers_count_kernels_installed:var:1 + + + /boot + ^config-.*$ + + + ^/boot/config-.*$ + ^CONFIG_DEBUG_SG="?(.*?)"?$ + 1 + + + oval:ssg-local_var_config_debug_sg_count_kernels_installed:var:1 + + + /boot + ^config-.*$ + + + ^/boot/config-.*$ + ^CONFIG_DEBUG_WX="?(.*?)"?$ + 1 + + + oval:ssg-local_var_config_debug_wx_count_kernels_installed:var:1 + + + /boot + ^config-.*$ + + + ^/boot/config-.*$ + ^CONFIG_DEVKMEM="?(.*?)"?$ + 1 + + + oval:ssg-local_var_config_devkmem_count_kernels_installed:var:1 + + + /boot + ^config-.*$ + + + ^/boot/config-.*$ + ^CONFIG_FORTIFY_SOURCE="?(.*?)"?$ + 1 + + + oval:ssg-local_var_config_fortify_source_count_kernels_installed:var:1 + + + /boot + ^config-.*$ + + + ^/boot/config-.*$ + ^CONFIG_GCC_PLUGIN_LATENT_ENTROPY="?(.*?)"?$ + 1 + + + oval:ssg-local_var_config_gcc_plugin_latent_entropy_count_kernels_installed:var:1 + + + /boot + ^config-.*$ + + + ^/boot/config-.*$ + ^CONFIG_GCC_PLUGIN_RANDSTRUCT="?(.*?)"?$ + 1 + + + oval:ssg-local_var_config_gcc_plugin_randstruct_count_kernels_installed:var:1 + + + /boot + ^config-.*$ + + + ^/boot/config-.*$ + ^CONFIG_GCC_PLUGIN_STACKLEAK="?(.*?)"?$ + 1 + + + oval:ssg-local_var_config_gcc_plugin_stackleak_count_kernels_installed:var:1 + + + /boot + ^config-.*$ + + + ^/boot/config-.*$ + ^CONFIG_GCC_PLUGIN_STRUCTLEAK="?(.*?)"?$ + 1 + + + oval:ssg-local_var_config_gcc_plugin_structleak_count_kernels_installed:var:1 + + + /boot + ^config-.*$ + + + ^/boot/config-.*$ + ^CONFIG_GCC_PLUGIN_STRUCTLEAK_BYREF_ALL="?(.*?)"?$ + 1 + + + oval:ssg-local_var_config_gcc_plugin_structleak_byref_all_count_kernels_installed:var:1 + + + /boot + ^config-.*$ + + + ^/boot/config-.*$ + ^CONFIG_HARDENED_USERCOPY="?(.*?)"?$ + 1 + + + oval:ssg-local_var_config_hardened_usercopy_count_kernels_installed:var:1 + + + /boot + ^config-.*$ + + + ^/boot/config-.*$ + ^CONFIG_HARDENED_USERCOPY_FALLBACK="?(.*?)"?$ + 1 + + + oval:ssg-local_var_config_hardened_usercopy_fallback_count_kernels_installed:var:1 + + + /boot + ^config-.*$ + + + ^/boot/config-.*$ + ^CONFIG_HIBERNATION="?(.*?)"?$ + 1 + + + oval:ssg-local_var_config_hibernation_count_kernels_installed:var:1 + + + /boot + ^config-.*$ + + + ^/boot/config-.*$ + ^CONFIG_IA32_EMULATION="?(.*?)"?$ + 1 + + + oval:ssg-local_var_config_ia32_emulation_count_kernels_installed:var:1 + + + /boot + ^config-.*$ + + + ^/boot/config-.*$ + ^CONFIG_IPV6="?(.*?)"?$ + 1 + + + oval:ssg-local_var_config_ipv6_count_kernels_installed:var:1 + + + /boot + ^config-.*$ + + + ^/boot/config-.*$ + ^CONFIG_KEXEC="?(.*?)"?$ + 1 + + + oval:ssg-local_var_config_kexec_count_kernels_installed:var:1 + + + /boot + ^config-.*$ + + + ^/boot/config-.*$ + ^CONFIG_LEGACY_PTYS="?(.*?)"?$ + 1 + + + oval:ssg-local_var_config_legacy_ptys_count_kernels_installed:var:1 + + + /boot + ^config-.*$ + + + ^/boot/config-.*$ + ^CONFIG_LEGACY_VSYSCALL_EMULATE="?(.*?)"?$ + 1 + + + oval:ssg-local_var_config_legacy_vsyscall_emulate_count_kernels_installed:var:1 + + + /boot + ^config-.*$ + + + ^/boot/config-.*$ + ^CONFIG_LEGACY_VSYSCALL_NONE="?(.*?)"?$ + 1 + + + oval:ssg-local_var_config_legacy_vsyscall_none_count_kernels_installed:var:1 + + + /boot + ^config-.*$ + + + ^/boot/config-.*$ + ^CONFIG_LEGACY_VSYSCALL_XONLY="?(.*?)"?$ + 1 + + + oval:ssg-local_var_config_legacy_vsyscall_xonly_count_kernels_installed:var:1 + + + /boot + ^config-.*$ + + + ^/boot/config-.*$ + ^CONFIG_MODIFY_LDT_SYSCALL="?(.*?)"?$ + 1 + + + oval:ssg-local_var_config_modify_ldt_syscall_count_kernels_installed:var:1 + + + /boot + ^config-.*$ + + + ^/boot/config-.*$ + ^CONFIG_MODULE_SIG="?(.*?)"?$ + 1 + + + oval:ssg-local_var_config_module_sig_count_kernels_installed:var:1 + + + /boot + ^config-.*$ + + + ^/boot/config-.*$ + ^CONFIG_MODULE_SIG_ALL="?(.*?)"?$ + 1 + + + oval:ssg-local_var_config_module_sig_all_count_kernels_installed:var:1 + + + /boot + ^config-.*$ + + + ^/boot/config-.*$ + ^CONFIG_MODULE_SIG_FORCE="?(.*?)"?$ + 1 + + + oval:ssg-local_var_config_module_sig_force_count_kernels_installed:var:1 + + + /boot + ^config-.*$ + + + ^/boot/config-.*$ + ^CONFIG_MODULE_SIG_HASH="?(.*?)"?$ + 1 + + + oval:ssg-local_var_config_module_sig_hash_count_kernels_installed:var:1 + + + /boot + ^config-.*$ + + + ^/boot/config-.*$ + ^CONFIG_MODULE_SIG_KEY="?(.*?)"?$ + 1 + + + oval:ssg-local_var_config_module_sig_key_count_kernels_installed:var:1 + + + /boot + ^config-.*$ + + + ^/boot/config-.*$ + ^CONFIG_MODULE_SIG_SHA512="?(.*?)"?$ + 1 + + + oval:ssg-local_var_config_module_sig_sha512_count_kernels_installed:var:1 + + + /boot + ^config-.*$ + + + ^/boot/config-.*$ + ^CONFIG_PAGE_POISONING="?(.*?)"?$ + 1 + + + oval:ssg-local_var_config_page_poisoning_count_kernels_installed:var:1 + + + /boot + ^config-.*$ + + + ^/boot/config-.*$ + ^CONFIG_PAGE_POISONING_NO_SANITY="?(.*?)"?$ + 1 + + + oval:ssg-local_var_config_page_poisoning_no_sanity_count_kernels_installed:var:1 + + + /boot + ^config-.*$ + + + ^/boot/config-.*$ + ^CONFIG_PAGE_POISONING_ZERO="?(.*?)"?$ + 1 + + + oval:ssg-local_var_config_page_poisoning_zero_count_kernels_installed:var:1 + + + /boot + ^config-.*$ + + + ^/boot/config-.*$ + ^CONFIG_PAGE_TABLE_ISOLATION="?(.*?)"?$ + 1 + + + oval:ssg-local_var_config_page_table_isolation_count_kernels_installed:var:1 + + + /boot + ^config-.*$ + + + ^/boot/config-.*$ + ^CONFIG_PANIC_ON_OOPS="?(.*?)"?$ + 1 + + + oval:ssg-local_var_config_panic_on_oops_count_kernels_installed:var:1 + + + /boot + ^config-.*$ + + + ^/boot/config-.*$ + ^CONFIG_PANIC_TIMEOUT="?(.*?)"?$ + 1 + + + oval:ssg-local_var_config_panic_timeout_count_kernels_installed:var:1 + + + /boot + ^config-.*$ + + + ^/boot/config-.*$ + ^CONFIG_PROC_KCORE="?(.*?)"?$ + 1 + + + oval:ssg-local_var_config_proc_kcore_count_kernels_installed:var:1 + + + /boot + ^config-.*$ + + + ^/boot/config-.*$ + ^CONFIG_RANDOMIZE_BASE="?(.*?)"?$ + 1 + + + oval:ssg-local_var_config_randomize_base_count_kernels_installed:var:1 + + + /boot + ^config-.*$ + + + ^/boot/config-.*$ + ^CONFIG_RANDOMIZE_MEMORY="?(.*?)"?$ + 1 + + + oval:ssg-local_var_config_randomize_memory_count_kernels_installed:var:1 + + + /boot + ^config-.*$ + + + ^/boot/config-.*$ + ^CONFIG_REFCOUNT_FULL="?(.*?)"?$ + 1 + + + oval:ssg-local_var_config_refcount_full_count_kernels_installed:var:1 + + + /boot + ^config-.*$ + + + ^/boot/config-.*$ + ^CONFIG_RETPOLINE="?(.*?)"?$ + 1 + + + oval:ssg-local_var_config_retpoline_count_kernels_installed:var:1 + + + /boot + ^config-.*$ + + + ^/boot/config-.*$ + ^CONFIG_SCHED_STACK_END_CHECK="?(.*?)"?$ + 1 + + + oval:ssg-local_var_config_sched_stack_end_check_count_kernels_installed:var:1 + + + /boot + ^config-.*$ + + + ^/boot/config-.*$ + ^CONFIG_SECCOMP="?(.*?)"?$ + 1 + + + oval:ssg-local_var_config_seccomp_count_kernels_installed:var:1 + + + /boot + ^config-.*$ + + + ^/boot/config-.*$ + ^CONFIG_SECCOMP_FILTER="?(.*?)"?$ + 1 + + + oval:ssg-local_var_config_seccomp_filter_count_kernels_installed:var:1 + + + /boot + ^config-.*$ + + + ^/boot/config-.*$ + ^CONFIG_SECURITY="?(.*?)"?$ + 1 + + + oval:ssg-local_var_config_security_count_kernels_installed:var:1 + + + /boot + ^config-.*$ + + + ^/boot/config-.*$ + ^CONFIG_SECURITY_DMESG_RESTRICT="?(.*?)"?$ + 1 + + + oval:ssg-local_var_config_security_dmesg_restrict_count_kernels_installed:var:1 + + + /boot + ^config-.*$ + + + ^/boot/config-.*$ + ^CONFIG_SECURITY_WRITABLE_HOOKS="?(.*?)"?$ + 1 + + + oval:ssg-local_var_config_security_writable_hooks_count_kernels_installed:var:1 + + + /boot + ^config-.*$ + + + ^/boot/config-.*$ + ^CONFIG_SECURITY_YAMA="?(.*?)"?$ + 1 + + + oval:ssg-local_var_config_security_yama_count_kernels_installed:var:1 + + + /boot + ^config-.*$ + + + ^/boot/config-.*$ + ^CONFIG_SLAB_FREELIST_HARDENED="?(.*?)"?$ + 1 + + + oval:ssg-local_var_config_slab_freelist_hardened_count_kernels_installed:var:1 + + + /boot + ^config-.*$ + + + ^/boot/config-.*$ + ^CONFIG_SLAB_FREELIST_RANDOM="?(.*?)"?$ + 1 + + + oval:ssg-local_var_config_slab_freelist_random_count_kernels_installed:var:1 + + + /boot + ^config-.*$ + + + ^/boot/config-.*$ + ^CONFIG_SLAB_MERGE_DEFAULT="?(.*?)"?$ + 1 + + + oval:ssg-local_var_config_slab_merge_default_count_kernels_installed:var:1 + + + /boot + ^config-.*$ + + + ^/boot/config-.*$ + ^CONFIG_SLUB_DEBUG="?(.*?)"?$ + 1 + + + oval:ssg-local_var_config_slub_debug_count_kernels_installed:var:1 + + + /boot + ^config-.*$ + + + ^/boot/config-.*$ + ^CONFIG_STACKPROTECTOR="?(.*?)"?$ + 1 + + + oval:ssg-local_var_config_stackprotector_count_kernels_installed:var:1 + + + /boot + ^config-.*$ + + + ^/boot/config-.*$ + ^CONFIG_STACKPROTECTOR_STRONG="?(.*?)"?$ + 1 + + + oval:ssg-local_var_config_stackprotector_strong_count_kernels_installed:var:1 + + + /boot + ^config-.*$ + + + ^/boot/config-.*$ + ^CONFIG_STRICT_KERNEL_RWX="?(.*?)"?$ + 1 + + + oval:ssg-local_var_config_strict_kernel_rwx_count_kernels_installed:var:1 + + + /boot + ^config-.*$ + + + ^/boot/config-.*$ + ^CONFIG_STRICT_MODULE_RWX="?(.*?)"?$ + 1 + + + oval:ssg-local_var_config_strict_module_rwx_count_kernels_installed:var:1 + + + /boot + ^config-.*$ + + + ^/boot/config-.*$ + ^CONFIG_SYN_COOKIES="?(.*?)"?$ + 1 + + + oval:ssg-local_var_config_syn_cookies_count_kernels_installed:var:1 + + + /boot + ^config-.*$ + + + ^/boot/config-.*$ + ^CONFIG_UNMAP_KERNEL_AT_EL0="?(.*?)"?$ + 1 + + + oval:ssg-local_var_config_unmap_kernel_at_el0_count_kernels_installed:var:1 + + + /boot + ^config-.*$ + + + ^/boot/config-.*$ + ^CONFIG_VMAP_STACK="?(.*?)"?$ + 1 + + + oval:ssg-local_var_config_vmap_stack_count_kernels_installed:var:1 + + + /boot + ^config-.*$ + + + ^/boot/config-.*$ + ^CONFIG_X86_VSYSCALL_EMULATION="?(.*?)"?$ + 1 + + + oval:ssg-local_var_config_x86_vsyscall_emulation_count_kernels_installed:var:1 + + + /boot + ^config-.*$ + + + + ^.*\.conf$ + ^\s*install\s+atm\s+(/bin/false|/bin/true)$ + 1 + + + + ^.*\.conf$ + ^blacklist\s+atm$ + 1 + + + + ^.*\.conf$ + ^\s*install\s+bluetooth\s+(/bin/false|/bin/true)$ + 1 + + + + ^.*\.conf$ + ^blacklist\s+bluetooth$ + 1 + + + + ^.*\.conf$ + ^\s*install\s+can\s+(/bin/false|/bin/true)$ + 1 + + + + ^.*\.conf$ + ^blacklist\s+can$ + 1 + + + + ^.*\.conf$ + ^\s*install\s+cramfs\s+(/bin/false|/bin/true)$ + 1 + + + + ^.*\.conf$ + ^blacklist\s+cramfs$ + 1 + + + + ^.*\.conf$ + ^\s*install\s+dccp\s+(/bin/false|/bin/true)$ + 1 + + + + ^.*\.conf$ + ^blacklist\s+dccp$ + 1 + + + + ^.*\.conf$ + ^\s*install\s+firewire-core\s+(/bin/false|/bin/true)$ + 1 + + + + ^.*\.conf$ + ^blacklist\s+firewire-core$ + 1 + + + + ^.*\.conf$ + ^\s*install\s+rds\s+(/bin/false|/bin/true)$ + 1 + + + + ^.*\.conf$ + ^blacklist\s+rds$ + 1 + + + + ^.*\.conf$ + ^\s*install\s+sctp\s+(/bin/false|/bin/true)$ + 1 + + + + ^.*\.conf$ + ^blacklist\s+sctp$ + 1 + + + + ^.*\.conf$ + ^\s*install\s+squashfs\s+(/bin/false|/bin/true)$ + 1 + + + + ^.*\.conf$ + ^blacklist\s+squashfs$ + 1 + + + + ^.*\.conf$ + ^\s*install\s+tipc\s+(/bin/false|/bin/true)$ + 1 + + + + ^.*\.conf$ + ^blacklist\s+tipc$ + 1 + + + + ^.*\.conf$ + ^\s*install\s+udf\s+(/bin/false|/bin/true)$ + 1 + + + + ^.*\.conf$ + ^blacklist\s+udf$ + 1 + + + + ^.*\.conf$ + ^\s*install\s+usb-storage\s+(/bin/false|/bin/true)$ + 1 + + + + ^.*\.conf$ + ^blacklist\s+usb-storage$ + 1 + + + + ^.*\.conf$ + ^\s*install\s+uvcvideo\s+(/bin/false|/bin/true)$ + 1 + + + + ^.*\.conf$ + ^blacklist\s+uvcvideo$ + 1 + + + /boot/efi + + + /etc/fstab + ^[\s]*(?!#)[\S]+[\s]+/boot/efi[\s]+[\S]+[\s]+([\S]+) + 1 + + + /boot + + + /etc/fstab + ^[\s]*(?!#)[\S]+[\s]+/boot[\s]+[\S]+[\s]+([\S]+) + 1 + + + /boot + + + /etc/fstab + ^[\s]*(?!#)[\S]+[\s]+/boot[\s]+[\S]+[\s]+([\S]+) + 1 + + + /boot + + + /etc/fstab + ^[\s]*(?!#)[\S]+[\s]+/boot[\s]+[\S]+[\s]+([\S]+) + 1 + + + /dev/shm + + + /etc/fstab + ^[\s]*(?!#)[\S]+[\s]+/dev/shm[\s]+[\S]+[\s]+([\S]+) + 1 + + + /dev/shm + + + /etc/fstab + ^[\s]*(?!#)[\S]+[\s]+/dev/shm[\s]+[\S]+[\s]+([\S]+) + 1 + + + /dev/shm + + + /etc/fstab + ^[\s]*(?!#)[\S]+[\s]+/dev/shm[\s]+[\S]+[\s]+([\S]+) + 1 + + + /etc/passwd + + 1 + + + / + + + + + + /home + + + /etc/fstab + ^[\s]*(?!#)[\S]+[\s]+/home[\s]+[\S]+[\s]+([\S]+) + 1 + + + /etc/passwd + + 1 + + + / + + + + + + /etc/passwd + + 1 + + + / + + + + + + /etc/passwd + + 1 + + + / + + + + + + /etc/fstab + ^\s*\[?[\.\w:-]+\]?[:=][/\w-]+\s+[/\w\\-]+\s+nfs[4]?\s+(.*)$ + 0 + + + /etc/fstab + ^\s*\[?[\.\w:-]+\]?[:=][/\w-]+\s+[/\w\\-]+\s+nfs[4]?\s+(.*)$ + 0 + + + /etc/fstab + + 1 + + + /etc/fstab + + 1 + + + /etc/fstab + ^\s*\[?[\.\w:-]+\]?[:=][/\w-]+\s+[/\w\\-]+\s+nfs[4]?\s+(.*)$ + 0 + + + /etc/fstab + + 1 + + + /etc/fstab + + 1 + + + /etc/fstab + ^\s*\[?[\.\w:-]+\]?[:=][/\w-]+\s+[/\w\\-]+\s+nfs[4]?\s+(.*)$ + 0 + + + /etc/fstab + + 1 + + + /etc/fstab + + 1 + + + /opt + + + /etc/fstab + ^[\s]*(?!#)[\S]+[\s]+/opt[\s]+[\S]+[\s]+([\S]+) + 1 + + + /srv + + + /etc/fstab + ^[\s]*(?!#)[\S]+[\s]+/srv[\s]+[\S]+[\s]+([\S]+) + 1 + + + /tmp + + + /etc/fstab + ^[\s]*(?!#)[\S]+[\s]+/tmp[\s]+[\S]+[\s]+([\S]+) + 1 + + + /tmp + + + /etc/fstab + ^[\s]*(?!#)[\S]+[\s]+/tmp[\s]+[\S]+[\s]+([\S]+) + 1 + + + /tmp + + + /etc/fstab + ^[\s]*(?!#)[\S]+[\s]+/tmp[\s]+[\S]+[\s]+([\S]+) + 1 + + + /var/log/audit + + + /etc/fstab + ^[\s]*(?!#)[\S]+[\s]+/var/log/audit[\s]+[\S]+[\s]+([\S]+) + 1 + + + /var/log/audit + + + /etc/fstab + ^[\s]*(?!#)[\S]+[\s]+/var/log/audit[\s]+[\S]+[\s]+([\S]+) + 1 + + + /var/log/audit + + + /etc/fstab + ^[\s]*(?!#)[\S]+[\s]+/var/log/audit[\s]+[\S]+[\s]+([\S]+) + 1 + + + /var/log + + + /etc/fstab + ^[\s]*(?!#)[\S]+[\s]+/var/log[\s]+[\S]+[\s]+([\S]+) + 1 + + + /var/log + + + /etc/fstab + ^[\s]*(?!#)[\S]+[\s]+/var/log[\s]+[\S]+[\s]+([\S]+) + 1 + + + /var/log + + + /etc/fstab + ^[\s]*(?!#)[\S]+[\s]+/var/log[\s]+[\S]+[\s]+([\S]+) + 1 + + + /var + + + /etc/fstab + ^[\s]*(?!#)[\S]+[\s]+/var[\s]+[\S]+[\s]+([\S]+) + 1 + + + /var + + + /etc/fstab + ^[\s]*(?!#)[\S]+[\s]+/var[\s]+[\S]+[\s]+([\S]+) + 1 + + + /var + + + /etc/fstab + ^[\s]*(?!#)[\S]+[\s]+/var[\s]+[\S]+[\s]+([\S]+) + 1 + + + /var/tmp + + + /etc/fstab + ^[\s]*(?!#)[\S]+[\s]+/var/tmp[\s]+[\S]+[\s]+([\S]+) + 1 + + + /var/tmp + + + /etc/fstab + ^[\s]*(?!#)[\S]+[\s]+/var/tmp[\s]+[\S]+[\s]+([\S]+) + 1 + + + /var/tmp + + + /etc/fstab + ^[\s]*(?!#)[\S]+[\s]+/var/tmp[\s]+[\S]+[\s]+([\S]+) + 1 + + + aide + + + audispd-plugins + + + audit + + + bind + + + chrony + + + cronie + + + crypto-policies + + + cryptsetup + + + cyrus-imapd + + + dconf + + + dhcp + + + dnf-automatic + + + dovecot + + + fapolicyd + + + firewalld + + + ftp + + + gdm + + + gnutls-utils + + + gssproxy + + + inetutils-telnetd + + + iprutils + + + libreswan + + + libselinux + + + logrotate + + + McAfeeTP + + + net-snmp + + + nfs-utils + + + nftables + + + nis + + + nss-tools + + + opensc + + + openscap-scanner + + + openssh-clients + + + openssh-server + + + openssh-server + + + pcsc-lite + + + policycoreutils-python-utils + + + policycoreutils + + + postfix + + + quagga + + + rear + + + rng-tools + + + rsh-server + + + rsh + + + rsyslog-gnutls + + + rsyslog + + + s-nail + + + scap-security-guide + + + sendmail + + + setroubleshoot-plugins + + + setroubleshoot-server + + + setroubleshoot + + + squid + + + sssd + + + sudo + + + syslog-ng + + + talk-server + + + talk + + + telnet-server + + + telnet + + + telnetd-ssl + + + telnetd + + + tftp-server + + + tftp + + + tuned + + + usbguard + + + vsftpd + + + xorg-x11-server-common + + + /dev/shm + + + /home + + + /srv + + + /tmp + + + /var + + + /var/log + + + /var/log/audit + + + /var/tmp + + + + /lib + ^.*$ + oval:ssg-symlink_file_groupownerroot_permissions_syslibrary_files_uid_0:ste:1 + oval:ssg-state_file_groupownerroot_permissions_syslibrary_files_gid_0_0:ste:1 + + + + /lib64 + ^.*$ + oval:ssg-symlink_file_groupownerroot_permissions_syslibrary_files_uid_0:ste:1 + oval:ssg-state_file_groupownerroot_permissions_syslibrary_files_gid_0_1:ste:1 + + + + /usr/lib + ^.*$ + oval:ssg-symlink_file_groupownerroot_permissions_syslibrary_files_uid_0:ste:1 + oval:ssg-state_file_groupownerroot_permissions_syslibrary_files_gid_0_2:ste:1 + + + + /usr/lib64 + ^.*$ + oval:ssg-symlink_file_groupownerroot_permissions_syslibrary_files_uid_0:ste:1 + oval:ssg-state_file_groupownerroot_permissions_syslibrary_files_gid_0_3:ste:1 + + + /etc/rsyslog.conf + ^(?:include\([\n\s]*file="([^\s;]+)".*|\$IncludeConfig[\s]+([^\s;]+))$ + 1 + + + oval:ssg-var_rsyslog_files_groupownership_include_config_regex:var:1 + + + oval:ssg-var_rsyslog_files_groupownership_syslog_config:var:1 + + + + oval:ssg-object_var_rsyslog_files_groupownership_include_config_regex:obj:1 + oval:ssg-object_var_rsyslog_files_groupownership_syslog_config:obj:1 + + + + + ^\s*[^(\s|#|\$)]+\s+.*(?:\bFile="|\s|\/|-)(\/[^:;\s"]+).*$ + 1 + oval:ssg-state_rsyslog_files_groupownership_ignore_include_paths:ste:1 + + + + + + /etc/group + ^root:\w+:(\w+):.* + 1 + + + /etc/rsyslog.conf + ^(?:include\([\n\s]*file="([^\s;]+)".*|\$IncludeConfig[\s]+([^\s;]+))$ + 1 + + + oval:ssg-var_rsyslog_files_ownership_include_config_regex:var:1 + + + oval:ssg-var_rsyslog_files_ownership_syslog_config:var:1 + + + + oval:ssg-object_var_rsyslog_files_ownership_include_config_regex:obj:1 + oval:ssg-object_var_rsyslog_files_ownership_syslog_config:obj:1 + + + + + ^\s*[^(\s|#|\$)]+\s+.*(?:\bFile="|\s|\/|-)(\/[^:;\s"]+).*$ + 1 + oval:ssg-state_rsyslog_files_ownership_ignore_include_paths:ste:1 + + + + + + /etc/passwd + ^root:\w+:(\w+):.* + 1 + + + /etc/rsyslog.conf + ^(?:include\([\n\s]*file="([^\s;]+)".*|\$IncludeConfig[\s]+([^\s;]+))$ + 1 + + + oval:ssg-var_rsyslog_files_permissions_include_config_regex:var:1 + + + oval:ssg-var_rsyslog_files_permissions_syslog_config:var:1 + + + + oval:ssg-object_var_rsyslog_files_permissions_include_config_regex:obj:1 + oval:ssg-object_var_rsyslog_files_permissions_syslog_config:obj:1 + + + + + ^\s*[^(\s|#|\$)]+\s+.*(?:\bFile="|\s|\/|-)(\/[^:;\s"]+).*$ + 1 + oval:ssg-state_rsyslog_files_permissions_ignore_include_paths:ste:1 + + + + + + auditadm_exec_content + + + authlogin_nsswitch_use_ldap + + + authlogin_radius + + + deny_execmem + + + kerberos_enabled + + + polyinstantiation_enabled + + + secure_mode_insmod + + + selinuxuser_execheap + + + selinuxuser_execmod + + + selinuxuser_execstack + + + ssh_sysadm_login + + + ^atd\.(service|socket)$ + ActiveState + + + ^atd\.(service|socket)$ + LoadState + + + at + + + multi-user.target + + + multi-user.target + + + ^auditd\.(socket|service)$ + ActiveState + + + audit + + + ^autofs\.(service|socket)$ + ActiveState + + + ^autofs\.(service|socket)$ + LoadState + + + autofs + + + ^avahi-daemon\.(service|socket)$ + ActiveState + + + ^avahi-daemon\.(service|socket)$ + LoadState + + + avahi + + + multi-user.target + + + multi-user.target + + + ^chronyd\.(socket|service)$ + ActiveState + + + chrony + + + multi-user.target + + + multi-user.target + + + ^crond\.(socket|service)$ + ActiveState + + + cronie + + + ^debug-shell\.(service|socket)$ + ActiveState + + + ^debug-shell\.(service|socket)$ + LoadState + + + systemd + + + multi-user.target + + + multi-user.target + + + ^fapolicyd\.(socket|service)$ + ActiveState + + + fapolicyd + + + multi-user.target + + + multi-user.target + + + ^firewalld\.(socket|service)$ + ActiveState + + + firewalld + + + multi-user.target + + + multi-user.target + + + ^iptables\.(socket|service)$ + ActiveState + + + iptables + + + ^kdump\.(service|socket)$ + ActiveState + + + ^kdump\.(service|socket)$ + LoadState + + + kexec-tools + + + ^nftables\.(service|socket)$ + ActiveState + + + ^nftables\.(service|socket)$ + LoadState + + + nftables + + + ^oddjobd\.(service|socket)$ + ActiveState + + + ^oddjobd\.(service|socket)$ + LoadState + + + oddjob + + + multi-user.target + + + multi-user.target + + + ^pcscd\.(socket|service)$ + ActiveState + + + pcsc-lite + + + multi-user.target + + + multi-user.target + + + ^postfix\.(socket|service)$ + ActiveState + + + postfix + + + ^rdisc\.(service|socket)$ + ActiveState + + + ^rdisc\.(service|socket)$ + LoadState + + + iputils + + + ^rlogin\.(service|socket)$ + ActiveState + + + ^rlogin\.(service|socket)$ + LoadState + + + rsh-server + + + multi-user.target + + + multi-user.target + + + ^rngd\.(socket|service)$ + ActiveState + + + rng-tools + + + ^rsyncd\.(service|socket)$ + ActiveState + + + ^rsyncd\.(service|socket)$ + LoadState + + + rsync-daemon + + + multi-user.target + + + multi-user.target + + + ^rsyslog\.(socket|service)$ + ActiveState + + + rsyslog + + + ^snmpd\.(service|socket)$ + ActiveState + + + ^snmpd\.(service|socket)$ + LoadState + + + net-snmp + + + ^squid\.(service|socket)$ + ActiveState + + + ^squid\.(service|socket)$ + LoadState + + + squid + + + ^sshd\.(service|socket)$ + ActiveState + + + ^sshd\.(service|socket)$ + LoadState + + + openssh-server + + + multi-user.target + + + multi-user.target + + + ^sshd\.(socket|service)$ + ActiveState + + + openssh-server + + + multi-user.target + + + multi-user.target + + + ^sssd\.(socket|service)$ + ActiveState + + + sssd-common + + + multi-user.target + + + multi-user.target + + + ^syslog-ng\.(socket|service)$ + ActiveState + + + syslog-ng + + + ^systemd-coredump.socket$ + LoadState + + + multi-user.target + + + multi-user.target + + + ^systemd-journald\.(socket|service)$ + ActiveState + + + systemd + + + ^telnet\.(service|socket)$ + ActiveState + + + ^telnet\.(service|socket)$ + LoadState + + + telnet-server + + + multi-user.target + + + multi-user.target + + + ^ufw\.(socket|service)$ + ActiveState + + + ufw + + + multi-user.target + + + multi-user.target + + + ^usbguard\.(socket|service)$ + ActiveState + + + usbguard + + + /etc/firewalld/firewalld.conf + ^[\s]*DefaultZone=drop[\s]*$ + 1 + + + /etc/ssh/sshd_config + ^[ \t]*(?i)include(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + + ^[ \t]*(?i)Protocol(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + /etc/ssh/sshd_config + ^[ \t]*(?i)Protocol(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + + oval:ssg-obj_sshd_allow_only_protocol2:obj:1 + oval:ssg-obj_sshd_allow_only_protocol2_sshd_included_files:obj:1 + + + + /etc/ssh/sshd_config + ^[ \t]*(?i)include(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + + ^[ \t]*(?i)Compression(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + /etc/ssh/sshd_config + ^[ \t]*(?i)Compression(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + + oval:ssg-obj_sshd_disable_compression:obj:1 + oval:ssg-obj_sshd_disable_compression_sshd_included_files:obj:1 + + + + /etc/ssh/sshd_config + ^[ \t]*(?i)include(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + + ^[ \t]*(?i)PermitEmptyPasswords(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + /etc/ssh/sshd_config + ^[ \t]*(?i)PermitEmptyPasswords(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + + oval:ssg-obj_sshd_disable_empty_passwords:obj:1 + oval:ssg-obj_sshd_disable_empty_passwords_sshd_included_files:obj:1 + + + + /etc/ssh/sshd_config + ^[ \t]*(?i)include(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + + ^[ \t]*(?i)GSSAPIAuthentication(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + /etc/ssh/sshd_config + ^[ \t]*(?i)GSSAPIAuthentication(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + + oval:ssg-obj_sshd_disable_gssapi_auth:obj:1 + oval:ssg-obj_sshd_disable_gssapi_auth_sshd_included_files:obj:1 + + + + /etc/ssh/sshd_config + ^[ \t]*(?i)include(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + + ^[ \t]*(?i)KerberosAuthentication(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + /etc/ssh/sshd_config + ^[ \t]*(?i)KerberosAuthentication(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + + oval:ssg-obj_sshd_disable_kerb_auth:obj:1 + oval:ssg-obj_sshd_disable_kerb_auth_sshd_included_files:obj:1 + + + + /etc/ssh/sshd_config + ^[ \t]*(?i)include(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + + ^[ \t]*(?i)PubkeyAuthentication(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + /etc/ssh/sshd_config + ^[ \t]*(?i)PubkeyAuthentication(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + + oval:ssg-obj_sshd_disable_pubkey_auth:obj:1 + oval:ssg-obj_sshd_disable_pubkey_auth_sshd_included_files:obj:1 + + + + /etc/ssh/sshd_config + ^[ \t]*(?i)include(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + + ^[ \t]*(?i)IgnoreRhosts(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + /etc/ssh/sshd_config + ^[ \t]*(?i)IgnoreRhosts(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + + oval:ssg-obj_sshd_disable_rhosts:obj:1 + oval:ssg-obj_sshd_disable_rhosts_sshd_included_files:obj:1 + + + + /etc/ssh/sshd_config + ^[ \t]*(?i)include(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + + ^[ \t]*(?i)RhostsRSAAuthentication(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + /etc/ssh/sshd_config + ^[ \t]*(?i)RhostsRSAAuthentication(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + + oval:ssg-obj_sshd_disable_rhosts_rsa:obj:1 + oval:ssg-obj_sshd_disable_rhosts_rsa_sshd_included_files:obj:1 + + + + /etc/ssh/sshd_config + ^[ \t]*(?i)include(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + + ^[ \t]*(?i)PermitRootLogin(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + /etc/ssh/sshd_config + ^[ \t]*(?i)PermitRootLogin(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + + oval:ssg-obj_sshd_disable_root_login:obj:1 + oval:ssg-obj_sshd_disable_root_login_sshd_included_files:obj:1 + + + + /etc/ssh/sshd_config + ^[ \t]*(?i)include(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + + ^[ \t]*(?i)PermitRootLogin(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + /etc/ssh/sshd_config + ^[ \t]*(?i)PermitRootLogin(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + + oval:ssg-obj_sshd_disable_root_password_login:obj:1 + oval:ssg-obj_sshd_disable_root_password_login_sshd_included_files:obj:1 + + + + /etc/ssh/sshd_config + ^[ \t]*(?i)include(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + + ^[ \t]*(?i)AllowTcpForwarding(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + /etc/ssh/sshd_config + ^[ \t]*(?i)AllowTcpForwarding(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + + oval:ssg-obj_sshd_disable_tcp_forwarding:obj:1 + oval:ssg-obj_sshd_disable_tcp_forwarding_sshd_included_files:obj:1 + + + + /etc/ssh/sshd_config + ^[ \t]*(?i)include(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + + ^[ \t]*(?i)IgnoreUserKnownHosts(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + /etc/ssh/sshd_config + ^[ \t]*(?i)IgnoreUserKnownHosts(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + + oval:ssg-obj_sshd_disable_user_known_hosts:obj:1 + oval:ssg-obj_sshd_disable_user_known_hosts_sshd_included_files:obj:1 + + + + /etc/ssh/sshd_config + ^[ \t]*(?i)include(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + + ^[ \t]*(?i)X11Forwarding(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + /etc/ssh/sshd_config + ^[ \t]*(?i)X11Forwarding(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + + oval:ssg-obj_sshd_disable_x11_forwarding:obj:1 + oval:ssg-obj_sshd_disable_x11_forwarding_sshd_included_files:obj:1 + + + + /etc/ssh/sshd_config + ^[ \t]*(?i)include(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + + ^[ \t]*(?i)PermitUserEnvironment(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + /etc/ssh/sshd_config + ^[ \t]*(?i)PermitUserEnvironment(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + + oval:ssg-obj_sshd_do_not_permit_user_env:obj:1 + oval:ssg-obj_sshd_do_not_permit_user_env_sshd_included_files:obj:1 + + + + /etc/ssh/sshd_config + ^[ \t]*(?i)include(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + + ^[ \t]*(?i)GSSAPIAuthentication(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + /etc/ssh/sshd_config + ^[ \t]*(?i)GSSAPIAuthentication(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + + oval:ssg-obj_sshd_enable_gssapi_auth:obj:1 + oval:ssg-obj_sshd_enable_gssapi_auth_sshd_included_files:obj:1 + + + + /etc/ssh/sshd_config + ^[ \t]*(?i)include(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + + ^[ \t]*(?i)UsePAM(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + /etc/ssh/sshd_config + ^[ \t]*(?i)UsePAM(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + + oval:ssg-obj_sshd_enable_pam:obj:1 + oval:ssg-obj_sshd_enable_pam_sshd_included_files:obj:1 + + + + /etc/ssh/sshd_config + ^[ \t]*(?i)include(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + + ^[ \t]*(?i)PubkeyAuthentication(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + /etc/ssh/sshd_config + ^[ \t]*(?i)PubkeyAuthentication(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + + oval:ssg-obj_sshd_enable_pubkey_auth:obj:1 + oval:ssg-obj_sshd_enable_pubkey_auth_sshd_included_files:obj:1 + + + + /etc/ssh/sshd_config + ^[ \t]*(?i)include(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + + ^[ \t]*(?i)StrictModes(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + /etc/ssh/sshd_config + ^[ \t]*(?i)StrictModes(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + + oval:ssg-obj_sshd_enable_strictmodes:obj:1 + oval:ssg-obj_sshd_enable_strictmodes_sshd_included_files:obj:1 + + + + /etc/ssh/sshd_config + ^[ \t]*(?i)include(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + + ^[ \t]*(?i)Banner(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + /etc/ssh/sshd_config + ^[ \t]*(?i)Banner(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + + oval:ssg-obj_sshd_enable_warning_banner:obj:1 + oval:ssg-obj_sshd_enable_warning_banner_sshd_included_files:obj:1 + + + + /etc/ssh/sshd_config + ^[ \t]*(?i)include(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + + ^[ \t]*(?i)Banner(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + /etc/ssh/sshd_config + ^[ \t]*(?i)Banner(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + + oval:ssg-obj_sshd_enable_warning_banner_net:obj:1 + oval:ssg-obj_sshd_enable_warning_banner_net_sshd_included_files:obj:1 + + + + /etc/ssh/sshd_config + ^[ \t]*(?i)include(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + + ^[ \t]*(?i)X11Forwarding(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + /etc/ssh/sshd_config + ^[ \t]*(?i)X11Forwarding(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + + oval:ssg-obj_sshd_enable_x11_forwarding:obj:1 + oval:ssg-obj_sshd_enable_x11_forwarding_sshd_included_files:obj:1 + + + + /etc/ssh/sshd_config + ^[\s]*Include /etc/ssh/sshd_config\.d/\*\.conf[\s]*$ + 1 + + + /etc/ssh/sshd_config + ^[ \t]*(?i)include(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + + ^[ \t]*(?i)PrintLastLog(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + /etc/ssh/sshd_config + ^[ \t]*(?i)PrintLastLog(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + + oval:ssg-obj_sshd_print_last_log:obj:1 + oval:ssg-obj_sshd_print_last_log_sshd_included_files:obj:1 + + + + /etc/ssh/sshd_config + ^[ \t]*(?i)include(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + + ^[ \t]*(?i)ClientAliveCountMax(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + /etc/ssh/sshd_config + ^[ \t]*(?i)ClientAliveCountMax(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + + oval:ssg-obj_sshd_set_keepalive:obj:1 + oval:ssg-obj_sshd_set_keepalive_sshd_included_files:obj:1 + + + + /etc/ssh/sshd_config + ^[ \t]*(?i)include(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + + ^[ \t]*(?i)ClientAliveCountMax(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + /etc/ssh/sshd_config + ^[ \t]*(?i)ClientAliveCountMax(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + + oval:ssg-obj_sshd_set_keepalive_0:obj:1 + oval:ssg-obj_sshd_set_keepalive_0_sshd_included_files:obj:1 + + + + /etc/ssh/sshd_config + ^[ \t]*(?i)include(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + + ^[ \t]*(?i)LogLevel(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + /etc/ssh/sshd_config + ^[ \t]*(?i)LogLevel(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + + oval:ssg-obj_sshd_set_loglevel_info:obj:1 + oval:ssg-obj_sshd_set_loglevel_info_sshd_included_files:obj:1 + + + + /etc/ssh/sshd_config + ^[ \t]*(?i)include(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + + ^[ \t]*(?i)LogLevel(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + /etc/ssh/sshd_config + ^[ \t]*(?i)LogLevel(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + + oval:ssg-obj_sshd_set_loglevel_verbose:obj:1 + oval:ssg-obj_sshd_set_loglevel_verbose_sshd_included_files:obj:1 + + + + /etc/ssh/sshd_config + ^[ \t]*(?i)include(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + + ^[ \t]*(?i)UsePrivilegeSeparation(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + /etc/ssh/sshd_config + ^[ \t]*(?i)UsePrivilegeSeparation(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + + oval:ssg-obj_sshd_use_priv_separation:obj:1 + oval:ssg-obj_sshd_use_priv_separation_sshd_included_files:obj:1 + + + + /etc/ssh/sshd_config + ^[ \t]*(?i)include(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + + ^[ \t]*(?i)X11UseLocalhost(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + /etc/ssh/sshd_config + ^[ \t]*(?i)X11UseLocalhost(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + + + + oval:ssg-obj_sshd_x11_use_localhost:obj:1 + oval:ssg-obj_sshd_x11_use_localhost_sshd_included_files:obj:1 + + + + /etc/sssd/sssd.conf + ^[\s]*\[certmap\/.+\/.+\][\s]*$ + 1 + + + ^/etc/sudoers(|\.d/.*)$ + ^[\s]*Defaults[\s]*[^!]\bnoexec.*$ + 1 + + + ^/etc/sudoers(|\.d/.*)$ + ^[\s]*Defaults[\s]*[^!]\brequiretty.*$ + 1 + + + ^/etc/sudoers(|\.d/.*)$ + ^[\s]*Defaults[\s]*[^!]\buse_pty.*$ + 1 + + + ^/etc/sudoers(|\.d/.*)$ + ^[\s]*Defaults[\s]*[^!]\blogfile\s*=\s*(?:"?([^",\s]+)"?).*$ + 1 + + + fs.protected_fifos + + + + oval:ssg-object_static_etc_lib_sysctls_sysctl_fs_protected_fifos:obj:1 + oval:ssg-object_static_run_usr_local_sysctls_sysctl_fs_protected_fifos:obj:1 + + + + + oval:ssg-object_static_etc_sysctls_sysctl_fs_protected_fifos:obj:1 + + + + + oval:ssg-object_static_sysctl_sysctl_fs_protected_fifos:obj:1 + oval:ssg-object_static_etc_sysctld_sysctl_fs_protected_fifos:obj:1 + + + + + oval:ssg-object_static_usr_local_lib_sysctld_sysctl_fs_protected_fifos:obj:1 + oval:ssg-object_static_run_sysctld_sysctl_fs_protected_fifos:obj:1 + + + + /etc/sysctl.conf + ^[\s]*fs.protected_fifos[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /etc/sysctl.d + ^.*\.conf$ + ^[\s]*fs.protected_fifos[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /run/sysctl.d + ^.*\.conf$ + ^[\s]*fs.protected_fifos[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/local/lib/sysctl.d + ^.*\.conf$ + ^[\s]*fs.protected_fifos[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/lib/sysctl.d + ^.*\.conf$ + ^[\s]*fs.protected_fifos[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + fs.protected_hardlinks + + + + oval:ssg-object_static_etc_lib_sysctls_sysctl_fs_protected_hardlinks:obj:1 + oval:ssg-object_static_run_usr_local_sysctls_sysctl_fs_protected_hardlinks:obj:1 + + + + + oval:ssg-object_static_etc_sysctls_sysctl_fs_protected_hardlinks:obj:1 + + + + + oval:ssg-object_static_sysctl_sysctl_fs_protected_hardlinks:obj:1 + oval:ssg-object_static_etc_sysctld_sysctl_fs_protected_hardlinks:obj:1 + + + + + oval:ssg-object_static_usr_local_lib_sysctld_sysctl_fs_protected_hardlinks:obj:1 + oval:ssg-object_static_run_sysctld_sysctl_fs_protected_hardlinks:obj:1 + + + + /etc/sysctl.conf + ^[\s]*fs.protected_hardlinks[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /etc/sysctl.d + ^.*\.conf$ + ^[\s]*fs.protected_hardlinks[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /run/sysctl.d + ^.*\.conf$ + ^[\s]*fs.protected_hardlinks[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/local/lib/sysctl.d + ^.*\.conf$ + ^[\s]*fs.protected_hardlinks[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/lib/sysctl.d + ^.*\.conf$ + ^[\s]*fs.protected_hardlinks[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + fs.protected_regular + + + + oval:ssg-object_static_etc_lib_sysctls_sysctl_fs_protected_regular:obj:1 + oval:ssg-object_static_run_usr_local_sysctls_sysctl_fs_protected_regular:obj:1 + + + + + oval:ssg-object_static_etc_sysctls_sysctl_fs_protected_regular:obj:1 + + + + + oval:ssg-object_static_sysctl_sysctl_fs_protected_regular:obj:1 + oval:ssg-object_static_etc_sysctld_sysctl_fs_protected_regular:obj:1 + + + + + oval:ssg-object_static_usr_local_lib_sysctld_sysctl_fs_protected_regular:obj:1 + oval:ssg-object_static_run_sysctld_sysctl_fs_protected_regular:obj:1 + + + + /etc/sysctl.conf + ^[\s]*fs.protected_regular[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /etc/sysctl.d + ^.*\.conf$ + ^[\s]*fs.protected_regular[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /run/sysctl.d + ^.*\.conf$ + ^[\s]*fs.protected_regular[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/local/lib/sysctl.d + ^.*\.conf$ + ^[\s]*fs.protected_regular[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/lib/sysctl.d + ^.*\.conf$ + ^[\s]*fs.protected_regular[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + fs.protected_symlinks + + + + oval:ssg-object_static_etc_lib_sysctls_sysctl_fs_protected_symlinks:obj:1 + oval:ssg-object_static_run_usr_local_sysctls_sysctl_fs_protected_symlinks:obj:1 + + + + + oval:ssg-object_static_etc_sysctls_sysctl_fs_protected_symlinks:obj:1 + + + + + oval:ssg-object_static_sysctl_sysctl_fs_protected_symlinks:obj:1 + oval:ssg-object_static_etc_sysctld_sysctl_fs_protected_symlinks:obj:1 + + + + + oval:ssg-object_static_usr_local_lib_sysctld_sysctl_fs_protected_symlinks:obj:1 + oval:ssg-object_static_run_sysctld_sysctl_fs_protected_symlinks:obj:1 + + + + /etc/sysctl.conf + ^[\s]*fs.protected_symlinks[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /etc/sysctl.d + ^.*\.conf$ + ^[\s]*fs.protected_symlinks[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /run/sysctl.d + ^.*\.conf$ + ^[\s]*fs.protected_symlinks[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/local/lib/sysctl.d + ^.*\.conf$ + ^[\s]*fs.protected_symlinks[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/lib/sysctl.d + ^.*\.conf$ + ^[\s]*fs.protected_symlinks[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + fs.suid_dumpable + + + + oval:ssg-object_static_etc_lib_sysctls_sysctl_fs_suid_dumpable:obj:1 + oval:ssg-object_static_run_usr_local_sysctls_sysctl_fs_suid_dumpable:obj:1 + + + + + oval:ssg-object_static_etc_sysctls_sysctl_fs_suid_dumpable:obj:1 + + + + + oval:ssg-object_static_sysctl_sysctl_fs_suid_dumpable:obj:1 + oval:ssg-object_static_etc_sysctld_sysctl_fs_suid_dumpable:obj:1 + + + + + oval:ssg-object_static_usr_local_lib_sysctld_sysctl_fs_suid_dumpable:obj:1 + oval:ssg-object_static_run_sysctld_sysctl_fs_suid_dumpable:obj:1 + + + + /etc/sysctl.conf + ^[\s]*fs.suid_dumpable[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /etc/sysctl.d + ^.*\.conf$ + ^[\s]*fs.suid_dumpable[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /run/sysctl.d + ^.*\.conf$ + ^[\s]*fs.suid_dumpable[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/local/lib/sysctl.d + ^.*\.conf$ + ^[\s]*fs.suid_dumpable[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/lib/sysctl.d + ^.*\.conf$ + ^[\s]*fs.suid_dumpable[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + kernel.core_pattern + + + + oval:ssg-object_static_etc_lib_sysctls_sysctl_kernel_core_pattern:obj:1 + oval:ssg-object_static_run_usr_local_sysctls_sysctl_kernel_core_pattern:obj:1 + + + + + oval:ssg-object_static_etc_sysctls_sysctl_kernel_core_pattern:obj:1 + + + + + oval:ssg-object_static_sysctl_sysctl_kernel_core_pattern:obj:1 + oval:ssg-object_static_etc_sysctld_sysctl_kernel_core_pattern:obj:1 + + + + + oval:ssg-object_static_usr_local_lib_sysctld_sysctl_kernel_core_pattern:obj:1 + oval:ssg-object_static_run_sysctld_sysctl_kernel_core_pattern:obj:1 + + + + /etc/sysctl.conf + ^[\s]*kernel.core_pattern[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /etc/sysctl.d + ^.*\.conf$ + ^[\s]*kernel.core_pattern[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /run/sysctl.d + ^.*\.conf$ + ^[\s]*kernel.core_pattern[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/local/lib/sysctl.d + ^.*\.conf$ + ^[\s]*kernel.core_pattern[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/lib/sysctl.d + ^.*\.conf$ + ^[\s]*kernel.core_pattern[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + kernel.core_uses_pid + + + + oval:ssg-object_static_etc_lib_sysctls_sysctl_kernel_core_uses_pid:obj:1 + oval:ssg-object_static_run_usr_local_sysctls_sysctl_kernel_core_uses_pid:obj:1 + + + + + oval:ssg-object_static_etc_sysctls_sysctl_kernel_core_uses_pid:obj:1 + + + + + oval:ssg-object_static_sysctl_sysctl_kernel_core_uses_pid:obj:1 + oval:ssg-object_static_etc_sysctld_sysctl_kernel_core_uses_pid:obj:1 + + + + + oval:ssg-object_static_usr_local_lib_sysctld_sysctl_kernel_core_uses_pid:obj:1 + oval:ssg-object_static_run_sysctld_sysctl_kernel_core_uses_pid:obj:1 + + + + /etc/sysctl.conf + ^[\s]*kernel.core_uses_pid[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /etc/sysctl.d + ^.*\.conf$ + ^[\s]*kernel.core_uses_pid[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /run/sysctl.d + ^.*\.conf$ + ^[\s]*kernel.core_uses_pid[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/local/lib/sysctl.d + ^.*\.conf$ + ^[\s]*kernel.core_uses_pid[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/lib/sysctl.d + ^.*\.conf$ + ^[\s]*kernel.core_uses_pid[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + kernel.dmesg_restrict + + + + oval:ssg-object_static_etc_lib_sysctls_sysctl_kernel_dmesg_restrict:obj:1 + oval:ssg-object_static_run_usr_local_sysctls_sysctl_kernel_dmesg_restrict:obj:1 + + + + + oval:ssg-object_static_etc_sysctls_sysctl_kernel_dmesg_restrict:obj:1 + + + + + oval:ssg-object_static_sysctl_sysctl_kernel_dmesg_restrict:obj:1 + oval:ssg-object_static_etc_sysctld_sysctl_kernel_dmesg_restrict:obj:1 + + + + + oval:ssg-object_static_usr_local_lib_sysctld_sysctl_kernel_dmesg_restrict:obj:1 + oval:ssg-object_static_run_sysctld_sysctl_kernel_dmesg_restrict:obj:1 + + + + /etc/sysctl.conf + ^[\s]*kernel.dmesg_restrict[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /etc/sysctl.d + ^.*\.conf$ + ^[\s]*kernel.dmesg_restrict[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /run/sysctl.d + ^.*\.conf$ + ^[\s]*kernel.dmesg_restrict[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/local/lib/sysctl.d + ^.*\.conf$ + ^[\s]*kernel.dmesg_restrict[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/lib/sysctl.d + ^.*\.conf$ + ^[\s]*kernel.dmesg_restrict[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + kernel.kexec_load_disabled + + + + oval:ssg-object_static_etc_lib_sysctls_sysctl_kernel_kexec_load_disabled:obj:1 + oval:ssg-object_static_run_usr_local_sysctls_sysctl_kernel_kexec_load_disabled:obj:1 + + + + + oval:ssg-object_static_etc_sysctls_sysctl_kernel_kexec_load_disabled:obj:1 + + + + + oval:ssg-object_static_sysctl_sysctl_kernel_kexec_load_disabled:obj:1 + oval:ssg-object_static_etc_sysctld_sysctl_kernel_kexec_load_disabled:obj:1 + + + + + oval:ssg-object_static_usr_local_lib_sysctld_sysctl_kernel_kexec_load_disabled:obj:1 + oval:ssg-object_static_run_sysctld_sysctl_kernel_kexec_load_disabled:obj:1 + + + + /etc/sysctl.conf + ^[\s]*kernel.kexec_load_disabled[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /etc/sysctl.d + ^.*\.conf$ + ^[\s]*kernel.kexec_load_disabled[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /run/sysctl.d + ^.*\.conf$ + ^[\s]*kernel.kexec_load_disabled[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/local/lib/sysctl.d + ^.*\.conf$ + ^[\s]*kernel.kexec_load_disabled[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/lib/sysctl.d + ^.*\.conf$ + ^[\s]*kernel.kexec_load_disabled[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + kernel.kptr_restrict + + + + oval:ssg-object_static_etc_lib_sysctls_sysctl_kernel_kptr_restrict:obj:1 + oval:ssg-object_static_run_usr_local_sysctls_sysctl_kernel_kptr_restrict:obj:1 + + + + + oval:ssg-object_static_etc_sysctls_sysctl_kernel_kptr_restrict:obj:1 + + + + + oval:ssg-object_static_sysctl_sysctl_kernel_kptr_restrict:obj:1 + oval:ssg-object_static_etc_sysctld_sysctl_kernel_kptr_restrict:obj:1 + + + + + oval:ssg-object_static_usr_local_lib_sysctld_sysctl_kernel_kptr_restrict:obj:1 + oval:ssg-object_static_run_sysctld_sysctl_kernel_kptr_restrict:obj:1 + + + + /etc/sysctl.conf + ^[\s]*kernel.kptr_restrict[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /etc/sysctl.d + ^.*\.conf$ + ^[\s]*kernel.kptr_restrict[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /run/sysctl.d + ^.*\.conf$ + ^[\s]*kernel.kptr_restrict[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/local/lib/sysctl.d + ^.*\.conf$ + ^[\s]*kernel.kptr_restrict[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/lib/sysctl.d + ^.*\.conf$ + ^[\s]*kernel.kptr_restrict[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + kernel.modules_disabled + + + + oval:ssg-object_static_etc_lib_sysctls_sysctl_kernel_modules_disabled:obj:1 + oval:ssg-object_static_run_usr_local_sysctls_sysctl_kernel_modules_disabled:obj:1 + + + + + oval:ssg-object_static_etc_sysctls_sysctl_kernel_modules_disabled:obj:1 + + + + + oval:ssg-object_static_sysctl_sysctl_kernel_modules_disabled:obj:1 + oval:ssg-object_static_etc_sysctld_sysctl_kernel_modules_disabled:obj:1 + + + + + oval:ssg-object_static_usr_local_lib_sysctld_sysctl_kernel_modules_disabled:obj:1 + oval:ssg-object_static_run_sysctld_sysctl_kernel_modules_disabled:obj:1 + + + + /etc/sysctl.conf + ^[\s]*kernel.modules_disabled[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /etc/sysctl.d + ^.*\.conf$ + ^[\s]*kernel.modules_disabled[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /run/sysctl.d + ^.*\.conf$ + ^[\s]*kernel.modules_disabled[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/local/lib/sysctl.d + ^.*\.conf$ + ^[\s]*kernel.modules_disabled[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/lib/sysctl.d + ^.*\.conf$ + ^[\s]*kernel.modules_disabled[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + kernel.panic_on_oops + + + + oval:ssg-object_static_etc_lib_sysctls_sysctl_kernel_panic_on_oops:obj:1 + oval:ssg-object_static_run_usr_local_sysctls_sysctl_kernel_panic_on_oops:obj:1 + + + + + oval:ssg-object_static_etc_sysctls_sysctl_kernel_panic_on_oops:obj:1 + + + + + oval:ssg-object_static_sysctl_sysctl_kernel_panic_on_oops:obj:1 + oval:ssg-object_static_etc_sysctld_sysctl_kernel_panic_on_oops:obj:1 + + + + + oval:ssg-object_static_usr_local_lib_sysctld_sysctl_kernel_panic_on_oops:obj:1 + oval:ssg-object_static_run_sysctld_sysctl_kernel_panic_on_oops:obj:1 + + + + /etc/sysctl.conf + ^[\s]*kernel.panic_on_oops[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /etc/sysctl.d + ^.*\.conf$ + ^[\s]*kernel.panic_on_oops[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /run/sysctl.d + ^.*\.conf$ + ^[\s]*kernel.panic_on_oops[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/local/lib/sysctl.d + ^.*\.conf$ + ^[\s]*kernel.panic_on_oops[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/lib/sysctl.d + ^.*\.conf$ + ^[\s]*kernel.panic_on_oops[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + kernel.perf_cpu_time_max_percent + + + + oval:ssg-object_static_etc_lib_sysctls_sysctl_kernel_perf_cpu_time_max_percent:obj:1 + oval:ssg-object_static_run_usr_local_sysctls_sysctl_kernel_perf_cpu_time_max_percent:obj:1 + + + + + oval:ssg-object_static_etc_sysctls_sysctl_kernel_perf_cpu_time_max_percent:obj:1 + + + + + oval:ssg-object_static_sysctl_sysctl_kernel_perf_cpu_time_max_percent:obj:1 + oval:ssg-object_static_etc_sysctld_sysctl_kernel_perf_cpu_time_max_percent:obj:1 + + + + + oval:ssg-object_static_usr_local_lib_sysctld_sysctl_kernel_perf_cpu_time_max_percent:obj:1 + oval:ssg-object_static_run_sysctld_sysctl_kernel_perf_cpu_time_max_percent:obj:1 + + + + /etc/sysctl.conf + ^[\s]*kernel.perf_cpu_time_max_percent[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /etc/sysctl.d + ^.*\.conf$ + ^[\s]*kernel.perf_cpu_time_max_percent[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /run/sysctl.d + ^.*\.conf$ + ^[\s]*kernel.perf_cpu_time_max_percent[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/local/lib/sysctl.d + ^.*\.conf$ + ^[\s]*kernel.perf_cpu_time_max_percent[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/lib/sysctl.d + ^.*\.conf$ + ^[\s]*kernel.perf_cpu_time_max_percent[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + kernel.perf_event_max_sample_rate + + + + oval:ssg-object_static_etc_lib_sysctls_sysctl_kernel_perf_event_max_sample_rate:obj:1 + oval:ssg-object_static_run_usr_local_sysctls_sysctl_kernel_perf_event_max_sample_rate:obj:1 + + + + + oval:ssg-object_static_etc_sysctls_sysctl_kernel_perf_event_max_sample_rate:obj:1 + + + + + oval:ssg-object_static_sysctl_sysctl_kernel_perf_event_max_sample_rate:obj:1 + oval:ssg-object_static_etc_sysctld_sysctl_kernel_perf_event_max_sample_rate:obj:1 + + + + + oval:ssg-object_static_usr_local_lib_sysctld_sysctl_kernel_perf_event_max_sample_rate:obj:1 + oval:ssg-object_static_run_sysctld_sysctl_kernel_perf_event_max_sample_rate:obj:1 + + + + /etc/sysctl.conf + ^[\s]*kernel.perf_event_max_sample_rate[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /etc/sysctl.d + ^.*\.conf$ + ^[\s]*kernel.perf_event_max_sample_rate[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /run/sysctl.d + ^.*\.conf$ + ^[\s]*kernel.perf_event_max_sample_rate[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/local/lib/sysctl.d + ^.*\.conf$ + ^[\s]*kernel.perf_event_max_sample_rate[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/lib/sysctl.d + ^.*\.conf$ + ^[\s]*kernel.perf_event_max_sample_rate[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + kernel.perf_event_paranoid + + + + oval:ssg-object_static_etc_lib_sysctls_sysctl_kernel_perf_event_paranoid:obj:1 + oval:ssg-object_static_run_usr_local_sysctls_sysctl_kernel_perf_event_paranoid:obj:1 + + + + + oval:ssg-object_static_etc_sysctls_sysctl_kernel_perf_event_paranoid:obj:1 + + + + + oval:ssg-object_static_sysctl_sysctl_kernel_perf_event_paranoid:obj:1 + oval:ssg-object_static_etc_sysctld_sysctl_kernel_perf_event_paranoid:obj:1 + + + + + oval:ssg-object_static_usr_local_lib_sysctld_sysctl_kernel_perf_event_paranoid:obj:1 + oval:ssg-object_static_run_sysctld_sysctl_kernel_perf_event_paranoid:obj:1 + + + + /etc/sysctl.conf + ^[\s]*kernel.perf_event_paranoid[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /etc/sysctl.d + ^.*\.conf$ + ^[\s]*kernel.perf_event_paranoid[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /run/sysctl.d + ^.*\.conf$ + ^[\s]*kernel.perf_event_paranoid[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/local/lib/sysctl.d + ^.*\.conf$ + ^[\s]*kernel.perf_event_paranoid[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/lib/sysctl.d + ^.*\.conf$ + ^[\s]*kernel.perf_event_paranoid[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + kernel.pid_max + + + + oval:ssg-object_static_etc_lib_sysctls_sysctl_kernel_pid_max:obj:1 + oval:ssg-object_static_run_usr_local_sysctls_sysctl_kernel_pid_max:obj:1 + + + + + oval:ssg-object_static_etc_sysctls_sysctl_kernel_pid_max:obj:1 + + + + + oval:ssg-object_static_sysctl_sysctl_kernel_pid_max:obj:1 + oval:ssg-object_static_etc_sysctld_sysctl_kernel_pid_max:obj:1 + + + + + oval:ssg-object_static_usr_local_lib_sysctld_sysctl_kernel_pid_max:obj:1 + oval:ssg-object_static_run_sysctld_sysctl_kernel_pid_max:obj:1 + + + + /etc/sysctl.conf + ^[\s]*kernel.pid_max[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /etc/sysctl.d + ^.*\.conf$ + ^[\s]*kernel.pid_max[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /run/sysctl.d + ^.*\.conf$ + ^[\s]*kernel.pid_max[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/local/lib/sysctl.d + ^.*\.conf$ + ^[\s]*kernel.pid_max[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/lib/sysctl.d + ^.*\.conf$ + ^[\s]*kernel.pid_max[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + kernel.randomize_va_space + + + + oval:ssg-object_static_etc_lib_sysctls_sysctl_kernel_randomize_va_space:obj:1 + oval:ssg-object_static_run_usr_local_sysctls_sysctl_kernel_randomize_va_space:obj:1 + + + + + oval:ssg-object_static_etc_sysctls_sysctl_kernel_randomize_va_space:obj:1 + + + + + oval:ssg-object_static_sysctl_sysctl_kernel_randomize_va_space:obj:1 + oval:ssg-object_static_etc_sysctld_sysctl_kernel_randomize_va_space:obj:1 + + + + + oval:ssg-object_static_usr_local_lib_sysctld_sysctl_kernel_randomize_va_space:obj:1 + oval:ssg-object_static_run_sysctld_sysctl_kernel_randomize_va_space:obj:1 + + + + /etc/sysctl.conf + ^[\s]*kernel.randomize_va_space[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /etc/sysctl.d + ^.*\.conf$ + ^[\s]*kernel.randomize_va_space[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /run/sysctl.d + ^.*\.conf$ + ^[\s]*kernel.randomize_va_space[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/local/lib/sysctl.d + ^.*\.conf$ + ^[\s]*kernel.randomize_va_space[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/lib/sysctl.d + ^.*\.conf$ + ^[\s]*kernel.randomize_va_space[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + kernel.sysrq + + + + oval:ssg-object_static_etc_lib_sysctls_sysctl_kernel_sysrq:obj:1 + oval:ssg-object_static_run_usr_local_sysctls_sysctl_kernel_sysrq:obj:1 + + + + + oval:ssg-object_static_etc_sysctls_sysctl_kernel_sysrq:obj:1 + + + + + oval:ssg-object_static_sysctl_sysctl_kernel_sysrq:obj:1 + oval:ssg-object_static_etc_sysctld_sysctl_kernel_sysrq:obj:1 + + + + + oval:ssg-object_static_usr_local_lib_sysctld_sysctl_kernel_sysrq:obj:1 + oval:ssg-object_static_run_sysctld_sysctl_kernel_sysrq:obj:1 + + + + /etc/sysctl.conf + ^[\s]*kernel.sysrq[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /etc/sysctl.d + ^.*\.conf$ + ^[\s]*kernel.sysrq[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /run/sysctl.d + ^.*\.conf$ + ^[\s]*kernel.sysrq[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/local/lib/sysctl.d + ^.*\.conf$ + ^[\s]*kernel.sysrq[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/lib/sysctl.d + ^.*\.conf$ + ^[\s]*kernel.sysrq[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + kernel.unprivileged_bpf_disabled + + + + oval:ssg-object_static_etc_lib_sysctls_sysctl_kernel_unprivileged_bpf_disabled:obj:1 + oval:ssg-object_static_run_usr_local_sysctls_sysctl_kernel_unprivileged_bpf_disabled:obj:1 + + + + + oval:ssg-object_static_etc_sysctls_sysctl_kernel_unprivileged_bpf_disabled:obj:1 + + + + + oval:ssg-object_static_sysctl_sysctl_kernel_unprivileged_bpf_disabled:obj:1 + oval:ssg-object_static_etc_sysctld_sysctl_kernel_unprivileged_bpf_disabled:obj:1 + + + + + oval:ssg-object_static_usr_local_lib_sysctld_sysctl_kernel_unprivileged_bpf_disabled:obj:1 + oval:ssg-object_static_run_sysctld_sysctl_kernel_unprivileged_bpf_disabled:obj:1 + + + + /etc/sysctl.conf + ^[\s]*kernel.unprivileged_bpf_disabled[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /etc/sysctl.d + ^.*\.conf$ + ^[\s]*kernel.unprivileged_bpf_disabled[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /run/sysctl.d + ^.*\.conf$ + ^[\s]*kernel.unprivileged_bpf_disabled[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/local/lib/sysctl.d + ^.*\.conf$ + ^[\s]*kernel.unprivileged_bpf_disabled[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/lib/sysctl.d + ^.*\.conf$ + ^[\s]*kernel.unprivileged_bpf_disabled[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + kernel.unprivileged_bpf_disabled + + + + oval:ssg-object_static_etc_lib_sysctls_sysctl_kernel_unprivileged_bpf_disabled_accept_default:obj:1 + oval:ssg-object_static_run_usr_local_sysctls_sysctl_kernel_unprivileged_bpf_disabled_accept_default:obj:1 + + + + + oval:ssg-object_static_etc_sysctls_sysctl_kernel_unprivileged_bpf_disabled_accept_default:obj:1 + + + + + oval:ssg-object_static_sysctl_sysctl_kernel_unprivileged_bpf_disabled_accept_default:obj:1 + oval:ssg-object_static_etc_sysctld_sysctl_kernel_unprivileged_bpf_disabled_accept_default:obj:1 + + + + + oval:ssg-object_static_usr_local_lib_sysctld_sysctl_kernel_unprivileged_bpf_disabled_accept_default:obj:1 + oval:ssg-object_static_run_sysctld_sysctl_kernel_unprivileged_bpf_disabled_accept_default:obj:1 + + + + /etc/sysctl.conf + ^[\s]*kernel.unprivileged_bpf_disabled[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /etc/sysctl.d + ^.*\.conf$ + ^[\s]*kernel.unprivileged_bpf_disabled[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /run/sysctl.d + ^.*\.conf$ + ^[\s]*kernel.unprivileged_bpf_disabled[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/local/lib/sysctl.d + ^.*\.conf$ + ^[\s]*kernel.unprivileged_bpf_disabled[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/lib/sysctl.d + ^.*\.conf$ + ^[\s]*kernel.unprivileged_bpf_disabled[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + kernel.yama.ptrace_scope + + + + oval:ssg-object_static_etc_lib_sysctls_sysctl_kernel_yama_ptrace_scope:obj:1 + oval:ssg-object_static_run_usr_local_sysctls_sysctl_kernel_yama_ptrace_scope:obj:1 + + + + + oval:ssg-object_static_etc_sysctls_sysctl_kernel_yama_ptrace_scope:obj:1 + + + + + oval:ssg-object_static_sysctl_sysctl_kernel_yama_ptrace_scope:obj:1 + oval:ssg-object_static_etc_sysctld_sysctl_kernel_yama_ptrace_scope:obj:1 + + + + + oval:ssg-object_static_usr_local_lib_sysctld_sysctl_kernel_yama_ptrace_scope:obj:1 + oval:ssg-object_static_run_sysctld_sysctl_kernel_yama_ptrace_scope:obj:1 + + + + /etc/sysctl.conf + ^[\s]*kernel.yama.ptrace_scope[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /etc/sysctl.d + ^.*\.conf$ + ^[\s]*kernel.yama.ptrace_scope[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /run/sysctl.d + ^.*\.conf$ + ^[\s]*kernel.yama.ptrace_scope[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/local/lib/sysctl.d + ^.*\.conf$ + ^[\s]*kernel.yama.ptrace_scope[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/lib/sysctl.d + ^.*\.conf$ + ^[\s]*kernel.yama.ptrace_scope[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + net.core.bpf_jit_harden + + + + oval:ssg-object_static_etc_lib_sysctls_sysctl_net_core_bpf_jit_harden:obj:1 + oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_core_bpf_jit_harden:obj:1 + + + + + oval:ssg-object_static_etc_sysctls_sysctl_net_core_bpf_jit_harden:obj:1 + + + + + oval:ssg-object_static_sysctl_sysctl_net_core_bpf_jit_harden:obj:1 + oval:ssg-object_static_etc_sysctld_sysctl_net_core_bpf_jit_harden:obj:1 + + + + + oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_core_bpf_jit_harden:obj:1 + oval:ssg-object_static_run_sysctld_sysctl_net_core_bpf_jit_harden:obj:1 + + + + /etc/sysctl.conf + ^[\s]*net.core.bpf_jit_harden[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /etc/sysctl.d + ^.*\.conf$ + ^[\s]*net.core.bpf_jit_harden[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /run/sysctl.d + ^.*\.conf$ + ^[\s]*net.core.bpf_jit_harden[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/local/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.core.bpf_jit_harden[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.core.bpf_jit_harden[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + net.ipv4.conf.all.accept_local + + + + oval:ssg-object_static_etc_lib_sysctls_sysctl_net_ipv4_conf_all_accept_local:obj:1 + oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv4_conf_all_accept_local:obj:1 + + + + + oval:ssg-object_static_etc_sysctls_sysctl_net_ipv4_conf_all_accept_local:obj:1 + + + + + oval:ssg-object_static_sysctl_sysctl_net_ipv4_conf_all_accept_local:obj:1 + oval:ssg-object_static_etc_sysctld_sysctl_net_ipv4_conf_all_accept_local:obj:1 + + + + + oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv4_conf_all_accept_local:obj:1 + oval:ssg-object_static_run_sysctld_sysctl_net_ipv4_conf_all_accept_local:obj:1 + + + + /etc/sysctl.conf + ^[\s]*net.ipv4.conf.all.accept_local[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /etc/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.conf.all.accept_local[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /run/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.conf.all.accept_local[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/local/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.conf.all.accept_local[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.conf.all.accept_local[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + net.ipv4.conf.all.accept_redirects + + + + oval:ssg-object_static_etc_lib_sysctls_sysctl_net_ipv4_conf_all_accept_redirects:obj:1 + oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv4_conf_all_accept_redirects:obj:1 + + + + + oval:ssg-object_static_etc_sysctls_sysctl_net_ipv4_conf_all_accept_redirects:obj:1 + + + + + oval:ssg-object_static_sysctl_sysctl_net_ipv4_conf_all_accept_redirects:obj:1 + oval:ssg-object_static_etc_sysctld_sysctl_net_ipv4_conf_all_accept_redirects:obj:1 + + + + + oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv4_conf_all_accept_redirects:obj:1 + oval:ssg-object_static_run_sysctld_sysctl_net_ipv4_conf_all_accept_redirects:obj:1 + + + + /etc/sysctl.conf + ^[\s]*net.ipv4.conf.all.accept_redirects[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /etc/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.conf.all.accept_redirects[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /run/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.conf.all.accept_redirects[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/local/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.conf.all.accept_redirects[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.conf.all.accept_redirects[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + net.ipv4.conf.all.accept_source_route + + + + oval:ssg-object_static_etc_lib_sysctls_sysctl_net_ipv4_conf_all_accept_source_route:obj:1 + oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv4_conf_all_accept_source_route:obj:1 + + + + + oval:ssg-object_static_etc_sysctls_sysctl_net_ipv4_conf_all_accept_source_route:obj:1 + + + + + oval:ssg-object_static_sysctl_sysctl_net_ipv4_conf_all_accept_source_route:obj:1 + oval:ssg-object_static_etc_sysctld_sysctl_net_ipv4_conf_all_accept_source_route:obj:1 + + + + + oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv4_conf_all_accept_source_route:obj:1 + oval:ssg-object_static_run_sysctld_sysctl_net_ipv4_conf_all_accept_source_route:obj:1 + + + + /etc/sysctl.conf + ^[\s]*net.ipv4.conf.all.accept_source_route[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /etc/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.conf.all.accept_source_route[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /run/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.conf.all.accept_source_route[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/local/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.conf.all.accept_source_route[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.conf.all.accept_source_route[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + net.ipv4.conf.all.arp_filter + + + + oval:ssg-object_static_etc_lib_sysctls_sysctl_net_ipv4_conf_all_arp_filter:obj:1 + oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv4_conf_all_arp_filter:obj:1 + + + + + oval:ssg-object_static_etc_sysctls_sysctl_net_ipv4_conf_all_arp_filter:obj:1 + + + + + oval:ssg-object_static_sysctl_sysctl_net_ipv4_conf_all_arp_filter:obj:1 + oval:ssg-object_static_etc_sysctld_sysctl_net_ipv4_conf_all_arp_filter:obj:1 + + + + + oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv4_conf_all_arp_filter:obj:1 + oval:ssg-object_static_run_sysctld_sysctl_net_ipv4_conf_all_arp_filter:obj:1 + + + + /etc/sysctl.conf + ^[\s]*net.ipv4.conf.all.arp_filter[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /etc/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.conf.all.arp_filter[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /run/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.conf.all.arp_filter[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/local/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.conf.all.arp_filter[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.conf.all.arp_filter[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + net.ipv4.conf.all.arp_ignore + + + + oval:ssg-object_static_etc_lib_sysctls_sysctl_net_ipv4_conf_all_arp_ignore:obj:1 + oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv4_conf_all_arp_ignore:obj:1 + + + + + oval:ssg-object_static_etc_sysctls_sysctl_net_ipv4_conf_all_arp_ignore:obj:1 + + + + + oval:ssg-object_static_sysctl_sysctl_net_ipv4_conf_all_arp_ignore:obj:1 + oval:ssg-object_static_etc_sysctld_sysctl_net_ipv4_conf_all_arp_ignore:obj:1 + + + + + oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv4_conf_all_arp_ignore:obj:1 + oval:ssg-object_static_run_sysctld_sysctl_net_ipv4_conf_all_arp_ignore:obj:1 + + + + /etc/sysctl.conf + ^[\s]*net.ipv4.conf.all.arp_ignore[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /etc/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.conf.all.arp_ignore[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /run/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.conf.all.arp_ignore[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/local/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.conf.all.arp_ignore[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.conf.all.arp_ignore[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + net.ipv4.conf.all.drop_gratuitous_arp + + + + oval:ssg-object_static_etc_lib_sysctls_sysctl_net_ipv4_conf_all_drop_gratuitous_arp:obj:1 + oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv4_conf_all_drop_gratuitous_arp:obj:1 + + + + + oval:ssg-object_static_etc_sysctls_sysctl_net_ipv4_conf_all_drop_gratuitous_arp:obj:1 + + + + + oval:ssg-object_static_sysctl_sysctl_net_ipv4_conf_all_drop_gratuitous_arp:obj:1 + oval:ssg-object_static_etc_sysctld_sysctl_net_ipv4_conf_all_drop_gratuitous_arp:obj:1 + + + + + oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv4_conf_all_drop_gratuitous_arp:obj:1 + oval:ssg-object_static_run_sysctld_sysctl_net_ipv4_conf_all_drop_gratuitous_arp:obj:1 + + + + /etc/sysctl.conf + ^[\s]*net.ipv4.conf.all.drop_gratuitous_arp[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /etc/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.conf.all.drop_gratuitous_arp[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /run/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.conf.all.drop_gratuitous_arp[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/local/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.conf.all.drop_gratuitous_arp[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.conf.all.drop_gratuitous_arp[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + net.ipv4.conf.all.forwarding + + + + oval:ssg-object_static_etc_lib_sysctls_sysctl_net_ipv4_conf_all_forwarding:obj:1 + oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv4_conf_all_forwarding:obj:1 + + + + + oval:ssg-object_static_etc_sysctls_sysctl_net_ipv4_conf_all_forwarding:obj:1 + + + + + oval:ssg-object_static_sysctl_sysctl_net_ipv4_conf_all_forwarding:obj:1 + oval:ssg-object_static_etc_sysctld_sysctl_net_ipv4_conf_all_forwarding:obj:1 + + + + + oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv4_conf_all_forwarding:obj:1 + oval:ssg-object_static_run_sysctld_sysctl_net_ipv4_conf_all_forwarding:obj:1 + + + + /etc/sysctl.conf + ^[\s]*net.ipv4.conf.all.forwarding[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /etc/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.conf.all.forwarding[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /run/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.conf.all.forwarding[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/local/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.conf.all.forwarding[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.conf.all.forwarding[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + net.ipv4.conf.all.log_martians + + + + oval:ssg-object_static_etc_lib_sysctls_sysctl_net_ipv4_conf_all_log_martians:obj:1 + oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv4_conf_all_log_martians:obj:1 + + + + + oval:ssg-object_static_etc_sysctls_sysctl_net_ipv4_conf_all_log_martians:obj:1 + + + + + oval:ssg-object_static_sysctl_sysctl_net_ipv4_conf_all_log_martians:obj:1 + oval:ssg-object_static_etc_sysctld_sysctl_net_ipv4_conf_all_log_martians:obj:1 + + + + + oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv4_conf_all_log_martians:obj:1 + oval:ssg-object_static_run_sysctld_sysctl_net_ipv4_conf_all_log_martians:obj:1 + + + + /etc/sysctl.conf + ^[\s]*net.ipv4.conf.all.log_martians[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /etc/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.conf.all.log_martians[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /run/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.conf.all.log_martians[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/local/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.conf.all.log_martians[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.conf.all.log_martians[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + net.ipv4.conf.all.route_localnet + + + + oval:ssg-object_static_etc_lib_sysctls_sysctl_net_ipv4_conf_all_route_localnet:obj:1 + oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv4_conf_all_route_localnet:obj:1 + + + + + oval:ssg-object_static_etc_sysctls_sysctl_net_ipv4_conf_all_route_localnet:obj:1 + + + + + oval:ssg-object_static_sysctl_sysctl_net_ipv4_conf_all_route_localnet:obj:1 + oval:ssg-object_static_etc_sysctld_sysctl_net_ipv4_conf_all_route_localnet:obj:1 + + + + + oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv4_conf_all_route_localnet:obj:1 + oval:ssg-object_static_run_sysctld_sysctl_net_ipv4_conf_all_route_localnet:obj:1 + + + + /etc/sysctl.conf + ^[\s]*net.ipv4.conf.all.route_localnet[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /etc/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.conf.all.route_localnet[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /run/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.conf.all.route_localnet[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/local/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.conf.all.route_localnet[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.conf.all.route_localnet[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + net.ipv4.conf.all.rp_filter + + + + oval:ssg-object_static_etc_lib_sysctls_sysctl_net_ipv4_conf_all_rp_filter:obj:1 + oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv4_conf_all_rp_filter:obj:1 + + + + + oval:ssg-object_static_etc_sysctls_sysctl_net_ipv4_conf_all_rp_filter:obj:1 + + + + + oval:ssg-object_static_sysctl_sysctl_net_ipv4_conf_all_rp_filter:obj:1 + oval:ssg-object_static_etc_sysctld_sysctl_net_ipv4_conf_all_rp_filter:obj:1 + + + + + oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv4_conf_all_rp_filter:obj:1 + oval:ssg-object_static_run_sysctld_sysctl_net_ipv4_conf_all_rp_filter:obj:1 + + + + /etc/sysctl.conf + ^[\s]*net.ipv4.conf.all.rp_filter[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /etc/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.conf.all.rp_filter[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /run/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.conf.all.rp_filter[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/local/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.conf.all.rp_filter[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.conf.all.rp_filter[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + net.ipv4.conf.all.secure_redirects + + + + oval:ssg-object_static_etc_lib_sysctls_sysctl_net_ipv4_conf_all_secure_redirects:obj:1 + oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv4_conf_all_secure_redirects:obj:1 + + + + + oval:ssg-object_static_etc_sysctls_sysctl_net_ipv4_conf_all_secure_redirects:obj:1 + + + + + oval:ssg-object_static_sysctl_sysctl_net_ipv4_conf_all_secure_redirects:obj:1 + oval:ssg-object_static_etc_sysctld_sysctl_net_ipv4_conf_all_secure_redirects:obj:1 + + + + + oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv4_conf_all_secure_redirects:obj:1 + oval:ssg-object_static_run_sysctld_sysctl_net_ipv4_conf_all_secure_redirects:obj:1 + + + + /etc/sysctl.conf + ^[\s]*net.ipv4.conf.all.secure_redirects[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /etc/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.conf.all.secure_redirects[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /run/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.conf.all.secure_redirects[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/local/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.conf.all.secure_redirects[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.conf.all.secure_redirects[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + net.ipv4.conf.all.send_redirects + + + + oval:ssg-object_static_etc_lib_sysctls_sysctl_net_ipv4_conf_all_send_redirects:obj:1 + oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv4_conf_all_send_redirects:obj:1 + + + + + oval:ssg-object_static_etc_sysctls_sysctl_net_ipv4_conf_all_send_redirects:obj:1 + + + + + oval:ssg-object_static_sysctl_sysctl_net_ipv4_conf_all_send_redirects:obj:1 + oval:ssg-object_static_etc_sysctld_sysctl_net_ipv4_conf_all_send_redirects:obj:1 + + + + + oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv4_conf_all_send_redirects:obj:1 + oval:ssg-object_static_run_sysctld_sysctl_net_ipv4_conf_all_send_redirects:obj:1 + + + + /etc/sysctl.conf + ^[\s]*net.ipv4.conf.all.send_redirects[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /etc/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.conf.all.send_redirects[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /run/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.conf.all.send_redirects[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/local/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.conf.all.send_redirects[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.conf.all.send_redirects[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + net.ipv4.conf.all.shared_media + + + + oval:ssg-object_static_etc_lib_sysctls_sysctl_net_ipv4_conf_all_shared_media:obj:1 + oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv4_conf_all_shared_media:obj:1 + + + + + oval:ssg-object_static_etc_sysctls_sysctl_net_ipv4_conf_all_shared_media:obj:1 + + + + + oval:ssg-object_static_sysctl_sysctl_net_ipv4_conf_all_shared_media:obj:1 + oval:ssg-object_static_etc_sysctld_sysctl_net_ipv4_conf_all_shared_media:obj:1 + + + + + oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv4_conf_all_shared_media:obj:1 + oval:ssg-object_static_run_sysctld_sysctl_net_ipv4_conf_all_shared_media:obj:1 + + + + /etc/sysctl.conf + ^[\s]*net.ipv4.conf.all.shared_media[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /etc/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.conf.all.shared_media[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /run/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.conf.all.shared_media[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/local/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.conf.all.shared_media[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.conf.all.shared_media[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + net.ipv4.conf.default.accept_redirects + + + + oval:ssg-object_static_etc_lib_sysctls_sysctl_net_ipv4_conf_default_accept_redirects:obj:1 + oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv4_conf_default_accept_redirects:obj:1 + + + + + oval:ssg-object_static_etc_sysctls_sysctl_net_ipv4_conf_default_accept_redirects:obj:1 + + + + + oval:ssg-object_static_sysctl_sysctl_net_ipv4_conf_default_accept_redirects:obj:1 + oval:ssg-object_static_etc_sysctld_sysctl_net_ipv4_conf_default_accept_redirects:obj:1 + + + + + oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv4_conf_default_accept_redirects:obj:1 + oval:ssg-object_static_run_sysctld_sysctl_net_ipv4_conf_default_accept_redirects:obj:1 + + + + /etc/sysctl.conf + ^[\s]*net.ipv4.conf.default.accept_redirects[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /etc/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.conf.default.accept_redirects[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /run/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.conf.default.accept_redirects[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/local/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.conf.default.accept_redirects[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.conf.default.accept_redirects[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + net.ipv4.conf.default.accept_source_route + + + + oval:ssg-object_static_etc_lib_sysctls_sysctl_net_ipv4_conf_default_accept_source_route:obj:1 + oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv4_conf_default_accept_source_route:obj:1 + + + + + oval:ssg-object_static_etc_sysctls_sysctl_net_ipv4_conf_default_accept_source_route:obj:1 + + + + + oval:ssg-object_static_sysctl_sysctl_net_ipv4_conf_default_accept_source_route:obj:1 + oval:ssg-object_static_etc_sysctld_sysctl_net_ipv4_conf_default_accept_source_route:obj:1 + + + + + oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv4_conf_default_accept_source_route:obj:1 + oval:ssg-object_static_run_sysctld_sysctl_net_ipv4_conf_default_accept_source_route:obj:1 + + + + /etc/sysctl.conf + ^[\s]*net.ipv4.conf.default.accept_source_route[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /etc/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.conf.default.accept_source_route[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /run/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.conf.default.accept_source_route[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/local/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.conf.default.accept_source_route[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.conf.default.accept_source_route[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + net.ipv4.conf.default.log_martians + + + + oval:ssg-object_static_etc_lib_sysctls_sysctl_net_ipv4_conf_default_log_martians:obj:1 + oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv4_conf_default_log_martians:obj:1 + + + + + oval:ssg-object_static_etc_sysctls_sysctl_net_ipv4_conf_default_log_martians:obj:1 + + + + + oval:ssg-object_static_sysctl_sysctl_net_ipv4_conf_default_log_martians:obj:1 + oval:ssg-object_static_etc_sysctld_sysctl_net_ipv4_conf_default_log_martians:obj:1 + + + + + oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv4_conf_default_log_martians:obj:1 + oval:ssg-object_static_run_sysctld_sysctl_net_ipv4_conf_default_log_martians:obj:1 + + + + /etc/sysctl.conf + ^[\s]*net.ipv4.conf.default.log_martians[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /etc/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.conf.default.log_martians[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /run/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.conf.default.log_martians[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/local/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.conf.default.log_martians[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.conf.default.log_martians[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + net.ipv4.conf.default.rp_filter + + + + oval:ssg-object_static_etc_lib_sysctls_sysctl_net_ipv4_conf_default_rp_filter:obj:1 + oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv4_conf_default_rp_filter:obj:1 + + + + + oval:ssg-object_static_etc_sysctls_sysctl_net_ipv4_conf_default_rp_filter:obj:1 + + + + + oval:ssg-object_static_sysctl_sysctl_net_ipv4_conf_default_rp_filter:obj:1 + oval:ssg-object_static_etc_sysctld_sysctl_net_ipv4_conf_default_rp_filter:obj:1 + + + + + oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv4_conf_default_rp_filter:obj:1 + oval:ssg-object_static_run_sysctld_sysctl_net_ipv4_conf_default_rp_filter:obj:1 + + + + /etc/sysctl.conf + ^[\s]*net.ipv4.conf.default.rp_filter[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /etc/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.conf.default.rp_filter[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /run/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.conf.default.rp_filter[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/local/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.conf.default.rp_filter[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.conf.default.rp_filter[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + net.ipv4.conf.default.secure_redirects + + + + oval:ssg-object_static_etc_lib_sysctls_sysctl_net_ipv4_conf_default_secure_redirects:obj:1 + oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv4_conf_default_secure_redirects:obj:1 + + + + + oval:ssg-object_static_etc_sysctls_sysctl_net_ipv4_conf_default_secure_redirects:obj:1 + + + + + oval:ssg-object_static_sysctl_sysctl_net_ipv4_conf_default_secure_redirects:obj:1 + oval:ssg-object_static_etc_sysctld_sysctl_net_ipv4_conf_default_secure_redirects:obj:1 + + + + + oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv4_conf_default_secure_redirects:obj:1 + oval:ssg-object_static_run_sysctld_sysctl_net_ipv4_conf_default_secure_redirects:obj:1 + + + + /etc/sysctl.conf + ^[\s]*net.ipv4.conf.default.secure_redirects[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /etc/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.conf.default.secure_redirects[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /run/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.conf.default.secure_redirects[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/local/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.conf.default.secure_redirects[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.conf.default.secure_redirects[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + net.ipv4.conf.default.send_redirects + + + + oval:ssg-object_static_etc_lib_sysctls_sysctl_net_ipv4_conf_default_send_redirects:obj:1 + oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv4_conf_default_send_redirects:obj:1 + + + + + oval:ssg-object_static_etc_sysctls_sysctl_net_ipv4_conf_default_send_redirects:obj:1 + + + + + oval:ssg-object_static_sysctl_sysctl_net_ipv4_conf_default_send_redirects:obj:1 + oval:ssg-object_static_etc_sysctld_sysctl_net_ipv4_conf_default_send_redirects:obj:1 + + + + + oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv4_conf_default_send_redirects:obj:1 + oval:ssg-object_static_run_sysctld_sysctl_net_ipv4_conf_default_send_redirects:obj:1 + + + + /etc/sysctl.conf + ^[\s]*net.ipv4.conf.default.send_redirects[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /etc/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.conf.default.send_redirects[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /run/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.conf.default.send_redirects[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/local/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.conf.default.send_redirects[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.conf.default.send_redirects[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + net.ipv4.conf.default.shared_media + + + + oval:ssg-object_static_etc_lib_sysctls_sysctl_net_ipv4_conf_default_shared_media:obj:1 + oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv4_conf_default_shared_media:obj:1 + + + + + oval:ssg-object_static_etc_sysctls_sysctl_net_ipv4_conf_default_shared_media:obj:1 + + + + + oval:ssg-object_static_sysctl_sysctl_net_ipv4_conf_default_shared_media:obj:1 + oval:ssg-object_static_etc_sysctld_sysctl_net_ipv4_conf_default_shared_media:obj:1 + + + + + oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv4_conf_default_shared_media:obj:1 + oval:ssg-object_static_run_sysctld_sysctl_net_ipv4_conf_default_shared_media:obj:1 + + + + /etc/sysctl.conf + ^[\s]*net.ipv4.conf.default.shared_media[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /etc/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.conf.default.shared_media[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /run/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.conf.default.shared_media[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/local/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.conf.default.shared_media[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.conf.default.shared_media[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + net.ipv4.icmp_echo_ignore_broadcasts + + + + oval:ssg-object_static_etc_lib_sysctls_sysctl_net_ipv4_icmp_echo_ignore_broadcasts:obj:1 + oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv4_icmp_echo_ignore_broadcasts:obj:1 + + + + + oval:ssg-object_static_etc_sysctls_sysctl_net_ipv4_icmp_echo_ignore_broadcasts:obj:1 + + + + + oval:ssg-object_static_sysctl_sysctl_net_ipv4_icmp_echo_ignore_broadcasts:obj:1 + oval:ssg-object_static_etc_sysctld_sysctl_net_ipv4_icmp_echo_ignore_broadcasts:obj:1 + + + + + oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv4_icmp_echo_ignore_broadcasts:obj:1 + oval:ssg-object_static_run_sysctld_sysctl_net_ipv4_icmp_echo_ignore_broadcasts:obj:1 + + + + /etc/sysctl.conf + ^[\s]*net.ipv4.icmp_echo_ignore_broadcasts[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /etc/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.icmp_echo_ignore_broadcasts[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /run/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.icmp_echo_ignore_broadcasts[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/local/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.icmp_echo_ignore_broadcasts[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.icmp_echo_ignore_broadcasts[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + net.ipv4.icmp_ignore_bogus_error_responses + + + + oval:ssg-object_static_etc_lib_sysctls_sysctl_net_ipv4_icmp_ignore_bogus_error_responses:obj:1 + oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv4_icmp_ignore_bogus_error_responses:obj:1 + + + + + oval:ssg-object_static_etc_sysctls_sysctl_net_ipv4_icmp_ignore_bogus_error_responses:obj:1 + + + + + oval:ssg-object_static_sysctl_sysctl_net_ipv4_icmp_ignore_bogus_error_responses:obj:1 + oval:ssg-object_static_etc_sysctld_sysctl_net_ipv4_icmp_ignore_bogus_error_responses:obj:1 + + + + + oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv4_icmp_ignore_bogus_error_responses:obj:1 + oval:ssg-object_static_run_sysctld_sysctl_net_ipv4_icmp_ignore_bogus_error_responses:obj:1 + + + + /etc/sysctl.conf + ^[\s]*net.ipv4.icmp_ignore_bogus_error_responses[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /etc/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.icmp_ignore_bogus_error_responses[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /run/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.icmp_ignore_bogus_error_responses[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/local/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.icmp_ignore_bogus_error_responses[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.icmp_ignore_bogus_error_responses[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + net.ipv4.ip_forward + + + + oval:ssg-object_static_etc_lib_sysctls_sysctl_net_ipv4_ip_forward:obj:1 + oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv4_ip_forward:obj:1 + + + + + oval:ssg-object_static_etc_sysctls_sysctl_net_ipv4_ip_forward:obj:1 + + + + + oval:ssg-object_static_sysctl_sysctl_net_ipv4_ip_forward:obj:1 + oval:ssg-object_static_etc_sysctld_sysctl_net_ipv4_ip_forward:obj:1 + + + + + oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv4_ip_forward:obj:1 + oval:ssg-object_static_run_sysctld_sysctl_net_ipv4_ip_forward:obj:1 + + + + /etc/sysctl.conf + ^[\s]*net.ipv4.ip_forward[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /etc/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.ip_forward[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /run/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.ip_forward[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/local/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.ip_forward[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.ip_forward[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + net.ipv4.ip_local_port_range + + + + oval:ssg-object_static_etc_lib_sysctls_sysctl_net_ipv4_ip_local_port_range:obj:1 + oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv4_ip_local_port_range:obj:1 + + + + + oval:ssg-object_static_etc_sysctls_sysctl_net_ipv4_ip_local_port_range:obj:1 + + + + + oval:ssg-object_static_sysctl_sysctl_net_ipv4_ip_local_port_range:obj:1 + oval:ssg-object_static_etc_sysctld_sysctl_net_ipv4_ip_local_port_range:obj:1 + + + + + oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv4_ip_local_port_range:obj:1 + oval:ssg-object_static_run_sysctld_sysctl_net_ipv4_ip_local_port_range:obj:1 + + + + /etc/sysctl.conf + ^[\s]*net.ipv4.ip_local_port_range[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /etc/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.ip_local_port_range[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /run/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.ip_local_port_range[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/local/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.ip_local_port_range[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.ip_local_port_range[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + net.ipv4.tcp_rfc1337 + + + + oval:ssg-object_static_etc_lib_sysctls_sysctl_net_ipv4_tcp_rfc1337:obj:1 + oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv4_tcp_rfc1337:obj:1 + + + + + oval:ssg-object_static_etc_sysctls_sysctl_net_ipv4_tcp_rfc1337:obj:1 + + + + + oval:ssg-object_static_sysctl_sysctl_net_ipv4_tcp_rfc1337:obj:1 + oval:ssg-object_static_etc_sysctld_sysctl_net_ipv4_tcp_rfc1337:obj:1 + + + + + oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv4_tcp_rfc1337:obj:1 + oval:ssg-object_static_run_sysctld_sysctl_net_ipv4_tcp_rfc1337:obj:1 + + + + /etc/sysctl.conf + ^[\s]*net.ipv4.tcp_rfc1337[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /etc/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.tcp_rfc1337[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /run/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.tcp_rfc1337[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/local/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.tcp_rfc1337[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.tcp_rfc1337[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + net.ipv4.tcp_syncookies + + + + oval:ssg-object_static_etc_lib_sysctls_sysctl_net_ipv4_tcp_syncookies:obj:1 + oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv4_tcp_syncookies:obj:1 + + + + + oval:ssg-object_static_etc_sysctls_sysctl_net_ipv4_tcp_syncookies:obj:1 + + + + + oval:ssg-object_static_sysctl_sysctl_net_ipv4_tcp_syncookies:obj:1 + oval:ssg-object_static_etc_sysctld_sysctl_net_ipv4_tcp_syncookies:obj:1 + + + + + oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv4_tcp_syncookies:obj:1 + oval:ssg-object_static_run_sysctld_sysctl_net_ipv4_tcp_syncookies:obj:1 + + + + /etc/sysctl.conf + ^[\s]*net.ipv4.tcp_syncookies[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /etc/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.tcp_syncookies[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /run/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.tcp_syncookies[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/local/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.tcp_syncookies[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv4.tcp_syncookies[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + net.ipv6.conf.all.accept_ra + + + + oval:ssg-object_static_etc_lib_sysctls_sysctl_net_ipv6_conf_all_accept_ra:obj:1 + oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv6_conf_all_accept_ra:obj:1 + + + + + oval:ssg-object_static_etc_sysctls_sysctl_net_ipv6_conf_all_accept_ra:obj:1 + + + + + oval:ssg-object_static_sysctl_sysctl_net_ipv6_conf_all_accept_ra:obj:1 + oval:ssg-object_static_etc_sysctld_sysctl_net_ipv6_conf_all_accept_ra:obj:1 + + + + + oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv6_conf_all_accept_ra:obj:1 + oval:ssg-object_static_run_sysctld_sysctl_net_ipv6_conf_all_accept_ra:obj:1 + + + + /etc/sysctl.conf + ^[\s]*net.ipv6.conf.all.accept_ra[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /etc/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.all.accept_ra[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /run/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.all.accept_ra[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/local/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.all.accept_ra[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.all.accept_ra[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + net.ipv6.conf.all.accept_ra_defrtr + + + + oval:ssg-object_static_etc_lib_sysctls_sysctl_net_ipv6_conf_all_accept_ra_defrtr:obj:1 + oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv6_conf_all_accept_ra_defrtr:obj:1 + + + + + oval:ssg-object_static_etc_sysctls_sysctl_net_ipv6_conf_all_accept_ra_defrtr:obj:1 + + + + + oval:ssg-object_static_sysctl_sysctl_net_ipv6_conf_all_accept_ra_defrtr:obj:1 + oval:ssg-object_static_etc_sysctld_sysctl_net_ipv6_conf_all_accept_ra_defrtr:obj:1 + + + + + oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv6_conf_all_accept_ra_defrtr:obj:1 + oval:ssg-object_static_run_sysctld_sysctl_net_ipv6_conf_all_accept_ra_defrtr:obj:1 + + + + /etc/sysctl.conf + ^[\s]*net.ipv6.conf.all.accept_ra_defrtr[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /etc/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.all.accept_ra_defrtr[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /run/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.all.accept_ra_defrtr[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/local/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.all.accept_ra_defrtr[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.all.accept_ra_defrtr[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + net.ipv6.conf.all.accept_ra_pinfo + + + + oval:ssg-object_static_etc_lib_sysctls_sysctl_net_ipv6_conf_all_accept_ra_pinfo:obj:1 + oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv6_conf_all_accept_ra_pinfo:obj:1 + + + + + oval:ssg-object_static_etc_sysctls_sysctl_net_ipv6_conf_all_accept_ra_pinfo:obj:1 + + + + + oval:ssg-object_static_sysctl_sysctl_net_ipv6_conf_all_accept_ra_pinfo:obj:1 + oval:ssg-object_static_etc_sysctld_sysctl_net_ipv6_conf_all_accept_ra_pinfo:obj:1 + + + + + oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv6_conf_all_accept_ra_pinfo:obj:1 + oval:ssg-object_static_run_sysctld_sysctl_net_ipv6_conf_all_accept_ra_pinfo:obj:1 + + + + /etc/sysctl.conf + ^[\s]*net.ipv6.conf.all.accept_ra_pinfo[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /etc/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.all.accept_ra_pinfo[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /run/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.all.accept_ra_pinfo[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/local/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.all.accept_ra_pinfo[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.all.accept_ra_pinfo[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + net.ipv6.conf.all.accept_ra_rtr_pref + + + + oval:ssg-object_static_etc_lib_sysctls_sysctl_net_ipv6_conf_all_accept_ra_rtr_pref:obj:1 + oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv6_conf_all_accept_ra_rtr_pref:obj:1 + + + + + oval:ssg-object_static_etc_sysctls_sysctl_net_ipv6_conf_all_accept_ra_rtr_pref:obj:1 + + + + + oval:ssg-object_static_sysctl_sysctl_net_ipv6_conf_all_accept_ra_rtr_pref:obj:1 + oval:ssg-object_static_etc_sysctld_sysctl_net_ipv6_conf_all_accept_ra_rtr_pref:obj:1 + + + + + oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv6_conf_all_accept_ra_rtr_pref:obj:1 + oval:ssg-object_static_run_sysctld_sysctl_net_ipv6_conf_all_accept_ra_rtr_pref:obj:1 + + + + /etc/sysctl.conf + ^[\s]*net.ipv6.conf.all.accept_ra_rtr_pref[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /etc/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.all.accept_ra_rtr_pref[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /run/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.all.accept_ra_rtr_pref[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/local/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.all.accept_ra_rtr_pref[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.all.accept_ra_rtr_pref[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + net.ipv6.conf.all.accept_redirects + + + + oval:ssg-object_static_etc_lib_sysctls_sysctl_net_ipv6_conf_all_accept_redirects:obj:1 + oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv6_conf_all_accept_redirects:obj:1 + + + + + oval:ssg-object_static_etc_sysctls_sysctl_net_ipv6_conf_all_accept_redirects:obj:1 + + + + + oval:ssg-object_static_sysctl_sysctl_net_ipv6_conf_all_accept_redirects:obj:1 + oval:ssg-object_static_etc_sysctld_sysctl_net_ipv6_conf_all_accept_redirects:obj:1 + + + + + oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv6_conf_all_accept_redirects:obj:1 + oval:ssg-object_static_run_sysctld_sysctl_net_ipv6_conf_all_accept_redirects:obj:1 + + + + /etc/sysctl.conf + ^[\s]*net.ipv6.conf.all.accept_redirects[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /etc/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.all.accept_redirects[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /run/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.all.accept_redirects[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/local/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.all.accept_redirects[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.all.accept_redirects[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + net.ipv6.conf.all.accept_source_route + + + + oval:ssg-object_static_etc_lib_sysctls_sysctl_net_ipv6_conf_all_accept_source_route:obj:1 + oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv6_conf_all_accept_source_route:obj:1 + + + + + oval:ssg-object_static_etc_sysctls_sysctl_net_ipv6_conf_all_accept_source_route:obj:1 + + + + + oval:ssg-object_static_sysctl_sysctl_net_ipv6_conf_all_accept_source_route:obj:1 + oval:ssg-object_static_etc_sysctld_sysctl_net_ipv6_conf_all_accept_source_route:obj:1 + + + + + oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv6_conf_all_accept_source_route:obj:1 + oval:ssg-object_static_run_sysctld_sysctl_net_ipv6_conf_all_accept_source_route:obj:1 + + + + /etc/sysctl.conf + ^[\s]*net.ipv6.conf.all.accept_source_route[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /etc/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.all.accept_source_route[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /run/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.all.accept_source_route[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/local/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.all.accept_source_route[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.all.accept_source_route[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + net.ipv6.conf.all.autoconf + + + + oval:ssg-object_static_etc_lib_sysctls_sysctl_net_ipv6_conf_all_autoconf:obj:1 + oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv6_conf_all_autoconf:obj:1 + + + + + oval:ssg-object_static_etc_sysctls_sysctl_net_ipv6_conf_all_autoconf:obj:1 + + + + + oval:ssg-object_static_sysctl_sysctl_net_ipv6_conf_all_autoconf:obj:1 + oval:ssg-object_static_etc_sysctld_sysctl_net_ipv6_conf_all_autoconf:obj:1 + + + + + oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv6_conf_all_autoconf:obj:1 + oval:ssg-object_static_run_sysctld_sysctl_net_ipv6_conf_all_autoconf:obj:1 + + + + /etc/sysctl.conf + ^[\s]*net.ipv6.conf.all.autoconf[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /etc/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.all.autoconf[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /run/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.all.autoconf[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/local/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.all.autoconf[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.all.autoconf[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + net.ipv6.conf.all.disable_ipv6 + + + + oval:ssg-object_static_etc_lib_sysctls_sysctl_net_ipv6_conf_all_disable_ipv6:obj:1 + oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv6_conf_all_disable_ipv6:obj:1 + + + + + oval:ssg-object_static_etc_sysctls_sysctl_net_ipv6_conf_all_disable_ipv6:obj:1 + + + + + oval:ssg-object_static_sysctl_sysctl_net_ipv6_conf_all_disable_ipv6:obj:1 + oval:ssg-object_static_etc_sysctld_sysctl_net_ipv6_conf_all_disable_ipv6:obj:1 + + + + + oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv6_conf_all_disable_ipv6:obj:1 + oval:ssg-object_static_run_sysctld_sysctl_net_ipv6_conf_all_disable_ipv6:obj:1 + + + + /etc/sysctl.conf + ^[\s]*net.ipv6.conf.all.disable_ipv6[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /etc/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.all.disable_ipv6[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /run/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.all.disable_ipv6[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/local/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.all.disable_ipv6[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.all.disable_ipv6[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + net.ipv6.conf.all.forwarding + + + + oval:ssg-object_static_etc_lib_sysctls_sysctl_net_ipv6_conf_all_forwarding:obj:1 + oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv6_conf_all_forwarding:obj:1 + + + + + oval:ssg-object_static_etc_sysctls_sysctl_net_ipv6_conf_all_forwarding:obj:1 + + + + + oval:ssg-object_static_sysctl_sysctl_net_ipv6_conf_all_forwarding:obj:1 + oval:ssg-object_static_etc_sysctld_sysctl_net_ipv6_conf_all_forwarding:obj:1 + + + + + oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv6_conf_all_forwarding:obj:1 + oval:ssg-object_static_run_sysctld_sysctl_net_ipv6_conf_all_forwarding:obj:1 + + + + /etc/sysctl.conf + ^[\s]*net.ipv6.conf.all.forwarding[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /etc/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.all.forwarding[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /run/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.all.forwarding[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/local/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.all.forwarding[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.all.forwarding[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + net.ipv6.conf.all.max_addresses + + + + oval:ssg-object_static_etc_lib_sysctls_sysctl_net_ipv6_conf_all_max_addresses:obj:1 + oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv6_conf_all_max_addresses:obj:1 + + + + + oval:ssg-object_static_etc_sysctls_sysctl_net_ipv6_conf_all_max_addresses:obj:1 + + + + + oval:ssg-object_static_sysctl_sysctl_net_ipv6_conf_all_max_addresses:obj:1 + oval:ssg-object_static_etc_sysctld_sysctl_net_ipv6_conf_all_max_addresses:obj:1 + + + + + oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv6_conf_all_max_addresses:obj:1 + oval:ssg-object_static_run_sysctld_sysctl_net_ipv6_conf_all_max_addresses:obj:1 + + + + /etc/sysctl.conf + ^[\s]*net.ipv6.conf.all.max_addresses[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /etc/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.all.max_addresses[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /run/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.all.max_addresses[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/local/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.all.max_addresses[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.all.max_addresses[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + net.ipv6.conf.all.router_solicitations + + + + oval:ssg-object_static_etc_lib_sysctls_sysctl_net_ipv6_conf_all_router_solicitations:obj:1 + oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv6_conf_all_router_solicitations:obj:1 + + + + + oval:ssg-object_static_etc_sysctls_sysctl_net_ipv6_conf_all_router_solicitations:obj:1 + + + + + oval:ssg-object_static_sysctl_sysctl_net_ipv6_conf_all_router_solicitations:obj:1 + oval:ssg-object_static_etc_sysctld_sysctl_net_ipv6_conf_all_router_solicitations:obj:1 + + + + + oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv6_conf_all_router_solicitations:obj:1 + oval:ssg-object_static_run_sysctld_sysctl_net_ipv6_conf_all_router_solicitations:obj:1 + + + + /etc/sysctl.conf + ^[\s]*net.ipv6.conf.all.router_solicitations[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /etc/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.all.router_solicitations[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /run/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.all.router_solicitations[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/local/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.all.router_solicitations[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.all.router_solicitations[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + net.ipv6.conf.default.accept_ra + + + + oval:ssg-object_static_etc_lib_sysctls_sysctl_net_ipv6_conf_default_accept_ra:obj:1 + oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv6_conf_default_accept_ra:obj:1 + + + + + oval:ssg-object_static_etc_sysctls_sysctl_net_ipv6_conf_default_accept_ra:obj:1 + + + + + oval:ssg-object_static_sysctl_sysctl_net_ipv6_conf_default_accept_ra:obj:1 + oval:ssg-object_static_etc_sysctld_sysctl_net_ipv6_conf_default_accept_ra:obj:1 + + + + + oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv6_conf_default_accept_ra:obj:1 + oval:ssg-object_static_run_sysctld_sysctl_net_ipv6_conf_default_accept_ra:obj:1 + + + + /etc/sysctl.conf + ^[\s]*net.ipv6.conf.default.accept_ra[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /etc/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.default.accept_ra[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /run/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.default.accept_ra[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/local/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.default.accept_ra[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.default.accept_ra[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + net.ipv6.conf.default.accept_ra_defrtr + + + + oval:ssg-object_static_etc_lib_sysctls_sysctl_net_ipv6_conf_default_accept_ra_defrtr:obj:1 + oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv6_conf_default_accept_ra_defrtr:obj:1 + + + + + oval:ssg-object_static_etc_sysctls_sysctl_net_ipv6_conf_default_accept_ra_defrtr:obj:1 + + + + + oval:ssg-object_static_sysctl_sysctl_net_ipv6_conf_default_accept_ra_defrtr:obj:1 + oval:ssg-object_static_etc_sysctld_sysctl_net_ipv6_conf_default_accept_ra_defrtr:obj:1 + + + + + oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv6_conf_default_accept_ra_defrtr:obj:1 + oval:ssg-object_static_run_sysctld_sysctl_net_ipv6_conf_default_accept_ra_defrtr:obj:1 + + + + /etc/sysctl.conf + ^[\s]*net.ipv6.conf.default.accept_ra_defrtr[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /etc/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.default.accept_ra_defrtr[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /run/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.default.accept_ra_defrtr[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/local/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.default.accept_ra_defrtr[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.default.accept_ra_defrtr[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + net.ipv6.conf.default.accept_ra_pinfo + + + + oval:ssg-object_static_etc_lib_sysctls_sysctl_net_ipv6_conf_default_accept_ra_pinfo:obj:1 + oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv6_conf_default_accept_ra_pinfo:obj:1 + + + + + oval:ssg-object_static_etc_sysctls_sysctl_net_ipv6_conf_default_accept_ra_pinfo:obj:1 + + + + + oval:ssg-object_static_sysctl_sysctl_net_ipv6_conf_default_accept_ra_pinfo:obj:1 + oval:ssg-object_static_etc_sysctld_sysctl_net_ipv6_conf_default_accept_ra_pinfo:obj:1 + + + + + oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv6_conf_default_accept_ra_pinfo:obj:1 + oval:ssg-object_static_run_sysctld_sysctl_net_ipv6_conf_default_accept_ra_pinfo:obj:1 + + + + /etc/sysctl.conf + ^[\s]*net.ipv6.conf.default.accept_ra_pinfo[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /etc/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.default.accept_ra_pinfo[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /run/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.default.accept_ra_pinfo[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/local/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.default.accept_ra_pinfo[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.default.accept_ra_pinfo[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + net.ipv6.conf.default.accept_ra_rtr_pref + + + + oval:ssg-object_static_etc_lib_sysctls_sysctl_net_ipv6_conf_default_accept_ra_rtr_pref:obj:1 + oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv6_conf_default_accept_ra_rtr_pref:obj:1 + + + + + oval:ssg-object_static_etc_sysctls_sysctl_net_ipv6_conf_default_accept_ra_rtr_pref:obj:1 + + + + + oval:ssg-object_static_sysctl_sysctl_net_ipv6_conf_default_accept_ra_rtr_pref:obj:1 + oval:ssg-object_static_etc_sysctld_sysctl_net_ipv6_conf_default_accept_ra_rtr_pref:obj:1 + + + + + oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv6_conf_default_accept_ra_rtr_pref:obj:1 + oval:ssg-object_static_run_sysctld_sysctl_net_ipv6_conf_default_accept_ra_rtr_pref:obj:1 + + + + /etc/sysctl.conf + ^[\s]*net.ipv6.conf.default.accept_ra_rtr_pref[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /etc/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.default.accept_ra_rtr_pref[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /run/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.default.accept_ra_rtr_pref[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/local/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.default.accept_ra_rtr_pref[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.default.accept_ra_rtr_pref[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + net.ipv6.conf.default.accept_redirects + + + + oval:ssg-object_static_etc_lib_sysctls_sysctl_net_ipv6_conf_default_accept_redirects:obj:1 + oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv6_conf_default_accept_redirects:obj:1 + + + + + oval:ssg-object_static_etc_sysctls_sysctl_net_ipv6_conf_default_accept_redirects:obj:1 + + + + + oval:ssg-object_static_sysctl_sysctl_net_ipv6_conf_default_accept_redirects:obj:1 + oval:ssg-object_static_etc_sysctld_sysctl_net_ipv6_conf_default_accept_redirects:obj:1 + + + + + oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv6_conf_default_accept_redirects:obj:1 + oval:ssg-object_static_run_sysctld_sysctl_net_ipv6_conf_default_accept_redirects:obj:1 + + + + /etc/sysctl.conf + ^[\s]*net.ipv6.conf.default.accept_redirects[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /etc/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.default.accept_redirects[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /run/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.default.accept_redirects[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/local/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.default.accept_redirects[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.default.accept_redirects[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + net.ipv6.conf.default.accept_source_route + + + + oval:ssg-object_static_etc_lib_sysctls_sysctl_net_ipv6_conf_default_accept_source_route:obj:1 + oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv6_conf_default_accept_source_route:obj:1 + + + + + oval:ssg-object_static_etc_sysctls_sysctl_net_ipv6_conf_default_accept_source_route:obj:1 + + + + + oval:ssg-object_static_sysctl_sysctl_net_ipv6_conf_default_accept_source_route:obj:1 + oval:ssg-object_static_etc_sysctld_sysctl_net_ipv6_conf_default_accept_source_route:obj:1 + + + + + oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv6_conf_default_accept_source_route:obj:1 + oval:ssg-object_static_run_sysctld_sysctl_net_ipv6_conf_default_accept_source_route:obj:1 + + + + /etc/sysctl.conf + ^[\s]*net.ipv6.conf.default.accept_source_route[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /etc/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.default.accept_source_route[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /run/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.default.accept_source_route[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/local/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.default.accept_source_route[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.default.accept_source_route[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + net.ipv6.conf.default.autoconf + + + + oval:ssg-object_static_etc_lib_sysctls_sysctl_net_ipv6_conf_default_autoconf:obj:1 + oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv6_conf_default_autoconf:obj:1 + + + + + oval:ssg-object_static_etc_sysctls_sysctl_net_ipv6_conf_default_autoconf:obj:1 + + + + + oval:ssg-object_static_sysctl_sysctl_net_ipv6_conf_default_autoconf:obj:1 + oval:ssg-object_static_etc_sysctld_sysctl_net_ipv6_conf_default_autoconf:obj:1 + + + + + oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv6_conf_default_autoconf:obj:1 + oval:ssg-object_static_run_sysctld_sysctl_net_ipv6_conf_default_autoconf:obj:1 + + + + /etc/sysctl.conf + ^[\s]*net.ipv6.conf.default.autoconf[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /etc/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.default.autoconf[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /run/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.default.autoconf[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/local/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.default.autoconf[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.default.autoconf[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + net.ipv6.conf.default.disable_ipv6 + + + + oval:ssg-object_static_etc_lib_sysctls_sysctl_net_ipv6_conf_default_disable_ipv6:obj:1 + oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv6_conf_default_disable_ipv6:obj:1 + + + + + oval:ssg-object_static_etc_sysctls_sysctl_net_ipv6_conf_default_disable_ipv6:obj:1 + + + + + oval:ssg-object_static_sysctl_sysctl_net_ipv6_conf_default_disable_ipv6:obj:1 + oval:ssg-object_static_etc_sysctld_sysctl_net_ipv6_conf_default_disable_ipv6:obj:1 + + + + + oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv6_conf_default_disable_ipv6:obj:1 + oval:ssg-object_static_run_sysctld_sysctl_net_ipv6_conf_default_disable_ipv6:obj:1 + + + + /etc/sysctl.conf + ^[\s]*net.ipv6.conf.default.disable_ipv6[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /etc/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.default.disable_ipv6[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /run/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.default.disable_ipv6[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/local/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.default.disable_ipv6[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.default.disable_ipv6[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + net.ipv6.conf.default.max_addresses + + + + oval:ssg-object_static_etc_lib_sysctls_sysctl_net_ipv6_conf_default_max_addresses:obj:1 + oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv6_conf_default_max_addresses:obj:1 + + + + + oval:ssg-object_static_etc_sysctls_sysctl_net_ipv6_conf_default_max_addresses:obj:1 + + + + + oval:ssg-object_static_sysctl_sysctl_net_ipv6_conf_default_max_addresses:obj:1 + oval:ssg-object_static_etc_sysctld_sysctl_net_ipv6_conf_default_max_addresses:obj:1 + + + + + oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv6_conf_default_max_addresses:obj:1 + oval:ssg-object_static_run_sysctld_sysctl_net_ipv6_conf_default_max_addresses:obj:1 + + + + /etc/sysctl.conf + ^[\s]*net.ipv6.conf.default.max_addresses[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /etc/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.default.max_addresses[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /run/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.default.max_addresses[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/local/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.default.max_addresses[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.default.max_addresses[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + net.ipv6.conf.default.router_solicitations + + + + oval:ssg-object_static_etc_lib_sysctls_sysctl_net_ipv6_conf_default_router_solicitations:obj:1 + oval:ssg-object_static_run_usr_local_sysctls_sysctl_net_ipv6_conf_default_router_solicitations:obj:1 + + + + + oval:ssg-object_static_etc_sysctls_sysctl_net_ipv6_conf_default_router_solicitations:obj:1 + + + + + oval:ssg-object_static_sysctl_sysctl_net_ipv6_conf_default_router_solicitations:obj:1 + oval:ssg-object_static_etc_sysctld_sysctl_net_ipv6_conf_default_router_solicitations:obj:1 + + + + + oval:ssg-object_static_usr_local_lib_sysctld_sysctl_net_ipv6_conf_default_router_solicitations:obj:1 + oval:ssg-object_static_run_sysctld_sysctl_net_ipv6_conf_default_router_solicitations:obj:1 + + + + /etc/sysctl.conf + ^[\s]*net.ipv6.conf.default.router_solicitations[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /etc/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.default.router_solicitations[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /run/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.default.router_solicitations[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/local/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.default.router_solicitations[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/lib/sysctl.d + ^.*\.conf$ + ^[\s]*net.ipv6.conf.default.router_solicitations[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + user.max_user_namespaces + + + + oval:ssg-object_static_etc_lib_sysctls_sysctl_user_max_user_namespaces:obj:1 + oval:ssg-object_static_run_usr_local_sysctls_sysctl_user_max_user_namespaces:obj:1 + + + + + oval:ssg-object_static_etc_sysctls_sysctl_user_max_user_namespaces:obj:1 + + + + + oval:ssg-object_static_sysctl_sysctl_user_max_user_namespaces:obj:1 + oval:ssg-object_static_etc_sysctld_sysctl_user_max_user_namespaces:obj:1 + + + + + oval:ssg-object_static_usr_local_lib_sysctld_sysctl_user_max_user_namespaces:obj:1 + oval:ssg-object_static_run_sysctld_sysctl_user_max_user_namespaces:obj:1 + + + + /etc/sysctl.conf + ^[\s]*user.max_user_namespaces[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /etc/sysctl.d + ^.*\.conf$ + ^[\s]*user.max_user_namespaces[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /run/sysctl.d + ^.*\.conf$ + ^[\s]*user.max_user_namespaces[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/local/lib/sysctl.d + ^.*\.conf$ + ^[\s]*user.max_user_namespaces[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/lib/sysctl.d + ^.*\.conf$ + ^[\s]*user.max_user_namespaces[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + vm.mmap_min_addr + + + + oval:ssg-object_static_etc_lib_sysctls_sysctl_vm_mmap_min_addr:obj:1 + oval:ssg-object_static_run_usr_local_sysctls_sysctl_vm_mmap_min_addr:obj:1 + + + + + oval:ssg-object_static_etc_sysctls_sysctl_vm_mmap_min_addr:obj:1 + + + + + oval:ssg-object_static_sysctl_sysctl_vm_mmap_min_addr:obj:1 + oval:ssg-object_static_etc_sysctld_sysctl_vm_mmap_min_addr:obj:1 + + + + + oval:ssg-object_static_usr_local_lib_sysctld_sysctl_vm_mmap_min_addr:obj:1 + oval:ssg-object_static_run_sysctld_sysctl_vm_mmap_min_addr:obj:1 + + + + /etc/sysctl.conf + ^[\s]*vm.mmap_min_addr[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /etc/sysctl.d + ^.*\.conf$ + ^[\s]*vm.mmap_min_addr[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /run/sysctl.d + ^.*\.conf$ + ^[\s]*vm.mmap_min_addr[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/local/lib/sysctl.d + ^.*\.conf$ + ^[\s]*vm.mmap_min_addr[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + /usr/lib/sysctl.d + ^.*\.conf$ + ^[\s]*vm.mmap_min_addr[\s]*=[\s]*(.*\S)[\s]*$ + 1 + + + multi-user.target + + + tmp.mount + ActiveState + + + multi-user.target + + + dnf-automatic\.timer + ActiveState + + + multi-user.target + + + logrotate\.timer + ActiveState + + + + ^\s*password\s+(?:(?:required)|(?:requisite))\s+pam_pwquality\.so.*$ + 1 + + + /usr/lib/systemd/system/auditd.service + ^ExecStartPost=\-\/sbin\/auditctl.*$ + 1 + + + /usr/lib/systemd/system/auditd.service + ^(ExecStartPost=\-\/sbin\/augenrules.*$|Requires=augenrules.service) + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+setdomainname[\s]+|([\s]+|[,])setdomainname([\s]+|[,]))).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+setdomainname[\s]+|([\s]+|[,])setdomainname([\s]+|[,]))).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+setdomainname[\s]+|([\s]+|[,])setdomainname([\s]+|[,]))).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+setdomainname[\s]+|([\s]+|[,])setdomainname([\s]+|[,]))).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+sethostname[\s]+|([\s]+|[,])sethostname([\s]+|[,]))).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+sethostname[\s]+|([\s]+|[,])sethostname([\s]+|[,]))).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+sethostname[\s]+|([\s]+|[,])sethostname([\s]+|[,]))).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+sethostname[\s]+|([\s]+|[,])sethostname([\s]+|[,]))).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/auditd.conf + ^(log_file\s*=\s*.*)$ + 1 + + + /etc/audit/auditd.conf + ^[ ]*log_group[ ]+=[ ]+root[ ]*$ + 1 + + + /etc/audit/auditd.conf + ^[ ]*log_group[ ]+=.*$ + 1 + + + kernel + + + rpm-ostree + + + bootc + + + openshift-kubelet + + + /etc/default/grub + ^\s*GRUB_DISABLE_RECOVERY=(.*)$ + 1 + + + ^/etc/chrony\.(conf|d/.+\.conf)$ + ^([\s]*server[\s]+.+$){2,}$ + 1 + + + oraclelinux-release + + + oraclelinux-release + + + oraclelinux-release + + + + /etc/os-release + ^ID="(\w+)"$ + 1 + + + /etc/os-release + ^VERSION_ID="(\d)\.\d+"$ + 1 + + + + redhat-release + + + /etc/redhat-release + ^Red Hat Enterprise Linux release (\d)\.\d+$ + 1 + + + + redhat-release + + + /etc/redhat-release + ^Red Hat Enterprise Linux release (\d)\.\d+$ + 1 + + + redhat-release-virtualization-host + + + + sled-release + + + sles-release + + + SLES_SAP-release + + + + sled-release + + + sles-release + + + SLES_SAP-release + + + SUSE-Manager-Server-release + + + SLE_HPC-release + + + + SUSE-MicroOS-release + + + SLE-Micro-release + + + /etc/lsb-release + + + /etc/lsb-release + ^DISTRIB_ID=Ubuntu$ + 1 + + + /etc/lsb-release + ^DISTRIB_CODENAME=xenial$ + 1 + + + /etc/lsb-release + ^DISTRIB_CODENAME=bionic$ + 1 + + + /etc/lsb-release + ^DISTRIB_CODENAME=focal$ + 1 + + + /etc/fstab + + 1 + + + + + + oval:ssg-sshd_required:var:1 + + + oval:ssg-sshd_required:var:1 + + + oval:ssg-sshd_required:var:1 + + + + + + + + + ^/etc/usbguard/(rules|rules\.d/.*)\.conf$ + ^.*\S+.*$ + 1 + + + oval:ssg-var_accounts_user_umask_umask_as_number:var:1 + + + oval:ssg-var_removable_partition:var:1 + + + + + + + + 0 + + + 0 + + + 0 + + + true + true + true + true + true + true + true + + + true + true + true + true + true + true + true + true + true + + + 0 + + + 0 + 0 + + + 0 + 0 + + + true + true + true + true + true + true + true + true + true + true + + + ^(/dev/.*|composefs)$ + + + nosuid + + + noexec + + + true + true + + + ^/var/tmp/dracut.* + + + ^/sysroot/.*$ + + + + + + + + + + + + + + + + + + + + + + + + + + + SYSLOG + + + SINGLE + + + HALT + + + + + + SYSLOG + + + SINGLE + + + HALT + + + + + + + + + + + + + + + rotate + + + single + + + + + + + + + + + + + + + ^(?i)(syslog|single|halt)(?-i)$ + + + 0 + + + + + + (?i)root + + + + + + ^permit_mynetworks[ \t]*[, \t][ \t]*reject$ + + + ^.*,sec=krb5\:krb5i\:krb5p.*$ + + + 0 + + + 0 + + + + + + maxpoll \d+ + + + altfiles + + + + + + symbolic link + + + + + + + + + symbolic link + + + /etc/ssh + .*_key$ + 0 + 0 + false + false + false + false + false + false + false + false + false + false + + + /etc/ssh + .*_key$ + + 0 + false + false + false + false + false + false + false + false + false + + + + + + + + + + + + + + + 0 + + + + + + 0 + + + + + + 0 + + + + + + 0 + + + + + + + + + + + + + + + + + + ^.*pam.*$ + + + (?i)true + + + ^.*allow_missing_name.*$ + + + ^.*(try_cert_auth|require_cert_auth).*$ + + + 1 + + + false + + + (?i)demand + + + (?i)true + + + ^LinuxAudit$ + + + /etc/systemd/system/default.target + ^(/usr)?/lib/systemd/system/multi-user.target$ + + + /etc/pam.d/fingerprint-auth + /etc/authselect/fingerprint-auth + + + /etc/pam.d/password-auth + /etc/authselect/password-auth + + + /etc/pam.d/postlogin + /etc/authselect/postlogin + + + /etc/pam.d/smartcard-auth + /etc/authselect/smartcard-auth + + + /etc/pam.d/system-auth + /etc/authselect/system-auth + + + + + + + + + + + + + + + faillog_t + + + + + + + + + + + + /var/run/faillock + + + 2 + + + 2 + + + + + + 0 + + + + + + + + + + + + + + + + + + 5000 + + + /etc/systemd/system/ctrl-alt-del.target + /dev/null + + + + + + .*/usr/lib/systemd/systemd-sulogin-shell[ ]+rescue + + + + + + + + + ^root$ + + + + + + + + + + + + 0 + + + + + + 0 + + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ^[x*]$ + + + ^(!|!!|!\*|\*|!locked)$ + + + ^(!\$6\$|!!\$6\$).*$ + + + SHA-512 + + + .* + + + ^(!|!!|!\*|\*|!locked)$ + + + + + + + + + + + + + + + 0 + + + ^[^:]+:[^:]+:[0-9]+:\s*$ + + + 1000 + + + ^(root|halt|sync|shutdown|nfsnobody)$ + + + ^(!|!!|!\*|\*|!locked).*$ + + + 0 + + + + + + + + + + + + + + + + + + + + + + + + directory + false + false + false + false + false + false + false + false + false + + + directory + false + false + false + false + false + false + false + false + false + + + 1 + + + + + + ^(nobody|nfsnobody)$ + + + ^(nobody|nfsnobody)$ + + + + + + 1000 + + + ^(nobody|nfsnobody)$ + + + ^/sbin/nologin$ + + + regular + true + + + ^(nobody|nfsnobody)$ + + + ^(nobody|nfsnobody)$ + + + + + + 1000 + + + ^(nobody|nfsnobody)$ + + + ^/sbin/nologin$ + + + ^\/[^\/\n]*\/[^\/\n]{1,}.*$ + + + ^(nobody|nfsnobody)$ + + + + + + ^(nobody|nfsnobody)$ + + + ^(nobody|nfsnobody)$ + + + + + + ^(nobody|nfsnobody)$ + + + ^(nobody|nfsnobody)$ + + + + + + ^(nobody|nfsnobody)$ + + + symbolic link + + + false + false + false + false + false + false + false + + + ^(nobody|nfsnobody)$ + + + ^(nobody|nfsnobody)$ + + + + + + false + false + false + false + false + false + false + false + + + 1000 + + + ^(nobody|nfsnobody)$ + + + ^/sbin/nologin$ + + + ^(nobody|nfsnobody)$ + + + directory + false + false + false + false + false + false + false + + + 1000 + + + ^(nobody|nfsnobody)$ + + + ^/sbin/nologin$ + + + directory + false + false + false + false + false + false + false + + + true + true + + + symbolic link + + + ^[:\.] + + + :: + + + \.\. + + + [:\.]$ + + + ^[^/] + + + [^\\]:[^/] + + + + + + + + + + + + + + + ^(nobody|nfsnobody)$ + + + ^\.bash_history + + + + + + 65536 + + + 32768 + + + + + + ^aarch64$ + + + ^x86_64$ + + + symbolic link + + + (?=[\S\s]*\s(?i)protocol(?-i)="tcp")(?=[\S\s]*\s(?i)Target(?-i)="[^"]+?")(?=[\S\s]*\s(?i)port(?-i)="6514")(?=[\S\s]*\s(?i)StreamDriver(?-i)="gtls")(?=[\S\s]*\s(?i)StreamDriverMode(?-i)="1")(?=[\S\s]*\s(?i)StreamDriverAuthMode(?-i)="x509/name")(?=[\S\s]*\s(?i)StreamDriver\.CheckExtendedKeyPurpose(?-i)="on") + + + 0 + + + ResultActive=auth_admin + + + PROMISC + + + UP + + + ^.*\bdefault|none\b.*$ + + + 0 + true + + + false + true + + + ^/dev/.*$ + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + true + + + ^/sysroot/.*$ + + + ^/dev/.*$ + + + + + + true + + + ^/sysroot/.*$ + + + ^/dev/.*$ + + + + + + regular + true + + + ^/selinux/(?:(?:member)|(?:user)|(?:relabel)|(?:create)|(?:access)|(?:context))$ + + + ^/sysroot/.*$ + + + ^/dev/.*$ + + + + + + + + + ^/sysroot/.*$ + + + ^/dev/.*$ + + + altfiles + + + + + + ^/dev/.*$ + + + 1000 + + + 0 + + + true + true + + + symbolic link + + + ^/dev/.*$ + nodev + + + 1 + nodev + + + + + + 1 + + + + + + ^(?!(\/etc\/sysctl\.conf$|(\/etc|\/run|\/usr\/lib)\/sysctl\.d\/)).*$ + + + + + + ^(?i)0(?-i)$ + + + ^(?i)0(?-i)$ + + + ^(?i)none(?-i)$ + + + ^(?i)none(?-i)$ + + + 0 + + + 0 + + + ^(block|character) special$ + + + device_t + + + unlabeled_t + + + unconfined_service_t + + + ^(enforcing|permissive)$ + + + + + + + + + x86_64 + + + \blm\b + + + ^(x86_64|aarch64|ppc64le|s390x|.*-amd64)$ + + + + + + ^false$ + + + + + + + + + + + + + + + + + + + + + /etc/crypto-policies/back-ends/krb5.config + + + ^final all$ + + + ^512M 1h$ + + + ^no$ + + + ^aes256-ctr,aes256-cbc,aes128-ctr,aes128-cbc$ + + + ^ssh-rsa,ecdsa-sha2-nistp384,ecdsa-sha2-nistp256$ + + + ^hmac-sha2-512,hmac-sha2-256$ + + + ^ecdh-sha2-nistp521,ecdh-sha2-nistp384,ecdh-sha2-nistp256,diffie-hellman-group14-sha1$ + + + + + + + + + + + + + + + fips + + + ^(?:.*\s)?fips=1(?:\s.*)?$ + + + ^FIPS(:OSPP)?$ + + + 1 + + + ^p\+i\+n\+u\+g\+s\+b\+acl(|\+selinux)\+xattrs\+sha512$ + + + ^.*sha512.*$ + + + ^.*acl.*$ + + + ^.*xattrs.*$ + + + fail + false + false + + + fail + fail + + + fail + + + 0 + + + ^yes$ + + + ^security$ + + + 629e59ec + 8d8b756f + + + 629ec292 + 8b4efbe6 + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + + + + + + + + + 1 + + + + + + + + + ## Unsuccessful file access (any other opens) This has to go last. -a always,exit -F arch=b32 -S open,openat,openat2,open_by_handle_at -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-access -a always,exit -F arch=b64 -S open,openat,openat2,open_by_handle_at -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-access -a always,exit -F arch=b32 -S open,openat,openat2,open_by_handle_at -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-access -a always,exit -F arch=b64 -S open,openat,openat2,open_by_handle_at -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-access - - - - ## Successful file access (any other opens) This has to go last. + + + + ## Successful file access (any other opens) This has to go last. ## These next two are likely to result in a whole lot of events -a always,exit -F arch=b32 -S open,openat,openat2,open_by_handle_at -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-access -a always,exit -F arch=b64 -S open,openat,openat2,open_by_handle_at -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-access - - - - ## First rule - delete all + + + + ## First rule - delete all -D ## Increase the buffers to survive stress events. @@ -217655,10 +234212,10 @@ which the system will be deployed as closely as possible. ## Set failure mode to syslog -f 1 - - - - ## Unsuccessful file creation (open with O_CREAT) + + + + ## Unsuccessful file creation (open with O_CREAT) -a always,exit -F arch=b32 -S openat,open_by_handle_at -F a2&0100 -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-create -a always,exit -F arch=b64 -S openat,open_by_handle_at -F a2&0100 -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-create -a always,exit -F arch=b32 -S open -F a1&0100 -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-create @@ -217671,40 +234228,40 @@ which the system will be deployed as closely as possible. -a always,exit -F arch=b64 -S open -F a1&0100 -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-create -a always,exit -F arch=b32 -S creat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-create -a always,exit -F arch=b64 -S creat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-create - - - - ## Successful file creation (open with O_CREAT) + + + + ## Successful file creation (open with O_CREAT) -a always,exit -F arch=b32 -S openat,open_by_handle_at -F a2&0100 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-create -a always,exit -F arch=b64 -S openat,open_by_handle_at -F a2&0100 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-create -a always,exit -F arch=b32 -S open -F a1&0100 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-create -a always,exit -F arch=b64 -S open -F a1&0100 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-create -a always,exit -F arch=b32 -S creat -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-create -a always,exit -F arch=b64 -S creat -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-create - - - - ## Unsuccessful file delete + + + + ## Unsuccessful file delete -a always,exit -F arch=b32 -S unlink,unlinkat,rename,renameat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-delete -a always,exit -F arch=b64 -S unlink,unlinkat,rename,renameat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-delete -a always,exit -F arch=b32 -S unlink,unlinkat,rename,renameat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-delete -a always,exit -F arch=b64 -S unlink,unlinkat,rename,renameat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-delete - - - - ## Successful file delete + + + + ## Successful file delete -a always,exit -F arch=b32 -S unlink,unlinkat,rename,renameat -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-delete -a always,exit -F arch=b64 -S unlink,unlinkat,rename,renameat -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-delete - - - - ## Make the loginuid immutable. This prevents tampering with the auid. + + + + ## Make the loginuid immutable. This prevents tampering with the auid. --loginuid-immutable - - - - ## Unsuccessful file modifications (open for write or truncate) + + + + ## Unsuccessful file modifications (open for write or truncate) -a always,exit -F arch=b32 -S openat,open_by_handle_at -F a2&01003 -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-modification -a always,exit -F arch=b64 -S openat,open_by_handle_at -F a2&01003 -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-modification -a always,exit -F arch=b32 -S open -F a1&01003 -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-modification @@ -217717,29 +234274,29 @@ which the system will be deployed as closely as possible. -a always,exit -F arch=b64 -S open -F a1&01003 -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-modification -a always,exit -F arch=b32 -S truncate,ftruncate -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-modification -a always,exit -F arch=b64 -S truncate,ftruncate -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-modification - - - - ## Successful file modifications (open for write or truncate) + + + + ## Successful file modifications (open for write or truncate) -a always,exit -F arch=b32 -S openat,open_by_handle_at -F a2&01003 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-modification -a always,exit -F arch=b64 -S openat,open_by_handle_at -F a2&01003 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-modification -a always,exit -F arch=b32 -S open -F a1&01003 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-modification -a always,exit -F arch=b64 -S open -F a1&01003 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-modification -a always,exit -F arch=b32 -S truncate,ftruncate -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-modification -a always,exit -F arch=b64 -S truncate,ftruncate -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-modification - - - - ## These rules watch for kernel module insertion. By monitoring + + + + ## These rules watch for kernel module insertion. By monitoring ## the syscall, we do not need any watches on programs. -a always,exit -F arch=b32 -S init_module,finit_module -F key=module-load -a always,exit -F arch=b64 -S init_module,finit_module -F key=module-load -a always,exit -F arch=b32 -S delete_module -F key=module-unload -a always,exit -F arch=b64 -S delete_module -F key=module-unload - - - - ## The purpose of these rules is to meet the requirements for Operating + + + + ## The purpose of these rules is to meet the requirements for Operating ## System Protection Profile (OSPP)v4.2. These rules depends on having ## the following rule files copied to /etc/audit/rules.d: ## @@ -217752,9 +234309,6 @@ which the system will be deployed as closely as possible. ## 30-ospp-v42-5-perm-change-success.rules, ## 30-ospp-v42-6-owner-change-failed.rules, ## 30-ospp-v42-6-owner-change-success.rules -## -## original copies may be found in /usr/share/audit/sample-rules/ - ## User add delete modify. This is covered by pam. However, someone could ## open a file and directly create or modify a user, so we'll watch passwd and @@ -217773,44 +234327,77 @@ which the system will be deployed as closely as possible. ## Group add delete modify. This is covered by pam. However, someone could ## open a file and directly create or modify a user, so we'll watch group and ## gshadow for writes --a always,exit -F path=/etc/passwd -F perm=wa -F auid>=1000 -F auid!=unset -F key=user-modify --a always,exit -F path=/etc/shadow -F perm=wa -F auid>=1000 -F auid!=unset -F key=user-modify --a always,exit -F path=/etc/group -F perm=wa -F auid>=1000 -F auid!=unset -F key=group-modify --a always,exit -F path=/etc/gshadow -F perm=wa -F auid>=1000 -F auid!=unset -F key=group-modify +-a always,exit -F arch=b32 -F path=/etc/passwd -F perm=wa -F auid>=1000 -F auid!=unset -F key=user-modify +-a always,exit -F arch=b64 -F path=/etc/passwd -F perm=wa -F auid>=1000 -F auid!=unset -F key=user-modify +-a always,exit -F arch=b32 -F path=/etc/shadow -F perm=wa -F auid>=1000 -F auid!=unset -F key=user-modify +-a always,exit -F arch=b64 -F path=/etc/shadow -F perm=wa -F auid>=1000 -F auid!=unset -F key=user-modify +-a always,exit -F arch=b32 -F path=/etc/group -F perm=wa -F auid>=1000 -F auid!=unset -F key=group-modify +-a always,exit -F arch=b64 -F path=/etc/group -F perm=wa -F auid>=1000 -F auid!=unset -F key=group-modify +-a always,exit -F arch=b32 -F path=/etc/gshadow -F perm=wa -F auid>=1000 -F auid!=unset -F key=group-modify +-a always,exit -F arch=b64 -F path=/etc/gshadow -F perm=wa -F auid>=1000 -F auid!=unset -F key=group-modify ## Use of special rights for config changes. This would be use of setuid ## programs that relate to user accts. This is not all setuid apps because ## requirements are only for ones that affect system configuration. --a always,exit -F path=/usr/sbin/unix_chkpwd -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes --a always,exit -F path=/usr/sbin/usernetctl -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes --a always,exit -F path=/usr/sbin/userhelper -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes --a always,exit -F path=/usr/sbin/seunshare -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes --a always,exit -F path=/usr/bin/mount -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes --a always,exit -F path=/usr/bin/newgrp -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes --a always,exit -F path=/usr/bin/newuidmap -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes --a always,exit -F path=/usr/bin/gpasswd -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes --a always,exit -F path=/usr/bin/newgidmap -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes --a always,exit -F path=/usr/bin/umount -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes --a always,exit -F path=/usr/bin/passwd -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes --a always,exit -F path=/usr/bin/crontab -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes --a always,exit -F path=/usr/bin/at -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b32 -F path=/usr/sbin/unix_chkpwd -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b64 -F path=/usr/sbin/unix_chkpwd -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b32 -F path=/usr/sbin/usernetctl -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b64 -F path=/usr/sbin/usernetctl -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b32 -F path=/usr/sbin/userhelper -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b64 -F path=/usr/sbin/userhelper -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b32 -F path=/usr/sbin/seunshare -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b64 -F path=/usr/sbin/seunshare -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b32 -F path=/usr/bin/mount -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b64 -F path=/usr/bin/mount -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b32 -F path=/usr/bin/newgrp -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b64 -F path=/usr/bin/newgrp -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b32 -F path=/usr/bin/newuidmap -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b64 -F path=/usr/bin/newuidmap -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b32 -F path=/usr/bin/gpasswd -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b64 -F path=/usr/bin/gpasswd -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b32 -F path=/usr/bin/newgidmap -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b64 -F path=/usr/bin/newgidmap -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b32 -F path=/usr/bin/umount -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b64 -F path=/usr/bin/umount -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b32 -F path=/usr/bin/passwd -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b64 -F path=/usr/bin/passwd -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b32 -F path=/usr/bin/crontab -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b64 -F path=/usr/bin/crontab -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b32 -F path=/usr/bin/at -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b64 -F path=/usr/bin/at -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b32 -F path=/usr/sbin/grub2-set-bootflag -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b64 -F path=/usr/sbin/grub2-set-bootflag -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes ## Privilege escalation via su or sudo. This is entirely handled by pam. +## Special case for systemd-run. It is not audit aware, specifically watch it +-a always,exit -F arch=b32 -F path=/usr/bin/systemd-run -F perm=x -F auid!=unset -F key=maybe-escalation +-a always,exit -F arch=b64 -F path=/usr/bin/systemd-run -F perm=x -F auid!=unset -F key=maybe-escalation +## Special case for pkexec. It is not audit aware, specifically watch it +-a always,exit -F arch=b32 -F path=/usr/bin/pkexec -F perm=x -F key=maybe-escalation +-a always,exit -F arch=b64 -F path=/usr/bin/pkexec -F perm=x -F key=maybe-escalation + ## Watch for configuration changes to privilege escalation. --a always,exit -F path=/etc/sudoers -F perm=wa -F key=special-config-changes --a always,exit -F dir=/etc/sudoers.d/ -F perm=wa -F key=special-config-changes +-a always,exit -F arch=b32 -F path=/etc/sudoers -F perm=wa -F key=special-config-changes +-a always,exit -F arch=b64 -F path=/etc/sudoers -F perm=wa -F key=special-config-changes +-a always,exit -F arch=b32 -F dir=/etc/sudoers.d/ -F perm=wa -F key=special-config-changes +-a always,exit -F arch=b64 -F dir=/etc/sudoers.d/ -F perm=wa -F key=special-config-changes ## Audit log access --a always,exit -F dir=/var/log/audit/ -F perm=r -F auid>=1000 -F auid!=unset -F key=access-audit-trail +-a always,exit -F arch=b32 -F dir=/var/log/audit/ -F perm=r -F auid>=1000 -F auid!=unset -F key=access-audit-trail +-a always,exit -F arch=b64 -F dir=/var/log/audit/ -F perm=r -F auid>=1000 -F auid!=unset -F key=access-audit-trail ## Attempts to Alter Process and Session Initiation Information --a always,exit -F path=/var/run/utmp -F perm=wa -F auid>=1000 -F auid!=unset -F key=session --a always,exit -F path=/var/log/btmp -F perm=wa -F auid>=1000 -F auid!=unset -F key=session --a always,exit -F path=/var/log/wtmp -F perm=wa -F auid>=1000 -F auid!=unset -F key=session +-a always,exit -F arch=b32 -F path=/var/run/utmp -F perm=wa -F auid>=1000 -F auid!=unset -F key=session +-a always,exit -F arch=b64 -F path=/var/run/utmp -F perm=wa -F auid>=1000 -F auid!=unset -F key=session +-a always,exit -F arch=b32 -F path=/var/log/btmp -F perm=wa -F auid>=1000 -F auid!=unset -F key=session +-a always,exit -F arch=b64 -F path=/var/log/btmp -F perm=wa -F auid>=1000 -F auid!=unset -F key=session +-a always,exit -F arch=b32 -F path=/var/log/wtmp -F perm=wa -F auid>=1000 -F auid!=unset -F key=session +-a always,exit -F arch=b64 -F path=/var/log/wtmp -F perm=wa -F auid>=1000 -F auid!=unset -F key=session ## Attempts to modify MAC controls --a always,exit -F dir=/etc/selinux/ -F perm=wa -F auid>=1000 -F auid!=unset -F key=MAC-policy +-a always,exit -F arch=b32 -F dir=/etc/selinux/ -F perm=wa -F auid>=1000 -F auid!=unset -F key=MAC-policy +-a always,exit -F arch=b64 -F dir=/etc/selinux/ -F perm=wa -F auid>=1000 -F auid!=unset -F key=MAC-policy ## Software updates. This is entirely handled by rpm. @@ -217823,17047 +234410,20402 @@ which the system will be deployed as closely as possible. ## state results from that policy. This would be handled entirely by ## that daemon. - - - - ## Unsuccessful ownership change + + + + ## Unsuccessful ownership change -a always,exit -F arch=b32 -S lchown,fchown,chown,fchownat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-owner-change -a always,exit -F arch=b64 -S lchown,fchown,chown,fchownat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-owner-change -a always,exit -F arch=b32 -S lchown,fchown,chown,fchownat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-owner-change -a always,exit -F arch=b64 -S lchown,fchown,chown,fchownat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-owner-change - - - - ## Successful ownership change + + + + ## Successful ownership change -a always,exit -F arch=b32 -S lchown,fchown,chown,fchownat -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-owner-change -a always,exit -F arch=b64 -S lchown,fchown,chown,fchownat -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-owner-change - - - - ## Unsuccessful permission change + + + + ## Unsuccessful permission change -a always,exit -F arch=b32 -S chmod,fchmod,fchmodat,setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-perm-change -a always,exit -F arch=b64 -S chmod,fchmod,fchmodat,setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-perm-change -a always,exit -F arch=b32 -S chmod,fchmod,fchmodat,setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-perm-change -a always,exit -F arch=b64 -S chmod,fchmod,fchmodat,setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-perm-change - - - - ## Successful permission change + + + + ## Successful permission change -a always,exit -F arch=b32 -S chmod,fchmod,fchmodat,setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-perm-change -a always,exit -F arch=b64 -S chmod,fchmod,fchmodat,setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-perm-change - - - - ^(?i)50(?-i)$ - - - ^(?i)yes(?-i)$ - - - ^(?i)ENRICHED(?-i)$ - - - ^(?i)yes(?-i)$ - - - ^'lock-screen'$ - - - 0 - - - 0 - - - 0 - - - 0 - - - symbolic link - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - symbolic link - - - 0 - - - 0 - - - 0 - - - 0 - - - symbolic link - - - false - false - false - false - false - - - false - false - false - false - false - - - false - false - false - false - false - - - false - false - false - false - false - - - false - false - false - false - false - - - false - false - false - false - false - - - symbolic link - - - false - false - - - false - false - - - false - false - - - false - false - - - symbolic link - - - ^no$ - - - ^no$ - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - symbolic link - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - symbolic link - - - false - false - false - false - false - - - false - false - false - false - false - - - false - false - false - false - false - - - false - false - false - false - false - - - false - false - false - false - false - - - false - false - false - false - false - - - false - false - false - false - false - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 4 - - - symbolic link - - - 0 - - - 0 - - - symbolic link - - - - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 104 - - - symbolic link - - - 0 - - - 0 - - - symbolic link - - - 0 - - - 0 - - - 0 - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - false - false - false - false - false - false - false - false - false - - - false - false - false - false - false - false - false - false - false - - - symbolic link - - - false - false - false - false - false - false - false - false - - - symbolic link - - - false - false - false - false - false - false - false - false - false - false - false - false - - - symbolic link - - - false - false - false - false - false - false - false - false - - - symbolic link - - - false - false - false - false - false - false - false - false - false - false - false - false - - - symbolic link - - - false - false - false - false - false - false - false - false - false - - - symbolic link - - - false - false - false - false - false - false - false - false - false - - - symbolic link - - - false - false - false - false - false - false - false - false - false - - - symbolic link - - - false - false - false - false - false - false - false - false - false - - - symbolic link - - - false - false - false - false - false - false - false - false - false - - - symbolic link - - - false - false - false - false - false - false - false - false - false - - - symbolic link - - - false - false - false - false - false - false - false - false - false - false - - - symbolic link - - - false - false - false - false - false - false - false - false - false - - - symbolic link - - - false - false - false - false - false - false - false - false - false - - - symbolic link - - - false - false - false - false - false - false - false - false - - - symbolic link - - - false - false - false - false - false - false - false - false - false - false - false - false - - - symbolic link - - - false - false - false - false - false - false - false - false - - - symbolic link - - - false - false - false - false - false - false - false - false - false - false - false - false - - - symbolic link - - - false - false - - - false - false - - - false - false - - - false - false - - - symbolic link - - - false - false - false - false - false - false - false - false - false - false - - - symbolic link - - - false - false - false - false - false - false - false - false - - - symbolic link - - - false - false - false - false - false - - - symbolic link - - - false - false - false - false - false - false - false - false - false - - - symbolic link - - - false - false - false - false - false - false - false - false - false - - - symbolic link - - - ^nftables$ - - - .*rescue\.conf$ - - - ^(?:.*\s)?audit=1(?:\s.*)?$ - - - .*rescue\.conf$ - - - ^(?:.*\s)?audit_backlog_limit=8192(?:\s.*)?$ - - - .*rescue\.conf$ - - - ^(?:.*\s)?iommu=force(?:\s.*)?$ - - - .*rescue\.conf$ - - - ^(?:.*\s)?init_on_alloc=1(?:\s.*)?$ - - - .*rescue\.conf$ - - - - - - .*rescue\.conf$ - - - ^(?:.*\s)?mce=0(?:\s.*)?$ - - - .*rescue\.conf$ - - - .*rescue\.conf$ - - - .*rescue\.conf$ - - - ^(?:.*\s)?page_alloc\.shuffle=1(?:\s.*)?$ - - - .*rescue\.conf$ - - - ^(?:.*\s)?page_poison=1(?:\s.*)?$ - - - .*rescue\.conf$ - - - ^(?:.*\s)?pti=on(?:\s.*)?$ - - - .*rescue\.conf$ - - - - - - .*rescue\.conf$ - - - ^(?:.*\s)?slab_nomerge=yes(?:\s.*)?$ - - - .*rescue\.conf$ - - - - - - .*rescue\.conf$ - - - - - - .*rescue\.conf$ - - - ^(?:.*\s)?spectre_v2=on(?:\s.*)?$ - - - .*rescue\.conf$ - - - .*rescue\.conf$ - - - ^(?:.*\s)?vsyscall=none(?:\s.*)?$ - - - n - - - - - - n - - - - - - y - - - - - - n - - - - - - n - - - - - - y - - - - - - n - - - - - - y - - - - - - y - - - - - - y - - - - - - 65536 - - - - - - n - - - - - - n - - - - - - n - - - - - - n - - - - - - n - - - - - - n - - - - - - y - - - - - - y - - - - - - y - - - - - - - - - - - - - - - - - - y - - - - - - y - - - - - - y - - - - - - y - - - - - - y - - - - - - - - - - - - n - - - - - - y - - - - - - y - - - - - - y - - - - - - y - - - - - - y - - - - - - y - - - - - - n - - - - - - y - - - - - - y - - - - - - y - - - - - - y - - - - - - y - - - - - - n - - - - - - nodev - - - 1 - nodev - - - noexec - - - 1 - noexec - - - nosuid - - - 1 - nosuid - - - nodev - - - 1 - nodev - - - noexec - - - 1 - noexec - - - nosuid - - - 1 - nosuid - - - grpquota - - - nodev - - - 1 - nodev - - - noexec - - - nosuid - - - usrquota - - - ^.*sec=krb5:krb5i:krb5p.*$ - - - ^.*nodev.*$ - - - ^.*,?nodev,?.*$ - - - ^.*,?nodev,?.* - - - ^.*noexec.*$ - - - ^.*,?noexec,?.*$ - - - ^.*,?noexec,?.* - - - ^.*nosuid.*$ - - - ^.*,?nosuid,?.*$ - - - ^.*,?nosuid,?.* - - - nosuid - - - 1 - nosuid - - - nosuid - - - 1 - nosuid - - - nodev - - - 1 - nodev - - - noexec - - - 1 - noexec - - - nosuid - - - 1 - nosuid - - - nodev - - - 1 - nodev - - - noexec - - - 1 - noexec - - - nosuid - - - 1 - nosuid - - - nodev - - - 1 - nodev - - - noexec - - - 1 - noexec - - - nosuid - - - 1 - nosuid - - - nodev - - - 1 - nodev - - - noexec - - - 1 - noexec - - - nosuid - - - 1 - nosuid - - - nodev - - - 1 - nodev - - - noexec - - - 1 - noexec - - - nosuid - - - 1 - nosuid - - - 0 - - - 0 - - - 0 - - - 0 - - - symbolic link - - - (?:file="[^\s;]+"|\$IncludeConfig[\s]+[^\s;]+|\/dev\/.*) - - - regular - 0 - - - (?:file="[^\s;]+"|\$IncludeConfig[\s]+[^\s;]+|\/dev\/.*) - - - regular - 0 - - - (?:file="[^\s;]+"|\$IncludeConfig[\s]+[^\s;]+|\/dev\/.*) - - - regular - false - false - false - false - false - false - false - false - false - - - deny_execmem - - - - - polyinstantiation_enabled - - - - - secure_mode_insmod - - - - - selinuxuser_execheap - - - - - selinuxuser_execmod - - - - - selinuxuser_execstack - - - - - ssh_sysadm_login - - - - - inactive|failed - - - masked - - - inactive|failed - - - masked - - - auditd.service - - - auditd.socket - - - active - - - inactive|failed - - - masked - - - inactive|failed - - - masked - - - chronyd.service - - - chronyd.socket - - - active - - - cron.service - - - cron.socket - - - active - - - crond.service - - - crond.socket - - - active - - - inactive|failed - - - masked - - - fapolicyd.service - - - fapolicyd.socket - - - active - - - firewalld.service - - - firewalld.socket - - - active - - - ip6tables.service - - - ip6tables.socket - - - active - - - iptables.service - - - iptables.socket - - - active - - - inactive|failed - - - masked - - - inactive|failed - - - masked - - - ntp.service - - - ntp.socket - - - active - - - ntpd.service - - - ntpd.socket - - - active - - - inactive|failed - - - masked - - - inactive|failed - - - masked - - - pcscd.service - - - pcscd.socket - - - active - - - postfix.service - - - postfix.socket - - - active - - - inactive|failed - - - masked - - - inactive|failed - - - masked - - - inactive|failed - - - masked - - - rngd.service - - - rngd.socket - - - active - - - rsyslog.service - - - rsyslog.socket - - - active - - - inactive|failed - - - masked - - - inactive|failed - - - masked - - - sshd.service - - - sshd.socket - - - active - - - inactive|failed - - - masked - - - syslog-ng.service - - - syslog-ng.socket - - - active - - - masked - - - systemd-journald.service - - - systemd-journald.socket - - - active - - - inactive|failed - - - masked - - - ufw.service - - - ufw.socket - - - active - - - usbguard.service - - - usbguard.socket - - - active - - - inactive|failed - - - masked - - - ^no$ - - - ^no$ - - - ^no$ - - - ^no$ - - - ^no$ - - - ^no$ - - - ^no$ - - - ^no$ - - - ^yes$ - - - ^yes$ - - - ^no$ - - - ^no$ - - - ^prohibit-password$ - - - ^prohibit-password$ - - - ^no$ - - - ^no$ - - - ^yes$ - - - ^yes$ - - - ^no$ - - - ^no$ - - - ^no$ - - - ^no$ - - - ^yes$ - - - ^yes$ - - - ^yes$ - - - ^yes$ - - - ^yes$ - - - ^yes$ - - - ^yes$ - - - ^yes$ - - - ^/etc/issue$ - - - ^/etc/issue$ - - - ^/etc/issue.net$ - - - ^/etc/issue.net$ - - - ^yes$ - - - ^yes$ - - - ^yes$ - - - ^yes$ - - - ^0$ - - - ^0$ - - - ^INFO$ - - - ^INFO$ - - - ^VERBOSE$ - - - ^VERBOSE$ - - - ^yes$ - - - ^yes$ - - - - - - 1 - - - 1 - - - 1 - - - 1 - - - 0 - - - 0 - - - |/bin/false - - - |/bin/false - - - 0 - - - 0 - - - 1 - - - 1 - - - 1 - - - 1 - - - 1 - - - 2 - - - 1 - - - 2 - - - 1 - - - 1 - - - 1 - - - 1 - - - 1 - - - 1 - - - 1 - - - 1 - - - 2 - - - 2 - - - 65536 - - - 65536 - - - 2 - - - 2 - - - 0 - - - 0 - - - 1 - - - 1 - - - 1 - - - 1 - - - 2 - - - 2 - - - 0 - - - 0 - - - - - - - - - - - - - - - - - - - - - - - - - - - 1 - - - 1 - - - - - - - - - 0 - - - 0 - - - 1 - - - 2 - - - 1 - - - 2 - - - - - - - - - 0 - - - 0 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 0 - - - 0 - - - - - - - - - - - - - - - - - - - - - 0 - - - 0 - - - 32768\s*65535 - - - 32768\s*65535 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1 - - - 1 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1 - - - 1 - - - - - - - - - - - - - - - 0 - - - 0 - - - 65536 - - - 65536 - - - dnf-automatic.timer - - - active - - - logrotate.timer - - - active - - - ^(true|"true")$ - - - ^23.*$ - - - ^7.*$ - - - centos - - - 8 - - - centos - - - 9 - - - ol - - - ^7.*$ - - - ^8.*$ - - - ^9.*$ - - - openSUSE-release - - - unix - - - rhcos - - - 4 - - - 9 - - - rhel - - - unix - - - ^7.*$ - - - ^7.*$ - - - ^7.*$ - - - ^7.*$ - - - 7 - - - unix - - - ^8.*$ - - - ^8.0*$ - - - ^8.1*$ - - - ^8.2*$ - - - ^8.3*$ - - - ^8.4*$ - - - ^8.5*$ - - - ^8.6*$ - - - ^8.7*$ - - - ^8.8*$ - - - ^8.9*$ - - - ^8.10*$ - - - 8 - - - unix - - - ^9.*$ - - - 9 - - - 0:4.4 - - - ^7.*$ - - - unix - - - ^12.*$ - - - ^12.*$ - - - ^12.*$ - - - unix - - - ^15.*$ - - - ^15.*$ - - - ^15.*$ - - - ^4.*$ - - - ^15.*$ - - - bwrap-osbuild - - - 1 - - - 2 - - - 0 - - - 0:7.4 - - - aarch64 - - - ppc64 - - - ppc64le - - - s390x - - - i686 - - - x86_64 - - - true - - - /dev/cdrom - - - - - - - - - - - - - ^[\s]*RekeyLimit[\s]+ - - [\s]+ - - [\s]*$ - - - - - - - - - - - - - - - - ^(dmz|external|home|internal|public|trusted|work)\.xml$ - - - - - - - - - - - - - - - - ^ - - [\s]+ - - [\s]*$ - - - - - - - - - - - - - - - - - - ^[\s]*auth[\s]+(?:required|requisite)[\s]+pam_faillock.so[^\n#]preauth[^\n#]*audit - - - - - ^\s*password\s+(?: - - )\s+pam_pwhistory\.so.*$ - - - - - - - - - - ^\s*password\b.*\bpam_pwhistory\.so\b.*\bremember=([0-9]*).*$ - - - ^\s*remember\s*=\s*([0-9]+) - - - - ^\s*password\s+(?: - - )\s+pam_pwhistory\.so.*$ - - - - - - - - - ^\s*password\b.*\bpam_pwhistory\.so\b.*\bremember=([0-9]*).*$ - - - ^\s*remember\s*=\s*([0-9]+) - - - - ^\s*password\s+(?:(?:requisite)|(?:required))\s+pam_pwhistory\.so.*$ - - - ^\s*password\b.*\bpam_pwhistory\.so\b.*\bremember=([0-9]*).*$ - - - ^\s*remember\s*=\s*([0-9]+) - - - ^[\s]*auth[\s]+(?:required|requisite)[\s]+pam_faillock.so[^\n#]preauth[^\n#]*audit - - - ^[\s]*auth\N+pam_unix\.so - - - ^[\s]*auth[\s]+(required|\[(?=.*?\bsuccess=ok\b)(?=.*?\bnew_authtok_reqd=ok\b)(?=.*?\bignore=ignore\b)(?=.*?\bdefault=bad\b).*\])[\s]+pam_faillock\.so[\s\w\d=]+preauth[\s\S]*^[\s]*auth[\s]+(sufficient|\[(?=.*\bsuccess=done\b)(?=.*?\bnew_authtok_reqd=done\b)(?=.*?\bdefault=ignore\b).*\])[\s]+pam_unix\.so[\s\S]*^[\s]*auth[\s]+(required|\[(?=.*?\bsuccess=ok\b)(?=.*?\bnew_authtok_reqd=ok\b)(?=.*?\bignore=ignore\b)(?=.*?\bdefault=bad\b).*\])[\s]+pam_faillock\.so[\s\w\d=]+authfail - - - ^[\s]*account[\s]+(required|\[(?=.*?\bsuccess=ok\b)(?=.*?\bnew_authtok_reqd=ok\b)(?=.*?\bignore=ignore\b)(?=.*?\bdefault=bad\b).*\])[\s]+pam_faillock\.so[\s\S]*^[\s]*account[\s]+(required|\[(?=.*?\bsuccess=ok\b)(?=.*?\bnew_authtok_reqd=ok\b)(?=.*?\bignore=ignore\b)(?=.*?\bdefault=bad\b).*\])[\s]+pam_unix\.so - - - ^[\s]*auth[\s]+.+[\s]+pam_faillock.so[\s]+[^\n]*deny=([0-9]+) - - - ^[\s]*deny[\s]*=[\s]*([0-9]+) - - - - ^[\s]*auth\N+pam_unix\.so - - - ^[\s]*auth[\s]+(required|\[(?=.*?\bsuccess=ok\b)(?=.*?\bnew_authtok_reqd=ok\b)(?=.*?\bignore=ignore\b)(?=.*?\bdefault=bad\b).*\])[\s]+pam_faillock\.so[\s\w\d=]+preauth[\s\S]*^[\s]*auth[\s]+(sufficient|\[(?=.*\bsuccess=done\b)(?=.*?\bnew_authtok_reqd=done\b)(?=.*?\bdefault=ignore\b).*\])[\s]+pam_unix\.so[\s\S]*^[\s]*auth[\s]+(required|\[(?=.*?\bsuccess=ok\b)(?=.*?\bnew_authtok_reqd=ok\b)(?=.*?\bignore=ignore\b)(?=.*?\bdefault=bad\b).*\])[\s]+pam_faillock\.so[\s\w\d=]+authfail - - - ^[\s]*account[\s]+(required|\[(?=.*?\bsuccess=ok\b)(?=.*?\bnew_authtok_reqd=ok\b)(?=.*?\bignore=ignore\b)(?=.*?\bdefault=bad\b).*\])[\s]+pam_faillock\.so[\s\S]*^[\s]*account[\s]+(required|\[(?=.*?\bsuccess=ok\b)(?=.*?\bnew_authtok_reqd=ok\b)(?=.*?\bignore=ignore\b)(?=.*?\bdefault=bad\b).*\])[\s]+pam_unix\.so - - - ^[\s]*auth[\s]+.+[\s]+pam_faillock.so[\s]+[^\n]*even_deny_root - - - ^[\s]*even_deny_root - - - dir\s*=\s*(\S+|"[^"]+) - - - - ^[\s]*auth[\s]+(?:required|requisite) - [\s]+pam_faillock.so[^\n#]* - - - - - - ^[\s]* - - - - - - - - - - - - - - - - - - - - - - - ^[\s]*auth\N+pam_unix\.so - - - ^[\s]*auth[\s]+(required|\[(?=.*?\bsuccess=ok\b)(?=.*?\bnew_authtok_reqd=ok\b)(?=.*?\bignore=ignore\b)(?=.*?\bdefault=bad\b).*\])[\s]+pam_faillock\.so[\s\w\d=]+preauth[\s\S]*^[\s]*auth[\s]+(sufficient|\[(?=.*\bsuccess=done\b)(?=.*?\bnew_authtok_reqd=done\b)(?=.*?\bdefault=ignore\b).*\])[\s]+pam_unix\.so[\s\S]*^[\s]*auth[\s]+(required|\[(?=.*?\bsuccess=ok\b)(?=.*?\bnew_authtok_reqd=ok\b)(?=.*?\bignore=ignore\b)(?=.*?\bdefault=bad\b).*\])[\s]+pam_faillock\.so[\s\w\d=]+authfail - - - ^[\s]*account[\s]+(required|\[(?=.*?\bsuccess=ok\b)(?=.*?\bnew_authtok_reqd=ok\b)(?=.*?\bignore=ignore\b)(?=.*?\bdefault=bad\b).*\])[\s]+pam_faillock\.so[\s\S]*^[\s]*account[\s]+(required|\[(?=.*?\bsuccess=ok\b)(?=.*?\bnew_authtok_reqd=ok\b)(?=.*?\bignore=ignore\b)(?=.*?\bdefault=bad\b).*\])[\s]+pam_unix\.so - - - ^[\s]*auth[\s]+.+[\s]+pam_faillock.so[\s]+[^\n]*fail_interval=([0-9]+) - - - ^[\s]*fail_interval[\s]*=[\s]*([0-9]+) - - - - ^[\s]*auth\N+pam_unix\.so - - - ^[\s]*auth[\s]+(required|\[(?=.*?\bsuccess=ok\b)(?=.*?\bnew_authtok_reqd=ok\b)(?=.*?\bignore=ignore\b)(?=.*?\bdefault=bad\b).*\])[\s]+pam_faillock\.so[\s\w\d=]+preauth[\s\S]*^[\s]*auth[\s]+(sufficient|\[(?=.*\bsuccess=done\b)(?=.*?\bnew_authtok_reqd=done\b)(?=.*?\bdefault=ignore\b).*\])[\s]+pam_unix\.so[\s\S]*^[\s]*auth[\s]+(required|\[(?=.*?\bsuccess=ok\b)(?=.*?\bnew_authtok_reqd=ok\b)(?=.*?\bignore=ignore\b)(?=.*?\bdefault=bad\b).*\])[\s]+pam_faillock\.so[\s\w\d=]+authfail - - - ^[\s]*account[\s]+(required|\[(?=.*?\bsuccess=ok\b)(?=.*?\bnew_authtok_reqd=ok\b)(?=.*?\bignore=ignore\b)(?=.*?\bdefault=bad\b).*\])[\s]+pam_faillock\.so[\s\S]*^[\s]*account[\s]+(required|\[(?=.*?\bsuccess=ok\b)(?=.*?\bnew_authtok_reqd=ok\b)(?=.*?\bignore=ignore\b)(?=.*?\bdefault=bad\b).*\])[\s]+pam_unix\.so - - - ^[\s]*auth[\s]+.+[\s]+pam_faillock.so[\s]+[^\n]*unlock_time=([0-9]+) - - - ^[\s]*unlock_time[\s]*=[\s]*([0-9]+) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 86400 - - - - - - - - - 5000 - - - - 5000 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ^[^#]* - - - - - - - - - ^(?: - - ):(?:[^:]*:){4}([^:]+):[^:]*$ - - - - - - - - - - - - - - - - - - ^(?: - - ):(?:[^:]*:){4}([^:]+):[^:]*$ - - - - - ^(?: - - :)(?:[^:]*:){2}([^:]+):(?:[^:]*:){2}[^:]*$ - - - - - - - - - - - - - - ^(?: - - ):(?:[^:]*:){4}([^:]+):[^:]*$ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 64 - - - - 8 - - - - - - - - - - - - - - - - - - - - - - - - 64 - - - - 8 - - - - - - - - - - - - - - - - - - - - - - - - 64 - - - - 8 - - - - - - - - - - - - - - - - - - - - - - - - 64 - - - - 8 - - - - - - - - ^(?: - - ):(?:[^:]*:){4}([^:]+):[^:]*$ - - - - - - - - ^[\s]*-a[\s]+always,exit[\s]+(?:-F[\s]+dir=/var/log/audit/)[\s]+(?:-F[\s]+perm=r)[\s]+(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295)[\s]+)(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - - - - - - - - - - - - - - - - - - - - - - - - - - - ^[\s]*-a always,exit (?:-F path=([\S]+))+(?: -F perm=x)? -F auid>=1000 -F auid!=(?:4294967295|unset)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - - - - - - - - - - - - - - (?i) - - - - - - - (?i) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Ciphers - - - - - - - -oCiphers= - - - - - - MACs - - - - - - - -oMACs= - - - - - - - / - - - - - - - - - - - - - - - ^[\s]*-a[\s]+always,exit[\s]+(?:-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+creat[\s]+|([\s]+|[,])creat([\s]+|[,])))(?:(?!-F[\s]+a\d&).)* - - - ^[\s]*-a[\s]+always,exit[\s]+(?:-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+creat[\s]+|([\s]+|[,])creat([\s]+|[,])))(?:(?!-F[\s]+a\d&).)* - - - [\s]+(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295)[\s]+)(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - - - - - (?:-F\s+exit=-EACCES) - - - - - - - (?:-F\s+exit=-EPERM) - - - - - - - (?:-F\s+exit=-EACCES) - - - - - - - (?:-F\s+exit=-EPERM) - - - - - ^[\s]*-a[\s]+always,exit[\s]+(?:-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+ftruncate[\s]+|([\s]+|[,])ftruncate([\s]+|[,])))(?:(?!-F[\s]+a\d&).)* - - - ^[\s]*-a[\s]+always,exit[\s]+(?:-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+ftruncate[\s]+|([\s]+|[,])ftruncate([\s]+|[,])))(?:(?!-F[\s]+a\d&).)* - - - [\s]+(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295)[\s]+)(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - - - - - (?:-F\s+exit=-EACCES) - - - - - - - (?:-F\s+exit=-EPERM) - - - - - - - (?:-F\s+exit=-EACCES) - - - - - - - (?:-F\s+exit=-EPERM) - - - - - ^[\s]*-a[\s]+always,exit[\s]+(?:-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+open[\s]+|([\s]+|[,])open([\s]+|[,])))(?:(?!-F[\s]+a\d&).)* - - - ^[\s]*-a[\s]+always,exit[\s]+(?:-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+open[\s]+|([\s]+|[,])open([\s]+|[,])))(?:(?!-F[\s]+a\d&).)* - - - [\s]+(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295)[\s]+)(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - - - - - (?:-F\s+exit=-EACCES) - - - - - - - (?:-F\s+exit=-EPERM) - - - - - - - (?:-F\s+exit=-EACCES) - - - - - - - (?:-F\s+exit=-EPERM) - - - - - ^[\s]*-a[\s]+always,exit[\s]+(?:-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+open_by_handle_at[\s]+|([\s]+|[,])open_by_handle_at([\s]+|[,])))(?:(?!-F[\s]+a\d&).)* - - - ^[\s]*-a[\s]+always,exit[\s]+(?:-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+open_by_handle_at[\s]+|([\s]+|[,])open_by_handle_at([\s]+|[,])))(?:(?!-F[\s]+a\d&).)* - - - [\s]+(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295)[\s]+)(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - - - - - (?:-F\s+exit=-EACCES) - - - - - - - (?:-F\s+exit=-EPERM) - - - - - - - (?:-F\s+exit=-EACCES) - - - - - - - (?:-F\s+exit=-EPERM) - - - - - ^[\s]*-a[\s]+always,exit[\s]+(?:-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+openat[\s]+|([\s]+|[,])openat([\s]+|[,])))(?:(?!-F[\s]+a\d&).)* - - - ^[\s]*-a[\s]+always,exit[\s]+(?:-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+openat[\s]+|([\s]+|[,])openat([\s]+|[,])))(?:(?!-F[\s]+a\d&).)* - - - [\s]+(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295)[\s]+)(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - - - - - (?:-F\s+exit=-EACCES) - - - - - - - (?:-F\s+exit=-EPERM) - - - - - - - (?:-F\s+exit=-EACCES) - - - - - - - (?:-F\s+exit=-EPERM) - - - - - ^[\s]*-a[\s]+always,exit[\s]+(?:-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+rename[\s]+|([\s]+|[,])rename([\s]+|[,])))(?:(?!-F[\s]+a\d&).)* - - - ^[\s]*-a[\s]+always,exit[\s]+(?:-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+rename[\s]+|([\s]+|[,])rename([\s]+|[,])))(?:(?!-F[\s]+a\d&).)* - - - [\s]+(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295)[\s]+)(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - - - - - (?:-F\s+exit=-EACCES) - - - - - - - (?:-F\s+exit=-EPERM) - - - - - - - (?:-F\s+exit=-EACCES) - - - - - - - (?:-F\s+exit=-EPERM) - - - - - ^[\s]*-a[\s]+always,exit[\s]+(?:-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+renameat[\s]+|([\s]+|[,])renameat([\s]+|[,])))(?:(?!-F[\s]+a\d&).)* - - - ^[\s]*-a[\s]+always,exit[\s]+(?:-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+renameat[\s]+|([\s]+|[,])renameat([\s]+|[,])))(?:(?!-F[\s]+a\d&).)* - - - [\s]+(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295)[\s]+)(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - - - - - (?:-F\s+exit=-EACCES) - - - - - - - (?:-F\s+exit=-EPERM) - - - - - - - (?:-F\s+exit=-EACCES) - - - - - - - (?:-F\s+exit=-EPERM) - - - - - ^[\s]*-a[\s]+always,exit[\s]+(?:-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+truncate[\s]+|([\s]+|[,])truncate([\s]+|[,])))(?:(?!-F[\s]+a\d&).)* - - - ^[\s]*-a[\s]+always,exit[\s]+(?:-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+truncate[\s]+|([\s]+|[,])truncate([\s]+|[,])))(?:(?!-F[\s]+a\d&).)* - - - [\s]+(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295)[\s]+)(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - - - - - (?:-F\s+exit=-EACCES) - - - - - - - (?:-F\s+exit=-EPERM) - - - - - - - (?:-F\s+exit=-EACCES) - - - - - - - (?:-F\s+exit=-EPERM) - - - - - ^[\s]*-a[\s]+always,exit[\s]+(?:-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+unlink[\s]+|([\s]+|[,])unlink([\s]+|[,])))(?:(?!-F[\s]+a\d&).)* - - - ^[\s]*-a[\s]+always,exit[\s]+(?:-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+unlink[\s]+|([\s]+|[,])unlink([\s]+|[,])))(?:(?!-F[\s]+a\d&).)* - - - [\s]+(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295)[\s]+)(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - - - - - (?:-F\s+exit=-EACCES) - - - - - - - (?:-F\s+exit=-EPERM) - - - - - - - (?:-F\s+exit=-EACCES) - - - - - - - (?:-F\s+exit=-EPERM) - - - - - ^[\s]*-a[\s]+always,exit[\s]+(?:-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+unlinkat[\s]+|([\s]+|[,])unlinkat([\s]+|[,])))(?:(?!-F[\s]+a\d&).)* - - - ^[\s]*-a[\s]+always,exit[\s]+(?:-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+unlinkat[\s]+|([\s]+|[,])unlinkat([\s]+|[,])))(?:(?!-F[\s]+a\d&).)* - - - [\s]+(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295)[\s]+)(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - - - - - (?:-F\s+exit=-EACCES) - - - - - - - (?:-F\s+exit=-EPERM) - - - - - - - (?:-F\s+exit=-EACCES) - - - - - - - (?:-F\s+exit=-EPERM) - - - - - - ^(/etc/ssh/(?!/))? - - - - - - - - - - - - - - - ^(?:.*\s)?l1tf= - - (?:\s.*)?$ - - - - - - ^(?:.*\s)?rng_core.default_quality= - - (?:\s.*)?$ - - - - - - ^(?:.*\s)?slub_debug= - - (?:\s.*)?$ - - - - - - ^(?:.*\s)?spec_store_bypass_disable= - - (?:\s.*)?$ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /etc/modprobe.d - /etc/modules-load.d - /run/modprobe.d - /run/modules-load.d - /usr/lib/modprobe.d - /usr/lib/modules-load.d - - - /etc/modprobe.d - /etc/modules-load.d - /run/modprobe.d - /run/modules-load.d - /usr/lib/modprobe.d - /usr/lib/modules-load.d - - - /etc/modprobe.d - /etc/modules-load.d - /run/modprobe.d - /run/modules-load.d - /usr/lib/modprobe.d - /usr/lib/modules-load.d - - - /etc/modprobe.d - /etc/modules-load.d - /run/modprobe.d - /run/modules-load.d - /usr/lib/modprobe.d - /usr/lib/modules-load.d - - - /etc/modprobe.d - /etc/modules-load.d - /run/modprobe.d - /run/modules-load.d - /usr/lib/modprobe.d - /usr/lib/modules-load.d - - - /etc/modprobe.d - /etc/modules-load.d - /run/modprobe.d - /run/modules-load.d - /usr/lib/modprobe.d - /usr/lib/modules-load.d - - - /etc/modprobe.d - /etc/modules-load.d - /run/modprobe.d - /run/modules-load.d - /usr/lib/modprobe.d - /usr/lib/modules-load.d - - - /etc/modprobe.d - /etc/modules-load.d - /run/modprobe.d - /run/modules-load.d - /usr/lib/modprobe.d - /usr/lib/modules-load.d - - - /etc/modprobe.d - /etc/modules-load.d - /run/modprobe.d - /run/modules-load.d - /usr/lib/modprobe.d - /usr/lib/modules-load.d - - - /etc/modprobe.d - /etc/modules-load.d - /run/modprobe.d - /run/modules-load.d - /usr/lib/modprobe.d - /usr/lib/modules-load.d - - - - ^(?:(?!nobody).*)?:.*?:[1-9]\d{3,}:.*?:.*?:( - - ).*?:.* - - - - - - - - ^(?:(?!nobody).*)?:.*?:[1-9]\d{3,}:.*?:.*?:( - - ).*?:.* - - - - - - - - ^(?:(?!nobody).*)?:.*?:[1-9]\d{3,}:.*?:.*?:( - - ).*?:.* - - - - - - - - ^(?:(?!nobody).*)?:.*?:[1-9]\d{3,}:.*?:.*?:( - - ).*?:.* - - - - - - - /dev/cdrom - /dev/dvd - /dev/scd0 - /dev/sr0 - - - - ^[\s]* - - [\s]+[/\w]+[\s]+[\w]+[\s]+([^\s]+)(?:[\s]+[\d]+){2}$ - - - - - ^[\s]* - - [\s]+[/\w]+[\s]+[\w]+[\s]+([^\s]+)(?:[\s]+[\d]+){2}$ - - - - - /dev/cdrom - /dev/dvd - /dev/scd0 - /dev/sr0 - - - - ^[\s]* - - [\s]+[/\w]+[\s]+[\w]+[\s]+([^\s]+)(?:[\s]+[\d]+){2}$ - - - - - ^[\s]* - - [\s]+[/\w]+[\s]+[\w]+[\s]+([^\s]+)(?:[\s]+[\d]+){2}$ - - - - /dev/cdrom - /dev/dvd - /dev/scd0 - /dev/sr0 - - - - ^[\s]* - - [\s]+[/\w]+[\s]+[\w]+[\s]+([^\s]+)(?:[\s]+[\d]+){2}$ - - - - - ^[\s]* - - [\s]+[/\w]+[\s]+[\w]+[\s]+([^\s]+)(?:[\s]+[\d]+){2}$ - - - - - - - - - - - ^/etc/rsyslog.conf$ - - - - - - - - - - - - - - - - ^/etc/rsyslog.conf$ - - - - - - - - - - - - - - - - ^/etc/rsyslog.conf$ - - - - - - - - - - - - - - - - - ^(/etc/ssh/(?!/))? - - - - - - - - - - - - ^(/etc/ssh/(?!/))? - - - - - - - - - - - - ^(/etc/ssh/(?!/))? - - - - - - - - - - - - ^(/etc/ssh/(?!/))? - - - - - - - - - - - - ^(/etc/ssh/(?!/))? - - - - - - - - - - - - ^(/etc/ssh/(?!/))? - - - - - - - - - - - - ^(/etc/ssh/(?!/))? - - - - - - - - - - - - ^(/etc/ssh/(?!/))? - - - - - - - - - - - - ^(/etc/ssh/(?!/))? - - - - - - - - - - - - ^(/etc/ssh/(?!/))? - - - - - - - - - - - - ^(/etc/ssh/(?!/))? - - - - - - - - - - - - ^(/etc/ssh/(?!/))? - - - - - - - - - - - - ^(/etc/ssh/(?!/))? - - - - - - - - - - - - ^(/etc/ssh/(?!/))? - - - - - - - - - - - - ^(/etc/ssh/(?!/))? - - - - - - - - - - - - ^(/etc/ssh/(?!/))? - - - - - - - - - - - - ^(/etc/ssh/(?!/))? - - - - - - - - - - - - ^(/etc/ssh/(?!/))? - - - - - - - - - - - - ^(/etc/ssh/(?!/))? - - - - - - - - - - - - ^(/etc/ssh/(?!/))? - - - - - - - - - - - - ^(/etc/ssh/(?!/))? - - - - - - - - - - - - ^(/etc/ssh/(?!/))? - - - - - - - - - - - - ^(/etc/ssh/(?!/))? - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /etc/pam.d/system-auth - - - - - - - - /dev/cdrom - /dev/dvd - /dev/scd0 - /dev/sr0 - - - - - - - - - - - - - - - - - - - - - - 64 - - - - 8 - - - - - - - - - - - - - - - - - - - - - - - - - 64 - - - - 8 - - - - - - - - - - - - build_shorthand.py from SCAP Security Guide - ssg: 0.1.69 - 2.0 - 2023-09-14T00:00:00 - - - - Disable Avahi Server Software - - ocil:ssg-service_avahi-daemon_disabled_action:testaction:1 - - - - Disable Automatic Bug Reporting Tool (abrtd) - - ocil:ssg-service_abrtd_disabled_action:testaction:1 - - - - Disable KDump Kernel Crash Analyzer (kdump) - - ocil:ssg-service_kdump_disabled_action:testaction:1 - - - - Disable ntpdate Service (ntpdate) - - ocil:ssg-service_ntpdate_disabled_action:testaction:1 - - - - Disable Odd Job Daemon (oddjobd) - - ocil:ssg-service_oddjobd_disabled_action:testaction:1 - - - - Disable Apache Qpid (qpidd) - - ocil:ssg-service_qpidd_disabled_action:testaction:1 - - - - Disable Network Router Discovery Daemon (rdisc) - - ocil:ssg-service_rdisc_disabled_action:testaction:1 - - - - Verify Group Who Owns /etc/cron.allow file - - ocil:ssg-file_groupowner_cron_allow_action:testaction:1 - - - - Verify User Who Owns /etc/cron.allow file - - ocil:ssg-file_owner_cron_allow_action:testaction:1 - - - - Verify Permissions on /etc/cron.allow file - - ocil:ssg-file_permissions_cron_allow_action:testaction:1 - - - - Verify Group Who Owns cron.d - - ocil:ssg-file_groupowner_cron_d_action:testaction:1 - - - - Verify Group Who Owns cron.daily - - ocil:ssg-file_groupowner_cron_daily_action:testaction:1 - - - - Verify Group Who Owns cron.hourly - - ocil:ssg-file_groupowner_cron_hourly_action:testaction:1 - - - - Verify Group Who Owns cron.monthly - - ocil:ssg-file_groupowner_cron_monthly_action:testaction:1 - - - - Verify Group Who Owns cron.weekly - - ocil:ssg-file_groupowner_cron_weekly_action:testaction:1 - - - - Verify Group Who Owns Crontab - - ocil:ssg-file_groupowner_crontab_action:testaction:1 - - - - Verify Owner on cron.d - - ocil:ssg-file_owner_cron_d_action:testaction:1 - - - - Verify Owner on cron.daily - - ocil:ssg-file_owner_cron_daily_action:testaction:1 - - - - Verify Owner on cron.hourly - - ocil:ssg-file_owner_cron_hourly_action:testaction:1 - - - - Verify Owner on cron.monthly - - ocil:ssg-file_owner_cron_monthly_action:testaction:1 - - - - Verify Owner on cron.weekly - - ocil:ssg-file_owner_cron_weekly_action:testaction:1 - - - - Verify Owner on crontab - - ocil:ssg-file_owner_crontab_action:testaction:1 - - - - Verify Permissions on cron.d - - ocil:ssg-file_permissions_cron_d_action:testaction:1 - - - - Verify Permissions on cron.daily - - ocil:ssg-file_permissions_cron_daily_action:testaction:1 - - - - Verify Permissions on cron.hourly - - ocil:ssg-file_permissions_cron_hourly_action:testaction:1 - - - - Verify Permissions on cron.monthly - - ocil:ssg-file_permissions_cron_monthly_action:testaction:1 - - - - Verify Permissions on cron.weekly - - ocil:ssg-file_permissions_cron_weekly_action:testaction:1 - - - - Verify Permissions on crontab - - ocil:ssg-file_permissions_crontab_action:testaction:1 - - - - Install the cron service - - ocil:ssg-package_cron_installed_action:testaction:1 - - - - Disable At Service (atd) - - ocil:ssg-service_atd_disabled_action:testaction:1 - - - - Enable cron Service - - ocil:ssg-service_cron_enabled_action:testaction:1 - - - - Enable cron Service - - ocil:ssg-service_crond_enabled_action:testaction:1 - - - - Uninstall DHCP Server Package - - ocil:ssg-package_dhcp_removed_action:testaction:1 - - - - Uninstall bind Package - - ocil:ssg-package_bind_removed_action:testaction:1 - - - - Configure Fapolicy Module to Employ a Deny-all, Permit-by-exception Policy to Allow the Execution of Authorized Software Programs. - - ocil:ssg-fapolicy_default_deny_action:testaction:1 - - - - Install fapolicyd Package - - ocil:ssg-package_fapolicyd_installed_action:testaction:1 - - - - Enable the File Access Policy Service - - ocil:ssg-service_fapolicyd_enabled_action:testaction:1 - - - - Uninstall vsftpd Package - - ocil:ssg-package_vsftpd_removed_action:testaction:1 - - - - Configure System to Forward All Mail For The Root Account - - ocil:ssg-postfix_client_configure_mail_alias_action:testaction:1 - - - - Configure System to Forward All Mail From Postmaster to The Root Account - - ocil:ssg-postfix_client_configure_mail_alias_postmaster_action:testaction:1 - - - - Configure System to Forward All Mail through a specific host - - ocil:ssg-postfix_client_configure_relayhost_action:testaction:1 - - - - Disable Postfix Network Listening - - ocil:ssg-postfix_network_listening_disabled_action:testaction:1 - - - - Prevent Unrestricted Mail Relaying - - ocil:ssg-postfix_prevent_unrestricted_relay_action:testaction:1 - - - - The Postfix package is installed - - ocil:ssg-package_postfix_installed_action:testaction:1 - - - - Uninstall Sendmail Package - - ocil:ssg-package_sendmail_removed_action:testaction:1 - - - - Enable Postfix Service - - ocil:ssg-service_postfix_enabled_action:testaction:1 - - - - Mount Remote Filesystems with Kerberos Security - - ocil:ssg-mount_option_krb_sec_remote_filesystems_action:testaction:1 - - - - Mount Remote Filesystems with nodev - - ocil:ssg-mount_option_nodev_remote_filesystems_action:testaction:1 - - - - Mount Remote Filesystems with noexec - - ocil:ssg-mount_option_noexec_remote_filesystems_action:testaction:1 - - - - Mount Remote Filesystems with nosuid - - ocil:ssg-mount_option_nosuid_remote_filesystems_action:testaction:1 - - - - Ensure All-Squashing Disabled On All Exports - - ocil:ssg-no_all_squash_exports_action:testaction:1 - - - - Use Kerberos Security on All Exports - - ocil:ssg-use_kerberos_security_all_exports_action:testaction:1 - - - - Uninstall nfs-utils Package - - ocil:ssg-package_nfs-utils_removed_action:testaction:1 - - - - Disable chrony daemon from acting as server - - ocil:ssg-chronyd_client_only_action:testaction:1 - - - - Disable network management of chrony daemon - - ocil:ssg-chronyd_no_chronyc_network_action:testaction:1 - - - - Configure Time Service Maxpoll Interval - - ocil:ssg-chronyd_or_ntpd_set_maxpoll_action:testaction:1 - - - - Ensure Chrony is only configured with the server directive - - ocil:ssg-chronyd_server_directive_action:testaction:1 - - - - A remote time server for Chrony is configured - - ocil:ssg-chronyd_specify_remote_server_action:testaction:1 - - - - Specify a Remote NTP Server - - ocil:ssg-ntpd_specify_remote_server_action:testaction:1 - - - - The Chrony package is installed - - ocil:ssg-package_chrony_installed_action:testaction:1 - - - - Install the ntp service - - ocil:ssg-package_ntp_installed_action:testaction:1 - - - - The Chronyd service is enabled - - ocil:ssg-service_chronyd_enabled_action:testaction:1 - - - - Enable the NTP Daemon - - ocil:ssg-service_ntp_enabled_action:testaction:1 - - - - Enable the NTP Daemon - - ocil:ssg-service_ntpd_enabled_action:testaction:1 - - - - Uninstall xinetd Package - - ocil:ssg-package_xinetd_removed_action:testaction:1 - - - - Disable xinetd Service - - ocil:ssg-service_xinetd_disabled_action:testaction:1 - - - - Remove Host-Based Authentication Files - - ocil:ssg-no_host_based_files_action:testaction:1 - - - - Remove Rsh Trust Files - - ocil:ssg-no_rsh_trust_files_action:testaction:1 - - - - Remove User Host-Based Authentication Files - - ocil:ssg-no_user_host_based_files_action:testaction:1 - - - - Uninstall rsh-server Package - - ocil:ssg-package_rsh-server_removed_action:testaction:1 - - - - Uninstall rsh Package - - ocil:ssg-package_rsh_removed_action:testaction:1 - - - - Disable rlogin Service - - ocil:ssg-service_rlogin_disabled_action:testaction:1 - - - - Uninstall talk-server Package - - ocil:ssg-package_talk-server_removed_action:testaction:1 - - - - Uninstall talk Package - - ocil:ssg-package_talk_removed_action:testaction:1 - - - - Uninstall telnet-server Package - - ocil:ssg-package_telnet-server_removed_action:testaction:1 - - - - Remove telnet Clients - - ocil:ssg-package_telnet_removed_action:testaction:1 - - - - Disable telnet Service - - ocil:ssg-service_telnet_disabled_action:testaction:1 - - - - Uninstall tftp-server Package - - ocil:ssg-package_tftp-server_removed_action:testaction:1 - - - - Remove tftp Daemon - - ocil:ssg-package_tftp_removed_action:testaction:1 - - - - Ensure tftp Daemon Uses Secure Mode - - ocil:ssg-tftpd_uses_secure_mode_action:testaction:1 - - - - Uninstall squid Package - - ocil:ssg-package_squid_removed_action:testaction:1 - - - - Disable Squid - - ocil:ssg-service_squid_disabled_action:testaction:1 - - - - Enable the Hardware RNG Entropy Gatherer Service - - ocil:ssg-service_rngd_enabled_action:testaction:1 - - - - Uninstall quagga Package - - ocil:ssg-package_quagga_removed_action:testaction:1 - - - - Configure session renegotiation for SSH client - - ocil:ssg-ssh_client_rekey_limit_action:testaction:1 - - - - Verify the SSH Private Key Files Have a Passcode - - ocil:ssg-ssh_keys_passphrase_protected_action:testaction:1 - - - - Disable Host-Based Authentication - - ocil:ssg-disable_host_auth_action:testaction:1 - - - - Enable SSH Server firewalld Firewall Exception - - ocil:ssg-firewalld_sshd_port_enabled_action:testaction:1 - - - - Allow Only SSH Protocol 2 - - ocil:ssg-sshd_allow_only_protocol2_action:testaction:1 - - - - Disable Compression Or Set Compression to delayed - - ocil:ssg-sshd_disable_compression_action:testaction:1 - - - - Disable SSH Access via Empty Passwords - - ocil:ssg-sshd_disable_empty_passwords_action:testaction:1 - - - - Disable GSSAPI Authentication - - ocil:ssg-sshd_disable_gssapi_auth_action:testaction:1 - - - - Disable Kerberos Authentication - - ocil:ssg-sshd_disable_kerb_auth_action:testaction:1 - - - - Disable PubkeyAuthentication Authentication - - ocil:ssg-sshd_disable_pubkey_auth_action:testaction:1 - - - - Disable SSH Support for .rhosts Files - - ocil:ssg-sshd_disable_rhosts_action:testaction:1 - - - - Disable SSH Support for Rhosts RSA Authentication - - ocil:ssg-sshd_disable_rhosts_rsa_action:testaction:1 - - - - Disable SSH Root Login - - ocil:ssg-sshd_disable_root_login_action:testaction:1 - - - - Disable SSH root Login with a Password (Insecure) - - ocil:ssg-sshd_disable_root_password_login_action:testaction:1 - - - - Disable SSH TCP Forwarding - - ocil:ssg-sshd_disable_tcp_forwarding_action:testaction:1 - - - - Disable SSH Support for User Known Hosts - - ocil:ssg-sshd_disable_user_known_hosts_action:testaction:1 - - - - Disable X11 Forwarding - - ocil:ssg-sshd_disable_x11_forwarding_action:testaction:1 - - - - Do Not Allow SSH Environment Options - - ocil:ssg-sshd_do_not_permit_user_env_action:testaction:1 - - - - Enable GSSAPI Authentication - - ocil:ssg-sshd_enable_gssapi_auth_action:testaction:1 - - - - Enable PAM - - ocil:ssg-sshd_enable_pam_action:testaction:1 - - - - Enable Public Key Authentication - - ocil:ssg-sshd_enable_pubkey_auth_action:testaction:1 - - - - Enable Use of Strict Mode Checking - - ocil:ssg-sshd_enable_strictmodes_action:testaction:1 - - - - Enable SSH Warning Banner - - ocil:ssg-sshd_enable_warning_banner_action:testaction:1 - - - - Enable SSH Warning Banner - - ocil:ssg-sshd_enable_warning_banner_net_action:testaction:1 - - - - Enable Encrypted X11 Forwarding - - ocil:ssg-sshd_enable_x11_forwarding_action:testaction:1 - - - - Limit Users' SSH Access - - ocil:ssg-sshd_limit_user_access_action:testaction:1 - - - - Enable SSH Print Last Log - - ocil:ssg-sshd_print_last_log_action:testaction:1 - - - - Force frequent session key renegotiation - - ocil:ssg-sshd_rekey_limit_action:testaction:1 - - - - Set SSH Client Alive Interval - - ocil:ssg-sshd_set_idle_timeout_action:testaction:1 - - - - Set SSH Client Alive Count Max - - ocil:ssg-sshd_set_keepalive_action:testaction:1 - - - - Set SSH Client Alive Count Max to zero - - ocil:ssg-sshd_set_keepalive_0_action:testaction:1 - - - - Ensure SSH LoginGraceTime is configured - - ocil:ssg-sshd_set_login_grace_time_action:testaction:1 - - - - Set LogLevel to INFO - - ocil:ssg-sshd_set_loglevel_info_action:testaction:1 - - - - Set SSH Daemon LogLevel to VERBOSE - - ocil:ssg-sshd_set_loglevel_verbose_action:testaction:1 - - - - Set SSH authentication attempt limit - - ocil:ssg-sshd_set_max_auth_tries_action:testaction:1 - - - - Set SSH MaxSessions limit - - ocil:ssg-sshd_set_max_sessions_action:testaction:1 - - - - Ensure SSH MaxStartups is configured - - ocil:ssg-sshd_set_maxstartups_action:testaction:1 - - - - Distribute the SSH Server configuration to multiple files in a config directory. - - ocil:ssg-sshd_use_directory_configuration_action:testaction:1 - - - - Enable Use of Privilege Separation - - ocil:ssg-sshd_use_priv_separation_action:testaction:1 - - - - Prevent remote hosts from connecting to the proxy display - - ocil:ssg-sshd_x11_use_localhost_action:testaction:1 - - - - Verify Group Who Owns SSH Server config file - - ocil:ssg-file_groupowner_sshd_config_action:testaction:1 - - - - Verify Group Ownership on SSH Server Private *_key Key Files - - ocil:ssg-file_groupownership_sshd_private_key_action:testaction:1 - - - - Verify Group Ownership on SSH Server Public *.pub Key Files - - ocil:ssg-file_groupownership_sshd_pub_key_action:testaction:1 - - - - Verify Owner on SSH Server config file - - ocil:ssg-file_owner_sshd_config_action:testaction:1 - - - - Verify Ownership on SSH Server Private *_key Key Files - - ocil:ssg-file_ownership_sshd_private_key_action:testaction:1 - - - - Verify Ownership on SSH Server Public *.pub Key Files - - ocil:ssg-file_ownership_sshd_pub_key_action:testaction:1 - - - - Verify Permissions on SSH Server config file - - ocil:ssg-file_permissions_sshd_config_action:testaction:1 - - - - Verify Permissions on SSH Server Private *_key Key Files - - ocil:ssg-file_permissions_sshd_private_key_action:testaction:1 - - - - Verify Permissions on SSH Server Public *.pub Key Files - - ocil:ssg-file_permissions_sshd_pub_key_action:testaction:1 - - - - Install OpenSSH client software - - ocil:ssg-package_openssh-clients_installed_action:testaction:1 - - - - Install the OpenSSH Server Package - - ocil:ssg-package_openssh-server_installed_action:testaction:1 - - - - Remove the OpenSSH Server Package - - ocil:ssg-package_openssh-server_removed_action:testaction:1 - - - - Disable SSH Server If Possible - - ocil:ssg-service_sshd_disabled_action:testaction:1 - - - - Enable the OpenSSH Service - - ocil:ssg-service_sshd_enabled_action:testaction:1 - - - - Certificate status checking in SSSD - - ocil:ssg-sssd_certificate_verification_action:testaction:1 - - - - Enable Certmap in SSSD - - ocil:ssg-sssd_enable_certmap_action:testaction:1 - - - - Enable Smartcards in SSSD - - ocil:ssg-sssd_enable_smartcards_action:testaction:1 - - - - SSSD Has a Correct Trust Anchor - - ocil:ssg-sssd_has_trust_anchor_action:testaction:1 - - - - Configure SSSD to Expire Offline Credentials - - ocil:ssg-sssd_offline_cred_expiration_action:testaction:1 - - - - Log USBGuard daemon audit events using Linux Audit - - ocil:ssg-configure_usbguard_auditbackend_action:testaction:1 - - - - Install usbguard Package - - ocil:ssg-package_usbguard_installed_action:testaction:1 - - - - Enable the USBGuard Service - - ocil:ssg-service_usbguard_enabled_action:testaction:1 - - - - Authorize Human Interface Devices and USB hubs in USBGuard daemon - - ocil:ssg-usbguard_allow_hid_and_hub_action:testaction:1 - - - - Generate USBGuard Policy - - ocil:ssg-usbguard_generate_policy_action:testaction:1 - - - - Remove the X Windows Package Group - - ocil:ssg-package_xorg-x11-server-common_removed_action:testaction:1 - - - - Disable graphical user interface - - ocil:ssg-xwindows_remove_packages_action:testaction:1 - - - - Disable X Windows Startup By Setting Default Target - - ocil:ssg-xwindows_runlevel_target_action:testaction:1 - - - - Enable GNOME3 Login Warning Banner - - ocil:ssg-dconf_gnome_banner_enabled_action:testaction:1 - - - - Set the GNOME3 Login Warning Banner Text - - ocil:ssg-dconf_gnome_login_banner_text_action:testaction:1 - - - - Modify the System Login Banner - - ocil:ssg-banner_etc_issue_action:testaction:1 - - - - Modify the System Login Banner for Remote Connections - - ocil:ssg-banner_etc_issue_net_action:testaction:1 - - - - Configure the Use of the pam_faillock.so Module in the /etc/pam.d/password-auth File. - - ocil:ssg-account_password_pam_faillock_password_auth_action:testaction:1 - - - - Configure the Use of the pam_faillock.so Module in the /etc/pam.d/system-auth File. - - ocil:ssg-account_password_pam_faillock_system_auth_action:testaction:1 - - - - An SELinux Context must be configured for the pam_faillock.so records directory - - ocil:ssg-account_password_selinux_faillock_dir_action:testaction:1 - - - - Account Lockouts Must Be Logged - - ocil:ssg-account_passwords_pam_faillock_audit_action:testaction:1 - - - - Account Lockouts Must Persist - - ocil:ssg-account_passwords_pam_faillock_dir_action:testaction:1 - - - - Limit Password Reuse: password-auth - - ocil:ssg-accounts_password_pam_pwhistory_remember_password_auth_action:testaction:1 - - - - Limit Password Reuse: system-auth - - ocil:ssg-accounts_password_pam_pwhistory_remember_system_auth_action:testaction:1 - - - - Limit Password Reuse - - ocil:ssg-accounts_password_pam_unix_remember_action:testaction:1 - - - - Account Lockouts Must Be Logged - - ocil:ssg-accounts_passwords_pam_faillock_audit_action:testaction:1 - - - - Verify No netrc Files Exist - - ocil:ssg-no_netrc_files_action:testaction:1 - - - - Lock Accounts After Failed Password Attempts - - ocil:ssg-accounts_passwords_pam_faillock_deny_action:testaction:1 - - - - Configure the root Account for Failed Password Attempts - - ocil:ssg-accounts_passwords_pam_faillock_deny_root_action:testaction:1 - - - - Lock Accounts Must Persist - - ocil:ssg-accounts_passwords_pam_faillock_dir_action:testaction:1 - - - - Set Interval For Counting Failed Password Attempts - - ocil:ssg-accounts_passwords_pam_faillock_interval_action:testaction:1 - - - - Set Lockout Time for Failed Password Attempts - - ocil:ssg-accounts_passwords_pam_faillock_unlock_time_action:testaction:1 - - - - Ensure PAM Enforces Password Requirements - Minimum Digit Characters - - ocil:ssg-accounts_password_pam_dcredit_action:testaction:1 - - - - Ensure PAM Enforces Password Requirements - Prevent the Use of Dictionary Words - - ocil:ssg-accounts_password_pam_dictcheck_action:testaction:1 - - - - Ensure PAM Enforces Password Requirements - Minimum Different Characters - - ocil:ssg-accounts_password_pam_difok_action:testaction:1 - - - - Ensure PAM Enforces Password Requirements - Enforce for root User - - ocil:ssg-accounts_password_pam_enforce_root_action:testaction:1 - - - - Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters - - ocil:ssg-accounts_password_pam_lcredit_action:testaction:1 - - - - Ensure PAM Enforces Password Requirements - Maximum Consecutive Repeating Characters from Same Character Class - - ocil:ssg-accounts_password_pam_maxclassrepeat_action:testaction:1 - - - - Set Password Maximum Consecutive Repeating Characters - - ocil:ssg-accounts_password_pam_maxrepeat_action:testaction:1 - - - - Ensure PAM Enforces Password Requirements - Minimum Different Categories - - ocil:ssg-accounts_password_pam_minclass_action:testaction:1 - - - - Ensure PAM Enforces Password Requirements - Minimum Length - - ocil:ssg-accounts_password_pam_minlen_action:testaction:1 - - - - Ensure PAM Enforces Password Requirements - Minimum Special Characters - - ocil:ssg-accounts_password_pam_ocredit_action:testaction:1 - - - - Ensure PAM password complexity module is enabled in password-auth - - ocil:ssg-accounts_password_pam_pwquality_password_auth_action:testaction:1 - - - - Ensure PAM password complexity module is enabled in system-auth - - ocil:ssg-accounts_password_pam_pwquality_system_auth_action:testaction:1 - - - - Ensure PAM Enforces Password Requirements - Authentication Retry Prompts Permitted Per-Session - - ocil:ssg-accounts_password_pam_retry_action:testaction:1 - - - - Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters - - ocil:ssg-accounts_password_pam_ucredit_action:testaction:1 - - - - Set Password Hashing Algorithm in /etc/libuser.conf - - ocil:ssg-set_password_hashing_algorithm_libuserconf_action:testaction:1 - - - - Set Password Hashing Algorithm in /etc/login.defs - - ocil:ssg-set_password_hashing_algorithm_logindefs_action:testaction:1 - - - - Set PAM''s Password Hashing Algorithm - password-auth - - ocil:ssg-set_password_hashing_algorithm_passwordauth_action:testaction:1 - - - - Set PAM''s Password Hashing Algorithm - - ocil:ssg-set_password_hashing_algorithm_systemauth_action:testaction:1 - - - - Set Password Hashing Rounds in /etc/login.defs - - ocil:ssg-set_password_hashing_min_rounds_logindefs_action:testaction:1 - - - - Disallow Configuration to Bypass Password Requirements for Privilege Escalation - - ocil:ssg-disallow_bypass_password_sudo_action:testaction:1 - - - - Ensure PAM Displays Last Logon/Access Notification - - ocil:ssg-display_login_attempts_action:testaction:1 - - - - Support session locking with tmux - - ocil:ssg-configure_bashrc_exec_tmux_action:testaction:1 - - - - Configure tmux to lock session after inactivity - - ocil:ssg-configure_tmux_lock_after_time_action:testaction:1 - - - - Configure the tmux Lock Command - - ocil:ssg-configure_tmux_lock_command_action:testaction:1 - - - - Prevent user from disabling the screen lock - - ocil:ssg-no_tmux_in_shells_action:testaction:1 - - - - Install the tmux Package - - ocil:ssg-package_tmux_installed_action:testaction:1 - - - - Configure opensc Smart Card Drivers - - ocil:ssg-configure_opensc_card_drivers_action:testaction:1 - - - - Force opensc To Use Defined Smart Card Driver - - ocil:ssg-force_opensc_card_drivers_action:testaction:1 - - - - Install Smart Card Packages For Multifactor Authentication - - ocil:ssg-install_smartcard_packages_action:testaction:1 - - - - Install the opensc Package For Multifactor Authentication - - ocil:ssg-package_opensc_installed_action:testaction:1 - - - - Install the pcsc-lite package - - ocil:ssg-package_pcsc-lite_installed_action:testaction:1 - - - - Enable the pcscd Service - - ocil:ssg-service_pcscd_enabled_action:testaction:1 - - - - Disable Ctrl-Alt-Del Burst Action - - ocil:ssg-disable_ctrlaltdel_burstaction_action:testaction:1 - - - - Disable Ctrl-Alt-Del Reboot Activation - - ocil:ssg-disable_ctrlaltdel_reboot_action:testaction:1 - - - - Verify that Interactive Boot is Disabled - - ocil:ssg-grub2_disable_interactive_boot_action:testaction:1 - - - - Require Authentication for Emergency Systemd Target - - ocil:ssg-require_emergency_target_auth_action:testaction:1 - - - - Require Authentication for Single User Mode - - ocil:ssg-require_singleuser_auth_action:testaction:1 - - - - Disable debug-shell SystemD Service - - ocil:ssg-service_debug-shell_disabled_action:testaction:1 - - - - Set Account Expiration Following Inactivity in password-auth - - ocil:ssg-account_disable_inactivity_password_auth_action:testaction:1 - - - - Set Account Expiration Following Inactivity in system-auth - - ocil:ssg-account_disable_inactivity_system_auth_action:testaction:1 - - - - Set Account Expiration Following Inactivity - - ocil:ssg-account_disable_post_pw_expiration_action:testaction:1 - - - - Assign Expiration Date to Emergency Accounts - - ocil:ssg-account_emergency_expire_date_action:testaction:1 - - - - Assign Expiration Date to Temporary Accounts - - ocil:ssg-account_temp_expire_date_action:testaction:1 - - - - Ensure All Accounts on the System Have Unique Names - - ocil:ssg-account_unique_name_action:testaction:1 - - - - Use Centralized and Automated Authentication - - ocil:ssg-account_use_centralized_automated_auth_action:testaction:1 - - - - Set Password Maximum Age - - ocil:ssg-accounts_maximum_age_login_defs_action:testaction:1 - - - - Set Password Minimum Age - - ocil:ssg-accounts_minimum_age_login_defs_action:testaction:1 - - - - Set Password Minimum Length in login.defs - - ocil:ssg-accounts_password_minlen_login_defs_action:testaction:1 - - - - Set Existing Passwords Maximum Age - - ocil:ssg-accounts_password_set_max_life_existing_action:testaction:1 - - - - Set Existing Passwords Minimum Age - - ocil:ssg-accounts_password_set_min_life_existing_action:testaction:1 - - - - Set Password Warning Age - - ocil:ssg-accounts_password_warn_age_login_defs_action:testaction:1 - - - - Verify All Account Password Hashes are Shadowed - - ocil:ssg-accounts_password_all_shadowed_action:testaction:1 - - - - Verify All Account Password Hashes are Shadowed with SHA512 - - ocil:ssg-accounts_password_all_shadowed_sha512_action:testaction:1 - - - - Ensure all users last password change date is in the past - - ocil:ssg-accounts_password_last_change_is_in_past_action:testaction:1 - - - - Set number of Password Hashing Rounds - password-auth - - ocil:ssg-accounts_password_pam_unix_rounds_password_auth_action:testaction:1 - - - - Set number of Password Hashing Rounds - system-auth - - ocil:ssg-accounts_password_pam_unix_rounds_system_auth_action:testaction:1 - - - - All GIDs referenced in /etc/passwd must be defined in /etc/group - - ocil:ssg-gid_passwd_group_same_action:testaction:1 - - - - Prevent Login to Accounts With Empty Password - - ocil:ssg-no_empty_passwords_action:testaction:1 - - - - Ensure There Are No Accounts With Blank or Null Passwords - - ocil:ssg-no_empty_passwords_etc_shadow_action:testaction:1 - - - - Verify Only Root Has UID 0 - - ocil:ssg-accounts_no_uid_except_zero_action:testaction:1 - - - - Verify Root Has A Primary GID 0 - - ocil:ssg-accounts_root_gid_zero_action:testaction:1 - - - - Direct root Logins Not Allowed - - ocil:ssg-no_direct_root_logins_action:testaction:1 - - - - Ensure that System Accounts Are Locked - - ocil:ssg-no_password_auth_for_systemaccounts_action:testaction:1 - - - - Ensure that System Accounts Do Not Run a Shell Upon Login - - ocil:ssg-no_shelllogin_for_systemaccounts_action:testaction:1 - - - - Restrict Serial Port Root Logins - - ocil:ssg-restrict_serial_port_logins_action:testaction:1 - - - - Restrict Virtual Console Root Logins - - ocil:ssg-securetty_root_login_console_only_action:testaction:1 - - - - Enforce usage of pam_wheel for su authentication - - ocil:ssg-use_pam_wheel_for_su_action:testaction:1 - - - - Ensure All Accounts on the System Have Unique User IDs - - ocil:ssg-account_unique_id_action:testaction:1 - - - - Only Authorized Local User Accounts Exist on Operating System - - ocil:ssg-accounts_authorized_local_users_action:testaction:1 - - - - Ensure All Groups on the System Have Unique Group ID - - ocil:ssg-group_unique_id_action:testaction:1 - - - - Ensure that Root's Path Does Not Include World or Group-Writable Directories - - ocil:ssg-accounts_root_path_dirs_no_write_action:testaction:1 - - - - Ensure the Default Bash Umask is Set Correctly - - ocil:ssg-accounts_umask_etc_bashrc_action:testaction:1 - - - - Ensure the Default C Shell Umask is Set Correctly - - ocil:ssg-accounts_umask_etc_csh_cshrc_action:testaction:1 - - - - Ensure the Default Umask is Set Correctly in login.defs - - ocil:ssg-accounts_umask_etc_login_defs_action:testaction:1 - - - - Set Interactive Session Timeout - - ocil:ssg-accounts_tmout_action:testaction:1 - - - - Ensure the Default Umask is Set Correctly in /etc/profile - - ocil:ssg-accounts_umask_etc_profile_action:testaction:1 - - - - Ensure the Default Umask is Set Correctly For Interactive Users - - ocil:ssg-accounts_umask_interactive_users_action:testaction:1 - - - - Ensure Home Directories are Created for New Users - - ocil:ssg-accounts_have_homedir_login_defs_action:testaction:1 - - - - Ensure the Logon Failure Delay is Set Correctly in login.defs - - ocil:ssg-accounts_logon_fail_delay_action:testaction:1 - - - - Limit the Number of Concurrent Login Sessions Allowed Per User - - ocil:ssg-accounts_max_concurrent_login_sessions_action:testaction:1 - - - - Configure Polyinstantiation of /tmp Directories - - ocil:ssg-accounts_polyinstantiated_tmp_action:testaction:1 - - - - Configure Polyinstantiation of /var/tmp Directories - - ocil:ssg-accounts_polyinstantiated_var_tmp_action:testaction:1 - - - - User Initialization Files Must Not Run World-Writable Programs - - ocil:ssg-accounts_user_dot_no_world_writable_programs_action:testaction:1 - - - - Ensure that Users Path Contains Only Local Directories - - ocil:ssg-accounts_user_home_paths_only_action:testaction:1 - - - - All Interactive Users Must Have A Home Directory Defined - - ocil:ssg-accounts_user_interactive_home_directory_defined_action:testaction:1 - - - - All Interactive Users Home Directories Must Exist - - ocil:ssg-accounts_user_interactive_home_directory_exists_action:testaction:1 - - - - All Interactive User Home Directories Must Be Group-Owned By The Primary Group - - ocil:ssg-file_groupownership_home_directories_action:testaction:1 - - - - Ensure All User Initialization Files Have Mode 0740 Or Less Permissive - - ocil:ssg-file_permission_user_init_files_action:testaction:1 - - - - All Interactive User Home Directories Must Have mode 0750 Or Less Permissive - - ocil:ssg-file_permissions_home_directories_action:testaction:1 - - - - Ensure that User Home Directories are not Group-Writable or World-Readable - - ocil:ssg-file_permissions_home_dirs_action:testaction:1 - - - - Enable authselect - - ocil:ssg-enable_authselect_action:testaction:1 - - - - Record Events that Modify the System's Discretionary Access Controls - chmod - - ocil:ssg-audit_rules_dac_modification_chmod_action:testaction:1 - - - - Record Events that Modify the System's Discretionary Access Controls - chown - - ocil:ssg-audit_rules_dac_modification_chown_action:testaction:1 - - - - Record Events that Modify the System's Discretionary Access Controls - fchmod - - ocil:ssg-audit_rules_dac_modification_fchmod_action:testaction:1 - - - - Record Events that Modify the System's Discretionary Access Controls - fchmodat - - ocil:ssg-audit_rules_dac_modification_fchmodat_action:testaction:1 - - - - Record Events that Modify the System's Discretionary Access Controls - fchown - - ocil:ssg-audit_rules_dac_modification_fchown_action:testaction:1 - - - - Record Events that Modify the System's Discretionary Access Controls - fchownat - - ocil:ssg-audit_rules_dac_modification_fchownat_action:testaction:1 - - - - Record Events that Modify the System's Discretionary Access Controls - fremovexattr - - ocil:ssg-audit_rules_dac_modification_fremovexattr_action:testaction:1 - - - - Record Events that Modify the System's Discretionary Access Controls - fsetxattr - - ocil:ssg-audit_rules_dac_modification_fsetxattr_action:testaction:1 - - - - Record Events that Modify the System's Discretionary Access Controls - lchown - - ocil:ssg-audit_rules_dac_modification_lchown_action:testaction:1 - - - - Record Events that Modify the System's Discretionary Access Controls - lremovexattr - - ocil:ssg-audit_rules_dac_modification_lremovexattr_action:testaction:1 - - - - Record Events that Modify the System's Discretionary Access Controls - lsetxattr - - ocil:ssg-audit_rules_dac_modification_lsetxattr_action:testaction:1 - - - - Record Events that Modify the System's Discretionary Access Controls - removexattr - - ocil:ssg-audit_rules_dac_modification_removexattr_action:testaction:1 - - - - Record Events that Modify the System's Discretionary Access Controls - setxattr - - ocil:ssg-audit_rules_dac_modification_setxattr_action:testaction:1 - - - - Record Events that Modify the System's Discretionary Access Controls - umount - - ocil:ssg-audit_rules_dac_modification_umount_action:testaction:1 - - - - Record Events that Modify the System's Discretionary Access Controls - umount2 - - ocil:ssg-audit_rules_dac_modification_umount2_action:testaction:1 - - - - Record Any Attempts to Run chacl - - ocil:ssg-audit_rules_execution_chacl_action:testaction:1 - - - - Record Any Attempts to Run setfacl - - ocil:ssg-audit_rules_execution_setfacl_action:testaction:1 - - - - Record Any Attempts to Run chcon - - ocil:ssg-audit_rules_execution_chcon_action:testaction:1 - - - - Record Any Attempts to Run restorecon - - ocil:ssg-audit_rules_execution_restorecon_action:testaction:1 - - - - Record Any Attempts to Run semanage - - ocil:ssg-audit_rules_execution_semanage_action:testaction:1 - - - - Record Any Attempts to Run setfiles - - ocil:ssg-audit_rules_execution_setfiles_action:testaction:1 - - - - Record Any Attempts to Run setsebool - - ocil:ssg-audit_rules_execution_setsebool_action:testaction:1 - - - - Record Any Attempts to Run seunshare - - ocil:ssg-audit_rules_execution_seunshare_action:testaction:1 - - - - Ensure auditd Collects File Deletion Events by User - - ocil:ssg-audit_rules_file_deletion_events_action:testaction:1 - - - - Ensure auditd Collects File Deletion Events by User - rename - - ocil:ssg-audit_rules_file_deletion_events_rename_action:testaction:1 - - - - Ensure auditd Collects File Deletion Events by User - renameat - - ocil:ssg-audit_rules_file_deletion_events_renameat_action:testaction:1 - - - - Ensure auditd Collects File Deletion Events by User - rmdir - - ocil:ssg-audit_rules_file_deletion_events_rmdir_action:testaction:1 - - - - Ensure auditd Collects File Deletion Events by User - unlink - - ocil:ssg-audit_rules_file_deletion_events_unlink_action:testaction:1 - - - - Ensure auditd Collects File Deletion Events by User - unlinkat - - ocil:ssg-audit_rules_file_deletion_events_unlinkat_action:testaction:1 - - - - Ensure auditd Collects Unauthorized Access Attempts to Files (unsuccessful) - - ocil:ssg-audit_rules_unsuccessful_file_modification_action:testaction:1 - - - - Record Unsuccessful Access Attempts to Files - creat - - ocil:ssg-audit_rules_unsuccessful_file_modification_creat_action:testaction:1 - - - - Record Unsuccessful Access Attempts to Files - ftruncate - - ocil:ssg-audit_rules_unsuccessful_file_modification_ftruncate_action:testaction:1 - - - - Record Unsuccessful Access Attempts to Files - open - - ocil:ssg-audit_rules_unsuccessful_file_modification_open_action:testaction:1 - - - - Record Unsuccessful Access Attempts to Files - open_by_handle_at - - ocil:ssg-audit_rules_unsuccessful_file_modification_open_by_handle_at_action:testaction:1 - - - - Record Unsuccessful Access Attempts to Files - openat - - ocil:ssg-audit_rules_unsuccessful_file_modification_openat_action:testaction:1 - - - - Record Unsuccessful Delete Attempts to Files - rename - - ocil:ssg-audit_rules_unsuccessful_file_modification_rename_action:testaction:1 - - - - Record Unsuccessful Delete Attempts to Files - renameat - - ocil:ssg-audit_rules_unsuccessful_file_modification_renameat_action:testaction:1 - - - - Record Unsuccessful Access Attempts to Files - truncate - - ocil:ssg-audit_rules_unsuccessful_file_modification_truncate_action:testaction:1 - - - - Record Unsuccessful Delete Attempts to Files - unlink - - ocil:ssg-audit_rules_unsuccessful_file_modification_unlink_action:testaction:1 - - - - Record Unsuccessful Delete Attempts to Files - unlinkat - - ocil:ssg-audit_rules_unsuccessful_file_modification_unlinkat_action:testaction:1 - - - - Ensure auditd Collects Information on Kernel Module Loading and Unloading - - ocil:ssg-audit_rules_kernel_module_loading_action:testaction:1 - - - - Ensure auditd Collects Information on Kernel Module Unloading - delete_module - - ocil:ssg-audit_rules_kernel_module_loading_delete_action:testaction:1 - - - - Ensure auditd Collects Information on Kernel Module Loading and Unloading - finit_module - - ocil:ssg-audit_rules_kernel_module_loading_finit_action:testaction:1 - - - - Ensure auditd Collects Information on Kernel Module Loading - init_module - - ocil:ssg-audit_rules_kernel_module_loading_init_action:testaction:1 - - - - Record Attempts to Alter Logon and Logout Events - faillock - - ocil:ssg-audit_rules_login_events_faillock_action:testaction:1 - - - - Record Attempts to Alter Logon and Logout Events - lastlog - - ocil:ssg-audit_rules_login_events_lastlog_action:testaction:1 - - - - Record Attempts to Alter Logon and Logout Events - tallylog - - ocil:ssg-audit_rules_login_events_tallylog_action:testaction:1 - - - - Ensure auditd Collects Information on the Use of Privileged Commands - init - - ocil:ssg-audit_privileged_commands_init_action:testaction:1 - - - - Ensure auditd Collects Information on the Use of Privileged Commands - poweroff - - ocil:ssg-audit_privileged_commands_poweroff_action:testaction:1 - - - - Ensure auditd Collects Information on the Use of Privileged Commands - reboot - - ocil:ssg-audit_privileged_commands_reboot_action:testaction:1 - - - - Ensure auditd Collects Information on the Use of Privileged Commands - shutdown - - ocil:ssg-audit_privileged_commands_shutdown_action:testaction:1 - - - - Ensure auditd Collects Information on the Use of Privileged Commands - - ocil:ssg-audit_rules_privileged_commands_action:testaction:1 - - - - Ensure auditd Collects Information on the Use of Privileged Commands - at - - ocil:ssg-audit_rules_privileged_commands_at_action:testaction:1 - - - - Ensure auditd Collects Information on the Use of Privileged Commands - chage - - ocil:ssg-audit_rules_privileged_commands_chage_action:testaction:1 - - - - Record Attempts to Alter Time Through stime - - ocil:ssg-audit_rules_time_stime_action:testaction:1 - - - - Ensure auditd Collects Information on the Use of Privileged Commands - chsh - - ocil:ssg-audit_rules_privileged_commands_chsh_action:testaction:1 - - - - Ensure auditd Collects Information on the Use of Privileged Commands - crontab - - ocil:ssg-audit_rules_privileged_commands_crontab_action:testaction:1 - - - - Ensure auditd Collects Information on the Use of Privileged Commands - gpasswd - - ocil:ssg-audit_rules_privileged_commands_gpasswd_action:testaction:1 - - - - Ensure auditd Collects Information on the Use of Privileged Commands - kmod - - ocil:ssg-audit_rules_privileged_commands_kmod_action:testaction:1 - - - - Ensure auditd Collects Information on the Use of Privileged Commands - mount - - ocil:ssg-audit_rules_privileged_commands_mount_action:testaction:1 - - - - Ensure auditd Collects Information on the Use of Privileged Commands - newgrp - - ocil:ssg-audit_rules_privileged_commands_newgrp_action:testaction:1 - - - - Ensure auditd Collects Information on the Use of Privileged Commands - pam_timestamp_check - - ocil:ssg-audit_rules_privileged_commands_pam_timestamp_check_action:testaction:1 - - - - Ensure auditd Collects Information on the Use of Privileged Commands - passwd - - ocil:ssg-audit_rules_privileged_commands_passwd_action:testaction:1 - - - - Ensure auditd Collects Information on the Use of Privileged Commands - postdrop - - ocil:ssg-audit_rules_privileged_commands_postdrop_action:testaction:1 - - - - Ensure auditd Collects Information on the Use of Privileged Commands - postqueue - - ocil:ssg-audit_rules_privileged_commands_postqueue_action:testaction:1 - - - - Ensure auditd Collects Information on the Use of Privileged Commands - pt_chown - - ocil:ssg-audit_rules_privileged_commands_pt_chown_action:testaction:1 - - - - Record Any Attempts to Run ssh-agent - - ocil:ssg-audit_rules_privileged_commands_ssh_agent_action:testaction:1 - - - - Ensure auditd Collects Information on the Use of Privileged Commands - ssh-keysign - - ocil:ssg-audit_rules_privileged_commands_ssh_keysign_action:testaction:1 - - - - Ensure auditd Collects Information on the Use of Privileged Commands - su - - ocil:ssg-audit_rules_privileged_commands_su_action:testaction:1 - - - - Ensure auditd Collects Information on the Use of Privileged Commands - sudo - - ocil:ssg-audit_rules_privileged_commands_sudo_action:testaction:1 - - - - Ensure auditd Collects Information on the Use of Privileged Commands - sudoedit - - ocil:ssg-audit_rules_privileged_commands_sudoedit_action:testaction:1 - - - - Ensure auditd Collects Information on the Use of Privileged Commands - umount - - ocil:ssg-audit_rules_privileged_commands_umount_action:testaction:1 - - - - Ensure auditd Collects Information on the Use of Privileged Commands - unix_chkpwd - - ocil:ssg-audit_rules_privileged_commands_unix_chkpwd_action:testaction:1 - - - - Ensure auditd Collects Information on the Use of Privileged Commands - unix_update - - ocil:ssg-audit_rules_privileged_commands_unix_update_action:testaction:1 - - - - Ensure auditd Collects Information on the Use of Privileged Commands - userhelper - - ocil:ssg-audit_rules_privileged_commands_userhelper_action:testaction:1 - - - - Ensure auditd Collects Information on the Use of Privileged Commands - usermod - - ocil:ssg-audit_rules_privileged_commands_usermod_action:testaction:1 - - - - Ensure auditd Collects Information on the Use of Privileged Commands - usernetctl - - ocil:ssg-audit_rules_privileged_commands_usernetctl_action:testaction:1 - - - - Record attempts to alter time through adjtimex - - ocil:ssg-audit_rules_time_adjtimex_action:testaction:1 - - - - Record Attempts to Alter Time Through clock_settime - - ocil:ssg-audit_rules_time_clock_settime_action:testaction:1 - - - - Record attempts to alter time through settimeofday - - ocil:ssg-audit_rules_time_settimeofday_action:testaction:1 - - - - Record Attempts to Alter the localtime File - - ocil:ssg-audit_rules_time_watch_localtime_action:testaction:1 - - - - Make the auditd Configuration Immutable - - ocil:ssg-audit_rules_immutable_action:testaction:1 - - - - Record Events that Modify the System's Mandatory Access Controls - - ocil:ssg-audit_rules_mac_modification_action:testaction:1 - - - - Record Events that Modify the System's Mandatory Access Controls in usr/share - - ocil:ssg-audit_rules_mac_modification_usr_share_action:testaction:1 - - - - Ensure auditd Collects Information on Exporting to Media (successful) - - ocil:ssg-audit_rules_media_export_action:testaction:1 - - - - Record Events that Modify the System's Network Environment - - ocil:ssg-audit_rules_networkconfig_modification_action:testaction:1 - - - - Ensure auditd Collects System Administrator Actions - /etc/sudoers - - ocil:ssg-audit_rules_sudoers_action:testaction:1 - - - - Ensure auditd Collects System Administrator Actions - /etc/sudoers.d/ - - ocil:ssg-audit_rules_sudoers_d_action:testaction:1 - - - - Record Events When Privileged Executables Are Run - - ocil:ssg-audit_rules_suid_privilege_function_action:testaction:1 - - - - Ensure auditd Collects System Administrator Actions - - ocil:ssg-audit_rules_sysadmin_actions_action:testaction:1 - - - - Shutdown System When Auditing Failures Occur - - ocil:ssg-audit_rules_system_shutdown_action:testaction:1 - - - - Record Events that Modify User/Group Information - - ocil:ssg-audit_rules_usergroup_modification_action:testaction:1 - - - - Record Events that Modify User/Group Information - /etc/group - - ocil:ssg-audit_rules_usergroup_modification_group_action:testaction:1 - - - - Record Events that Modify User/Group Information - /etc/gshadow - - ocil:ssg-audit_rules_usergroup_modification_gshadow_action:testaction:1 - - - - Record Events that Modify User/Group Information - /etc/security/opasswd - - ocil:ssg-audit_rules_usergroup_modification_opasswd_action:testaction:1 - - - - Record Events that Modify User/Group Information - /etc/passwd - - ocil:ssg-audit_rules_usergroup_modification_passwd_action:testaction:1 - - - - Record Events that Modify User/Group Information - /etc/shadow - - ocil:ssg-audit_rules_usergroup_modification_shadow_action:testaction:1 - - - - Record Access Events to Audit Log Directory - - ocil:ssg-directory_access_var_log_audit_action:testaction:1 - - - - System Audit Directories Must Be Group Owned By Root - - ocil:ssg-directory_group_ownership_var_log_audit_action:testaction:1 - - - - System Audit Directories Must Be Owned By Root - - ocil:ssg-directory_ownership_var_log_audit_action:testaction:1 - - - - System Audit Logs Must Have Mode 0750 or Less Permissive - - ocil:ssg-directory_permissions_var_log_audit_action:testaction:1 - - - - System Audit Logs Must Be Group Owned By Root - - ocil:ssg-file_group_ownership_var_log_audit_action:testaction:1 - - - - Audit Configuration Files Must Be Owned By Group root - - ocil:ssg-file_groupownership_audit_configuration_action:testaction:1 - - - - Audit Configuration Files Must Be Owned By Root - - ocil:ssg-file_ownership_audit_configuration_action:testaction:1 - - - - System Audit Logs Must Be Owned By Root - - ocil:ssg-file_ownership_var_log_audit_action:testaction:1 - - - - System Audit Logs Must Be Owned By Root - - ocil:ssg-file_ownership_var_log_audit_stig_action:testaction:1 - - - - Audit Configuration Files Permissions are 640 or More Restrictive - - ocil:ssg-file_permissions_audit_configuration_action:testaction:1 - - - - System Audit Logs Must Have Mode 0640 or Less Permissive - - ocil:ssg-file_permissions_var_log_audit_action:testaction:1 - - - - Configure a Sufficiently Large Partition for Audit Logs - - ocil:ssg-auditd_audispd_configure_sufficiently_large_partition_action:testaction:1 - - - - Configure auditd to use audispd's syslog plugin - - ocil:ssg-auditd_audispd_syslog_plugin_activated_action:testaction:1 - - - - Configure auditd Disk Error Action on Disk Error - - ocil:ssg-auditd_data_disk_error_action_action:testaction:1 - - - - Configure auditd Disk Error Action on Disk Error - - ocil:ssg-auditd_data_disk_error_action_stig_action:testaction:1 - - - - Configure auditd Disk Full Action when Disk Space Is Full - - ocil:ssg-auditd_data_disk_full_action_action:testaction:1 - - - - Configure auditd Disk Full Action when Disk Space Is Full - - ocil:ssg-auditd_data_disk_full_action_stig_action:testaction:1 - - - - Configure auditd mail_acct Action on Low Disk Space - - ocil:ssg-auditd_data_retention_action_mail_acct_action:testaction:1 - - - - Configure auditd admin_space_left Action on Low Disk Space - - ocil:ssg-auditd_data_retention_admin_space_left_action_action:testaction:1 - - - - Configure auditd admin_space_left on Low Disk Space - - ocil:ssg-auditd_data_retention_admin_space_left_percentage_action:testaction:1 - - - - Configure auditd flush priority - - ocil:ssg-auditd_data_retention_flush_action:testaction:1 - - - - Configure auditd Max Log File Size - - ocil:ssg-auditd_data_retention_max_log_file_action:testaction:1 - - - - Configure auditd max_log_file_action Upon Reaching Maximum Log Size - - ocil:ssg-auditd_data_retention_max_log_file_action_action:testaction:1 - - - - Configure auditd max_log_file_action Upon Reaching Maximum Log Size - - ocil:ssg-auditd_data_retention_max_log_file_action_stig_action:testaction:1 - - - - Configure auditd Number of Logs Retained - - ocil:ssg-auditd_data_retention_num_logs_action:testaction:1 - - - - Configure auditd space_left Action on Low Disk Space - - ocil:ssg-auditd_data_retention_space_left_action_action:testaction:1 - - - - Configure auditd space_left on Low Disk Space - - ocil:ssg-auditd_data_retention_space_left_percentage_action:testaction:1 - - - - Set number of records to cause an explicit flush to audit logs - - ocil:ssg-auditd_freq_action:testaction:1 - - - - Include Local Events in Audit Logs - - ocil:ssg-auditd_local_events_action:testaction:1 - - - - Resolve information before writing to audit logs - - ocil:ssg-auditd_log_format_action:testaction:1 - - - - Set hostname as computer node name in audit logs - - ocil:ssg-auditd_name_format_action:testaction:1 - - - - Appropriate Action Must be Setup When the Internal Audit Event Queue is Full - - ocil:ssg-auditd_overflow_action_action:testaction:1 - - - - Write Audit Logs to the Disk - - ocil:ssg-auditd_write_logs_action:testaction:1 - - - - Configure auditing of unsuccessful file accesses - - ocil:ssg-audit_access_failed_action:testaction:1 - - - - Configure auditing of successful file accesses - - ocil:ssg-audit_access_success_action:testaction:1 - - - - Configure basic parameters of Audit system - - ocil:ssg-audit_basic_configuration_action:testaction:1 - - - - Configure auditing of unsuccessful file creations - - ocil:ssg-audit_create_failed_action:testaction:1 - - - - Configure auditing of successful file creations - - ocil:ssg-audit_create_success_action:testaction:1 - - - - Configure auditing of unsuccessful file deletions - - ocil:ssg-audit_delete_failed_action:testaction:1 - - - - Configure auditing of successful file deletions - - ocil:ssg-audit_delete_success_action:testaction:1 - - - - Configure immutable Audit login UIDs - - ocil:ssg-audit_immutable_login_uids_action:testaction:1 - - - - Configure auditing of unsuccessful file modifications - - ocil:ssg-audit_modify_failed_action:testaction:1 - - - - Configure auditing of successful file modifications - - ocil:ssg-audit_modify_success_action:testaction:1 - - - - Configure auditing of loading and unloading of kernel modules - - ocil:ssg-audit_module_load_action:testaction:1 - - - - Perform general configuration of Audit for OSPP - - ocil:ssg-audit_ospp_general_action:testaction:1 - - - - Configure auditing of unsuccessful ownership changes - - ocil:ssg-audit_owner_change_failed_action:testaction:1 - - - - Configure auditing of successful ownership changes - - ocil:ssg-audit_owner_change_success_action:testaction:1 - - - - Configure auditing of unsuccessful permission changes - - ocil:ssg-audit_perm_change_failed_action:testaction:1 - - - - Configure auditing of successful permission changes - - ocil:ssg-audit_perm_change_success_action:testaction:1 - - - - Enable Auditing for Processes Which Start Prior to the Audit Daemon - - ocil:ssg-grub2_audit_argument_action:testaction:1 - - - - Extend Audit Backlog Limit for the Audit Daemon - - ocil:ssg-grub2_audit_backlog_limit_argument_action:testaction:1 - - - - Install audispd-plugins Package - - ocil:ssg-package_audispd-plugins_installed_action:testaction:1 - - - - Ensure the default plugins for the audit dispatcher are Installed - - ocil:ssg-package_audit-audispd-plugins_installed_action:testaction:1 - - - - Ensure the audit Subsystem is Installed - - ocil:ssg-package_audit_installed_action:testaction:1 - - - - Enable auditd Service - - ocil:ssg-service_auditd_enabled_action:testaction:1 - - - - Verify /boot/grub2/grub.cfg Group Ownership - - ocil:ssg-file_groupowner_grub2_cfg_action:testaction:1 - - - - Verify /boot/grub2/user.cfg Group Ownership - - ocil:ssg-file_groupowner_user_cfg_action:testaction:1 - - - - Verify /boot/grub2/grub.cfg User Ownership - - ocil:ssg-file_owner_grub2_cfg_action:testaction:1 - - - - Verify /boot/grub2/user.cfg User Ownership - - ocil:ssg-file_owner_user_cfg_action:testaction:1 - - - - Set the Boot Loader Admin Username to a Non-Default Value - - ocil:ssg-grub2_admin_username_action:testaction:1 - - - - Set Boot Loader Password in grub2 - - ocil:ssg-grub2_password_action:testaction:1 - - - - Verify /boot/grub2/user.cfg Group Ownership - - ocil:ssg-file_groupowner_efi_user_cfg_action:testaction:1 - - - - Set the UEFI Boot Loader Admin Username to a Non-Default Value - - ocil:ssg-grub2_uefi_admin_username_action:testaction:1 - - - - Set the UEFI Boot Loader Password - - ocil:ssg-grub2_uefi_password_action:testaction:1 - - - - Disable Recovery Booting - - ocil:ssg-grub2_disable_recovery_action:testaction:1 - - - - IOMMU configuration directive - - ocil:ssg-grub2_enable_iommu_force_action:testaction:1 - - - - Configure kernel to zero out memory before allocation - - ocil:ssg-grub2_init_on_alloc_argument_action:testaction:1 - - - - Configure L1 Terminal Fault mitigations - - ocil:ssg-grub2_l1tf_argument_action:testaction:1 - - - - Force kernel panic on uncorrected MCEs - - ocil:ssg-grub2_mce_argument_action:testaction:1 - - - - Ensure SMAP is not disabled during boot - - ocil:ssg-grub2_nosmap_argument_absent_action:testaction:1 - - - - Ensure SMEP is not disabled during boot - - ocil:ssg-grub2_nosmep_argument_absent_action:testaction:1 - - - - Enable randomization of the page allocator - - ocil:ssg-grub2_page_alloc_shuffle_argument_action:testaction:1 - - - - Enable Kernel Page-Table Isolation (KPTI) - - ocil:ssg-grub2_pti_argument_action:testaction:1 - - - - Configure the confidence in TPM for entropy - - ocil:ssg-grub2_rng_core_default_quality_argument_action:testaction:1 - - - - Disable merging of slabs with similar size - - ocil:ssg-grub2_slab_nomerge_argument_action:testaction:1 - - - - Configure Speculative Store Bypass Mitigation - - ocil:ssg-grub2_spec_store_bypass_disable_argument_action:testaction:1 - - - - Enforce Spectre v2 mitigation - - ocil:ssg-grub2_spectre_v2_argument_action:testaction:1 - - - - Ensure debug-shell service is not enabled during boot - - ocil:ssg-grub2_systemd_debug-shell_argument_absent_action:testaction:1 - - - - Disable vsyscalls - - ocil:ssg-grub2_vsyscall_argument_action:testaction:1 - - - - Do not allow ACPI methods to be inserted/replaced at run time - - ocil:ssg-kernel_config_acpi_custom_method_action:testaction:1 - - - - Disable kernel support for MISC binaries - - ocil:ssg-kernel_config_binfmt_misc_action:testaction:1 - - - - Enable support for BUG() - - ocil:ssg-kernel_config_bug_action:testaction:1 - - - - Disable compatibility with brk() - - ocil:ssg-kernel_config_compat_brk_action:testaction:1 - - - - Disable the 32-bit vDSO - - ocil:ssg-kernel_config_compat_vdso_action:testaction:1 - - - - Enable checks on credential management - - ocil:ssg-kernel_config_debug_credentials_action:testaction:1 - - - - Disable kernel debugfs - - ocil:ssg-kernel_config_debug_fs_action:testaction:1 - - - - Enable checks on linked list manipulation - - ocil:ssg-kernel_config_debug_list_action:testaction:1 - - - - Enable checks on notifier call chains - - ocil:ssg-kernel_config_debug_notifiers_action:testaction:1 - - - - Enable checks on scatter-gather (SG) table operations - - ocil:ssg-kernel_config_debug_sg_action:testaction:1 - - - - Configure low address space to protect from user allocation - - ocil:ssg-kernel_config_default_mmap_min_addr_action:testaction:1 - - - - Disable /dev/kmem virtual device support - - ocil:ssg-kernel_config_devkmem_action:testaction:1 - - - - Disable hibernation - - ocil:ssg-kernel_config_hibernation_action:testaction:1 - - - - Disable IA32 emulation - - ocil:ssg-kernel_config_ia32_emulation_action:testaction:1 - - - - Disable the IPv6 protocol - - ocil:ssg-kernel_config_ipv6_action:testaction:1 - - - - Disable kexec system call - - ocil:ssg-kernel_config_kexec_action:testaction:1 - - - - Disable legacy (BSD) PTY support - - ocil:ssg-kernel_config_legacy_ptys_action:testaction:1 - - - - Enable module signature verification - - ocil:ssg-kernel_config_module_sig_action:testaction:1 - - - - Enable automatic signing of all modules - - ocil:ssg-kernel_config_module_sig_all_action:testaction:1 - - - - Require modules to be validly signed - - ocil:ssg-kernel_config_module_sig_force_action:testaction:1 - - - - Specify the hash to use when signing modules - - ocil:ssg-kernel_config_module_sig_hash_action:testaction:1 - - - - Specify module signing key to use - - ocil:ssg-kernel_config_module_sig_key_action:testaction:1 - - - - Sign kernel modules with SHA-512 - - ocil:ssg-kernel_config_module_sig_sha512_action:testaction:1 - - - - Enable poison without sanity check - - ocil:ssg-kernel_config_page_poisoning_no_sanity_action:testaction:1 - - - - Use zero for poisoning instead of debugging value - - ocil:ssg-kernel_config_page_poisoning_zero_action:testaction:1 - - - - Remove the kernel mapping in user mode - - ocil:ssg-kernel_config_page_table_isolation_action:testaction:1 - - - - Kernel panic oops - - ocil:ssg-kernel_config_panic_on_oops_action:testaction:1 - - - - Kernel panic timeout - - ocil:ssg-kernel_config_panic_timeout_action:testaction:1 - - - - Disable support for /proc/kkcore - - ocil:ssg-kernel_config_proc_kcore_action:testaction:1 - - - - Randomize the address of the kernel image (KASLR) - - ocil:ssg-kernel_config_randomize_base_action:testaction:1 - - - - Randomize the kernel memory sections - - ocil:ssg-kernel_config_randomize_memory_action:testaction:1 - - - - Avoid speculative indirect branches in kernel - - ocil:ssg-kernel_config_retpoline_action:testaction:1 - - - - Enable seccomp to safely compute untrusted bytecode - - ocil:ssg-kernel_config_seccomp_action:testaction:1 - - - - Enable use of Berkeley Packet Filter with seccomp - - ocil:ssg-kernel_config_seccomp_filter_action:testaction:1 - - - - Enable different security models - - ocil:ssg-kernel_config_security_action:testaction:1 - - - - Restrict unprivileged access to the kernel syslog - - ocil:ssg-kernel_config_security_dmesg_restrict_action:testaction:1 - - - - Disable mutable hooks - - ocil:ssg-kernel_config_security_writable_hooks_action:testaction:1 - - - - Enable Yama support - - ocil:ssg-kernel_config_security_yama_action:testaction:1 - - - - Enable SLUB debugging support - - ocil:ssg-kernel_config_slub_debug_action:testaction:1 - - - - Enable TCP/IP syncookie support - - ocil:ssg-kernel_config_syn_cookies_action:testaction:1 - - - - Unmap kernel when running in userspace (aka KAISER) - - ocil:ssg-kernel_config_unmap_kernel_at_el0_action:testaction:1 - - - - Disable x86 vsyscall emulation - - ocil:ssg-kernel_config_x86_vsyscall_emulation_action:testaction:1 - - - - Ensure cron Is Logging To Rsyslog - - ocil:ssg-rsyslog_cron_logging_action:testaction:1 - - - - Ensure Rsyslog Authenticates Off-Loaded Audit Records - - ocil:ssg-rsyslog_encrypt_offload_actionsendstreamdriverauthmode_action:testaction:1 - - - - Ensure Rsyslog Encrypts Off-Loaded Audit Records - - ocil:ssg-rsyslog_encrypt_offload_actionsendstreamdrivermode_action:testaction:1 - - - - Ensure Rsyslog Encrypts Off-Loaded Audit Records - - ocil:ssg-rsyslog_encrypt_offload_defaultnetstreamdriver_action:testaction:1 - - - - Ensure Log Files Are Owned By Appropriate Group - - ocil:ssg-rsyslog_files_groupownership_action:testaction:1 - - - - Ensure Log Files Are Owned By Appropriate User - - ocil:ssg-rsyslog_files_ownership_action:testaction:1 - - - - Ensure System Log Files Have Correct Permissions - - ocil:ssg-rsyslog_files_permissions_action:testaction:1 - - - - Ensure remote access methods are monitored in Rsyslog - - ocil:ssg-rsyslog_remote_access_monitoring_action:testaction:1 - - - - Enable systemd-journald Service - - ocil:ssg-service_systemd-journald_enabled_action:testaction:1 - - - - Ensure Logrotate Runs Periodically - - ocil:ssg-ensure_logrotate_activated_action:testaction:1 - - - - Ensure logrotate is Installed - - ocil:ssg-package_logrotate_installed_action:testaction:1 - - - - Enable logrotate Timer - - ocil:ssg-timer_logrotate_enabled_action:testaction:1 - - - - Ensure syslog-ng is Installed - - ocil:ssg-package_syslogng_installed_action:testaction:1 - - - - Ensure rsyslog Does Not Accept Remote Messages Unless Acting As Log Server - - ocil:ssg-rsyslog_nolisten_action:testaction:1 - - - - Enable syslog-ng Service - - ocil:ssg-service_syslogng_enabled_action:testaction:1 - - - - Ensure Logs Sent To Remote Host - - ocil:ssg-rsyslog_remote_loghost_action:testaction:1 - - - - Configure TLS for rsyslog remote logging - - ocil:ssg-rsyslog_remote_tls_action:testaction:1 - - - - Configure CA certificate for rsyslog remote logging - - ocil:ssg-rsyslog_remote_tls_cacert_action:testaction:1 - - - - Ensure rsyslog-gnutls is installed - - ocil:ssg-package_rsyslog-gnutls_installed_action:testaction:1 - - - - Ensure rsyslog is Installed - - ocil:ssg-package_rsyslog_installed_action:testaction:1 - - - - Enable rsyslog Service - - ocil:ssg-service_rsyslog_enabled_action:testaction:1 - - - - Install firewalld Package - - ocil:ssg-package_firewalld_installed_action:testaction:1 - - - - Verify firewalld Enabled - - ocil:ssg-service_firewalld_enabled_action:testaction:1 - - - - Configure the Firewalld Ports - - ocil:ssg-configure_firewalld_ports_action:testaction:1 - - - - Firewalld Must Employ a Deny-all, Allow-by-exception Policy for Allowing Connections to Other Systems - - ocil:ssg-configured_firewalld_default_deny_action:testaction:1 - - - - Set Default firewalld Zone for Incoming Packets - - ocil:ssg-set_firewalld_default_zone_action:testaction:1 - - - - Configure Firewalld to Use the Nftables Backend - - ocil:ssg-firewalld-backend_action:testaction:1 - - - - Verify Any Configured IPSec Tunnel Connections - - ocil:ssg-libreswan_approved_tunnels_action:testaction:1 - - - - Install libreswan Package - - ocil:ssg-package_libreswan_installed_action:testaction:1 - - - - Verify ip6tables Enabled if Using IPv6 - - ocil:ssg-service_ip6tables_enabled_action:testaction:1 - - - - Verify iptables Enabled - - ocil:ssg-service_iptables_enabled_action:testaction:1 - - - - Set Default ip6tables Policy for Incoming Packets - - ocil:ssg-set_ip6tables_default_rule_action:testaction:1 - - - - Set configuration for IPv6 loopback traffic - - ocil:ssg-set_ipv6_loopback_traffic_action:testaction:1 - - - - Set configuration for loopback traffic - - ocil:ssg-set_loopback_traffic_action:testaction:1 - - - - Set Default iptables Policy for Incoming Packets - - ocil:ssg-set_iptables_default_rule_action:testaction:1 - - - - Set Default iptables Policy for Forwarded Packets - - ocil:ssg-set_iptables_default_rule_forward_action:testaction:1 - - - - Configure Accepting Router Advertisements on All IPv6 Interfaces - - ocil:ssg-sysctl_net_ipv6_conf_all_accept_ra_action:testaction:1 - - - - Configure Accepting Default Router in Router Advertisements on All IPv6 Interfaces - - ocil:ssg-sysctl_net_ipv6_conf_all_accept_ra_defrtr_action:testaction:1 - - - - Configure Accepting Prefix Information in Router Advertisements on All IPv6 Interfaces - - ocil:ssg-sysctl_net_ipv6_conf_all_accept_ra_pinfo_action:testaction:1 - - - - Configure Accepting Router Preference in Router Advertisements on All IPv6 Interfaces - - ocil:ssg-sysctl_net_ipv6_conf_all_accept_ra_rtr_pref_action:testaction:1 - - - - Disable Accepting ICMP Redirects for All IPv6 Interfaces - - ocil:ssg-sysctl_net_ipv6_conf_all_accept_redirects_action:testaction:1 - - - - Disable Kernel Parameter for Accepting Source-Routed Packets on all IPv6 Interfaces - - ocil:ssg-sysctl_net_ipv6_conf_all_accept_source_route_action:testaction:1 - - - - Configure Auto Configuration on All IPv6 Interfaces - - ocil:ssg-sysctl_net_ipv6_conf_all_autoconf_action:testaction:1 - - - - Disable Kernel Parameter for IPv6 Forwarding - - ocil:ssg-sysctl_net_ipv6_conf_all_forwarding_action:testaction:1 - - - - Configure Maximum Number of Autoconfigured Addresses on All IPv6 Interfaces - - ocil:ssg-sysctl_net_ipv6_conf_all_max_addresses_action:testaction:1 - - - - Configure Denying Router Solicitations on All IPv6 Interfaces - - ocil:ssg-sysctl_net_ipv6_conf_all_router_solicitations_action:testaction:1 - - - - Disable Accepting Router Advertisements on all IPv6 Interfaces by Default - - ocil:ssg-sysctl_net_ipv6_conf_default_accept_ra_action:testaction:1 - - - - Configure Accepting Default Router in Router Advertisements on All IPv6 Interfaces By Default - - ocil:ssg-sysctl_net_ipv6_conf_default_accept_ra_defrtr_action:testaction:1 - - - - Configure Accepting Prefix Information in Router Advertisements on All IPv6 Interfaces By Default - - ocil:ssg-sysctl_net_ipv6_conf_default_accept_ra_pinfo_action:testaction:1 - - - - Configure Accepting Router Preference in Router Advertisements on All IPv6 Interfaces By Default - - ocil:ssg-sysctl_net_ipv6_conf_default_accept_ra_rtr_pref_action:testaction:1 - - - - Disable Kernel Parameter for Accepting ICMP Redirects by Default on IPv6 Interfaces - - ocil:ssg-sysctl_net_ipv6_conf_default_accept_redirects_action:testaction:1 - - - - Disable Kernel Parameter for Accepting Source-Routed Packets on IPv6 Interfaces by Default - - ocil:ssg-sysctl_net_ipv6_conf_default_accept_source_route_action:testaction:1 - - - - Configure Auto Configuration on All IPv6 Interfaces By Default - - ocil:ssg-sysctl_net_ipv6_conf_default_autoconf_action:testaction:1 - - - - Configure Maximum Number of Autoconfigured Addresses on All IPv6 Interfaces By Default - - ocil:ssg-sysctl_net_ipv6_conf_default_max_addresses_action:testaction:1 - - - - Configure Denying Router Solicitations on All IPv6 Interfaces By Default - - ocil:ssg-sysctl_net_ipv6_conf_default_router_solicitations_action:testaction:1 - - - - Disable IPv6 Networking Support Automatic Loading - - ocil:ssg-kernel_module_ipv6_option_disabled_action:testaction:1 - - - - Disable IPv6 Addressing on All IPv6 Interfaces - - ocil:ssg-sysctl_net_ipv6_conf_all_disable_ipv6_action:testaction:1 - - - - Disable IPv6 Addressing on IPv6 Interfaces by Default - - ocil:ssg-sysctl_net_ipv6_conf_default_disable_ipv6_action:testaction:1 - - - - Disable Accepting Packets Routed Between Local Interfaces - - ocil:ssg-sysctl_net_ipv4_conf_all_accept_local_action:testaction:1 - - - - Disable Accepting ICMP Redirects for All IPv4 Interfaces - - ocil:ssg-sysctl_net_ipv4_conf_all_accept_redirects_action:testaction:1 - - - - Disable Kernel Parameter for Accepting Source-Routed Packets on all IPv4 Interfaces - - ocil:ssg-sysctl_net_ipv4_conf_all_accept_source_route_action:testaction:1 - - - - Configure ARP filtering for All IPv4 Interfaces - - ocil:ssg-sysctl_net_ipv4_conf_all_arp_filter_action:testaction:1 - - - - Configure Response Mode of ARP Requests for All IPv4 Interfaces - - ocil:ssg-sysctl_net_ipv4_conf_all_arp_ignore_action:testaction:1 - - - - Drop Gratuitious ARP frames on All IPv4 Interfaces - - ocil:ssg-sysctl_net_ipv4_conf_all_drop_gratuitous_arp_action:testaction:1 - - - - Enable Kernel Parameter to Log Martian Packets on all IPv4 Interfaces - - ocil:ssg-sysctl_net_ipv4_conf_all_log_martians_action:testaction:1 - - - - Prevent Routing External Traffic to Local Loopback on All IPv4 Interfaces - - ocil:ssg-sysctl_net_ipv4_conf_all_route_localnet_action:testaction:1 - - - - Enable Kernel Parameter to Use Reverse Path Filtering on all IPv4 Interfaces - - ocil:ssg-sysctl_net_ipv4_conf_all_rp_filter_action:testaction:1 - - - - Disable Kernel Parameter for Accepting Secure ICMP Redirects on all IPv4 Interfaces - - ocil:ssg-sysctl_net_ipv4_conf_all_secure_redirects_action:testaction:1 - - - - Configure Sending and Accepting Shared Media Redirects for All IPv4 Interfaces - - ocil:ssg-sysctl_net_ipv4_conf_all_shared_media_action:testaction:1 - - - - Disable Kernel Parameter for Accepting ICMP Redirects by Default on IPv4 Interfaces - - ocil:ssg-sysctl_net_ipv4_conf_default_accept_redirects_action:testaction:1 - - - - Disable Kernel Parameter for Accepting Source-Routed Packets on IPv4 Interfaces by Default - - ocil:ssg-sysctl_net_ipv4_conf_default_accept_source_route_action:testaction:1 - - - - Enable Kernel Paremeter to Log Martian Packets on all IPv4 Interfaces by Default - - ocil:ssg-sysctl_net_ipv4_conf_default_log_martians_action:testaction:1 - - - - Enable Kernel Parameter to Use Reverse Path Filtering on all IPv4 Interfaces by Default - - ocil:ssg-sysctl_net_ipv4_conf_default_rp_filter_action:testaction:1 - - - - Configure Kernel Parameter for Accepting Secure Redirects By Default - - ocil:ssg-sysctl_net_ipv4_conf_default_secure_redirects_action:testaction:1 - - - - Configure Sending and Accepting Shared Media Redirects by Default - - ocil:ssg-sysctl_net_ipv4_conf_default_shared_media_action:testaction:1 - - - - Enable Kernel Parameter to Ignore ICMP Broadcast Echo Requests on IPv4 Interfaces - - ocil:ssg-sysctl_net_ipv4_icmp_echo_ignore_broadcasts_action:testaction:1 - - - - Enable Kernel Parameter to Ignore Bogus ICMP Error Responses on IPv4 Interfaces - - ocil:ssg-sysctl_net_ipv4_icmp_ignore_bogus_error_responses_action:testaction:1 - - - - Set Kernel Parameter to Increase Local Port Range - - ocil:ssg-sysctl_net_ipv4_ip_local_port_range_action:testaction:1 - - - - Configure Kernel to Rate Limit Sending of Duplicate TCP Acknowledgments - - ocil:ssg-sysctl_net_ipv4_tcp_invalid_ratelimit_action:testaction:1 - - - - Enable Kernel Parameter to Use TCP RFC 1337 on IPv4 Interfaces - - ocil:ssg-sysctl_net_ipv4_tcp_rfc1337_action:testaction:1 - - - - Enable Kernel Parameter to Use TCP Syncookies on Network Interfaces - - ocil:ssg-sysctl_net_ipv4_tcp_syncookies_action:testaction:1 - - - - Disable Kernel Parameter for Sending ICMP Redirects on all IPv4 Interfaces - - ocil:ssg-sysctl_net_ipv4_conf_all_send_redirects_action:testaction:1 - - - - Disable Kernel Parameter for Sending ICMP Redirects on all IPv4 Interfaces by Default - - ocil:ssg-sysctl_net_ipv4_conf_default_send_redirects_action:testaction:1 - - - - Disable Kernel Parameter for IP Forwarding on IPv4 Interfaces - - ocil:ssg-sysctl_net_ipv4_ip_forward_action:testaction:1 - - - - Verify ufw Enabled - - ocil:ssg-service_ufw_enabled_action:testaction:1 - - - - Disable ATM Support - - ocil:ssg-kernel_module_atm_disabled_action:testaction:1 - - - - Disable CAN Support - - ocil:ssg-kernel_module_can_disabled_action:testaction:1 - - - - Disable IEEE 1394 (FireWire) Support - - ocil:ssg-kernel_module_firewire-core_disabled_action:testaction:1 - - - - Disable RDS Support - - ocil:ssg-kernel_module_rds_disabled_action:testaction:1 - - - - Disable SCTP Support - - ocil:ssg-kernel_module_sctp_disabled_action:testaction:1 - - - - Disable TIPC Support - - ocil:ssg-kernel_module_tipc_disabled_action:testaction:1 - - - - Disable Bluetooth Kernel Module - - ocil:ssg-kernel_module_bluetooth_disabled_action:testaction:1 - - - - Deactivate Wireless Network Interfaces - - ocil:ssg-wireless_disable_interfaces_action:testaction:1 - - - - Configure Multiple DNS Servers in /etc/resolv.conf - - ocil:ssg-network_configure_name_resolution_action:testaction:1 - - - - Ensure System is Not Acting as a Network Sniffer - - ocil:ssg-network_sniffer_disabled_action:testaction:1 - - - - Verify Group Who Owns Backup group File - - ocil:ssg-file_groupowner_backup_etc_group_action:testaction:1 - - - - Verify Group Who Owns Backup gshadow File - - ocil:ssg-file_groupowner_backup_etc_gshadow_action:testaction:1 - - - - Verify Group Who Owns Backup passwd File - - ocil:ssg-file_groupowner_backup_etc_passwd_action:testaction:1 - - - - Verify User Who Owns Backup shadow File - - ocil:ssg-file_groupowner_backup_etc_shadow_action:testaction:1 - - - - Verify Group Who Owns group File - - ocil:ssg-file_groupowner_etc_group_action:testaction:1 - - - - Verify Group Who Owns gshadow File - - ocil:ssg-file_groupowner_etc_gshadow_action:testaction:1 - - - - Verify Group Who Owns passwd File - - ocil:ssg-file_groupowner_etc_passwd_action:testaction:1 - - - - Verify Group Who Owns shadow File - - ocil:ssg-file_groupowner_etc_shadow_action:testaction:1 - - - - Verify User Who Owns Backup group File - - ocil:ssg-file_owner_backup_etc_group_action:testaction:1 - - - - Verify User Who Owns Backup gshadow File - - ocil:ssg-file_owner_backup_etc_gshadow_action:testaction:1 - - - - Verify User Who Owns Backup passwd File - - ocil:ssg-file_owner_backup_etc_passwd_action:testaction:1 - - - - Verify Group Who Owns Backup shadow File - - ocil:ssg-file_owner_backup_etc_shadow_action:testaction:1 - - - - Verify User Who Owns group File - - ocil:ssg-file_owner_etc_group_action:testaction:1 - - - - Verify User Who Owns gshadow File - - ocil:ssg-file_owner_etc_gshadow_action:testaction:1 - - - - Verify User Who Owns passwd File - - ocil:ssg-file_owner_etc_passwd_action:testaction:1 - - - - Verify User Who Owns shadow File - - ocil:ssg-file_owner_etc_shadow_action:testaction:1 - - - - Verify Permissions on Backup group File - - ocil:ssg-file_permissions_backup_etc_group_action:testaction:1 - - - - Verify Permissions on Backup gshadow File - - ocil:ssg-file_permissions_backup_etc_gshadow_action:testaction:1 - - - - Verify Permissions on Backup passwd File - - ocil:ssg-file_permissions_backup_etc_passwd_action:testaction:1 - - - - Verify Permissions on Backup shadow File - - ocil:ssg-file_permissions_backup_etc_shadow_action:testaction:1 - - - - Verify Permissions on group File - - ocil:ssg-file_permissions_etc_group_action:testaction:1 - - - - Verify Permissions on gshadow File - - ocil:ssg-file_permissions_etc_gshadow_action:testaction:1 - - - - Verify Permissions on passwd File - - ocil:ssg-file_permissions_etc_passwd_action:testaction:1 - - - - Verify Permissions on shadow File - - ocil:ssg-file_permissions_etc_shadow_action:testaction:1 - - - - Verify Group Who Owns /var/log Directory - - ocil:ssg-file_groupowner_var_log_action:testaction:1 - - - - Verify Group Who Owns /var/log/messages File - - ocil:ssg-file_groupowner_var_log_messages_action:testaction:1 - - - - Verify Group Who Owns /var/log/syslog File - - ocil:ssg-file_groupowner_var_log_syslog_action:testaction:1 - - - - Verify User Who Owns /var/log Directory - - ocil:ssg-file_owner_var_log_action:testaction:1 - - - - Verify User Who Owns /var/log/messages File - - ocil:ssg-file_owner_var_log_messages_action:testaction:1 - - - - Verify User Who Owns /var/log/syslog File - - ocil:ssg-file_owner_var_log_syslog_action:testaction:1 - - - - Verify Permissions on /var/log Directory - - ocil:ssg-file_permissions_var_log_action:testaction:1 - - - - Verify Permissions on /var/log/messages File - - ocil:ssg-file_permissions_var_log_messages_action:testaction:1 - - - - Verify Permissions on /var/log/syslog File - - ocil:ssg-file_permissions_var_log_syslog_action:testaction:1 - - - - Verify that Shared Library Directories Have Root Group Ownership - - ocil:ssg-dir_group_ownership_library_dirs_action:testaction:1 - - - - Verify that System Executable Have Root Ownership - - ocil:ssg-dir_ownership_binary_dirs_action:testaction:1 - - - - Verify that Shared Library Directories Have Root Ownership - - ocil:ssg-dir_ownership_library_dirs_action:testaction:1 - - - - Verify that System Executable Directories Have Restrictive Permissions - - ocil:ssg-dir_permissions_binary_dirs_action:testaction:1 - - - - Verify that Shared Library Directories Have Restrictive Permissions - - ocil:ssg-dir_permissions_library_dirs_action:testaction:1 - - - - Verify that system commands files are group owned by root or a system account - - ocil:ssg-file_groupownership_system_commands_dirs_action:testaction:1 - - - - Verify that System Executables Have Root Ownership - - ocil:ssg-file_ownership_binary_dirs_action:testaction:1 - - - - Verify that Shared Library Files Have Root Ownership - - ocil:ssg-file_ownership_library_dirs_action:testaction:1 - - - - Verify that System Executables Have Restrictive Permissions - - ocil:ssg-file_permissions_binary_dirs_action:testaction:1 - - - - Verify that Shared Library Files Have Restrictive Permissions - - ocil:ssg-file_permissions_library_dirs_action:testaction:1 - - - - Verify the system-wide library files in directories -"/lib", "/lib64", "/usr/lib/" and "/usr/lib64" are group-owned by root. - - ocil:ssg-root_permissions_syslibrary_files_action:testaction:1 - - - - Ensure All World-Writable Directories Are Owned by root User - - ocil:ssg-dir_perms_world_writable_root_owned_action:testaction:1 - - - - Verify that All World-Writable Directories Have Sticky Bits Set - - ocil:ssg-dir_perms_world_writable_sticky_bits_action:testaction:1 - - - - Verify Permissions on /etc/audit/auditd.conf - - ocil:ssg-file_permissions_etc_audit_auditd_action:testaction:1 - - - - Verify Permissions on /etc/audit/rules.d/*.rules - - ocil:ssg-file_permissions_etc_audit_rulesd_action:testaction:1 - - - - Verify that local System.map file (if exists) is readable only by root - - ocil:ssg-file_permissions_systemmap_action:testaction:1 - - - - Ensure All SGID Executables Are Authorized - - ocil:ssg-file_permissions_unauthorized_sgid_action:testaction:1 - - - - Ensure All SUID Executables Are Authorized - - ocil:ssg-file_permissions_unauthorized_suid_action:testaction:1 - - - - Ensure No World-Writable Files Exist - - ocil:ssg-file_permissions_unauthorized_world_writable_action:testaction:1 - - - - Ensure All Files Are Owned by a Group - - ocil:ssg-file_permissions_ungroupowned_action:testaction:1 - - - - Ensure All Files Are Owned by a User - - ocil:ssg-no_files_unowned_by_user_action:testaction:1 - - - - Enable Kernel Parameter to Enforce DAC on Hardlinks - - ocil:ssg-sysctl_fs_protected_hardlinks_action:testaction:1 - - - - Enable Kernel Parameter to Enforce DAC on Symlinks - - ocil:ssg-sysctl_fs_protected_symlinks_action:testaction:1 - - - - Disable Mounting of cramfs - - ocil:ssg-kernel_module_cramfs_disabled_action:testaction:1 - - - - Disable Modprobe Loading of USB Storage Driver - - ocil:ssg-kernel_module_usb-storage_disabled_action:testaction:1 - - - - Disable the Automounter - - ocil:ssg-service_autofs_disabled_action:testaction:1 - - - - Add nodev Option to /boot - - ocil:ssg-mount_option_boot_nodev_action:testaction:1 - - - - Add noexec Option to /boot - - ocil:ssg-mount_option_boot_noexec_action:testaction:1 - - - - Add nosuid Option to /boot - - ocil:ssg-mount_option_boot_nosuid_action:testaction:1 - - - - Add nodev Option to /dev/shm - - ocil:ssg-mount_option_dev_shm_nodev_action:testaction:1 - - - - Add noexec Option to /dev/shm - - ocil:ssg-mount_option_dev_shm_noexec_action:testaction:1 - - - - Add nosuid Option to /dev/shm - - ocil:ssg-mount_option_dev_shm_nosuid_action:testaction:1 - - - - Add grpquota Option to /home - - ocil:ssg-mount_option_home_grpquota_action:testaction:1 - - - - Add nodev Option to /home - - ocil:ssg-mount_option_home_nodev_action:testaction:1 - - - - Add noexec Option to /home - - ocil:ssg-mount_option_home_noexec_action:testaction:1 - - - - Add nosuid Option to /home - - ocil:ssg-mount_option_home_nosuid_action:testaction:1 - - - - Add usrquota Option to /home - - ocil:ssg-mount_option_home_usrquota_action:testaction:1 - - - - Add nodev Option to Non-Root Local Partitions - - ocil:ssg-mount_option_nodev_nonroot_local_partitions_action:testaction:1 - - - - Add nodev Option to Removable Media Partitions - - ocil:ssg-mount_option_nodev_removable_partitions_action:testaction:1 - - - - Add noexec Option to Removable Media Partitions - - ocil:ssg-mount_option_noexec_removable_partitions_action:testaction:1 - - - - Add nosuid Option to Removable Media Partitions - - ocil:ssg-mount_option_nosuid_removable_partitions_action:testaction:1 - - - - Add nosuid Option to /opt - - ocil:ssg-mount_option_opt_nosuid_action:testaction:1 - - - - Add nosuid Option to /srv - - ocil:ssg-mount_option_srv_nosuid_action:testaction:1 - - - - Add nodev Option to /tmp - - ocil:ssg-mount_option_tmp_nodev_action:testaction:1 - - - - Add noexec Option to /tmp - - ocil:ssg-mount_option_tmp_noexec_action:testaction:1 - - - - Add nosuid Option to /tmp - - ocil:ssg-mount_option_tmp_nosuid_action:testaction:1 - - - - Add nodev Option to /var/log/audit - - ocil:ssg-mount_option_var_log_audit_nodev_action:testaction:1 - - - - Add noexec Option to /var/log/audit - - ocil:ssg-mount_option_var_log_audit_noexec_action:testaction:1 - - - - Add nosuid Option to /var/log/audit - - ocil:ssg-mount_option_var_log_audit_nosuid_action:testaction:1 - - - - Add nodev Option to /var/log - - ocil:ssg-mount_option_var_log_nodev_action:testaction:1 - - - - Add noexec Option to /var/log - - ocil:ssg-mount_option_var_log_noexec_action:testaction:1 - - - - Add nosuid Option to /var/log - - ocil:ssg-mount_option_var_log_nosuid_action:testaction:1 - - - - Add nodev Option to /var - - ocil:ssg-mount_option_var_nodev_action:testaction:1 - - - - Add noexec Option to /var - - ocil:ssg-mount_option_var_noexec_action:testaction:1 - - - - Add nosuid Option to /var - - ocil:ssg-mount_option_var_nosuid_action:testaction:1 - - - - Add nodev Option to /var/tmp - - ocil:ssg-mount_option_var_tmp_nodev_action:testaction:1 - - - - Add noexec Option to /var/tmp - - ocil:ssg-mount_option_var_tmp_noexec_action:testaction:1 - - - - Add nosuid Option to /var/tmp - - ocil:ssg-mount_option_var_tmp_nosuid_action:testaction:1 - - - - Disable core dump backtraces - - ocil:ssg-coredump_disable_backtraces_action:testaction:1 - - - - Disable storing core dump - - ocil:ssg-coredump_disable_storage_action:testaction:1 - - - - Disable Core Dumps for All Users - - ocil:ssg-disable_users_coredumps_action:testaction:1 - - - - Disable acquiring, saving, and processing core dumps - - ocil:ssg-service_systemd-coredump_disabled_action:testaction:1 - - - - Disable Core Dumps for SUID programs - - ocil:ssg-sysctl_fs_suid_dumpable_action:testaction:1 - - - - Restrict Exposed Kernel Pointer Addresses Access - - ocil:ssg-sysctl_kernel_kptr_restrict_action:testaction:1 - - - - Enable Randomized Layout of Virtual Address Space - - ocil:ssg-sysctl_kernel_randomize_va_space_action:testaction:1 - - - - Enable NX or XD Support in the BIOS - - ocil:ssg-bios_enable_execution_restrictions_action:testaction:1 - - - - Enable page allocator poisoning - - ocil:ssg-grub2_page_poison_argument_action:testaction:1 - - - - Enable SLUB/SLAB allocator poisoning - - ocil:ssg-grub2_slub_debug_argument_action:testaction:1 - - - - Disable the uvcvideo module - - ocil:ssg-kernel_module_uvcvideo_disabled_action:testaction:1 - - - - Disable storing core dumps - - ocil:ssg-sysctl_kernel_core_pattern_action:testaction:1 - - - - Configure file name of core dumps - - ocil:ssg-sysctl_kernel_core_uses_pid_action:testaction:1 - - - - Restrict Access to Kernel Message Buffer - - ocil:ssg-sysctl_kernel_dmesg_restrict_action:testaction:1 - - - - Disable Kernel Image Loading - - ocil:ssg-sysctl_kernel_kexec_load_disabled_action:testaction:1 - - - - Disable loading and unloading of kernel modules - - ocil:ssg-sysctl_kernel_modules_disabled_action:testaction:1 - - - - Kernel panic on oops - - ocil:ssg-sysctl_kernel_panic_on_oops_action:testaction:1 - - - - Limit CPU consumption of the Perf system - - ocil:ssg-sysctl_kernel_perf_cpu_time_max_percent_action:testaction:1 - - - - Limit sampling frequency of the Perf system - - ocil:ssg-sysctl_kernel_perf_event_max_sample_rate_action:testaction:1 - - - - Disallow kernel profiling by unprivileged users - - ocil:ssg-sysctl_kernel_perf_event_paranoid_action:testaction:1 - - - - Configure maximum number of process identifiers - - ocil:ssg-sysctl_kernel_pid_max_action:testaction:1 - - - - Disallow magic SysRq key - - ocil:ssg-sysctl_kernel_sysrq_action:testaction:1 - - - - Disable Access to Network bpf() Syscall From Unprivileged Processes - - ocil:ssg-sysctl_kernel_unprivileged_bpf_disabled_action:testaction:1 - - - - Restrict usage of ptrace to descendant processes - - ocil:ssg-sysctl_kernel_yama_ptrace_scope_action:testaction:1 - - - - Harden the operation of the BPF just-in-time compiler - - ocil:ssg-sysctl_net_core_bpf_jit_harden_action:testaction:1 - - - - Disable the use of user namespaces - - ocil:ssg-sysctl_user_max_user_namespaces_action:testaction:1 - - - - Prevent applications from mapping low portion of virtual memory - - ocil:ssg-sysctl_vm_mmap_min_addr_action:testaction:1 - - - - Configure the deny_execmem SELinux Boolean - - ocil:ssg-sebool_deny_execmem_action:testaction:1 - - - - Configure the polyinstantiation_enabled SELinux Boolean - - ocil:ssg-sebool_polyinstantiation_enabled_action:testaction:1 - - - - Configure the secure_mode_insmod SELinux Boolean - - ocil:ssg-sebool_secure_mode_insmod_action:testaction:1 - - - - Disable the selinuxuser_execheap SELinux Boolean - - ocil:ssg-sebool_selinuxuser_execheap_action:testaction:1 - - - - Enable the selinuxuser_execmod SELinux Boolean - - ocil:ssg-sebool_selinuxuser_execmod_action:testaction:1 - - - - Disable the selinuxuser_execstack SELinux Boolean - - ocil:ssg-sebool_selinuxuser_execstack_action:testaction:1 - - - - Disable the ssh_sysadm_login SELinux Boolean - - ocil:ssg-sebool_ssh_sysadm_login_action:testaction:1 - - - - Ensure SELinux Not Disabled in /etc/default/grub - - ocil:ssg-grub2_enable_selinux_action:testaction:1 - - - - Install policycoreutils-python-utils package - - ocil:ssg-package_policycoreutils-python-utils_installed_action:testaction:1 - - - - Install policycoreutils Package - - ocil:ssg-package_policycoreutils_installed_action:testaction:1 - - - - Uninstall setroubleshoot-plugins Package - - ocil:ssg-package_setroubleshoot-plugins_removed_action:testaction:1 - - - - Uninstall setroubleshoot-server Package - - ocil:ssg-package_setroubleshoot-server_removed_action:testaction:1 - - - - Ensure No Daemons are Unconfined by SELinux - - ocil:ssg-selinux_confinement_of_daemons_action:testaction:1 - - - - Ensure SELinux is Not Disabled - - ocil:ssg-selinux_not_disabled_action:testaction:1 - - - - Configure SELinux Policy - - ocil:ssg-selinux_policytype_action:testaction:1 - - - - Ensure SELinux State is Enforcing - - ocil:ssg-selinux_state_action:testaction:1 - - - - Encrypt Partitions - - ocil:ssg-encrypt_partitions_action:testaction:1 - - - - Ensure /dev/shm is configured - - ocil:ssg-partition_for_dev_shm_action:testaction:1 - - - - Ensure /home Located On Separate Partition - - ocil:ssg-partition_for_home_action:testaction:1 - - - - Ensure /srv Located On Separate Partition - - ocil:ssg-partition_for_srv_action:testaction:1 - - - - Ensure /tmp Located On Separate Partition - - ocil:ssg-partition_for_tmp_action:testaction:1 - - - - Ensure /var Located On Separate Partition - - ocil:ssg-partition_for_var_action:testaction:1 - - - - Ensure /var/log Located On Separate Partition - - ocil:ssg-partition_for_var_log_action:testaction:1 - - - - Ensure /var/log/audit Located On Separate Partition - - ocil:ssg-partition_for_var_log_audit_action:testaction:1 - - - - Ensure /var/tmp Located On Separate Partition - - ocil:ssg-partition_for_var_tmp_action:testaction:1 - - - - Disable the GNOME3 Login Restart and Shutdown Buttons - - ocil:ssg-dconf_gnome_disable_restart_shutdown_action:testaction:1 - - - - Disable the GNOME3 Login User List - - ocil:ssg-dconf_gnome_disable_user_list_action:testaction:1 - - - - Enable the GNOME3 Screen Locking On Smartcard Removal - - ocil:ssg-dconf_gnome_lock_screen_on_smartcard_removal_action:testaction:1 - - - - Disable GDM Automatic Login - - ocil:ssg-gnome_gdm_disable_automatic_login_action:testaction:1 - - - - Disable XDMCP in GDM - - ocil:ssg-gnome_gdm_disable_xdmcp_action:testaction:1 - - - - Disable GNOME3 Automount Opening - - ocil:ssg-dconf_gnome_disable_automount_open_action:testaction:1 - - - - Disable GNOME3 Automount running - - ocil:ssg-dconf_gnome_disable_autorun_action:testaction:1 - - - - Require Credential Prompting for Remote Access in GNOME3 - - ocil:ssg-dconf_gnome_remote_access_credential_prompt_action:testaction:1 - - - - Require Encryption for Remote Access in GNOME3 - - ocil:ssg-dconf_gnome_remote_access_encryption_action:testaction:1 - - - - Enable GNOME3 Screensaver Idle Activation - - ocil:ssg-dconf_gnome_screensaver_idle_activation_enabled_action:testaction:1 - - - - Set GNOME3 Screensaver Inactivity Timeout - - ocil:ssg-dconf_gnome_screensaver_idle_delay_action:testaction:1 - - - - Set GNOME3 Screensaver Lock Delay After Activation Period - - ocil:ssg-dconf_gnome_screensaver_lock_delay_action:testaction:1 - - - - Enable GNOME3 Screensaver Lock After Idle Period - - ocil:ssg-dconf_gnome_screensaver_lock_enabled_action:testaction:1 - - - - Ensure Users Cannot Change GNOME3 Screensaver Lock After Idle Period - - ocil:ssg-dconf_gnome_screensaver_lock_locked_action:testaction:1 - - - - Implement Blank Screensaver - - ocil:ssg-dconf_gnome_screensaver_mode_blank_action:testaction:1 - - - - Ensure Users Cannot Change GNOME3 Screensaver Settings - - ocil:ssg-dconf_gnome_screensaver_user_locks_action:testaction:1 - - - - Ensure Users Cannot Change GNOME3 Session Idle Settings - - ocil:ssg-dconf_gnome_session_idle_user_locks_action:testaction:1 - - - - Disable Ctrl-Alt-Del Reboot Key Sequence in GNOME3 - - ocil:ssg-dconf_gnome_disable_ctrlaltdel_reboot_action:testaction:1 - - - - Make sure that the dconf databases are up-to-date with regards to respective keyfiles - - ocil:ssg-dconf_db_up_to_date_action:testaction:1 - - - - Configure GNOME3 DConf User Profile - - ocil:ssg-enable_dconf_user_profile_action:testaction:1 - - - - The Installed Operating System Is Vendor Supported - - ocil:ssg-installed_OS_is_vendor_supported_action:testaction:1 - - - - Configure BIND to use System Crypto Policy - - ocil:ssg-configure_bind_crypto_policy_action:testaction:1 - - - - Configure System Cryptography Policy - - ocil:ssg-configure_crypto_policy_action:testaction:1 - - - - Configure Kerberos to use System Crypto Policy - - ocil:ssg-configure_kerberos_crypto_policy_action:testaction:1 - - - - Configure Libreswan to use System Crypto Policy - - ocil:ssg-configure_libreswan_crypto_policy_action:testaction:1 - - - - Configure OpenSSL library to use System Crypto Policy - - ocil:ssg-configure_openssl_crypto_policy_action:testaction:1 - - - - Configure OpenSSL library to use TLS Encryption - - ocil:ssg-configure_openssl_tls_crypto_policy_action:testaction:1 - - - - Configure SSH to use System Crypto Policy - - ocil:ssg-configure_ssh_crypto_policy_action:testaction:1 - - - - Harden SSH client Crypto Policy - - ocil:ssg-harden_ssh_client_crypto_policy_action:testaction:1 - - - - Configure SSH Client to Use FIPS 140-2 Validated Ciphers: openssh.config - - ocil:ssg-harden_sshd_ciphers_openssh_conf_crypto_policy_action:testaction:1 - - - - Configure SSH Server to Use FIPS 140-2 Validated Ciphers: opensshserver.config - - ocil:ssg-harden_sshd_ciphers_opensshserver_conf_crypto_policy_action:testaction:1 - - - - Configure SSH Client to Use FIPS 140-2 Validated MACs: openssh.config - - ocil:ssg-harden_sshd_macs_openssh_conf_crypto_policy_action:testaction:1 - - - - Configure SSH Server to Use FIPS 140-2 Validated MACs: opensshserver.config - - ocil:ssg-harden_sshd_macs_opensshserver_conf_crypto_policy_action:testaction:1 - - - - Install crypto-policies package - - ocil:ssg-package_crypto-policies_installed_action:testaction:1 - - - - Ensure McAfee Endpoint Security for Linux (ENSL) is running - - ocil:ssg-agent_mfetpd_running_action:testaction:1 - - - - Install McAfee Endpoint Security for Linux (ENSL) - - ocil:ssg-package_mcafeetp_installed_action:testaction:1 - - - - Install the Host Intrusion Prevention System (HIPS) Module - - ocil:ssg-package_MFEhiplsm_installed_action:testaction:1 - - - - Configure Backups of User Data - - ocil:ssg-configure_user_data_backups_action:testaction:1 - - - - Install Intrusion Detection Software - - ocil:ssg-install_hids_action:testaction:1 - - - - Enable Dracut FIPS Module - - ocil:ssg-enable_dracut_fips_module_action:testaction:1 - - - - Enable FIPS Mode - - ocil:ssg-enable_fips_mode_action:testaction:1 - - - - Ensure '/etc/system-fips' exists - - ocil:ssg-etc_system_fips_exists_action:testaction:1 - - - - Set kernel parameter 'crypto.fips_enabled' to 1 - - ocil:ssg-sysctl_crypto_fips_enabled_action:testaction:1 - - - - Build and Test AIDE Database - - ocil:ssg-aide_build_database_action:testaction:1 - - - - Configure AIDE to Verify the Audit Tools - - ocil:ssg-aide_check_audit_tools_action:testaction:1 - - - - Configure Periodic Execution of AIDE - - ocil:ssg-aide_periodic_cron_checking_action:testaction:1 - - - - Configure Notification of Post-AIDE Scan Details - - ocil:ssg-aide_scan_notification_action:testaction:1 - - - - Configure AIDE to Verify Access Control Lists (ACLs) - - ocil:ssg-aide_verify_acls_action:testaction:1 - - - - Configure AIDE to Verify Extended Attributes - - ocil:ssg-aide_verify_ext_attributes_action:testaction:1 - - - - Audit Tools Must Be Group-owned by Root - - ocil:ssg-file_audit_tools_group_ownership_action:testaction:1 - - - - Audit Tools Must Be Owned by Root - - ocil:ssg-file_audit_tools_ownership_action:testaction:1 - - - - Audit Tools Must Have a Mode of 0755 or Less Permissive - - ocil:ssg-file_audit_tools_permissions_action:testaction:1 - - - - Install AIDE - - ocil:ssg-package_aide_installed_action:testaction:1 - - - - Verify File Hashes with RPM - - ocil:ssg-rpm_verify_hashes_action:testaction:1 - - - - Verify and Correct Ownership with RPM - - ocil:ssg-rpm_verify_ownership_action:testaction:1 - - - - Verify and Correct File Permissions with RPM - - ocil:ssg-rpm_verify_permissions_action:testaction:1 - - - - Install sudo Package - - ocil:ssg-package_sudo_installed_action:testaction:1 - - - - Ensure Privileged Escalated Commands Cannot Execute Other Commands - sudo NOEXEC - - ocil:ssg-sudo_add_noexec_action:testaction:1 - - - - Ensure Only Users Logged In To Real tty Can Execute Sudo - sudo requiretty - - ocil:ssg-sudo_add_requiretty_action:testaction:1 - - - - Ensure Only Users Logged In To Real tty Can Execute Sudo - sudo use_pty - - ocil:ssg-sudo_add_use_pty_action:testaction:1 - - - - Ensure Sudo Logfile Exists - sudo logfile - - ocil:ssg-sudo_custom_logfile_action:testaction:1 - - - - Ensure Users Re-Authenticate for Privilege Escalation - sudo !authenticate - - ocil:ssg-sudo_remove_no_authenticate_action:testaction:1 - - - - Ensure Users Re-Authenticate for Privilege Escalation - sudo NOPASSWD - - ocil:ssg-sudo_remove_nopasswd_action:testaction:1 - - - - Ensure Users Re-Authenticate for Privilege Escalation - sudo - - ocil:ssg-sudo_require_authentication_action:testaction:1 - - - - Require Re-Authentication When Using the sudo Command - - ocil:ssg-sudo_require_reauthentication_action:testaction:1 - - - - The operating system must restrict privilege elevation to authorized personnel - - ocil:ssg-sudo_restrict_privilege_elevation_to_authorized_action:testaction:1 - - - - Only the VDSM User Can Use sudo NOPASSWD - - ocil:ssg-sudo_vdsm_nopasswd_action:testaction:1 - - - - Explicit arguments in sudo specifications - - ocil:ssg-sudoers_explicit_command_args_action:testaction:1 - - - - Don't define allowed commands in sudoers by means of exclusion - - ocil:ssg-sudoers_no_command_negation_action:testaction:1 - - - - Don't target root user in the sudoers file - - ocil:ssg-sudoers_no_root_target_action:testaction:1 - - - - Ensure invoking users password for privilege escalation when using sudo - - ocil:ssg-sudoers_validate_passwd_action:testaction:1 - - - - Ensure gnutls-utils is installed - - ocil:ssg-package_gnutls-utils_installed_action:testaction:1 - - - - Uninstall gssproxy Package - - ocil:ssg-package_gssproxy_removed_action:testaction:1 - - - - Uninstall iprutils Package - - ocil:ssg-package_iprutils_removed_action:testaction:1 - - - - Uninstall krb5-workstation Package - - ocil:ssg-package_krb5-workstation_removed_action:testaction:1 - - - - Ensure nss-tools is installed - - ocil:ssg-package_nss-tools_installed_action:testaction:1 - - - - Install openscap-scanner Package - - ocil:ssg-package_openscap-scanner_installed_action:testaction:1 - - - - Install rear Package - - ocil:ssg-package_rear_installed_action:testaction:1 - - - - Install rng-tools Package - - ocil:ssg-package_rng-tools_installed_action:testaction:1 - - - - Install scap-security-guide Package - - ocil:ssg-package_scap-security-guide_installed_action:testaction:1 - - - - Uninstall tuned Package - - ocil:ssg-package_tuned_removed_action:testaction:1 - - - - Ensure yum Removes Previous Package Versions - - ocil:ssg-clean_components_post_updating_action:testaction:1 - - - - Configure dnf-automatic to Install Available Updates Automatically - - ocil:ssg-dnf-automatic_apply_updates_action:testaction:1 - - - - Configure dnf-automatic to Install Only Security Updates - - ocil:ssg-dnf-automatic_security_updates_only_action:testaction:1 - - - - Ensure gpgcheck Enabled In Main yum Configuration - - ocil:ssg-ensure_gpgcheck_globally_activated_action:testaction:1 - - - - Ensure gpgcheck Enabled for Local Packages - - ocil:ssg-ensure_gpgcheck_local_packages_action:testaction:1 - - - - Ensure gpgcheck Enabled for All yum Package Repositories - - ocil:ssg-ensure_gpgcheck_never_disabled_action:testaction:1 - - - - Ensure Oracle Linux GPG Key Installed - - ocil:ssg-ensure_oracle_gpgkey_installed_action:testaction:1 - - - - Install dnf-automatic Package - - ocil:ssg-package_dnf-automatic_installed_action:testaction:1 - - - - Ensure Software Patches Installed - - ocil:ssg-security_patches_up_to_date_action:testaction:1 - - - - Enable dnf-automatic Timer - - ocil:ssg-timer_dnf-automatic_enabled_action:testaction:1 - - - - Prefer to use a 64-bit Operating System when supported - - ocil:ssg-prefer_64bit_os_action:testaction:1 - - - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - - To check that the avahi-daemon service is disabled in system boot configuration, -run the following command: -$ sudo systemctl is-enabled avahi-daemon -Output should indicate the avahi-daemon service has either not been installed, -or has been disabled at all runlevels, as shown in the example below: -$ sudo systemctl is-enabled avahi-daemon disabled + + + + ^(?i)50(?-i)$ + + + ^(?i)yes(?-i)$ + + + ^(?i)ENRICHED(?-i)$ + + + ^(?i)yes(?-i)$ + + + ^'lock-screen'$ + + + 0 + + + 0 + + + 0 + + + 0 + + + symbolic link + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + symbolic link + + + 0 + + + 0 + + + 0 + + + 0 + + + symbolic link + + + false + false + false + false + false + + + false + false + false + false + false + + + false + false + false + false + false + + + false + false + false + false + false + + + false + false + false + false + false + + + false + false + false + false + false + + + symbolic link + + + false + false + + + false + false + + + false + false + + + false + false + + + symbolic link + + + + + + symbolic link + + + + + + symbolic link + + + + + + symbolic link + + + + + + symbolic link + + + + + + symbolic link + + + + + + symbolic link + + + 0 + + + symbolic link + + + 0 + + + symbolic link + + + 0 + + + symbolic link + + + 0 + + + symbolic link + + + 0 + + + symbolic link + + + 0 + + + symbolic link + + + false + false + false + false + false + false + false + false + false + + + symbolic link + + + false + false + false + false + false + false + false + false + false + + + symbolic link + + + false + false + false + false + false + false + false + false + false + + + symbolic link + + + false + false + false + false + false + + + symbolic link + + + false + false + false + false + false + false + false + + + symbolic link + + + false + false + false + false + false + + + symbolic link + + + ^no$ + + + ^no$ + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + symbolic link + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + symbolic link + + + false + false + false + false + false + + + false + false + false + false + false + + + false + false + false + false + false + + + false + false + false + false + false + + + false + false + false + false + false + + + false + false + false + false + false + + + false + false + false + false + false + + + symbolic link + + + 0 + + + symbolic link + + + 0 + + + symbolic link + + + 0 + + + symbolic link + + + 0 + + + symbolic link + + + 0 + + + symbolic link + + + 0 + + + symbolic link + + + 0 + + + symbolic link + + + 0 + + + symbolic link + + + 0 + + + symbolic link + + + 0 + + + symbolic link + + + 0 + + + symbolic link + + + 0 + + + symbolic link + + + 0 + + + symbolic link + + + 0 + + + symbolic link + + + 0 + + + symbolic link + + + + + + symbolic link + + + 0 + + + symbolic link + + + 0 + + + symbolic link + + + + + + symbolic link + + + + + + symbolic link + + + 0 + + + symbolic link + + + 0 + + + symbolic link + + + + + + symbolic link + + + 0 + + + symbolic link + + + 0 + + + symbolic link + + + + + + symbolic link + + + 0 + + + symbolic link + + + 0 + + + symbolic link + + + + + + symbolic link + + + 0 + + + symbolic link + + + 0 + + + symbolic link + + + 0 + + + symbolic link + + + 4 + + + symbolic link + + + 0 + + + 0 + + + symbolic link + + + + + + symbolic link + + + 0 + + + symbolic link + + + 0 + + + symbolic link + + + 0 + + + symbolic link + + + 0 + + + symbolic link + + + 0 + + + symbolic link + + + 0 + + + symbolic link + + + 0 + + + symbolic link + + + 0 + + + symbolic link + + + 0 + + + symbolic link + + + 0 + + + symbolic link + + + 0 + + + symbolic link + + + 0 + + + symbolic link + + + 0 + + + symbolic link + + + 0 + + + symbolic link + + + 0 + + + symbolic link + + + 0 + + + symbolic link + + + 0 + + + symbolic link + + + 0 + + + symbolic link + + + 0 + + + symbolic link + + + 0 + + + symbolic link + + + 0 + + + symbolic link + + + 0 + + + symbolic link + + + 0 + + + symbolic link + + + 0 + + + symbolic link + + + 0 + + + symbolic link + + + 0 + + + symbolic link + + + 0 + + + symbolic link + + + 0 + + + symbolic link + + + 0 + + + symbolic link + + + 0 + + + symbolic link + + + 0 + + + symbolic link + + + 0 + + + symbolic link + + + 0 + + + symbolic link + + + 104 + + + symbolic link + + + 0 + + + 0 + + + symbolic link + + + 0 + + + 0 + + + 0 + + + 0 + + + symbolic link + + + 0 + + + symbolic link + + + 0 + + + symbolic link + + + false + false + false + false + false + false + false + false + false + + + symbolic link + + + false + false + false + false + false + false + false + false + false + + + false + false + false + false + false + false + false + false + false + + + symbolic link + + + false + false + false + false + false + false + false + false + + + symbolic link + + + false + false + false + false + false + false + false + false + false + false + false + false + + + symbolic link + + + false + false + false + false + false + false + false + false + + + symbolic link + + + false + false + false + false + false + false + false + false + false + false + false + false + + + symbolic link + + + false + false + false + false + false + false + false + false + false + + + symbolic link + + + false + false + false + false + false + false + false + false + false + + + symbolic link + + + false + false + false + false + false + false + false + false + false + + + symbolic link + + + false + false + false + false + false + false + false + false + false + + + symbolic link + + + false + false + false + false + false + false + false + false + false + + + symbolic link + + + false + false + false + false + false + false + false + false + false + + + symbolic link + + + false + false + false + false + false + false + false + false + false + false + + + symbolic link + + + false + false + false + false + false + false + false + false + false + + + symbolic link + + + false + false + false + false + false + false + false + false + false + + + symbolic link + + + false + false + false + false + false + false + false + false + false + + + symbolic link + + + false + false + false + false + false + false + false + false + false + false + + + symbolic link + + + false + false + false + false + false + false + false + false + false + + + symbolic link + + + false + false + false + false + false + false + false + false + false + false + + + symbolic link + + + false + false + false + false + false + false + false + false + + + symbolic link + + + false + false + false + false + false + false + false + false + false + false + false + false + + + symbolic link + + + false + false + false + false + false + false + false + false + + + symbolic link + + + false + false + false + false + false + false + false + false + + + symbolic link + + + false + false + false + false + false + false + false + false + + + symbolic link + + + false + false + false + false + false + false + false + false + + + symbolic link + + + false + false + false + false + false + false + false + false + + + symbolic link + + + false + false + false + false + false + false + false + false + false + false + false + false + + + symbolic link + + + false + false + false + false + false + false + false + false + + + symbolic link + + + false + false + false + false + false + false + false + false + false + false + + + symbolic link + + + false + false + false + false + false + false + false + false + false + false + + + symbolic link + + + false + false + + + false + false + + + false + false + + + false + false + + + symbolic link + + + false + false + false + false + false + false + false + false + false + false + + + symbolic link + + + false + false + false + false + false + false + false + false + + + symbolic link + + + true + false + false + false + false + true + false + false + true + false + false + false + + + symbolic link + + + false + false + false + false + false + false + false + false + false + false + + + symbolic link + + + false + false + false + false + false + false + false + false + false + false + + + symbolic link + + + false + false + false + false + false + + + symbolic link + + + false + false + false + false + false + false + false + false + false + false + + + symbolic link + + + false + false + false + false + false + false + false + false + false + + + symbolic link + + + ^nftables$ + + + .*rescue\.conf$ + + + ^(?:.*\s)?audit=1(?:\s.*)?$ + + + .*rescue\.conf$ + + + ^(?:.*\s)?audit_backlog_limit=8192(?:\s.*)?$ + + + .*rescue\.conf$ + + + ^(?:.*\s)?iommu=force(?:\s.*)?$ + + + .*rescue\.conf$ + + + ^(?:.*\s)?init_on_alloc=1(?:\s.*)?$ + + + .*rescue\.conf$ + + + + + + .*rescue\.conf$ + + + ^(?:.*\s)?mce=0(?:\s.*)?$ + + + .*rescue\.conf$ + + + + + + .*rescue\.conf$ + + + .*rescue\.conf$ + + + .*rescue\.conf$ + + + ^(?:.*\s)?page_alloc\.shuffle=1(?:\s.*)?$ + + + .*rescue\.conf$ + + + ^(?:.*\s)?page_poison=1(?:\s.*)?$ + + + .*rescue\.conf$ + + + ^(?:.*\s)?pti=on(?:\s.*)?$ + + + .*rescue\.conf$ + + + + + + .*rescue\.conf$ + + + ^(?:.*\s)?slab_nomerge=yes(?:\s.*)?$ + + + .*rescue\.conf$ + + + + + + .*rescue\.conf$ + + + + + + .*rescue\.conf$ + + + ^(?:.*\s)?spectre_v2=on(?:\s.*)?$ + + + .*rescue\.conf$ + + + .*rescue\.conf$ + + + ^(?:.*\s)?vsyscall=none(?:\s.*)?$ + + + n + + + + + + y + + + + + + n + + + + + + y + + + + + + y + + + + + + n + + + + + + n + + + + + + y + + + + + + n + + + + + + y + + + + + + y + + + + + + y + + + + + + y + + + + + + n + + + + + + y + + + + + + y + + + + + + y + + + + + + y + + + + + + y + + + + + + y + + + + + + y + + + + + + n + + + + + + n + + + + + + n + + + + + + n + + + + + + n + + + + + + n + + + + + + n + + + + + + y + + + + + + n + + + + + + n + + + + + + y + + + + + + y + + + + + + y + + + + + + + + + + + + + + + + + + y + + + + + + y + + + + + + y + + + + + + y + + + + + + y + + + + + + y + + + + + + + + + + + + n + + + + + + y + + + + + + y + + + + + + y + + + + + + y + + + + + + y + + + + + + y + + + + + + y + + + + + + y + + + + + + y + + + + + + n + + + + + + y + + + + + + y + + + + + + y + + + + + + n + + + + + + y + + + + + + y + + + + + + y + + + + + + y + + + + + + y + + + + + + y + + + + + + y + + + + + + y + + + + + + n + + + + + + nosuid + + + 1 + nosuid + + + nodev + + + 1 + nodev + + + noexec + + + 1 + noexec + + + nosuid + + + 1 + nosuid + + + nodev + + + 1 + nodev + + + noexec + + + 1 + noexec + + + nosuid + + + 1 + nosuid + + + grpquota + + + nodev + + + 1 + nodev + + + noexec + + + nosuid + + + usrquota + + + ^.*sec=krb5:krb5i:krb5p.*$ + + + ^.*nodev.*$ + + + ^.*,?nodev,?.*$ + + + ^.*,?nodev,?.* + + + ^.*noexec.*$ + + + ^.*,?noexec,?.*$ + + + ^.*,?noexec,?.* + + + ^.*nosuid.*$ + + + ^.*,?nosuid,?.*$ + + + ^.*,?nosuid,?.* + + + nosuid + + + 1 + nosuid + + + nosuid + + + 1 + nosuid + + + nodev + + + 1 + nodev + + + noexec + + + 1 + noexec + + + nosuid + + + 1 + nosuid + + + nodev + + + 1 + nodev + + + noexec + + + 1 + noexec + + + nosuid + + + 1 + nosuid + + + nodev + + + 1 + nodev + + + noexec + + + 1 + noexec + + + nosuid + + + 1 + nosuid + + + nodev + + + 1 + nodev + + + noexec + + + 1 + noexec + + + nosuid + + + 1 + nosuid + + + nodev + + + 1 + nodev + + + noexec + + + 1 + noexec + + + nosuid + + + 1 + nosuid + + + 0 + + + 0 + + + 0 + + + 0 + + + symbolic link + + + (?:file="[^\s;]+"|\$IncludeConfig[\s]+[^\s;]+|\/dev\/.*) + + + regular + + + + (?:file="[^\s;]+"|\$IncludeConfig[\s]+[^\s;]+|\/dev\/.*) + + + regular + + + + (?:file="[^\s;]+"|\$IncludeConfig[\s]+[^\s;]+|\/dev\/.*) + + + regular + false + false + false + false + false + false + false + false + false + + + auditadm_exec_content + + + + + authlogin_nsswitch_use_ldap + + + + + authlogin_radius + + + + + deny_execmem + + + + + kerberos_enabled + + + + + polyinstantiation_enabled + + + + + secure_mode_insmod + + + + + selinuxuser_execheap + + + + + selinuxuser_execmod + + + + + selinuxuser_execstack + + + + + ssh_sysadm_login + + + + + inactive|failed + + + masked + + + auditd.service + + + auditd.socket + + + active + + + inactive|failed + + + masked + + + inactive|failed + + + masked + + + chronyd.service + + + chronyd.socket + + + active + + + crond.service + + + crond.socket + + + active + + + inactive|failed + + + masked + + + fapolicyd.service + + + fapolicyd.socket + + + active + + + firewalld.service + + + firewalld.socket + + + active + + + iptables.service + + + iptables.socket + + + active + + + inactive|failed + + + masked + + + inactive|failed + + + masked + + + inactive|failed + + + masked + + + pcscd.service + + + pcscd.socket + + + active + + + postfix.service + + + postfix.socket + + + active + + + inactive|failed + + + masked + + + inactive|failed + + + masked + + + rngd.service + + + rngd.socket + + + active + + + inactive|failed + + + masked + + + rsyslog.service + + + rsyslog.socket + + + active + + + inactive|failed + + + masked + + + inactive|failed + + + masked + + + inactive|failed + + + masked + + + sshd.service + + + sshd.socket + + + active + + + sssd.service + + + sssd.socket + + + active + + + syslog-ng.service + + + syslog-ng.socket + + + active + + + masked + + + systemd-journald.service + + + systemd-journald.socket + + + active + + + inactive|failed + + + masked + + + ufw.service + + + ufw.socket + + + active + + + usbguard.service + + + usbguard.socket + + + active + + + ^2$ + + + ^2$ + + + + + + + + + ^no$ + + + ^no$ + + + ^no$ + + + ^no$ + + + ^no$ + + + ^no$ + + + ^no$ + + + ^no$ + + + ^yes$ + + + ^yes$ + + + ^no$ + + + ^no$ + + + ^no$ + + + ^no$ + + + ^prohibit-password$ + + + ^prohibit-password$ + + + ^no$ + + + ^no$ + + + ^yes$ + + + ^yes$ + + + ^no$ + + + ^no$ + + + ^no$ + + + ^no$ + + + ^yes$ + + + ^yes$ + + + ^yes$ + + + ^yes$ + + + ^yes$ + + + ^yes$ + + + ^yes$ + + + ^yes$ + + + ^/etc/issue$ + + + ^/etc/issue$ + + + ^/etc/issue.net$ + + + ^/etc/issue.net$ + + + ^yes$ + + + ^yes$ + + + ^yes$ + + + ^yes$ + + + + + + + + + ^0$ + + + ^0$ + + + ^INFO$ + + + ^INFO$ + + + ^VERBOSE$ + + + ^VERBOSE$ + + + + + + + + + ^yes$ + + + ^yes$ + + + + + + 2 + + + 2 + + + 1 + + + 1 + + + 2 + + + 2 + + + 1 + + + 1 + + + 0 + + + 0 + + + |/bin/false + + + |/bin/false + + + 0 + + + 0 + + + 1 + + + 1 + + + 1 + + + 1 + + + 1 + + + 2 + + + 1 + + + 2 + + + 1 + + + 1 + + + 1 + + + 1 + + + 1 + + + 1 + + + 1 + + + 1 + + + 2 + + + 2 + + + 65536 + + + 65536 + + + 2 + + + 2 + + + 0 + + + 0 + + + 1 + + + 1 + + + 1 + + + 2 + + + 1 + + + 2 + + + 1 + + + 1 + + + 2 + + + 2 + + + 0 + + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + 1 + + + 1 + + + + + + + + + + + + + + + 0 + + + 0 + + + 1 + + + 2 + + + 1 + + + 2 + + + + + + + + + 0 + + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + 0 + + + + + + + + + + + + + + + + + + + + + 0 + + + 0 + + + 32768\s*65535 + + + 32768\s*65535 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1 + + + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1 + + + 1 + + + + + + + + + + + + + + + 0 + + + 0 + + + 65536 + + + 65536 + + + tmp.mount + + + active + + + dnf-automatic.timer + + + active + + + logrotate.timer + + + active + + + ^(true|"true")$ + + + ^7.*$ + + + ^8.*$ + + + ^9.*$ + + + unix + + + rhcos + + + 4 + + + unix + + + ^8\.\d{1,2}$ + + + 8 + + + unix + + + ^9.*$ + + + 9 + + + 0:4.4 + + + unix + + + ^12.*$ + + + ^12.*$ + + + ^12.*$ + + + unix + + + ^15.*$ + + + ^15.*$ + + + ^15.*$ + + + ^4.*$ + + + ^15.*$ + + + unix + + + ^5.*$ + + + ^5.*$ + + + 1 + + + 2 + + + 0 + + + aarch64 + + + ppc64 + + + ppc64le + + + s390x + + + i686 + + + x86_64 + + + /dev/cdrom + + + + + + ^[\s]*-a[\s]+always,exit[\s]+(?:-F[\s]+dir=/var/log/audit/)[\s]+(?:-F[\s]+perm=r)[\s]+(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295)[\s]+)(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ^[\s]*-a always,exit (?:-F path=([\S]+))+(?: -F perm=x)? -F auid>=1000 -F auid!=(?:4294967295|unset)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + + + + + + + + + + + + + + + + + + + (?i) + + + + + + + (?i) + + + + + + + + (?i) + + + + + + + + + + (?i) + + + + + + + + (?i) + + + + + + + + + + ^(?:server)[[:space:]] + + + + $ + + + + + + ^(?:pool)[[:space:]] + + + + $ + + + + + + + + + + + + + + + + ^[\s]*RekeyLimit[\s]+ + + [\s]+ + + [\s]*$ + + + + + + ^(dmz|external|home|internal|public|trusted|work)\.xml$ + + + + + + + + + + + + + + + ^ + + [\s]+ + + [\s]*$ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ^[\s]*auth[\s]+(required|\[(?=.*?\bsuccess=ok\b)(?=.*?\bnew_authtok_reqd=ok\b)(?=.*?\bignore=ignore\b)(?=.*?\bdefault=bad\b).*\])[\s]+pam_faillock\.so[\s\w\d=]+preauth[\s\S]*^[\s]*auth[\s]+(sufficient|\[(?=.*\bsuccess=done\b)(?=.*?\bnew_authtok_reqd=done\b)(?=.*?\bdefault=ignore\b).*\])[\s]+pam_unix\.so[\s\S]*^[\s]*auth[\s]+(required|\[(?=.*?\bsuccess=ok\b)(?=.*?\bnew_authtok_reqd=ok\b)(?=.*?\bignore=ignore\b)(?=.*?\bdefault=bad\b).*\])[\s]+pam_faillock\.so[\s\w\d=]+authfail + + + ^[\s]*account[\s]+(required|\[(?=.*?\bsuccess=ok\b)(?=.*?\bnew_authtok_reqd=ok\b)(?=.*?\bignore=ignore\b)(?=.*?\bdefault=bad\b).*\])[\s]+pam_faillock\.so[\s\S]*^[\s]*account[\s]+(required|\[(?=.*?\bsuccess=ok\b)(?=.*?\bnew_authtok_reqd=ok\b)(?=.*?\bignore=ignore\b)(?=.*?\bdefault=bad\b).*\])[\s]+pam_unix\.so + + + ^[\s]*auth[\s]+(required|\[(?=.*?\bsuccess=ok\b)(?=.*?\bnew_authtok_reqd=ok\b)(?=.*?\bignore=ignore\b)(?=.*?\bdefault=bad\b).*\])[\s]+pam_faillock\.so[\s\w\d=]+preauth[\s\S]*^[\s]*auth[\s]+(sufficient|\[(?=.*\bsuccess=done\b)(?=.*?\bnew_authtok_reqd=done\b)(?=.*?\bdefault=ignore\b).*\])[\s]+pam_unix\.so[\s\S]*^[\s]*auth[\s]+(required|\[(?=.*?\bsuccess=ok\b)(?=.*?\bnew_authtok_reqd=ok\b)(?=.*?\bignore=ignore\b)(?=.*?\bdefault=bad\b).*\])[\s]+pam_faillock\.so[\s\w\d=]+authfail + + + ^[\s]*account[\s]+(required|\[(?=.*?\bsuccess=ok\b)(?=.*?\bnew_authtok_reqd=ok\b)(?=.*?\bignore=ignore\b)(?=.*?\bdefault=bad\b).*\])[\s]+pam_faillock\.so[\s\S]*^[\s]*account[\s]+(required|\[(?=.*?\bsuccess=ok\b)(?=.*?\bnew_authtok_reqd=ok\b)(?=.*?\bignore=ignore\b)(?=.*?\bdefault=bad\b).*\])[\s]+pam_unix\.so + + + + + + ^[\s]*auth[\s]+(?:required|requisite)[\s]+pam_faillock.so[^\n#]preauth[^\n#]*audit + + + + + ^\s*password\s+(?: + + )\s+pam_pwhistory\.so.*$ + + + + + + + + + + ^\s*password\b.*\bpam_pwhistory\.so\b.*\bremember=([0-9]*).*$ + + + ^\s*remember\s*=\s*([0-9]+) + + + + ^\s*password\s+(?: + + )\s+pam_pwhistory\.so.*$ + + + + + + + + + ^\s*password\b.*\bpam_pwhistory\.so\b.*\bremember=([0-9]*).*$ + + + ^\s*remember\s*=\s*([0-9]+) + + + + ^\s*password\s+(?:(?:requisite)|(?:required))\s+pam_pwhistory\.so.*$ + + + ^\s*password\b.*\bpam_pwhistory\.so\b.*\bremember=([0-9]*).*$ + + + ^\s*remember\s*=\s*([0-9]+) + + + ^[\s]*auth[\s]+(?:required|requisite)[\s]+pam_faillock.so[^\n#]preauth[^\n#]*audit + + + ^[\s]*auth\N+pam_unix\.so + + + ^[\s]*auth[\s]+(required|\[(?=.*?\bsuccess=ok\b)(?=.*?\bnew_authtok_reqd=ok\b)(?=.*?\bignore=ignore\b)(?=.*?\bdefault=bad\b).*\])[\s]+pam_faillock\.so[\s\w\d=]+preauth[\s\S]*^[\s]*auth[\s]+(sufficient|\[(?=.*\bsuccess=done\b)(?=.*?\bnew_authtok_reqd=done\b)(?=.*?\bdefault=ignore\b).*\])[\s]+pam_unix\.so[\s\S]*^[\s]*auth[\s]+(required|\[(?=.*?\bsuccess=ok\b)(?=.*?\bnew_authtok_reqd=ok\b)(?=.*?\bignore=ignore\b)(?=.*?\bdefault=bad\b).*\])[\s]+pam_faillock\.so[\s\w\d=]+authfail + + + ^[\s]*account[\s]+(required|\[(?=.*?\bsuccess=ok\b)(?=.*?\bnew_authtok_reqd=ok\b)(?=.*?\bignore=ignore\b)(?=.*?\bdefault=bad\b).*\])[\s]+pam_faillock\.so[\s\S]*^[\s]*account[\s]+(required|\[(?=.*?\bsuccess=ok\b)(?=.*?\bnew_authtok_reqd=ok\b)(?=.*?\bignore=ignore\b)(?=.*?\bdefault=bad\b).*\])[\s]+pam_unix\.so + + + ^[\s]*auth[\s]+.+[\s]+pam_faillock.so[\s]+[^\n]*even_deny_root + + + ^[\s]*even_deny_root + + + dir\s*=\s*(\S+|"[^"]+) + + + + ^[\s]*auth[\s]+(?:required|requisite) + [\s]+pam_faillock.so[^\n#]* + + + + + + ^[\s]* + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ^ + + $ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 86400 + + + + + + + + + + 0 + + + + + + + + + ^ + + + + :[^:]+:[0-9]+:.*$ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ^(?: + + ):(?:[^:]*:){4}([^:]+):[^:]*$ + + + + + ^(?: + + :)(?:[^:]*:){2}([^:]+):(?:[^:]*:){2}[^:]*$ + + + + + + + + + + + + + + + + + ^[^#]* + + + + + + + + + ^(?: + + ):(?:[^:]*:){4}([^:]+):[^:]*$ + + + + + ^(?: + + :)(?:[^:]*:)([^:]+):(?:[^:]*:){3}[^:]*$ + + + + + + + + + + + ^(?: + + ):(?:[^:]*:){4}([^:]+):[^:]*$ + + + + + + + + + + + + + + + + + + ^(?: + + ):(?:[^:]*:){4}([^:]+):[^:]*$ + + + + + ^(?: + + :)(?:[^:]*:){2}([^:]+):(?:[^:]*:){2}[^:]*$ + + + + + + + + + + + ^(?: + + ):(?:[^:]*:){4}([^:]+):[^:]*$ + + + + + ^(?: + + :)(?:[^:]*:)([^:]+):(?:[^:]*:){3}[^:]*$ + + + + + + + + + + + ^(?: + + ):(?:[^:]*:){4}([^:]+):[^:]*$ + + + + + + + + ^(?: + + ):(?:[^:]*:){4}([^:]+):[^:]*$ + + + + + ^(?: + + :)(?:[^:]*:){2}([^:]+):(?:[^:]*:){2}[^:]*$ + + + + + + + + + + + + + + ^(?: + + ):(?:[^:]*:){4}([^:]+):[^:]*$ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 64 + + + + 8 + + + + + + + + + + + + + + + + + + + + + + + + 64 + + + + 8 + + + + + + + + + + + + + + + + + + + + + + + + 64 + + + + 8 + + + + + + + + + + + + + + + + + + + + + + + + 64 + + + + 8 + + + + + + + + ^(?: + + ):(?:[^:]*:){4}([^:]+):[^:]*$ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Ciphers + + + + + + MACs + + + + + + -oMACs= + + + + + + + / + + + + + + ^ + + :x:(\d+):.*$ + + + + + + + + + + + + + + + ^\s*auth\N+pam_unix\.so + + + ^[\s]*auth[\s]+(required|\[(?=.*?\bsuccess=ok\b)(?=.*?\bnew_authtok_reqd=ok\b)(?=.*?\bignore=ignore\b)(?=.*?\bdefault=bad\b).*\])[\s]+pam_faillock\.so[\s\w\d=]+preauth[\s\S]*^[\s]*auth[\s]+(sufficient|\[(?=.*\bsuccess=done\b)(?=.*?\bnew_authtok_reqd=done\b)(?=.*?\bdefault=ignore\b).*\])[\s]+pam_unix\.so[\s\S]*^[\s]*auth[\s]+(required|\[(?=.*?\bsuccess=ok\b)(?=.*?\bnew_authtok_reqd=ok\b)(?=.*?\bignore=ignore\b)(?=.*?\bdefault=bad\b).*\])[\s]+pam_faillock\.so[\s\w\d=]+authfail + + + ^[\s]*account[\s]+(required|\[(?=.*?\bsuccess=ok\b)(?=.*?\bnew_authtok_reqd=ok\b)(?=.*?\bignore=ignore\b)(?=.*?\bdefault=bad\b).*\])[\s]+pam_faillock\.so[\s\S]*^[\s]*account[\s]+(required|\[(?=.*?\bsuccess=ok\b)(?=.*?\bnew_authtok_reqd=ok\b)(?=.*?\bignore=ignore\b)(?=.*?\bdefault=bad\b).*\])[\s]+pam_unix\.so + + + ^[\s]*auth[\s]+.+[\s]+pam_faillock.so[\s]+[^\n]*deny=([0-9]+) + + + ^[\s]*deny[\s]*=[\s]*([0-9]+) + + + + ^\s*auth\N+pam_unix\.so + + + ^[\s]*auth[\s]+(required|\[(?=.*?\bsuccess=ok\b)(?=.*?\bnew_authtok_reqd=ok\b)(?=.*?\bignore=ignore\b)(?=.*?\bdefault=bad\b).*\])[\s]+pam_faillock\.so[\s\w\d=]+preauth[\s\S]*^[\s]*auth[\s]+(sufficient|\[(?=.*\bsuccess=done\b)(?=.*?\bnew_authtok_reqd=done\b)(?=.*?\bdefault=ignore\b).*\])[\s]+pam_unix\.so[\s\S]*^[\s]*auth[\s]+(required|\[(?=.*?\bsuccess=ok\b)(?=.*?\bnew_authtok_reqd=ok\b)(?=.*?\bignore=ignore\b)(?=.*?\bdefault=bad\b).*\])[\s]+pam_faillock\.so[\s\w\d=]+authfail + + + ^[\s]*account[\s]+(required|\[(?=.*?\bsuccess=ok\b)(?=.*?\bnew_authtok_reqd=ok\b)(?=.*?\bignore=ignore\b)(?=.*?\bdefault=bad\b).*\])[\s]+pam_faillock\.so[\s\S]*^[\s]*account[\s]+(required|\[(?=.*?\bsuccess=ok\b)(?=.*?\bnew_authtok_reqd=ok\b)(?=.*?\bignore=ignore\b)(?=.*?\bdefault=bad\b).*\])[\s]+pam_unix\.so + + + ^[\s]*auth[\s]+.+[\s]+pam_faillock.so[\s]+[^\n]*fail_interval=([0-9]+) + + + ^[\s]*fail_interval[\s]*=[\s]*([0-9]+) + + + + + ^\s*auth\N+pam_unix\.so + + + ^[\s]*auth[\s]+(required|\[(?=.*?\bsuccess=ok\b)(?=.*?\bnew_authtok_reqd=ok\b)(?=.*?\bignore=ignore\b)(?=.*?\bdefault=bad\b).*\])[\s]+pam_faillock\.so[\s\w\d=]+preauth[\s\S]*^[\s]*auth[\s]+(sufficient|\[(?=.*\bsuccess=done\b)(?=.*?\bnew_authtok_reqd=done\b)(?=.*?\bdefault=ignore\b).*\])[\s]+pam_unix\.so[\s\S]*^[\s]*auth[\s]+(required|\[(?=.*?\bsuccess=ok\b)(?=.*?\bnew_authtok_reqd=ok\b)(?=.*?\bignore=ignore\b)(?=.*?\bdefault=bad\b).*\])[\s]+pam_faillock\.so[\s\w\d=]+authfail + + + ^[\s]*account[\s]+(required|\[(?=.*?\bsuccess=ok\b)(?=.*?\bnew_authtok_reqd=ok\b)(?=.*?\bignore=ignore\b)(?=.*?\bdefault=bad\b).*\])[\s]+pam_faillock\.so[\s\S]*^[\s]*account[\s]+(required|\[(?=.*?\bsuccess=ok\b)(?=.*?\bnew_authtok_reqd=ok\b)(?=.*?\bignore=ignore\b)(?=.*?\bdefault=bad\b).*\])[\s]+pam_unix\.so + + + ^[\s]*auth[\s]+.+[\s]+pam_faillock.so[\s]+[^\n]*unlock_time=([0-9]+) + + + ^[\s]*unlock_time[\s]*=[\s]*([0-9]+) + + + + ^\-w[\s]+ + + [\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + + + + + + ^\-w[\s]+ + \/var\/log\/lastlog + [\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + + + + + ^\-w[\s]+ + \/var\/log\/tallylog + [\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + + + + ^[\s]*-a[\s]+always,exit[\s]+(?:-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+creat[\s]+|([\s]+|[,])creat([\s]+|[,])))(?:(?!-F[\s]+a\d&).)* + + + ^[\s]*-a[\s]+always,exit[\s]+(?:-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+creat[\s]+|([\s]+|[,])creat([\s]+|[,])))(?:(?!-F[\s]+a\d&).)* + + + [\s]+(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295)[\s]+)(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + + + + + (?:-F\s+exit=-EACCES) + + + + + + + (?:-F\s+exit=-EPERM) + + + + + + + (?:-F\s+exit=-EACCES) + + + + + + + (?:-F\s+exit=-EPERM) + + + + + ^[\s]*-a[\s]+always,exit[\s]+(?:-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+ftruncate[\s]+|([\s]+|[,])ftruncate([\s]+|[,])))(?:(?!-F[\s]+a\d&).)* + + + ^[\s]*-a[\s]+always,exit[\s]+(?:-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+ftruncate[\s]+|([\s]+|[,])ftruncate([\s]+|[,])))(?:(?!-F[\s]+a\d&).)* + + + [\s]+(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295)[\s]+)(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + + + + + (?:-F\s+exit=-EACCES) + + + + + + + (?:-F\s+exit=-EPERM) + + + + + + + (?:-F\s+exit=-EACCES) + + + + + + + (?:-F\s+exit=-EPERM) + + + + + ^[\s]*-a[\s]+always,exit[\s]+(?:-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+open[\s]+|([\s]+|[,])open([\s]+|[,])))(?:(?!-F[\s]+a\d&).)* + + + ^[\s]*-a[\s]+always,exit[\s]+(?:-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+open[\s]+|([\s]+|[,])open([\s]+|[,])))(?:(?!-F[\s]+a\d&).)* + + + [\s]+(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295)[\s]+)(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + + + + + (?:-F\s+exit=-EACCES) + + + + + + + (?:-F\s+exit=-EPERM) + + + + + + + (?:-F\s+exit=-EACCES) + + + + + + + (?:-F\s+exit=-EPERM) + + + + + ^[\s]*-a[\s]+always,exit[\s]+(?:-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+open_by_handle_at[\s]+|([\s]+|[,])open_by_handle_at([\s]+|[,])))(?:(?!-F[\s]+a\d&).)* + + + ^[\s]*-a[\s]+always,exit[\s]+(?:-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+open_by_handle_at[\s]+|([\s]+|[,])open_by_handle_at([\s]+|[,])))(?:(?!-F[\s]+a\d&).)* + + + [\s]+(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295)[\s]+)(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + + + + + (?:-F\s+exit=-EACCES) + + + + + + + (?:-F\s+exit=-EPERM) + + + + + + + (?:-F\s+exit=-EACCES) + + + + + + + (?:-F\s+exit=-EPERM) + + + + + ^[\s]*-a[\s]+always,exit[\s]+(?:-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+openat[\s]+|([\s]+|[,])openat([\s]+|[,])))(?:(?!-F[\s]+a\d&).)* + + + ^[\s]*-a[\s]+always,exit[\s]+(?:-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+openat[\s]+|([\s]+|[,])openat([\s]+|[,])))(?:(?!-F[\s]+a\d&).)* + + + [\s]+(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295)[\s]+)(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + + + + + (?:-F\s+exit=-EACCES) + + + + + + + (?:-F\s+exit=-EPERM) + + + + + + + (?:-F\s+exit=-EACCES) + + + + + + + (?:-F\s+exit=-EPERM) + + + + + ^[\s]*-a[\s]+always,exit[\s]+(?:-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+truncate[\s]+|([\s]+|[,])truncate([\s]+|[,])))(?:(?!-F[\s]+a\d&).)* + + + ^[\s]*-a[\s]+always,exit[\s]+(?:-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+truncate[\s]+|([\s]+|[,])truncate([\s]+|[,])))(?:(?!-F[\s]+a\d&).)* + + + [\s]+(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295)[\s]+)(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + + + + + (?:-F\s+exit=-EACCES) + + + + + + + (?:-F\s+exit=-EPERM) + + + + + + + (?:-F\s+exit=-EACCES) + + + + + + + (?:-F\s+exit=-EPERM) + + + + + + ^\-w[\s]+ + \/var\/log\/sudo.log + [\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + + + + + + + + + + + + + + + + + + + + + + + ^(/etc/ssh/(?!/))? + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ^(?:.*\s)?l1tf= + + (?:\s.*)?$ + + + + + + ^(?:.*\s)?mds= + + (?:\s.*)?$ + + + + + + ^(?:.*\s)?rng_core.default_quality= + + (?:\s.*)?$ + + + + + + ^(?:.*\s)?slub_debug= + + (?:\s.*)?$ + + + + + + ^(?:.*\s)?spec_store_bypass_disable= + + (?:\s.*)?$ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + /etc/modprobe.d + /etc/modules-load.d + /run/modprobe.d + /run/modules-load.d + /usr/lib/modprobe.d + /usr/lib/modules-load.d + + + /etc/modprobe.d + /etc/modules-load.d + /run/modprobe.d + /run/modules-load.d + /usr/lib/modprobe.d + /usr/lib/modules-load.d + + + /etc/modprobe.d + /etc/modules-load.d + /run/modprobe.d + /run/modules-load.d + /usr/lib/modprobe.d + /usr/lib/modules-load.d + + + /etc/modprobe.d + /etc/modules-load.d + /run/modprobe.d + /run/modules-load.d + /usr/lib/modprobe.d + /usr/lib/modules-load.d + + + /etc/modprobe.d + /etc/modules-load.d + /run/modprobe.d + /run/modules-load.d + /usr/lib/modprobe.d + /usr/lib/modules-load.d + + + /etc/modprobe.d + /etc/modules-load.d + /run/modprobe.d + /run/modules-load.d + /usr/lib/modprobe.d + /usr/lib/modules-load.d + + + /etc/modprobe.d + /etc/modules-load.d + /run/modprobe.d + /run/modules-load.d + /usr/lib/modprobe.d + /usr/lib/modules-load.d + + + /etc/modprobe.d + /etc/modules-load.d + /run/modprobe.d + /run/modules-load.d + /usr/lib/modprobe.d + /usr/lib/modules-load.d + + + /etc/modprobe.d + /etc/modules-load.d + /run/modprobe.d + /run/modules-load.d + /usr/lib/modprobe.d + /usr/lib/modules-load.d + + + /etc/modprobe.d + /etc/modules-load.d + /run/modprobe.d + /run/modules-load.d + /usr/lib/modprobe.d + /usr/lib/modules-load.d + + + /etc/modprobe.d + /etc/modules-load.d + /run/modprobe.d + /run/modules-load.d + /usr/lib/modprobe.d + /usr/lib/modules-load.d + + + /etc/modprobe.d + /etc/modules-load.d + /run/modprobe.d + /run/modules-load.d + /usr/lib/modprobe.d + /usr/lib/modules-load.d + + + /etc/modprobe.d + /etc/modules-load.d + /run/modprobe.d + /run/modules-load.d + /usr/lib/modprobe.d + /usr/lib/modules-load.d + + + + ^(?:(?!nobody).*)?:.*?:[1-9]\d{3,}:.*?:.*?:( + + ).*?:.* + + + + + + + + ^(?:(?!nobody).*)?:.*?:[1-9]\d{3,}:.*?:.*?:( + + ).*?:.* + + + + + + + + ^(?:(?!nobody).*)?:.*?:[1-9]\d{3,}:.*?:.*?:( + + ).*?:.* + + + + + + + + ^(?:(?!nobody).*)?:.*?:[1-9]\d{3,}:.*?:.*?:( + + ).*?:.* + + + + + + + /dev/cdrom + /dev/dvd + /dev/scd0 + /dev/sr0 + + + + ^[\s]* + + [\s]+[/\w]+[\s]+[\w]+[\s]+([^\s]+)(?:[\s]+[\d]+){2}$ + + + + + ^[\s]* + + [\s]+[/\w]+[\s]+[\w]+[\s]+([^\s]+)(?:[\s]+[\d]+){2}$ + + + + + /dev/cdrom + /dev/dvd + /dev/scd0 + /dev/sr0 + + + + ^[\s]* + + [\s]+[/\w]+[\s]+[\w]+[\s]+([^\s]+)(?:[\s]+[\d]+){2}$ + + + + + ^[\s]* + + [\s]+[/\w]+[\s]+[\w]+[\s]+([^\s]+)(?:[\s]+[\d]+){2}$ + + + + /dev/cdrom + /dev/dvd + /dev/scd0 + /dev/sr0 + + + + ^[\s]* + + [\s]+[/\w]+[\s]+[\w]+[\s]+([^\s]+)(?:[\s]+[\d]+){2}$ + + + + + ^[\s]* + + [\s]+[/\w]+[\s]+[\w]+[\s]+([^\s]+)(?:[\s]+[\d]+){2}$ + + + + + + + + + + + ^/etc/rsyslog.conf$ + + + + + + + + + + + + + + + + + + + ^/etc/rsyslog.conf$ + + + + + + + + + + + + + + + + + + + ^/etc/rsyslog.conf$ + + + + + + + + + + + + + + + + + + + + + ^(/etc/ssh/(?!/))? + + + + + + + + + + + + + + + + ^(/etc/ssh/(?!/))? + + + + + + + + + + + + ^(/etc/ssh/(?!/))? + + + + + + + + + + + + ^(/etc/ssh/(?!/))? + + + + + + + + + + + + ^(/etc/ssh/(?!/))? + + + + + + + + + + + + ^(/etc/ssh/(?!/))? + + + + + + + + + + + + ^(/etc/ssh/(?!/))? + + + + + + + + + + + + ^(/etc/ssh/(?!/))? + + + + + + + + + + + + ^(/etc/ssh/(?!/))? + + + + + + + + + + + + ^(/etc/ssh/(?!/))? + + + + + + + + + + + + ^(/etc/ssh/(?!/))? + + + + + + + + + + + + ^(/etc/ssh/(?!/))? + + + + + + + + + + + + ^(/etc/ssh/(?!/))? + + + + + + + + + + + + ^(/etc/ssh/(?!/))? + + + + + + + + + + + + ^(/etc/ssh/(?!/))? + + + + + + + + + + + + ^(/etc/ssh/(?!/))? + + + + + + + + + + + + ^(/etc/ssh/(?!/))? + + + + + + + + + + + + ^(/etc/ssh/(?!/))? + + + + + + + + + + + + ^(/etc/ssh/(?!/))? + + + + + + + + + + + + ^(/etc/ssh/(?!/))? + + + + + + + + + + + + ^(/etc/ssh/(?!/))? + + + + + + + + + + + + ^(/etc/ssh/(?!/))? + + + + + + + + + + + + + + + + ^(/etc/ssh/(?!/))? + + + + + + + + + + + + ^(/etc/ssh/(?!/))? + + + + + + + + + + + + ^(/etc/ssh/(?!/))? + + + + + + + + + + + + ^(/etc/ssh/(?!/))? + + + + + + + + + + + + + + + + ^(/etc/ssh/(?!/))? + + + + + + + + + + + + ^(/etc/ssh/(?!/))? + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + /etc/pam.d/system-auth + + + + + + + + /dev/cdrom + /dev/dvd + /dev/scd0 + /dev/sr0 + + + + + + + + + + + + + + + + + + + + + + 64 + + + + 8 + + + + + + + + + + + + build_shorthand.py from SCAP Security Guide + ssg: 0.1.76 + 2.0 + 2025-05-06T00:00:00 + + + + Ensure gpgcheck Enabled In Main yum Configuration + + ocil:ssg-ensure_gpgcheck_globally_activated_action:testaction:1 + + + + Ensure auditd Collects Information on the Use of Privileged Commands - unix_chkpwd + + ocil:ssg-audit_rules_privileged_commands_unix_chkpwd_action:testaction:1 + + + + Enable Kernel Paremeter to Log Martian Packets on all IPv4 Interfaces by Default + + ocil:ssg-sysctl_net_ipv4_conf_default_log_martians_action:testaction:1 + + + + Verify Permissions On /etc/nftables Directory + + ocil:ssg-directory_permissions_etc_nftables_action:testaction:1 + + + + All User Files and Directories In The Home Directory Must Have Mode 0750 Or Less Permissive + + ocil:ssg-accounts_users_home_files_permissions_action:testaction:1 + + + + Verify /boot/grub2/grub.cfg User Ownership + + ocil:ssg-file_owner_grub2_cfg_action:testaction:1 + + + + Configure the confidence in TPM for entropy + + ocil:ssg-grub2_rng_core_default_quality_argument_action:testaction:1 + + + + Ensure the Default Umask is Set Correctly in login.defs + + ocil:ssg-accounts_umask_etc_login_defs_action:testaction:1 + + + + Uninstall talk-server Package + + ocil:ssg-package_talk-server_removed_action:testaction:1 + + + + Disable vsyscall emulate execution only + + ocil:ssg-kernel_config_legacy_vsyscall_xonly_action:testaction:1 + + + + Disable RDS Support + + ocil:ssg-kernel_module_rds_disabled_action:testaction:1 + + + + Configure System to Forward All Mail through a specific host + + ocil:ssg-postfix_client_configure_relayhost_action:testaction:1 + + + + Verify Group Who Owns cron.monthly + + ocil:ssg-file_groupowner_cron_monthly_action:testaction:1 + + + + Ensure tftp Daemon Uses Secure Mode + + ocil:ssg-tftpd_uses_secure_mode_action:testaction:1 + + + + Ensure '/etc/system-fips' exists + + ocil:ssg-etc_system_fips_exists_action:testaction:1 + + + + Record Events that Modify the System's Discretionary Access Controls - lchown + + ocil:ssg-audit_rules_dac_modification_lchown_action:testaction:1 + + + + Uninstall squid Package + + ocil:ssg-package_squid_removed_action:testaction:1 + + + + Disable vsyscalls + + ocil:ssg-grub2_vsyscall_argument_action:testaction:1 + + + + Sign kernel modules with SHA-512 + + ocil:ssg-kernel_config_module_sig_sha512_action:testaction:1 + + + + Disable IPv6 Addressing on All IPv6 Interfaces + + ocil:ssg-sysctl_net_ipv6_conf_all_disable_ipv6_action:testaction:1 + + + + Configure SSSD LDAP Backend to Use TLS For All Transactions + + ocil:ssg-sssd_ldap_start_tls_action:testaction:1 + + + + Add noexec Option to Removable Media Partitions + + ocil:ssg-mount_option_noexec_removable_partitions_action:testaction:1 + + + + Verify Group Who Owns /etc/sysctl.d Directory + + ocil:ssg-directory_groupowner_etc_sysctld_action:testaction:1 + + + + Verify Group Who Owns /etc/sudoers File + + ocil:ssg-file_groupowner_etc_sudoers_action:testaction:1 + + + + Disable Accepting ICMP Redirects for All IPv6 Interfaces + + ocil:ssg-sysctl_net_ipv6_conf_all_accept_redirects_action:testaction:1 + + + + Set Password Hashing Algorithm in /etc/libuser.conf + + ocil:ssg-set_password_hashing_algorithm_libuserconf_action:testaction:1 + + + + Enable Kernel Parameter to Enforce DAC on Symlinks + + ocil:ssg-sysctl_fs_protected_symlinks_action:testaction:1 + + + + Verify Permissions On /etc/ipsec.d Directory + + ocil:ssg-directory_permissions_etc_ipsecd_action:testaction:1 + + + + Ensure that System Accounts Do Not Run a Shell Upon Login + + ocil:ssg-no_shelllogin_for_systemaccounts_action:testaction:1 + + + + Add nodev Option to /var/log + + ocil:ssg-mount_option_var_log_nodev_action:testaction:1 + + + + Ensure cron Is Logging To Rsyslog + + ocil:ssg-rsyslog_cron_logging_action:testaction:1 + + + + Install dnf-automatic Package + + ocil:ssg-package_dnf-automatic_installed_action:testaction:1 + + + + Limit the Number of Concurrent Login Sessions Allowed Per User + + ocil:ssg-accounts_max_concurrent_login_sessions_action:testaction:1 + + + + Ensure yum Removes Previous Package Versions + + ocil:ssg-clean_components_post_updating_action:testaction:1 + + + + Uninstall DHCP Server Package + + ocil:ssg-package_dhcp_removed_action:testaction:1 + + + + Verify Permissions on System.map Files + + ocil:ssg-file_permissions_systemmap_action:testaction:1 + + + + Enable use of Berkeley Packet Filter with seccomp + + ocil:ssg-kernel_config_seccomp_filter_action:testaction:1 + + + + Require Authentication for Emergency Systemd Target + + ocil:ssg-require_emergency_target_auth_action:testaction:1 + + + + Set SSH Client Alive Count Max + + ocil:ssg-sshd_set_keepalive_action:testaction:1 + + + + Add nodev Option to Non-Root Local Partitions + + ocil:ssg-mount_option_nodev_nonroot_local_partitions_action:testaction:1 + + + + User Initialization Files Must Not Run World-Writable Programs + + ocil:ssg-accounts_user_dot_no_world_writable_programs_action:testaction:1 + + + + All Interactive Users Must Have A Home Directory Defined + + ocil:ssg-accounts_user_interactive_home_directory_defined_action:testaction:1 + + + + Configure Accepting Router Advertisements on All IPv6 Interfaces + + ocil:ssg-sysctl_net_ipv6_conf_all_accept_ra_action:testaction:1 + + + + Add nodev Option to /tmp + + ocil:ssg-mount_option_tmp_nodev_action:testaction:1 + + + + Uninstall rsh Package + + ocil:ssg-package_rsh_removed_action:testaction:1 + + + + Add nosuid Option to /var/tmp + + ocil:ssg-mount_option_var_tmp_nosuid_action:testaction:1 + + + + Verify the SSH Private Key Files Have a Passcode + + ocil:ssg-ssh_keys_passphrase_protected_action:testaction:1 + + + + Ensure SELinux is Not Disabled + + ocil:ssg-selinux_not_disabled_action:testaction:1 + + + + Install the cron service + + ocil:ssg-package_cron_installed_action:testaction:1 + + + + Ensure PAM Enforces Password Requirements - Minimum Different Characters + + ocil:ssg-accounts_password_pam_difok_action:testaction:1 + + + + Enable seccomp to safely compute untrusted bytecode + + ocil:ssg-kernel_config_seccomp_action:testaction:1 + + + + Require Credential Prompting for Remote Access in GNOME3 + + ocil:ssg-dconf_gnome_remote_access_credential_prompt_action:testaction:1 + + + + Verify /boot/grub2/user.cfg Group Ownership + + ocil:ssg-file_groupowner_user_cfg_action:testaction:1 + + + + Verify that Shared Library Directories Have Root Ownership + + ocil:ssg-dir_ownership_library_dirs_action:testaction:1 + + + + Verify the system-wide library files in directories +"/lib", "/lib64", "/usr/lib/" and "/usr/lib64" are group-owned by root. + + ocil:ssg-root_permissions_syslibrary_files_action:testaction:1 + + + + Enable ExecShield via sysctl + + ocil:ssg-sysctl_kernel_exec_shield_action:testaction:1 + + + + Record Events that Modify User/Group Information - /etc/shadow + + ocil:ssg-audit_rules_usergroup_modification_shadow_action:testaction:1 + + + + All User Files and Directories In The Home Directory Must Have a Valid Owner + + ocil:ssg-accounts_users_home_files_ownership_action:testaction:1 + + + + Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters + + ocil:ssg-accounts_password_pam_lcredit_action:testaction:1 + + + + The Chronyd service is enabled + + ocil:ssg-service_chronyd_enabled_action:testaction:1 + + + + Install firewalld Package + + ocil:ssg-package_firewalld_installed_action:testaction:1 + + + + Verify Permissions On /etc/sudoers.d Directory + + ocil:ssg-directory_permissions_etc_sudoersd_action:testaction:1 + + + + Set GNOME3 Screensaver Inactivity Timeout + + ocil:ssg-dconf_gnome_screensaver_idle_delay_action:testaction:1 + + + + Record Events that Modify User/Group Information + + ocil:ssg-audit_rules_usergroup_modification_action:testaction:1 + + + + Verify Permissions on SSH Server config file + + ocil:ssg-file_permissions_sshd_config_action:testaction:1 + + + + Ensure Authentication Required for Single User Mode + + ocil:ssg-ensure_root_password_configured_action:testaction:1 + + + + Authorize Human Interface Devices and USB hubs in USBGuard daemon + + ocil:ssg-usbguard_allow_hid_and_hub_action:testaction:1 + + + + Ensure /tmp Located On Separate Partition + + ocil:ssg-partition_for_tmp_action:testaction:1 + + + + Enable the OpenSSH Service + + ocil:ssg-service_sshd_enabled_action:testaction:1 + + + + Verify /boot/grub2/grub.cfg Permissions + + ocil:ssg-file_permissions_grub2_cfg_action:testaction:1 + + + + Enable SSH Warning Banner + + ocil:ssg-sshd_enable_warning_banner_net_action:testaction:1 + + + + Enable Kernel Parameter to Ignore Bogus ICMP Error Responses on IPv4 Interfaces + + ocil:ssg-sysctl_net_ipv4_icmp_ignore_bogus_error_responses_action:testaction:1 + + + + Configure auditing of successful permission changes + + ocil:ssg-audit_perm_change_success_action:testaction:1 + + + + Disable Bluetooth Kernel Module + + ocil:ssg-kernel_module_bluetooth_disabled_action:testaction:1 + + + + Install libselinux Package + + ocil:ssg-package_libselinux_installed_action:testaction:1 + + + + Verify User Who Owns gshadow File + + ocil:ssg-file_owner_etc_gshadow_action:testaction:1 + + + + Uninstall net-snmp Package + + ocil:ssg-package_net-snmp_removed_action:testaction:1 + + + + Remove ftp Package + + ocil:ssg-package_ftp_removed_action:testaction:1 + + + + Ensure auditd Collects Information on the Use of Privileged Commands - poweroff + + ocil:ssg-audit_privileged_commands_poweroff_action:testaction:1 + + + + Restrict unprivileged access to the kernel syslog + + ocil:ssg-kernel_config_security_dmesg_restrict_action:testaction:1 + + + + Verify Group Who Owns Backup gshadow File + + ocil:ssg-file_groupowner_backup_etc_gshadow_action:testaction:1 + + + + Verify User Who Owns /var/log/messages File + + ocil:ssg-file_owner_var_log_messages_action:testaction:1 + + + + Record Events that Modify the System's Discretionary Access Controls - umount2 + + ocil:ssg-audit_rules_dac_modification_umount2_action:testaction:1 + + + + Ensure All Files Are Owned by a Group + + ocil:ssg-file_permissions_ungroupowned_action:testaction:1 + + + + Add nosuid Option to /dev/shm + + ocil:ssg-mount_option_dev_shm_nosuid_action:testaction:1 + + + + Audit Configuration Files Permissions are 640 or More Restrictive + + ocil:ssg-file_permissions_audit_configuration_action:testaction:1 + + + + Verify Permissions on /etc/audit/rules.d/*.rules + + ocil:ssg-file_permissions_etc_audit_rulesd_action:testaction:1 + + + + Ensure a dedicated group owns sudo + + ocil:ssg-sudo_dedicated_group_action:testaction:1 + + + + Ensure /srv Located On Separate Partition + + ocil:ssg-partition_for_srv_action:testaction:1 + + + + Randomize the address of the kernel image (KASLR) + + ocil:ssg-kernel_config_randomize_base_action:testaction:1 + + + + Enable checks on notifier call chains + + ocil:ssg-kernel_config_debug_notifiers_action:testaction:1 + + + + Set Interval For Counting Failed Password Attempts + + ocil:ssg-accounts_passwords_pam_faillock_interval_action:testaction:1 + + + + Ensure PAM Enforces Password Requirements - Minimum Different Categories + + ocil:ssg-accounts_password_pam_minclass_action:testaction:1 + + + + Record Events that Modify the System's Network Environment + + ocil:ssg-audit_rules_networkconfig_modification_action:testaction:1 + + + + Ensure Users Cannot Change GNOME3 Screensaver Settings + + ocil:ssg-dconf_gnome_screensaver_user_locks_action:testaction:1 + + + + Disable the authlogin_nsswitch_use_ldap SELinux Boolean + + ocil:ssg-sebool_authlogin_nsswitch_use_ldap_action:testaction:1 + + + + Make sure that the dconf databases are up-to-date with regards to respective keyfiles + + ocil:ssg-dconf_db_up_to_date_action:testaction:1 + + + + Record Events that Modify the System's Discretionary Access Controls - fchmod + + ocil:ssg-audit_rules_dac_modification_fchmod_action:testaction:1 + + + + Verify All Account Password Hashes are Shadowed + + ocil:ssg-accounts_password_all_shadowed_action:testaction:1 + + + + Allow Only SSH Protocol 2 + + ocil:ssg-sshd_allow_only_protocol2_action:testaction:1 + + + + Deactivate Wireless Network Interfaces + + ocil:ssg-wireless_disable_interfaces_action:testaction:1 + + + + Configure auditing of successful file creations + + ocil:ssg-audit_create_success_action:testaction:1 + + + + Install cryptsetup Package + + ocil:ssg-package_cryptsetup-luks_installed_action:testaction:1 + + + + Disable Ctrl-Alt-Del Reboot Activation + + ocil:ssg-disable_ctrlaltdel_reboot_action:testaction:1 + + + + Install the opensc Package For Multifactor Authentication + + ocil:ssg-package_opensc_installed_action:testaction:1 + + + + Only Authorized Local User Accounts Exist on Operating System + + ocil:ssg-accounts_authorized_local_users_action:testaction:1 + + + + Direct root Logins Not Allowed + + ocil:ssg-no_direct_root_logins_action:testaction:1 + + + + Enable GSSAPI Authentication + + ocil:ssg-sshd_enable_gssapi_auth_action:testaction:1 + + + + Audit Configuration Files Must Be Owned By Root + + ocil:ssg-file_ownership_audit_configuration_action:testaction:1 + + + + Ensure auditd Collects Information on Kernel Module Loading - init_module + + ocil:ssg-audit_rules_kernel_module_loading_init_action:testaction:1 + + + + Set Existing Passwords Warning Age + + ocil:ssg-accounts_password_set_warn_age_existing_action:testaction:1 + + + + Record Events that Modify the System's Discretionary Access Controls - chown + + ocil:ssg-audit_rules_dac_modification_chown_action:testaction:1 + + + + Uninstall nfs-utils Package + + ocil:ssg-package_nfs-utils_removed_action:testaction:1 + + + + Verify that system commands directories have root ownership + + ocil:ssg-dir_system_commands_root_owned_action:testaction:1 + + + + Verify User Who Owns group File + + ocil:ssg-file_owner_etc_group_action:testaction:1 + + + + Uninstall cyrus-imapd Package + + ocil:ssg-package_cyrus-imapd_removed_action:testaction:1 + + + + Encrypt Partitions + + ocil:ssg-encrypt_partitions_action:testaction:1 + + + + Ensure auditd Collects File Deletion Events by User - renameat + + ocil:ssg-audit_rules_file_deletion_events_renameat_action:testaction:1 + + + + Add usrquota Option to /home + + ocil:ssg-mount_option_home_usrquota_action:testaction:1 + + + + Ensure auditd Collects Information on the Use of Privileged Commands - usermod + + ocil:ssg-audit_rules_privileged_commands_usermod_action:testaction:1 + + + + Disable the selinuxuser_execstack SELinux Boolean + + ocil:ssg-sebool_selinuxuser_execstack_action:testaction:1 + + + + Ensure SELinux Not Disabled in /etc/default/grub + + ocil:ssg-grub2_enable_selinux_action:testaction:1 + + + + Record Access Events to Audit Log Directory + + ocil:ssg-directory_access_var_log_audit_action:testaction:1 + + + + Disable the uvcvideo module + + ocil:ssg-kernel_module_uvcvideo_disabled_action:testaction:1 + + + + Assign Expiration Date to Temporary Accounts + + ocil:ssg-account_temp_expire_date_action:testaction:1 + + + + Record Events When Privileged Executables Are Run + + ocil:ssg-audit_rules_suid_privilege_function_action:testaction:1 + + + + Set Default ip6tables Policy for Incoming Packets + + ocil:ssg-set_ip6tables_default_rule_action:testaction:1 + + + + Account Lockouts Must Be Logged + + ocil:ssg-account_passwords_pam_faillock_audit_action:testaction:1 + + + + Record Any Attempts to Run setsebool + + ocil:ssg-audit_rules_execution_setsebool_action:testaction:1 + + + + Verify that Shared Library Files Have Restrictive Permissions + + ocil:ssg-file_permissions_library_dirs_action:testaction:1 + + + + Restrict Virtual Console Root Logins + + ocil:ssg-securetty_root_login_console_only_action:testaction:1 + + + + Enable Randomized Layout of Virtual Address Space + + ocil:ssg-sysctl_kernel_randomize_va_space_action:testaction:1 + + + + Set Existing Passwords Maximum Age + + ocil:ssg-accounts_password_set_max_life_existing_action:testaction:1 + + + + Add nosuid Option to /tmp + + ocil:ssg-mount_option_tmp_nosuid_action:testaction:1 + + + + Disable X11 Forwarding + + ocil:ssg-sshd_disable_x11_forwarding_action:testaction:1 + + + + Enable Use of Privilege Separation + + ocil:ssg-sshd_use_priv_separation_action:testaction:1 + + + + Ensure that /etc/at.deny does not exist + + ocil:ssg-file_at_deny_not_exist_action:testaction:1 + + + + Install sudo Package + + ocil:ssg-package_sudo_installed_action:testaction:1 + + + + Restrict usage of ptrace to descendant processes + + ocil:ssg-sysctl_kernel_yama_ptrace_scope_action:testaction:1 + + + + Enable Kernel Parameter to Use Reverse Path Filtering on all IPv4 Interfaces by Default + + ocil:ssg-sysctl_net_ipv4_conf_default_rp_filter_action:testaction:1 + + + + Set SSH MaxSessions limit + + ocil:ssg-sshd_set_max_sessions_action:testaction:1 + + + + Verify Group Who Owns Crontab + + ocil:ssg-file_groupowner_crontab_action:testaction:1 + + + + Verify Group Who Owns /etc/shells File + + ocil:ssg-file_groupowner_etc_shells_action:testaction:1 + + + + Verify Owner on cron.weekly + + ocil:ssg-file_owner_cron_weekly_action:testaction:1 + + + + Randomize layout of sensitive kernel structures + + ocil:ssg-kernel_config_gcc_plugin_randstruct_action:testaction:1 + + + + Remove the OpenSSH Server Package + + ocil:ssg-package_openssh-server_removed_action:testaction:1 + + + + Disable IEEE 1394 (FireWire) Support + + ocil:ssg-kernel_module_firewire-core_disabled_action:testaction:1 + + + + Disable rlogin Service + + ocil:ssg-service_rlogin_disabled_action:testaction:1 + + + + Disable support for /proc/kkcore + + ocil:ssg-kernel_config_proc_kcore_action:testaction:1 + + + + Verify Group Who Owns passwd File + + ocil:ssg-file_groupowner_etc_passwd_action:testaction:1 + + + + Configure auditing of successful file modifications + + ocil:ssg-audit_modify_success_action:testaction:1 + + + + Enable Dracut FIPS Module + + ocil:ssg-enable_dracut_fips_module_action:testaction:1 + + + + Verify User Who Owns /etc/sudoers File + + ocil:ssg-file_owner_etc_sudoers_action:testaction:1 + + + + Ensure the Default Umask is Set Correctly in /etc/profile + + ocil:ssg-accounts_umask_etc_profile_action:testaction:1 + + + + Enable Encrypted X11 Forwarding + + ocil:ssg-sshd_enable_x11_forwarding_action:testaction:1 + + + + Prevent Unrestricted Mail Relaying + + ocil:ssg-postfix_prevent_unrestricted_relay_action:testaction:1 + + + + Ensure the audit Subsystem is Installed + + ocil:ssg-package_audit_installed_action:testaction:1 + + + + Set Password Hashing Rounds in /etc/login.defs + + ocil:ssg-set_password_hashing_min_rounds_logindefs_action:testaction:1 + + + + Configure Firewalld to Trust Loopback Traffic + + ocil:ssg-firewalld_loopback_traffic_trusted_action:testaction:1 + + + + Verify Owner on cron.monthly + + ocil:ssg-file_owner_cron_monthly_action:testaction:1 + + + + Configure Denying Router Solicitations on All IPv6 Interfaces + + ocil:ssg-sysctl_net_ipv6_conf_all_router_solicitations_action:testaction:1 + + + + Enable Kernel Parameter to Log Martian Packets on all IPv4 Interfaces + + ocil:ssg-sysctl_net_ipv4_conf_all_log_martians_action:testaction:1 + + + + Do not allow usercopy whitelist violations to fallback to object size + + ocil:ssg-kernel_config_hardened_usercopy_fallback_action:testaction:1 + + + + Record Any Attempts to Run semanage + + ocil:ssg-audit_rules_execution_semanage_action:testaction:1 + + + + Ensure Sudo Logfile Exists - sudo logfile + + ocil:ssg-sudo_custom_logfile_action:testaction:1 + + + + Disable Core Dumps for All Users + + ocil:ssg-disable_users_coredumps_action:testaction:1 + + + + Configure file name of core dumps + + ocil:ssg-sysctl_kernel_core_uses_pid_action:testaction:1 + + + + Record Events that Modify User/Group Information - /etc/passwd + + ocil:ssg-audit_rules_usergroup_modification_passwd_action:testaction:1 + + + + Generate some entropy during boot and runtime + + ocil:ssg-kernel_config_gcc_plugin_latent_entropy_action:testaction:1 + + + + Configure SSH Client to Use FIPS 140-2 Validated MACs: openssh.config + + ocil:ssg-harden_sshd_macs_openssh_conf_crypto_policy_action:testaction:1 + + + + Enable the kerberos_enabled SELinux Boolean + + ocil:ssg-sebool_kerberos_enabled_action:testaction:1 + + + + Verify Permissions on Backup passwd File + + ocil:ssg-file_permissions_backup_etc_passwd_action:testaction:1 + + + + Disable graphical user interface + + ocil:ssg-xwindows_remove_packages_action:testaction:1 + + + + Record Any Attempts to Run seunshare + + ocil:ssg-audit_rules_execution_seunshare_action:testaction:1 + + + + Ensure invoking users password for privilege escalation when using sudo + + ocil:ssg-sudoers_validate_passwd_action:testaction:1 + + + + Add nodev Option to /dev/shm + + ocil:ssg-mount_option_dev_shm_nodev_action:testaction:1 + + + + Enable checks on linked list manipulation + + ocil:ssg-kernel_config_debug_list_action:testaction:1 + + + + Verify Group Who Owns /etc/chrony.keys File + + ocil:ssg-file_groupowner_etc_chrony_keys_action:testaction:1 + + + + Kernel panic oops + + ocil:ssg-kernel_config_panic_on_oops_action:testaction:1 + + + + Disable loading and unloading of kernel modules + + ocil:ssg-sysctl_kernel_modules_disabled_action:testaction:1 + + + + Ensure /var/log Located On Separate Partition + + ocil:ssg-partition_for_var_log_action:testaction:1 + + + + Verify Group Who Owns group File + + ocil:ssg-file_groupowner_etc_group_action:testaction:1 + + + + Disable network management of chrony daemon + + ocil:ssg-chronyd_no_chronyc_network_action:testaction:1 + + + + Ensure gnutls-utils is installed + + ocil:ssg-package_gnutls-utils_installed_action:testaction:1 + + + + Disable debug-shell SystemD Service + + ocil:ssg-service_debug-shell_disabled_action:testaction:1 + + + + Configure SSH Server to Use FIPS 140-2 Validated MACs: opensshserver.config + + ocil:ssg-harden_sshd_macs_opensshserver_conf_crypto_policy_action:testaction:1 + + + + Configure Accepting Prefix Information in Router Advertisements on All IPv6 Interfaces By Default + + ocil:ssg-sysctl_net_ipv6_conf_default_accept_ra_pinfo_action:testaction:1 + + + + Randomize the kernel memory sections + + ocil:ssg-kernel_config_randomize_memory_action:testaction:1 + + + + Disable the IPv6 protocol + + ocil:ssg-kernel_config_ipv6_action:testaction:1 + + + + Record Events that Modify the System's Discretionary Access Controls - umount + + ocil:ssg-audit_rules_dac_modification_umount_action:testaction:1 + + + + Enable syslog-ng Service + + ocil:ssg-service_syslogng_enabled_action:testaction:1 + + + + Disable the selinuxuser_execheap SELinux Boolean + + ocil:ssg-sebool_selinuxuser_execheap_action:testaction:1 + + + + Configure Libreswan to use System Crypto Policy + + ocil:ssg-configure_libreswan_crypto_policy_action:testaction:1 + + + + Enable the selinuxuser_execmod SELinux Boolean + + ocil:ssg-sebool_selinuxuser_execmod_action:testaction:1 + + + + Verify User Who Owns Backup gshadow File + + ocil:ssg-file_owner_backup_etc_gshadow_action:testaction:1 + + + + Disable Mounting of cramfs + + ocil:ssg-kernel_module_cramfs_disabled_action:testaction:1 + + + + Ensure auditd Collects Information on the Use of Privileged Commands - chsh + + ocil:ssg-audit_rules_privileged_commands_chsh_action:testaction:1 + + + + Verify Group Who Owns /etc/iptables Directory + + ocil:ssg-directory_groupowner_etc_iptables_action:testaction:1 + + + + Install the pcsc-lite package + + ocil:ssg-package_pcsc-lite_installed_action:testaction:1 + + + + Ensure No Device Files are Unlabeled by SELinux + + ocil:ssg-selinux_all_devicefiles_labeled_action:testaction:1 + + + + zero-init everything passed by reference + + ocil:ssg-kernel_config_gcc_plugin_structleak_byref_all_action:testaction:1 + + + + Ensure auditd Collects Information on Kernel Module Loading and Unloading - finit_module + + ocil:ssg-audit_rules_kernel_module_loading_finit_action:testaction:1 + + + + Ensure PAM Displays Last Logon/Access Notification + + ocil:ssg-display_login_attempts_action:testaction:1 + + + + Configure Multiple DNS Servers in /etc/resolv.conf + + ocil:ssg-network_configure_name_resolution_action:testaction:1 + + + + Configure Microarchitectural Data Sampling mitigation + + ocil:ssg-grub2_mds_argument_action:testaction:1 + + + + Install AIDE + + ocil:ssg-package_aide_installed_action:testaction:1 + + + + Install rear Package + + ocil:ssg-package_rear_installed_action:testaction:1 + + + + Add noexec Option to /home + + ocil:ssg-mount_option_home_noexec_action:testaction:1 + + + + Verify Group Who Owns /var/log/messages File + + ocil:ssg-file_groupowner_var_log_messages_action:testaction:1 + + + + Set Default firewalld Zone for Incoming Packets + + ocil:ssg-set_firewalld_default_zone_action:testaction:1 + + + + Verify Only Root Has UID 0 + + ocil:ssg-accounts_no_uid_except_zero_action:testaction:1 + + + + Verify that System Executables Have Restrictive Permissions + + ocil:ssg-file_permissions_binary_dirs_action:testaction:1 + + + + Ensure auditd Collects Information on the Use of Privileged Commands - userhelper + + ocil:ssg-audit_rules_privileged_commands_userhelper_action:testaction:1 + + + + Ensure syslog-ng is Installed + + ocil:ssg-package_syslogng_installed_action:testaction:1 + + + + Ensure auditd Collects Information on the Use of Privileged Commands - gpasswd + + ocil:ssg-audit_rules_privileged_commands_gpasswd_action:testaction:1 + + + + Ensure auditd Collects File Deletion Events by User + + ocil:ssg-audit_rules_file_deletion_events_action:testaction:1 + + + + Verify /boot/grub2/user.cfg User Ownership + + ocil:ssg-file_owner_user_cfg_action:testaction:1 + + + + Disable the use of user namespaces + + ocil:ssg-sysctl_user_max_user_namespaces_action:testaction:1 + + + + Configure dnf-automatic to Install Available Updates Automatically + + ocil:ssg-dnf-automatic_apply_updates_action:testaction:1 + + + + Configure auditd mail_acct Action on Low Disk Space + + ocil:ssg-auditd_data_retention_action_mail_acct_action:testaction:1 + + + + Ensure McAfee Endpoint Security for Linux (ENSL) is running + + ocil:ssg-agent_mfetpd_running_action:testaction:1 + + + + Disable legacy (BSD) PTY support + + ocil:ssg-kernel_config_legacy_ptys_action:testaction:1 + + + + Ensure auditd Collects File Deletion Events by User - rename + + ocil:ssg-audit_rules_file_deletion_events_rename_action:testaction:1 + + + + Add nosuid Option to Removable Media Partitions + + ocil:ssg-mount_option_nosuid_removable_partitions_action:testaction:1 + + + + Ensure auditd Collects Information on Exporting to Media (successful) + + ocil:ssg-audit_rules_media_export_action:testaction:1 + + + + Verify Owner on cron.hourly + + ocil:ssg-file_owner_cron_hourly_action:testaction:1 + + + + Verify /boot/grub2/user.cfg Permissions + + ocil:ssg-file_permissions_efi_user_cfg_action:testaction:1 + + + + Ensure auditd Collects Information on the Use of Privileged Commands - passwd + + ocil:ssg-audit_rules_privileged_commands_passwd_action:testaction:1 + + + + Configure Sending and Accepting Shared Media Redirects by Default + + ocil:ssg-sysctl_net_ipv4_conf_default_shared_media_action:testaction:1 + + + + Ensure SELinux State is Enforcing + + ocil:ssg-selinux_state_action:testaction:1 + + + + Limit Password Reuse: system-auth + + ocil:ssg-accounts_password_pam_pwhistory_remember_system_auth_action:testaction:1 + + + + Log USBGuard daemon audit events using Linux Audit + + ocil:ssg-configure_usbguard_auditbackend_action:testaction:1 + + + + Verify Permissions on cron.monthly + + ocil:ssg-file_permissions_cron_monthly_action:testaction:1 + + + + Disable the 32-bit vDSO + + ocil:ssg-kernel_config_compat_vdso_action:testaction:1 + + + + Configure Firewalld to Use the Nftables Backend + + ocil:ssg-firewalld-backend_action:testaction:1 + + + + Verify Group Ownership of System Login Banner for Remote Connections + + ocil:ssg-file_groupowner_etc_issue_net_action:testaction:1 + + + + Ensure tmp.mount Unit Is Enabled + + ocil:ssg-systemd_tmp_mount_enabled_action:testaction:1 + + + + Add nosuid Option to /boot/efi + + ocil:ssg-mount_option_boot_efi_nosuid_action:testaction:1 + + + + Record Events that Modify the System's Discretionary Access Controls - setxattr + + ocil:ssg-audit_rules_dac_modification_setxattr_action:testaction:1 + + + + Verify Group Who Owns /etc/selinux Directory + + ocil:ssg-directory_groupowner_etc_selinux_action:testaction:1 + + + + Configure SELinux Policy + + ocil:ssg-selinux_policytype_action:testaction:1 + + + + Disable vsyscall mapping + + ocil:ssg-kernel_config_legacy_vsyscall_none_action:testaction:1 + + + + Verify nftables Service is Disabled + + ocil:ssg-service_nftables_disabled_action:testaction:1 + + + + Verify User Who Owns passwd File + + ocil:ssg-file_owner_etc_passwd_action:testaction:1 + + + + Configure immutable Audit login UIDs + + ocil:ssg-audit_immutable_login_uids_action:testaction:1 + + + + All GIDs referenced in /etc/passwd must be defined in /etc/group + + ocil:ssg-gid_passwd_group_same_action:testaction:1 + + + + Ensure Logrotate Runs Periodically + + ocil:ssg-ensure_logrotate_activated_action:testaction:1 + + + + Uninstall setroubleshoot-server Package + + ocil:ssg-package_setroubleshoot-server_removed_action:testaction:1 + + + + Add nodev Option to /var/log/audit + + ocil:ssg-mount_option_var_log_audit_nodev_action:testaction:1 + + + + Set Account Expiration Following Inactivity + + ocil:ssg-account_disable_post_pw_expiration_action:testaction:1 + + + + Ensure auditd Collects Information on the Use of Privileged Commands - ssh-keysign + + ocil:ssg-audit_rules_privileged_commands_ssh_keysign_action:testaction:1 + + + + Audit Tools Must Have a Mode of 0755 or Less Permissive + + ocil:ssg-file_audit_tools_permissions_action:testaction:1 + + + + Verify Group Who Owns /etc/ipsec.conf File + + ocil:ssg-file_groupowner_etc_ipsec_conf_action:testaction:1 + + + + Record Attempts to perform maintenance activities + + ocil:ssg-audit_sudo_log_events_action:testaction:1 + + + + Disable mutable hooks + + ocil:ssg-kernel_config_security_writable_hooks_action:testaction:1 + + + + Enforce usage of pam_wheel for su authentication + + ocil:ssg-use_pam_wheel_for_su_action:testaction:1 + + + + Disable KDump Kernel Crash Analyzer (kdump) + + ocil:ssg-service_kdump_disabled_action:testaction:1 + + + + Configure Accepting Router Preference in Router Advertisements on All IPv6 Interfaces By Default + + ocil:ssg-sysctl_net_ipv6_conf_default_accept_ra_rtr_pref_action:testaction:1 + + + + Disable GNOME3 Automount running + + ocil:ssg-dconf_gnome_disable_autorun_action:testaction:1 + + + + Ensure Logs Sent To Remote Host + + ocil:ssg-rsyslog_remote_loghost_action:testaction:1 + + + + Ensure All SUID Executables Are Authorized + + ocil:ssg-file_permissions_unauthorized_suid_action:testaction:1 + + + + Verify User Who Owns /var/log/syslog File + + ocil:ssg-file_owner_var_log_syslog_action:testaction:1 + + + + Verify Group Who Owns gshadow File + + ocil:ssg-file_groupowner_etc_gshadow_action:testaction:1 + + + + Prevent Login to Accounts With Empty Password + + ocil:ssg-no_empty_passwords_action:testaction:1 + + + + Ensure auditd Collects Information on the Use of Privileged Commands - reboot + + ocil:ssg-audit_privileged_commands_reboot_action:testaction:1 + + + + Verify Group Who Owns /var/log/syslog File + + ocil:ssg-file_groupowner_var_log_syslog_action:testaction:1 + + + + Ensure All User Initialization Files Have Mode 0740 Or Less Permissive + + ocil:ssg-file_permission_user_init_files_action:testaction:1 + + + + Record Attempts to Alter Time Through clock_settime + + ocil:ssg-audit_rules_time_clock_settime_action:testaction:1 + + + + Disable merging of slabs with similar size + + ocil:ssg-grub2_slab_nomerge_argument_action:testaction:1 + + + + Configure SSH Client to Use FIPS 140 Validated Ciphers: openssh.config + + ocil:ssg-harden_sshd_ciphers_openssh_conf_crypto_policy_action:testaction:1 + + + + Set Boot Loader Password in grub2 + + ocil:ssg-grub2_password_action:testaction:1 + + + + Verify Permissions on /var/log/syslog File + + ocil:ssg-file_permissions_var_log_syslog_action:testaction:1 + + + + Verify Group Who Owns /etc/cron.allow file + + ocil:ssg-file_groupowner_cron_allow_action:testaction:1 + + + + Configure dnf-automatic to Install Only Security Updates + + ocil:ssg-dnf-automatic_security_updates_only_action:testaction:1 + + + + Harden the operation of the BPF just-in-time compiler + + ocil:ssg-sysctl_net_core_bpf_jit_harden_action:testaction:1 + + + + Set SSH Client Alive Interval + + ocil:ssg-sshd_set_idle_timeout_action:testaction:1 + + + + Verify User Who Owns Backup passwd File + + ocil:ssg-file_owner_backup_etc_passwd_action:testaction:1 + + + + Record Events that Modify the System's Discretionary Access Controls - removexattr + + ocil:ssg-audit_rules_dac_modification_removexattr_action:testaction:1 + + + + Ensure System Log Files Have Correct Permissions + + ocil:ssg-rsyslog_files_permissions_action:testaction:1 + + + + Ensure the Default C Shell Umask is Set Correctly + + ocil:ssg-accounts_umask_etc_csh_cshrc_action:testaction:1 + + + + Disable kernel support for MISC binaries + + ocil:ssg-kernel_config_binfmt_misc_action:testaction:1 + + + + Configure Polyinstantiation of /tmp Directories + + ocil:ssg-accounts_polyinstantiated_tmp_action:testaction:1 + + + + Verify Group Who Owns /etc/ipsec.secrets File + + ocil:ssg-file_groupowner_etc_ipsec_secrets_action:testaction:1 + + + + Shutdown System When Auditing Failures Occur + + ocil:ssg-audit_rules_system_shutdown_action:testaction:1 + + + + Make the kernel text and rodata read-only + + ocil:ssg-kernel_config_strict_kernel_rwx_action:testaction:1 + + + + Avoid speculative indirect branches in kernel + + ocil:ssg-kernel_config_retpoline_action:testaction:1 + + + + Set PAM''s Password Hashing Algorithm - password-auth + + ocil:ssg-set_password_hashing_algorithm_passwordauth_action:testaction:1 + + + + Verify that Shared Library Files Have Root Ownership + + ocil:ssg-file_ownership_library_dirs_action:testaction:1 + + + + Enable Smartcards in SSSD + + ocil:ssg-sssd_enable_smartcards_action:testaction:1 + + + + Verify ufw Enabled + + ocil:ssg-service_ufw_enabled_action:testaction:1 + + + + System Audit Logs Must Have Mode 0640 or Less Permissive + + ocil:ssg-file_permissions_var_log_audit_action:testaction:1 + + + + Ensure /var/tmp Located On Separate Partition + + ocil:ssg-partition_for_var_tmp_action:testaction:1 + + + + Ensure auditd Collects Information on the Use of Privileged Commands - pam_timestamp_check + + ocil:ssg-audit_rules_privileged_commands_pam_timestamp_check_action:testaction:1 + + + + Ensure auditd Collects File Deletion Events by User - unlinkat + + ocil:ssg-audit_rules_file_deletion_events_unlinkat_action:testaction:1 + + + + Enable SSH Server firewalld Firewall Exception + + ocil:ssg-firewalld_sshd_port_enabled_action:testaction:1 + + + + Ensure No World-Writable Files Exist + + ocil:ssg-file_permissions_unauthorized_world_writable_action:testaction:1 + + + + Configure Response Mode of ARP Requests for All IPv4 Interfaces + + ocil:ssg-sysctl_net_ipv4_conf_all_arp_ignore_action:testaction:1 + + + + Resolve information before writing to audit logs + + ocil:ssg-auditd_log_format_action:testaction:1 + + + + Set GNOME3 Screensaver Lock Delay After Activation Period + + ocil:ssg-dconf_gnome_screensaver_lock_delay_action:testaction:1 + + + + Restrict Access to Kernel Message Buffer + + ocil:ssg-sysctl_kernel_dmesg_restrict_action:testaction:1 + + + + Disable Accepting Router Advertisements on all IPv6 Interfaces by Default + + ocil:ssg-sysctl_net_ipv6_conf_default_accept_ra_action:testaction:1 + + + + Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters + + ocil:ssg-accounts_password_pam_ucredit_action:testaction:1 + + + + Ensure /var/log/audit Located On Separate Partition + + ocil:ssg-partition_for_var_log_audit_action:testaction:1 + + + + Enable Kernel Parameter to Enforce DAC on Hardlinks + + ocil:ssg-sysctl_fs_protected_hardlinks_action:testaction:1 + + + + Ensure gpgcheck Enabled for Local Packages + + ocil:ssg-ensure_gpgcheck_local_packages_action:testaction:1 + + + + Enable the USBGuard Service + + ocil:ssg-service_usbguard_enabled_action:testaction:1 + + + + Record Events that Modify the System's Mandatory Access Controls in usr/share + + ocil:ssg-audit_rules_mac_modification_usr_share_action:testaction:1 + + + + Configure SSSD to Expire Offline Credentials + + ocil:ssg-sssd_offline_cred_expiration_action:testaction:1 + + + + Set number of Password Hashing Rounds - system-auth + + ocil:ssg-accounts_password_pam_unix_rounds_system_auth_action:testaction:1 + + + + Enable checks on credential management + + ocil:ssg-kernel_config_debug_credentials_action:testaction:1 + + + + Verify and Correct Ownership with RPM + + ocil:ssg-rpm_verify_ownership_action:testaction:1 + + + + Disable snmpd Service + + ocil:ssg-service_snmpd_disabled_action:testaction:1 + + + + Verify File Hashes with RPM + + ocil:ssg-rpm_verify_hashes_action:testaction:1 + + + + Verify Group Who Owns SSH Server config file + + ocil:ssg-file_groupowner_sshd_config_action:testaction:1 + + + + Install crypto-policies package + + ocil:ssg-package_crypto-policies_installed_action:testaction:1 + + + + Ensure SMEP is not disabled during boot + + ocil:ssg-grub2_nosmep_argument_absent_action:testaction:1 + + + + Install audispd-plugins Package + + ocil:ssg-package_audispd-plugins_installed_action:testaction:1 + + + + Enable SLUB/SLAB allocator poisoning + + ocil:ssg-grub2_slub_debug_argument_action:testaction:1 + + + + Verify User Who Owns Backup shadow File + + ocil:ssg-file_groupowner_backup_etc_shadow_action:testaction:1 + + + + Ensure Rsyslog Encrypts Off-Loaded Audit Records + + ocil:ssg-rsyslog_encrypt_offload_actionsendstreamdrivermode_action:testaction:1 + + + + User a virtually-mapped stack + + ocil:ssg-kernel_config_vmap_stack_action:testaction:1 + + + + Verify Group Who Owns /var/log Directory + + ocil:ssg-file_groupowner_var_log_action:testaction:1 + + + + Harden SSH client Crypto Policy + + ocil:ssg-harden_ssh_client_crypto_policy_action:testaction:1 + + + + Verify Permissions on Backup gshadow File + + ocil:ssg-file_permissions_backup_etc_gshadow_action:testaction:1 + + + + Ensure All-Squashing Disabled On All Exports + + ocil:ssg-no_all_squash_exports_action:testaction:1 + + + + Configure the Use of the pam_faillock.so Module in the /etc/pam.d/system-auth File. + + ocil:ssg-account_password_pam_faillock_system_auth_action:testaction:1 + + + + Disable GSSAPI Authentication + + ocil:ssg-sshd_disable_gssapi_auth_action:testaction:1 + + + + Enable TCP/IP syncookie support + + ocil:ssg-kernel_config_syn_cookies_action:testaction:1 + + + + Verify User Who Owns Backup group File + + ocil:ssg-file_owner_backup_etc_group_action:testaction:1 + + + + Set type of computer node name logging in audit logs + + ocil:ssg-auditd_name_format_action:testaction:1 + + + + Disable telnet Service + + ocil:ssg-service_telnet_disabled_action:testaction:1 + + + + Verify Permissions On /etc/selinux Directory + + ocil:ssg-directory_permissions_etc_selinux_action:testaction:1 + + + + Disallow kernel profiling by unprivileged users + + ocil:ssg-sysctl_kernel_perf_event_paranoid_action:testaction:1 + + + + Record Events that Modify the System's Discretionary Access Controls - lremovexattr + + ocil:ssg-audit_rules_dac_modification_lremovexattr_action:testaction:1 + + + + Enable SSH Warning Banner + + ocil:ssg-sshd_enable_warning_banner_action:testaction:1 + + + + Audit Tools Must Be Owned by Root + + ocil:ssg-file_audit_tools_ownership_action:testaction:1 + + + + Ensure auditd Collects File Deletion Events by User - unlink + + ocil:ssg-audit_rules_file_deletion_events_unlink_action:testaction:1 + + + + Configure Logind to terminate idle sessions after certain time of inactivity + + ocil:ssg-logind_session_timeout_action:testaction:1 + + + + Configure auditd Disk Error Action on Disk Error + + ocil:ssg-auditd_data_disk_error_action_action:testaction:1 + + + + Enable the GNOME3 Screen Locking On Smartcard Removal + + ocil:ssg-dconf_gnome_lock_screen_on_smartcard_removal_action:testaction:1 + + + + Record Events that Modify the System's Mandatory Access Controls + + ocil:ssg-audit_rules_mac_modification_action:testaction:1 + + + + Verify Permissions On /etc/ipsec.secrets File + + ocil:ssg-file_permissions_etc_ipsec_secrets_action:testaction:1 + + + + Disable Kernel Parameter for Accepting ICMP Redirects by Default on IPv6 Interfaces + + ocil:ssg-sysctl_net_ipv6_conf_default_accept_redirects_action:testaction:1 + + + + Disable SSH Root Login + + ocil:ssg-sshd_disable_root_login_action:testaction:1 + + + + Verify Group Ownership on SSH Server Public *.pub Key Files + + ocil:ssg-file_groupownership_sshd_pub_key_action:testaction:1 + + + + Configure auditing of unsuccessful file accesses + + ocil:ssg-audit_access_failed_action:testaction:1 + + + + Add noexec Option to /var + + ocil:ssg-mount_option_var_noexec_action:testaction:1 + + + + Remove telnet Clients + + ocil:ssg-package_telnet_removed_action:testaction:1 + + + + Set SSH Daemon LogLevel to VERBOSE + + ocil:ssg-sshd_set_loglevel_verbose_action:testaction:1 + + + + Configure Denying Router Solicitations on All IPv6 Interfaces By Default + + ocil:ssg-sysctl_net_ipv6_conf_default_router_solicitations_action:testaction:1 + + + + Make the module text and rodata read-only + + ocil:ssg-kernel_config_strict_module_rwx_action:testaction:1 + + + + Set Root Account Password Maximum Age + + ocil:ssg-accounts_password_set_max_life_root_action:testaction:1 + + + + Configure Accepting Default Router in Router Advertisements on All IPv6 Interfaces + + ocil:ssg-sysctl_net_ipv6_conf_all_accept_ra_defrtr_action:testaction:1 + + + + Disable SSH TCP Forwarding + + ocil:ssg-sshd_disable_tcp_forwarding_action:testaction:1 + + + + Verify Ownership on SSH Server Private *_key Key Files + + ocil:ssg-file_ownership_sshd_private_key_action:testaction:1 + + + + SSSD Has a Correct Trust Anchor + + ocil:ssg-sssd_has_trust_anchor_action:testaction:1 + + + + Set Password Maximum Consecutive Repeating Characters + + ocil:ssg-accounts_password_pam_maxrepeat_action:testaction:1 + + + + Ensure Only Users Logged In To Real tty Can Execute Sudo - sudo use_pty + + ocil:ssg-sudo_add_use_pty_action:testaction:1 + + + + Configure the secure_mode_insmod SELinux Boolean + + ocil:ssg-sebool_secure_mode_insmod_action:testaction:1 + + + + Configure auditing of loading and unloading of kernel modules + + ocil:ssg-audit_module_load_action:testaction:1 + + + + Verify Permissions on SSH Server Private *_key Key Files + + ocil:ssg-file_permissions_sshd_private_key_action:testaction:1 + + + + Configure System to Forward All Mail For The Root Account + + ocil:ssg-postfix_client_configure_mail_alias_action:testaction:1 + + + + Verify Group Who Owns cron.d + + ocil:ssg-file_groupowner_cron_d_action:testaction:1 + + + + Use Centralized and Automated Authentication + + ocil:ssg-account_use_centralized_automated_auth_action:testaction:1 + + + + Verify Permissions on /etc/cron.allow file + + ocil:ssg-file_permissions_cron_allow_action:testaction:1 + + + + Don't target root user in the sudoers file + + ocil:ssg-sudoers_no_root_target_action:testaction:1 + + + + Configure auditd Disk Full Action when Disk Space Is Full + + ocil:ssg-auditd_data_disk_full_action_stig_action:testaction:1 + + + + Disable Kernel Parameter for Accepting Source-Routed Packets on IPv6 Interfaces by Default + + ocil:ssg-sysctl_net_ipv6_conf_default_accept_source_route_action:testaction:1 + + + + Ensure auditd Collects Information on the Use of Privileged Commands - mount + + ocil:ssg-audit_rules_privileged_commands_mount_action:testaction:1 + + + + Install policycoreutils Package + + ocil:ssg-package_policycoreutils_installed_action:testaction:1 + + + + Prefer to use a 64-bit Operating System when supported + + ocil:ssg-prefer_64bit_os_action:testaction:1 + + + + Configure Notification of Post-AIDE Scan Details + + ocil:ssg-aide_scan_notification_action:testaction:1 + + + + Modify the System Login Banner for Remote Connections + + ocil:ssg-banner_etc_issue_net_action:testaction:1 + + + + Configure System to Forward All Mail From Postmaster to The Root Account + + ocil:ssg-postfix_client_configure_mail_alias_postmaster_action:testaction:1 + + + + The Chrony package is installed + + ocil:ssg-package_chrony_installed_action:testaction:1 + + + + Configure maximum number of process identifiers + + ocil:ssg-sysctl_kernel_pid_max_action:testaction:1 + + + + Verify Permissions on /var/log Directory + + ocil:ssg-file_permissions_var_log_action:testaction:1 + + + + Poison kernel stack before returning from syscalls + + ocil:ssg-kernel_config_gcc_plugin_stackleak_action:testaction:1 + + + + Enable FIPS Mode + + ocil:ssg-enable_fips_mode_action:testaction:1 + + + + Ensure There Are No Accounts With Blank or Null Passwords + + ocil:ssg-no_empty_passwords_etc_shadow_action:testaction:1 + + + + Ensure All Files Are Owned by a User + + ocil:ssg-no_files_unowned_by_user_action:testaction:1 + + + + Install usbguard Package + + ocil:ssg-package_usbguard_installed_action:testaction:1 + + + + Ensure Privileged Escalated Commands Cannot Execute Other Commands - sudo NOEXEC + + ocil:ssg-sudo_add_noexec_action:testaction:1 + + + + Ensure auditd Collects Information on the Use of Privileged Commands - postqueue + + ocil:ssg-audit_rules_privileged_commands_postqueue_action:testaction:1 + + + + Install scap-security-guide Package + + ocil:ssg-package_scap-security-guide_installed_action:testaction:1 + + + + Disable storing core dumps + + ocil:ssg-sysctl_kernel_core_pattern_empty_string_action:testaction:1 + + + + Limit CPU consumption of the Perf system + + ocil:ssg-sysctl_kernel_perf_cpu_time_max_percent_action:testaction:1 + + + + Set the Boot Loader Admin Username to a Non-Default Value + + ocil:ssg-grub2_admin_username_action:testaction:1 + + + + Configure auditing of unsuccessful file deletions + + ocil:ssg-audit_delete_failed_action:testaction:1 + + + + Ensure PAM password complexity module is enabled in password-auth + + ocil:ssg-accounts_password_pam_pwquality_password_auth_action:testaction:1 + + + + Explicit arguments in sudo specifications + + ocil:ssg-sudoers_explicit_command_args_action:testaction:1 + + + + Disable Avahi Server Software + + ocil:ssg-service_avahi-daemon_disabled_action:testaction:1 + + + + Ensure the Group Used by pam_wheel.so Module Exists on System and is Empty + + ocil:ssg-ensure_pam_wheel_group_empty_action:testaction:1 + + + + Disable storing core dumps + + ocil:ssg-sysctl_kernel_core_pattern_action:testaction:1 + + + + Record Events that Modify User/Group Information - /etc/gshadow + + ocil:ssg-audit_rules_usergroup_modification_gshadow_action:testaction:1 + + + + Prevent remote hosts from connecting to the proxy display + + ocil:ssg-sshd_x11_use_localhost_action:testaction:1 + + + + Add noexec Option to /dev/shm + + ocil:ssg-mount_option_dev_shm_noexec_action:testaction:1 + + + + Kernel panic timeout + + ocil:ssg-kernel_config_panic_timeout_action:testaction:1 + + + + Configure Maximum Number of Autoconfigured Addresses on All IPv6 Interfaces By Default + + ocil:ssg-sysctl_net_ipv6_conf_default_max_addresses_action:testaction:1 + + + + Verify User Who Owns /etc/chrony.keys File + + ocil:ssg-file_owner_etc_chrony_keys_action:testaction:1 + + + + Record Events that Modify the System's Discretionary Access Controls - fremovexattr + + ocil:ssg-audit_rules_dac_modification_fremovexattr_action:testaction:1 + + + + Record Events that Modify User/Group Information - /etc/group + + ocil:ssg-audit_rules_usergroup_modification_group_action:testaction:1 + + + + Disable Kernel Parameter for IP Forwarding on IPv4 Interfaces + + ocil:ssg-sysctl_net_ipv4_ip_forward_action:testaction:1 + + + + Enable the pcscd Service + + ocil:ssg-service_pcscd_enabled_action:testaction:1 + + + + Enable poison of pages after freeing + + ocil:ssg-kernel_config_page_poisoning_action:testaction:1 + + + + Verify Permissions on passwd File + + ocil:ssg-file_permissions_etc_passwd_action:testaction:1 + + + + Set PAM''s Password Hashing Algorithm + + ocil:ssg-set_password_hashing_algorithm_systemauth_action:testaction:1 + + + + Configure Backups of User Data + + ocil:ssg-configure_user_data_backups_action:testaction:1 + + + + Only the VDSM User Can Use sudo NOPASSWD + + ocil:ssg-sudo_vdsm_nopasswd_action:testaction:1 + + + + Ensure rsyslog-gnutls is installed + + ocil:ssg-package_rsyslog-gnutls_installed_action:testaction:1 + + + + Configure auditd to use audispd's syslog plugin + + ocil:ssg-auditd_audispd_syslog_plugin_activated_action:testaction:1 + + + + Verify Permissions on Backup group File + + ocil:ssg-file_permissions_backup_etc_group_action:testaction:1 + + + + Verify User Who Owns System.map Files + + ocil:ssg-file_owner_systemmap_action:testaction:1 + + + + Add noexec Option to /var/tmp + + ocil:ssg-mount_option_var_tmp_noexec_action:testaction:1 + + + + Disable Squid + + ocil:ssg-service_squid_disabled_action:testaction:1 + + + + Verify Permissions on crontab + + ocil:ssg-file_permissions_crontab_action:testaction:1 + + + + Ensure Users Re-Authenticate for Privilege Escalation - sudo !authenticate + + ocil:ssg-sudo_remove_no_authenticate_action:testaction:1 + + + + System Audit Logs Must Be Group Owned By Root + + ocil:ssg-file_group_ownership_var_log_audit_action:testaction:1 + + + + The operating system must restrict privilege elevation to authorized personnel + + ocil:ssg-sudo_restrict_privilege_elevation_to_authorized_action:testaction:1 + + + + Ensure auditd Collects Information on the Use of Privileged Commands - init + + ocil:ssg-audit_privileged_commands_init_action:testaction:1 + + + + Verify Group Who Owns Backup group File + + ocil:ssg-file_groupowner_backup_etc_group_action:testaction:1 + + + + Configure BIND to use System Crypto Policy + + ocil:ssg-configure_bind_crypto_policy_action:testaction:1 + + + + Disable Access to Network bpf() Syscall From Unprivileged Processes + + ocil:ssg-sysctl_kernel_unprivileged_bpf_disabled_accept_default_action:testaction:1 + + + + Ensure auditd Collects Information on the Use of Privileged Commands - newgrp + + ocil:ssg-audit_rules_privileged_commands_newgrp_action:testaction:1 + + + + Enable Kernel Parameter to Enforce DAC on Regular files + + ocil:ssg-sysctl_fs_protected_regular_action:testaction:1 + + + + Enable auditd Service + + ocil:ssg-service_auditd_enabled_action:testaction:1 + + + + Ensure rsyncd service is disabled + + ocil:ssg-service_rsyncd_disabled_action:testaction:1 + + + + Verify User Who Owns /etc/ipsec.d Directory + + ocil:ssg-directory_owner_etc_ipsecd_action:testaction:1 + + + + Disable kexec system call + + ocil:ssg-kernel_config_kexec_action:testaction:1 + + + + Ensure auditd Collects File Deletion Events by User - rmdir + + ocil:ssg-audit_rules_file_deletion_events_rmdir_action:testaction:1 + + + + Record attempts to alter time through adjtimex + + ocil:ssg-audit_rules_time_adjtimex_action:testaction:1 + + + + Disable SSH Support for User Known Hosts + + ocil:ssg-sshd_disable_user_known_hosts_action:testaction:1 + + + + Verify User Who Owns /var/log Directory + + ocil:ssg-file_owner_var_log_action:testaction:1 + + + + Ensure that chronyd is running under chrony user account + + ocil:ssg-chronyd_run_as_chrony_user_action:testaction:1 + + + + Enable PAM + + ocil:ssg-sshd_enable_pam_action:testaction:1 + + + + Disable Postfix Network Listening + + ocil:ssg-postfix_network_listening_disabled_action:testaction:1 + + + + Verify User Who Owns /etc/sestatus.conf File + + ocil:ssg-file_owner_etc_sestatus_conf_action:testaction:1 + + + + Configure auditd Disk Error Action on Disk Error + + ocil:ssg-auditd_data_disk_error_action_stig_action:testaction:1 + + + + Configure Time Service Maxpoll Interval + + ocil:ssg-chronyd_or_ntpd_set_maxpoll_action:testaction:1 + + + + Add noexec Option to /tmp + + ocil:ssg-mount_option_tmp_noexec_action:testaction:1 + + + + Disable the ssh_sysadm_login SELinux Boolean + + ocil:ssg-sebool_ssh_sysadm_login_action:testaction:1 + + + + Ensure auditd Collects Information on the Use of Privileged Commands + + ocil:ssg-audit_rules_privileged_commands_action:testaction:1 + + + + Verify Group Who Owns System.map Files + + ocil:ssg-file_groupowner_systemmap_action:testaction:1 + + + + Mount Remote Filesystems with noexec + + ocil:ssg-mount_option_noexec_remote_filesystems_action:testaction:1 + + + + Ensure SSH MaxStartups is configured + + ocil:ssg-sshd_set_maxstartups_action:testaction:1 + + + + Chrony Configure Pool and Server + + ocil:ssg-chronyd_configure_pool_and_server_action:testaction:1 + + + + Verify Group Who Owns /etc/nftables Directory + + ocil:ssg-directory_groupowner_etc_nftables_action:testaction:1 + + + + Verify Group Who Owns cron.daily + + ocil:ssg-file_groupowner_cron_daily_action:testaction:1 + + + + Ensure auditd Collects Information on the Use of Privileged Commands - unix_update + + ocil:ssg-audit_rules_privileged_commands_unix_update_action:testaction:1 + + + + Configure auditd space_left on Low Disk Space + + ocil:ssg-auditd_data_retention_space_left_percentage_action:testaction:1 + + + + Disable Modprobe Loading of USB Storage Driver + + ocil:ssg-kernel_module_usb-storage_disabled_action:testaction:1 + + + + Set number of Password Hashing Rounds - password-auth + + ocil:ssg-accounts_password_pam_unix_rounds_password_auth_action:testaction:1 + + + + Configure auditing of unsuccessful file modifications + + ocil:ssg-audit_modify_failed_action:testaction:1 + + + + Add noexec Option to /var/log/audit + + ocil:ssg-mount_option_var_log_audit_noexec_action:testaction:1 + + + + Do not allow ACPI methods to be inserted/replaced at run time + + ocil:ssg-kernel_config_acpi_custom_method_action:testaction:1 + + + + Disable SSH root Login with a Password (Insecure) + + ocil:ssg-sshd_disable_root_password_login_action:testaction:1 + + + + Ensure the Default Umask is Set Correctly For Interactive Users + + ocil:ssg-accounts_umask_interactive_users_action:testaction:1 + + + + Add noexec Option to /boot + + ocil:ssg-mount_option_boot_noexec_action:testaction:1 + + + + Install the SSSD Package + + ocil:ssg-package_sssd_installed_action:testaction:1 + + + + Enable dnf-automatic Timer + + ocil:ssg-timer_dnf-automatic_enabled_action:testaction:1 + + + + Verify Permissions On /etc/crypttab File + + ocil:ssg-file_permissions_etc_crypttab_action:testaction:1 + + + + Configure auditing of unsuccessful ownership changes + + ocil:ssg-audit_owner_change_failed_action:testaction:1 + + + + All Interactive Users Home Directories Must Exist + + ocil:ssg-accounts_user_interactive_home_directory_exists_action:testaction:1 + + + + Generate USBGuard Policy + + ocil:ssg-usbguard_generate_policy_action:testaction:1 + + + + Enable module signature verification + + ocil:ssg-kernel_config_module_sig_action:testaction:1 + + + + Disable Compression Or Set Compression to delayed + + ocil:ssg-sshd_disable_compression_action:testaction:1 + + + + Ensure No Daemons are Unconfined by SELinux + + ocil:ssg-selinux_confinement_of_daemons_action:testaction:1 + + + + Ensure All World-Writable Directories Are Owned by root User + + ocil:ssg-dir_perms_world_writable_root_owned_action:testaction:1 + + + + Record Attempts to Alter Time Through stime + + ocil:ssg-audit_rules_time_stime_action:testaction:1 + + + + Record Any Attempts to Run chcon + + ocil:ssg-audit_rules_execution_chcon_action:testaction:1 + + + + Disable acquiring, saving, and processing core dumps + + ocil:ssg-service_systemd-coredump_disabled_action:testaction:1 + + + + Add nosuid Option to /home + + ocil:ssg-mount_option_home_nosuid_action:testaction:1 + + + + Ensure Log Files Are Owned By Appropriate Group + + ocil:ssg-rsyslog_files_groupownership_action:testaction:1 + + + + Verify Permissions On /etc/iptables Directory + + ocil:ssg-directory_permissions_etc_iptables_action:testaction:1 + + + + Configure auditd flush priority + + ocil:ssg-auditd_data_retention_flush_action:testaction:1 + + + + Add nosuid Option to /var + + ocil:ssg-mount_option_var_nosuid_action:testaction:1 + + + + Enable checks on scatter-gather (SG) table operations + + ocil:ssg-kernel_config_debug_sg_action:testaction:1 + + + + Warn on W+X mappings found at boot + + ocil:ssg-kernel_config_debug_wx_action:testaction:1 + + + + Do Not Allow SSH Environment Options + + ocil:ssg-sshd_do_not_permit_user_env_action:testaction:1 + + + + Configure auditing of successful file accesses + + ocil:ssg-audit_access_success_action:testaction:1 + + + + Ensure All Groups on the System Have Unique Group ID + + ocil:ssg-group_unique_id_action:testaction:1 + + + + The s-nail Package Is Installed + + ocil:ssg-package_s-nail_installed_action:testaction:1 + + + + Verify ownership of System Login Banner for Remote Connections + + ocil:ssg-file_owner_etc_issue_net_action:testaction:1 + + + + Ensure Rsyslog Authenticates Off-Loaded Audit Records + + ocil:ssg-rsyslog_encrypt_offload_actionsendstreamdriverauthmode_action:testaction:1 + + + + Verify User Who Owns /etc/ipsec.secrets File + + ocil:ssg-file_owner_etc_ipsec_secrets_action:testaction:1 + + + + Enable Kernel Parameter to Enforce DAC on FIFOs + + ocil:ssg-sysctl_fs_protected_fifos_action:testaction:1 + + + + Ensure /var Located On Separate Partition + + ocil:ssg-partition_for_var_action:testaction:1 + + + + Verify User Who Owns /etc/ipsec.conf File + + ocil:ssg-file_owner_etc_ipsec_conf_action:testaction:1 + + + + Add nosuid Option to /var/log/audit + + ocil:ssg-mount_option_var_log_audit_nosuid_action:testaction:1 + + + + Ensure Users Re-Authenticate for Privilege Escalation - sudo NOPASSWD + + ocil:ssg-sudo_remove_nopasswd_action:testaction:1 + + + + Add nodev Option to /var/tmp + + ocil:ssg-mount_option_var_tmp_nodev_action:testaction:1 + + + + Set Password Hashing Algorithm in /etc/login.defs + + ocil:ssg-set_password_hashing_algorithm_logindefs_action:testaction:1 + + + + Disable the Automounter + + ocil:ssg-service_autofs_disabled_action:testaction:1 + + + + Verify permissions on System Login Banner for Remote Connections + + ocil:ssg-file_permissions_etc_issue_net_action:testaction:1 + + + + Disable Graphical Environment Startup By Setting Default Target + + ocil:ssg-xwindows_runlevel_target_action:testaction:1 + + + + Disable Ctrl-Alt-Del Burst Action + + ocil:ssg-disable_ctrlaltdel_burstaction_action:testaction:1 + + + + Remove the X Windows Package Group + + ocil:ssg-package_xorg-x11-server-common_removed_action:testaction:1 + + + + Add noexec Option to /var/log + + ocil:ssg-mount_option_var_log_noexec_action:testaction:1 + + + + Record Events that Modify the System's Discretionary Access Controls - chmod + + ocil:ssg-audit_rules_dac_modification_chmod_action:testaction:1 + + + + Record Events that Modify the System's Discretionary Access Controls - lsetxattr + + ocil:ssg-audit_rules_dac_modification_lsetxattr_action:testaction:1 + + + + Record Unsuccessful Access Attempts to Files - openat + + ocil:ssg-audit_rules_unsuccessful_file_modification_openat_action:testaction:1 + + + + Verify Permissions On /etc/sudoers File + + ocil:ssg-file_permissions_etc_sudoers_action:testaction:1 + + + + Verify the UEFI Boot Loader grub.cfg Group Ownership + + ocil:ssg-file_groupowner_efi_grub2_cfg_action:testaction:1 + + + + Ensure Software Patches Installed + + ocil:ssg-security_patches_up_to_date_action:testaction:1 + + + + Perform general configuration of Audit for OSPP + + ocil:ssg-audit_ospp_general_action:testaction:1 + + + + Enable cron Service + + ocil:ssg-service_crond_enabled_action:testaction:1 + + + + Disable Kernel Parameter for Accepting Secure ICMP Redirects on all IPv4 Interfaces + + ocil:ssg-sysctl_net_ipv4_conf_all_secure_redirects_action:testaction:1 + + + + Verify Permissions on cron.d + + ocil:ssg-file_permissions_cron_d_action:testaction:1 + + + + Ensure rsyslog is Installed + + ocil:ssg-package_rsyslog_installed_action:testaction:1 + + + + Add nodev Option to /var + + ocil:ssg-mount_option_var_nodev_action:testaction:1 + + + + Record attempts to alter time through settimeofday + + ocil:ssg-audit_rules_time_settimeofday_action:testaction:1 + + + + Specify the hash to use when signing modules + + ocil:ssg-kernel_config_module_sig_hash_action:testaction:1 + + + + Disable Accepting Packets Routed Between Local Interfaces + + ocil:ssg-sysctl_net_ipv4_conf_all_accept_local_action:testaction:1 + + + + Require Authentication for Single User Mode + + ocil:ssg-require_singleuser_auth_action:testaction:1 + + + + Enable GNOME3 Login Warning Banner + + ocil:ssg-dconf_gnome_banner_enabled_action:testaction:1 + + + + Ensure PAM Enforces Password Requirements - Maximum Consecutive Repeating Characters from Same Character Class + + ocil:ssg-accounts_password_pam_maxclassrepeat_action:testaction:1 + + + + Set the UEFI Boot Loader Password + + ocil:ssg-grub2_uefi_password_action:testaction:1 + + + + Configure TLS for rsyslog remote logging + + ocil:ssg-rsyslog_remote_tls_action:testaction:1 + + + + Disable Kernel Parameter for Accepting Source-Routed Packets on IPv4 Interfaces by Default + + ocil:ssg-sysctl_net_ipv4_conf_default_accept_source_route_action:testaction:1 + + + + Verify Permissions on cron.weekly + + ocil:ssg-file_permissions_cron_weekly_action:testaction:1 + + + + Ensure Rsyslog Encrypts Off-Loaded Audit Records + + ocil:ssg-rsyslog_encrypt_offload_defaultnetstreamdriver_action:testaction:1 + + + + Enable the File Access Policy Service + + ocil:ssg-service_fapolicyd_enabled_action:testaction:1 + + + + Uninstall rsh-server Package + + ocil:ssg-package_rsh-server_removed_action:testaction:1 + + + + Record Events that Modify the System's Discretionary Access Controls - fsetxattr + + ocil:ssg-audit_rules_dac_modification_fsetxattr_action:testaction:1 + + + + Disable compatibility with brk() + + ocil:ssg-kernel_config_compat_brk_action:testaction:1 + + + + Randomize slab freelist + + ocil:ssg-kernel_config_slab_freelist_random_action:testaction:1 + + + + Uninstall Sendmail Package + + ocil:ssg-package_sendmail_removed_action:testaction:1 + + + + Configure auditd Disk Full Action when Disk Space Is Full + + ocil:ssg-auditd_data_disk_full_action_action:testaction:1 + + + + Require Re-Authentication When Using the sudo Command + + ocil:ssg-sudo_require_reauthentication_action:testaction:1 + + + + Require Encryption for Remote Access in GNOME3 + + ocil:ssg-dconf_gnome_remote_access_encryption_action:testaction:1 + + + + Verify Group Who Owns /etc/at.allow file + + ocil:ssg-file_groupowner_at_allow_action:testaction:1 + + + + Disable SSH Access via Empty Passwords + + ocil:ssg-sshd_disable_empty_passwords_action:testaction:1 + + + + Ensure Users Re-Authenticate for Privilege Escalation - sudo + + ocil:ssg-sudo_require_authentication_action:testaction:1 + + + + Verify Permissions on gshadow File + + ocil:ssg-file_permissions_etc_gshadow_action:testaction:1 + + + + Enable Certmap in SSSD + + ocil:ssg-sssd_enable_certmap_action:testaction:1 + + + + Disable hibernation + + ocil:ssg-kernel_config_hibernation_action:testaction:1 + + + + Disable the GNOME3 Login Restart and Shutdown Buttons + + ocil:ssg-dconf_gnome_disable_restart_shutdown_action:testaction:1 + + + + Configure L1 Terminal Fault mitigations + + ocil:ssg-grub2_l1tf_argument_action:testaction:1 + + + + Disable Kernel Parameter for Sending ICMP Redirects on all IPv4 Interfaces by Default + + ocil:ssg-sysctl_net_ipv4_conf_default_send_redirects_action:testaction:1 + + + + Ensure auditd Collects Information on the Use of Privileged Commands - crontab + + ocil:ssg-audit_rules_privileged_commands_crontab_action:testaction:1 + + + + Limit Users' SSH Access + + ocil:ssg-sshd_limit_user_access_action:testaction:1 + + + + Ensure All SGID Executables Are Authorized + + ocil:ssg-file_permissions_unauthorized_sgid_action:testaction:1 + + + + Enable randomization of the page allocator + + ocil:ssg-grub2_page_alloc_shuffle_argument_action:testaction:1 + + + + Configure GNOME3 DConf User Profile + + ocil:ssg-enable_dconf_user_profile_action:testaction:1 + + + + Enable GNOME3 Screensaver Idle Activation + + ocil:ssg-dconf_gnome_screensaver_idle_activation_enabled_action:testaction:1 + + + + Enable authselect + + ocil:ssg-enable_authselect_action:testaction:1 + + + + Disable x86 vsyscall emulation + + ocil:ssg-kernel_config_x86_vsyscall_emulation_action:testaction:1 + + + + Ensure System is Not Acting as a Network Sniffer + + ocil:ssg-network_sniffer_disabled_action:testaction:1 + + + + Ensure that /etc/cron.deny does not exist + + ocil:ssg-file_cron_deny_not_exist_action:testaction:1 + + + + Install nftables Package + + ocil:ssg-package_nftables_installed_action:testaction:1 + + + + Verify Group Who Owns cron.hourly + + ocil:ssg-file_groupowner_cron_hourly_action:testaction:1 + + + + Disable Odd Job Daemon (oddjobd) + + ocil:ssg-service_oddjobd_disabled_action:testaction:1 + + + + Ensure all users last password change date is in the past + + ocil:ssg-accounts_password_last_change_is_in_past_action:testaction:1 + + + + Uninstall tftp-server Package + + ocil:ssg-package_tftp-server_removed_action:testaction:1 + + + + Configure auditd max_log_file_action Upon Reaching Maximum Log Size + + ocil:ssg-auditd_data_retention_max_log_file_action_stig_action:testaction:1 + + + + Verify that Shared Library Directories Have Root Group Ownership + + ocil:ssg-dir_group_ownership_library_dirs_action:testaction:1 + + + + Configure AIDE to Verify the Audit Tools + + ocil:ssg-aide_check_audit_tools_action:testaction:1 + + + + Ensure auditd Collects Information on Kernel Module Loading and Unloading + + ocil:ssg-audit_rules_kernel_module_loading_action:testaction:1 + + + + Firewalld Must Employ a Deny-all, Allow-by-exception Policy for Allowing Connections to Other Systems + + ocil:ssg-configured_firewalld_default_deny_action:testaction:1 + + + + Audit Tools Must Be Group-owned by Root + + ocil:ssg-file_audit_tools_group_ownership_action:testaction:1 + + + + Verify Permissions on /etc/shells File + + ocil:ssg-file_permissions_etc_shells_action:testaction:1 + + + + Verify Permissions on SSH Server Public *.pub Key Files + + ocil:ssg-file_permissions_sshd_pub_key_action:testaction:1 + + + + Ensure SSH LoginGraceTime is configured + + ocil:ssg-sshd_set_login_grace_time_action:testaction:1 + + + + Ensure Log Files Are Owned By Appropriate User + + ocil:ssg-rsyslog_files_ownership_action:testaction:1 + + + + Enable Postfix Service + + ocil:ssg-service_postfix_enabled_action:testaction:1 + + + + Record Attempts to Alter Logon and Logout Events - faillock + + ocil:ssg-audit_rules_login_events_faillock_action:testaction:1 + + + + The Installed Operating System Is Vendor Supported + + ocil:ssg-installed_OS_is_vendor_supported_action:testaction:1 + + + + Ensure that User Home Directories are not Group-Writable or World-Readable + + ocil:ssg-file_permissions_home_dirs_action:testaction:1 + + + + Verify Permissions On /etc/sysctl.d Directory + + ocil:ssg-directory_permissions_etc_sysctld_action:testaction:1 + + + + Verify Owner on SSH Server config file + + ocil:ssg-file_owner_sshd_config_action:testaction:1 + + + + Verify the UEFI Boot Loader grub.cfg Permissions + + ocil:ssg-file_permissions_efi_grub2_cfg_action:testaction:1 + + + + Ensure auditd Collects Information on the Use of Privileged Commands - shutdown + + ocil:ssg-audit_privileged_commands_shutdown_action:testaction:1 + + + + Verify firewalld Enabled + + ocil:ssg-service_firewalld_enabled_action:testaction:1 + + + + Record Any Attempts to Run chacl + + ocil:ssg-audit_rules_execution_chacl_action:testaction:1 + + + + Uninstall quagga Package + + ocil:ssg-package_quagga_removed_action:testaction:1 + + + + Disable chrony daemon from acting as server + + ocil:ssg-chronyd_client_only_action:testaction:1 + + + + Record Any Attempts to Run ssh-agent + + ocil:ssg-audit_rules_privileged_commands_ssh_agent_action:testaction:1 + + + + Certificate status checking in SSSD + + ocil:ssg-sssd_certificate_verification_action:testaction:1 + + + + Verify Group Who Owns /etc/sestatus.conf File + + ocil:ssg-file_groupowner_etc_sestatus_conf_action:testaction:1 + + + + Uninstall talk Package + + ocil:ssg-package_talk_removed_action:testaction:1 + + + + Harden common str/mem functions against buffer overflows + + ocil:ssg-kernel_config_fortify_source_action:testaction:1 + + + + Disallow merge of slab caches + + ocil:ssg-kernel_config_slab_merge_default_action:testaction:1 + + + + Force frequent session key renegotiation + + ocil:ssg-sshd_rekey_limit_action:testaction:1 + + + + Record Unsuccessful Access Attempts to Files - open_by_handle_at + + ocil:ssg-audit_rules_unsuccessful_file_modification_open_by_handle_at_action:testaction:1 + + + + Verify Permissions on cron.hourly + + ocil:ssg-file_permissions_cron_hourly_action:testaction:1 + + + + Configure the Use of the pam_faillock.so Module in the /etc/pam.d/password-auth File. + + ocil:ssg-account_password_pam_faillock_password_auth_action:testaction:1 + + + + Set number of records to cause an explicit flush to audit logs + + ocil:ssg-auditd_freq_action:testaction:1 + + + + Enable automatic signing of all modules + + ocil:ssg-kernel_config_module_sig_all_action:testaction:1 + + + + Configure Accepting Prefix Information in Router Advertisements on All IPv6 Interfaces + + ocil:ssg-sysctl_net_ipv6_conf_all_accept_ra_pinfo_action:testaction:1 + + + + Install OpenSSH client software + + ocil:ssg-package_openssh-clients_installed_action:testaction:1 + + + + Unmap kernel when running in userspace (aka KAISER) + + ocil:ssg-kernel_config_unmap_kernel_at_el0_action:testaction:1 + + + + Configure SSSD LDAP Backend Client to Demand a Valid Certificate from the Server + + ocil:ssg-sssd_ldap_configure_tls_reqcert_action:testaction:1 + + + + Ensure PAM Enforces Password Requirements - Prevent the Use of Dictionary Words + + ocil:ssg-accounts_password_pam_dictcheck_action:testaction:1 + + + + Verify /boot/grub2/user.cfg User Ownership + + ocil:ssg-file_owner_efi_user_cfg_action:testaction:1 + + + + Detect stack corruption on calls to schedule() + + ocil:ssg-kernel_config_sched_stack_end_check_action:testaction:1 + + + + Ensure logrotate is Installed + + ocil:ssg-package_logrotate_installed_action:testaction:1 + + + + Enable poison without sanity check + + ocil:ssg-kernel_config_page_poisoning_no_sanity_action:testaction:1 + + + + Ensure Users Cannot Change GNOME3 Session Idle Settings + + ocil:ssg-dconf_gnome_session_idle_user_locks_action:testaction:1 + + + + Verify Permissions on Backup shadow File + + ocil:ssg-file_permissions_backup_etc_shadow_action:testaction:1 + + + + Configure Firewalld to Restrict Loopback Traffic + + ocil:ssg-firewalld_loopback_traffic_restricted_action:testaction:1 + + + + Configure the polyinstantiation_enabled SELinux Boolean + + ocil:ssg-sebool_polyinstantiation_enabled_action:testaction:1 + + + + Specify module signing key to use + + ocil:ssg-kernel_config_module_sig_key_action:testaction:1 + + + + Build and Test AIDE Database + + ocil:ssg-aide_build_database_action:testaction:1 + + + + Verify Group Who Owns /etc/sudoers.d Directory + + ocil:ssg-directory_groupowner_etc_sudoersd_action:testaction:1 + + + + Uninstall vsftpd Package + + ocil:ssg-package_vsftpd_removed_action:testaction:1 + + + + Set Account Expiration Following Inactivity in system-auth + + ocil:ssg-account_disable_inactivity_system_auth_action:testaction:1 + + + + Set Account Expiration Following Inactivity in password-auth + + ocil:ssg-account_disable_inactivity_password_auth_action:testaction:1 + + + + Set kernel parameter 'crypto.fips_enabled' to 1 + + ocil:ssg-sysctl_crypto_fips_enabled_action:testaction:1 + + + + Verify Owner on crontab + + ocil:ssg-file_owner_crontab_action:testaction:1 + + + + Verify that System Executable Directories Have Restrictive Permissions + + ocil:ssg-dir_permissions_binary_dirs_action:testaction:1 + + + + Ensure PAM Enforces Password Requirements - Minimum Length + + ocil:ssg-accounts_password_pam_minlen_action:testaction:1 + + + + Verify Group Who Owns /etc/ipsec.d Directory + + ocil:ssg-directory_groupowner_etc_ipsecd_action:testaction:1 + + + + Verify User Who Owns /etc/cron.allow file + + ocil:ssg-file_owner_cron_allow_action:testaction:1 + + + + Configure the root Account for Failed Password Attempts + + ocil:ssg-accounts_passwords_pam_faillock_deny_root_action:testaction:1 + + + + Configure Accepting Default Router in Router Advertisements on All IPv6 Interfaces By Default + + ocil:ssg-sysctl_net_ipv6_conf_default_accept_ra_defrtr_action:testaction:1 + + + + Record Unsuccessful Access Attempts to Files - creat + + ocil:ssg-audit_rules_unsuccessful_file_modification_creat_action:testaction:1 + + + + Harden memory copies between kernel and userspace + + ocil:ssg-kernel_config_hardened_usercopy_action:testaction:1 + + + + Disable GNOME3 Automount Opening + + ocil:ssg-dconf_gnome_disable_automount_open_action:testaction:1 + + + + Disable PubkeyAuthentication Authentication + + ocil:ssg-sshd_disable_pubkey_auth_action:testaction:1 + + + + Configure auditd admin_space_left Action on Low Disk Space + + ocil:ssg-auditd_data_retention_admin_space_left_action_action:testaction:1 + + + + Enforce Usage of pam_wheel with Group Parameter for su Authentication + + ocil:ssg-use_pam_wheel_group_for_su_action:testaction:1 + + + + Account Lockouts Must Persist + + ocil:ssg-account_passwords_pam_faillock_dir_action:testaction:1 + + + + Lock Accounts Must Persist + + ocil:ssg-accounts_passwords_pam_faillock_dir_action:testaction:1 + + + + Configure kernel to zero out memory before allocation + + ocil:ssg-grub2_init_on_alloc_argument_action:testaction:1 + + + + Use Only Strong MACs + + ocil:ssg-sshd_use_strong_macs_action:testaction:1 + + + + Ensure auditd Collects Information on the Use of Privileged Commands - umount + + ocil:ssg-audit_rules_privileged_commands_umount_action:testaction:1 + + + + Extend Audit Backlog Limit for the Audit Daemon + + ocil:ssg-grub2_audit_backlog_limit_argument_action:testaction:1 + + + + The Postfix package is installed + + ocil:ssg-package_postfix_installed_action:testaction:1 + + + + Trigger a kernel BUG when data corruption is detected + + ocil:ssg-kernel_config_bug_on_data_corruption_action:testaction:1 + + + + Verify Group Who Owns cron.deny + + ocil:ssg-file_groupowner_cron_deny_action:testaction:1 + + + + Disable Access to Network bpf() Syscall From Unprivileged Processes + + ocil:ssg-sysctl_kernel_unprivileged_bpf_disabled_action:testaction:1 + + + + Disallow magic SysRq key + + ocil:ssg-sysctl_kernel_sysrq_action:testaction:1 + + + + Enable systemd-journald Service + + ocil:ssg-service_systemd-journald_enabled_action:testaction:1 + + + + Ensure PAM Enforces Password Requirements - Minimum Special Characters + + ocil:ssg-accounts_password_pam_ocredit_action:testaction:1 + + + + Ensure that Users Path Contains Only Local Directories + + ocil:ssg-accounts_user_home_paths_only_action:testaction:1 + + + + System Audit Logs Must Have Mode 0750 or Less Permissive + + ocil:ssg-directory_permissions_var_log_audit_action:testaction:1 + + + + Configure Low Address Space To Protect From User Allocation + + ocil:ssg-kernel_config_default_mmap_min_addr_action:testaction:1 + + + + Disable GNOME3 Automounting + + ocil:ssg-dconf_gnome_disable_automount_action:testaction:1 + + + + Record Unsuccessful Access Attempts to Files - open + + ocil:ssg-audit_rules_unsuccessful_file_modification_open_action:testaction:1 + + + + Disable Host-Based Authentication + + ocil:ssg-disable_host_auth_action:testaction:1 + + + + System Audit Logs Must Be Owned By Root + + ocil:ssg-file_ownership_var_log_audit_action:testaction:1 + + + + Add nosuid Option to /boot + + ocil:ssg-mount_option_boot_nosuid_action:testaction:1 + + + + Write Audit Logs to the Disk + + ocil:ssg-auditd_write_logs_action:testaction:1 + + + + Configure auditd space_left Action on Low Disk Space + + ocil:ssg-auditd_data_retention_space_left_action_action:testaction:1 + + + + Configure Maximum Number of Autoconfigured Addresses on All IPv6 Interfaces + + ocil:ssg-sysctl_net_ipv6_conf_all_max_addresses_action:testaction:1 + + + + Configure ARP filtering for All IPv4 Interfaces + + ocil:ssg-sysctl_net_ipv4_conf_all_arp_filter_action:testaction:1 + + + + Require modules to be validly signed + + ocil:ssg-kernel_config_module_sig_force_action:testaction:1 + + + + Verify that System Executables Have Root Ownership + + ocil:ssg-file_ownership_binary_dirs_action:testaction:1 + + + + Limit Password Reuse + + ocil:ssg-accounts_password_pam_unix_remember_action:testaction:1 + + + + Disable vsyscall emulation + + ocil:ssg-kernel_config_legacy_vsyscall_emulate_action:testaction:1 + + + + Configure auditing of unsuccessful file creations + + ocil:ssg-audit_create_failed_action:testaction:1 + + + + Verify /boot/grub2/user.cfg Group Ownership + + ocil:ssg-file_groupowner_efi_user_cfg_action:testaction:1 + + + + Ensure Oracle Linux GPG Key Installed + + ocil:ssg-ensure_oracle_gpgkey_installed_action:testaction:1 + + + + Include Local Events in Audit Logs + + ocil:ssg-auditd_local_events_action:testaction:1 + + + + Stack Protector buffer overlow detection + + ocil:ssg-kernel_config_stackprotector_action:testaction:1 + + + + Add grpquota Option to /home + + ocil:ssg-mount_option_home_grpquota_action:testaction:1 + + + + Limit Password Reuse: password-auth + + ocil:ssg-accounts_password_pam_pwhistory_remember_password_auth_action:testaction:1 + + + + Install the OpenSSH Server Package + + ocil:ssg-package_openssh-server_installed_action:testaction:1 + + + + Ensure auditd Collects Information on the Use of Privileged Commands - postdrop + + ocil:ssg-audit_rules_privileged_commands_postdrop_action:testaction:1 + + + + Ensure auditd Collects System Administrator Actions - /etc/sudoers.d/ + + ocil:ssg-audit_rules_sudoers_d_action:testaction:1 + + + + Disable Kernel Parameter for IPv6 Forwarding + + ocil:ssg-sysctl_net_ipv6_conf_all_forwarding_action:testaction:1 + + + + Record Attempts to Alter the localtime File + + ocil:ssg-audit_rules_time_watch_localtime_action:testaction:1 + + + + Disable Kernel Parameter for IPv4 Forwarding on all IPv4 Interfaces + + ocil:ssg-sysctl_net_ipv4_conf_all_forwarding_action:testaction:1 + + + + Install fapolicyd Package + + ocil:ssg-package_fapolicyd_installed_action:testaction:1 + + + + Set the GNOME3 Login Warning Banner Text + + ocil:ssg-dconf_gnome_login_banner_text_action:testaction:1 + + + + Enforce Spectre v2 mitigation + + ocil:ssg-grub2_spectre_v2_argument_action:testaction:1 + + + + Disable Kernel Parameter for Accepting Source-Routed Packets on all IPv6 Interfaces + + ocil:ssg-sysctl_net_ipv6_conf_all_accept_source_route_action:testaction:1 + + + + Configure Auto Configuration on All IPv6 Interfaces By Default + + ocil:ssg-sysctl_net_ipv6_conf_default_autoconf_action:testaction:1 + + + + Prevent applications from mapping low portion of virtual memory + + ocil:ssg-sysctl_vm_mmap_min_addr_action:testaction:1 + + + + Verify Permissions On /etc/ipsec.conf File + + ocil:ssg-file_permissions_etc_ipsec_conf_action:testaction:1 + + + + Enable Kernel Parameter to Use TCP Syncookies on Network Interfaces + + ocil:ssg-sysctl_net_ipv4_tcp_syncookies_action:testaction:1 + + + + Force initialization of variables containing userspace addresses + + ocil:ssg-kernel_config_gcc_plugin_structleak_action:testaction:1 + + + + Emulate Privileged Access Never (PAN) + + ocil:ssg-kernel_config_arm64_sw_ttbr0_pan_action:testaction:1 + + + + Disable IPv6 Addressing on IPv6 Interfaces by Default + + ocil:ssg-sysctl_net_ipv6_conf_default_disable_ipv6_action:testaction:1 + + + + Add nosuid Option to /srv + + ocil:ssg-mount_option_srv_nosuid_action:testaction:1 + + + + Disable the GNOME3 Login User List + + ocil:ssg-dconf_gnome_disable_user_list_action:testaction:1 + + + + Disable IA32 emulation + + ocil:ssg-kernel_config_ia32_emulation_action:testaction:1 + + + + Disable Recovery Booting + + ocil:ssg-grub2_disable_recovery_action:testaction:1 + + + + Ensure rsyslog Does Not Accept Remote Messages Unless Acting As Log Server + + ocil:ssg-rsyslog_nolisten_action:testaction:1 + + + + Ensure All Accounts on the System Have Unique Names + + ocil:ssg-account_unique_name_action:testaction:1 + + + + Verify Group Who Owns cron.weekly + + ocil:ssg-file_groupowner_cron_weekly_action:testaction:1 + + + + Install Smart Card Packages For Multifactor Authentication + + ocil:ssg-install_smartcard_packages_action:testaction:1 + + + + Configure SSH Server to Use FIPS 140-2 Validated Ciphers: opensshserver.config + + ocil:ssg-harden_sshd_ciphers_opensshserver_conf_crypto_policy_action:testaction:1 + + + + Verify /boot/grub2/grub.cfg Group Ownership + + ocil:ssg-file_groupowner_grub2_cfg_action:testaction:1 + + + + Enable Kernel Page-Table Isolation (KPTI) + + ocil:ssg-grub2_pti_argument_action:testaction:1 + + + + Verify No netrc Files Exist + + ocil:ssg-no_netrc_files_action:testaction:1 + + + + Record Attempts to Alter Logon and Logout Events - tallylog + + ocil:ssg-audit_rules_login_events_tallylog_action:testaction:1 + + + + System Audit Directories Must Be Group Owned By Root + + ocil:ssg-directory_group_ownership_var_log_audit_action:testaction:1 + + + + All Interactive User Home Directories Must Have mode 0750 Or Less Permissive + + ocil:ssg-file_permissions_home_directories_action:testaction:1 + + + + Ensure nss-tools is installed + + ocil:ssg-package_nss-tools_installed_action:testaction:1 + + + + Ensure auditd Collects Information on the Use of Privileged Commands - at + + ocil:ssg-audit_rules_privileged_commands_at_action:testaction:1 + + + + Verify Group Ownership on SSH Server Private *_key Key Files + + ocil:ssg-file_groupownership_sshd_private_key_action:testaction:1 + + + + Disable SSH Server If Possible + + ocil:ssg-service_sshd_disabled_action:testaction:1 + + + + Configure Polyinstantiation of /var/tmp Directories + + ocil:ssg-accounts_polyinstantiated_var_tmp_action:testaction:1 + + + + Verify Owner on cron.daily + + ocil:ssg-file_owner_cron_daily_action:testaction:1 + + + + Enable logrotate Timer + + ocil:ssg-timer_logrotate_enabled_action:testaction:1 + + + + All Interactive User Home Directories Must Be Group-Owned By The Primary Group + + ocil:ssg-file_groupownership_home_directories_action:testaction:1 + + + + Set Default iptables Policy for Incoming Packets + + ocil:ssg-set_iptables_default_rule_action:testaction:1 + + + + Remove Rsh Trust Files + + ocil:ssg-no_rsh_trust_files_action:testaction:1 + + + + Verify that All World-Writable Directories Have Sticky Bits Set + + ocil:ssg-dir_perms_world_writable_sticky_bits_action:testaction:1 + + + + Configure Auto Configuration on All IPv6 Interfaces + + ocil:ssg-sysctl_net_ipv6_conf_all_autoconf_action:testaction:1 + + + + Remove the kernel mapping in user mode + + ocil:ssg-kernel_config_page_table_isolation_action:testaction:1 + + + + Ensure auditd Collects Information on the Use of Privileged Commands - kmod + + ocil:ssg-audit_rules_privileged_commands_kmod_action:testaction:1 + + + + Uninstall telnet-server Package + + ocil:ssg-package_telnet-server_removed_action:testaction:1 + + + + Verify User Who Owns /etc/selinux Directory + + ocil:ssg-directory_owner_etc_selinux_action:testaction:1 + + + + Install openscap-scanner Package + + ocil:ssg-package_openscap-scanner_installed_action:testaction:1 + + + + Ensure the Logon Failure Delay is Set Correctly in login.defs + + ocil:ssg-accounts_logon_fail_delay_action:testaction:1 + + + + Ensure auditd Collects Information on Kernel Module Unloading - delete_module + + ocil:ssg-audit_rules_kernel_module_loading_delete_action:testaction:1 + + + + Verify User Who Owns shadow File + + ocil:ssg-file_owner_etc_shadow_action:testaction:1 + + + + Verify User Who Owns /etc/crypttab File + + ocil:ssg-file_owner_etc_crypttab_action:testaction:1 + + + + Verify Permissions On /etc/chrony.keys File + + ocil:ssg-file_permissions_etc_chrony_keys_action:testaction:1 + + + + Verify that Shared Library Directories Have Restrictive Permissions + + ocil:ssg-dir_permissions_library_dirs_action:testaction:1 + + + + Record Events that Modify the System's Discretionary Access Controls - fchown + + ocil:ssg-audit_rules_dac_modification_fchown_action:testaction:1 + + + + Disable At Service (atd) + + ocil:ssg-service_atd_disabled_action:testaction:1 + + + + Ensure auditd Collects System Administrator Actions - /etc/sudoers + + ocil:ssg-audit_rules_sudoers_action:testaction:1 + + + + Strong Stack Protector + + ocil:ssg-kernel_config_stackprotector_strong_action:testaction:1 + + + + Configure the Firewalld Ports + + ocil:ssg-configure_firewalld_ports_action:testaction:1 + + + + Install policycoreutils-python-utils package + + ocil:ssg-package_policycoreutils-python-utils_installed_action:testaction:1 + + + + Configure AIDE to Use FIPS 140-2 for Validating Hashes + + ocil:ssg-aide_use_fips_hashes_action:testaction:1 + + + + Remove Host-Based Authentication Files + + ocil:ssg-no_host_based_files_action:testaction:1 + + + + Ensure SMAP is not disabled during boot + + ocil:ssg-grub2_nosmap_argument_absent_action:testaction:1 + + + + Verify iptables Enabled + + ocil:ssg-service_iptables_enabled_action:testaction:1 + + + + Enable different security models + + ocil:ssg-kernel_config_security_action:testaction:1 + + + + Disable CAN Support + + ocil:ssg-kernel_module_can_disabled_action:testaction:1 + + + + Perform full reference count validation + + ocil:ssg-kernel_config_refcount_full_action:testaction:1 + + + + Enable rsyslog Service + + ocil:ssg-service_rsyslog_enabled_action:testaction:1 + + + + Restrict Serial Port Root Logins + + ocil:ssg-restrict_serial_port_logins_action:testaction:1 + + + + Appropriate Action Must be Setup When the Internal Audit Event Queue is Full + + ocil:ssg-auditd_overflow_action_action:testaction:1 + + + + Ensure auditd Collects Information on the Use of Privileged Commands - su + + ocil:ssg-audit_rules_privileged_commands_su_action:testaction:1 + + + + Configure SNMP Service to Use Only SNMPv3 or Newer + + ocil:ssg-snmpd_use_newer_protocol_action:testaction:1 + + + + Disable Accepting ICMP Redirects for All IPv4 Interfaces + + ocil:ssg-sysctl_net_ipv4_conf_all_accept_redirects_action:testaction:1 + + + + Verify User Who Owns /etc/sudoers.d Directory + + ocil:ssg-directory_owner_etc_sudoersd_action:testaction:1 + + + + Ensure that System Accounts Are Locked + + ocil:ssg-no_password_auth_for_systemaccounts_action:testaction:1 + + + + Enable SSH Print Last Log + + ocil:ssg-sshd_print_last_log_action:testaction:1 + + + + Mount Remote Filesystems with nosuid + + ocil:ssg-mount_option_nosuid_remote_filesystems_action:testaction:1 + + + + Verify that System Executable Have Root Ownership + + ocil:ssg-dir_ownership_binary_dirs_action:testaction:1 + + + + Configure Accepting Router Preference in Router Advertisements on All IPv6 Interfaces + + ocil:ssg-sysctl_net_ipv6_conf_all_accept_ra_rtr_pref_action:testaction:1 + + + + Configure session renegotiation for SSH client + + ocil:ssg-ssh_client_rekey_limit_action:testaction:1 + + + + Configure SSH to use System Crypto Policy + + ocil:ssg-configure_ssh_crypto_policy_action:testaction:1 + + + + Make the auditd Configuration Immutable + + ocil:ssg-audit_rules_immutable_action:testaction:1 + + + + Configure PAM in SSSD Services + + ocil:ssg-sssd_enable_pam_services_action:testaction:1 + + + + Set Password Minimum Length in login.defs + + ocil:ssg-accounts_password_minlen_login_defs_action:testaction:1 + + + + Verify Permissions on /etc/at.allow file + + ocil:ssg-file_permissions_at_allow_action:testaction:1 + + + + Verify Group Who Owns /etc/crypttab File + + ocil:ssg-file_groupowner_etc_crypttab_action:testaction:1 + + + + Harden slab freelist metadata + + ocil:ssg-kernel_config_slab_freelist_hardened_action:testaction:1 + + + + Kernel panic on oops + + ocil:ssg-sysctl_kernel_panic_on_oops_action:testaction:1 + + + + Set Default iptables Policy for Forwarded Packets + + ocil:ssg-set_iptables_default_rule_forward_action:testaction:1 + + + + Enable support for BUG() + + ocil:ssg-kernel_config_bug_action:testaction:1 + + + + Verify Group Who Owns shadow File + + ocil:ssg-file_groupowner_etc_shadow_action:testaction:1 + + + + Disable XDMCP in GDM + + ocil:ssg-gnome_gdm_disable_xdmcp_action:testaction:1 + + + + Set SSH Client Alive Count Max to zero + + ocil:ssg-sshd_set_keepalive_0_action:testaction:1 + + + + Disable Network Router Discovery Daemon (rdisc) + + ocil:ssg-service_rdisc_disabled_action:testaction:1 + + + + Ensure PAM Enforces Password Requirements - Enforce for root User + + ocil:ssg-accounts_password_pam_enforce_root_action:testaction:1 + + + + Uninstall tuned Package + + ocil:ssg-package_tuned_removed_action:testaction:1 + + + + Modify the System Message of the Day Banner + + ocil:ssg-banner_etc_motd_action:testaction:1 + + + + Verify Permissions on /etc/audit/auditd.conf + + ocil:ssg-file_permissions_etc_audit_auditd_action:testaction:1 + + + + Enable NX or XD Support in the BIOS + + ocil:ssg-bios_enable_execution_restrictions_action:testaction:1 + + + + Configure Periodic Execution of AIDE + + ocil:ssg-aide_periodic_cron_checking_action:testaction:1 + + + + Ensure All Accounts on the System Have Unique User IDs + + ocil:ssg-account_unique_id_action:testaction:1 + + + + Uninstall bind Package + + ocil:ssg-package_bind_removed_action:testaction:1 + + + + Ensure /dev/shm is configured + + ocil:ssg-partition_for_dev_shm_action:testaction:1 + + + + Disable the LDT (local descriptor table) + + ocil:ssg-kernel_config_modify_ldt_syscall_action:testaction:1 + + + + Record Any Attempts to Run setfiles + + ocil:ssg-audit_rules_execution_setfiles_action:testaction:1 + + + + Enable the auditadm_exec_content SELinux Boolean + + ocil:ssg-sebool_auditadm_exec_content_action:testaction:1 + + + + Install McAfee Endpoint Security for Linux (ENSL) + + ocil:ssg-package_mcafeetp_installed_action:testaction:1 + + + + Verify Any Configured IPSec Tunnel Connections + + ocil:ssg-libreswan_approved_tunnels_action:testaction:1 + + + + Implement Blank Screensaver + + ocil:ssg-dconf_gnome_screensaver_mode_blank_action:testaction:1 + + + + Uninstall gssproxy Package + + ocil:ssg-package_gssproxy_removed_action:testaction:1 + + + + NetworkManager DNS Mode Must Be Must Configured + + ocil:ssg-networkmanager_dns_mode_action:testaction:1 + + + + Add nosuid Option to /opt + + ocil:ssg-mount_option_opt_nosuid_action:testaction:1 + + + + Ensure that Root's Path Does Not Include World or Group-Writable Directories + + ocil:ssg-accounts_root_path_dirs_no_write_action:testaction:1 + + + + Set Lockout Time for Failed Password Attempts + + ocil:ssg-accounts_passwords_pam_faillock_unlock_time_action:testaction:1 + + + + Enable Yama support + + ocil:ssg-kernel_config_security_yama_action:testaction:1 + + + + Configure OpenSSL library to use System Crypto Policy + + ocil:ssg-configure_openssl_crypto_policy_action:testaction:1 + + + + System Audit Directories Must Be Owned By Root + + ocil:ssg-directory_ownership_var_log_audit_action:testaction:1 + + + + User Initialization Files Must Be Owned By the Primary User + + ocil:ssg-accounts_user_dot_user_ownership_action:testaction:1 + + + + Configure Kerberos to use System Crypto Policy + + ocil:ssg-configure_kerberos_crypto_policy_action:testaction:1 + + + + Drop Gratuitious ARP frames on All IPv4 Interfaces + + ocil:ssg-sysctl_net_ipv4_conf_all_drop_gratuitous_arp_action:testaction:1 + + + + Configure AIDE to Verify Access Control Lists (ACLs) + + ocil:ssg-aide_verify_acls_action:testaction:1 + + + + Enable Auditing for Processes Which Start Prior to the Audit Daemon + + ocil:ssg-grub2_audit_argument_action:testaction:1 + + + + Modify the System Login Banner + + ocil:ssg-banner_etc_issue_action:testaction:1 + + + + Disable ATM Support + + ocil:ssg-kernel_module_atm_disabled_action:testaction:1 + + + + Configure CA certificate for rsyslog remote logging + + ocil:ssg-rsyslog_remote_tls_cacert_action:testaction:1 + + + + Ensure auditd Collects Unauthorized Access Attempts to Files (unsuccessful) + + ocil:ssg-audit_rules_unsuccessful_file_modification_action:testaction:1 + + + + Configure auditing of unsuccessful permission changes + + ocil:ssg-audit_perm_change_failed_action:testaction:1 + + + + Disable Kernel Image Loading + + ocil:ssg-sysctl_kernel_kexec_load_disabled_action:testaction:1 + + + + Ensure the Default Bash Umask is Set Correctly + + ocil:ssg-accounts_umask_etc_bashrc_action:testaction:1 + + + + Verify Root Has A Primary GID 0 + + ocil:ssg-accounts_root_gid_zero_action:testaction:1 + + + + Configure auditd space_left on Low Disk Space + + ocil:ssg-auditd_data_retention_space_left_action:testaction:1 + + + + Remove tftp Daemon + + ocil:ssg-package_tftp_removed_action:testaction:1 + + + + Disable SSH Support for Rhosts RSA Authentication + + ocil:ssg-sshd_disable_rhosts_rsa_action:testaction:1 + + + + Verify Permissions on cron.daily + + ocil:ssg-file_permissions_cron_daily_action:testaction:1 + + + + Disable Kernel Parameter for Sending ICMP Redirects on all IPv4 Interfaces + + ocil:ssg-sysctl_net_ipv4_conf_all_send_redirects_action:testaction:1 + + + + Configure a Sufficiently Large Partition for Audit Logs + + ocil:ssg-auditd_audispd_configure_sufficiently_large_partition_action:testaction:1 + + + + Verify that system commands files are group owned by root or a system account + + ocil:ssg-file_groupownership_system_commands_dirs_action:testaction:1 + + + + Uninstall dovecot Package + + ocil:ssg-package_dovecot_removed_action:testaction:1 + + + + Verify Permissions on group File + + ocil:ssg-file_permissions_etc_group_action:testaction:1 + + + + Ensure remote access methods are monitored in Rsyslog + + ocil:ssg-rsyslog_remote_access_monitoring_action:testaction:1 + + + + Verify that system commands directories have root as a group owner + + ocil:ssg-dir_system_commands_group_root_owned_action:testaction:1 + + + + Verify User Who Owns /etc/iptables Directory + + ocil:ssg-directory_owner_etc_iptables_action:testaction:1 + + + + Disable Core Dumps for SUID programs + + ocil:ssg-sysctl_fs_suid_dumpable_action:testaction:1 + + + + Audit Configuration Files Must Be Owned By Group root + + ocil:ssg-file_groupownership_audit_configuration_action:testaction:1 + + + + Disable Kerberos Authentication + + ocil:ssg-sshd_disable_kerb_auth_action:testaction:1 + + + + Disable storing core dump + + ocil:ssg-coredump_disable_storage_action:testaction:1 + + + + Prevent Routing External Traffic to Local Loopback on All IPv4 Interfaces + + ocil:ssg-sysctl_net_ipv4_conf_all_route_localnet_action:testaction:1 + + + + Ensure auditd Collects Information on the Use of Privileged Commands - chage + + ocil:ssg-audit_rules_privileged_commands_chage_action:testaction:1 + + + + Disable IPv6 Networking Support Automatic Loading + + ocil:ssg-kernel_module_ipv6_option_disabled_action:testaction:1 + + + + Set Kernel Parameter to Increase Local Port Range + + ocil:ssg-sysctl_net_ipv4_ip_local_port_range_action:testaction:1 + + + + Enable the Hardware RNG Entropy Gatherer Service + + ocil:ssg-service_rngd_enabled_action:testaction:1 + + + + Enable the SSSD Service + + ocil:ssg-service_sssd_enabled_action:testaction:1 + + + + Disable TIPC Support + + ocil:ssg-kernel_module_tipc_disabled_action:testaction:1 + + + + Account Lockouts Must Be Logged + + ocil:ssg-accounts_passwords_pam_faillock_audit_action:testaction:1 + + + + Lock Accounts After Failed Password Attempts + + ocil:ssg-accounts_passwords_pam_faillock_deny_action:testaction:1 + + + + Remove User Host-Based Authentication Files + + ocil:ssg-no_user_host_based_files_action:testaction:1 + + + + Record Any Attempts to Run setfacl + + ocil:ssg-audit_rules_execution_setfacl_action:testaction:1 + + + + Enable Kernel Parameter to Ignore ICMP Broadcast Echo Requests on IPv4 Interfaces + + ocil:ssg-sysctl_net_ipv4_icmp_echo_ignore_broadcasts_action:testaction:1 + + + + Disable core dump backtraces + + ocil:ssg-coredump_disable_backtraces_action:testaction:1 + + + + Configure immutable Audit login UIDs + + ocil:ssg-audit_rules_immutable_login_uids_action:testaction:1 + + + + Restrict Exposed Kernel Pointer Addresses Access + + ocil:ssg-sysctl_kernel_kptr_restrict_action:testaction:1 + + + + Enable Use of Strict Mode Checking + + ocil:ssg-sshd_enable_strictmodes_action:testaction:1 + + + + Verify Owner on cron.deny + + ocil:ssg-file_owner_cron_deny_action:testaction:1 + + + + Configure Sending and Accepting Shared Media Redirects for All IPv4 Interfaces + + ocil:ssg-sysctl_net_ipv4_conf_all_shared_media_action:testaction:1 + + + + Set Password Warning Age + + ocil:ssg-accounts_password_warn_age_login_defs_action:testaction:1 + + + + Use Kerberos Security on All Exports + + ocil:ssg-use_kerberos_security_all_exports_action:testaction:1 + + + + Verify Group Who Owns Backup passwd File + + ocil:ssg-file_groupowner_backup_etc_passwd_action:testaction:1 + + + + Enable Kernel Parameter to Use TCP RFC 1337 on IPv4 Interfaces + + ocil:ssg-sysctl_net_ipv4_tcp_rfc1337_action:testaction:1 + + + + Mount Remote Filesystems with nodev + + ocil:ssg-mount_option_nodev_remote_filesystems_action:testaction:1 + + + + Ensure gpgcheck Enabled for All yum Package Repositories + + ocil:ssg-ensure_gpgcheck_never_disabled_action:testaction:1 + + + + Ensure Only Users Logged In To Real tty Can Execute Sudo - sudo requiretty + + ocil:ssg-sudo_add_requiretty_action:testaction:1 + + + + Configure the deny_execmem SELinux Boolean + + ocil:ssg-sebool_deny_execmem_action:testaction:1 + + + + Record Unsuccessful Access Attempts to Files - truncate + + ocil:ssg-audit_rules_unsuccessful_file_modification_truncate_action:testaction:1 + + + + Disable Ctrl-Alt-Del Reboot Key Sequence in GNOME3 + + ocil:ssg-dconf_gnome_disable_ctrlaltdel_reboot_action:testaction:1 + + + + Verify and Correct File Permissions with RPM + + ocil:ssg-rpm_verify_permissions_action:testaction:1 + + + + Ensure auditd Collects Information on the Use of Privileged Commands - sudo + + ocil:ssg-audit_rules_privileged_commands_sudo_action:testaction:1 + + + + Force kernel panic on uncorrected MCEs + + ocil:ssg-grub2_mce_argument_action:testaction:1 + + + + Install rng-tools Package + + ocil:ssg-package_rng-tools_installed_action:testaction:1 + + + + Enable Kernel Parameter to Use Reverse Path Filtering on all IPv4 Interfaces + + ocil:ssg-sysctl_net_ipv4_conf_all_rp_filter_action:testaction:1 + + + + Disable SSH Support for .rhosts Files + + ocil:ssg-sshd_disable_rhosts_action:testaction:1 + + + + Set Interactive Session Timeout + + ocil:ssg-accounts_tmout_action:testaction:1 + + + + Set LogLevel to INFO + + ocil:ssg-sshd_set_loglevel_info_action:testaction:1 + + + + Configure auditing of successful ownership changes + + ocil:ssg-audit_owner_change_success_action:testaction:1 + + + + Distribute the SSH Server configuration to multiple files in a config directory. + + ocil:ssg-sshd_use_directory_configuration_action:testaction:1 + + + + Record Events that Modify User/Group Information - /etc/security/opasswd + + ocil:ssg-audit_rules_usergroup_modification_opasswd_action:testaction:1 + + + + Verify Permissions On /etc/sestatus.conf File + + ocil:ssg-file_permissions_etc_sestatus_conf_action:testaction:1 + + + + Configure AIDE to Verify Extended Attributes + + ocil:ssg-aide_verify_ext_attributes_action:testaction:1 + + + + Set Existing Passwords Minimum Age + + ocil:ssg-accounts_password_set_min_life_existing_action:testaction:1 + + + + Configure auditd max_log_file_action Upon Reaching Maximum Log Size + + ocil:ssg-auditd_data_retention_max_log_file_action_action:testaction:1 + + + + Configure System Cryptography Policy + + ocil:ssg-configure_crypto_policy_action:testaction:1 + + + + Record Attempts to Alter Logon and Logout Events - lastlog + + ocil:ssg-audit_rules_login_events_lastlog_action:testaction:1 + + + + IOMMU configuration directive + + ocil:ssg-grub2_enable_iommu_force_action:testaction:1 + + + + Disable /dev/kmem virtual device support + + ocil:ssg-kernel_config_devkmem_action:testaction:1 + + + + Ensure Chrony is only configured with the server directive + + ocil:ssg-chronyd_server_directive_action:testaction:1 + + + + Verify Permissions on /var/log/messages File + + ocil:ssg-file_permissions_var_log_messages_action:testaction:1 + + + + Set Password Minimum Age + + ocil:ssg-accounts_minimum_age_login_defs_action:testaction:1 + + + + Install libreswan Package + + ocil:ssg-package_libreswan_installed_action:testaction:1 + + + + Ensure debug-shell service is not enabled during boot + + ocil:ssg-grub2_systemd_debug-shell_argument_absent_action:testaction:1 + + + + Prevent non-Privileged Users from Modifying Network Interfaces using nmcli + + ocil:ssg-network_nmcli_permissions_action:testaction:1 + + + + Add nodev Option to /boot + + ocil:ssg-mount_option_boot_nodev_action:testaction:1 + + + + Ensure PAM Enforces Password Requirements - Minimum Digit Characters + + ocil:ssg-accounts_password_pam_dcredit_action:testaction:1 + + + + Enable Public Key Authentication + + ocil:ssg-sshd_enable_pubkey_auth_action:testaction:1 + + + + Configure Kernel Parameter for Accepting Secure Redirects By Default + + ocil:ssg-sysctl_net_ipv4_conf_default_secure_redirects_action:testaction:1 + + + + Configure basic parameters of Audit system + + ocil:ssg-audit_basic_configuration_action:testaction:1 + + + + Add nodev Option to /home + + ocil:ssg-mount_option_home_nodev_action:testaction:1 + + + + Enable GNOME3 Screensaver Lock After Idle Period + + ocil:ssg-dconf_gnome_screensaver_lock_enabled_action:testaction:1 + + + + Enable page allocator poisoning + + ocil:ssg-grub2_page_poison_argument_action:testaction:1 + + + + Ensure auditd Collects Information on the Use of Privileged Commands - sudoedit + + ocil:ssg-audit_rules_privileged_commands_sudoedit_action:testaction:1 + + + + Disable SCTP Support + + ocil:ssg-kernel_module_sctp_disabled_action:testaction:1 + + + + Ensure auditd Collects System Administrator Actions + + ocil:ssg-audit_rules_sysadmin_actions_action:testaction:1 + + + + Record Events that Modify the System's Discretionary Access Controls - fchownat + + ocil:ssg-audit_rules_dac_modification_fchownat_action:testaction:1 + + + + Verify Owner on cron.d + + ocil:ssg-file_owner_cron_d_action:testaction:1 + + + + A remote time server for Chrony is configured + + ocil:ssg-chronyd_specify_remote_server_action:testaction:1 + + + + All User Files and Directories In The Home Directory Must Be Group-Owned By The Primary Group + + ocil:ssg-accounts_users_home_files_groupownership_action:testaction:1 + + + + An SELinux Context must be configured for the pam_faillock.so records directory + + ocil:ssg-account_password_selinux_faillock_dir_action:testaction:1 + + + + Verify Who Owns /etc/shells File + + ocil:ssg-file_owner_etc_shells_action:testaction:1 + + + + Verify All Account Password Hashes are Shadowed with SHA512 + + ocil:ssg-accounts_password_all_shadowed_sha512_action:testaction:1 + + + + Disable GDM Automatic Login + + ocil:ssg-gnome_gdm_disable_automatic_login_action:testaction:1 + + + + Set Password Maximum Age + + ocil:ssg-accounts_maximum_age_login_defs_action:testaction:1 + + + + Record Events that Modify the System's Discretionary Access Controls - fchmodat + + ocil:ssg-audit_rules_dac_modification_fchmodat_action:testaction:1 + + + + Don't define allowed commands in sudoers by means of exclusion + + ocil:ssg-sudoers_no_command_negation_action:testaction:1 + + + + Enable SLUB debugging support + + ocil:ssg-kernel_config_slub_debug_action:testaction:1 + + + + Verify that Interactive Boot is Disabled + + ocil:ssg-grub2_disable_interactive_boot_action:testaction:1 + + + + Verify /boot/grub2/user.cfg Permissions + + ocil:ssg-file_permissions_user_cfg_action:testaction:1 + + + + Verify Permissions on shadow File + + ocil:ssg-file_permissions_etc_shadow_action:testaction:1 + + + + Configure auditing of successful file deletions + + ocil:ssg-audit_delete_success_action:testaction:1 + + + + Uninstall iprutils Package + + ocil:ssg-package_iprutils_removed_action:testaction:1 + + + + Limit sampling frequency of the Perf system + + ocil:ssg-sysctl_kernel_perf_event_max_sample_rate_action:testaction:1 + + + + Configure opensc Smart Card Drivers + + ocil:ssg-configure_opensc_card_drivers_action:testaction:1 + + + + Disable Kernel Parameter for Accepting Source-Routed Packets on all IPv4 Interfaces + + ocil:ssg-sysctl_net_ipv4_conf_all_accept_source_route_action:testaction:1 + + + + Set existing passwords a period of inactivity before they been locked + + ocil:ssg-accounts_set_post_pw_existing_action:testaction:1 + + + + Disable kernel debugfs + + ocil:ssg-kernel_config_debug_fs_action:testaction:1 + + + + Verify the UEFI Boot Loader grub.cfg User Ownership + + ocil:ssg-file_owner_efi_grub2_cfg_action:testaction:1 + + + + Record Any Attempts to Run restorecon + + ocil:ssg-audit_rules_execution_restorecon_action:testaction:1 + + + + Record Unsuccessful Access Attempts to Files - ftruncate + + ocil:ssg-audit_rules_unsuccessful_file_modification_ftruncate_action:testaction:1 + + + + Uninstall setroubleshoot-plugins Package + + ocil:ssg-package_setroubleshoot-plugins_removed_action:testaction:1 + + + + Disable DCCP Support + + ocil:ssg-kernel_module_dccp_disabled_action:testaction:1 + + + + Ensure Home Directories are Created for New Users + + ocil:ssg-accounts_have_homedir_login_defs_action:testaction:1 + + + + Set SSH authentication attempt limit + + ocil:ssg-sshd_set_max_auth_tries_action:testaction:1 + + + + Add nodev Option to Removable Media Partitions + + ocil:ssg-mount_option_nodev_removable_partitions_action:testaction:1 + + + + User Initialization Files Must Be Group-Owned By The Primary Group + + ocil:ssg-accounts_user_dot_group_ownership_action:testaction:1 + + + + Verify User Who Owns /etc/nftables Directory + + ocil:ssg-directory_owner_etc_nftables_action:testaction:1 + + + + Verify Group Who Owns Backup shadow File + + ocil:ssg-file_owner_backup_etc_shadow_action:testaction:1 + + + + Use zero for poisoning instead of debugging value + + ocil:ssg-kernel_config_page_poisoning_zero_action:testaction:1 + + + + Ensure PAM password complexity module is enabled in system-auth + + ocil:ssg-accounts_password_pam_pwquality_system_auth_action:testaction:1 + + + + Ensure PAM Enforces Password Requirements - Authentication Retry Prompts Permitted Per-Session + + ocil:ssg-accounts_password_pam_retry_action:testaction:1 + + + + Disable the authlogin_radius SELinux Boolean + + ocil:ssg-sebool_authlogin_radius_action:testaction:1 + + + + Verify User Who Owns /etc/sysctl.d Directory + + ocil:ssg-directory_owner_etc_sysctld_action:testaction:1 + + + + Configure Fapolicy Module to Employ a Deny-all, Permit-by-exception Policy to Allow the Execution of Authorized Software Programs. + + ocil:ssg-fapolicy_default_deny_action:testaction:1 + + + + Add nosuid Option to /var/log + + ocil:ssg-mount_option_var_log_nosuid_action:testaction:1 + + + + Ensure /home Located On Separate Partition + + ocil:ssg-partition_for_home_action:testaction:1 + + + + Mount Remote Filesystems with Kerberos Security + + ocil:ssg-mount_option_krb_sec_remote_filesystems_action:testaction:1 + + + + Configure Speculative Store Bypass Mitigation + + ocil:ssg-grub2_spec_store_bypass_disable_argument_action:testaction:1 + + + + Disable Kernel Parameter for Accepting ICMP Redirects by Default on IPv4 Interfaces + + ocil:ssg-sysctl_net_ipv4_conf_default_accept_redirects_action:testaction:1 + + + + Ensure auditd Collects Information on the Use of Privileged Commands - usernetctl + + ocil:ssg-audit_rules_privileged_commands_usernetctl_action:testaction:1 + + + + Disallow Configuration to Bypass Password Requirements for Privilege Escalation + + ocil:ssg-disallow_bypass_password_sudo_action:testaction:1 + + + + Verify Ownership on SSH Server Public *.pub Key Files + + ocil:ssg-file_ownership_sshd_pub_key_action:testaction:1 + + + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + + Verify that yum verifies the signature of packages from a repository prior to install with the following command: -Run the following command to verify avahi-daemon is not active (i.e. not running) through current runtime configuration: -$ sudo systemctl is-active avahi-daemon +$ grep gpgcheck /etc/yum.conf -If the service is not running the command will return the following output: -inactive +gpgcheck=1 -The service will also be masked, to check that the avahi-daemon is masked, run the following command: -$ sudo systemctl show avahi-daemon | grep "LoadState\|UnitFileState" +If "gpgcheck" is not set to "1", or if the option is missing or commented out, ask the System Administrator how the certificates for patches and other operating system components are verified. + Is it the case that there is no process to validate certificates that is approved by the organization? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "unix_chkpwd" command with the following command: -If the service is masked the command will return the following outputs: +$ sudo auditctl -l | grep unix_chkpwd -LoadState=masked +-a always,exit -F path=/usr/bin/unix_chkpwd -F perm=x -F auid>=1000 -F auid!=unset -k privileged-unix_chkpwd + Is it the case that the command does not return a line, or the line is commented out? + + + + The runtime status of the net.ipv4.conf.default.log_martians kernel parameter can be queried +by running the following command: +$ sysctl net.ipv4.conf.default.log_martians +1. -UnitFileState=masked - Is it the case that the "avahi-daemon" is loaded and not masked? - - - - To check that the abrtd service is disabled in system boot configuration, -run the following command: -$ sudo systemctl is-enabled abrtd -Output should indicate the abrtd service has either not been installed, -or has been disabled at all runlevels, as shown in the example below: -$ sudo systemctl is-enabled abrtd disabled - -Run the following command to verify abrtd is not active (i.e. not running) through current runtime configuration: -$ sudo systemctl is-active abrtd - -If the service is not running the command will return the following output: -inactive - -The service will also be masked, to check that the abrtd is masked, run the following command: -$ sudo systemctl show abrtd | grep "LoadState\|UnitFileState" - -If the service is masked the command will return the following outputs: - -LoadState=masked - -UnitFileState=masked - Is it the case that the "abrtd" is loaded and not masked? - - - - To check that the kdump service is disabled in system boot configuration, -run the following command: -$ sudo systemctl is-enabled kdump -Output should indicate the kdump service has either not been installed, -or has been disabled at all runlevels, as shown in the example below: -$ sudo systemctl is-enabled kdump disabled - -Run the following command to verify kdump is not active (i.e. not running) through current runtime configuration: -$ sudo systemctl is-active kdump - -If the service is not running the command will return the following output: -inactive - -The service will also be masked, to check that the kdump is masked, run the following command: -$ sudo systemctl show kdump | grep "LoadState\|UnitFileState" - -If the service is masked the command will return the following outputs: - -LoadState=masked - -UnitFileState=masked - Is it the case that the "kdump" is loaded and not masked? - - - - To check that the ntpdate service is disabled in system boot configuration, -run the following command: -$ sudo systemctl is-enabled ntpdate -Output should indicate the ntpdate service has either not been installed, -or has been disabled at all runlevels, as shown in the example below: -$ sudo systemctl is-enabled ntpdate disabled - -Run the following command to verify ntpdate is not active (i.e. not running) through current runtime configuration: -$ sudo systemctl is-active ntpdate - -If the service is not running the command will return the following output: -inactive - -The service will also be masked, to check that the ntpdate is masked, run the following command: -$ sudo systemctl show ntpdate | grep "LoadState\|UnitFileState" - -If the service is masked the command will return the following outputs: - -LoadState=masked - -UnitFileState=masked - Is it the case that the "ntpdate" is loaded and not masked? - - - - To check that the oddjobd service is disabled in system boot configuration, -run the following command: -$ sudo systemctl is-enabled oddjobd -Output should indicate the oddjobd service has either not been installed, -or has been disabled at all runlevels, as shown in the example below: -$ sudo systemctl is-enabled oddjobd disabled - -Run the following command to verify oddjobd is not active (i.e. not running) through current runtime configuration: -$ sudo systemctl is-active oddjobd - -If the service is not running the command will return the following output: -inactive - -The service will also be masked, to check that the oddjobd is masked, run the following command: -$ sudo systemctl show oddjobd | grep "LoadState\|UnitFileState" - -If the service is masked the command will return the following outputs: - -LoadState=masked - -UnitFileState=masked - Is it the case that the "oddjobd" is loaded and not masked? - - - - To check that the qpidd service is disabled in system boot configuration, -run the following command: -$ sudo systemctl is-enabled qpidd -Output should indicate the qpidd service has either not been installed, -or has been disabled at all runlevels, as shown in the example below: -$ sudo systemctl is-enabled qpidd disabled - -Run the following command to verify qpidd is not active (i.e. not running) through current runtime configuration: -$ sudo systemctl is-active qpidd - -If the service is not running the command will return the following output: -inactive - -The service will also be masked, to check that the qpidd is masked, run the following command: -$ sudo systemctl show qpidd | grep "LoadState\|UnitFileState" - -If the service is masked the command will return the following outputs: - -LoadState=masked - -UnitFileState=masked - Is it the case that the "qpidd" is loaded and not masked? - - - - To check that the rdisc service is disabled in system boot configuration, -run the following command: -$ sudo systemctl is-enabled rdisc -Output should indicate the rdisc service has either not been installed, -or has been disabled at all runlevels, as shown in the example below: -$ sudo systemctl is-enabled rdisc disabled - -Run the following command to verify rdisc is not active (i.e. not running) through current runtime configuration: -$ sudo systemctl is-active rdisc - -If the service is not running the command will return the following output: -inactive - -The service will also be masked, to check that the rdisc is masked, run the following command: -$ sudo systemctl show rdisc | grep "LoadState\|UnitFileState" - -If the service is masked the command will return the following outputs: - -LoadState=masked - -UnitFileState=masked - Is it the case that the "rdisc" is loaded and not masked? - - - - To check the group ownership of /etc/cron.allow, + Is it the case that the correct value is not returned? + + + + To check the permissions of /etc/nftables, run the command: -$ ls -lL /etc/cron.allow -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/cron.allow does not have a group owner of root? - - - - To check the ownership of /etc/cron.allow, +$ ls -l /etc/nftables +If properly configured, the output should indicate the following permissions: +0700 + Is it the case that /etc/nftables does not have unix mode 0700? + + + + To verify all files and directories contained in interactive user home +directory, excluding local initialization files, have a mode of 0750, +run the following command: +$ sudo ls -lLR /home/USER + Is it the case that home directory files or folders have incorrect permissions? + + + + To check the ownership of /boot/grub2/grub.cfg, run the command: -$ ls -lL /etc/cron.allow +$ ls -lL /boot/grub2/grub.cfg If properly configured, the output should indicate the following owner: root - Is it the case that /etc/cron.allow does not have an owner of root? - - - - To check the permissions of /etc/cron.allow, -run the command: -$ ls -l /etc/cron.allow -If properly configured, the output should indicate the following permissions: --rw-r----- - Is it the case that /etc/cron.allow does not have unix mode -rw-r-----? - - - - To check the group ownership of /etc/cron.d, -run the command: -$ ls -lL /etc/cron.d -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/cron.d does not have a group owner of root? - - - - To check the group ownership of /etc/cron.daily, -run the command: -$ ls -lL /etc/cron.daily -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/cron.daily does not have a group owner of root? - - - - To check the group ownership of /etc/cron.hourly, -run the command: -$ ls -lL /etc/cron.hourly -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/cron.hourly does not have a group owner of root? - - - - To check the group ownership of /etc/cron.monthly, + Is it the case that /boot/grub2/grub.cfg does not have an owner of root? + + + + Inspect the form of default GRUB 2 command line for the Linux operating system +in /etc/default/grub. If it includes rng_core.default_quality=, +then the parameter will be configured for newly installed kernels. +First check if the GRUB recovery is enabled: +$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub +If this option is set to true, then check that a line is output by the following command: +$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*rng_core.default_quality=.*' /etc/default/grub +If the recovery is disabled, check the line with +$ sudo grep 'GRUB_CMDLINE_LINUX.*rng_core.default_quality=.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. +Run the following command: +$ sudo grubby --info=ALL | grep args | grep -v 'rng_core.default_quality=' +The command should not return any output. + Is it the case that trust on hardware random number generator is not configured appropriately? + + + + Verify Oracle Linux 9 defines default permissions for all authenticated users in such a way that the user can only read and modify their own files with the following command: + +# grep -i umask /etc/login.defs + +UMASK + Is it the case that the value for the "UMASK" parameter is not "<sub idref="var_accounts_user_umask" />", or the "UMASK" parameter is missing or is commented out? + + + + Run the following command to determine if the talk-server package is installed: +$ rpm -q talk-server + Is it the case that the package is installed? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_LEGACY_VSYSCALL_XONLY /boot/config.* + + Configs with value 'n' are not explicitly set in the file, so either commented lines or no + lines should be returned. + + Is it the case that the kernel was not built with the required value? + + + + +If the system is configured to prevent the loading of the rds kernel module, +it will contain lines inside any file in /etc/modprobe.d or the deprecated /etc/modprobe.conf. +These lines instruct the module loading system to run another program (such as /bin/false) upon a module install event. + +These lines can also instruct the module loading system to ignore the rds kernel module via blacklist keyword. + +Run the following command to search for such lines in all files in /etc/modprobe.d and the deprecated /etc/modprobe.conf: +$ grep -r rds /etc/modprobe.conf /etc/modprobe.d + Is it the case that no line is returned? + + + + Run the following command to ensure postfix routes mail to this system: +$ grep relayhost /etc/postfix/main.cf +If properly configured, the output should show only . + Is it the case that it is not? + + + + To check the group ownership of /etc/cron.monthly, run the command: $ ls -lL /etc/cron.monthly If properly configured, the output should indicate the following group-owner: root Is it the case that /etc/cron.monthly does not have a group owner of root? - - - - To check the group ownership of /etc/cron.weekly, -run the command: -$ ls -lL /etc/cron.weekly -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/cron.weekly does not have a group owner of root? - - - - To check the group ownership of /etc/crontab, -run the command: -$ ls -lL /etc/crontab -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/crontab does not have a group owner of root? - - - - To check the ownership of /etc/cron.d, -run the command: -$ ls -lL /etc/cron.d -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/cron.d does not have an owner of root? - - - - To check the ownership of /etc/cron.daily, -run the command: -$ ls -lL /etc/cron.daily -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/cron.daily does not have an owner of root? - - - - To check the ownership of /etc/cron.hourly, -run the command: -$ ls -lL /etc/cron.hourly -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/cron.hourly does not have an owner of root? - - - - To check the ownership of /etc/cron.monthly, -run the command: -$ ls -lL /etc/cron.monthly -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/cron.monthly does not have an owner of root? - - - - To check the ownership of /etc/cron.weekly, -run the command: -$ ls -lL /etc/cron.weekly -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/cron.weekly does not have an owner of root? - - - - To check the ownership of /etc/crontab, -run the command: -$ ls -lL /etc/crontab -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/crontab does not have an owner of root? - - - - To check the permissions of /etc/cron.d, -run the command: -$ ls -l /etc/cron.d -If properly configured, the output should indicate the following permissions: --rwx------ - Is it the case that /etc/cron.d does not have unix mode -rwx------? - - - - To check the permissions of /etc/cron.daily, -run the command: -$ ls -l /etc/cron.daily -If properly configured, the output should indicate the following permissions: --rwx------ - Is it the case that /etc/cron.daily does not have unix mode -rwx------? - - - - To check the permissions of /etc/cron.hourly, -run the command: -$ ls -l /etc/cron.hourly -If properly configured, the output should indicate the following permissions: --rwx------ - Is it the case that /etc/cron.hourly does not have unix mode -rwx------? - - - - To check the permissions of /etc/cron.monthly, -run the command: -$ ls -l /etc/cron.monthly -If properly configured, the output should indicate the following permissions: --rwx------ - Is it the case that /etc/cron.monthly does not have unix mode -rwx------? - - - - To check the permissions of /etc/cron.weekly, -run the command: -$ ls -l /etc/cron.weekly -If properly configured, the output should indicate the following permissions: --rwx------ - Is it the case that /etc/cron.weekly does not have unix mode -rwx------? - - - - To check the permissions of /etc/crontab, -run the command: -$ ls -l /etc/crontab -If properly configured, the output should indicate the following permissions: --rw------- - Is it the case that /etc/crontab does not have unix mode -rw-------? - - - - Run the following command to determine if the cron package is installed: -$ rpm -q cron + + + + Verify the TFTP daemon is configured to operate in secure mode. + +Check if a TFTP server is installed with the following command: + +$ sudo dnf list --installed tftp-server + +tftp-server.x86_64 5.2-35.el9.x86_64 + + +If a TFTP server is not installed, this is Not Applicable. + + +If a TFTP server is installed, check for the server arguments with the following command: + +$ systemctl cat tftp | grep ExecStart= +ExecStart=/usr/sbin/in.tftpd -s + Is it the case that 'the "ExecStart" line does not have a "-s" option, and a subdirectory is not assigned'? + + + + To verify /etc/system-fips exists, run the following command: +ls -l /etc/system-fips +The output should be similar to the following: +-rw-r--r--. 1 root root 36 Nov 26 11:31 /etc/system-fips + Is it the case that /etc/system-fips does not exist? + + + + To determine if the system is configured to audit calls to the +lchown system call, run the following command: +$ sudo grep "lchown" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. + + Is it the case that no line is returned? + + + + Run the following command to determine if the squid package is installed: +$ rpm -q squid Is it the case that the package is installed? - - - - To check that the atd service is disabled in system boot configuration, + + + + Inspect the form of default GRUB 2 command line for the Linux operating system +in /etc/default/grub. If it includes vsyscall=none, +then the parameter will be configured for newly installed kernels. +First check if the GRUB recovery is enabled: +$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub +If this option is set to true, then check that a line is output by the following command: +$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*vsyscall=none.*' /etc/default/grub +If the recovery is disabled, check the line with +$ sudo grep 'GRUB_CMDLINE_LINUX.*vsyscall=none.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. +Run the following command: +$ sudo grubby --info=ALL | grep args | grep -v 'vsyscall=none' +The command should not return any output. + Is it the case that vsyscalls are enabled? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_MODULE_SIG_SHA512 /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + If the system uses IPv6, this is not applicable. + +If the system is configured to prevent the usage of the ipv6 on +network interfaces, it will contain a line of the form: +net.ipv6.conf.all.disable_ipv6 = 1 +Such lines may be inside any file in the /etc/sysctl.d directory. +This permits insertion of the IPv6 kernel module (which other parts of the +system expect to be present), but otherwise keeps all network interfaces +from using IPv6. Run the following command to search for such lines in all +files in /etc/sysctl.d: +$ grep -r ipv6 /etc/sysctl.d + Is it the case that the ipv6 support is disabled on all network interfaces? + + + + If the system is not using TLS, set the ldap_id_use_start_tls option +in /etc/sssd/sssd.conf to true. + Is it the case that the 'ldap_id_use_start_tls' option is not set to 'true'? + + + + To verify that binaries cannot be directly executed from removable media, run the following command: +$ grep -v noexec /etc/fstab +The resulting output will show partitions which do not have the noexec flag. Verify all partitions +in the output are not removable media. + Is it the case that removable media partitions are present? + + + + To check the group ownership of /etc/sysctl.d, +run the command: +$ ls -lL /etc/sysctl.d +If properly configured, the output should indicate the following group-owner: +root + Is it the case that /etc/sysctl.d does not have a group owner of root? + + + + To check the group ownership of /etc/sudoers, +run the command: +$ ls -lL /etc/sudoers +If properly configured, the output should indicate the following group-owner: +root + Is it the case that /etc/sudoers does not have a group owner of root? + + + + The runtime status of the net.ipv6.conf.all.accept_redirects kernel parameter can be queried +by running the following command: +$ sysctl net.ipv6.conf.all.accept_redirects +0. + + Is it the case that the correct value is not returned? + + + + Verify that the libuser is set to encrypt password with a FIPS 140-3 approved cryptographic hashing algorithm. + + +Check the hashing algorithm that is being used to hash passwords with the following command: + +$ sudo grep -i crypt_style /etc/libuser.conf + +crypt_style = + Is it the case that crypt_style is not set to sha512? + + + + The runtime status of the fs.protected_symlinks kernel parameter can be queried +by running the following command: +$ sysctl fs.protected_symlinks +1. + + Is it the case that the correct value is not returned? + + + + To check the permissions of /etc/ipsec.d, +run the command: +$ ls -l /etc/ipsec.d +If properly configured, the output should indicate the following permissions: +0700 + Is it the case that /etc/ipsec.d does not have unix mode 0700? + + + + To obtain a listing of all users, their UIDs, and their shells, run the command: +$ awk -F: '{print $1 ":" $3 ":" $7}' /etc/passwd +Identify the system accounts from this listing. These will primarily be the accounts with UID +numbers less than 1000, other than root. + Is it the case that any system account other than root has a login shell? + + + + Verify the nodev option is configured for the /var/log mount point, + run the following command: + $ sudo mount | grep '\s/var/log\s' + . . . /var/log . . . nodev . . . + + Is it the case that the "/var/log" file system does not have the "nodev" option set? + + + + Verify that cron is logging to rsyslog, run the following command: -$ sudo systemctl is-enabled atd -Output should indicate the atd service has either not been installed, -or has been disabled at all runlevels, as shown in the example below: -$ sudo systemctl is-enabled atd disabled +grep -rni "cron\.\*" /etc/rsyslog.* +cron.* /var/log/cron +or +cron.* action(type="omfile" file="/var/log/cron") + Is it the case that cron is not logging to rsyslog? + + + + Run the following command to determine if the dnf-automatic package is installed: $ rpm -q dnf-automatic + Is it the case that the package is not installed? + + + + Verify Oracle Linux 9 limits the number of concurrent sessions to +"" for all +accounts and/or account types with the following command: +$ grep -r -s maxlogins /etc/security/limits.conf /etc/security/limits.d/*.conf +/etc/security/limits.conf:* hard maxlogins 10 +This can be set as a global domain (with the * wildcard) but may be set differently for multiple domains. + Is it the case that the "maxlogins" item is missing, commented out, or the value is set greater +than "<sub idref="var_accounts_max_concurrent_login_sessions" />" and +is not documented with the Information System Security Officer (ISSO) as an +operational requirement for all domains that have the "maxlogins" item +assigned'? + + + + Verify Oracle Linux 9 removes all software components after updated versions have been installed. -Run the following command to verify atd is not active (i.e. not running) through current runtime configuration: -$ sudo systemctl is-active atd -If the service is not running the command will return the following output: -inactive - -The service will also be masked, to check that the atd is masked, run the following command: -$ sudo systemctl show atd | grep "LoadState\|UnitFileState" - -If the service is masked the command will return the following outputs: - -LoadState=masked - -UnitFileState=masked - Is it the case that the "atd" is loaded and not masked? - - - - - -Run the following command to determine the current status of the -cron service: -$ sudo systemctl is-active cron -If the service is running, it should return the following: active - Is it the case that ? - - - - - -Run the following command to determine the current status of the -crond service: -$ sudo systemctl is-active crond -If the service is running, it should return the following: active - Is it the case that ? - - - - Run the following command to determine if the dhcp-server package is installed: +$ grep clean_requirements_on_remove /etc/yum.conf +clean_requirements_on_remove=1 + Is it the case that '"clean_requirements_on_remove" is not set to "1"'? + + + + Run the following command to determine if the dhcp-server package is installed: $ rpm -q dhcp-server Is it the case that the package is installed? - - - - Run the following command to determine if the bind package is installed: -$ rpm -q bind + + + + To check the permissions of /boot/System.map*, +run the command: +$ ls -l /boot/System.map* +If properly configured, the output should indicate the following permissions: +-rw------- + Is it the case that /boot/System.map* does not have unix mode -rw-------? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_SECCOMP_FILTER /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To check if authentication is required for emergency mode, run the following command: +$ grep sulogin /usr/lib/systemd/system/emergency.service +The output should be similar to the following, and the line must begin with +ExecStart and /usr/lib/systemd/systemd-sulogin-shell. + ExecStart=-/usr/lib/systemd/systemd-sulogin-shell emergency + +Then, check if the emergency target requires the emergency service: +Run the following command: +$ sudo grep Requires /usr/lib/systemd/system/emergency.target +The output should be the following: +Requires=emergency.service + +Then, check if there is no custom emergency target configured in systemd configuration. +Run the following command: +$ sudo grep -r emergency.target /etc/systemd/system/ +The output should be empty. + +Then, check if there is no custom emergency service configured in systemd configuration. +Run the following command: +$ sudo grep -r emergency.service /etc/systemd/system/ +The output should be empty. + Is it the case that the output is different? + + + + To ensure ClientAliveInterval is set correctly, run the following command: +$ sudo grep ClientAliveCountMax /etc/ssh/sshd_config +If properly configured, the output should be: +ClientAliveCountMax +For SSH earlier than v8.2, a ClientAliveCountMax value of 0 causes a timeout precisely when +the ClientAliveInterval is set. Starting with v8.2, a value of 0 disables the timeout +functionality completely. +If the option is set to a number greater than 0, then the session will be disconnected after +ClientAliveInterval * ClientAliveCountMax seconds without receiving a keep alive message. + Is it the case that it is commented out or not configured properly? + + + + To verify the nodev option is configured for non-root local partitions, run the following command: +$ sudo mount | grep '^/dev\S* on /\S' | grep --invert-match 'nodev' +The output shows local non-root partitions mounted without the nodev option, and there should be no output at all. + + Is it the case that some mounts appear among output lines? + + + + Verify that local initialization files do not execute world-writable programs with the following command: + +Note: The example will be for a system that is configured to create user home directories in the "/home" directory. + +$ sudo find /home -perm -002 -type f -name ".[^.]*" -exec ls -ld {} \; + Is it the case that any local initialization files are found to reference world-writable files? + + + + Verify that interactive users on the system have a home directory assigned with the following command: + +$ sudo awk -F: '($3>=1000)&&($7 !~ /nologin/){print $1, $3, $6}' /etc/passwd + +Inspect the output and verify that all interactive users (normally users with a UID greater than 1000) have a home directory defined. + Is it the case that users home directory is not defined? + + + + The runtime status of the net.ipv6.conf.all.accept_ra kernel parameter can be queried +by running the following command: +$ sysctl net.ipv6.conf.all.accept_ra +0. + + Is it the case that the correct value is not returned? + + + + Verify the nodev option is configured for the /tmp mount point, + run the following command: + $ sudo mount | grep '\s/tmp\s' + . . . /tmp . . . nodev . . . + + Is it the case that the "/tmp" file system does not have the "nodev" option set? + + + + The rsh package can be removed with the following command: $ sudo yum erase rsh + Is it the case that ? + + + + Verify the nosuid option is configured for the /var/tmp mount point, + run the following command: + $ sudo mount | grep '\s/var/tmp\s' + . . . /var/tmp . . . nosuid . . . + + Is it the case that the "/var/tmp" file system does not have the "nosuid" option set? + + + + For each private key stored on the system, use the following command: +$ sudo ssh-keygen -y -f /path/to/file +If the contents of the key are displayed, this is a finding. + Is it the case that no ssh private key is accessible without a passcode? + + + + Ensure that Oracle Linux 9 does not disable SELinux. + +Check if "SELinux" is active and in "enforcing" or "permissive" mode with the following command: + +$ sudo getenforce +Enforcing +-OR- +Permissive + Is it the case that SELinux is disabled? + + + + Run the following command to determine if the cronie package is installed: +$ rpm -q cronie Is it the case that the package is installed? - - - - Verify the Oracle Linux 9 "fapolicyd" employs a deny-all, permit-by-exception policy. + + + + Verify the value of the "difok" option in "/etc/security/pwquality.conf" with the following command: -Check that "fapolicyd" is in enforcement mode with the following command: +$ sudo grep difok /etc/security/pwquality.conf -$ sudo grep permissive /etc/fapolicyd/fapolicyd.conf +difok = + Is it the case that the value of "difok" is set to less than "<sub idref="var_password_pam_difok" />", or is commented out? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_SECCOMP /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To ensure that remote access requires credentials, run the following command: +$ gsettings get org.gnome.Vino authentication-methods +If properly configured, the output should be false. +To ensure that users cannot disable credentials for remote access, run the following: +$ grep authentication-methods /etc/dconf/db/local.d/locks/* +If properly configured, the output should be +/org/gnome/Vino/authentication-methods + Is it the case that wireless network notification is enabled and not disabled? + + + + To check the group ownership of /boot/grub2/user.cfg, +run the command: +$ ls -lL /boot/grub2/user.cfg +If properly configured, the output should indicate the following group-owner: +root + Is it the case that /boot/grub2/user.cfg does not have a group owner of root? + + + + Verify the system-wide shared library directories are owned by "root" with the following command: -permissive = 0 +$ sudo find /lib /lib64 /usr/lib /usr/lib64 ! -user root -type d -exec stat -c "%n %U" '{}' \; + Is it the case that any system-wide shared library directory is not owned by root? + + + + Verify the system-wide shared library files are group-owned by "root" with the following command: -Check that fapolicyd employs a deny-all policy on system mounts with the following commands: -$ sudo tail /etc/fapolicyd/compiled.rules - -allow exe=/usr/bin/python3.7 : ftype=text/x-python -deny_audit perm=any pattern=ld_so : all -deny perm=any all : all - Is it the case that fapolicyd is not running in enforcement mode with a deny-all, permit-by-exception policy? - - - - Run the following command to determine if the fapolicyd package is installed: $ rpm -q fapolicyd - Is it the case that the fapolicyd package is not installed? - - - - - -Run the following command to determine the current status of the -fapolicyd service: -$ sudo systemctl is-active fapolicyd -If the service is running, it should return the following: active - Is it the case that the service is not enabled? - - - - Run the following command to determine if the vsftpd package is installed: -$ rpm -q vsftpd - Is it the case that the package is installed? - - - - Find the list of alias maps used by the Postfix mail server: -$ sudo postconf alias_maps -Query the Postfix alias maps for an alias for the root user: -$ sudo postmap -q root hash:/etc/aliases -The output should return an alias. - Is it the case that the alias is not set? - - - - Find the list of alias maps used by the Postfix mail server: -$ sudo postconf alias_maps -Query the Postfix alias maps for an alias for the postmaster user: -$ sudo postmap -q postmaster hash:/etc/aliases -The output should return root. - Is it the case that the alias is not set or is not root? - - - - Run the following command to ensure postfix routes mail to this system: -$ grep relayhost /etc/postfix/main.cf -If properly configured, the output should show only . - Is it the case that it is not? - - - - Run the following command to ensure postfix accepts mail messages from only the local system: -$ grep inet_interfaces /etc/postfix/main.cf -If properly configured, the output should show only . - Is it the case that it does not? - - - - Verify that Oracle Linux 9 is configured to prevent unrestricted mail relaying, +$ sudo find -L /lib /lib64 /usr/lib /usr/lib64 ! -group root -exec ls -l {} \; + Is it the case that any system wide shared library file is returned and is not group-owned by a required system account? + + + + To verify ExecShield is enabled on 64-bit Oracle Linux 9 systems, run the following command: -$ sudo postconf -n smtpd_client_restrictions - Is it the case that the "smtpd_client_restrictions" parameter contains any entries other than "permit_mynetworks" and "reject"? - - - - Run the following command to determine if the postfix package is installed: $ rpm -q postfix - Is it the case that the package is not installed? - - - - Run the following command to determine if the sendmail package is installed: -$ rpm -q sendmail - Is it the case that the package is installed? - - - - +$ dmesg | grep '[NX|DX]*protection' +The output should not contain 'disabled by kernel command line option'. +Inspect the form of default GRUB 2 command line for the Linux operating system +in /etc/default/grub. If it includes noexec=off, +then the parameter will be configured for newly installed kernels. +First check if the GRUB recovery is enabled: +$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub +If this option is set to true, then check that a line is output by the following command: +$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*noexec=off.*' /etc/default/grub +If the recovery is disabled, check the line with +$ sudo grep 'GRUB_CMDLINE_LINUX.*noexec=off.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. +Run the following command: +$ sudo grubby --info=ALL | grep args | grep -v 'noexec=off' +The command should not return any output. + Is it the case that ExecShield is not supported by the hardware, is not enabled, or has been disabled by the kernel configuration.? + + + + Verify Oracle Linux 9 generates audit records for all account creations, modifications, disabling, and termination events that affect "/etc/passwd with the following command: -Run the following command to determine the current status of the -postfix service: -$ sudo systemctl is-active postfix -If the service is running, it should return the following: active - Is it the case that the system is not a cross domain solution and the service is not enabled? - - - - To verify the sec option is configured for all NFS mounts, run the following command: -$ mount | grep "sec=" -All NFS mounts should show the sec=krb5:krb5i:krb5p setting in parentheses. -This is not applicable if NFS is not implemented. - Is it the case that the setting is not configured, has the 'sys' option added, or does not have all Kerberos options added? - - - - To verify the nodev option is configured for all NFS mounts, run -the following command: -$ mount | grep nfs -All NFS mounts should show the nodev setting in parentheses. This -is not applicable if NFS is not implemented. - Is it the case that the setting does not show? - - - - To verify the noexec option is configured for all NFS mounts, run the following command: -$ mount | grep nfs -All NFS mounts should show the noexec setting in parentheses. This is not applicable if NFS is -not implemented. - Is it the case that the setting does not show? - - - - To verify the nosuid option is configured for all NFS mounts, run -the following command: -$ mount | grep nfs -All NFS mounts should show the nosuid setting in parentheses. This -is not applicable if NFS is not implemented. - Is it the case that the setting does not show? - - - - To verify all squashing has been disabled, run the following command: -$ grep all_squash /etc/exports - Is it the case that there is output? - - - - To verify the sec option is configured for all NFS mounts, run the following command: -$ grep "sec=" /etc/exports -All configured NFS exports should show the sec=krb5:krb5i:krb5p setting in parentheses. -This is not applicable if NFS is not implemented. - Is it the case that the setting is not configured, has the 'sys' option added, or does not have all Kerberos options added? - - - - Run the following command to determine if the nfs-utils package is installed: -$ rpm -q nfs-utils - Is it the case that the package is installed? - - - - Verify Oracle Linux 9 disables the chrony daemon from acting as a server with the following command: -$ grep -w port /etc/chrony.conf -port 0 - Is it the case that the "port" option is not set to "0", is commented out, or is missing? - - - - Verify Oracle Linux 9 disables network management of the chrony daemon with the following command: -$ grep -w cmdport /etc/chrony.conf -cmdport 0 - Is it the case that the "cmdport" option is not set to "0", is commented out, or is missing? - - - - Verify Oracle Linux 9 is securely comparing internal information system clocks at a regular interval with an NTP server with the following command: -$ sudo grep maxpoll /etc/ntp.conf /etc/chrony.conf -server [ntp.server.name] iburst maxpoll . - Is it the case that "maxpoll" has not been set to the value of "<sub idref="var_time_service_set_maxpoll" />", is commented out, or is missing? - - - - Run the following command and verify that time sources are only configured with server directive: -# grep -E "^(server|pool)" /etc/chrony.conf -A line with the appropriate server should be returned, any line returned starting with pool is a finding. - Is it the case that an authoritative remote time server is not configured or configured with pool directive? - - - - Run the following command and verify remote server is configured properly: -# grep -E "^(server|pool)" /etc/chrony.conf - Is it the case that a remote time server is not configured? - - - - To verify that a remote NTP service is configured for time synchronization, -open the following file: -/etc/ntp.conf -In the file, there should be a section similar to the following: -server ntpserver - Is it the case that this is not the case? - - - - Run the following command to determine if the chrony package is installed: $ rpm -q chrony - Is it the case that the package is not installed? - - - - Run the following command to determine if the ntp package is installed: $ rpm -q ntp - Is it the case that the package is not installed? - - - - +$ sudo auditctl -l | grep -E '(/etc/shadow)' + +-w /etc/shadow -p wa -k identity + Is it the case that command does not return a line, or the line is commented out? + + + + To verify all files and directories in a local interactive user's +home directory have a valid owner, run the following command: +$ sudo ls -lLR /home/USER + Is it the case that the user ownership is incorrect? + + + + Verify that Oracle Linux 9 enforces password complexity by requiring that at least one lower-case character. + +Check the value for "lcredit" with the following command: + +$ sudo grep lcredit /etc/security/pwquality.conf /etc/security/pwquality.conf.d/*.conf + +/etc/security/pwquality.conf:lcredit = -1 + Is it the case that the value of "lcredit" is a positive number or is commented out? + + + + Run the following command to determine the current status of the chronyd service: $ sudo systemctl is-active chronyd If the service is running, it should return the following: active Is it the case that the chronyd process is not running? - - - - - -Run the following command to determine the current status of the -ntp service: -$ sudo systemctl is-active ntp -If the service is running, it should return the following: active - Is it the case that ? - - - - - -Run the following command to determine the current status of the -ntpd service: -$ sudo systemctl is-active ntpd -If the service is running, it should return the following: active - Is it the case that ? - - - - Run the following command to determine if the xinetd package is installed: -$ rpm -q xinetd - Is it the case that the package is installed? - - - - If network services are using the xinetd service, this is not applicable. - -To check that the xinetd service is disabled in system boot configuration, + + + + Run the following command to determine if the firewalld package is installed: $ rpm -q firewalld + Is it the case that the package is not installed? + + + + To check the permissions of /etc/sudoers.d, +run the command: +$ ls -l /etc/sudoers.d +If properly configured, the output should indicate the following permissions: +0750 + Is it the case that /etc/sudoers.d does not have unix mode 0750? + + + + To check the current idle time-out value, run the following command: +$ gsettings get org.gnome.desktop.session idle-delay +If properly configured, the output should be 'uint32 '. +To ensure that users cannot change the screensaver inactivity timeout setting, run the following: +$ grep idle-delay /etc/dconf/db/local.d/locks/* +If properly configured, the output should be /org/gnome/desktop/session/idle-delay + Is it the case that idle-delay is set to 0 or a value greater than <sub idref="inactivity_timeout_value" />? + + + + To determine if the system is configured to audit account changes, run the following command: -$ sudo systemctl is-enabled xinetd -Output should indicate the xinetd service has either not been installed, -or has been disabled at all runlevels, as shown in the example below: -$ sudo systemctl is-enabled xinetd disabled +auditctl -l | grep -E '(/etc/passwd|/etc/shadow|/etc/group|/etc/gshadow|/etc/security/opasswd)' +If the system is configured to watch for account changes, lines should be returned for +each file specified (and with perm=wa for each). + Is it the case that the system is not configured to audit account changes? + + + + To check the permissions of /etc/ssh/sshd_config, +run the command: +$ ls -l /etc/ssh/sshd_config +If properly configured, the output should indicate the following permissions: +-rw------- + Is it the case that /etc/ssh/sshd_config does not have unix mode -rw-------? + + + + root password is not set + Is it the case that Perform the following to determine if a password is set for the +root user: +<pre># grep -Eq '^root:\$[0-9]' /etc/shadow || echo "root is locked"</pre> +No results should be returned. +Otherwise, run the following command and follow the prompts to set a +password for the root user: +<pre># passwd root</pre>? + + + + To verify that USB Human Interface Devices and hubs will be authorized by the USBGuard daemon, +run the following command: +$ sudo grep allow /etc/usbguard/rules.conf +The output lines should include +allow with-interface match-all { 03:*:* 09:00:* } + Is it the case that USB devices of class 3 and 9:00 are not authorized? + + + + Verify that a separate file system/partition has been created for /tmp with the following command: -Run the following command to verify xinetd is not active (i.e. not running) through current runtime configuration: -$ sudo systemctl is-active xinetd +$ mountpoint /tmp -If the service is not running the command will return the following output: -inactive + Is it the case that "/tmp is not a mountpoint" is returned? + + + + -The service will also be masked, to check that the xinetd is masked, run the following command: -$ sudo systemctl show xinetd | grep "LoadState\|UnitFileState" +Run the following command to determine the current status of the +sshd service: +$ sudo systemctl is-active sshd +If the service is running, it should return the following: active + Is it the case that sshd service is disabled? + + + + To check the permissions of /boot/grub2/grub.cfg, run the command: +$ sudo ls -lL /boot/grub2/grub.cfg +If properly configured, the output should indicate the following +permissions: -rw------- + Is it the case that it does not? + + + + To determine how the SSH daemon's Banner option is set, run the following command: -If the service is masked the command will return the following outputs: +$ sudo grep -i Banner /etc/ssh/sshd_config -LoadState=masked +If a line indicating /etc/issue.net is returned, then the required value is set. -UnitFileState=masked - Is it the case that the "xinetd" is loaded and not masked? - - - - Verify that there are no shosts.equiv files on the system, run the following command: -$ find / -name shosts.equiv - Is it the case that shosts.equiv files exist? - - - - The existence of the file /etc/hosts.equiv or a file named -.rhosts inside a user home directory indicates the presence -of an Rsh trust relationship. - Is it the case that these files exist? - - - - To verify that there are no .shosts files -on the system, run the following command: -$ sudo find / -name '.shosts' - Is it the case that .shosts files exist? - - - - Run the following command to determine if the rsh-server package is installed: -$ rpm -q rsh-server + Is it the case that the required value is not set? + + + + The runtime status of the net.ipv4.icmp_ignore_bogus_error_responses kernel parameter can be queried +by running the following command: +$ sysctl net.ipv4.icmp_ignore_bogus_error_responses +1. + + Is it the case that the correct value is not returned? + + + + To verify that the Audit is correctly configured according to recommended rules, check the content of the file with the following command: +cat /etc/audit/rules.d/30-ospp-v42-5-perm-change-success.rules +The output has to be exactly as follows: +## Successful permission change +-a always,exit -F arch=b32 -S chmod,fchmod,fchmodat,setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-perm-change +-a always,exit -F arch=b64 -S chmod,fchmod,fchmodat,setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-perm-change + Is it the case that the file does not exist or the content differs? + + + + +If the system is configured to prevent the loading of the bluetooth kernel module, +it will contain lines inside any file in /etc/modprobe.d or the deprecated /etc/modprobe.conf. +These lines instruct the module loading system to run another program (such as /bin/false) upon a module install event. + +These lines can also instruct the module loading system to ignore the bluetooth kernel module via blacklist keyword. + +Run the following command to search for such lines in all files in /etc/modprobe.d and the deprecated /etc/modprobe.conf: +$ grep -r bluetooth /etc/modprobe.conf /etc/modprobe.d + Is it the case that no line is returned? + + + + Run the following command to determine if the libselinux package is installed: $ rpm -q libselinux + Is it the case that the package is not installed? + + + + To check the ownership of /etc/gshadow, +run the command: +$ ls -lL /etc/gshadow +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/gshadow does not have an owner of root? + + + + Run the following command to determine if the net-snmp package is installed: +$ rpm -q net-snmp Is it the case that the package is installed? - - - - The rsh package can be removed with the following command: $ sudo yum erase rsh + + + + The ftp package can be removed with the following command: $ sudo yum erase ftp Is it the case that ? - - - - + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "poweroff" command with the following command: + +$ sudo auditctl -l | grep poweroff + +-a always,exit -F path=/poweroff -F perm=x -F auid>=1000 -F auid!=unset -k privileged-poweroff + Is it the case that the command does not return a line, or the line is commented out? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_SECURITY_DMESG_RESTRICT /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To check the group ownership of /etc/gshadow-, +run the command: +$ ls -lL /etc/gshadow- +If properly configured, the output should indicate the following group-owner: +root + Is it the case that /etc/gshadow- does not have a group owner of root? + + + + To check the ownership of /var/log/messages, +run the command: +$ ls -lL /var/log/messages +If properly configured, the output should indicate the following owner: +root + Is it the case that /var/log/messages does not have an owner of root? + + + + To determine if the system is configured to audit calls to the +umount2 system call, run the following command: +$ sudo grep "umount2" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. + + Is it the case that no line is returned? + + + + The following command will locate the mount points related to local devices: +$ findmnt -n -l -k -it $(awk '/nodev/ { print $2 }' /proc/filesystems | paste -sd,) + +The following command will show files which do not belong to a valid group: +$ sudo find MOUNTPOINT -xdev -nogroup 2>/dev/null + +Replace MOUNTPOINT by the mount points listed by the fist command. + +No files without a valid group should be located. + Is it the case that there is output? + + + + Verify the nosuid option is configured for the /dev/shm mount point, + run the following command: + $ sudo mount | grep '\s/dev/shm\s' + . . . /dev/shm . . . nosuid . . . + + Is it the case that the "/dev/shm" file system does not have the "nosuid" option set? + + + + +To properly set the permissions of /etc/audit/, run the command: +$ sudo chmod 0640 /etc/audit/ + +To properly set the permissions of /etc/audit/rules.d/, run the command: +$ sudo chmod 0640 /etc/audit/rules.d/ + Is it the case that ? + + + + To check the permissions of /etc/audit/rules.d/*.rules, +run the command: +$ ls -l /etc/audit/rules.d/*.rules +If properly configured, the output should indicate the following permissions: +-rw------- + Is it the case that /etc/audit/rules.d/*.rules does not have unix mode -rw-------? + + + + To check the group ownership of /usr/bin/sudo, +run the command: +$ ls -lL /usr/bin/sudo +If properly configured, the output should indicate the following group-owner: + + Is it the case that /usr/bin/sudo does not have a group owner of <sub idref="var_sudo_dedicated_group" />? + + + + Verify that a separate file system/partition has been created for /srv with the following command: + +$ mountpoint /srv + + Is it the case that "/srv is not a mountpoint" is returned? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_RANDOMIZE_BASE /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_DEBUG_NOTIFIERS /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To ensure the failed password attempt policy is configured correctly, run the following command: + +$ grep fail_interval /etc/security/faillock.conf +The output should show fail_interval = <interval-in-seconds> where interval-in-seconds is or greater. + Is it the case that the "fail_interval" option is not set to "<sub idref="var_accounts_passwords_pam_faillock_fail_interval" />" +or less (but not "0"), the line is commented out, or the line is missing? + + + + Verify the value of the "minclass" option in "/etc/security/pwquality.conf" with the following command: + +$ grep minclass /etc/security/pwquality.conf + +minclass = + Is it the case that the value of "minclass" is set to less than "<sub idref="var_password_pam_minclass" />" or is commented out? + + + + To determine if the system is configured to audit changes to its network configuration, +run the following command: +auditctl -l | grep -E '(/etc/issue|/etc/issue.net|/etc/hosts|/etc/sysconfig/network)' + +If the system is configured to watch for network configuration changes, a line should be returned for +each file specified (and perm=wa should be indicated for each). + Is it the case that the system is not configured to audit changes of the network configuration? + + + + To ensure that users cannot change session idle and lock settings, run the following: +$ grep 'lock-delay' /etc/dconf/db/local.d/locks/* +If properly configured, the output should return: +/org/gnome/desktop/screensaver/lock-delay + Is it the case that GNOME3 session settings are not locked or configured properly? + + + + +Run the following command to determine if the authlogin_nsswitch_use_ldap SELinux boolean is disabled: +$ getsebool authlogin_nsswitch_use_ldap +If properly configured, the output should show the following: +authlogin_nsswitch_use_ldap --> off + Is it the case that authlogin_nsswitch_use_ldap is not disabled? + + + + In order to be sure that the databases are up-to-date, run the +dconf update +command as the administrator. + Is it the case that The system-wide dconf databases are up-to-date with regards to respective keyfiles? + + + + To determine if the system is configured to audit calls to the +fchmod system call, run the following command: +$ sudo grep "fchmod" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. + + Is it the case that no line is returned? + + + + To check that no password hashes are stored in +/etc/passwd, run the following command: +awk '!/\S:x|\*/ {print}' /etc/passwd +If it produces any output, then a password hash is +stored in /etc/passwd. + Is it the case that any stored hashes are found in /etc/passwd? + + + + To check which SSH protocol version is allowed, check version of openssh-server with following command: + +$ rpm -qi openssh-server | grep Version + +Versions equal to or higher than 7.4 only allow Protocol 2. +If version is lower than 7.4, run the following command to check configuration: +$ sudo grep Protocol /etc/ssh/sshd_config +If configured properly, output should be Protocol 2 + Is it the case that it is commented out or is not set correctly to Protocol 2? + + + + Verify that there are no wireless interfaces configured on the system +with the following command: + +Note: This requirement is Not Applicable for systems that do not have physical wireless network radios. + +$ nmcli device status +DEVICE TYPE STATE CONNECTION +virbr0 bridge connected virbr0 +wlp7s0 wifi connected wifiSSID +enp6s0 ethernet disconnected -- +p2p-dev-wlp7s0 wifi-p2p disconnected -- +lo loopback unmanaged -- +virbr0-nic tun unmanaged -- + Is it the case that a wireless interface is configured and has not been documented and approved by the Information System Security Officer (ISSO)? + + + + To verify that the Audit is correctly configured according to recommended rules, check the content of the file with the following command: +cat /etc/audit/rules.d/30-ospp-v42-1-create-success.rules +The output has to be exactly as follows: +## Successful file creation (open with O_CREAT) +-a always,exit -F arch=b32 -S openat,open_by_handle_at -F a2&0100 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-create +-a always,exit -F arch=b64 -S openat,open_by_handle_at -F a2&0100 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-create +-a always,exit -F arch=b32 -S open -F a1&0100 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-create +-a always,exit -F arch=b64 -S open -F a1&0100 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-create +-a always,exit -F arch=b32 -S creat -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-create +-a always,exit -F arch=b64 -S creat -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-create + Is it the case that the file does not exist or the content differs? + + + + Run the following command to determine if the cryptsetup package is installed: $ rpm -q cryptsetup + Is it the case that the package is not installed? + + + + To ensure the system is configured to mask the Ctrl-Alt-Del sequence, Check +that the ctrl-alt-del.target is masked and not active with the following +command: +sudo systemctl status ctrl-alt-del.target +The output should indicate that the target is masked and not active. It +might resemble following output: +ctrl-alt-del.target +Loaded: masked (/dev/null; bad) +Active: inactive (dead) + Is it the case that the system is configured to reboot when Ctrl-Alt-Del is pressed? + + + + Run the following command to determine if the opensc package is installed: $ rpm -q opensc + Is it the case that the package is not installed? + + + + To verify that there are no unauthorized local user accounts, run the following command: +$ less /etc/passwd +Inspect the results, and if unauthorized local user accounts exist, remove them by running +the following command: +$ sudo userdel unauthorized_user + Is it the case that there are unauthorized local user accounts on the system? + + + + To ensure root may not directly login to the system over physical consoles, +run the following command: +cat /etc/securetty +If any output is returned, this is a finding. + Is it the case that the /etc/securetty file is not empty? + + + + To determine how the SSH daemon's GSSAPIAuthentication option is set, run the following command: + +$ sudo grep -i GSSAPIAuthentication /etc/ssh/sshd_config + +If a line indicating yes is returned, then the required value is set. + + Is it the case that the required value is not set? + + + + +To properly set the owner of /etc/audit/, run the command: +$ sudo chown root /etc/audit/ + +To properly set the owner of /etc/audit/rules.d/, run the command: +$ sudo chown root /etc/audit/rules.d/ + Is it the case that ? + + + + To determine if the system is configured to audit calls to the +init_module system call, run the following command: +$ sudo grep "init_module" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. + + Is it the case that no line is returned? + + + + Verify that Oracle Linux 9 set the days of warning before a password expires to + or more for users with a +password: + +$ sudo awk -F: '$6 || $6 == "" {print $1}' /etc/shadow + Is it the case that any results are returned that are not associated with a system account? + + + + To determine if the system is configured to audit calls to the +chown system call, run the following command: +$ sudo grep "chown" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. + + Is it the case that no line is returned? + + + + Run the following command to determine if the nfs-utils package is installed: +$ rpm -q nfs-utils + Is it the case that the package is installed? + + + + System commands are stored in the following directories: +/bin +/sbin +/usr/bin +/usr/sbin +/usr/local/bin +/usr/local/sbin +For each of these directories, run the following command to find directories not +owned by root: +$ sudo find -L $DIR ! -user root -type d + Is it the case that any of these directories are not owned by root? + + + + To check the ownership of /etc/group, +run the command: +$ ls -lL /etc/group +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/group does not have an owner of root? + + + + Run the following command to determine if the cyrus-imapd package is installed: +$ rpm -q cyrus-imapd + Is it the case that the package is installed? + + + + Check the system partitions to determine if they are encrypted with the following command: +blkid + +Output will be similar to: +/dev/sda1: UUID=" ab12c3de-4f56-789a-8f33-3850cc8ce3a2 +" TYPE="crypto_LUKS" +/dev/sda2: UUID=" bc98d7ef-6g54-321h-1d24-9870de2ge1a2 +" TYPE="crypto_LUKS" + +The boot partition and pseudo-file systems, such as /proc, /sys, and tmpfs, +are not required to use disk encryption and are not a finding. + Is it the case that partitions do not have a type of crypto_LUKS? + + + + To determine if the system is configured to audit calls to the +renameat system call, run the following command: +$ sudo grep "renameat" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. + + Is it the case that no line is returned? + + + + Verify the usrquota option is configured for the /home mount point, + run the following command: + $ sudo mount | grep '\s/home\s' + . . . /home . . . usrquota . . . + + Is it the case that the "/home" file system does not have the "usrquota" option set? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "usermod" command with the following command: + +$ sudo auditctl -l | grep usermod + +-a always,exit -F path=/usr/bin/usermod -F perm=x -F auid>=1000 -F auid!=unset -k privileged-usermod + Is it the case that the command does not return a line, or the line is commented out? + + + + +Run the following command to determine if the selinuxuser_execstack SELinux boolean is disabled: +$ getsebool selinuxuser_execstack +If properly configured, the output should show the following: +selinuxuser_execstack --> off + Is it the case that selinuxuser_execstack is not disabled? + + + + Inspect /etc/default/grub for any instances of selinux=0 +in the kernel boot arguments. Presence of selinux=0 indicates +that SELinux is disabled at boot time. + Is it the case that SELinux is disabled at boot time? + + + + To determine if the system is configured to audit accesses to +/var/log/audit directory, run the following command: +$ sudo grep "dir=/var/log/audit" /etc/audit/audit.rules +If the system is configured to audit this activity, it will return a line. + Is it the case that no line is returned? + + + + If the device or Oracle Linux 9 does not have a camera installed, this requirement is not applicable. + +This requirement is not applicable to mobile devices (smartphones and tablets), where the use of the camera is a local AO decision. + +This requirement is not applicable to dedicated VTC suites located in approved VTC locations that are centrally managed. + +For an external camera, if there is not a method for the operator to manually disconnect the camera at the end of collaborative computing sessions, this is a finding. + +For a built-in camera, the camera must be protected by a camera cover (e.g., laptop camera cover slide) when not in use. If the built-in camera is not protected with a camera cover, or is not physically disabled, this is a finding. + +If the camera is not disconnected, covered, or physically disabled, determine if it is being disabled via software with the following commands: + +Verify the operating system disables the ability to load the uvcvideo kernel module. + +$ sudo grep -r uvcvideo /etc/modprobe.d/* | grep "/bin/true" + +install uvcvideo /bin/true + Is it the case that the command does not return any output, or the line is commented out, and the collaborative computing device has not been authorized for use? + + + + Verify that temporary accounts have been provisioned with an expiration date +of 72 hours. For every temporary account, run the following command to +obtain its account aging and expiration information: +$ sudo chage -l temporary_account_name +Verify each of these accounts has an expiration date set within 72 hours or +as documented. + Is it the case that any temporary accounts have no expiration date set or do not expire within 72 hours? + + + + Verify Oracle Linux 9 audits the execution of privileged functions. + +Check if Oracle Linux 9 is configured to audit the execution of the "execve" system call using the following command: + +$ sudo grep execve /etc/audit/audit.rules + +The output should be the following: + + +-a always,exit -F arch=b32 -S execve -C uid!=euid -F euid=0 -k setuid +-a always,exit -F arch=b64 -S execve -C uid!=euid -F euid=0 -k setuid +-a always,exit -F arch=b32 -S execve -C gid!=egid -F egid=0 -k setgid +-a always,exit -F arch=b64 -S execve -C gid!=egid -F egid=0 -k setgid + Is it the case that the command does not return all lines, or the lines are commented out? + + + + If IPv6 is disabled, this is not applicable. + +Inspect the file /etc/sysconfig/ip6tables to determine +the default policy for the INPUT chain. It should be set to DROP: +$ sudo grep ":INPUT" /etc/sysconfig/ip6tables + Is it the case that the default policy for the INPUT chain is not set to DROP? + + + + Verify the "/etc/security/faillock.conf" file is configured to log user name information when unsuccessful logon attempts occur: + +$ sudo grep audit /etc/security/faillock.conf + +audit + Is it the case that the "audit" option is not set, is missing or commented out? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "setsebool" command with the following command: + +$ sudo auditctl -l | grep setsebool + +-a always,exit -F path=/usr/sbin/setsebool -F perm=x -F auid>=1000 -F auid!=unset -k privileged + Is it the case that the command does not return a line, or the line is commented out? + + + + Verify the system-wide shared library files contained in the following directories have mode "755" or less permissive with the following command: + +$ sudo find -L /lib /lib64 /usr/lib /usr/lib64 -perm /022 -type f -exec ls -l {} \; + Is it the case that any system-wide shared library file is found to be group-writable or world-writable? + + + + To check for virtual console entries which permit root login, run the +following command: +$ sudo grep ^vc/[0-9] /etc/securetty +If any output is returned, then root logins over virtual console devices is permitted. + Is it the case that root login over virtual console devices is permitted? + + + + The runtime status of the kernel.randomize_va_space kernel parameter can be queried +by running the following command: +$ sysctl kernel.randomize_va_space +2. + + Is it the case that the correct value is not returned? + + + + Check whether the maximum time period for existing passwords is restricted to days with the following commands: + +$ sudo awk -F: '$5 > 60 {print $1 " " $5}' /etc/shadow + +$ sudo awk -F: '$5 <= 0 {print $1 " " $5}' /etc/shadow + Is it the case that any results are returned that are not associated with a system account? + + + + Verify the nosuid option is configured for the /tmp mount point, + run the following command: + $ sudo mount | grep '\s/tmp\s' + . . . /tmp . . . nosuid . . . + + Is it the case that the "/tmp" file system does not have the "nosuid" option set? + + + + To determine how the SSH daemon's X11Forwarding option is set, run the following command: + +$ sudo grep -i X11Forwarding /etc/ssh/sshd_config + +If a line indicating no is returned, then the required value is set. + + Is it the case that the required value is not set? + + + + To check if UsePrivilegeSeparation is enabled or set correctly, run the +following command: +$ sudo grep UsePrivilegeSeparation /etc/ssh/sshd_config +If configured properly, output should be . + Is it the case that it is commented out or is not enabled? + + + + The file /etc/at.deny should not exist. +This can be checked by running the following + +stat /etc/at.deny + +and the output should be + +stat: cannot stat `/etc/at.deny': No such file or directory + + Is it the case that the file /etc/at.deny exists? + + + + Run the following command to determine if the sudo package is installed: $ rpm -q sudo + Is it the case that the package is not installed? + + + + The runtime status of the kernel.yama.ptrace_scope kernel parameter can be queried +by running the following command: +$ sysctl kernel.yama.ptrace_scope +1. + + Is it the case that the correct value is not returned? + + + + The runtime status of the net.ipv4.conf.default.rp_filter kernel parameter can be queried +by running the following command: +$ sysctl net.ipv4.conf.default.rp_filter +1. + + Is it the case that the correct value is not returned? + + + + Run the following command to see what the max sessions number is: +$ sudo grep MaxSessions /etc/ssh/sshd_config +If properly configured, the output should be: +MaxSessions + Is it the case that MaxSessions is not configured or not configured correctly? + + + + To check the group ownership of /etc/crontab, +run the command: +$ ls -lL /etc/crontab +If properly configured, the output should indicate the following group-owner: +root + Is it the case that /etc/crontab does not have a group owner of root? + + + + To check the group ownership of /etc/shells, +run the command: +$ ls -lL /etc/shells +If properly configured, the output should indicate the following group-owner: +root + Is it the case that /etc/shells does not have a group owner of root? + + + + To check the ownership of /etc/cron.weekly, +run the command: +$ ls -lL /etc/cron.weekly +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/cron.weekly does not have an owner of root? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_GCC_PLUGIN_RANDSTRUCT /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was built with the required value? + + + + Run the following command to determine if the openssh-server package is installed: $ rpm -q openssh-server + Is it the case that the package is installed? + + + + +If the system is configured to prevent the loading of the firewire-core kernel module, +it will contain lines inside any file in /etc/modprobe.d or the deprecated /etc/modprobe.conf. +These lines instruct the module loading system to run another program (such as /bin/false) upon a module install event. + +These lines can also instruct the module loading system to ignore the firewire-core kernel module via blacklist keyword. + +Run the following command to search for such lines in all files in /etc/modprobe.d and the deprecated /etc/modprobe.conf: +$ grep -r firewire-core /etc/modprobe.conf /etc/modprobe.d + Is it the case that no line is returned? + + + + To check that the rlogin service is disabled in system boot configuration with xinetd, run the following command: $ chkconfig rlogin --list Output should indicate the rlogin service has either not been installed, or has been disabled, as shown in the example below: @@ -234900,33 +254842,1778 @@ LoadState=masked UnitFileState=masked Is it the case that service and/or socket are running? - - - - Run the following command to determine if the talk-server package is installed: -$ rpm -q talk-server - Is it the case that the package is installed? - - - - Run the following command to determine if the talk package is installed: -$ rpm -q talk - Is it the case that the package is installed? - - - - Run the following command to determine if the telnet-server package is installed: -$ rpm -q telnet-server - Is it the case that the package is installed? - - - - The telnet package can be removed with the following command: $ sudo yum erase telnet + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_PROC_KCORE /boot/config.* + + Configs with value 'n' are not explicitly set in the file, so either commented lines or no + lines should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To check the group ownership of /etc/passwd, +run the command: +$ ls -lL /etc/passwd +If properly configured, the output should indicate the following group-owner: +root + Is it the case that /etc/passwd does not have a group owner of root? + + + + To verify that the Audit is correctly configured according to recommended rules, check the content of the file with the following command: +cat /etc/audit/rules.d/30-ospp-v42-2-modify-success.rules +The output has to be exactly as follows: +## Successful file modifications (open for write or truncate) +-a always,exit -F arch=b32 -S openat,open_by_handle_at -F a2&01003 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-modification +-a always,exit -F arch=b64 -S openat,open_by_handle_at -F a2&01003 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-modification +-a always,exit -F arch=b32 -S open -F a1&01003 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-modification +-a always,exit -F arch=b64 -S open -F a1&01003 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-modification +-a always,exit -F arch=b32 -S truncate,ftruncate -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-modification +-a always,exit -F arch=b64 -S truncate,ftruncate -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-modification + Is it the case that the file does not exist or the content differs? + + + + To verify that the Dracut FIPS module is enabled, run the following command: +grep "add_dracutmodules" /etc/dracut.conf.d/40-fips.conf +The output should look like this: +add_dracutmodules+=" fips " + Is it the case that the Dracut FIPS module is not enabled? + + + + To check the ownership of /etc/sudoers, +run the command: +$ ls -lL /etc/sudoers +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/sudoers does not have an owner of root? + + + + Verify the umask setting is configured correctly in the /etc/profile file +or scripts within /etc/profile.d directory with the following command: +$ grep "umask" /etc/profile* +umask + Is it the case that the value for the "umask" parameter is not "<sub idref="var_accounts_user_umask" />", +or the "umask" parameter is missing or is commented out? + + + + To determine how the SSH daemon's X11Forwarding option is set, run the following command: + +$ sudo grep -i X11Forwarding /etc/ssh/sshd_config + +If a line indicating yes is returned, then the required value is set. + + Is it the case that the required value is not set? + + + + Verify that Oracle Linux 9 is configured to prevent unrestricted mail relaying, +run the following command: +$ sudo postconf -n smtpd_client_restrictions + Is it the case that the "smtpd_client_restrictions" parameter contains any entries other than "permit_mynetworks" and "reject"? + + + + Run the following command to determine if the audit package is installed: $ rpm -q audit + Is it the case that the audit package is not installed? + + + + Inspect /etc/login.defs and ensure that if either +SHA_CRYPT_MIN_ROUNDS or SHA_CRYPT_MAX_ROUNDS +are set, they must have the minimum value of . + Is it the case that it does not? + + + + Inspect the network interfaces assigned to the firewalld trusted zone and verify the +lo interface is listed by running the following command: + +$ sudo firewall-cmd --list-interfaces --zone=trusted + Is it the case that loopback traffic is not trusted? + + + + To check the ownership of /etc/cron.monthly, +run the command: +$ ls -lL /etc/cron.monthly +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/cron.monthly does not have an owner of root? + + + + The runtime status of the net.ipv6.conf.all.router_solicitations kernel parameter can be queried +by running the following command: +$ sysctl net.ipv6.conf.all.router_solicitations +0. + + Is it the case that the correct value is not returned? + + + + The runtime status of the net.ipv4.conf.all.log_martians kernel parameter can be queried +by running the following command: +$ sysctl net.ipv4.conf.all.log_martians +1. + + Is it the case that the correct value is not returned? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_HARDENED_USERCOPY_FALLBACK /boot/config.* + + Configs with value 'n' are not explicitly set in the file, so either commented lines or no + lines should be returned. + + Is it the case that the kernel was not built with the required value? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "semanage" command with the following command: + +$ sudo auditctl -l | grep semanage + +-a always,exit -F path=/usr/sbin/semanage -F perm=x -F auid>=1000 -F auid!=unset -k privileged-unix-update + Is it the case that the command does not return a line, or the line is commented out? + + + + To determine if logfile has been configured for sudo, run the following command: +$ sudo grep -ri "^[\s]*Defaults\s*\blogfile\b.*" /etc/sudoers /etc/sudoers.d/ +The command should return a matching output. + Is it the case that logfile is not enabled in sudo? + + + + Verify that core dumps are disabled for all users, run the following command: +$ grep core /etc/security/limits.conf +* hard core 0 + Is it the case that the "core" item is missing, commented out, or the value is anything other than "0" and the need for core dumps is not documented with the Information System Security Officer (ISSO) as an operational requirement for all domains that have the "core"? + + + + The runtime status of the kernel.core_uses_pid kernel parameter can be queried +by running the following command: +$ sysctl kernel.core_uses_pid +0. + Is it the case that the returned line does not have a value of 0? + + + + Verify Oracle Linux 9 generates audit records for all account creations, modifications, disabling, and termination events that affect "/etc/passwd" with the following command: + +$ sudo auditctl -l | grep -E '(/etc/passwd)' + +-w /etc/passwd -p wa -k identity + Is it the case that the command does not return a line, or the line is commented out? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_GCC_PLUGIN_LATENT_ENTROPY /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To verify if the OpenSSH client uses defined MACs in the Crypto Policy, run: +$ grep -i macs /etc/crypto-policies/back-ends/openssh.config +and verify that the line matches: +MACs + Is it the case that Crypto Policy for OpenSSH client is not configured correctly? + + + + +Run the following command to determine if the kerberos_enabled SELinux boolean is enabled: +$ getsebool kerberos_enabled +If properly configured, the output should show the following: +kerberos_enabled --> on + Is it the case that kerberos_enabled is not enabled? + + + + To check the permissions of /etc/passwd-, +run the command: +$ ls -l /etc/passwd- +If properly configured, the output should indicate the following permissions: +-rw-r--r-- + Is it the case that /etc/passwd- does not have unix mode -rw-r--r--? + + + + To ensure the X Windows package group is removed, run the following command: + +$ rpm -qi xorg-x11-server-Xorg xorg-x11-server-common xorg-x11-server-utils xorg-x11-server-Xwayland + +For each package mentioned above you should receive following line: +package <package> is not installed + Is it the case that xorg related packages are not removed and run level is not correctly configured? + + + + To verify that execution of the command is being audited, run the following command: +$ sudo grep "path=/usr/sbin/seunshare" /etc/audit/audit.rules /etc/audit/rules.d/* +The output should return something similar to: +-a always,exit -F path=/usr/sbin/seunshare -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged Is it the case that ? - - - - + + + + Run the following command to Verify that the sudoers security policy is configured to use the invoking user's password for privilege escalation: + sudo cvtsudoers -f sudoers /etc/sudoers | grep -E '^Defaults !?(rootpw|targetpw|runaspw)' +or if cvtsudoers not supported: + sudo find /etc/sudoers /etc/sudoers.d \( \! -name '*~' -a \! -name '*.*' \) -exec grep -E --with-filename '^[[:blank:]]*Defaults[[:blank:]](.*[[:blank:]])?!?\b(rootpw|targetpw|runaspw)' -- {} \; +If no results are returned, this is a finding. +If conflicting results are returned, this is a finding. +If "Defaults !targetpw" is not defined, this is a finding. +If "Defaults !rootpw" is not defined, this is a finding. +If "Defaults !runaspw" is not defined, this is a finding. + Is it the case that invoke user passwd when using sudo? + + + + Verify the nodev option is configured for the /dev/shm mount point, + run the following command: + $ sudo mount | grep '\s/dev/shm\s' + . . . /dev/shm . . . nodev . . . + + Is it the case that the "/dev/shm" file system does not have the "nodev" option set? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_DEBUG_LIST /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To check the group ownership of /etc/chrony.keys, +run the command: +$ ls -lL /etc/chrony.keys +If properly configured, the output should indicate the following group-owner: +chrony + Is it the case that /etc/chrony.keys does not have a group owner of chrony? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_PANIC_ON_OOPS /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + The runtime status of the kernel.modules_disabled kernel parameter can be queried +by running the following command: +$ sysctl kernel.modules_disabled +1. + + Is it the case that the correct value is not returned? + + + + Verify that a separate file system/partition has been created for /var/log with the following command: + +$ mountpoint /var/log + + Is it the case that "/var/log is not a mountpoint" is returned? + + + + To check the group ownership of /etc/group, +run the command: +$ ls -lL /etc/group +If properly configured, the output should indicate the following group-owner: +root + Is it the case that /etc/group does not have a group owner of root? + + + + Verify Oracle Linux 9 disables network management of the chrony daemon with the following command: +$ grep -w cmdport /etc/chrony.conf +cmdport 0 + Is it the case that the "cmdport" option is not set to "0", is commented out, or is missing? + + + + Run the following command to determine if the gnutls-utils package is installed: $ rpm -q gnutls-utils + Is it the case that the package is not installed? + + + + To check that the debug-shell service is disabled in system boot configuration, +run the following command: +$ sudo systemctl is-enabled debug-shell +Output should indicate the debug-shell service has either not been installed, +or has been disabled at all runlevels, as shown in the example below: +$ sudo systemctl is-enabled debug-shell disabled + +Run the following command to verify debug-shell is not active (i.e. not running) through current runtime configuration: +$ sudo systemctl is-active debug-shell + +If the service is not running the command will return the following output: +inactive + +The service will also be masked, to check that the debug-shell is masked, run the following command: +$ sudo systemctl show debug-shell | grep "LoadState\|UnitFileState" + +If the service is masked the command will return the following outputs: + +LoadState=masked + +UnitFileState=masked + Is it the case that the "debug-shell" is loaded and not masked? + + + + To verify if the OpenSSH server uses defined MACs in the Crypto Policy, run: +$ grep -Po '(-oMACs=\S+)' /etc/crypto-policies/back-ends/opensshserver.config +and verify that the line matches: +-oMACS= + Is it the case that Crypto Policy for OpenSSH Server is not configured correctly? + + + + The runtime status of the net.ipv6.conf.default.accept_ra_pinfo kernel parameter can be queried +by running the following command: +$ sysctl net.ipv6.conf.default.accept_ra_pinfo +0. + + Is it the case that the correct value is not returned? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_RANDOMIZE_MEMORY /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_IPV6 /boot/config.* + + Configs with value 'n' are not explicitly set in the file, so either commented lines or no + lines should be returned. + + Is it the case that the kernel was not built with the required value? + + + + Verify that Oracle Linux 9 generates an audit record for all uses of the "umount" and system call. +To determine if the system is configured to audit calls to the +"umount" system call, run the following command: +$ sudo grep "umount" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line like the following. +-a always,exit -F arch=b32 -S umount -F auid>=1000 -F auid!=unset -k privileged-umount + Is it the case that the command does not return a line, or the line is commented out? + + + + + +Run the following command to determine the current status of the +syslog-ng service: +$ sudo systemctl is-active syslog-ng +If the service is running, it should return the following: active + Is it the case that the "syslog-ng" service is disabled, masked, or not started.? + + + + +Run the following command to determine if the selinuxuser_execheap SELinux boolean is disabled: +$ getsebool selinuxuser_execheap +If properly configured, the output should show the following: +selinuxuser_execheap --> off + Is it the case that selinuxuser_execheap is not disabled? + + + + Verify that the IPSec service uses the system crypto policy. + +If the ipsec service is not installed is not applicable. + +Check to see if the "IPsec" service is active with the following command: + +$ systemctl status ipsec + +ipsec.service - Internet Key Exchange (IKE) Protocol Daemon for IPsec +Loaded: loaded (/usr/lib/systemd/system/ipsec.service; disabled) +Active: inactive (dead) + +If the "IPsec" service is active, check to see if it is using the system crypto policy with the following command: + +$ sudo grep include /etc/ipsec.conf /etc/ipsec.d/*.conf + +/etc/ipsec.conf:include /etc/crypto-policies/back-ends/libreswan.config + Is it the case that the "IPsec" service is active and the ipsec configuration file does not contain does not contain <tt>include /etc/crypto-policies/back-ends/libreswan.config</tt>? + + + + +Run the following command to determine if the selinuxuser_execmod SELinux boolean is enabled: +$ getsebool selinuxuser_execmod +If properly configured, the output should show the following: +selinuxuser_execmod --> on + Is it the case that selinuxuser_execmod is not enabled? + + + + To check the ownership of /etc/gshadow-, +run the command: +$ ls -lL /etc/gshadow- +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/gshadow- does not have an owner of root? + + + + +If the system is configured to prevent the loading of the cramfs kernel module, +it will contain lines inside any file in /etc/modprobe.d or the deprecated /etc/modprobe.conf. +These lines instruct the module loading system to run another program (such as /bin/false) upon a module install event. + +These lines can also instruct the module loading system to ignore the cramfs kernel module via blacklist keyword. + +Run the following command to search for such lines in all files in /etc/modprobe.d and the deprecated /etc/modprobe.conf: +$ grep -r cramfs /etc/modprobe.conf /etc/modprobe.d + Is it the case that no line is returned? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "chsh" command with the following command: + +$ sudo auditctl -l | grep chsh + +-a always,exit -F path=/usr/bin/chsh -F perm=x -F auid>=1000 -F auid!=unset -k privileged-chsh + Is it the case that the command does not return a line, or the line is commented out? + + + + To check the group ownership of /etc/iptables, +run the command: +$ ls -lL /etc/iptables +If properly configured, the output should indicate the following group-owner: +root + Is it the case that /etc/iptables does not have a group owner of root? + + + + Run the following command to determine if the pcsc-lite package is installed: $ rpm -q pcsc-lite + Is it the case that the package is not installed? + + + + To check for incorrectly labeled device files, run following commands: +$ sudo find /dev -context *:device_t:* \( -type c -o -type b \) -printf "%p %Z\n" +$ sudo find /dev -context *:unlabeled_t:* \( -type c -o -type b \) -printf "%p %Z\n" +It should produce no output in a well-configured system. + Is it the case that there is output? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_GCC_PLUGIN_STRUCTLEAK_BYREF_ALL /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine if the system is configured to audit calls to the +finit_module system call, run the following command: +$ sudo grep "finit_module" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. + + Is it the case that no line is returned? + + + + Verify users are provided with feedback on when account accesses last occurred with the following command: + +$ sudo grep pam_lastlog /etc/pam.d/postlogin + +session required pam_lastlog.so showfailed + Is it the case that "pam_lastlog.so" is not properly configured in "/etc/pam.d/postlogin" file? + + + + Verify that DNS servers have been configured properly, perform the following: +$ sudo grep nameserver /etc/resolv.conf + Is it the case that less than two lines are returned that are not commented out? + + + + Inspect the form of default GRUB 2 command line for the Linux operating system +in /etc/default/grub. If it includes mds=, +then the parameter will be configured for newly installed kernels. +First check if the GRUB recovery is enabled: +$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub +If this option is set to true, then check that a line is output by the following command: +$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*mds=.*' /etc/default/grub +If the recovery is disabled, check the line with +$ sudo grep 'GRUB_CMDLINE_LINUX.*mds=.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. +Run the following command: +$ sudo grubby --info=ALL | grep args | grep -v 'mds=' +The command should not return any output. + Is it the case that MDS mitigations are not configured appropriately? + + + + Run the following command to determine if the aide package is installed: $ rpm -q aide + Is it the case that the package is not installed? + + + + Run the following command to determine if the rear package is installed: $ rpm -q rear + Is it the case that the package is not installed? + + + + Verify the noexec option is configured for the /home mount point, + run the following command: + $ sudo mount | grep '\s/home\s' + . . . /home . . . noexec . . . + + Is it the case that the "/home" file system does not have the "noexec" option set? + + + + To check the group ownership of /var/log/messages, +run the command: +$ ls -lL /var/log/messages +If properly configured, the output should indicate the following group-owner: +root + Is it the case that /var/log/messages does not have a group owner of root? + + + + Inspect the file /etc/firewalld/firewalld.conf to determine +the default zone for the firewalld. It should be set to DefaultZone=drop: +$ sudo grep DefaultZone /etc/firewalld/firewalld.conf + Is it the case that the default zone is not set to DROP? + + + + Verify that only the "root" account has a UID "0" assignment with the +following command: +$ awk -F: '$3 == 0 {print $1}' /etc/passwd +root + Is it the case that any accounts other than "root" have a UID of "0"? + + + + Verify the system commands contained in the following directories have mode "755" or less permissive with the following command: + +$ sudo find -L /bin /sbin /usr/bin /usr/sbin /usr/libexec /usr/local/bin /usr/local/sbin -perm /022 -exec ls -l {} \; + Is it the case that any system commands are found to be group-writable or world-writable? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "userhelper" command with the following command: + +$ sudo auditctl -l | grep userhelper + +-a always,exit -F path=/usr/bin/userhelper -F perm=x -F auid>=1000 -F auid!=unset -k privileged-userhelper + Is it the case that the command does not return a line, or the line is commented out? + + + + Run the following command to determine if the syslog-ng-core package is installed: $ rpm -q syslog-ng-core + Is it the case that the package is not installed? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "gpasswd" command with the following command: + +$ sudo auditctl -l | grep gpasswd + +-a always,exit -F path=/usr/bin/gpasswd -F perm=x -F auid>=1000 -F auid!=unset -k privileged-gpasswd + Is it the case that the command does not return a line, or the line is commented out? + + + + To determine if the system is configured to audit calls to the +rmdir system call, run the following command: +$ sudo grep "rmdir" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. +To determine if the system is configured to audit calls to the +unlink system call, run the following command: +$ sudo grep "unlink" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. +To determine if the system is configured to audit calls to the +unlinkat system call, run the following command: +$ sudo grep "unlinkat" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. +To determine if the system is configured to audit calls to the +rename system call, run the following command: +$ sudo grep "rename" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. +To determine if the system is configured to audit calls to the +renameat system call, run the following command: +$ sudo grep "renameat" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. + Is it the case that no line is returned? + + + + To check the ownership of /boot/grub2/user.cfg, +run the command: +$ ls -lL /boot/grub2/user.cfg +If properly configured, the output should indicate the following owner: +root + Is it the case that /boot/grub2/user.cfg does not have an owner of root? + + + + Verify that Oracle Linux 9 disables the use of user namespaces with the following commands: + +Note: User namespaces are used primarily for Linux containers. If containers are in use, this requirement is not applicable. + +The runtime status of the user.max_user_namespaces kernel parameter can be queried +by running the following command: +$ sysctl user.max_user_namespaces +0. + + Is it the case that the correct value is not returned? + + + + To verify that packages comprising the available updates will be automatically installed by dnf-automatic, run the following command: +$ sudo grep apply_updates /etc/dnf/automatic.conf +The output should return the following: +apply_updates = yes + Is it the case that apply_updates is not set to yes? + + + + Verify that Oracle Linux 9 is configured to notify the SA and/or ISSO (at a minimum) in the event of an audit processing failure with the following command: + +$ sudo grep action_mail_acct /etc/audit/auditd.conf + +action_mail_acct = + Is it the case that the value of the "action_mail_acct" keyword is not set to "<sub idref="var_auditd_action_mail_acct" />" and/or other accounts for security personnel, the "action_mail_acct" keyword is missing, or the retuned line is commented out, ask the system administrator to indicate how they and the ISSO are notified of an audit process failure. If there is no evidence of the proper personnel being notified of an audit processing failure? + + + + To verify that McAfee Endpoint Security for Linux is +running, run the following command: +$ sudo ps -ef | grep -i mfetpd + Is it the case that virus scanning software is not running? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_LEGACY_PTYS /boot/config.* + + Configs with value 'n' are not explicitly set in the file, so either commented lines or no + lines should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine if the system is configured to audit calls to the +rename system call, run the following command: +$ sudo grep "rename" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. + + Is it the case that no line is returned? + + + + Verify file systems that are used for removable media are mounted with the "nosuid" option with the following command: + +$ sudo more /etc/fstab + +UUID=2bc871e4-e2a3-4f29-9ece-3be60c835222 /mnt/usbflash vfat noauto,owner,ro,nosuid,nodev,noexec 0 0 + Is it the case that file system found in "/etc/fstab" refers to removable media and it does not have the "nosuid" option set? + + + + To determine if the system is configured to audit calls to the +mount system call, run the following command: +$ sudo grep "mount" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. + + Is it the case that no line is returned? + + + + To check the ownership of /etc/cron.hourly, +run the command: +$ ls -lL /etc/cron.hourly +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/cron.hourly does not have an owner of root? + + + + To check the permissions of /boot/grub2/user.cfg, +run the command: +$ ls -l /boot/grub2/user.cfg +If properly configured, the output should indicate the following permissions: +-rw------- + Is it the case that /boot/grub2/user.cfg does not have unix mode -rw-------? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "passwd" command with the following command: + +$ sudo auditctl -l | grep passwd + +-a always,exit -F path=/usr/bin/passwd -F perm=x -F auid>=1000 -F auid!=unset -k privileged-passwd + Is it the case that the command does not return a line, or the line is commented out? + + + + The runtime status of the net.ipv4.conf.default.shared_media kernel parameter can be queried +by running the following command: +$ sysctl net.ipv4.conf.default.shared_media +0. + + Is it the case that the correct value is not returned? + + + + Ensure that Oracle Linux 9 verifies correct operation of security functions. + +Check if "SELinux" is active and in "" mode with the following command: + +$ sudo getenforce + + Is it the case that SELINUX is not set to enforcing? + + + + Verify Oracle Linux 9 use the "pam_pwhistory.so" module in the /etc/pam.d/system-auth file +and is configured to prohibit password reuse for a minimum of +generations. + +Verify the "/etc/pam.d/system-auth" file with the following command: + +$ grep pam_pwhistory.so /etc/pam.d/system-auth +password pam_pwhistory.so use_authtok remember= + + +Verify the "/etc/security/pwhistory.conf" file using the following command: + +$ grep remember /etc/security/pwhistory.conf +remember = + +The pam_pwhistory.so "remember" option must be configured only in one file. + Is it the case that the pam_pwhistory.so module is not used, the "remember" module option is not set in +/etc/pam.d/system-auth or in /etc/security/pwhistory.conf, or is set in both files, or is set +with a value less than "<sub idref="var_password_pam_remember" />"? + + + + To verify that Linux Audit logging is enabled for the USBGuard daemon, +run the following command: +$ sudo grep AuditBackend /etc/usbguard/usbguard-daemon.conf +The output should be +AuditBackend=LinuxAudit + Is it the case that AuditBackend is not set to LinuxAudit? + + + + To check the permissions of /etc/cron.monthly, +run the command: +$ ls -l /etc/cron.monthly +If properly configured, the output should indicate the following permissions: +-rwx------ + Is it the case that /etc/cron.monthly does not have unix mode -rwx------? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_COMPAT_VDSO /boot/config.* + + Configs with value 'n' are not explicitly set in the file, so either commented lines or no + lines should be returned. + + Is it the case that the kernel was not built with the required value? + + + + Verify "nftables" is configured to allow rate limits on any connection to the system with the following command: + +Verify "firewalld" has "nftables" set as the default backend: + +$ sudo grep -i firewallbackend /etc/firewalld/firewalld.conf + +# FirewallBackend +FirewallBackend=nftables + Is it the case that the "nftables" is not set as the "firewallbackend"? + + + + To check the group ownership of /etc/issue.net, +run the command: +$ ls -lL /etc/issue.net +If properly configured, the output should indicate the following group-owner: +root + Is it the case that /etc/issue.net does not have a group owner of root? + + + + +Run the following command to determine the current status of the +tmp mount: +$ sudo systemctl is-active tmp.mount +If the mount unit is running, it should return the following: active + Is it the case that the tmp.mount unit is masked or disabled? + + + + Verify the nosuid option is configured for the /boot/efi mount point, + run the following command: + $ sudo mount | grep '\s/boot/efi\s' + . . . /boot/efi . . . nosuid . . . + + Is it the case that the "/boot/efi" file system does not have the "nosuid" option set? + + + + To determine if the system is configured to audit calls to the +setxattr system call, run the following command: +$ sudo grep "setxattr" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. + + Is it the case that no line is returned? + + + + To check the group ownership of /etc/selinux, +run the command: +$ ls -lL /etc/selinux +If properly configured, the output should indicate the following group-owner: +root + Is it the case that /etc/selinux does not have a group owner of root? + + + + Verify the SELINUX on Oracle Linux 9 is using the policy with the following command: + +$ sestatus | grep policy + +Loaded policy name: + Is it the case that the loaded policy name is not "<sub idref="var_selinux_policy_name" />"? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_LEGACY_VSYSCALL_NONE /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To check that the nftables service is disabled in system boot configuration, +run the following command: +$ sudo systemctl is-enabled nftables +Output should indicate the nftables service has either not been installed, +or has been disabled at all runlevels, as shown in the example below: +$ sudo systemctl is-enabled nftables disabled + +Run the following command to verify nftables is not active (i.e. not running) through current runtime configuration: +$ sudo systemctl is-active nftables + +If the service is not running the command will return the following output: +inactive + +The service will also be masked, to check that the nftables is masked, run the following command: +$ sudo systemctl show nftables | grep "LoadState\|UnitFileState" + +If the service is masked the command will return the following outputs: + +LoadState=masked + +UnitFileState=masked + Is it the case that the "nftables" is loaded and not masked? + + + + To check the ownership of /etc/passwd, +run the command: +$ ls -lL /etc/passwd +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/passwd does not have an owner of root? + + + + To verify that the Audit is correctly configured according to recommended rules, check the content of the file with the following command: +$ sudo cat /etc/audit/rules.d/11-loginuid.rules +The output has to be exactly as follows: +## Make the loginuid immutable. This prevents tampering with the auid. +--loginuid-immutable + Is it the case that the file does not exist or the content differs? + + + + To ensure all GIDs referenced in /etc/passwd are defined in /etc/group, +run the following command: +$ sudo pwck -qr +There should be no output. + Is it the case that GIDs referenced in /etc/passwd are returned as not defined in /etc/group? + + + + To determine the status and frequency of logrotate, run the following command: +$ sudo grep logrotate /var/log/cron* +If logrotate is configured properly, output should include references to +/etc/cron.daily. + Is it the case that logrotate is not configured to run daily? + + + + Run the following command to determine if the setroubleshoot-server package is installed: +$ rpm -q setroubleshoot-server + Is it the case that the package is installed? + + + + Verify the nodev option is configured for the /var/log/audit mount point, + run the following command: + $ sudo mount | grep '\s/var/log/audit\s' + . . . /var/log/audit . . . nodev . . . + + Is it the case that the "/var/log/audit" file system does not have the "nodev" option set? + + + + To verify the INACTIVE setting, run the following command: +$ grep "INACTIVE" /etc/default/useradd +The output should indicate the INACTIVE configuration option is set +to an appropriate integer as shown in the example below: +$ grep "INACTIVE" /etc/default/useradd +INACTIVE= + Is it the case that the value of INACTIVE is greater than the expected value or is -1? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "ssh-keysign" command with the following command: + +$ sudo auditctl -l | grep ssh-keysign + +-a always,exit -F path=/usr/libexec/openssh/ssh-keysign -F perm=x -F auid>=1000 -F auid!=unset -k privileged-ssh-keysign + Is it the case that the command does not return a line, or the line is commented out? + + + + Verify the audit tools are protected from unauthorized access, deletion, or modification by checking the permissive mode. + +Check the octal permission of each audit tool by running the following command: + +$ sudo stat -c "%U %n" /sbin/auditctl /sbin/aureport /sbin/ausearch /sbin/autrace /sbin/auditd /sbin/rsyslogd /sbin/augenrules + Is it the case that any of these files have more permissive permissions than 0755? + + + + To check the group ownership of /etc/ipsec.conf, +run the command: +$ ls -lL /etc/ipsec.conf +If properly configured, the output should indicate the following group-owner: +root + Is it the case that /etc/ipsec.conf does not have a group owner of root? + + + + Verify the operating system audits activities performed during nonlocal +maintenance and diagnostic sessions. Run the following command: +$ sudo auditctl -l | grep sudo.log +-w /var/log/sudo.log -p wa -k maintenance + + Is it the case that Audit rule is not present? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_SECURITY_WRITABLE_HOOKS /boot/config.* + + Configs with value 'n' are not explicitly set in the file, so either commented lines or no + lines should be returned. + + Is it the case that the kernel was not built with the required value? + + + + Run the following command to check if the line is present: +grep pam_wheel /etc/pam.d/su +The output should contain the following line: +auth required pam_wheel.so use_uid + Is it the case that the line is not in the file or it is commented? + + + + To check that the kdump service is disabled in system boot configuration, +run the following command: +$ sudo systemctl is-enabled kdump +Output should indicate the kdump service has either not been installed, +or has been disabled at all runlevels, as shown in the example below: +$ sudo systemctl is-enabled kdump disabled + +Run the following command to verify kdump is not active (i.e. not running) through current runtime configuration: +$ sudo systemctl is-active kdump + +If the service is not running the command will return the following output: +inactive + +The service will also be masked, to check that the kdump is masked, run the following command: +$ sudo systemctl show kdump | grep "LoadState\|UnitFileState" + +If the service is masked the command will return the following outputs: + +LoadState=masked + +UnitFileState=masked + Is it the case that the "kdump" is loaded and not masked? + + + + The runtime status of the net.ipv6.conf.default.accept_ra_rtr_pref kernel parameter can be queried +by running the following command: +$ sysctl net.ipv6.conf.default.accept_ra_rtr_pref +0. + + Is it the case that the correct value is not returned? + + + + These settings can be verified by running the following: +$ gsettings get org.gnome.desktop.media-handling autorun-never +If properly configured, the output for autorun-nevershould be true. +To ensure that users cannot enable autorun in GNOME3, run the following: +$ grep 'autorun-never' /etc/dconf/db/local.d/locks/* +If properly configured, the output for autorun-never should be /org/gnome/desktop/media-handling/autorun-never + Is it the case that GNOME autorun is not disabled? + + + + To ensure logs are sent to a remote host, examine the file +/etc/rsyslog.conf. +If using UDP, a line similar to the following should be present: + *.* @ +If using TCP, a line similar to the following should be present: + *.* @@ +If using RELP, a line similar to the following should be present: + *.* :omrelp: + Is it the case that no evidence that the audit logs are being off-loaded to another system or media? + + + + To find SUID files, run the following command: +$ sudo find / -xdev -type f -perm -4000 + Is it the case that only authorized files appear in the output of the find command? + + + + To check the ownership of /var/log/syslog, +run the command: +$ ls -lL /var/log/syslog +If properly configured, the output should indicate the following owner: +syslog + Is it the case that /var/log/syslog does not have an owner of syslog? + + + + To check the group ownership of /etc/gshadow, +run the command: +$ ls -lL /etc/gshadow +If properly configured, the output should indicate the following group-owner: +root + Is it the case that /etc/gshadow does not have a group owner of root? + + + + To verify that null passwords cannot be used, run the following command: + +$ grep nullok /etc/pam.d/system-auth /etc/pam.d/password-auth + +If this produces any output, it may be possible to log into accounts +with empty passwords. Remove any instances of the nullok option to +prevent logins with empty passwords. + Is it the case that NULL passwords can be used? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "reboot" command with the following command: + +$ sudo auditctl -l | grep reboot + +-a always,exit -F path=/reboot -F perm=x -F auid>=1000 -F auid!=unset -k privileged-reboot + Is it the case that the command does not return a line, or the line is commented out? + + + + To check the group ownership of /var/log/syslog, +run the command: +$ ls -lL /var/log/syslog +If properly configured, the output should indicate the following group-owner: +adm + Is it the case that /var/log/syslog does not have a group owner of adm? + + + + To verify that all user initialization files have a mode of 0740 or +less permissive, run the following command: +$ sudo find /home -type f -name '\.*' \( -perm -0002 -o -perm -0020 \) +There should be no output. + Is it the case that they are not 0740 or more permissive? + + + + To determine if the system is configured to audit calls to the +clock_settime system call, run the following command: +$ sudo grep "clock_settime" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. + + Is it the case that no line is returned? + + + + Inspect the form of default GRUB 2 command line for the Linux operating system +in /etc/default/grub. If it includes slab_nomerge=yes, +then the parameter will be configured for newly installed kernels. +First check if the GRUB recovery is enabled: +$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub +If this option is set to true, then check that a line is output by the following command: +$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*slab_nomerge=yes.*' /etc/default/grub +If the recovery is disabled, check the line with +$ sudo grep 'GRUB_CMDLINE_LINUX.*slab_nomerge=yes.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. +Run the following command: +$ sudo grubby --info=ALL | grep args | grep -v 'slab_nomerge=yes' +The command should not return any output. + Is it the case that merging of slabs with similar size is enabled? + + + + To verify if the OpenSSH client uses defined Cipher suite in the Crypto Policy, run: +$ grep -i ciphers /etc/crypto-policies/back-ends/openssh.config +and verify that the line matches: +Ciphers + Is it the case that Crypto Policy for OpenSSH client is not configured correctly? + + + + First, check whether the password is defined in either /boot/grub2/user.cfg or +/boot/grub2/grub.cfg. +Run the following commands: +$ sudo grep '^[\s]*GRUB2_PASSWORD=grub\.pbkdf2\.sha512.*$' /boot/grub2/user.cfg +$ sudo grep '^[\s]*password_pbkdf2[\s]+.*[\s]+grub\.pbkdf2\.sha512.*$' /boot/grub2/grub.cfg + + +Second, check that a superuser is defined in /boot/grub2/grub.cfg. +$ sudo grep '^[\s]*set[\s]+superusers=("?)[a-zA-Z_]+\1$' /boot/grub2/grub.cfg + Is it the case that it does not produce any output? + + + + To check the permissions of /var/log/syslog, +run the command: +$ ls -l /var/log/syslog +If properly configured, the output should indicate the following permissions: +-rw-r----- + Is it the case that /var/log/syslog does not have unix mode -rw-r-----? + + + + To check the group ownership of /etc/cron.allow, +run the command: +$ ls -lL /etc/cron.allow +If properly configured, the output should indicate the following group-owner: +root + Is it the case that /etc/cron.allow does not have a group owner of root? + + + + To verify that only security updates will be automatically installed by dnf-automatic, run the following command: +$ sudo grep upgrade_type /etc/dnf/automatic.conf +The output should return the following: +upgrade_type = security + Is it the case that the upgrade_type is not set to security? + + + + The runtime status of the net.core.bpf_jit_harden kernel parameter can be queried +by running the following command: +$ sysctl net.core.bpf_jit_harden +2. + + Is it the case that the correct value is not returned? + + + + Run the following command to see what the timeout interval is: +$ sudo grep ClientAliveInterval /etc/ssh/sshd_config +If properly configured, the output should be: +ClientAliveInterval + Is it the case that it is commented out or not configured properly? + + + + To check the ownership of /etc/passwd-, +run the command: +$ ls -lL /etc/passwd- +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/passwd- does not have an owner of root? + + + + To determine if the system is configured to audit calls to the +removexattr system call, run the following command: +$ sudo grep "removexattr" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. + + Is it the case that no line is returned? + + + + The file permissions for all log files written by rsyslog should +be set to 640, or more restrictive. These log files are determined by the +second part of each Rule line in /etc/rsyslog.conf and typically +all appear in /var/log. To see the permissions of a given log +file, run the following command: +$ ls -l LOGFILE +The permissions should be 640, or more restrictive. + Is it the case that the permissions are not correct? + + + + Verify the "umask" setting is configured correctly in the "/etc/csh.cshrc" file with the following command: + +$ grep umask /etc/csh.cshrc + +umask 077 +umask 077 + Is it the case that the value for the "umask" parameter is not "<sub idref="var_accounts_user_umask" />", or the "umask" parameter is missing or is commented out? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_BINFMT_MISC /boot/config.* + + Configs with value 'n' are not explicitly set in the file, so either commented lines or no + lines should be returned. + + Is it the case that the kernel was not built with the required value? + + + + Run the following command to ensure that /tmp is configured as a +polyinstantiated directory: +$ sudo grep /tmp /etc/security/namespace.conf +The output should return the following: +/tmp /tmp/tmp-inst/ level root,adm + Is it the case that is not configured? + + + + To check the group ownership of /etc/ipsec.secrets, +run the command: +$ ls -lL /etc/ipsec.secrets +If properly configured, the output should indicate the following group-owner: +root + Is it the case that /etc/ipsec.secrets does not have a group owner of root? + + + + To verify that the system will shutdown when auditd fails, +run the following command: +$ sudo grep "\-f " /etc/audit/audit.rules +The output should contain: +-f + Is it the case that the system is not configured to shutdown on auditd failures? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_STRICT_KERNEL_WRX /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_RETPOLINE /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + Inspect the password section of /etc/pam.d/password-auth +and ensure that the pam_unix.so module is configured to use the argument +: + +$ grep /etc/pam.d/password-auth + Is it the case that it does not? + + + + Verify the system-wide shared library files are owned by "root" with the following command: + +$ sudo find -L /lib /lib64 /usr/lib /usr/lib64 ! -user root -exec ls -l {} \; + Is it the case that any system wide shared library file is not owned by root? + + + + To verify that smart cards are enabled in SSSD, run the following command: +$ sudo grep pam_cert_auth /etc/sssd/sssd.conf +If configured properly, output should be +pam_cert_auth = True + + +To verify that smart cards are enabled in PAM files, run the following command: +$ sudo grep -e "auth.*pam_sss\.so.*\(allow_missing_name\|try_cert_auth\)" /etc/pam.d/smartcard-auth /etc/pam.d/system-auth +If configured properly, output should be + +/etc/pam.d/smartcard-auth:auth sufficient pam_sss.so allow_missing_name +/etc/pam.d/system-auth:auth [success=done authinfo_unavail=ignore ignore=ignore default=die] pam_sss.so try_cert_auth + + Is it the case that smart cards are not enabled in SSSD? + + + + + +Run the following command to determine the current status of the +ufw service: +$ sudo systemctl is-active ufw +If the service is running, it should return the following: active + Is it the case that the service is not enabled? + + + + Run the following command to check the mode of the system audit logs: +$ sudo grep -iw log_file /etc/audit/auditd.conf +log_file=/var/log/audit/audit.log +$ sudo stat -c "%n %a" /var/log/audit/* +$ sudo ls -l /var/log/audit +Audit logs must be mode 0640 or less permissive. + Is it the case that any permissions are more permissive? + + + + Verify that a separate file system/partition has been created for /var/tmp with the following command: + +$ mountpoint /var/tmp + + Is it the case that "/var/tmp is not a mountpoint" is returned? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "pam_timestamp_check" command with the following command: + +$ sudo auditctl -l | grep pam_timestamp_check + +-a always,exit -F path=/usr/sbin/pam_timestamp_check -F perm=x -F auid>=1000 -F auid!=unset -k privileged-pam_timestamp_check + Is it the case that the command does not return a line, or the line is commented out? + + + + To determine if the system is configured to audit calls to the +unlinkat system call, run the following command: +$ sudo grep "unlinkat" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. + + Is it the case that no line is returned? + + + + + + +To determine if firewalld is configured to allow access + +on port 22/tcp, run the following command(s): + firewall-cmd --list-ports + + +to ssh + firewall-cmd --list-services + +If firewalld is configured to allow access through the firewall, something similar to the following will be output: + +If it is a service: +ssh + + +If it is a port: +22/tcp + + Is it the case that sshd service is not enabled in the proper firewalld zone? + + + + To find world-writable files, run the following command: +$ sudo find / -xdev -type f -perm -002 + Is it the case that there is output? + + + + The runtime status of the net.ipv4.conf.all.arp_ignore kernel parameter can be queried +by running the following command: +$ sysctl net.ipv4.conf.all.arp_ignore +. + + Is it the case that the correct value is not returned? + + + + To verify that Audit Daemon is configured to resolve all uid, gid, syscall, +architecture, and socket address information before writing the event to disk, +run the following command: +$ sudo grep log_format /etc/audit/auditd.conf +The output should return the following: +log_format = ENRICHED + Is it the case that log_format isn't set to ENRICHED? + + + + To check that the screen locks immediately when activated, run the following command: +$ gsettings get org.gnome.desktop.screensaver lock-delay +If properly configured, the output should be 'uint32 '. + Is it the case that the screensaver lock delay is missing, or is set to a value greater than <sub idref="var_screensaver_lock_delay" />? + + + + The runtime status of the kernel.dmesg_restrict kernel parameter can be queried +by running the following command: +$ sysctl kernel.dmesg_restrict +1. + + Is it the case that the correct value is not returned? + + + + The runtime status of the net.ipv6.conf.default.accept_ra kernel parameter can be queried +by running the following command: +$ sysctl net.ipv6.conf.default.accept_ra +0. + + Is it the case that the correct value is not returned? + + + + Verify that Oracle Linux 9 enforces password complexity by requiring that at least one upper-case character. + +Check the value for "ucredit" with the following command: + +$ sudo grep ucredit /etc/security/pwquality.conf /etc/security/pwquality.conf.d/*.conf + +ucredit = -1 + Is it the case that the value of "ucredit" is a positive number or is commented out? + + + + Verify that a separate file system/partition has been created for /var/log/audit with the following command: + +$ mountpoint /var/log/audit + + Is it the case that "/var/log/audit is not a mountpoint" is returned? + + + + The runtime status of the fs.protected_hardlinks kernel parameter can be queried +by running the following command: +$ sysctl fs.protected_hardlinks +1. + + Is it the case that the correct value is not returned? + + + + Verify that yum verifies the signature of local packages prior to install with the following command: + +$ grep localpkg_gpgcheck /etc/yum.conf + +localpkg_gpgcheck=1 + +If "localpkg_gpgcheck" is not set to "1", or if the option is missing or commented out, ask the System Administrator how the certificates for patches and other operating system components are verified. + Is it the case that there is no process to validate certificates for local packages that is approved by the organization? + + + + + +Run the following command to determine the current status of the +usbguard service: +$ sudo systemctl is-active usbguard +If the service is running, it should return the following: active + Is it the case that the service is not enabled? + + + + To determine if the system is configured to audit changes to its SELinux +configuration files, run the following command: +$ sudo auditctl -l | grep "dir=/usr/share/selinux" +If the system is configured to watch for changes to its SELinux +configuration, a line should be returned (including +perm=wa indicating permissions that are watched). + Is it the case that the system is not configured to audit attempts to change the MAC policy? + + + + +Check if SSSD allows cached authentications with the following command: + +$ sudo grep cache_credentials /etc/sssd/sssd.conf +cache_credentials = true + +If "cache_credentials" is set to "false" or is missing no further checks are required. + +To verify that SSSD expires offline credentials, run the following command: +$ sudo grep offline_credentials_expiration /etc/sssd/sssd.conf /etc/sssd/conf.d/*.conf +If configured properly, output should be +offline_credentials_expiration = 1 + Is it the case that it does not exist or is not configured properly? + + + + To verify the number of rounds for the password hashing algorithm is configured, run the following command: +$ sudo grep rounds /etc/pam.d/system-auth +The output should show the following match: +password sufficient pam_unix.so sha512 rounds= + Is it the case that rounds is not set to <sub idref="var_password_pam_unix_rounds" /> or is commented out? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_DEBUG_CREDENTIALS /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + The following command will list which files on the system have ownership different from what +is expected by the RPM database: +$ rpm -Va | rpm -Va --nofiledigest | awk '{ if (substr($0,6,1)=="U" || substr($0,7,1)=="G") print $NF }' + Is it the case that there is output? + + + + To check that the snmpd service is disabled in system boot configuration, +run the following command: +$ sudo systemctl is-enabled snmpd +Output should indicate the snmpd service has either not been installed, +or has been disabled at all runlevels, as shown in the example below: +$ sudo systemctl is-enabled snmpd disabled + +Run the following command to verify snmpd is not active (i.e. not running) through current runtime configuration: +$ sudo systemctl is-active snmpd + +If the service is not running the command will return the following output: +inactive + +The service will also be masked, to check that the snmpd is masked, run the following command: +$ sudo systemctl show snmpd | grep "LoadState\|UnitFileState" + +If the service is masked the command will return the following outputs: + +LoadState=masked + +UnitFileState=masked + Is it the case that the "snmpd" is loaded and not masked? + + + + The following command will list which files on the system have file hashes different from what +is expected by the RPM database. +$ rpm -Va --noconfig | awk '$1 ~ /..5/' + Is it the case that there is output? + + + + To check the group ownership of /etc/ssh/sshd_config, +run the command: +$ ls -lL /etc/ssh/sshd_config +If properly configured, the output should indicate the following group-owner: +root + Is it the case that /etc/ssh/sshd_config does not have a group owner of root? + + + + Run the following command to determine if the crypto-policies package is installed: $ rpm -q crypto-policies + Is it the case that the package is not installed? + + + + Make sure that the kernel is not disabling SMEP with the following +commands. +grep -q nosmep /boot/config-`uname -r` +If the command returns a line, it means that SMEP is being disabled. + Is it the case that the kernel is configured to disable SMEP? + + + + Run the following command to determine if the audispd-plugins package is installed: $ rpm -q audispd-plugins + Is it the case that the package is not installed? + + + + Inspect the form of default GRUB 2 command line for the Linux operating system +in /etc/default/grub. If it includes slub_debug=, +then the parameter will be configured for newly installed kernels. +First check if the GRUB recovery is enabled: +$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub +If this option is set to true, then check that a line is output by the following command: +$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*slub_debug=.*' /etc/default/grub +If the recovery is disabled, check the line with +$ sudo grep 'GRUB_CMDLINE_LINUX.*slub_debug=.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. +Run the following command: +$ sudo grubby --info=ALL | grep args | grep -v 'slub_debug=' +The command should not return any output. + Is it the case that SLUB/SLAB poisoning is not enabled? + + + + To check the group ownership of /etc/shadow-, +run the command: +$ ls -lL /etc/shadow- +If properly configured, the output should indicate the following group-owner: +root + Is it the case that /etc/shadow- does not have a group owner of root? + + + + Verify the operating system encrypts audit records off-loaded onto a different system +or media from the system being audited with the following commands: + +$ sudo grep -i '$ActionSendStreamDriverMode' /etc/rsyslog.conf /etc/rsyslog.d/*.conf + +The output should be: + +/etc/rsyslog.conf:$ActionSendStreamDriverMode 1 + Is it the case that rsyslogd ActionSendStreamDriverMode is not set to 1? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_VMAP_STACK /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To check the group ownership of /var/log, +run the command: +$ ls -lL /var/log +If properly configured, the output should indicate the following group-owner: +root + Is it the case that /var/log does not have a group owner of root? + + + + To verify if the OpenSSH Client uses defined Crypto Policy, run: +$ cat /etc/ssh/ssh_config.d/02-ospp.conf +and verify that the line matches +Match final all +RekeyLimit 512M 1h +GSSAPIAuthentication no +Ciphers aes256-ctr,aes256-cbc,aes128-ctr,aes128-cbc +PubkeyAcceptedKeyTypes ssh-rsa,ecdsa-sha2-nistp384,ecdsa-sha2-nistp256 +MACs hmac-sha2-512,hmac-sha2-256 +KexAlgorithms ecdh-sha2-nistp521,ecdh-sha2-nistp384,ecdh-sha2-nistp256,diffie-hellman-group14-sha1 + Is it the case that Crypto Policy for OpenSSH Client is not configured according to CC requirements? + + + + To check the permissions of /etc/gshadow-, +run the command: +$ ls -l /etc/gshadow- +If properly configured, the output should indicate the following permissions: +---------- + Is it the case that /etc/gshadow- does not have unix mode ----------? + + + + To verify all squashing has been disabled, run the following command: +$ grep all_squash /etc/exports + Is it the case that there is output? + + + + Verify the pam_faillock.so module is present in the "/etc/pam.d/system-auth" file: + +$ sudo grep pam_faillock.so /etc/pam.d/system-auth + +auth required pam_faillock.so preauth +auth required pam_faillock.so authfail +account required pam_faillock.so + Is it the case that the pam_faillock.so module is not present in the "/etc/pam.d/system-auth" file with the "preauth" line listed before pam_unix.so? + + + + To determine how the SSH daemon's GSSAPIAuthentication option is set, run the following command: + +$ sudo grep -i GSSAPIAuthentication /etc/ssh/sshd_config + +If a line indicating no is returned, then the required value is set. + + Is it the case that the required value is not set? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_SYN_COOKIES /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To check the ownership of /etc/group-, +run the command: +$ ls -lL /etc/group- +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/group- does not have an owner of root? + + + + To verify that Audit Daemon is configured to record the computer node +name in the audit events, run the following command: +$ sudo grep name_format /etc/audit/auditd.conf +The output should return the following: +name_format = + Is it the case that name_format isn't set to <sub idref="var_auditd_name_format" />? + + + + To check that the telnet service is disabled in system boot configuration with xinetd, run the following command: $ chkconfig telnet --list Output should indicate the telnet service has either not been installed, or has been disabled, as shown in the example below: @@ -234963,47 +256650,789 @@ LoadState=masked UnitFileState=masked Is it the case that service and/or socket are running? - - - - Run the following command to determine if the tftp-server package is installed: -$ rpm -q tftp-server - Is it the case that the package is installed? - - - - The tftp package can be removed with the following command: $ sudo yum erase tftp + + + + To check the permissions of /etc/selinux, +run the command: +$ ls -l /etc/selinux +If properly configured, the output should indicate the following permissions: +0755 + Is it the case that /etc/selinux does not have unix mode 0755? + + + + The runtime status of the kernel.perf_event_paranoid kernel parameter can be queried +by running the following command: +$ sysctl kernel.perf_event_paranoid +2. + + Is it the case that the correct value is not returned? + + + + To determine if the system is configured to audit calls to the +lremovexattr system call, run the following command: +$ sudo grep "lremovexattr" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. + + Is it the case that no line is returned? + + + + To determine how the SSH daemon's Banner option is set, run the following command: + +$ sudo grep -i Banner /etc/ssh/sshd_config + +If a line indicating /etc/issue is returned, then the required value is set. + + Is it the case that the required value is not set? + + + + Verify the audit tools are owned by "root" to prevent any unauthorized access, deletion, or modification. + +Check the owner of each audit tool by running the following command: + +$ sudo stat -c "%U %n" /sbin/auditctl /sbin/aureport /sbin/ausearch /sbin/autrace /sbin/auditd /sbin/rsyslogd /sbin/augenrules + +root /sbin/auditctl +root /sbin/aureport +root /sbin/ausearch +root /sbin/autrace +root /sbin/auditd +root /sbin/rsyslogd +root /sbin/augenrules + Is it the case that any audit tools are not owned by root? + + + + To determine if the system is configured to audit calls to the +unlink system call, run the following command: +$ sudo grep "unlink" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. + + Is it the case that no line is returned? + + + + Display the contents of the file /etc/systemd/logind.conf: +cat /etc/systemd/logind.conf +Ensure that there is a section [login] which contains the +configuration StopIdleSessionSec=. + Is it the case that the option is not configured? + + + + Verify Oracle Linux 9 takes the appropriate action when an audit processing failure occurs. + +Check that Oracle Linux 9 takes the appropriate action when an audit processing failure occurs with the following command: + +$ sudo grep disk_error_action /etc/audit/auditd.conf + +disk_error_action = + +If the value of the "disk_error_action" option is not "SYSLOG", "SINGLE", or "HALT", or the line is commented out, ask the system administrator to indicate how the system takes appropriate action when an audit process failure occurs. + Is it the case that there is no evidence of appropriate action? + + + + To ensure screen locking on smartcard removal is enabled, run the following command: +$ grep removal-action /etc/dconf/db/local.d/* +The output should be 'lock-screen'. +To ensure that users cannot disable screen locking on smartcard removal, run the following: +$ grep removal-action /etc/dconf/db/local.d/locks/* +If properly configured, the output should be /org/gnome/settings-daemon/peripherals/smartcard/removal-action + Is it the case that removal-action has not been configured? + + + + To determine if the system is configured to audit changes to its SELinux +configuration files, run the following command: +$ sudo auditctl -l | grep "dir=/etc/selinux" +If the system is configured to watch for changes to its SELinux +configuration, a line should be returned (including +perm=wa indicating permissions that are watched). + Is it the case that the system is not configured to audit attempts to change the MAC policy? + + + + To check the permissions of /etc/ipsec.secrets, +run the command: +$ ls -l /etc/ipsec.secrets +If properly configured, the output should indicate the following permissions: +0644 + Is it the case that /etc/ipsec.secrets does not have unix mode 0644? + + + + The runtime status of the net.ipv6.conf.default.accept_redirects kernel parameter can be queried +by running the following command: +$ sysctl net.ipv6.conf.default.accept_redirects +0. + + Is it the case that the correct value is not returned? + + + + To determine how the SSH daemon's PermitRootLogin option is set, run the following command: + +$ sudo grep -i PermitRootLogin /etc/ssh/sshd_config + +If a line indicating no is returned, then the required value is set. + + Is it the case that the required value is not set? + + + + To check the group ownership of /etc/ssh/*.pub, +run the command: +$ ls -lL /etc/ssh/*.pub +If properly configured, the output should indicate the following group-owner: +root + Is it the case that /etc/ssh/*.pub does not have a group owner of root? + + + + To verify that the Audit is correctly configured according to recommended rules, check the content of the file with the following command: +cat /etc/audit/rules.d/30-ospp-v42-3-access-failed.rules +The output has to be exactly as follows: +## Unsuccessful file access (any other opens) This has to go last. +-a always,exit -F arch=b32 -S open,openat,openat2,open_by_handle_at -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-access +-a always,exit -F arch=b64 -S open,openat,openat2,open_by_handle_at -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-access +-a always,exit -F arch=b32 -S open,openat,openat2,open_by_handle_at -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-access +-a always,exit -F arch=b64 -S open,openat,openat2,open_by_handle_at -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-access + Is it the case that the file does not exist or the content differs? + + + + Verify the noexec option is configured for the /var mount point, + run the following command: + $ sudo mount | grep '\s/var\s' + . . . /var . . . noexec . . . + + Is it the case that the "/var" file system does not have the "noexec" option set? + + + + The telnet package can be removed with the following command: $ sudo yum erase telnet Is it the case that ? - - - - Verify the TFTP daemon is configured to operate in secure mode. + + + + To determine how the SSH daemon's LogLevel option is set, run the following command: -Check if a TFTP server is installed with the following command: +$ sudo grep -i LogLevel /etc/ssh/sshd_config -$ sudo dnf list --installed tftp-server +If a line indicating VERBOSE is returned, then the required value is set. -tftp-server.x86_64 5.2-35.el9.x86_64 + Is it the case that the required value is not set? + + + + The runtime status of the net.ipv6.conf.default.router_solicitations kernel parameter can be queried +by running the following command: +$ sysctl net.ipv6.conf.default.router_solicitations +0. + Is it the case that the correct value is not returned? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_STRICT_MODULE_RWX /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + Check whether the maximum time period for root account password is restricted to days with the following commands: -If a TFTP server is not installed, this is Not Applicable. +$ sudo awk -F: '$1 == "root" {print $1 " " $5}' /etc/shadow + Is it the case that any results are returned that are not associated with a system account? + + + + The runtime status of the net.ipv6.conf.all.accept_ra_defrtr kernel parameter can be queried +by running the following command: +$ sysctl net.ipv6.conf.all.accept_ra_defrtr +0. + Is it the case that the correct value is not returned? + + + + To determine how the SSH daemon's AllowTcpForwarding option is set, run the following command: -If a TFTP server is installed, check for the server arguments with the following command: +$ sudo grep -i AllowTcpForwarding /etc/ssh/sshd_config -$ systemctl cat tftp | grep ExecStart= -ExecStart=/usr/sbin/in.tftpd -s - Is it the case that 'the "ExecStart" line does not have a "-s" option, and a subdirectory is not assigned'? - - - - Run the following command to determine if the squid package is installed: -$ rpm -q squid +If a line indicating no is returned, then the required value is set. + Is it the case that The AllowTcpForwarding option exists and is disabled? + + + + To check the ownership of /etc/ssh/*_key, +run the command: +$ ls -lL /etc/ssh/*_key +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/ssh/*_key does not have an owner of root? + + + + Verify Oracle Linux 9 for PKI-based authentication has valid certificates by constructing a +certification path (which includes status information) to an accepted trust anchor. + +Check that the system has a valid DoD root CA installed with the following command: + +$ sudo openssl x509 -text -in /etc/sssd/pki/sssd_auth_ca_db.pem + +Certificate: +Data: +Version: 3 (0x2) +Serial Number: 1 (0x1) +Signature Algorithm: sha256WithRSAEncryption +Issuer: C = US, O = U.S. Government, OU = DoD, OU = PKI, CN = DoD Root CA 3 +Validity +Not Before: Mar 20 18:46:41 2012 GMT +Not After : Dec 30 18:46:41 2029 GMT +Subject: C = US, O = U.S. Government, OU = DoD, OU = PKI, CN = DoD Root CA 3 +Subject Public Key Info: +Public Key Algorithm: rsaEncryption + Is it the case that root CA file is not a DoD-issued certificate with a valid date and installed in the /etc/sssd/pki/sssd_auth_ca_db.pem location? + + + + Verify the value of the "maxrepeat" option in "/etc/security/pwquality.conf" with the following command: + +$ grep maxrepeat /etc/security/pwquality.conf + +maxrepeat = + Is it the case that the value of "maxrepeat" is set to more than "<sub idref="var_password_pam_maxrepeat" />" or is commented out? + + + + To determine if use_pty has been configured for sudo, run the following command: +$ sudo grep -ri "^[\s]*Defaults.*\buse_pty\b.*" /etc/sudoers /etc/sudoers.d/ +The command should return a matching output. + Is it the case that use_pty is not enabled in sudo? + + + + +Run the following command to get the current configured value for secure_mode_insmod +SELinux boolean: +$ getsebool secure_mode_insmod +The expected cofiguration is . +"on" means true, and "off" means false + Is it the case that secure_mode_insmod is not set as expected? + + + + To verify that the Audit is correctly configured according to recommended rules, check the content of the file with the following command: +cat /etc/audit/rules.d/43-module-load.rules +The output has to be exactly as follows: +## These rules watch for kernel module insertion. By monitoring +## the syscall, we do not need any watches on programs. +-a always,exit -F arch=b32 -S init_module,finit_module -F key=module-load +-a always,exit -F arch=b64 -S init_module,finit_module -F key=module-load +-a always,exit -F arch=b32 -S delete_module -F key=module-unload +-a always,exit -F arch=b64 -S delete_module -F key=module-unload + Is it the case that the file does not exist or the content differs? + + + + To check the permissions of /etc/ssh/*_key, +run the command: +$ ls -l /etc/ssh/*_key +If properly configured, the output should indicate the following permissions: +-rw------- + Is it the case that /etc/ssh/*_key does not have unix mode -rw-------? + + + + Find the list of alias maps used by the Postfix mail server: +$ sudo postconf alias_maps +Query the Postfix alias maps for an alias for the root user: +$ sudo postmap -q root hash:/etc/aliases +The output should return an alias. + Is it the case that the alias is not set? + + + + To check the group ownership of /etc/cron.d, +run the command: +$ ls -lL /etc/cron.d +If properly configured, the output should indicate the following group-owner: +root + Is it the case that /etc/cron.d does not have a group owner of root? + + + + Verify that the system is integrated with a centralized authentication mechanism +such as as Active Directory, Kerberos, Directory Server, etc. that has +automated account mechanisms in place. + Is it the case that the system is not using a centralized authentication mechanism, or it is not automated? + + + + To check the permissions of /etc/cron.allow, +run the command: +$ ls -l /etc/cron.allow +If properly configured, the output should indicate the following permissions: +-rw-r----- + Is it the case that /etc/cron.allow does not have unix mode -rw-r-----? + + + + To determine if the users are allowed to run commands as root, run the following commands: +$ sudo grep -PR '^\s*((?!root\b)[\w]+)\s*(\w+)\s*=\s*(.*,)?\s*[^\(\s]' /etc/sudoers /etc/sudoers.d/ +and +$ sudo grep -PR '^\s*((?!root\b)[\w]+)\s*(\w+)\s*=\s*(.*,)?\s*\([\w\s]*\b(root|ALL)\b[\w\s]*\)' /etc/sudoers /etc/sudoers.d/ +Both commands should return no output. + Is it the case that /etc/sudoers file contains rules that allow non-root users to run commands as root? + + + + Verify Oracle Linux 9 takes the appropriate action when the audit storage volume is full. + +Check that Oracle Linux 9 takes the appropriate action when the audit storage volume is full with the following command: + +$ sudo grep disk_full_action /etc/audit/auditd.conf + +disk_full_action = + +If the value of the "disk_full_action" option is not "SYSLOG", "SINGLE", or "HALT", or the line is commented out, ask the system administrator to indicate how the system takes appropriate action when an audit storage volume is full. + Is it the case that there is no evidence of appropriate action? + + + + The runtime status of the net.ipv6.conf.default.accept_source_route kernel parameter can be queried +by running the following command: +$ sysctl net.ipv6.conf.default.accept_source_route +0. + + Is it the case that the correct value is not returned? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "mount" command with the following command: + +$ sudo auditctl -l | grep mount + +-a always,exit -F path=/usr/bin/mount -F perm=x -F auid>=1000 -F auid!=unset -k privileged-mount + Is it the case that the command does not return a line, or the line is commented out? + + + + Run the following command to determine if the policycoreutils package is installed: $ rpm -q policycoreutils + Is it the case that the policycoreutils package is not installed? + + + + To check if the installed Operating System is 64-bit, run the following command: +$ uname -m +The output should be one of the following: x86_64, aarch64, ppc64le or s390x. +If the output is i686 or i386 the operating system is 32-bit. +Check if the installed CPU supports 64-bit operating systems by running the following command: +$ lscpu | grep "CPU op-mode" +If the output contains 64bit, the CPU supports 64-bit operating systems. + Is it the case that the installed operating sytem is 32-bit but the CPU supports operation in 64-bit? + + + + To determine that periodic AIDE execution has been scheduled, run the following command: + +$ grep aide /etc/crontab +The output should return something similar to the following: +05 4 * * * root /usr/sbin/aide --check | /bin/mail -s "$(hostname) - AIDE Integrity Check" root@localhost +The email address that the notifications are sent to can be changed by overriding +. + Is it the case that AIDE has not been configured or has not been configured to notify personnel of scan details? + + + + To check if the system login banner is compliant, run the following command: +$ cat /etc/issue.net + Is it the case that it does not display the required banner? + + + + Find the list of alias maps used by the Postfix mail server: +$ sudo postconf alias_maps +Query the Postfix alias maps for an alias for the postmaster user: +$ sudo postmap -q postmaster hash:/etc/aliases +The output should return root. + Is it the case that the alias is not set or is not root? + + + + Run the following command to determine if the chrony package is installed: $ rpm -q chrony + Is it the case that the package is not installed? + + + + The runtime status of the kernel.pid_max kernel parameter can be queried +by running the following command: +$ sysctl kernel.pid_max +65536. + + Is it the case that the correct value is not returned? + + + + To check the permissions of /var/log, +run the command: +$ ls -l /var/log +If properly configured, the output should indicate the following permissions: +drwxr-xr-x + Is it the case that /var/log does not have unix mode drwxr-xr-x? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_GCC_PLUGIN_STACKLEAK /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To verify that FIPS mode is enabled properly, run the following command: +cat /proc/sys/crypto/fips_enabled +The output be must: +1 + Is it the case that FIPS mode is not enabled? + + + + To verify that null passwords cannot be used, run the following command: +$ sudo awk -F: '!$2 {print $1}' /etc/shadow +If this produces any output, it may be possible to log into accounts +with empty passwords. + Is it the case that Blank or NULL passwords can be used? + + + + The following command will locate the mount points related to local devices: +$ findmnt -n -l -k -it $(awk '/nodev/ { print $2 }' /proc/filesystems | paste -sd,) + +The following command will show files which do not belong to a valid user: +$ sudo find MOUNTPOINT -xdev -nouser 2>/dev/null + +Replace MOUNTPOINT by the mount points listed by the fist command. + +No files without a valid user should be located. + Is it the case that files exist that are not owned by a valid user? + + + + Run the following command to determine if the usbguard package is installed: $ rpm -q usbguard + Is it the case that the package is not installed? + + + + To determine if NOEXEC has been configured for sudo, run the following command: +$ sudo grep -ri "^[\s]*Defaults.*\bnoexec\b.*" /etc/sudoers /etc/sudoers.d/ +The command should return a matching output. + Is it the case that noexec is not enabled in sudo? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "postqueue" command with the following command: + +$ sudo auditctl -l | grep postqueue + +-a always,exit -F path=/usr/bin/postqueue -F perm=x -F auid>=1000 -F auid!=unset -k privileged-postqueue + Is it the case that the command does not return a line, or the line is commented out? + + + + Run the following command to determine if the scap-security-guide package is installed: $ rpm -q scap-security-guide + Is it the case that the package is not installed? + + + + The runtime status of the kernel.core_pattern kernel parameter can be queried +by running the following command: +$ sysctl kernel.core_pattern | cat -A +kernel.core_pattern = $ + + Is it the case that the returned line does not have an empty string? + + + + The runtime status of the kernel.perf_cpu_time_max_percent kernel parameter can be queried +by running the following command: +$ sysctl kernel.perf_cpu_time_max_percent +1. + + Is it the case that the correct value is not returned? + + + + To verify the boot loader superuser account has been set, run the following +command: +sudo grep -A1 "superusers" /boot/grub2/grub.cfg +The output should show the following: +set superusers="superusers-account" +export superusers +where superusers-account is the actual account name different from common names like root, +admin, or administrator and different from any other existing user name. + Is it the case that superuser account is not set or is set to root, admin, administrator or any other existing user name? + + + + To verify that the Audit is correctly configured according to recommended rules, check the content of the file with the following command: +cat /etc/audit/rules.d/30-ospp-v42-4-delete-failed.rules +The output has to be exactly as follows: +## Unsuccessful file delete +-a always,exit -F arch=b32 -S unlink,unlinkat,rename,renameat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-delete +-a always,exit -F arch=b64 -S unlink,unlinkat,rename,renameat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-delete +-a always,exit -F arch=b32 -S unlink,unlinkat,rename,renameat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-delete +-a always,exit -F arch=b64 -S unlink,unlinkat,rename,renameat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-delete + Is it the case that the file does not exist or the content differs? + + + + To check if pam_pwquality.so is enabled in password-auth, run the following command: +$ grep pam_pwquality /etc/pam.d/password-auth +The output should be similar to the following: +password requisite pam_pwquality.so + Is it the case that pam_pwquality.so is not enabled in password-auth? + + + + To determine if arguments that commands can be executed with are restricted, run the following command: +$ sudo grep -PR '^(?:\s*[^#=]+)=(?:\s*(?:\([^\)]+\))?\s*(?!\s*\()[^,\s]+(?:[ \t]+[^,\s]+)+[ \t]*,)*(\s*(?:\([^\)]+\))?\s*(?!\s*\()[^,\s]+[ \t]*(?:,|$))' /etc/sudoers /etc/sudoers.d/ +The command should return no output. + Is it the case that /etc/sudoers file contains user specifications that allow execution of commands with any arguments? + + + + To check that the avahi-daemon service is disabled in system boot configuration, +run the following command: +$ sudo systemctl is-enabled avahi-daemon +Output should indicate the avahi-daemon service has either not been installed, +or has been disabled at all runlevels, as shown in the example below: +$ sudo systemctl is-enabled avahi-daemon disabled + +Run the following command to verify avahi-daemon is not active (i.e. not running) through current runtime configuration: +$ sudo systemctl is-active avahi-daemon + +If the service is not running the command will return the following output: +inactive + +The service will also be masked, to check that the avahi-daemon is masked, run the following command: +$ sudo systemctl show avahi-daemon | grep "LoadState\|UnitFileState" + +If the service is masked the command will return the following outputs: + +LoadState=masked + +UnitFileState=masked + Is it the case that the "avahi-daemon" is loaded and not masked? + + + + Run the following command to check if the group exists: +grep /etc/group +The output should contain the following line: +:x: + Is it the case that group exists and has no user members? + + + + The runtime status of the kernel.core_pattern kernel parameter can be queried +by running the following command: +$ sysctl kernel.core_pattern +|/bin/false. + + Is it the case that the returned line does not have a value of "|/bin/false", or a line is not +returned and the need for core dumps is not documented with the Information +System Security Officer (ISSO) as an operational requirement? + + + + Verify Oracle Linux 9 generates audit records for all account creations, modifications, disabling, and termination events that affect "/etc/gshadow" with the following command: + +$ sudo auditctl -l | grep -E '(/etc/gshadow)' + +-w /etc/gshadow -p wa -k identity + +If the command does not return a line, or the line is commented out, this is a finding. + Is it the case that the system is not configured to audit account changes? + + + + To determine how the SSH daemon's X11UseLocalhost option is set, run the following command: + +$ sudo grep -i X11UseLocalhost /etc/ssh/sshd_config + +If a line indicating yes is returned, then the required value is set. + Is it the case that the display proxy is listening on wildcard address? + + + + Verify the noexec option is configured for the /dev/shm mount point, + run the following command: + $ sudo mount | grep '\s/dev/shm\s' + . . . /dev/shm . . . noexec . . . + + Is it the case that the "/dev/shm" file system does not have the "noexec" option set? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_PANIC_TIMEOUT /boot/config.* + + For each kernel installed, a line with value "" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + The runtime status of the net.ipv6.conf.default.max_addresses kernel parameter can be queried +by running the following command: +$ sysctl net.ipv6.conf.default.max_addresses +1. + + Is it the case that the correct value is not returned? + + + + To check the ownership of /etc/chrony.keys, +run the command: +$ ls -lL /etc/chrony.keys +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/chrony.keys does not have an owner of root? + + + + To determine if the system is configured to audit calls to the +fremovexattr system call, run the following command: +$ sudo grep "fremovexattr" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. + + Is it the case that no line is returned? + + + + Verify Oracle Linux 9 generates audit records for all account creations, modifications, disabling, and termination events that affect "/etc/group" with the following command: + +$ sudo auditctl -l | grep -E '(/etc/group)' + +-w /etc/group -p wa -k identity + Is it the case that the command does not return a line, or the line is commented out? + + + + The runtime status of the net.ipv4.ip_forward kernel parameter can be queried +by running the following command: +$ sysctl net.ipv4.ip_forward +0. +The ability to forward packets is only appropriate for routers. + Is it the case that the correct value is not returned? + + + + + +Run the following command to determine the current status of the +pcscd service: +$ sudo systemctl is-active pcscd +If the service is running, it should return the following: active + Is it the case that the pcscd service is not enabled? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_PAGE_POISONING /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To check the permissions of /etc/passwd, +run the command: +$ ls -l /etc/passwd +If properly configured, the output should indicate the following permissions: +-rw-r--r-- + Is it the case that /etc/passwd does not have unix mode -rw-r--r--? + + + + Inspect the password section of /etc/pam.d/system-auth +and ensure that the pam_unix.so module is configured to use the argument +: + +$ sudo grep "^password.*pam_unix\.so.*" /etc/pam.d/system-auth + +password sufficient pam_unix.so + Is it the case that "<sub idref="var_password_hashing_algorithm_pam" />" is missing, or is commented out? + + + + Verify that the system backups user data. + Is it the case that it is not? + + + + To determine if NOPASSWD has been configured for the vdsm user for sudo, +run the following command: +$ sudo grep -ri nopasswd /etc/sudoers.d/ +The command should return output only for the vdsm user. + Is it the case that nopasswd is set for any users beyond vdsm? + + + + Run the following command to determine if the rsyslog-gnutls package is installed: +$ rpm -q rsyslog-gnutls Is it the case that the package is installed? - - - - To check that the squid service is disabled in system boot configuration, + + + + To verify the audispd's syslog plugin is active, run the following command: +$ sudo grep active /etc/audit/plugins.d/syslog.conf +If the plugin is active, the output will show yes. + Is it the case that it is not activated? + + + + To check the permissions of /etc/group-, +run the command: +$ ls -l /etc/group- +If properly configured, the output should indicate the following permissions: +-rw-r--r-- + Is it the case that /etc/group- does not have unix mode -rw-r--r--? + + + + To check the ownership of /boot/System.map*, +run the command: +$ ls -lL /boot/System.map* +If properly configured, the output should indicate the following owner: +root + Is it the case that /boot/System.map* does not have an owner of root? + + + + Verify the noexec option is configured for the /var/tmp mount point, + run the following command: + $ sudo mount | grep '\s/var/tmp\s' + . . . /var/tmp . . . noexec . . . + + Is it the case that the "/var/tmp" file system does not have the "noexec" option set? + + + + To check that the squid service is disabled in system boot configuration, run the following command: $ sudo systemctl is-enabled squid Output should indicate the squid service has either not been installed, @@ -235025,2910 +257454,26 @@ LoadState=masked UnitFileState=masked Is it the case that the "squid" is loaded and not masked? - - - - - -Run the following command to determine the current status of the -rngd service: -$ sudo systemctl is-active rngd -If the service is running, it should return the following: active - Is it the case that the "rngd" service is disabled, masked, or not started.? - - - - Run the following command to determine if the quagga package is installed: -$ rpm -q quagga - Is it the case that the package is installed? - - - - To check if RekeyLimit is set correctly, run the following command: -$ sudo grep RekeyLimit /etc/ssh/ssh_config.d/*.conf -If configured properly, output should be -/etc/ssh/ssh_config.d/02-rekey-limit.conf: -RekeyLimit -Check also the main configuration file with the following command: -$ sudo grep RekeyLimit /etc/ssh/ssh_config -The command should not return any output. - Is it the case that it is commented out or is not set? - - - - For each private key stored on the system, use the following command: -$ sudo ssh-keygen -y -f /path/to/file -If the contents of the key are displayed, this is a finding. - Is it the case that no ssh private key is accessible without a passcode? - - - - To determine how the SSH daemon's HostbasedAuthentication option is set, run the following command: - -$ sudo grep -i HostbasedAuthentication /etc/ssh/sshd_config - -If a line indicating no is returned, then the required value is set. - - Is it the case that the required value is not set? - - - - - -To determine if firewalld is configured to allow access to ssh -on port 22/tcp, run the following command(s): - - firewall-cmd --list-ports - - - firewall-cmd --list-services - -If firewalld is configured to allow access through the firewall, something similar to the following will be output: - -If it is a service: -ssh - - -If it is a port: -22/tcp - - Is it the case that sshd service is not enabled in the proper firewalld zone? - - - - To check which SSH protocol version is allowed, check version of openssh-server with following command: - -$ rpm -qi openssh-server | grep Version - -Versions equal to or higher than 7.4 only allow Protocol 2. -If version is lower than 7.4, run the following command to check configuration: -$ sudo grep Protocol /etc/ssh/sshd_config -If configured properly, output should be Protocol 2 - Is it the case that it is commented out or is not set correctly to Protocol 2? - - - - To check if compression is enabled or set correctly, run the -following command: -$ sudo grep Compression /etc/ssh/sshd_config -If configured properly, output should be no or delayed. - Is it the case that it is commented out, or is not set to no or delayed? - - - - To determine how the SSH daemon's PermitEmptyPasswords option is set, run the following command: - -$ sudo grep -i PermitEmptyPasswords /etc/ssh/sshd_config - -If a line indicating no is returned, then the required value is set. - - Is it the case that the required value is not set? - - - - To determine how the SSH daemon's GSSAPIAuthentication option is set, run the following command: - -$ sudo grep -i GSSAPIAuthentication /etc/ssh/sshd_config - -If a line indicating no is returned, then the required value is set. - - Is it the case that the required value is not set? - - - - To determine how the SSH daemon's KerberosAuthentication option is set, run the following command: - -$ sudo grep -i KerberosAuthentication /etc/ssh/sshd_config - -If a line indicating no is returned, then the required value is set. - - Is it the case that the required value is not set? - - - - To determine how the SSH daemon's PubkeyAuthentication option is set, run the following command: - -$ sudo grep -i PubkeyAuthentication /etc/ssh/sshd_config - -If a line indicating no is returned, then the required value is set. - - Is it the case that the required value is not set? - - - - To determine how the SSH daemon's IgnoreRhosts option is set, run the following command: - -$ sudo grep -i IgnoreRhosts /etc/ssh/sshd_config - -If a line indicating yes is returned, then the required value is set. - - Is it the case that the required value is not set? - - - - To check which SSH protocol version is allowed, check version of -openssh-server with following command: -$ rpm -qi openssh-server | grep Version -Versions equal to or higher than 7.4 have deprecated the RhostsRSAAuthentication option. -If version is lower than 7.4, run the following command to check configuration: -To determine how the SSH daemon's RhostsRSAAuthentication option is set, run the following command: - -$ sudo grep -i RhostsRSAAuthentication /etc/ssh/sshd_config - -If a line indicating no is returned, then the required value is set. - - Is it the case that the required value is not set? - - - - To determine how the SSH daemon's PermitRootLogin option is set, run the following command: - -$ sudo grep -i PermitRootLogin /etc/ssh/sshd_config - -If a line indicating no is returned, then the required value is set. - - Is it the case that the required value is not set? - - - - To determine how the SSH daemon's PermitRootLogin option is set, run the following command: - -$ sudo grep -i PermitRootLogin /etc/ssh/sshd_config - -If a line indicating prohibit-password is returned, then the required value is set. - Is it the case that it is commented out or not configured properly? - - - - To determine how the SSH daemon's AllowTcpForwarding option is set, run the following command: - -$ sudo grep -i AllowTcpForwarding /etc/ssh/sshd_config - -If a line indicating no is returned, then the required value is set. - Is it the case that The AllowTcpForwarding option exists and is disabled? - - - - To determine how the SSH daemon's IgnoreUserKnownHosts option is set, run the following command: - -$ sudo grep -i IgnoreUserKnownHosts /etc/ssh/sshd_config - -If a line indicating yes is returned, then the required value is set. - - Is it the case that the required value is not set? - - - - To determine how the SSH daemon's X11Forwarding option is set, run the following command: - -$ sudo grep -i X11Forwarding /etc/ssh/sshd_config - -If a line indicating no is returned, then the required value is set. - - Is it the case that the required value is not set? - - - - To determine how the SSH daemon's PermitUserEnvironment option is set, run the following command: - -$ sudo grep -i PermitUserEnvironment /etc/ssh/sshd_config - -If a line indicating no is returned, then the required value is set. - - Is it the case that the required value is not set? - - - - To determine how the SSH daemon's GSSAPIAuthentication option is set, run the following command: - -$ sudo grep -i GSSAPIAuthentication /etc/ssh/sshd_config - -If a line indicating yes is returned, then the required value is set. - - Is it the case that the required value is not set? - - - - To determine how the SSH daemon's UsePAM option is set, run the following command: - -$ sudo grep -i UsePAM /etc/ssh/sshd_config - -If a line indicating yes is returned, then the required value is set. - - Is it the case that the required value is not set? - - - - To determine how the SSH daemon's PubkeyAuthentication option is set, run the following command: - -$ sudo grep -i PubkeyAuthentication /etc/ssh/sshd_config - -If a line indicating yes is returned, then the required value is set. - - Is it the case that the required value is not set? - - - - To determine how the SSH daemon's StrictModes option is set, run the following command: - -$ sudo grep -i StrictModes /etc/ssh/sshd_config - -If a line indicating yes is returned, then the required value is set. - - Is it the case that the required value is not set? - - - - To determine how the SSH daemon's Banner option is set, run the following command: - -$ sudo grep -i Banner /etc/ssh/sshd_config - -If a line indicating /etc/issue is returned, then the required value is set. - - Is it the case that the required value is not set? - - - - To determine how the SSH daemon's Banner option is set, run the following command: - -$ sudo grep -i Banner /etc/ssh/sshd_config - -If a line indicating /etc/issue.net is returned, then the required value is set. - - Is it the case that the required value is not set? - - - - To determine how the SSH daemon's X11Forwarding option is set, run the following command: - -$ sudo grep -i X11Forwarding /etc/ssh/sshd_config - -If a line indicating yes is returned, then the required value is set. - - Is it the case that the required value is not set? - - - - To ensure sshd limits the users who can log in, run the following: -pre>$ sudo grep -rPi '^\h*(allow|deny)(users|groups)\h+\H+(\h+.*)?$' /etc/ssh/sshd_config* -If properly configured, the output should be a list of usernames and/or -groups allowed to log in to this system. - Is it the case that sshd does not limit the users who can log in? - - - - To determine how the SSH daemon's PrintLastLog option is set, run the following command: - -$ sudo grep -i PrintLastLog /etc/ssh/sshd_config - -If a line indicating yes is returned, then the required value is set. - - Is it the case that the required value is not set? - - - - To check if RekeyLimit is set correctly, run the -following command: - -$ sudo grep RekeyLimit /etc/ssh/sshd_config - -If configured properly, output should be -RekeyLimit - Is it the case that it is commented out or is not set? - - - - Run the following command to see what the timeout interval is: -$ sudo grep ClientAliveInterval /etc/ssh/sshd_config -If properly configured, the output should be: -ClientAliveInterval - Is it the case that it is commented out or not configured properly? - - - - To ensure ClientAliveInterval is set correctly, run the following command: -$ sudo grep ClientAliveCountMax /etc/ssh/sshd_config -If properly configured, the output should be: -ClientAliveCountMax -For SSH earlier than v8.2, a ClientAliveCountMax value of 0 causes a timeout precisely when -the ClientAliveInterval is set. Starting with v8.2, a value of 0 disables the timeout -functionality completely. -If the option is set to a number greater than 0, then the session will be disconnected after -ClientAliveInterval * ClientAliveCountMax seconds without receiving a keep alive message. - Is it the case that it is commented out or not configured properly? - - - - To ensure ClientAliveInterval is set correctly, run the following command: - -$ sudo grep ClientAliveCountMax /etc/ssh/sshd_config - -If properly configured, the output should be: -ClientAliveCountMax 0 - -In this case, the SSH timeout occurs precisely when -the ClientAliveInterval is set. - Is it the case that it is commented out or not configured properly? - - - - To ensure LoginGraceTime is set correctly, run the following command: -$ sudo grep LoginGraceTime /etc/ssh/sshd_config -If properly configured, the output should be: -LoginGraceTime -If the option is set to a number greater than 0, then the unauthenticated session will be disconnected -after the configured number seconds. - Is it the case that it is commented out or not configured properly? - - - - To determine how the SSH daemon's LogLevel option is set, run the following command: - -$ sudo grep -i LogLevel /etc/ssh/sshd_config - -If a line indicating INFO is returned, then the required value is set. - - Is it the case that the required value is not set? - - - - To determine how the SSH daemon's LogLevel option is set, run the following command: - -$ sudo grep -i LogLevel /etc/ssh/sshd_config - -If a line indicating VERBOSE is returned, then the required value is set. - - Is it the case that the required value is not set? - - - - To ensure the MaxAuthTries parameter is set, run the following command: -$ sudo grep MaxAuthTries /etc/ssh/sshd_config -If properly configured, output should be: -MaxAuthTries - Is it the case that it is commented out or not configured properly? - - - - Run the following command to see what the max sessions number is: -$ sudo grep MaxSessions /etc/ssh/sshd_config -If properly configured, the output should be: -MaxSessions - Is it the case that MaxSessions is not configured or not configured correctly? - - - - To check if MaxStartups is configured, run the following command: -$ sudo grep MaxStartups /etc/ssh/sshd_config -If configured, this command should output the configuration. - Is it the case that maxstartups is not configured? - - - - To determine whether the SSH server includes configuration files from the right directory, run the following command: -$ sudo grep -i '^Include' /etc/ssh/sshd_config -If a line Include /etc/ssh/sshd_config.d/*.conf is returned, then the configuration file inclusion is set correctly. - Is it the case that you don't include other configuration files from the main configuration file? - - - - To check if UsePrivilegeSeparation is enabled or set correctly, run the -following command: -$ sudo grep UsePrivilegeSeparation /etc/ssh/sshd_config -If configured properly, output should be . - Is it the case that it is commented out or is not enabled? - - - - To determine how the SSH daemon's X11UseLocalhost option is set, run the following command: - -$ sudo grep -i X11UseLocalhost /etc/ssh/sshd_config - -If a line indicating yes is returned, then the required value is set. - Is it the case that the display proxy is listening on wildcard address? - - - - To check the group ownership of /etc/ssh/sshd_config, + + + + To check the permissions of /etc/crontab, run the command: -$ ls -lL /etc/ssh/sshd_config -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/ssh/sshd_config does not have a group owner of root? - - - - To check the group ownership of /etc/ssh/*_key, -run the command: -$ ls -lL /etc/ssh/*_key -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/ssh/*_key does not have a group owner of root? - - - - To check the group ownership of /etc/ssh/*.pub, -run the command: -$ ls -lL /etc/ssh/*.pub -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/ssh/*.pub does not have a group owner of root? - - - - To check the ownership of /etc/ssh/sshd_config, -run the command: -$ ls -lL /etc/ssh/sshd_config -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/ssh/sshd_config does not have an owner of root? - - - - To check the ownership of /etc/ssh/*_key, -run the command: -$ ls -lL /etc/ssh/*_key -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/ssh/*_key does not have an owner of root? - - - - To check the ownership of /etc/ssh/*.pub, -run the command: -$ ls -lL /etc/ssh/*.pub -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/ssh/*.pub does not have an owner of root? - - - - To check the permissions of /etc/ssh/sshd_config, -run the command: -$ ls -l /etc/ssh/sshd_config +$ ls -l /etc/crontab If properly configured, the output should indicate the following permissions: -rw------- - Is it the case that /etc/ssh/sshd_config does not have unix mode -rw-------? - - - - To check the permissions of /etc/ssh/*_key, -run the command: -$ ls -l /etc/ssh/*_key -If properly configured, the output should indicate the following permissions: --rw------- - Is it the case that /etc/ssh/*_key does not have unix mode -rw-------? - - - - To check the permissions of /etc/ssh/*.pub, -run the command: -$ ls -l /etc/ssh/*.pub -If properly configured, the output should indicate the following permissions: --rw-r--r-- - Is it the case that /etc/ssh/*.pub does not have unix mode -rw-r--r--? - - - - Run the following command to determine if the openssh-clients package is installed: $ rpm -q openssh-clients - Is it the case that the package is not installed? - - - - Run the following command to determine if the openssh-server package is installed: $ rpm -q openssh-server - Is it the case that the package is not installed? - - - - Run the following command to determine if the openssh-server package is installed: $ rpm -q openssh-server - Is it the case that the package is installed? - - - - To check that the sshd service is disabled in system boot configuration, -run the following command: -$ sudo systemctl is-enabled sshd -Output should indicate the sshd service has either not been installed, -or has been disabled at all runlevels, as shown in the example below: -$ sudo systemctl is-enabled sshd disabled - -Run the following command to verify sshd is not active (i.e. not running) through current runtime configuration: -$ sudo systemctl is-active sshd - -If the service is not running the command will return the following output: -inactive - -The service will also be masked, to check that the sshd is masked, run the following command: -$ sudo systemctl show sshd | grep "LoadState\|UnitFileState" - -If the service is masked the command will return the following outputs: - -LoadState=masked - -UnitFileState=masked - Is it the case that the "sshd" is loaded and not masked? - - - - - -Run the following command to determine the current status of the -sshd service: -$ sudo systemctl is-active sshd -If the service is running, it should return the following: active - Is it the case that sshd service is disabled? - - - - Check to see if Online Certificate Status Protocol (OCSP) -is enabled and using the proper digest value on the system with the following command: -$ sudo grep certificate_verification /etc/sssd/sssd.conf /etc/sssd/conf.d/*.conf | grep -v "^#" -If configured properly, output should look like - - certificate_verification = ocsp_dgst= - - Is it the case that certificate_verification in sssd is not configured? - - - - To verify Certmap is enabled in SSSD, run the following command: -$ sudo cat /etc/sssd/sssd.conf -If configured properly, output should contain section like the following - -[certmap/testing.test/rule_name] -matchrule =<SAN>.*EDIPI@mil -maprule = (userCertificate;binary={cert!bin}) -domains = testing.test - - Is it the case that Certmap is not configured in SSSD? - - - - To verify that smart cards are enabled in SSSD, run the following command: -$ sudo grep pam_cert_auth /etc/sssd/sssd.conf -If configured properly, output should be -pam_cert_auth = True - - -To verify that smart cards are enabled in PAM files, run the following command: -$ sudo grep -e "auth.*pam_sss\.so.*\(allow_missing_name\|try_cert_auth\)" /etc/pam.d/smartcard-auth /etc/pam.d/system-auth -If configured properly, output should be - -/etc/pam.d/smartcard-auth:auth sufficient pam_sss.so allow_missing_name -/etc/pam.d/system-auth:auth [success=done authinfo_unavail=ignore ignore=ignore default=die] pam_sss.so try_cert_auth - - Is it the case that smart cards are not enabled in SSSD? - - - - Verify Oracle Linux 9 for PKI-based authentication has valid certificates by constructing a -certification path (which includes status information) to an accepted trust anchor. - -Check that the system has a valid DoD root CA installed with the following command: - -$ sudo openssl x509 -text -in /etc/sssd/pki/sssd_auth_ca_db.pem - -Certificate: -Data: -Version: 3 (0x2) -Serial Number: 1 (0x1) -Signature Algorithm: sha256WithRSAEncryption -Issuer: C = US, O = U.S. Government, OU = DoD, OU = PKI, CN = DoD Root CA 3 -Validity -Not Before: Mar 20 18:46:41 2012 GMT -Not After : Dec 30 18:46:41 2029 GMT -Subject: C = US, O = U.S. Government, OU = DoD, OU = PKI, CN = DoD Root CA 3 -Subject Public Key Info: -Public Key Algorithm: rsaEncryption - Is it the case that root CA file is not a DoD-issued certificate with a valid date and installed in the /etc/sssd/pki/sssd_auth_ca_db.pem location? - - - - -To verify that SSSD expires offline credentials, run the following command: -$ sudo grep offline_credentials_expiration /etc/sssd/sssd.conf -If configured properly, output should be -offline_credentials_expiration = 1 - Is it the case that it does not exist or is not configured properly? - - - - To verify that Linux Audit logging is enabled for the USBGuard daemon, -run the following command: -$ sudo grep AuditBackend /etc/usbguard/usbguard-daemon.conf -The output should be -AuditBackend=LinuxAudit - Is it the case that AuditBackend is not set to LinuxAudit? - - - - Run the following command to determine if the usbguard package is installed: $ rpm -q usbguard - Is it the case that the package is not installed? - - - - - -Run the following command to determine the current status of the -usbguard service: -$ sudo systemctl is-active usbguard -If the service is running, it should return the following: active - Is it the case that the service is not enabled? - - - - To verify that USB Human Interface Devices and hubs will be authorized by the USBGuard daemon, -run the following command: -$ sudo grep allow /etc/usbguard/rules.conf -The output lines should include -allow with-interface match-all { 03:*:* 09:00:* } - Is it the case that USB devices of class 3 and 9:00 are not authorized? - - - - Verify the USBGuard has a policy configured with the following command: - -$ usbguard list-rules - -allow id 1d6b:0001 serial - -If the command does not return results or an error is returned, ask the SA to indicate how unauthorized peripherals are being blocked. - Is it the case that there is no evidence that unauthorized peripherals are being blocked before establishing a connection? - - - - To ensure the X Windows package group is removed, run the following command: -$ rpm -qi xorg-x11-server-common -The output should be: -package xorg-x11-server-common is not installed - Is it the case that the X Windows package group or xorg-x11-server-common has not be removed? - - - - To ensure the X Windows package group is removed, run the following command: - -$ rpm -qi xorg-x11-server-Xorg xorg-x11-server-common xorg-x11-server-utils xorg-x11-server-Xwayland - -For each package mentioned above you should receive following line: -package <package> is not installed - Is it the case that xorg related packages are not removed and run level is not correctly configured? - - - - Verify that Oracle Linux 9 is configured to boot to the command line: -$ systemctl get-default -multi-user.target - Is it the case that the system default target is not set to "multi-user.target" and the Information System Security Officer (ISSO) lacks a documented requirement for a graphical user interface? - - - - To ensure a login warning banner is enabled, run the following: -$ grep banner-message-enable /etc/dconf/db/gdm.d/* -If properly configured, the output should be true. -To ensure a login warning banner is locked and cannot be changed by a user, run the following: -$ grep banner-message-enable /etc/dconf/db/gdm.d/locks/* -If properly configured, the output should be /org/gnome/login-screen/banner-message-enable. - Is it the case that it is not? - - - - -To ensure the login warning banner text is properly set, run the following: -$ grep banner-message-text /etc/dconf/db/gdm.d/* -If properly configured, the proper banner text will appear. -To ensure the login warning banner text is locked and cannot be changed by a user, run the following: -$ grep banner-message-text /etc/dconf/db/gdm.d/locks/* -If properly configured, the output should be /org/gnome/login-screen/banner-message-text. - Is it the case that it does not? - - - - To check if the system login banner is compliant, -run the following command: -$ cat /etc/issue - Is it the case that it does not display the required banner? - - - - To check if the system login banner is compliant, run the following command: -$ cat /etc/issue.net - Is it the case that it does not display the required banner? - - - - Verify the pam_faillock.so module is present in the "/etc/pam.d/password-auth" file: - -$ sudo grep pam_faillock.so /etc/pam.d/password-auth - -auth required pam_faillock.so preauth -auth required pam_faillock.so authfail -account required pam_faillock.so - Is it the case that the pam_faillock.so module is not present in the "/etc/pam.d/password-auth" file with the "preauth" line listed before pam_unix.so? - - - - Verify the pam_faillock.so module is present in the "/etc/pam.d/system-auth" file: - -$ sudo grep pam_faillock.so /etc/pam.d/system-auth - -auth required pam_faillock.so preauth -auth required pam_faillock.so authfail -account required pam_faillock.so - Is it the case that the pam_faillock.so module is not present in the "/etc/pam.d/system-auth" file with the "preauth" line listed before pam_unix.so? - - - - If the system does not have SELinux enabled and enforcing a targeted policy, or if the -pam_faillock.so module is not configured for use, this requirement is not applicable. - -Verify the location of the non-default tally directory for the pam_faillock.so module with -the following command: - -$ sudo grep -w dir /etc/security/faillock.conf - -dir = /var/log/faillock - -Check the security context type of the non-default tally directory with the following command: - -$ sudo ls -Zd /var/log/faillock - -unconfined_u:object_r:faillog_t:s0 /var/log/faillock - Is it the case that the security context type of the non-default tally directory is not "faillog_t"? - - - - Verify the "/etc/security/faillock.conf" file is configured to log user name information when unsuccessful logon attempts occur: - -$ sudo grep audit /etc/security/faillock.conf - -audit - Is it the case that the "audit" option is not set, is missing or commented out? - - - - Verify the "/etc/security/faillock.conf" file is configured use a non-default faillock directory to ensure contents persist after reboot: - -$ sudo grep 'dir =' /etc/security/faillock.conf - -dir = /var/log/faillock - Is it the case that the "dir" option is not set to a non-default documented tally log directory, is missing or commented out? - - - - Verify Oracle Linux 9 use the "pam_pwhistory.so" module in the /etc/pam.d/password-auth file -and is configured to prohibit password reuse for a minimum of -generations. - -Verify the "/etc/pam.d/password-auth" file with the following command: - -$ grep pam_pwhistory.so /etc/pam.d/password-auth -password pam_pwhistory.so use_authtok remember= - - -Verify the "/etc/security/pwhistory.conf" file using the following command: - -$ grep remember /etc/security/pwhistory.conf -remember = - -The pam_pwhistory.so "remember" option must be configured only in one file. - Is it the case that the pam_pwhistory.so module is not used, the "remember" module option is not set in -/etc/pam.d/password-auth or in /etc/security/pwhistory.conf, or is set in both files, or is set -with a value less than "<sub idref="var_password_pam_remember" />"? - - - - Verify Oracle Linux 9 use the "pam_pwhistory.so" module in the /etc/pam.d/system-auth file -and is configured to prohibit password reuse for a minimum of -generations. - -Verify the "/etc/pam.d/system-auth" file with the following command: - -$ grep pam_pwhistory.so /etc/pam.d/system-auth -password pam_pwhistory.so use_authtok remember= - - -Verify the "/etc/security/pwhistory.conf" file using the following command: - -$ grep remember /etc/security/pwhistory.conf -remember = - -The pam_pwhistory.so "remember" option must be configured only in one file. - Is it the case that the pam_pwhistory.so module is not used, the "remember" module option is not set in -/etc/pam.d/system-auth or in /etc/security/pwhistory.conf, or is set in both files, or is set -with a value less than "<sub idref="var_password_pam_remember" />"? - - - - To verify the password reuse setting is compliant, run the following command: -$ grep remember /etc/pam.d/system-auth -The output should show the following at the end of the line: -remember= - - -In newer systems, the pam_pwhistory PAM module options can also be set in -"/etc/security/pwhistory.conf" file. Use the following command to verify: -$ grep remember /etc/security/pwhistory.conf -remember = - -The pam_pwhistory remember option must be configured only in one file. - Is it the case that the value of remember is not equal to or greater than the expected value? - - - - Verify the "/etc/security/faillock.conf" file is configured to log user name information when unsuccessful logon attempts occur: - -$ sudo grep audit /etc/security/faillock.conf - -audit - Is it the case that the "audit" option is not set, is missing or commented out? - - - - To check the system for the existence of any .netrc files, -run the following command: -$ sudo find /home -xdev -name .netrc - Is it the case that any .netrc files exist? - - - - Verify Oracle Linux 9 is configured to lock an account after -unsuccessful logon attempts with the command: - - -$ grep 'deny =' /etc/security/faillock.conf -deny = . - Is it the case that the "deny" option is not set to "<sub idref="var_accounts_passwords_pam_faillock_deny" />" -or less (but not "0"), is missing or commented out? - - - - Verify Oracle Linux 9 is configured to lock the root account after -unsuccessful logon attempts with the command: - - -$ grep even_deny_root /etc/security/faillock.conf -even_deny_root - Is it the case that the "even_deny_root" option is not set, is missing or commented out? - - - - To ensure the tally directory is configured correctly, run the following command: -$ sudo grep 'dir =' /etc/security/faillock.conf -The output should show that dir is set to something other than "/var/run/faillock" - Is it the case that the "dir" option is not set to a non-default documented tally log directory, is missing or commented out? - - - - To ensure the failed password attempt policy is configured correctly, run the following command: - -$ grep fail_interval /etc/security/faillock.conf -The output should show fail_interval = <interval-in-seconds> where interval-in-seconds is or greater. - Is it the case that the "fail_interval" option is not set to "<sub idref="var_accounts_passwords_pam_faillock_fail_interval" />" -or less (but not "0"), the line is commented out, or the line is missing? - - - - Verify Oracle Linux 9 is configured to lock an account until released by an administrator -after unsuccessful logon -attempts with the command: - - -$ grep 'unlock_time =' /etc/security/faillock.conf -unlock_time = - Is it the case that the "unlock_time" option is not set to "<sub idref="var_accounts_passwords_pam_faillock_unlock_time" />", -the line is missing, or commented out? - - - - Verify that Oracle Linux 9 enforces password complexity by requiring that at least one numeric character be used. - -Check the value for "dcredit" with the following command: - -$ sudo grep dcredit /etc/security/pwquality.conf /etc/security/pwquality.conf.d/*.conf - -/etc/security/pwquality.conf:dcredit = - Is it the case that the value of "dcredit" is a positive number or is commented out? - - - - Verify Oracle Linux 9 prevents the use of dictionary words for passwords with the following command: - -$ sudo grep dictcheck /etc/security/pwquality.conf /etc/pwquality.conf.d/*.conf - -/etc/security/pwquality.conf:dictcheck=1 - Is it the case that "dictcheck" does not have a value other than "0", or is commented out? - - - - Verify the value of the "difok" option in "/etc/security/pwquality.conf" with the following command: - -$ sudo grep difok /etc/security/pwquality.conf - -difok = - Is it the case that the value of "difok" is set to less than "<sub idref="var_password_pam_difok" />", or is commented out? - - - - Verify that Oracle Linux 9 enforces password complexity rules for the root account. - -Check if root user is required to use complex passwords with the following command: - -$ grep enforce_for_root /etc/security/pwquality.conf /etc/security/pwquality.conf.d/*.conf - -/etc/security/pwquality.conf:enforce_for_root - Is it the case that "enforce_for_root" is commented or missing? - - - - Verify that Oracle Linux 9 enforces password complexity by requiring that at least one lower-case character. - -Check the value for "lcredit" with the following command: - -$ sudo grep lcredit /etc/security/pwquality.conf /etc/security/pwquality.conf.d/*.conf - -/etc/security/pwquality.conf:lcredit = -1 - Is it the case that the value of "lcredit" is a positive number or is commented out? - - - - Verify the value of the "maxclassrepeat" option in "/etc/security/pwquality.conf" with the following command: - -$ grep maxclassrepeat /etc/security/pwquality.conf - -maxclassrepeat = - Is it the case that the value of "maxclassrepeat" is set to "0", more than "<sub idref="var_password_pam_maxclassrepeat" />" or is commented out? - - - - Verify the value of the "maxrepeat" option in "/etc/security/pwquality.conf" with the following command: - -$ grep maxrepeat /etc/security/pwquality.conf - -maxrepeat = - Is it the case that the value of "maxrepeat" is set to more than "<sub idref="var_password_pam_maxrepeat" />" or is commented out? - - - - Verify the value of the "minclass" option in "/etc/security/pwquality.conf" with the following command: - -$ grep minclass /etc/security/pwquality.conf - -minclass = - Is it the case that the value of "minclass" is set to less than "<sub idref="var_password_pam_minclass" />" or is commented out? - - - - Verify that Oracle Linux 9 enforces a minimum -character password length with the following command: - -$ grep minlen /etc/security/pwquality.conf - -minlen = - Is it the case that the command does not return a "minlen" value of "<sub idref="var_password_pam_minlen" />" or greater, does not return a line, or the line is commented out? - - - - Verify that Oracle Linux 9 enforces password complexity by requiring that at least one special character with the following command: - -$ sudo grep ocredit /etc/security/pwquality.conf /etc/security/pwquality.conf.d/*.conf - -ocredit = - Is it the case that value of "ocredit" is a positive number or is commented out? - - - - To check if pam_pwquality.so is enabled in password-auth, run the following command: -$ grep pam_pwquality /etc/pam.d/password-auth -The output should be similar to the following: -password requisite pam_pwquality.so - Is it the case that pam_pwquality.so is not enabled in password-auth? - - - - To check if pam_pwquality.so is enabled in system-auth, run the following command: -$ grep pam_pwquality /etc/pam.d/system-auth -The output should be similar to the following: -password requisite pam_pwquality.so - Is it the case that pam_pwquality.so is not enabled in system-auth? - - - - Verify Oracle Linux 9 is configured to limit the "pwquality" retry option to . - - -Check for the use of the "pwquality" retry option in the pwquality.conf file with the following command: -$ grep retry /etc/security/pwquality.conf - Is it the case that the value of "retry" is set to "0" or greater than "<sub idref="var_password_pam_retry" />", or is missing? - - - - Verify that Oracle Linux 9 enforces password complexity by requiring that at least one upper-case character. - -Check the value for "ucredit" with the following command: - -$ sudo grep ucredit /etc/security/pwquality.conf /etc/security/pwquality.conf.d/*.conf - -ucredit = -1 - Is it the case that the value of "ucredit" is a positive number or is commented out? - - - - Verify that the libuser is set to encrypt password with a FIPS 140-3 approved cryptographic hashing algorithm. - - -Check the hashing algorithm that is being used to hash passwords with the following command: - -$ sudo grep -i crypt_style /etc/libuser.conf - -crypt_style = sha512 - Is it the case that crypt_style is not set to sha512? - - - - Verify that the shadow password suite configuration is set to encrypt password with a FIPS 140-3 approved cryptographic hashing algorithm. - - -Check the hashing algorithm that is being used to hash passwords with the following command: - -$ sudo grep -i ENCRYPT_METHOD /etc/login.defs - -ENCRYPT_METHOD - Is it the case that ENCRYPT_METHOD is not set to <sub idref="var_password_hashing_algorithm" />? - - - - Inspect the password section of /etc/pam.d/password-auth -and ensure that the pam_unix.so module includes the argument -sha512: -$ grep sha512 /etc/pam.d/password-auth - Is it the case that it does not? - - - - Inspect the password section of /etc/pam.d/system-auth -and ensure that the pam_unix.so module is configured to use the argument -sha512: - -$ sudo grep "^password.*pam_unix\.so.*sha512" /etc/pam.d/system-auth - -password sufficient pam_unix.so sha512 - Is it the case that "sha512" is missing, or is commented out? - - - - Inspect /etc/login.defs and ensure that if eihter -SHA_CRYPT_MIN_ROUNDS or SHA_CRYPT_MAX_ROUNDS -are set, they must have the minimum value of 5000. - Is it the case that it does not? - - - - Verify the operating system is not configured to bypass password requirements for privilege -escalation. Check the configuration of the "/etc/pam.d/sudo" file with the following command: -$ sudo grep pam_succeed_if /etc/pam.d/sudo - Is it the case that system is configured to bypass password requirements for privilege escalation? - - - - Verify users are provided with feedback on when account accesses last occurred with the following command: - -$ sudo grep pam_lastlog /etc/pam.d/postlogin - -session required pam_lastlog.so showfailed - Is it the case that "pam_lastlog" is missing from "/etc/pam.d/postlogin" file, or the silent option is present? - - - - Verify Oracle Linux 9 shell initialization file is configured to start each shell with the tmux terminal multiplexer. - -Determine the location of the tmux script with the following command: - -$ sudo grep tmux /etc/bashrc /etc/profile.d/* - -/etc/profile.d/tmux.sh: case "$name" in (sshd|login) exec tmux ;; esac - -Review the tmux script by using the following example: - -$ cat /etc/profile.d/tmux.sh - -if [ "$PS1" ]; then -parent=$(ps -o ppid= -p $$) -name=$(ps -o comm= -p $parent) -case "$name" in (sshd|login) exec tmux ;; esac -fi - -If the shell file is not configured as the example above, is commented out, or is missing, this is a finding. - -Determine if tmux is currently running with the following command: - -$ sudo ps all | grep tmux | grep -v grep - Is it the case that the command does not produce output? - - - - Verify Oracle Linux 9 initiates a session lock after 15 minutes of inactivity. - -Check the value of the system inactivity timeout with the following command: - -$ grep -i lock-after-time /etc/tmux.conf - -set -g lock-after-time 900 - -Then, verify that the /etc/tmux.conf file can be read by other users than root: - -$ sudo ls -al /etc/tmux.conf - Is it the case that "lock-after-time" is not set to "900" or less in the global tmux configuration file to enforce session lock after inactivity? - - - - Verify Oracle Linux 9 enables the user to initiate a session lock with the following command: - -$ grep lock-command /etc/tmux.conf - -set -g lock-command vlock - -Then, verify that the /etc/tmux.conf file can be read by other users than root: - -$ sudo ls -al /etc/tmux.conf - Is it the case that the "lock-command" is not set in the global settings to call "vlock"? - - - - To verify that tmux is not listed as allowed shell on the system -run the following command: -$ grep 'tmux$' /etc/shells -The output should be empty. - Is it the case that tmux is listed in /etc/shells? - - - - Run the following command to determine if the tmux package is installed: $ rpm -q tmux - Is it the case that the package is not installed? - - - - Verify that Oracle Linux 9 loads the driver with the following command: - -$ grep card_drivers /etc/opensc.conf - -card_drivers = ; - Is it the case that "<sub idref="var_smartcard_drivers" />" is not listed as a card driver, or there is no line returned for "card_drivers"? - - - - To verify that is configured -as the smart card driver, run the following command: -$ grep force_card_driver /etc/opensc.conf -The output should return something similar to: -force_card_driver = ; - Is it the case that the smart card driver is not configured correctly? - - - - Check that Oracle Linux 9 has the packages for smart card support installed. - -Run the following command to determine if the openssl-pkcs11 package is installed: -$ rpm -q openssl-pkcs11 - Is it the case that smartcard software is not installed? - - - - Run the following command to determine if the opensc package is installed: $ rpm -q opensc - Is it the case that the package is not installed? - - - - Run the following command to determine if the pcsc-lite package is installed: $ rpm -q pcsc-lite - Is it the case that the package is not installed? - - - - - -Run the following command to determine the current status of the -pcscd service: -$ sudo systemctl is-active pcscd -If the service is running, it should return the following: active - Is it the case that the pcscd service is not enabled? - - - - To ensure the system is configured to ignore the Ctrl-Alt-Del setting, -enter the following command: -$ sudo grep -i ctrlaltdelburstaction /etc/systemd/system.conf -The output should return: -CtrlAltDelBurstAction=none - Is it the case that the system is configured to reboot when Ctrl-Alt-Del is pressed more than 7 times in 2 seconds.? - - - - To ensure the system is configured to mask the Ctrl-Alt-Del sequence, Check -that the ctrl-alt-del.target is masked and not active with the following -command: -sudo systemctl status ctrl-alt-del.target -The output should indicate that the target is masked and not active. It -might resemble following output: -ctrl-alt-del.target -Loaded: masked (/dev/null; bad) -Active: inactive (dead) - Is it the case that the system is configured to reboot when Ctrl-Alt-Del is pressed? - - - - Inspect /etc/default/grub for any instances of -systemd.confirm_spawn=(1|yes|true|on) in the kernel boot arguments. -Presence of a systemd.confirm_spawn=(1|yes|true|on) indicates -that interactive boot is enabled at boot time and verify that -GRUB_DISABLE_RECOVERY=true to disable recovery boot. - Is it the case that Interactive boot is enabled at boot time? - - - - To check if authentication is required for emergency mode, run the following command: -$ grep sulogin /usr/lib/systemd/system/emergency.service -The output should be similar to the following, and the line must begin with -ExecStart and /usr/lib/systemd/systemd-sulogin-shell. - ExecStart=-/usr/lib/systemd/systemd-sulogin-shell emergency - -Then, check if the emergency target requires the emergency service: -Run the following command: -$ sudo grep Requires /usr/lib/systemd/system/emergency.target -The output should be the following: -Requires=emergency.service - -Then, check if there is no custom emergency target configured in systemd configuration. -Run the following command: -$ sudo grep -r emergency.target /etc/systemd/system/ -The output should be empty. - -Then, check if there is no custom emergency service configured in systemd configuration. -Run the following command: -$ sudo grep -r emergency.service /etc/systemd/system/ -The output should be empty. - Is it the case that the output is different? - - - - To check if authentication is required for single-user mode, run the following command: -$ grep sulogin /usr/lib/systemd/system/rescue.service -The output should be similar to the following, and the line must begin with -ExecStart and /usr/lib/systemd/systemd-sulogin-shell. - ExecStart=-/usr/lib/systemd/systemd-sulogin-shell rescue - - -Then, verify that the rescue service is in the runlevel1.target. -Run the following command: -$ sudo grep "^Requires=.*rescue\.service" /usr/lib/systemd/system/runlevel1.target -The output should be the following: -Requires=sysinit.target rescue.service - -Then, check if there is no custom runlevel1 target configured in systemd configuration. -Run the following command: -$ sudo grep -r "^runlevel1.target$" /etc/systemd/system -There should be no output. - -Then, check if there is no custom rescue service configured in systemd configuration. -Run the following command: -$ sudo grep -r "^rescue.service$" /etc/systemd/system -There should be no output. - Is it the case that the output is different? - - - - To check that the debug-shell service is disabled in system boot configuration, -run the following command: -$ sudo systemctl is-enabled debug-shell -Output should indicate the debug-shell service has either not been installed, -or has been disabled at all runlevels, as shown in the example below: -$ sudo systemctl is-enabled debug-shell disabled - -Run the following command to verify debug-shell is not active (i.e. not running) through current runtime configuration: -$ sudo systemctl is-active debug-shell - -If the service is not running the command will return the following output: -inactive - -The service will also be masked, to check that the debug-shell is masked, run the following command: -$ sudo systemctl show debug-shell | grep "LoadState\|UnitFileState" - -If the service is masked the command will return the following outputs: - -LoadState=masked - -UnitFileState=masked - Is it the case that the "debug-shell" is loaded and not masked? - - - - To verify the inactive setting, run the following command: -$ grep 'inactive\|pam_unix' /etc/pam.d/password-auth | grep -w auth -The output should indicate the inactive configuration option is set -to an appropriate integer between 1 and -; and should appear -before the pam_unix.so module as shown in the example below: -$ grep 'inactive\|pam_unix' /etc/pam.d/password-auth | grep -w auth -auth required pam_lastlog.so inactive= -auth sufficient pam_unix.so - Is it the case that the value of inactive is incorrect or is not set before pam_unix.so? - - - - To verify the inactive setting, run the following command: -$ grep 'inactive\|pam_unix' /etc/pam.d/system-auth | grep -w auth -The output should indicate the inactive configuration option is set -to an appropriate integer between 1 and -; and should appear -before the pam_unix.so module as shown in the example below: -$ grep 'inactive\|pam_unix' /etc/pam.d/system-auth | grep -w auth -auth required pam_lastlog.so inactive= -auth sufficient pam_unix.so - Is it the case that the value of inactive is incorrect or is not set before pam_unix.so? - - - - To verify the INACTIVE setting, run the following command: -$ grep "INACTIVE" /etc/default/useradd -The output should indicate the INACTIVE configuration option is set -to an appropriate integer as shown in the example below: -$ grep "INACTIVE" /etc/default/useradd -INACTIVE= - Is it the case that the value of INACTIVE is greater than the expected value or is -1? - - - - Verify emergency accounts have been provisioned with an expiration date of 72 hours. - -For every emergency account, run the following command to obtain its account aging and expiration information: - -$ sudo chage -l emergency_account_name - -Verify each of these accounts has an expiration date set within 72 hours or as documented. - Is it the case that any emergency accounts have no expiration date set or do not expire within 72 hours? - - - - Verify that temporary accounts have been provisioned with an expiration date -of 72 hours. For every temporary account, run the following command to -obtain its account aging and expiration information: -$ sudo chage -l temporary_account_name -Verify each of these accounts has an expiration date set within 72 hours or -as documented. - Is it the case that any temporary accounts have no expiration date set or do not expire within 72 hours? - - - - To verify all accounts have unique names, run the following command: -$ sudo getent passwd | awk -F: '{ print $1}' | uniq -d -No output should be returned. - Is it the case that a line is returned? - - - - Verify that the system is integrated with a centralized authentication mechanism -such as as Active Directory, Kerberos, Directory Server, etc. that has -automated account mechanisms in place. - Is it the case that the system is not using a centralized authentication mechanism, or it is not automated? - - - - Verify that Oracle Linux 9 enforces a -day maximum password lifetime for new user accounts by running the following command: - -$ grep -i pass_max_days /etc/login.defs - -PASS_MAX_DAYS - Is it the case that the "PASS_MAX_DAYS" parameter value is greater than "<sub idref="var_accounts_maximum_age_login_defs" />", or commented out? - - - - Verify Oracle Linux 9 enforces 24 hours/1 day as the minimum password lifetime for new user accounts. - -Check for the value of "PASS_MIN_DAYS" in "/etc/login.defs" with the following command: - -$ grep -i pass_min_days /etc/login.defs - -PASS_MIN_DAYS - Is it the case that the "PASS_MIN_DAYS" parameter value is not "<sub idref="var_accounts_minimum_age_login_defs" />" or greater, or is commented out? - - - - To check the minimum password length, run the command: -$ grep PASS_MIN_LEN /etc/login.defs -The DoD requirement is 15. - Is it the case that it is not set to the required value? - - - - Check whether the maximum time period for existing passwords is restricted to days with the following commands: - -$ sudo awk -F: '$5 > 60 {print $1 " " $5}' /etc/shadow - -$ sudo awk -F: '$5 <= 0 {print $1 " " $5}' /etc/shadow - Is it the case that any results are returned that are not associated with a system account? - - - - Verify that Oracle Linux 9 has configured the minimum time period between password changes for each user account is one day or greater with the following command: - -$ sudo awk -F: '$4 < 1 {print $1 " " $4}' /etc/shadow - Is it the case that any results are returned that are not associated with a system account? - - - - To check the password warning age, run the command: -$ grep PASS_WARN_AGE /etc/login.defs -The DoD requirement is 7. - Is it the case that it is not set to the required value? - - - - To check that no password hashes are stored in -/etc/passwd, run the following command: -awk '!/\S:x|\*/ {print}' /etc/passwd -If it produces any output, then a password hash is -stored in /etc/passwd. - Is it the case that any stored hashes are found in /etc/passwd? - - - - Verify that the interactive user account passwords are using a strong -password hash with the following command: - -$ sudo cut -d: -f2 /etc/shadow - -$6$kcOnRq/5$NUEYPuyL.wghQwWssXRcLRFiiru7f5JPV6GaJhNC2aK5F3PZpE/BCCtwrxRc/AInKMNX3CdMw11m9STiql12f/ - -Password hashes ! or * indicate inactive accounts not -available for logon and are not evaluated. - Is it the case that any interactive user password hash does not begin with "$6"? - - - - Verify that the interactive user account passwords last change time is not in the future -The following command should return no output -$ sudo expiration=$(cat /etc/shadow|awk -F ':' '{print $3}'); -for edate in ${expiration[@]}; do if [[ $edate > $(( $(date +%s)/86400 )) ]]; -then echo "Expiry date in future"; -fi; done - Is it the case that any interactive user password that has last change time in the future? - - - - To verify the number of rounds for the password hashing algorithm is configured, run the following command: -$ sudo grep rounds /etc/pam.d/password-auth -The output should show the following match: -password sufficient pam_unix.so sha512 rounds= - Is it the case that rounds is not set to <sub idref="var_password_pam_unix_rounds" /> or is commented out? - - - - To verify the number of rounds for the password hashing algorithm is configured, run the following command: -$ sudo grep rounds /etc/pam.d/system-auth -The output should show the following match: -password sufficient pam_unix.so sha512 rounds= - Is it the case that rounds is not set to <sub idref="var_password_pam_unix_rounds" /> or is commented out? - - - - To ensure all GIDs referenced in /etc/passwd are defined in /etc/group, -run the following command: -$ sudo pwck -qr -There should be no output. - Is it the case that GIDs referenced in /etc/passwd are returned as not defined in /etc/group? - - - - To verify that null passwords cannot be used, run the following command: - -$ grep nullok /etc/pam.d/system-auth /etc/pam.d/password-auth - -If this produces any output, it may be possible to log into accounts -with empty passwords. Remove any instances of the nullok option to -prevent logins with empty passwords. - Is it the case that NULL passwords can be used? - - - - To verify that null passwords cannot be used, run the following command: -$ sudo awk -F: '!$2 {print $1}' /etc/shadow -If this produces any output, it may be possible to log into accounts -with empty passwords. - Is it the case that Blank or NULL passwords can be used? - - - - Verify that only the "root" account has a UID "0" assignment with the -following command: -$ awk -F: '$3 == 0 {print $1}' /etc/passwd -root - Is it the case that any accounts other than "root" have a UID of "0"? - - - - To verify that root's primary group is zero run the following command: - - grep '^root:' /etc/passwd | cut -d : -f 4 - -The command should return: - -0 - - Is it the case that root has a primary gid not equal to zero? - - - - To ensure root may not directly login to the system over physical consoles, -run the following command: -cat /etc/securetty -If any output is returned, this is a finding. - Is it the case that the /etc/securetty file is not empty? - - - - To obtain a list of all users and the content of their shadow password field, run the command: -$ sudo readarray -t systemaccounts -Verify if all accounts are locked. - Is it the case that system accounts are not locked? - - - - To obtain a listing of all users, their UIDs, and their shells, run the command: -$ awk -F: '{print $1 ":" $3 ":" $7}' /etc/passwd -Identify the system accounts from this listing. These will primarily be the accounts with UID -numbers less than 1000, other than root. - Is it the case that any system account other than root has a login shell? - - - - To check for serial port entries which permit root login, -run the following command: -$ sudo grep ^ttyS/[0-9] /etc/securetty -If any output is returned, then root login over serial ports is permitted. - Is it the case that root login over serial ports is permitted? - - - - To check for virtual console entries which permit root login, run the -following command: -$ sudo grep ^vc/[0-9] /etc/securetty -If any output is returned, then root logins over virtual console devices is permitted. - Is it the case that root login over virtual console devices is permitted? - - - - Run the following command to check if the line is present: -grep pam_wheel /etc/pam.d/su -The output should contain the following line: -auth required pam_wheel.so use_uid - Is it the case that the line is not in the file or it is commented? - - - - Verify that Oracle Linux 9 contains no duplicate User IDs (UIDs) for interactive users. - -Check that the operating system contains no duplicate UIDs for interactive users with the following command: - -$ sudo awk -F ":" 'list[$3]++{print $1, $3}' /etc/passwd - Is it the case that output is produced and the accounts listed are interactive user accounts? - - - - To verify that there are no unauthorized local user accounts, run the following command: -$ less /etc/passwd -Inspect the results, and if unauthorized local user accounts exist, remove them by running -the following command: -$ sudo userdel unauthorized_user - Is it the case that there are unauthorized local user accounts on the system? - - - - Run the following command to check for duplicate group names: -Check that the operating system contains no duplicate group names for interactive users by running the following command: - - cut -d : -f 3 /etc/group | uniq -d - -If output is produced, this is a finding. -Configure the operating system to contain no duplicate names for groups. -Edit the file "/etc/group" and provide each group that has a duplicate group id with a unique group id. - Is it the case that the system has duplicate group ids? - - - - To ensure write permissions are disabled for group and other - for each element in root's path, run the following command: -# ls -ld DIR - Is it the case that group or other write permissions exist? - - - - Verify the umask setting is configured correctly in the /etc/bashrc file with the following command: - -$ sudo grep "umask" /etc/bashrc - -umask - Is it the case that the value for the "umask" parameter is not "<sub idref="var_accounts_user_umask" />", or the "umask" parameter is missing or is commented out? - - - - Verify the "umask" setting is configured correctly in the "/etc/csh.cshrc" file with the following command: - -$ grep umask /etc/csh.cshrc - -umask 077 -umask 077 - Is it the case that the value for the "umask" parameter is not "<sub idref="var_accounts_user_umask" />", or the "umask" parameter is missing or is commented out? - - - - Verify Oracle Linux 9 defines default permissions for all authenticated users in such a way that the user can only read and modify their own files with the following command: - -# grep -i umask /etc/login.defs - -UMASK - Is it the case that the value for the "UMASK" parameter is not "<sub idref="var_accounts_user_umask" />", or the "UMASK" parameter is missing or is commented out? - - - - Run the following command to ensure the TMOUT value is configured for all users -on the system: - -$ sudo grep TMOUT /etc/profile /etc/profile.d/*.sh - -The output should return the following: -TMOUT= - Is it the case that value of TMOUT is not less than or equal to expected setting? - - - - Verify the umask setting is configured correctly in the /etc/profile file -or scripts within /etc/profile.d directory with the following command: -$ grep "umask" /etc/profile* -umask - Is it the case that the value for the "umask" parameter is not "<sub idref="var_accounts_user_umask" />", -or the "umask" parameter is missing or is commented out? - - - - Verify that the default umask for all local interactive users is "077". - -Identify the locations of all local interactive user home directories by looking at the "/etc/passwd" file. - -Check all local interactive user initialization files for interactive users with the following command: - -Note: The example is for a system that is configured to create users home directories in the "/home" directory. - -# grep -ri umask /home/ - -/home/smithj/.bash_history:grep -i umask /etc/bashrc /etc/csh.cshrc /etc/profile -/home/smithj/.bash_history:grep -i umask /etc/login.defs - Is it the case that any local interactive user initialization files are found to have a umask statement that sets a value less restrictive than "077"? - - - - Verify all local interactive users on Oracle Linux 9 are assigned a home -directory upon creation with the following command: -$ grep -i create_home /etc/login.defs -CREATE_HOME yes - Is it the case that the value for "CREATE_HOME" parameter is not set to "yes", the line is missing, or the line is commented out? - - - - Verify Oracle Linux 9 enforces a delay of at least seconds between console logon prompts following a failed logon attempt with the following command: - -$ sudo grep -i "FAIL_DELAY" /etc/login.defs -FAIL_DELAY - Is it the case that the value of "FAIL_DELAY" is not set to "<sub idref="var_accounts_fail_delay" />" or greater, or the line is commented out? - - - - Verify Oracle Linux 9 limits the number of concurrent sessions to -"" for all -accounts and/or account types with the following command: -$ grep -r -s maxlogins /etc/security/limits.conf /etc/security/limits.d/*.conf -/etc/security/limits.conf:* hard maxlogins 10 -This can be set as a global domain (with the * wildcard) but may be set differently for multiple domains. - Is it the case that the "maxlogins" item is missing, commented out, or the value is set greater -than "<sub idref="var_accounts_max_concurrent_login_sessions" />" and -is not documented with the Information System Security Officer (ISSO) as an -operational requirement for all domains that have the "maxlogins" item -assigned'? - - - - Run the following command to ensure that /tmp is configured as a -polyinstantiated directory: -$ sudo grep /tmp /etc/security/namespace.conf -The output should return the following: -/tmp /tmp/tmp-inst/ level root,adm - Is it the case that is not configured? - - - - Run the following command to ensure that /var/tmp is configured as a -polyinstantiated directory: -$ sudo grep /var/tmp /etc/security/namespace.conf -The output should return the following: -/var/tmp /var/tmp/tmp-inst/ level root,adm - Is it the case that is not configured? - - - - Verify that local initialization files do not execute world-writable programs with the following command: - -Note: The example will be for a system that is configured to create user home directories in the "/home" directory. - -$ sudo find /home -perm -002 -type f -name ".[^.]*" -exec ls -ld {} \; - Is it the case that any local initialization files are found to reference world-writable files? - - - - Verify that all local interactive user initialization file executable search path statements do not contain statements that will reference a working directory other than user home directories with the following commands: - -$ sudo grep -i path= /home/*/.* - -/home/[localinteractiveuser]/.bash_profile:PATH=$PATH:$HOME/.local/bin:$HOME/bin - Is it the case that any local interactive user initialization files have executable search path statements that include directories outside of their home directory and is not documented with the ISSO as an operational requirement? - - - - Verify that interactive users on the system have a home directory assigned with the following command: - -$ sudo awk -F: '($3>=1000)&&($7 !~ /nologin/){print $1, $3, $6}' /etc/passwd - -Inspect the output and verify that all interactive users (normally users with a UID greater than 1000) have a home directory defined. - Is it the case that users home directory is not defined? - - - - Verify the assigned home directories of all interactive users on the system exist with the following command: - -$ sudo pwck -r - -user 'mailnull': directory 'var/spool/mqueue' does not exist - -The output should not return any interactive users. - Is it the case that users home directory does not exist? - - - - To verify the assigned home directory of all interactive users is group- -owned by that users primary GID, run the following command: -# ls -ld $(awk -F: '($3>=1000)&&($7 !~ /nologin/){print $6}' /etc/passwd) - Is it the case that the group ownership is incorrect? - - - - To verify that all user initialization files have a mode of 0740 or -less permissive, run the following command: -$ sudo find /home -type f -name '\.*' \( -perm -0002 -o -perm -0020 \) -There should be no output. - Is it the case that they are not 0740 or more permissive? - - - - To verify the assigned home directory of all interactive user home directories -have a mode of 0750 or less permissive, run the following command: -$ sudo ls -l /home -Inspect the output for any directories with incorrect permissions. - Is it the case that they are more permissive? - - - - To ensure the user home directory is not group-writable or world-readable, run the following: -# ls -ld /home/USER - Is it the case that the user home directory is group-writable or world-readable? - - - - Verify that authselect is enabled by running -authselect current -If authselect is enabled on the system, the output should show the ID of the profile which is currently in use. - Is it the case that authselect is not used to manage user authentication setup on the system? - - - - To determine if the system is configured to audit calls to the -chmod system call, run the following command: -$ sudo grep "chmod" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. - - Is it the case that no line is returned? - - - - To determine if the system is configured to audit calls to the -chown system call, run the following command: -$ sudo grep "chown" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. - - Is it the case that no line is returned? - - - - To determine if the system is configured to audit calls to the -fchmod system call, run the following command: -$ sudo grep "fchmod" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. - - Is it the case that no line is returned? - - - - To determine if the system is configured to audit calls to the -fchmodat system call, run the following command: -$ sudo grep "fchmodat" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. - - Is it the case that no line is returned? - - - - To determine if the system is configured to audit calls to the -fchown system call, run the following command: -$ sudo grep "fchown" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. - - Is it the case that no line is returned? - - - - To determine if the system is configured to audit calls to the -fchownat system call, run the following command: -$ sudo grep "fchownat" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. - - Is it the case that no line is returned? - - - - To determine if the system is configured to audit calls to the -fremovexattr system call, run the following command: -$ sudo grep "fremovexattr" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. - - Is it the case that no line is returned? - - - - To determine if the system is configured to audit calls to the -fsetxattr system call, run the following command: -$ sudo grep "fsetxattr" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. - - Is it the case that no line is returned? - - - - To determine if the system is configured to audit calls to the -lchown system call, run the following command: -$ sudo grep "lchown" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. - - Is it the case that no line is returned? - - - - To determine if the system is configured to audit calls to the -lremovexattr system call, run the following command: -$ sudo grep "lremovexattr" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. - - Is it the case that no line is returned? - - - - To determine if the system is configured to audit calls to the -lsetxattr system call, run the following command: -$ sudo grep "lsetxattr" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. - - Is it the case that no line is returned? - - - - To determine if the system is configured to audit calls to the -removexattr system call, run the following command: -$ sudo grep "removexattr" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. - - Is it the case that no line is returned? - - - - To determine if the system is configured to audit calls to the -setxattr system call, run the following command: -$ sudo grep "setxattr" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. - - Is it the case that no line is returned? - - - - Verify that Oracle Linux 9 generates an audit record for all uses of the "umount" and system call. -To determine if the system is configured to audit calls to the -"umount" system call, run the following command: -$ sudo grep "umount" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line like the following. --a always,exit -F arch=b32 -S umount -F auid>=1000 -F auid!=unset -k privileged-umount - Is it the case that the command does not return a line, or the line is commented out? - - - - To determine if the system is configured to audit calls to the -umount2 system call, run the following command: -$ sudo grep "umount2" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. - - Is it the case that no line is returned? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "chacl" command with the following command: - -$ sudo auditctl -l | grep chacl - --a always,exit -F path=/usr/bin/chacl -F perm=x -F auid>=1000 -F auid!=unset -k perm_mod - Is it the case that the command does not return a line, or the line is commented out? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "setfacl" command with the following command: - -$ sudo auditctl -l | grep setfacl - --a always,exit -F path=/usr/bin/setfacl -F perm=x -F auid>=1000 -F auid!=unset -k perm_mod - Is it the case that the command does not return a line, or the line is commented out? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "chcon" command with the following command: - -$ sudo auditctl -l | grep chcon - --a always,exit -F path=/usr/bin/chcon -F perm=x -F auid>=1000 -F auid!=unset -k perm_mod - Is it the case that the command does not return a line, or the line is commented out? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "restorecon" command with the following command: - -$ sudo auditctl -l | grep restorecon - --a always,exit -F path=/usr/sbin/restorecon -F perm=x -F auid>=1000 -F auid!=unset -k privileged-restorecon - Is it the case that the command does not return a line, or the line is commented out? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "semanage" command with the following command: - -$ sudo auditctl -l | grep semanage - --a always,exit -F path=/usr/sbin/semanage -F perm=x -F auid>=1000 -F auid!=unset -k privileged-unix-update - Is it the case that the command does not return a line, or the line is commented out? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "setfiles" command with the following command: - -$ sudo auditctl -l | grep setfiles - --a always,exit -F path=/usr/sbin/setfiles -F perm=x -F auid>=1000 -F auid!=unset -k privileged-unix-update - Is it the case that the command does not return a line, or the line is commented out? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "setsebool" command with the following command: - -$ sudo auditctl -l | grep setsebool - --a always,exit -F path=/usr/sbin/setsebool -F perm=x -F auid>=1000 -F auid!=unset -k privileged - Is it the case that the command does not return a line, or the line is commented out? - - - - To verify that execution of the command is being audited, run the following command: -$ sudo grep "path=/usr/sbin/seunshare" /etc/audit/audit.rules /etc/audit/rules.d/* -The output should return something similar to: --a always,exit -F path=/usr/sbin/seunshare -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged - Is it the case that ? - - - - To determine if the system is configured to audit calls to the -rmdir system call, run the following command: -$ sudo grep "rmdir" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. -To determine if the system is configured to audit calls to the -unlink system call, run the following command: -$ sudo grep "unlink" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. -To determine if the system is configured to audit calls to the -unlinkat system call, run the following command: -$ sudo grep "unlinkat" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. -To determine if the system is configured to audit calls to the -rename system call, run the following command: -$ sudo grep "rename" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. -To determine if the system is configured to audit calls to the -renameat system call, run the following command: -$ sudo grep "renameat" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. - Is it the case that no line is returned? - - - - To determine if the system is configured to audit calls to the -rename system call, run the following command: -$ sudo grep "rename" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. - - Is it the case that no line is returned? - - - - To determine if the system is configured to audit calls to the -renameat system call, run the following command: -$ sudo grep "renameat" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. - - Is it the case that no line is returned? - - - - To determine if the system is configured to audit calls to the -rmdir system call, run the following command: -$ sudo grep "rmdir" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. - - Is it the case that no line is returned? - - - - To determine if the system is configured to audit calls to the -unlink system call, run the following command: -$ sudo grep "unlink" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. - - Is it the case that no line is returned? - - - - To determine if the system is configured to audit calls to the -unlinkat system call, run the following command: -$ sudo grep "unlinkat" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. - - Is it the case that no line is returned? - - - - To verify that the audit system collects unauthorized file accesses, run the following commands: -$ sudo grep EACCES /etc/audit/audit.rules -$ sudo grep EPERM /etc/audit/audit.rules - Is it the case that 32-bit and 64-bit system calls to creat, open, openat, open_by_handle_at, truncate, and ftruncate are not audited during EACCES and EPERM? - - - - Verify Oracle Linux 9 generates an audit record for unsuccessful attempts to use the creat system call. - -If the auditd daemon is configured to use the "augenrules" program to to read audit rules during daemon startup (the default), run the following command: - -$ sudo grep -r creat /etc/audit/rules.d - -If the auditd daemon is configured to use the "auditctl" utility to read audit rules during daemon startup, run the following command: - -$ sudo grep creat /etc/audit/audit.rules - -The output should be the following: - --a always,exit -F arch=b32 -S creat -F exit=-EPERM -F auid>=1000 -F auid!=unset -k access --a always,exit -F arch=b64 -S creat -F exit=-EPERM -F auid>=1000 -F auid!=unset -k access --a always,exit -F arch=b32 -S creat -F exit=-EACCES -F auid>=1000 -F auid!=unset -k access --a always,exit -F arch=b64 -S creat -F exit=-EACCES -F auid>=1000 -F auid!=unset -k access - Is it the case that the command does not return a line, or the line is commented out? - - - - Verify Oracle Linux 9 generates an audit record for unsuccessful attempts to use the ftruncate system call. - -If the auditd daemon is configured to use the "augenrules" program to to read audit rules during daemon startup (the default), run the following command: - -$ sudo grep -r ftruncate /etc/audit/rules.d - -If the auditd daemon is configured to use the "auditctl" utility to read audit rules during daemon startup, run the following command: - -$ sudo grep ftruncate /etc/audit/audit.rules - -The output should be the following: - --a always,exit -F arch=b32 -S ftruncate -F exit=-EPERM -F auid>=1000 -F auid!=unset -k access --a always,exit -F arch=b64 -S ftruncate -F exit=-EPERM -F auid>=1000 -F auid!=unset -k access --a always,exit -F arch=b32 -S ftruncate -F exit=-EACCES -F auid>=1000 -F auid!=unset -k access --a always,exit -F arch=b64 -S ftruncate -F exit=-EACCES -F auid>=1000 -F auid!=unset -k access - Is it the case that the command does not return a line, or the line is commented out? - - - - Verify Oracle Linux 9 generates an audit record for unsuccessful attempts to use the open system call. - -If the auditd daemon is configured to use the "augenrules" program to to read audit rules during daemon startup (the default), run the following command: - -$ sudo grep -r open /etc/audit/rules.d - -If the auditd daemon is configured to use the "auditctl" utility to read audit rules during daemon startup, run the following command: - -$ sudo grep open /etc/audit/audit.rules - -The output should be the following: - --a always,exit -F arch=b32 -S open -F exit=-EPERM -F auid>=1000 -F auid!=unset -k access --a always,exit -F arch=b64 -S open -F exit=-EPERM -F auid>=1000 -F auid!=unset -k access --a always,exit -F arch=b32 -S open -F exit=-EACCES -F auid>=1000 -F auid!=unset -k access --a always,exit -F arch=b64 -S open -F exit=-EACCES -F auid>=1000 -F auid!=unset -k access - Is it the case that the command does not return a line, or the line is commented out? - - - - Verify Oracle Linux 9 generates an audit record for unsuccessful attempts to use the open_by_handle_at system call. - -If the auditd daemon is configured to use the "augenrules" program to to read audit rules during daemon startup (the default), run the following command: - -$ sudo grep -r open_by_handle_at /etc/audit/rules.d - -If the auditd daemon is configured to use the "auditctl" utility to read audit rules during daemon startup, run the following command: - -$ sudo grep open_by_handle_at /etc/audit/audit.rules - -The output should be the following: - --a always,exit -F arch=b32 -S open_by_handle_at -F exit=-EPERM -F auid>=1000 -F auid!=unset -k access --a always,exit -F arch=b64 -S open_by_handle_at -F exit=-EPERM -F auid>=1000 -F auid!=unset -k access --a always,exit -F arch=b32 -S open_by_handle_at -F exit=-EACCES -F auid>=1000 -F auid!=unset -k access --a always,exit -F arch=b64 -S open_by_handle_at -F exit=-EACCES -F auid>=1000 -F auid!=unset -k access - Is it the case that the command does not return a line, or the line is commented out? - - - - Verify Oracle Linux 9 generates an audit record for unsuccessful attempts to use the openat system call. - -If the auditd daemon is configured to use the "augenrules" program to to read audit rules during daemon startup (the default), run the following command: - -$ sudo grep -r openat /etc/audit/rules.d - -If the auditd daemon is configured to use the "auditctl" utility to read audit rules during daemon startup, run the following command: - -$ sudo grep openat /etc/audit/audit.rules - -The output should be the following: - --a always,exit -F arch=b32 -S openat -F exit=-EPERM -F auid>=1000 -F auid!=unset -k access --a always,exit -F arch=b64 -S openat -F exit=-EPERM -F auid>=1000 -F auid!=unset -k access --a always,exit -F arch=b32 -S openat -F exit=-EACCES -F auid>=1000 -F auid!=unset -k access --a always,exit -F arch=b64 -S openat -F exit=-EACCES -F auid>=1000 -F auid!=unset -k access - Is it the case that the command does not return a line, or the line is commented out? - - - - Verify Oracle Linux 9 generates an audit record for unsuccessful attempts to use the rename system call. - -If the auditd daemon is configured to use the "augenrules" program to to read audit rules during daemon startup (the default), run the following command: - -$ sudo grep -r rename /etc/audit/rules.d - -If the auditd daemon is configured to use the "auditctl" utility to read audit rules during daemon startup, run the following command: - -$ sudo grep rename /etc/audit/audit.rules - -The output should be the following: - --a always,exit -F arch=b32 -S rename -F exit=-EPERM -F auid>=1000 -F auid!=unset -k unsuccessful-delete --a always,exit -F arch=b64 -S rename -F exit=-EPERM -F auid>=1000 -F auid!=unset -k unsuccessful-delete --a always,exit -F arch=b32 -S rename -F exit=-EACCES -F auid>=1000 -F auid!=unset -k unsuccessful-delete --a always,exit -F arch=b64 -S rename -F exit=-EACCES -F auid>=1000 -F auid!=unset -k unsuccessful-delete - Is it the case that the command does not return a line, or the line is commented out? - - - - Verify Oracle Linux 9 generates an audit record for unsuccessful attempts to use the renameat system call. - -If the auditd daemon is configured to use the "augenrules" program to to read audit rules during daemon startup (the default), run the following command: - -$ sudo grep -r renameat /etc/audit/rules.d - -If the auditd daemon is configured to use the "auditctl" utility to read audit rules during daemon startup, run the following command: - -$ sudo grep renameat /etc/audit/audit.rules - -The output should be the following: - --a always,exit -F arch=b32 -S renameat -F exit=-EPERM -F auid>=1000 -F auid!=unset -k unsuccessful-delete --a always,exit -F arch=b64 -S renameat -F exit=-EPERM -F auid>=1000 -F auid!=unset -k unsuccessful-delete --a always,exit -F arch=b32 -S renameat -F exit=-EACCES -F auid>=1000 -F auid!=unset -k unsuccessful-delete --a always,exit -F arch=b64 -S renameat -F exit=-EACCES -F auid>=1000 -F auid!=unset -k unsuccessful-delete - Is it the case that the command does not return a line, or the line is commented out? - - - - Verify Oracle Linux 9 generates an audit record for unsuccessful attempts to use the truncate system call. - -If the auditd daemon is configured to use the "augenrules" program to to read audit rules during daemon startup (the default), run the following command: - -$ sudo grep -r truncate /etc/audit/rules.d - -If the auditd daemon is configured to use the "auditctl" utility to read audit rules during daemon startup, run the following command: - -$ sudo grep truncate /etc/audit/audit.rules - -The output should be the following: - --a always,exit -F arch=b32 -S truncate -F exit=-EPERM -F auid>=1000 -F auid!=unset -k access --a always,exit -F arch=b64 -S truncate -F exit=-EPERM -F auid>=1000 -F auid!=unset -k access --a always,exit -F arch=b32 -S truncate -F exit=-EACCES -F auid>=1000 -F auid!=unset -k access --a always,exit -F arch=b64 -S truncate -F exit=-EACCES -F auid>=1000 -F auid!=unset -k access - Is it the case that the command does not return a line, or the line is commented out? - - - - Verify Oracle Linux 9 generates an audit record for unsuccessful attempts to use the unlink system call. - -If the auditd daemon is configured to use the "augenrules" program to to read audit rules during daemon startup (the default), run the following command: - -$ sudo grep -r unlink /etc/audit/rules.d - -If the auditd daemon is configured to use the "auditctl" utility to read audit rules during daemon startup, run the following command: - -$ sudo grep unlink /etc/audit/audit.rules - -The output should be the following: - --a always,exit -F arch=b32 -S unlink -F exit=-EPERM -F auid>=1000 -F auid!=unset -k unsuccessful-delete --a always,exit -F arch=b64 -S unlink -F exit=-EPERM -F auid>=1000 -F auid!=unset -k unsuccessful-delete --a always,exit -F arch=b32 -S unlink -F exit=-EACCES -F auid>=1000 -F auid!=unset -k unsuccessful-delete --a always,exit -F arch=b64 -S unlink -F exit=-EACCES -F auid>=1000 -F auid!=unset -k unsuccessful-delete - Is it the case that the command does not return a line, or the line is commented out? - - - - Verify Oracle Linux 9 generates an audit record for unsuccessful attempts to use the unlinkat system call. - -If the auditd daemon is configured to use the "augenrules" program to to read audit rules during daemon startup (the default), run the following command: - -$ sudo grep -r unlinkat /etc/audit/rules.d - -If the auditd daemon is configured to use the "auditctl" utility to read audit rules during daemon startup, run the following command: - -$ sudo grep unlinkat /etc/audit/audit.rules - -The output should be the following: - --a always,exit -F arch=b32 -S unlinkat -F exit=-EPERM -F auid>=1000 -F auid!=unset -k unsuccessful-delete --a always,exit -F arch=b64 -S unlinkat -F exit=-EPERM -F auid>=1000 -F auid!=unset -k unsuccessful-delete --a always,exit -F arch=b32 -S unlinkat -F exit=-EACCES -F auid>=1000 -F auid!=unset -k unsuccessful-delete --a always,exit -F arch=b64 -S unlinkat -F exit=-EACCES -F auid>=1000 -F auid!=unset -k unsuccessful-delete - Is it the case that the command does not return a line, or the line is commented out? - - - - To determine if the system is configured to audit calls to the -init_module system call, run the following command: -$ sudo grep "init_module" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. -To determine if the system is configured to audit calls to the -delete_module system call, run the following command: -$ sudo grep "delete_module" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. - Is it the case that no line is returned? - - - - To determine if the system is configured to audit calls to the -delete_module system call, run the following command: -$ sudo grep "delete_module" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. - - Is it the case that no line is returned? - - - - To determine if the system is configured to audit calls to the -finit_module system call, run the following command: -$ sudo grep "finit_module" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. - - Is it the case that no line is returned? - - - - To determine if the system is configured to audit calls to the -init_module system call, run the following command: -$ sudo grep "init_module" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. - - Is it the case that no line is returned? - - - - Verify Oracle Linux 9 generates audit records for all account creations, modifications, disabling, and termination events that affect "/etc/security/opasswd" with the following command: - -$ sudo auditctl -l | grep /var/log/faillock - --w /var/log/faillock -p wa -k logins - Is it the case that the command does not return a line, or the line is commented out? - - - - Verify Oracle Linux 9 generates audit records for all account creations, modifications, disabling, and termination events that affect "/var/log/lastlog" with the following command: - -$ sudo auditctl -l | grep /var/log/lastlog - --w /var/log/lastlog -p wa -k logins - Is it the case that the command does not return a line, or the line is commented out? - - - - Verify Oracle Linux 9 generates audit records for all account creations, modifications, disabling, and termination events that affect "/var/log/tallylog" with the following command: - -$ sudo auditctl -l | grep /var/log/tallylog - --w /var/log/tallylog -p wa -k logins - Is it the case that the command does not return a line, or the line is commented out? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "init" command with the following command: - -$ sudo auditctl -l | grep init - --a always,exit -F path=/init -F perm=x -F auid>=1000 -F auid!=unset -k privileged-init - Is it the case that the command does not return a line, or the line is commented out? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "poweroff" command with the following command: - -$ sudo auditctl -l | grep poweroff - --a always,exit -F path=/poweroff -F perm=x -F auid>=1000 -F auid!=unset -k privileged-poweroff - Is it the case that the command does not return a line, or the line is commented out? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "reboot" command with the following command: - -$ sudo auditctl -l | grep reboot - --a always,exit -F path=/reboot -F perm=x -F auid>=1000 -F auid!=unset -k privileged-reboot - Is it the case that the command does not return a line, or the line is commented out? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "shutdown" command with the following command: - -$ sudo auditctl -l | grep shutdown - --a always,exit -F path=/shutdown -F perm=x -F auid>=1000 -F auid!=unset -k privileged-shutdown - Is it the case that the command does not return a line, or the line is commented out? - - - - To verify that auditing of privileged command use is configured, run the following command -to search privileged commands in relevant partitions and check if they are covered by auditd -rules: - -FILTER_NODEV=$(awk '/nodev/ { print $2 }' /proc/filesystems | paste -sd,) -PARTITIONS=$(findmnt -n -l -k -it $FILTER_NODEV | grep -Pv "noexec|nosuid" | awk '{ print $1 }') -for PARTITION in $PARTITIONS; do - for PRIV_CMD in $(find "${PARTITION}" -xdev -perm /6000 -type f 2>/dev/null); do - grep -qr "${PRIV_CMD}" /etc/audit/rules.d /etc/audit/audit.rules && - printf "OK: ${PRIV_CMD}\n" || printf "WARNING - rule not found for: ${PRIV_CMD}\n" - done -done - -The output should not contain any WARNING. - Is it the case that any setuid or setgid programs doesn't have a line in the audit rules? - - - - To verify that auditing of privileged command use is configured, run the -following command: -$ sudo grep '\bat\b' /etc/audit/audit.rules /etc/audit/rules.d/* -It should return a relevant line in the audit rules. - Is it the case that the command does not return a line, or the line is commented out? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "chage" command with the following command: - -$ sudo auditctl -l | grep chage - --a always,exit -F path=/usr/bin/chage -F perm=x -F auid>=1000 -F auid!=unset -k privileged-chage - Is it the case that the command does not return a line, or the line is commented out? - - - - If the system is not configured to audit time changes, this is a finding. -If the system is 64-bit only, this is not applicable -ocil: | -To determine if the system is configured to audit calls to the -stime system call, run the following command: -$ sudo grep "stime" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. - Is it the case that no line is returned? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "chsh" command with the following command: - -$ sudo auditctl -l | grep chsh - --a always,exit -F path=/usr/bin/chsh -F perm=x -F auid>=1000 -F auid!=unset -k privileged-chsh - Is it the case that the command does not return a line, or the line is commented out? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "crontab" command with the following command: - -$ sudo auditctl -l | grep crontab - --a always,exit -F path=/usr/bin/crontab -F perm=x -F auid>=1000 -F auid!=unset -k privileged-crontab - Is it the case that the command does not return a line, or the line is commented out? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "gpasswd" command with the following command: - -$ sudo auditctl -l | grep gpasswd - --a always,exit -F path=/usr/bin/gpasswd -F perm=x -F auid>=1000 -F auid!=unset -k privileged-gpasswd - Is it the case that the command does not return a line, or the line is commented out? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "kmod" command with the following command: - -$ sudo auditctl -l | grep kmod - --a always,exit -F path=/usr/bin/kmod -F perm=x -F auid>=1000 -F auid!=unset -k privileged-kmod - Is it the case that the command does not return a line, or the line is commented out? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "mount" command with the following command: - -$ sudo auditctl -l | grep mount - --a always,exit -F path=/usr/bin/mount -F perm=x -F auid>=1000 -F auid!=unset -k privileged-mount - Is it the case that the command does not return a line, or the line is commented out? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "newgrp" command with the following command: - -$ sudo auditctl -l | grep newgrp - --a always,exit -F path=/usr/bin/newgrp -F perm=x -F auid>=1000 -F auid!=unset -k privileged-newgrp - Is it the case that the command does not return a line, or the line is commented out? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "pam_timestamp_check" command with the following command: - -$ sudo auditctl -l | grep pam_timestamp_check - --a always,exit -F path=/usr/sbin/pam_timestamp_check -F perm=x -F auid>=1000 -F auid!=unset -k privileged-pam_timestamp_check - Is it the case that the command does not return a line, or the line is commented out? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "passwd" command with the following command: - -$ sudo auditctl -l | grep passwd - --a always,exit -F path=/usr/bin/passwd -F perm=x -F auid>=1000 -F auid!=unset -k privileged-passwd - Is it the case that the command does not return a line, or the line is commented out? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "postdrop" command with the following command: - -$ sudo auditctl -l | grep postdrop - --a always,exit -F path=/usr/bin/postdrop -F perm=x -F auid>=1000 -F auid!=unset -k privileged-postdrop - Is it the case that the command does not return a line, or the line is commented out? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "postqueue" command with the following command: - -$ sudo auditctl -l | grep postqueue - --a always,exit -F path=/usr/bin/postqueue -F perm=x -F auid>=1000 -F auid!=unset -k privileged-postqueue - Is it the case that the command does not return a line, or the line is commented out? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "pt_chown" command with the following command: - -$ sudo auditctl -l | grep pt_chown - --a always,exit -F path=/usr/libexec/pt_chown -F perm=x -F auid>=1000 -F auid!=unset -k privileged-pt_chown - Is it the case that the command does not return a line, or the line is commented out? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "ssh-agent" command with the following command: - -$ sudo auditctl -l | grep ssh-agent - --a always,exit -F path=/usr/bin/ssh-agent -F perm=x -F auid>=1000 -F auid!=unset -k privileged-ssh-agent - Is it the case that the command does not return a line, or the line is commented out? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "ssh-keysign" command with the following command: - -$ sudo auditctl -l | grep ssh-keysign - --a always,exit -F path=/usr/libexec/openssh/ssh-keysign -F perm=x -F auid>=1000 -F auid!=unset -k privileged-ssh-keysign - Is it the case that the command does not return a line, or the line is commented out? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "su" command with the following command: - -$ sudo auditctl -l | grep su - --a always,exit -F path=/usr/bin/su -F perm=x -F auid>=1000 -F auid!=unset -k privileged-su - Is it the case that the command does not return a line, or the line is commented out? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "sudo" command with the following command: - -$ sudo auditctl -l | grep sudo - --a always,exit -F path=/usr/bin/sudo -F perm=x -F auid>=1000 -F auid!=unset -k privileged-sudo - Is it the case that the command does not return a line, or the line is commented out? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "sudoedit" command with the following command: - -$ sudo auditctl -l | grep sudoedit - --a always,exit -F path=/usr/bin/sudoedit -F perm=x -F auid>=1000 -F auid!=unset -k privileged-sudoedit - Is it the case that the command does not return a line, or the line is commented out? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "umount" command with the following command: - -$ sudo auditctl -l | grep umount - --a always,exit -F path=/usr/bin/umount -F perm=x -F auid>=1000 -F auid!=unset -k privileged-umount - Is it the case that the command does not return a line, or the line is commented out? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "unix_chkpwd" command with the following command: - -$ sudo auditctl -l | grep unix_chkpwd - --a always,exit -F path=/usr/bin/unix_chkpwd -F perm=x -F auid>=1000 -F auid!=unset -k privileged-unix_chkpwd - Is it the case that the command does not return a line, or the line is commented out? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "unix_update" command with the following command: - -$ sudo auditctl -l | grep unix_update - --a always,exit -F path=/usr/bin/unix_update -F perm=x -F auid>=1000 -F auid!=unset -k privileged-unix_update - Is it the case that the command does not return a line, or the line is commented out? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "userhelper" command with the following command: - -$ sudo auditctl -l | grep userhelper - --a always,exit -F path=/usr/bin/userhelper -F perm=x -F auid>=1000 -F auid!=unset -k privileged-userhelper - Is it the case that the command does not return a line, or the line is commented out? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "usermod" command with the following command: - -$ sudo auditctl -l | grep usermod - --a always,exit -F path=/usr/bin/usermod -F perm=x -F auid>=1000 -F auid!=unset -k privileged-usermod - Is it the case that the command does not return a line, or the line is commented out? - - - - To verify that auditing of privileged command use is configured, run the -following command: -$ sudo grep usernetctl /etc/audit/audit.rules /etc/audit/rules.d/* -It should return a relevant line in the audit rules. - Is it the case that the command does not return a line, or the line is commented out? - - - - To determine if the system is configured to audit calls to the -adjtimex system call, run the following command: -$ sudo grep "adjtimex" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. - - Is it the case that no line is returned? - - - - To determine if the system is configured to audit calls to the -clock_settime system call, run the following command: -$ sudo grep "clock_settime" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. - - Is it the case that no line is returned? - - - - To determine if the system is configured to audit calls to the -settimeofday system call, run the following command: -$ sudo grep "settimeofday" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. - - Is it the case that no line is returned? - - - - To determine if the system is configured to audit attempts to -alter time via the /etc/localtime file, run the following -command: -$ sudo auditctl -l | grep "watch=/etc/localtime" -If the system is configured to audit this activity, it will return a line. - Is it the case that the system is not configured to audit time changes? - - - - Verify the audit system prevents unauthorized changes with the following command: - -$ sudo grep "^\s*[^#]" /etc/audit/audit.rules | tail -1 --e 2 - - Is it the case that the audit system is not set to be immutable by adding the "-e 2" option to the end of "/etc/audit/audit.rules"? - - - - To determine if the system is configured to audit changes to its SELinux -configuration files, run the following command: -$ sudo auditctl -l | grep "dir=/etc/selinux" -If the system is configured to watch for changes to its SELinux -configuration, a line should be returned (including -perm=wa indicating permissions that are watched). - Is it the case that the system is not configured to audit attempts to change the MAC policy? - - - - To determine if the system is configured to audit changes to its SELinux -configuration files, run the following command: -$ sudo auditctl -l | grep "dir=/usr/share/selinux" -If the system is configured to watch for changes to its SELinux -configuration, a line should be returned (including -perm=wa indicating permissions that are watched). - Is it the case that the system is not configured to audit attempts to change the MAC policy? - - - - To determine if the system is configured to audit calls to the -mount system call, run the following command: -$ sudo grep "mount" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. - - Is it the case that no line is returned? - - - - To determine if the system is configured to audit changes to its network configuration, -run the following command: -auditctl -l | grep -E '(/etc/issue|/etc/issue.net|/etc/hosts|/etc/sysconfig/network)' -If the system is configured to watch for network configuration changes, a line should be returned for -each file specified (and perm=wa should be indicated for each). - Is it the case that the system is not configured to audit changes of the network configuration? - - - - Verify Oracle Linux 9 generates audit records for all account creations, modifications, disabling, and termination events that affect "/etc/sudoers" with the following command: - -$ sudo auditctl -l | grep /etc/sudoers - --w /etc/sudoers -p wa -k identity - Is it the case that the command does not return a line, or the line is commented out? - - - - Verify Oracle Linux 9 generates audit records for all account creations, modifications, disabling, and termination events that affect "/etc/sudoers.d/" with the following command: - -$ sudo auditctl -l | grep/etc/sudoers.d - --w /etc/sudoers.d/ -p wa -k identity - Is it the case that the command does not return a line, or the line is commented out? - - - - Verify Oracle Linux 9 audits the execution of privileged functions. - -Check if Oracle Linux 9 is configured to audit the execution of the "execve" system call using the following command: - -$ sudo grep execve /etc/audit/audit.rules - -The output should be the following: - - --a always,exit -F arch=b32 -S execve -C uid!=euid -F euid=0 -k setuid --a always,exit -F arch=b64 -S execve -C uid!=euid -F euid=0 -k setuid --a always,exit -F arch=b32 -S execve -C gid!=egid -F egid=0 -k setgid --a always,exit -F arch=b64 -S execve -C gid!=egid -F egid=0 -k setgid - Is it the case that the command does not return all lines, or the lines are commented out? - - - - To verify that auditing is configured for system administrator actions, run the following command: -$ sudo auditctl -l | grep "watch=/etc/sudoers\|watch=/etc/sudoers.d\|-w /etc/sudoers\|-w /etc/sudoers.d" - Is it the case that there is not output? - - - - To verify that the system will shutdown when auditd fails, -run the following command: -$ sudo grep "\-f " /etc/audit/audit.rules -The output should contain: --f - Is it the case that the system is not configured to shutdown on auditd failures? - - - - To determine if the system is configured to audit account changes, -run the following command: -auditctl -l | grep -E '(/etc/passwd|/etc/shadow|/etc/group|/etc/gshadow|/etc/security/opasswd)' -If the system is configured to watch for account changes, lines should be returned for -each file specified (and with perm=wa for each). - Is it the case that the system is not configured to audit account changes? - - - - Verify Oracle Linux 9 generates audit records for all account creations, modifications, disabling, and termination events that affect "/etc/group" with the following command: - -$ sudo auditctl -l | grep -E '(/etc/group)' - --w /etc/group -p wa -k identity - Is it the case that the command does not return a line, or the line is commented out? - - - - Verify Oracle Linux 9 generates audit records for all account creations, modifications, disabling, and termination events that affect "/etc/gshadow" with the following command: - -$ sudo auditctl -l | grep -E '(/etc/gshadow)' - --w /etc/gshadow -p wa -k identity - -If the command does not return a line, or the line is commented out, this is a finding. - Is it the case that the system is not configured to audit account changes? - - - - Verify Oracle Linux 9 generates audit records for all account creations, modifications, disabling, and termination events that affect "/etc/security/opasswd" with the following command: - -$ sudo auditctl -l | grep -E '(/etc/security/opasswd)' - --w /etc/security/opasswd -p wa -k identity - Is it the case that the command does not return a line, or the line is commented out? - - - - Verify Oracle Linux 9 generates audit records for all account creations, modifications, disabling, and termination events that affect "/etc/passwd" with the following command: - -$ sudo auditctl -l | grep -E '(/etc/passwd)' - --w /etc/passwd -p wa -k identity - Is it the case that the command does not return a line, or the line is commented out? - - - - Verify Oracle Linux 9 generates audit records for all account creations, modifications, disabling, and termination events that affect "/etc/passwd with the following command: - -$ sudo auditctl -l | grep -E '(/etc/shadow)' - --w /etc/shadow -p wa -k identity - Is it the case that command does not return a line, or the line is commented out? - - - - To determine if the system is configured to audit accesses to -/var/log/audit directory, run the following command: -$ sudo grep "dir=/var/log/audit" /etc/audit/audit.rules -If the system is configured to audit this activity, it will return a line. - Is it the case that no line is returned? - - - - -Determine the audit log group by running the following command: - -$ sudo grep -P '^[ ]*log_group[ ]+=.*$' /etc/audit/auditd.conf - -Then, check that all directories within the /var/log/audit directory are owned by the group specified as log_group or by root if the log_group is not specified. -Run the following command: - -$ sudo find /var/log/audit -type d -printf "%p %g\n" - -All listed directories must be owned by the log_group or by root if the log_group is not specified. - Is it the case that there is a directory owned by different group? - - - - Determine where the audit logs are stored with the following command: - -$ sudo grep -iw log_file /etc/audit/auditd.conf - -log_file = /var/log/audit/audit.log - -Determine the owner of the audit log directory by using the output of the above command -(default: "/var/log/audit/"). Run the following command with the correct audit log directory -path: - -$ sudo ls -ld /var/log/audit - -drwx------ 2 root root 23 Jun 11 11:56 /var/log/audit - -The audit log directory must be owned by "root" - Is it the case that the directory is not owned by root? - - - - Verify the audit log directories have a correct mode or less permissive mode. - -Find the location of the audit logs: - -$ sudo grep "^log_file" /etc/audit/auditd.conf - - -Find the group that owns audit logs: - -$ sudo grep "^log_group" /etc/audit/auditd.conf - - -Run the following command to check the mode of the system audit logs: - -$ sudo stat -c "%a %n" [audit_log_directory] - -Replace "[audit_log_directory]" to the correct audit log directory path, by default this location is "/var/log/audit". - - -If the log_group is "root" or is not set, the correct permissions are 0700, otherwise they are 0750. - Is it the case that audit logs have a more permissive mode? - - - - Check group owners of the system audit logs. + Is it the case that /etc/crontab does not have unix mode -rw-------? + + + + To determine if !authenticate has not been configured for sudo, run the following command: +$ sudo grep -r \!authenticate /etc/sudoers /etc/sudoers.d/ +The command should return no output. + Is it the case that !authenticate is specified in the sudo config files? + + + + Check group owners of the system audit logs. First, determine where the audit log file is located. @@ -237951,115 +257496,213 @@ $ sudo stat -c "%n %G" log_file The audit log file must be owned by the log_group or by root if the log_group is not specified. Is it the case that audit log files are owned by incorrect group? - - - - -To properly set the group owner of /etc/audit/, run the command: -$ sudo chgrp root /etc/audit/ + + + + Determine if "sudoers" file restricts sudo access run the following commands: +$ sudo grep -PR '^\s*ALL\s+ALL\=\(ALL\)\s+ALL\s*$' /etc/sudoers /etc/sudoers.d/* +$ sudo grep -PR '^\s*ALL\s+ALL\=\(ALL\:ALL\)\s+ALL\s*$' /etc/sudoers /etc/sudoers.d/* + Is it the case that either of the commands returned a line? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "init" command with the following command: -To properly set the group owner of /etc/audit/rules.d/, run the command: -$ sudo chgrp root /etc/audit/rules.d/ - Is it the case that ? - - - - -To properly set the owner of /etc/audit/, run the command: -$ sudo chown root /etc/audit/ +$ sudo auditctl -l | grep init -To properly set the owner of /etc/audit/rules.d/, run the command: -$ sudo chown root /etc/audit/rules.d/ - Is it the case that ? - - - - -To properly set the owner of /var/log/audit, run the command: -$ sudo chown root /var/log/audit +-a always,exit -F path=/init -F perm=x -F auid>=1000 -F auid!=unset -k privileged-init + Is it the case that the command does not return a line, or the line is commented out? + + + + To check the group ownership of /etc/group-, +run the command: +$ ls -lL /etc/group- +If properly configured, the output should indicate the following group-owner: +root + Is it the case that /etc/group- does not have a group owner of root? + + + + To verify that BIND uses the system crypto policy, check out that the BIND config file +/etc/named.conf contains the include "/etc/crypto-policies/back-ends/bind.config"; +directive: +$ sudo grep 'include "/etc/crypto-policies/back-ends/bind.config";' /etc/named.conf +Verify that the directive is at the bottom of the options section of the config file. + Is it the case that BIND is installed and the BIND config file doesn't contain the +<pre>include "/etc/crypto-policies/back-ends/bind.config";</pre> directive? + + + + The runtime status of the kernel.unprivileged_bpf_disabled +kernel parameter can be queried by running the following command: +$ sysctl kernel.unprivileged_bpf_disabled +The output of the command should indicate either: +kernel.unprivileged_bpf_disabled = 1 +or: +kernel.unprivileged_bpf_disabled = 2 +The output of the command should not indicate: +kernel.unprivileged_bpf_disabled = 0 -To properly set the owner of /var/log/audit/*, run the command: -$ sudo chown root /var/log/audit/* - Is it the case that ? - - - - Verify the audit logs are owned by "root". First, determine where the audit logs are stored with the following command: -$ sudo grep -iw log_file /etc/audit/auditd.conf -log_file = /var/log/audit/audit.log -Using the location of the audit log file, determine if the audit log is owned by "root" using the following command: -$ sudo stat -c "%n %U" /var/log/audit/audit.log -Audit logs must be owned by user root. -If the log_file isn't defined in /etc/audit/auditd.conf, check all files in /var/log/audit/ directory instead. - Is it the case that the audit log is not owned by root? - - - - -To properly set the permissions of /etc/audit/, run the command: -$ sudo chmod 0640 /etc/audit/ +The preferable way how to assure the runtime compliance is to have +correct persistent configuration, and rebooting the system. -To properly set the permissions of /etc/audit/rules.d/, run the command: -$ sudo chmod 0640 /etc/audit/rules.d/ - Is it the case that ? - - - - Run the following command to check the mode of the system audit logs: -$ sudo grep -iw log_file /etc/audit/auditd.conf -log_file=/var/log/audit/audit.log -$ sudo stat -c "%n %a" /var/log/audit/* -$ sudo ls -l /var/log/audit -Audit logs must be mode 0640 or less permissive. - Is it the case that any permissions are more permissive? - - - - To verify whether audispd plugin off-loads audit records onto a different -system or media from the system being audited, run the following command: +The persistent kernel parameter configuration is performed by specifying the appropriate +assignment in any file located in the /etc/sysctl.d directory. +Verify that there is not any existing incorrect configuration by executing the following command: +$ grep -r '^\s*\s*=' /etc/sysctl.conf /etc/sysctl.d +The command should not find any assignments other than: +kernel.unprivileged_bpf_disabled = 1 +or: +kernel.unprivileged_bpf_disabled = 2 -$ sudo grep -i remote_server /etc/audit/audisp-remote.conf +Duplicate assignments are not allowed. Empty output is allowed, because the system default is 2. + Is it the case that the kernel.unprivileged_bpf_disabled is not set to 1 or 2 or is configured to be 0? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "newgrp" command with the following command: -The output should return something similar to where REMOTE_SYSTEM -is an IP address or hostname: -remote_server = REMOTE_SYSTEM +$ sudo auditctl -l | grep newgrp -Determine which partition the audit records are being written to with the -following command: +-a always,exit -F path=/usr/bin/newgrp -F perm=x -F auid>=1000 -F auid!=unset -k privileged-newgrp + Is it the case that the command does not return a line, or the line is commented out? + + + + The runtime status of the fs.protected_regular kernel parameter can be queried +by running the following command: +$ sysctl fs.protected_regular +2. -$ sudo grep log_file /etc/audit/auditd.conf -log_file = /var/log/audit/audit.log + Is it the case that the correct value is not returned? + + + + -Check the size of the partition that audit records are written to with the -following command and verify whether it is sufficiently large: +Run the following command to determine the current status of the +auditd service: +$ sudo systemctl is-active auditd +If the service is running, it should return the following: active + Is it the case that the auditd service is not running? + + + + To check that the rsyncd service is disabled in system boot configuration, +run the following command: +$ sudo systemctl is-enabled rsyncd +Output should indicate the rsyncd service has either not been installed, +or has been disabled at all runlevels, as shown in the example below: +$ sudo systemctl is-enabled rsyncd disabled -$ sudo df -h /var/log/audit/ -/dev/sda2 24G 10.4G 13.6G 43% /var/log/audit - Is it the case that audispd is not sending logs to a remote system and the local partition has inadequate space? - - - - To verify the audispd's syslog plugin is active, run the following command: -$ sudo grep active /etc/audit/plugins.d/syslog.conf -If the plugin is active, the output will show yes. - Is it the case that it is not activated? - - - - Verify Oracle Linux 9 takes the appropriate action when an audit processing failure occurs. +Run the following command to verify rsyncd is not active (i.e. not running) through current runtime configuration: +$ sudo systemctl is-active rsyncd -Check that Oracle Linux 9 takes the appropriate action when an audit processing failure occurs with the following command: +If the service is not running the command will return the following output: +inactive -$ sudo grep disk_error_action /etc/audit/auditd.conf +The service will also be masked, to check that the rsyncd is masked, run the following command: +$ sudo systemctl show rsyncd | grep "LoadState\|UnitFileState" -disk_error_action = +If the service is masked the command will return the following outputs: -If the value of the "disk_error_action" option is not "SYSLOG", "SINGLE", or "HALT", or the line is commented out, ask the system administrator to indicate how the system takes appropriate action when an audit process failure occurs. - Is it the case that there is no evidence of appropriate action? - - - - Verify Oracle Linux 9 takes the appropriate action when an audit processing failure occurs. +LoadState=masked + +UnitFileState=masked + Is it the case that the "rsyncd" is loaded and not masked? + + + + To check the ownership of /etc/ipsec.d, +run the command: +$ ls -lL /etc/ipsec.d +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/ipsec.d does not have an owner of root? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_KEXEC /boot/config.* + + Configs with value 'n' are not explicitly set in the file, so either commented lines or no + lines should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine if the system is configured to audit calls to the +rmdir system call, run the following command: +$ sudo grep "rmdir" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. + + Is it the case that no line is returned? + + + + To determine if the system is configured to audit calls to the +adjtimex system call, run the following command: +$ sudo grep "adjtimex" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. + + Is it the case that no line is returned? + + + + To determine how the SSH daemon's IgnoreUserKnownHosts option is set, run the following command: + +$ sudo grep -i IgnoreUserKnownHosts /etc/ssh/sshd_config + +If a line indicating yes is returned, then the required value is set. + + Is it the case that the required value is not set? + + + + To check the ownership of /var/log, +run the command: +$ ls -lL /var/log +If properly configured, the output should indicate the following owner: +root + Is it the case that /var/log does not have an owner of root? + + + + # grep "^OPTIONS.*-u" /etc/sysconfig/chronyd | grep -v -e '-u\s*chrony\b' +returns no output + Is it the case that chronyd is not running under chrony user account? + + + + To determine how the SSH daemon's UsePAM option is set, run the following command: + +$ sudo grep -i UsePAM /etc/ssh/sshd_config + +If a line indicating yes is returned, then the required value is set. + + Is it the case that the required value is not set? + + + + Run the following command to ensure postfix accepts mail messages from only the local system: +$ grep inet_interfaces /etc/postfix/main.cf +If properly configured, the output should show only . + Is it the case that it does not? + + + + To check the ownership of /etc/sestatus.conf, +run the command: +$ ls -lL /etc/sestatus.conf +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/sestatus.conf does not have an owner of root? + + + + Verify Oracle Linux 9 takes the appropriate action when an audit processing failure occurs. Check that Oracle Linux 9 takes the appropriate action when an audit processing failure occurs with the following command: @@ -238069,300 +257712,141 @@ disk_error_action = HALT If the value of the "disk_error_action" option is not "SYSLOG", "SINGLE", or "HALT", or the line is commented out, ask the system administrator to indicate how the system takes appropriate action when an audit process failure occurs. Is it the case that there is no evidence of appropriate action? - - - - Verify Oracle Linux 9 takes the appropriate action when the audit storage volume is full. + + + + Verify Oracle Linux 9 is securely comparing internal information system clocks at a regular interval with an NTP server with the following command: +$ sudo grep maxpoll /etc/ntp.conf /etc/chrony.conf /etc/chrony.d/ +server [ntp.server.name] iburst maxpoll . + Is it the case that "maxpoll" has not been set to the value of "<sub idref="var_time_service_set_maxpoll" />", is commented out, or is missing? + + + + Verify the noexec option is configured for the /tmp mount point, + run the following command: + $ sudo mount | grep '\s/tmp\s' + . . . /tmp . . . noexec . . . -Check that Oracle Linux 9 takes the appropriate action when the audit storage volume is full with the following command: + Is it the case that the "/tmp" file system does not have the "noexec" option set? + + + + +Run the following command to determine if the ssh_sysadm_login SELinux boolean is disabled: +$ getsebool ssh_sysadm_login +If properly configured, the output should show the following: +ssh_sysadm_login --> off + Is it the case that ssh_sysadm_login is not disabled? + + + + To verify that auditing of privileged command use is configured, run the following command +to search privileged commands in relevant partitions and check if they are covered by auditd +rules: -$ sudo grep disk_full_action /etc/audit/auditd.conf +FILTER_NODEV=$(awk '/nodev/ { print $2 }' /proc/filesystems | paste -sd,) +PARTITIONS=$(findmnt -n -l -k -it $FILTER_NODEV | grep -Pv "noexec|nosuid" | awk '{ print $1 }') +for PARTITION in $PARTITIONS; do + for PRIV_CMD in $(find "${PARTITION}" -xdev -perm /6000 -type f 2>/dev/null); do + grep -qr "${PRIV_CMD}" /etc/audit/rules.d /etc/audit/audit.rules && + printf "OK: ${PRIV_CMD}\n" || printf "WARNING - rule not found for: ${PRIV_CMD}\n" + done +done -disk_full_action = +The output should not contain any WARNING. + Is it the case that any setuid or setgid programs doesn't have a line in the audit rules? + + + + To check the group ownership of /boot/System.map*, +run the command: +$ ls -lL /boot/System.map* +If properly configured, the output should indicate the following group-owner: +root + Is it the case that /boot/System.map* does not have a group owner of root? + + + + To verify the noexec option is configured for all NFS mounts, run the following command: +$ mount | grep nfs +All NFS mounts should show the noexec setting in parentheses. This is not applicable if NFS is +not implemented. + Is it the case that the setting does not show? + + + + To check if MaxStartups is configured, run the following command: +$ sudo grep -r ^[\s]*MaxStartups /etc/ssh/sshd_config* +If configured, this command should output the configuration. + Is it the case that maxstartups is not configured? + + + + Run the following command and verify remote servers are configured properly: +# grep -E "^(server|pool)" /etc/chrony.conf + Is it the case that a remote time server is not configured? + + + + To check the group ownership of /etc/nftables, +run the command: +$ ls -lL /etc/nftables +If properly configured, the output should indicate the following group-owner: +root + Is it the case that /etc/nftables does not have a group owner of root? + + + + To check the group ownership of /etc/cron.daily, +run the command: +$ ls -lL /etc/cron.daily +If properly configured, the output should indicate the following group-owner: +root + Is it the case that /etc/cron.daily does not have a group owner of root? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "unix_update" command with the following command: -If the value of the "disk_full_action" option is not "SYSLOG", "SINGLE", or "HALT", or the line is commented out, ask the system administrator to indicate how the system takes appropriate action when an audit storage volume is full. - Is it the case that there is no evidence of appropriate action? - - - - Verify Oracle Linux 9 takes the appropriate action when the audit storage volume is full. +$ sudo auditctl -l | grep unix_update -Check that Oracle Linux 9 takes the appropriate action when the audit storage volume is full with the following command: - -$ sudo grep disk_full_action /etc/audit/auditd.conf - -disk_full_action = - -If the value of the "disk_full_action" option is not "SYSLOG", "SINGLE", or "HALT", or the line is commented out, ask the system administrator to indicate how the system takes appropriate action when an audit storage volume is full. - Is it the case that there is no evidence of appropriate action? - - - - Verify that Oracle Linux 9 is configured to notify the SA and/or ISSO (at a minimum) in the event of an audit processing failure with the following command: - -$ sudo grep action_mail_acct /etc/audit/auditd.conf - -action_mail_acct = - Is it the case that the value of the "action_mail_acct" keyword is not set to "<sub idref="var_auditd_action_mail_acct" />" and/or other accounts for security personnel, the "action_mail_acct" keyword is missing, or the retuned line is commented out, ask the system administrator to indicate how they and the ISSO are notified of an audit process failure. If there is no evidence of the proper personnel being notified of an audit processing failure? - - - - Verify that Oracle Linux 9 is configured to take action in the event of allocated audit record storage volume reaches 95 percent of the repository maximum audit record storage capacity with the following command: - -$ sudo grep admin_space_left_action /etc/audit/auditd.conf - -admin_space_left_action = single - -If the value of the "admin_space_left_action" is not set to "single", or if the line is commented out, ask the System Administrator to indicate how the system is providing real-time alerts to the SA and ISSO. - Is it the case that there is no evidence that real-time alerts are configured on the system? - - - - Verify Oracle Linux 9 takes action when allocated audit record storage volume reaches 95 percent of the repository maximum audit record storage capacity with the following command: - -$ sudo grep -w admin_space_left /etc/audit/auditd.conf - -admin_space_left = % - -If the value of the "admin_space_left" keyword is not set to % of the storage volume allocated to audit logs, or if the line is commented out, ask the System Administrator to indicate how the system is taking action if the allocated storage is about to reach capacity. - Is it the case that the "admin_space_left" value is not configured to the correct value? - - - - Inspect /etc/audit/auditd.conf and locate the following line to -determine if the system is configured to synchronize audit event data -with the log files on the disk: -$ sudo grep flush /etc/audit/auditd.conf -flush = DATA -Acceptable values are DATA, and SYNC. The setting is -case-insensitive. - Is it the case that auditd is not configured to synchronously write audit event data to disk? - - - - Inspect /etc/audit/auditd.conf and locate the following line to -determine how much data the system will retain in each audit log file: -$ sudo grep max_log_file /etc/audit/auditd.conf -max_log_file = 6 - Is it the case that the system audit data threshold has not been properly configured? - - - - Verify that the SA and ISSO (at a minimum) are notified when the audit storage volume is full. - -Check which action Oracle Linux 9 takes when the audit storage volume is full with the following command: - -$ sudo grep max_log_file_action /etc/audit/auditd.conf -max_log_file_action = - Is it the case that the value of the "max_log_file_action" option is set to "ignore", "rotate", or "suspend", or the line is commented out? - - - - Verify Oracle Linux 9 takes the appropriate action when the audit files have reached maximum size. - -Check that Oracle Linux 9 takes the appropriate action when the audit files have reached maximum size with the following command: - -$ sudo grep max_log_file_action /etc/audit/auditd.conf - -max_log_file_action = - Is it the case that the value of the "max_log_file_action" option is not "ROTATE", "SINGLE", or the line is commented out, ask the system administrator to indicate how the system takes appropriate action when an audit storage volume is full. If there is no evidence of appropriate action? - - - - Inspect /etc/audit/auditd.conf and locate the following line to -determine how many logs the system is configured to retain after rotation: -$ sudo grep num_logs /etc/audit/auditd.conf -num_logs = 5 - Is it the case that the system log file retention has not been properly configured? - - - - Verify Oracle Linux 9 notifies the SA and ISSO (at a minimum) when allocated audit record storage volume reaches 75 percent of the repository maximum audit record storage capacity with the following command: - -$ sudo grep -w space_left_action /etc/audit/auditd.conf - -space_left_action = - -If the value of the "space_left_action" is not set to "", or if the line is commented out, ask the System Administrator to indicate how the system is providing real-time alerts to the SA and ISSO. - Is it the case that there is no evidence that real-time alerts are configured on the system? - - - - Verify Oracle Linux 9 takes action when allocated audit record storage volume reaches 75 percent of the repository maximum audit record storage capacity with the following command: +-a always,exit -F path=/usr/bin/unix_update -F perm=x -F auid>=1000 -F auid!=unset -k privileged-unix_update + Is it the case that the command does not return a line, or the line is commented out? + + + + Verify Oracle Linux 9 takes action when allocated audit record storage volume reaches 75 percent of the repository maximum audit record storage capacity with the following command: $ sudo grep -w space_left /etc/audit/auditd.conf space_left = % Is it the case that the value of the "space_left" keyword is not set to <sub idref="var_auditd_space_left_percentage" />% of the storage volume allocated to audit logs, or if the line is commented out, ask the System Administrator to indicate how the system is providing real-time alerts to the SA and ISSO. If the "space_left" value is not configured to the correct value? - - - - To verify that Audit Daemon is configured to flush to disk after -every records, run the following command: -$ sudo grep freq /etc/audit/auditd.conf -The output should return the following: -freq = - Is it the case that freq isn't set to <sub idref="var_auditd_freq" />? - - - - To verify that Audit Daemon is configured to include local events, run the -following command: -$ sudo grep local_events /etc/audit/auditd.conf -The output should return the following: -local_events = yes - Is it the case that local_events isn't set to yes? - - - - To verify that Audit Daemon is configured to resolve all uid, gid, syscall, -architecture, and socket address information before writing the event to disk, -run the following command: -$ sudo grep log_format /etc/audit/auditd.conf -The output should return the following: -log_format = ENRICHED - Is it the case that log_format isn't set to ENRICHED? - - - - To verify that Audit Daemon is configured to record the hostname -in audit events, run the following command: -$ sudo grep name_format /etc/audit/auditd.conf -The output should return the following: -name_format = hostname - Is it the case that name_format isn't set to hostname? - - - - Verify the audit system is configured to take an appropriate action when the internal event queue is full: -$ sudo grep -i overflow_action /etc/audit/auditd.conf + + + + +If the system is configured to prevent the loading of the usb-storage kernel module, +it will contain lines inside any file in /etc/modprobe.d or the deprecated /etc/modprobe.conf. +These lines instruct the module loading system to run another program (such as /bin/false) upon a module install event. -The output should contain overflow_action = syslog +These lines can also instruct the module loading system to ignore the usb-storage kernel module via blacklist keyword. -If the value of the "overflow_action" option is not set to syslog, -single, halt or the line is commented out, ask the System Administrator -to indicate how the audit logs are off-loaded to a different system or media. - Is it the case that auditd overflow action is not set correctly? - - - - To verify that Audit Daemon is configured to write logs to the disk, run the -following command: -$ sudo grep write_logs /etc/audit/auditd.conf -The output should return the following: -write_logs = yes - Is it the case that write_logs isn't set to yes? - - - - To verify that the Audit is correctly configured according to recommended rules, check the content of the file with the following command: -cat /etc/audit/rules.d/30-ospp-v42-3-access-failed.rules -The output has to be exactly as follows: -## Unsuccessful file access (any other opens) This has to go last. --a always,exit -F arch=b32 -S open,openat,openat2,open_by_handle_at -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-access --a always,exit -F arch=b64 -S open,openat,openat2,open_by_handle_at -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-access --a always,exit -F arch=b32 -S open,openat,openat2,open_by_handle_at -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-access --a always,exit -F arch=b64 -S open,openat,openat2,open_by_handle_at -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-access - Is it the case that the file does not exist or the content differs? - - - - To verify that the Audit is correctly configured according to recommended rules, check the content of the file with the following command: -cat /etc/audit/rules.d/30-ospp-v42-3-access-success.rules -The output has to be exactly as follows: -## Successful file access (any other opens) This has to go last. -## These next two are likely to result in a whole lot of events --a always,exit -F arch=b32 -S open,openat,openat2,open_by_handle_at -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-access --a always,exit -F arch=b64 -S open,openat,openat2,open_by_handle_at -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-access - Is it the case that the file does not exist or the content differs? - - - - To verify that the Audit is correctly configured according to recommended rules, check the content of the file with the following command: -cat /etc/audit/rules.d/10-base-config.rules -The output has to be exactly as follows: -## First rule - delete all --D +Run the following command to search for such lines in all files in /etc/modprobe.d and the deprecated /etc/modprobe.conf: +$ grep -r usb-storage /etc/modprobe.conf /etc/modprobe.d + Is it the case that no line is returned? + + + + To verify the number of rounds for the password hashing algorithm is configured, run the following command: +$ sudo grep rounds /etc/pam.d/password-auth +The output should show the following match: -## Increase the buffers to survive stress events. -## Make this bigger for busy systems --b 8192 - -## This determine how long to wait in burst of events ---backlog_wait_time 60000 - -## Set failure mode to syslog --f 1 - Is it the case that the file does not exist or the content differs? - - - - To verify that the Audit is correctly configured according to recommended rules, check the content of the file with the following command: -cat /etc/audit/rules.d/30-ospp-v42-1-create-failed.rules -The output has to be exactly as follows: -## Unsuccessful file creation (open with O_CREAT) --a always,exit -F arch=b32 -S openat,open_by_handle_at -F a2&0100 -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-create --a always,exit -F arch=b64 -S openat,open_by_handle_at -F a2&0100 -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-create --a always,exit -F arch=b32 -S open -F a1&0100 -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-create --a always,exit -F arch=b64 -S open -F a1&0100 -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-create --a always,exit -F arch=b32 -S creat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-create --a always,exit -F arch=b64 -S creat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-create --a always,exit -F arch=b32 -S openat,open_by_handle_at -F a2&0100 -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-create --a always,exit -F arch=b64 -S openat,open_by_handle_at -F a2&0100 -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-create --a always,exit -F arch=b32 -S open -F a1&0100 -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-create --a always,exit -F arch=b64 -S open -F a1&0100 -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-create --a always,exit -F arch=b32 -S creat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-create --a always,exit -F arch=b64 -S creat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-create - Is it the case that the file does not exist or the content differs? - - - - To verify that the Audit is correctly configured according to recommended rules, check the content of the file with the following command: -cat /etc/audit/rules.d/30-ospp-v42-1-create-success.rules -The output has to be exactly as follows: -## Successful file creation (open with O_CREAT) --a always,exit -F arch=b32 -S openat,open_by_handle_at -F a2&0100 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-create --a always,exit -F arch=b64 -S openat,open_by_handle_at -F a2&0100 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-create --a always,exit -F arch=b32 -S open -F a1&0100 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-create --a always,exit -F arch=b64 -S open -F a1&0100 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-create --a always,exit -F arch=b32 -S creat -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-create --a always,exit -F arch=b64 -S creat -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-create - Is it the case that the file does not exist or the content differs? - - - - To verify that the Audit is correctly configured according to recommended rules, check the content of the file with the following command: -cat /etc/audit/rules.d/30-ospp-v42-4-delete-failed.rules -The output has to be exactly as follows: -## Unsuccessful file delete --a always,exit -F arch=b32 -S unlink,unlinkat,rename,renameat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-delete --a always,exit -F arch=b64 -S unlink,unlinkat,rename,renameat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-delete --a always,exit -F arch=b32 -S unlink,unlinkat,rename,renameat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-delete --a always,exit -F arch=b64 -S unlink,unlinkat,rename,renameat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-delete - Is it the case that the file does not exist or the content differs? - - - - To verify that the Audit is correctly configured according to recommended rules, check the content of the file with the following command: -cat /etc/audit/rules.d/30-ospp-v42-4-delete-success.rules -The output has to be exactly as follows: -## Successful file delete --a always,exit -F arch=b32 -S unlink,unlinkat,rename,renameat -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-delete --a always,exit -F arch=b64 -S unlink,unlinkat,rename,renameat -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-delete - Is it the case that the file does not exist or the content differs? - - - - To verify that the Audit is correctly configured according to recommended rules, check the content of the file with the following command: -$ sudo cat /etc/audit/rules.d/11-loginuid.rules -The output has to be exactly as follows: -## Make the loginuid immutable. This prevents tampering with the auid. ---loginuid-immutable - Is it the case that the file does not exist or the content differs? - - - - To verify that the Audit is correctly configured according to recommended rules, check the content of the file with the following command: +password sufficient pam_unix.so sha512 rounds= + Is it the case that rounds is not set to <sub idref="var_password_pam_unix_rounds" /> or is commented out? + + + + To verify that the Audit is correctly configured according to recommended rules, check the content of the file with the following command: cat /etc/audit/rules.d/30-ospp-v42-2-modify-failed.rules The output has to be exactly as follows: ## Unsuccessful file modifications (open for write or truncate) @@ -238379,37 +257863,506 @@ The output has to be exactly as follows: -a always,exit -F arch=b32 -S truncate,ftruncate -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-modification -a always,exit -F arch=b64 -S truncate,ftruncate -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-modification Is it the case that the file does not exist or the content differs? - - - - To verify that the Audit is correctly configured according to recommended rules, check the content of the file with the following command: -cat /etc/audit/rules.d/30-ospp-v42-2-modify-success.rules + + + + Verify the noexec option is configured for the /var/log/audit mount point, + run the following command: + $ sudo mount | grep '\s/var/log/audit\s' + . . . /var/log/audit . . . noexec . . . + + Is it the case that the "/var/log/audit" file system does not have the "noexec" option set? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_ACPI_CUSTOM_METHOD /boot/config.* + + Configs with value 'n' are not explicitly set in the file, so either commented lines or no + lines should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine how the SSH daemon's PermitRootLogin option is set, run the following command: + +$ sudo grep -i PermitRootLogin /etc/ssh/sshd_config + +If a line indicating prohibit-password is returned, then the required value is set. + Is it the case that it is commented out or not configured properly? + + + + Verify that the default umask for all local interactive users is "077". + +Identify the locations of all local interactive user home directories by looking at the "/etc/passwd" file. + +Check all local interactive user initialization files for interactive users with the following command: + +Note: The example is for a system that is configured to create users home directories in the "/home" directory. + +$ sudo find /home -maxdepth 2 -type f -name ".[^.]*" -exec grep -iH -d skip --exclude=.bash_history umask {} \; + +/home/wadea/.bash_history:grep -i umask /etc/bashrc /etc/csh.cshrc /etc/profile +/home/wadea/.bash_history:grep -i umask /etc/login.defs + Is it the case that any local interactive user initialization files are found to have a umask statement that sets a value less restrictive than "077"? + + + + Verify the noexec option is configured for the /boot mount point, + run the following command: + $ sudo mount | grep '\s/boot\s' + . . . /boot . . . noexec . . . + + Is it the case that the "/boot" file system does not have the "noexec" option set? + + + + Run the following command to determine if the sssd package is installed: $ rpm -q sssd + Is it the case that the package is not installed? + + + + Run the following command to determine the current status of the dnf-automatic timer: $ sudo systemctl is-active dnf-automatic.timer If the timer is running, it should return the following: active + Is it the case that the dnf-automatic.timer is not enabled? + + + + To check the permissions of /etc/crypttab, +run the command: +$ ls -l /etc/crypttab +If properly configured, the output should indicate the following permissions: +0600 + Is it the case that /etc/crypttab does not have unix mode 0600? + + + + To verify that the Audit is correctly configured according to recommended rules, check the content of the file with the following command: +cat /etc/audit/rules.d/30-ospp-v42-6-owner-change-failed.rules The output has to be exactly as follows: -## Successful file modifications (open for write or truncate) --a always,exit -F arch=b32 -S openat,open_by_handle_at -F a2&01003 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-modification --a always,exit -F arch=b64 -S openat,open_by_handle_at -F a2&01003 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-modification --a always,exit -F arch=b32 -S open -F a1&01003 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-modification --a always,exit -F arch=b64 -S open -F a1&01003 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-modification --a always,exit -F arch=b32 -S truncate,ftruncate -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-modification --a always,exit -F arch=b64 -S truncate,ftruncate -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-modification +## Unsuccessful ownership change +-a always,exit -F arch=b32 -S lchown,fchown,chown,fchownat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-owner-change +-a always,exit -F arch=b64 -S lchown,fchown,chown,fchownat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-owner-change +-a always,exit -F arch=b32 -S lchown,fchown,chown,fchownat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-owner-change +-a always,exit -F arch=b64 -S lchown,fchown,chown,fchownat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-owner-change Is it the case that the file does not exist or the content differs? - - - - To verify that the Audit is correctly configured according to recommended rules, check the content of the file with the following command: -cat /etc/audit/rules.d/43-module-load.rules + + + + Verify the assigned home directories of all interactive users on the system exist with the following command: + +$ sudo pwck -r + +user 'mailnull': directory 'var/spool/mqueue' does not exist + +The output should not return any interactive users. + Is it the case that users home directory does not exist? + + + + Verify the USBGuard has a policy configured with the following command: + +$ usbguard list-rules + +allow id 1d6b:0001 serial + +If the command does not return results or an error is returned, ask the SA to indicate how unauthorized peripherals are being blocked. + Is it the case that there is no evidence that unauthorized peripherals are being blocked before establishing a connection? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_MODULE_SIG /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To check if compression is enabled or set correctly, run the +following command: +$ sudo grep Compression /etc/ssh/sshd_config +If configured properly, output should be no or delayed. + Is it the case that it is commented out, or is not set to no or delayed? + + + + Ensure there are no unconfined daemons running on the system, +the following command should produce no output: +$ sudo ps -eZ | grep "unconfined_service_t" + Is it the case that There are unconfined daemons running on the system? + + + + The following command will discover and print world-writable directories that +are not owned by root. Run it once for each local partition PART: +$ sudo find PART -xdev -type d -perm -0002 -uid +0 -print + Is it the case that there are world-writable directories not owned by root? + + + + If the system is not configured to audit time changes, this is a finding. +If the system is 64-bit only, this is not applicable +ocil: | +To determine if the system is configured to audit calls to the +stime system call, run the following command: +$ sudo grep "stime" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. + Is it the case that no line is returned? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "chcon" command with the following command: + +$ sudo auditctl -l | grep chcon + +-a always,exit -F path=/usr/bin/chcon -F perm=x -F auid>=1000 -F auid!=unset -k perm_mod + Is it the case that the command does not return a line, or the line is commented out? + + + + To verify that acquiring, saving, and processing core dumps is disabled, run the +following command: +$ systemctl status systemd-coredump.socket +The output should be similar to: +● systemd-coredump.socket + Loaded: masked (Reason: Unit systemd-coredump.socket is masked.) + Active: inactive (dead) ... + + Is it the case that unit systemd-coredump.socket is not masked or running? + + + + Verify the nosuid option is configured for the /home mount point, + run the following command: + $ sudo mount | grep '\s/home\s' + . . . /home . . . nosuid . . . + + Is it the case that the "/home" file system does not have the "nosuid" option set? + + + + The group-owner of all log files written by rsyslog should be +root. +These log files are determined by the second part of each Rule line in +/etc/rsyslog.conf and typically all appear in /var/log. +To see the group-owner of a given log file, run the following command: +$ ls -l LOGFILE + Is it the case that the group-owner is not correct? + + + + To check the permissions of /etc/iptables, +run the command: +$ ls -l /etc/iptables +If properly configured, the output should indicate the following permissions: +0700 + Is it the case that /etc/iptables does not have unix mode 0700? + + + + Inspect /etc/audit/auditd.conf and locate the following line to +determine if the system is configured to synchronize audit event data +with the log files on the disk: +$ sudo grep flush /etc/audit/auditd.conf +flush = DATA +Acceptable values are DATA, and SYNC. The setting is +case-insensitive. + Is it the case that auditd is not configured to synchronously write audit event data to disk? + + + + Verify the nosuid option is configured for the /var mount point, + run the following command: + $ sudo mount | grep '\s/var\s' + . . . /var . . . nosuid . . . + + Is it the case that the "/var" file system does not have the "nosuid" option set? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_DEBUG_SG /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_DEBUG_WX /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine how the SSH daemon's PermitUserEnvironment option is set, run the following command: + +$ sudo grep -i PermitUserEnvironment /etc/ssh/sshd_config + +If a line indicating no is returned, then the required value is set. + + Is it the case that the required value is not set? + + + + To verify that the Audit is correctly configured according to recommended rules, check the content of the file with the following command: +cat /etc/audit/rules.d/30-ospp-v42-3-access-success.rules The output has to be exactly as follows: -## These rules watch for kernel module insertion. By monitoring -## the syscall, we do not need any watches on programs. --a always,exit -F arch=b32 -S init_module,finit_module -F key=module-load --a always,exit -F arch=b64 -S init_module,finit_module -F key=module-load --a always,exit -F arch=b32 -S delete_module -F key=module-unload --a always,exit -F arch=b64 -S delete_module -F key=module-unload +## Successful file access (any other opens) This has to go last. +## These next two are likely to result in a whole lot of events +-a always,exit -F arch=b32 -S open,openat,openat2,open_by_handle_at -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-access +-a always,exit -F arch=b64 -S open,openat,openat2,open_by_handle_at -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-access Is it the case that the file does not exist or the content differs? - - - - To verify that the Audit is correctly configured according to recommended rules, check the content of the file with the following command: + + + + Run the following command to check for duplicate group names: +Check that the operating system contains no duplicate Group ID (GID) for interactive users by running the following command: + + cut -d : -f 3 /etc/group | uniq -d + +If output is produced, this is a finding. +Configure the operating system to contain no duplicate GIDs. +Edit the file "/etc/group" and provide each group that has a duplicate GID with a unique GID. + Is it the case that the system has duplicate group ids? + + + + Run the following command to determine if the s-nail package is installed: $ rpm -q s-nail + Is it the case that the package is not installed? + + + + To check the ownership of /etc/issue.net, +run the command: +$ ls -lL /etc/issue.net +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/issue.net does not have an owner of root? + + + + Verify the operating system authenticates the remote logging server for off-loading audit logs with the following command: + +$ sudo grep -i '$ActionSendStreamDriverAuthMode' /etc/rsyslog.conf /etc/rsyslog.d/*.conf +The output should be +$/etc/rsyslog.conf:$ActionSendStreamDriverAuthMode x509/name + Is it the case that $ActionSendStreamDriverAuthMode in /etc/rsyslog.conf is not set to x509/name? + + + + To check the ownership of /etc/ipsec.secrets, +run the command: +$ ls -lL /etc/ipsec.secrets +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/ipsec.secrets does not have an owner of root? + + + + The runtime status of the fs.protected_fifos kernel parameter can be queried +by running the following command: +$ sysctl fs.protected_fifos +2. + + Is it the case that the correct value is not returned? + + + + Verify that a separate file system/partition has been created for /var with the following command: + +$ mountpoint /var + + Is it the case that "/var is not a mountpoint" is returned? + + + + To check the ownership of /etc/ipsec.conf, +run the command: +$ ls -lL /etc/ipsec.conf +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/ipsec.conf does not have an owner of root? + + + + Verify the nosuid option is configured for the /var/log/audit mount point, + run the following command: + $ sudo mount | grep '\s/var/log/audit\s' + . . . /var/log/audit . . . nosuid . . . + + Is it the case that the "/var/log/audit" file system does not have the "nosuid" option set? + + + + To determine if NOPASSWD has been configured for sudo, run the following command: +$ sudo grep -ri nopasswd /etc/sudoers /etc/sudoers.d/ +The command should return no output. + Is it the case that nopasswd is specified in the sudo config files? + + + + Verify the nodev option is configured for the /var/tmp mount point, + run the following command: + $ sudo mount | grep '\s/var/tmp\s' + . . . /var/tmp . . . nodev . . . + + Is it the case that the "/var/tmp" file system does not have the "nodev" option set? + + + + Verify that the shadow password suite configuration is set to encrypt password with a FIPS 140-3 approved cryptographic hashing algorithm. + + +Check the hashing algorithm that is being used to hash passwords with the following command: + +$ sudo grep -i ENCRYPT_METHOD /etc/login.defs + +ENCRYPT_METHOD + Is it the case that ENCRYPT_METHOD is not set to <sub idref="var_password_hashing_algorithm" />? + + + + To check that the autofs service is disabled in system boot configuration, +run the following command: +$ sudo systemctl is-enabled autofs +Output should indicate the autofs service has either not been installed, +or has been disabled at all runlevels, as shown in the example below: +$ sudo systemctl is-enabled autofs disabled + +Run the following command to verify autofs is not active (i.e. not running) through current runtime configuration: +$ sudo systemctl is-active autofs + +If the service is not running the command will return the following output: +inactive + +The service will also be masked, to check that the autofs is masked, run the following command: +$ sudo systemctl show autofs | grep "LoadState\|UnitFileState" + +If the service is masked the command will return the following outputs: + +LoadState=masked + +UnitFileState=masked + Is it the case that the "autofs" is loaded and not masked? + + + + To check the permissions of /etc/issue.net, +run the command: +$ ls -l /etc/issue.net +If properly configured, the output should indicate the following permissions: +-rw-r--r-- + Is it the case that /etc/issue.net does not have unix mode -rw-r--r--? + + + + Verify that Oracle Linux 9 is configured to boot to the command line: +$ systemctl get-default +multi-user.target + Is it the case that the system default target is not set to "multi-user.target" and the Information System Security Officer (ISSO) lacks a documented requirement for a graphical user interface? + + + + To ensure the system is configured to ignore the Ctrl-Alt-Del setting, +enter the following command: +$ sudo grep -i ctrlaltdelburstaction /etc/systemd/system.conf +The output should return: +CtrlAltDelBurstAction=none + Is it the case that the system is configured to reboot when Ctrl-Alt-Del is pressed more than 7 times in 2 seconds.? + + + + To ensure the X Windows package group is removed, run the following command: +$ rpm -qi xorg-x11-server-common +The output should be: +package xorg-x11-server-common is not installed + Is it the case that the X Windows package group or xorg-x11-server-common has not be removed? + + + + Verify the noexec option is configured for the /var/log mount point, + run the following command: + $ sudo mount | grep '\s/var/log\s' + . . . /var/log . . . noexec . . . + + Is it the case that the "/var/log" file system does not have the "noexec" option set? + + + + To determine if the system is configured to audit calls to the +chmod system call, run the following command: +$ sudo grep "chmod" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. + + Is it the case that no line is returned? + + + + To determine if the system is configured to audit calls to the +lsetxattr system call, run the following command: +$ sudo grep "lsetxattr" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. + + Is it the case that no line is returned? + + + + Verify Oracle Linux 9 generates an audit record for unsuccessful attempts to use the openat system call. + +If the auditd daemon is configured to use the "augenrules" program to to read audit rules during daemon startup (the default), run the following command: + +$ sudo grep -r openat /etc/audit/rules.d + +If the auditd daemon is configured to use the "auditctl" utility to read audit rules during daemon startup, run the following command: + +$ sudo grep openat /etc/audit/audit.rules + +The output should be the following: + +-a always,exit -F arch=b32 -S openat -F exit=-EPERM -F auid>=1000 -F auid!=unset -k access +-a always,exit -F arch=b64 -S openat -F exit=-EPERM -F auid>=1000 -F auid!=unset -k access +-a always,exit -F arch=b32 -S openat -F exit=-EACCES -F auid>=1000 -F auid!=unset -k access +-a always,exit -F arch=b64 -S openat -F exit=-EACCES -F auid>=1000 -F auid!=unset -k access + Is it the case that the command does not return a line, or the line is commented out? + + + + To check the permissions of /etc/sudoers, +run the command: +$ ls -l /etc/sudoers +If properly configured, the output should indicate the following permissions: +0440 + Is it the case that /etc/sudoers does not have unix mode 0440? + + + + To check the group ownership of /boot/grub2/grub.cfg, +run the command: +$ ls -lL /boot/grub2/grub.cfg +If properly configured, the output should indicate the following group-owner: +root + Is it the case that /boot/grub2/grub.cfg does not have a group owner of root? + + + + Verify Oracle Linux 9 security patches and updates are installed and up to date. +Updates are required to be applied with a frequency determined by organizational policy. + + + +Typical update frequency may be overridden by Information Assurance Vulnerability Alert (IAVA) notifications from CYBERCOM. + Is it the case that Oracle Linux 9 is in non-compliance with the organizational patching policy? + + + + To verify that the Audit is correctly configured according to recommended rules, check the content of the file with the following command: cat /etc/audit/rules.d/30-ospp-v42.rules The output has to be exactly as follows: ## The purpose of these rules is to meet the requirements for Operating @@ -238425,9 +258378,6 @@ The output has to be exactly as follows: ## 30-ospp-v42-5-perm-change-success.rules, ## 30-ospp-v42-6-owner-change-failed.rules, ## 30-ospp-v42-6-owner-change-success.rules -## -## original copies may be found in /usr/share/audit/sample-rules/ - ## User add delete modify. This is covered by pam. However, someone could ## open a file and directly create or modify a user, so we'll watch passwd and @@ -238446,44 +258396,77 @@ The output has to be exactly as follows: ## Group add delete modify. This is covered by pam. However, someone could ## open a file and directly create or modify a user, so we'll watch group and ## gshadow for writes --a always,exit -F path=/etc/passwd -F perm=wa -F auid>=1000 -F auid!=unset -F key=user-modify --a always,exit -F path=/etc/shadow -F perm=wa -F auid>=1000 -F auid!=unset -F key=user-modify --a always,exit -F path=/etc/group -F perm=wa -F auid>=1000 -F auid!=unset -F key=group-modify --a always,exit -F path=/etc/gshadow -F perm=wa -F auid>=1000 -F auid!=unset -F key=group-modify +-a always,exit -F arch=b32 -F path=/etc/passwd -F perm=wa -F auid>=1000 -F auid!=unset -F key=user-modify +-a always,exit -F arch=b64 -F path=/etc/passwd -F perm=wa -F auid>=1000 -F auid!=unset -F key=user-modify +-a always,exit -F arch=b32 -F path=/etc/shadow -F perm=wa -F auid>=1000 -F auid!=unset -F key=user-modify +-a always,exit -F arch=b64 -F path=/etc/shadow -F perm=wa -F auid>=1000 -F auid!=unset -F key=user-modify +-a always,exit -F arch=b32 -F path=/etc/group -F perm=wa -F auid>=1000 -F auid!=unset -F key=group-modify +-a always,exit -F arch=b64 -F path=/etc/group -F perm=wa -F auid>=1000 -F auid!=unset -F key=group-modify +-a always,exit -F arch=b32 -F path=/etc/gshadow -F perm=wa -F auid>=1000 -F auid!=unset -F key=group-modify +-a always,exit -F arch=b64 -F path=/etc/gshadow -F perm=wa -F auid>=1000 -F auid!=unset -F key=group-modify ## Use of special rights for config changes. This would be use of setuid ## programs that relate to user accts. This is not all setuid apps because ## requirements are only for ones that affect system configuration. --a always,exit -F path=/usr/sbin/unix_chkpwd -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes --a always,exit -F path=/usr/sbin/usernetctl -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes --a always,exit -F path=/usr/sbin/userhelper -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes --a always,exit -F path=/usr/sbin/seunshare -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes --a always,exit -F path=/usr/bin/mount -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes --a always,exit -F path=/usr/bin/newgrp -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes --a always,exit -F path=/usr/bin/newuidmap -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes --a always,exit -F path=/usr/bin/gpasswd -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes --a always,exit -F path=/usr/bin/newgidmap -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes --a always,exit -F path=/usr/bin/umount -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes --a always,exit -F path=/usr/bin/passwd -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes --a always,exit -F path=/usr/bin/crontab -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes --a always,exit -F path=/usr/bin/at -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b32 -F path=/usr/sbin/unix_chkpwd -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b64 -F path=/usr/sbin/unix_chkpwd -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b32 -F path=/usr/sbin/usernetctl -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b64 -F path=/usr/sbin/usernetctl -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b32 -F path=/usr/sbin/userhelper -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b64 -F path=/usr/sbin/userhelper -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b32 -F path=/usr/sbin/seunshare -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b64 -F path=/usr/sbin/seunshare -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b32 -F path=/usr/bin/mount -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b64 -F path=/usr/bin/mount -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b32 -F path=/usr/bin/newgrp -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b64 -F path=/usr/bin/newgrp -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b32 -F path=/usr/bin/newuidmap -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b64 -F path=/usr/bin/newuidmap -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b32 -F path=/usr/bin/gpasswd -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b64 -F path=/usr/bin/gpasswd -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b32 -F path=/usr/bin/newgidmap -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b64 -F path=/usr/bin/newgidmap -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b32 -F path=/usr/bin/umount -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b64 -F path=/usr/bin/umount -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b32 -F path=/usr/bin/passwd -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b64 -F path=/usr/bin/passwd -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b32 -F path=/usr/bin/crontab -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b64 -F path=/usr/bin/crontab -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b32 -F path=/usr/bin/at -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b64 -F path=/usr/bin/at -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b32 -F path=/usr/sbin/grub2-set-bootflag -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes +-a always,exit -F arch=b64 -F path=/usr/sbin/grub2-set-bootflag -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes ## Privilege escalation via su or sudo. This is entirely handled by pam. +## Special case for systemd-run. It is not audit aware, specifically watch it +-a always,exit -F arch=b32 -F path=/usr/bin/systemd-run -F perm=x -F auid!=unset -F key=maybe-escalation +-a always,exit -F arch=b64 -F path=/usr/bin/systemd-run -F perm=x -F auid!=unset -F key=maybe-escalation +## Special case for pkexec. It is not audit aware, specifically watch it +-a always,exit -F arch=b32 -F path=/usr/bin/pkexec -F perm=x -F key=maybe-escalation +-a always,exit -F arch=b64 -F path=/usr/bin/pkexec -F perm=x -F key=maybe-escalation + ## Watch for configuration changes to privilege escalation. --a always,exit -F path=/etc/sudoers -F perm=wa -F key=special-config-changes --a always,exit -F dir=/etc/sudoers.d/ -F perm=wa -F key=special-config-changes +-a always,exit -F arch=b32 -F path=/etc/sudoers -F perm=wa -F key=special-config-changes +-a always,exit -F arch=b64 -F path=/etc/sudoers -F perm=wa -F key=special-config-changes +-a always,exit -F arch=b32 -F dir=/etc/sudoers.d/ -F perm=wa -F key=special-config-changes +-a always,exit -F arch=b64 -F dir=/etc/sudoers.d/ -F perm=wa -F key=special-config-changes ## Audit log access --a always,exit -F dir=/var/log/audit/ -F perm=r -F auid>=1000 -F auid!=unset -F key=access-audit-trail +-a always,exit -F arch=b32 -F dir=/var/log/audit/ -F perm=r -F auid>=1000 -F auid!=unset -F key=access-audit-trail +-a always,exit -F arch=b64 -F dir=/var/log/audit/ -F perm=r -F auid>=1000 -F auid!=unset -F key=access-audit-trail ## Attempts to Alter Process and Session Initiation Information --a always,exit -F path=/var/run/utmp -F perm=wa -F auid>=1000 -F auid!=unset -F key=session --a always,exit -F path=/var/log/btmp -F perm=wa -F auid>=1000 -F auid!=unset -F key=session --a always,exit -F path=/var/log/wtmp -F perm=wa -F auid>=1000 -F auid!=unset -F key=session +-a always,exit -F arch=b32 -F path=/var/run/utmp -F perm=wa -F auid>=1000 -F auid!=unset -F key=session +-a always,exit -F arch=b64 -F path=/var/run/utmp -F perm=wa -F auid>=1000 -F auid!=unset -F key=session +-a always,exit -F arch=b32 -F path=/var/log/btmp -F perm=wa -F auid>=1000 -F auid!=unset -F key=session +-a always,exit -F arch=b64 -F path=/var/log/btmp -F perm=wa -F auid>=1000 -F auid!=unset -F key=session +-a always,exit -F arch=b32 -F path=/var/log/wtmp -F perm=wa -F auid>=1000 -F auid!=unset -F key=session +-a always,exit -F arch=b64 -F path=/var/log/wtmp -F perm=wa -F auid>=1000 -F auid!=unset -F key=session ## Attempts to modify MAC controls --a always,exit -F dir=/etc/selinux/ -F perm=wa -F auid>=1000 -F auid!=unset -F key=MAC-policy +-a always,exit -F arch=b32 -F dir=/etc/selinux/ -F perm=wa -F auid>=1000 -F auid!=unset -F key=MAC-policy +-a always,exit -F arch=b64 -F dir=/etc/selinux/ -F perm=wa -F auid>=1000 -F auid!=unset -F key=MAC-policy ## Software updates. This is entirely handled by rpm. @@ -238496,193 +258479,131 @@ The output has to be exactly as follows: ## state results from that policy. This would be handled entirely by ## that daemon. Is it the case that the file does not exist or the content differs? - - - - To verify that the Audit is correctly configured according to recommended rules, check the content of the file with the following command: -cat /etc/audit/rules.d/30-ospp-v42-6-owner-change-failed.rules -The output has to be exactly as follows: -## Unsuccessful ownership change --a always,exit -F arch=b32 -S lchown,fchown,chown,fchownat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-owner-change --a always,exit -F arch=b64 -S lchown,fchown,chown,fchownat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-owner-change --a always,exit -F arch=b32 -S lchown,fchown,chown,fchownat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-owner-change --a always,exit -F arch=b64 -S lchown,fchown,chown,fchownat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-owner-change - Is it the case that the file does not exist or the content differs? - - - - To verify that the Audit is correctly configured according to recommended rules, check the content of the file with the following command: -cat /etc/audit/rules.d/30-ospp-v42-6-owner-change-success.rules -The output has to be exactly as follows: -## Successful ownership change --a always,exit -F arch=b32 -S lchown,fchown,chown,fchownat -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-owner-change --a always,exit -F arch=b64 -S lchown,fchown,chown,fchownat -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-owner-change - Is it the case that the file does not exist or the content differs? - - - - To verify that the Audit is correctly configured according to recommended rules, check the content of the file with the following command: -cat /etc/audit/rules.d/30-ospp-v42-5-perm-change-failed.rules -The output has to be exactly as follows: -## Unsuccessful permission change --a always,exit -F arch=b32 -S chmod,fchmod,fchmodat,setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-perm-change --a always,exit -F arch=b64 -S chmod,fchmod,fchmodat,setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-perm-change --a always,exit -F arch=b32 -S chmod,fchmod,fchmodat,setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-perm-change --a always,exit -F arch=b64 -S chmod,fchmod,fchmodat,setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-perm-change - Is it the case that the file does not exist or the content differs? - - - - To verify that the Audit is correctly configured according to recommended rules, check the content of the file with the following command: -cat /etc/audit/rules.d/30-ospp-v42-5-perm-change-success.rules -The output has to be exactly as follows: -## Successful permission change --a always,exit -F arch=b32 -S chmod,fchmod,fchmodat,setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-perm-change --a always,exit -F arch=b64 -S chmod,fchmod,fchmodat,setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-perm-change - Is it the case that the file does not exist or the content differs? - - - - Inspect the form of default GRUB 2 command line for the Linux operating system -in /etc/default/grub. If it includes audit=1, -then the parameter will be configured for newly installed kernels. -First check if the GRUB recovery is enabled: -$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub -If this option is set to true, then check that a line is output by the following command: -$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*audit=1.*' /etc/default/grub -If the recovery is disabled, check the line with -$ sudo grep 'GRUB_CMDLINE_LINUX.*audit=1.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. -Run the following command: -$ sudo grubby --info=ALL | grep args | grep -v 'audit=1' -The command should not return any output. - Is it the case that auditing is not enabled at boot time? - - - - Inspect the form of default GRUB 2 command line for the Linux operating system -in /etc/default/grub. If it includes audit_backlog_limit=8192, -then the parameter will be configured for newly installed kernels. -First check if the GRUB recovery is enabled: -$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub -If this option is set to true, then check that a line is output by the following command: -$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*audit_backlog_limit=8192.*' /etc/default/grub -If the recovery is disabled, check the line with -$ sudo grep 'GRUB_CMDLINE_LINUX.*audit_backlog_limit=8192.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. -Run the following command: -$ sudo grubby --info=ALL | grep args | grep -v 'audit_backlog_limit=8192' -The command should not return any output. - Is it the case that audit backlog limit is not configured? - - - - Run the following command to determine if the audispd-plugins package is installed: $ rpm -q audispd-plugins - Is it the case that the package is not installed? - - - - - Is it the case that the package is not installed? - - - - Run the following command to determine if the audit package is installed: $ rpm -q audit - Is it the case that the audit package is not installed? - - - - + + + + Run the following command to determine the current status of the -auditd service: -$ sudo systemctl is-active auditd +crond service: +$ sudo systemctl is-active crond If the service is running, it should return the following: active - Is it the case that the auditd service is not running? - - - - To check the group ownership of /boot/grub2/grub.cfg, + Is it the case that ? + + + + The runtime status of the net.ipv4.conf.all.secure_redirects kernel parameter can be queried +by running the following command: +$ sysctl net.ipv4.conf.all.secure_redirects +0. + + Is it the case that the correct value is not returned? + + + + To check the permissions of /etc/cron.d, run the command: -$ ls -lL /boot/grub2/grub.cfg -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /boot/grub2/grub.cfg does not have a group owner of root? - - - - To check the group ownership of /boot/grub2/user.cfg, -run the command: -$ ls -lL /boot/grub2/user.cfg -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /boot/grub2/user.cfg does not have a group owner of root? - - - - To check the ownership of /boot/grub2/grub.cfg, -run the command: -$ ls -lL /boot/grub2/grub.cfg -If properly configured, the output should indicate the following owner: -root - Is it the case that /boot/grub2/grub.cfg does not have an owner of root? - - - - To check the ownership of /boot/grub2/user.cfg, -run the command: -$ ls -lL /boot/grub2/user.cfg -If properly configured, the output should indicate the following owner: -root - Is it the case that /boot/grub2/user.cfg does not have an owner of root? - - - - To verify the boot loader superuser account has been set, run the following -command: -sudo grep -A1 "superusers" /boot/grub2/grub.cfg -The output should show the following: -set superusers="superusers-account" -export superusers -where superusers-account is the actual account name different from common names like root, -admin, or administrator and different from any other existing user name. - Is it the case that superuser account is not set or is set to root, admin, administrator or any other existing user name? - - - - First, check whether the password is defined in either /boot/grub2/user.cfg or -/boot/grub2/grub.cfg. -Run the following commands: -$ sudo grep '^[\s]*GRUB2_PASSWORD=grub\.pbkdf2\.sha512.*$' /boot/grub2/user.cfg -$ sudo grep '^[\s]*password_pbkdf2[\s]+.*[\s]+grub\.pbkdf2\.sha512.*$' /boot/grub2/grub.cfg +$ ls -l /etc/cron.d +If properly configured, the output should indicate the following permissions: +-rwx------ + Is it the case that /etc/cron.d does not have unix mode -rwx------? + + + + Run the following command to determine if the rsyslog package is installed: $ rpm -q rsyslog + Is it the case that the package is not installed? + + + + Verify the nodev option is configured for the /var mount point, + run the following command: + $ sudo mount | grep '\s/var\s' + . . . /var . . . nodev . . . + + Is it the case that the "/var" file system does not have the "nodev" option set? + + + + To determine if the system is configured to audit calls to the +settimeofday system call, run the following command: +$ sudo grep "settimeofday" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. + + Is it the case that no line is returned? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_MODULE_SIG_HASH /boot/config.* + + For each kernel installed, a line with value "" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + The runtime status of the net.ipv4.conf.all.accept_local kernel parameter can be queried +by running the following command: +$ sysctl net.ipv4.conf.all.accept_local +0. + + Is it the case that the correct value is not returned? + + + + To check if authentication is required for single-user mode, run the following command: +$ grep sulogin /usr/lib/systemd/system/rescue.service +The output should be similar to the following, and the line must begin with +ExecStart and /usr/lib/systemd/systemd-sulogin-shell. + ExecStart=-/usr/lib/systemd/systemd-sulogin-shell rescue + +In case the output does not match, check if the ExecStart directive is not overridden: +grep ExecStart /etc/systemd/system/rescue.service.d/*.conf +The output should contain two lines: +ExecStart= +ExecStart=-/usr/lib/systemd/systemd-sulogin-shell rescue -Second, check that a superuser is defined in /boot/grub2/grub.cfg. -$ sudo grep '^[\s]*set[\s]+superusers=("?)[a-zA-Z_]+\1$' /boot/grub2/grub.cfg - Is it the case that it does not produce any output? - - - - To check the group ownership of /boot/grub2/user.cfg, -run the command: -$ ls -lL /boot/grub2/user.cfg -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /boot/grub2/user.cfg does not have a group owner of root? - - - - To verify the boot loader superuser account has been set, run the following -command: -sudo grep -A1 "superusers" /boot/grub2/grub.cfg -The output should show the following: -set superusers="superusers-account" -export superusers -where superusers-account is the actual account name different from common names like root, -admin, or administrator and different from any other existing user name. - Is it the case that superuser account is not set or is set to an existing name or to a common name? - - - - To verify the boot loader superuser password has been set, run the following command: + +Then, verify that the rescue service is in the runlevel1.target. +Run the following command: +$ sudo grep "^Requires=.*rescue\.service" /usr/lib/systemd/system/runlevel1.target +The output should be the following: +Requires=sysinit.target rescue.service + +Then, check if there is no custom runlevel1 target configured in systemd configuration. +Run the following command: +$ sudo grep -r "^runlevel1.target$" /etc/systemd/system +There should be no output. + +Then, check if there is no custom rescue service configured in systemd configuration. +Run the following command: +$ sudo grep -r "^rescue.service$" /etc/systemd/system +There should be no output. + Is it the case that the output is different? + + + + To ensure a login warning banner is enabled, run the following: +$ grep banner-message-enable /etc/dconf/db/local.d/* +If properly configured, the output should be true. +To ensure a login warning banner is locked and cannot be changed by a user, run the following: +$ grep banner-message-enable /etc/dconf/db/local.d/locks/* +If properly configured, the output should be /org/gnome/login-screen/banner-message-enable. + Is it the case that it is not? + + + + Verify the value of the "maxclassrepeat" option in "/etc/security/pwquality.conf" with the following command: + +$ grep maxclassrepeat /etc/security/pwquality.conf + +maxclassrepeat = + Is it the case that the value of "maxclassrepeat" is set to "0", more than "<sub idref="var_password_pam_maxclassrepeat" />" or is commented out? + + + + To verify the boot loader superuser password has been set, run the following command: $ sudo grep "^[\s]*GRUB2_PASSWORD=grub\.pbkdf2\.sha512.*$" /boot/grub2/user.cfg The output should be similar to: GRUB2_PASSWORD=grub.pbkdf2.sha512.10000.C4E08AC72FBFF7E837FD267BFAD7AEB3D42DDC @@ -238690,50 +258611,205 @@ GRUB2_PASSWORD=grub.pbkdf2.sha512.10000.C4E08AC72FBFF7E837FD267BFAD7AEB3D42DDC 916F7AB46E0D.1302284FCCC52CD73BA3671C6C12C26FF50BA873293B24EE2A96EE3B57963E6D7 0C83964B473EC8F93B07FE749AA6710269E904A9B08A6BBACB00A2D242AD828 Is it the case that no password is set? - - - - Verify that GRUB_DISABLE_RECOVERY is set to true in /etc/default/grub to disable recovery boot. -Run the following command: + + + + To verify that rsyslog's Forwarding Output Module is configured +to use TLS for logging to remote server, run the following command: +$ grep omfwd /etc/rsyslog.conf /etc/rsyslog.d/*.conf +The output should include record similar to +action(type="omfwd" protocol="tcp" Target="<remote system>" port="6514" + StreamDriver="gtls" StreamDriverMode="1" StreamDriverAuthMode="x509/name" streamdriver.CheckExtendedKeyPurpose="on") -$ sudo grep GRUB_DISABLE_RECOVERY /etc/default/grub - Is it the case that GRUB_DISABLE_RECOVERY is not set to true or is missing? - - - - Inspect the form of default GRUB 2 command line for the Linux operating system -in /etc/default/grub. If it includes iommu=force, -then the parameter will be configured for newly installed kernels. -First check if the GRUB recovery is enabled: -$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub -If this option is set to true, then check that a line is output by the following command: -$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*iommu=force.*' /etc/default/grub -If the recovery is disabled, check the line with -$ sudo grep 'GRUB_CMDLINE_LINUX.*iommu=force.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. -Run the following command: -$ sudo grubby --info=ALL | grep args | grep -v 'iommu=force' -The command should not return any output. - Is it the case that I/OMMU is not activated? - - - - Inspect the form of default GRUB 2 command line for the Linux operating system -in /etc/default/grub. If it includes init_on_alloc=1, -then the parameter will be configured for newly installed kernels. -First check if the GRUB recovery is enabled: -$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub -If this option is set to true, then check that a line is output by the following command: -$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*init_on_alloc=1.*' /etc/default/grub -If the recovery is disabled, check the line with -$ sudo grep 'GRUB_CMDLINE_LINUX.*init_on_alloc=1.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. -Run the following command: -$ sudo grubby --info=ALL | grep args | grep -v 'init_on_alloc=1' -The command should not return any output. - Is it the case that the kernel is not configured to zero out memory before allocation? - - - - Inspect the form of default GRUB 2 command line for the Linux operating system +where the <remote system> present in the configuration line above must be a valid IP address or a host name of the remote logging server. + Is it the case that omfwd is not configured with gtls and AuthMode? + + + + The runtime status of the net.ipv4.conf.default.accept_source_route kernel parameter can be queried +by running the following command: +$ sysctl net.ipv4.conf.default.accept_source_route +0. + + Is it the case that the correct value is not returned? + + + + To check the permissions of /etc/cron.weekly, +run the command: +$ ls -l /etc/cron.weekly +If properly configured, the output should indicate the following permissions: +-rwx------ + Is it the case that /etc/cron.weekly does not have unix mode -rwx------? + + + + Verify the operating system encrypts audit records off-loaded onto a different system +or media from the system being audited with the following commands: + +$ sudo grep -i '$DefaultNetstreamDriver' /etc/rsyslog.conf /etc/rsyslog.d/*.conf + +The output should be: + +/etc/rsyslog.conf:$DefaultNetstreamDriver gtls + Is it the case that rsyslogd DefaultNetstreamDriver not set to gtls? + + + + + +Run the following command to determine the current status of the +fapolicyd service: +$ sudo systemctl is-active fapolicyd +If the service is running, it should return the following: active + Is it the case that the service is not enabled? + + + + Run the following command to determine if the rsh-server package is installed: +$ rpm -q rsh-server + Is it the case that the package is installed? + + + + To determine if the system is configured to audit calls to the +fsetxattr system call, run the following command: +$ sudo grep "fsetxattr" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. + + Is it the case that no line is returned? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_COMPAT_BRK /boot/config.* + + Configs with value 'n' are not explicitly set in the file, so either commented lines or no + lines should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_SLAB_FREELIST_RANDOM /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + Run the following command to determine if the sendmail package is installed: +$ rpm -q sendmail + Is it the case that the package is installed? + + + + Verify Oracle Linux 9 takes the appropriate action when the audit storage volume is full. + +Check that Oracle Linux 9 takes the appropriate action when the audit storage volume is full with the following command: + +$ sudo grep disk_full_action /etc/audit/auditd.conf + +disk_full_action = + +If the value of the "disk_full_action" option is not "SYSLOG", "SINGLE", or "HALT", or the line is commented out, ask the system administrator to indicate how the system takes appropriate action when an audit storage volume is full. + Is it the case that there is no evidence of appropriate action? + + + + Verify the operating system requires re-authentication +when using the "sudo" command to elevate privileges, run the following command: +sudo grep -ri '^Defaults.*timestamp_timeout' /etc/sudoers /etc/sudoers.d +The output should be: +/etc/sudoers:Defaults timestamp_timeout=0 or "timestamp_timeout" is set to a positive number. +If conflicting results are returned, this is a finding. + Is it the case that timestamp_timeout is not set with the appropriate value for sudo? + + + + To ensure that remote access connections are encrypted, run the following command: +$ gsettings get org.gnome.Vino require-encrpytion +If properly configured, the output should be true. +To ensure that users cannot disable encrypted remote connections, run the following: +$ grep require-encryption /etc/dconf/db/local.d/locks/* +If properly configured, the output should be +/org/gnome/Vino/require-encryption + Is it the case that remote access connections are not encrypted? + + + + To check the group ownership of /etc/at.allow, +run the command: +$ ls -lL /etc/at.allow +If properly configured, the output should indicate the following group-owner: +root + Is it the case that /etc/at.allow does not have a group owner of root? + + + + To determine how the SSH daemon's PermitEmptyPasswords option is set, run the following command: + +$ sudo grep -i PermitEmptyPasswords /etc/ssh/sshd_config + +If a line indicating no is returned, then the required value is set. + + Is it the case that the required value is not set? + + + + To determine if NOPASSWD or !authenticate have been configured for +sudo, run the following command: +$ sudo grep -ri "nopasswd\|\!authenticate" /etc/sudoers /etc/sudoers.d/ +The command should return no output. + Is it the case that nopasswd and/or !authenticate is enabled in sudo? + + + + To check the permissions of /etc/gshadow, +run the command: +$ ls -l /etc/gshadow +If properly configured, the output should indicate the following permissions: +---------- + Is it the case that /etc/gshadow does not have unix mode ----------? + + + + To verify Certmap is enabled in SSSD, run the following command: +$ sudo cat /etc/sssd/sssd.conf +If configured properly, output should contain section like the following + +[certmap/testing.test/rule_name] +matchrule =<SAN>.*EDIPI@mil +maprule = (userCertificate;binary={cert!bin}) +domains = testing.test + + Is it the case that Certmap is not configured in SSSD? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_HIBERNATION /boot/config.* + + Configs with value 'n' are not explicitly set in the file, so either commented lines or no + lines should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To ensure disable and restart on the login screen are disabled, run the following command: +$ grep disable-restart-buttons /etc/dconf/db/local.d/* +The output should be true. +To ensure that users cannot enable disable and restart on the login screen, run the following: +$ grep disable-restart-buttons /etc/dconf/db/local.d/locks/* +If properly configured, the output should be /org/gnome/login-screen/disable-restart-buttons + Is it the case that disable-restart-buttons has not been configured or is not disabled? + + + + Inspect the form of default GRUB 2 command line for the Linux operating system in /etc/default/grub. If it includes l1tf=, then the parameter will be configured for newly installed kernels. First check if the GRUB recovery is enabled: @@ -238746,42 +258822,42 @@ Run the following command: $ sudo grubby --info=ALL | grep args | grep -v 'l1tf=' The command should not return any output. Is it the case that l1tf mitigations are not configured appropriately? - - - - Inspect the form of default GRUB 2 command line for the Linux operating system -in /etc/default/grub. If it includes mce=0, -then the parameter will be configured for newly installed kernels. -First check if the GRUB recovery is enabled: -$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub -If this option is set to true, then check that a line is output by the following command: -$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*mce=0.*' /etc/default/grub -If the recovery is disabled, check the line with -$ sudo grep 'GRUB_CMDLINE_LINUX.*mce=0.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. -Run the following command: -$ sudo grubby --info=ALL | grep args | grep -v 'mce=0' -The command should not return any output. - Is it the case that MCE tolerance is not set to zero? - - - - Make sure that the kernel is not disabling SMAP with the following -commands. -grep -q nosmap /boot/config-`uname -r` -If the command returns a line, it means that SMAP is being disabled. - Is it the case that the kernel is configured to disable SMAP? - - - - Make sure that the kernel is not disabling SMEP with the following -commands. -grep -q nosmep /boot/config-`uname -r` -If the command returns a line, it means that SMEP is being disabled. - Is it the case that the kernel is configured to disable SMEP? - - - - Inspect the form of default GRUB 2 command line for the Linux operating system + + + + The runtime status of the net.ipv4.conf.default.send_redirects kernel parameter can be queried +by running the following command: +$ sysctl net.ipv4.conf.default.send_redirects +0. + + Is it the case that the correct value is not returned? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "crontab" command with the following command: + +$ sudo auditctl -l | grep crontab + +-a always,exit -F path=/usr/bin/crontab -F perm=x -F auid>=1000 -F auid!=unset -k privileged-crontab + Is it the case that the command does not return a line, or the line is commented out? + + + + To ensure sshd limits the users who can log in, run the following: +pre>$ sudo grep -rPi '^\h*(allow|deny)(users|groups)\h+\H+(\h+.*)?$' /etc/ssh/sshd_config* +If properly configured, the output should be a list of usernames and/or +groups allowed to log in to this system. + Is it the case that sshd does not limit the users who can log in? + + + + To find SGID files, run the following command: +$ sudo find / -xdev -type f -perm -2000 + Is it the case that there is output? + + + + Inspect the form of default GRUB 2 command line for the Linux operating system in /etc/default/grub. If it includes page_alloc.shuffle=1, then the parameter will be configured for newly installed kernels. First check if the GRUB recovery is enabled: @@ -238794,74 +258870,1257 @@ Run the following command: $ sudo grubby --info=ALL | grep args | grep -v 'page_alloc.shuffle=1' The command should not return any output. Is it the case that randomization of the page allocator is not enabled in the kernel? - - - - Inspect the form of default GRUB 2 command line for the Linux operating system -in /etc/default/grub. If it includes pti=on, + + + + To verify that the DConf User profile is configured correctly, run the following +command: + +$ cat /etc/dconf/profile/user +The output should show the following: +user-db:user +system-db:local +system-db:site +system-db:distro + Is it the case that DConf User profile does not exist or is not configured correctly? + + + + To check the screensaver mandatory use status, run the following command: +$ gsettings get org.gnome.desktop.screensaver idle-activation-enabled +If properly configured, the output should be true. +To ensure that users cannot disable the screensaver idle inactivity setting, run the following: +$ grep idle-activation-enabled /etc/dconf/db/local.d/locks/* +If properly configured, the output should be /org/gnome/desktop/screensaver/idle-activation-enabled + Is it the case that idle-activation-enabled is not enabled or configured? + + + + Verify that authselect is enabled by running +authselect current +If authselect is enabled on the system, the output should show the ID of the profile which is currently in use. + Is it the case that authselect is not used to manage user authentication setup on the system? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_X86_VSYSCALL_EMULATION /boot/config.* + + Configs with value 'n' are not explicitly set in the file, so either commented lines or no + lines should be returned. + + Is it the case that the kernel was not built with the required value? + + + + Verify that Promiscuous mode of an interface is disabled, run the following command: +$ ip link | grep PROMISC + Is it the case that any network device is in promiscuous mode? + + + + The file /etc/cron.deny should not exist. +This can be checked by runnig the following + +stat /etc/cron.deny + +and the output should be + +stat: cannot stat `/etc/cron.deny': No such file or directory + + Is it the case that the file /etc/cron.deny exists? + + + + Run the following command to determine if the nftables package is installed: $ rpm -q nftables + Is it the case that the package is not installed? + + + + To check the group ownership of /etc/cron.hourly, +run the command: +$ ls -lL /etc/cron.hourly +If properly configured, the output should indicate the following group-owner: +root + Is it the case that /etc/cron.hourly does not have a group owner of root? + + + + To check that the oddjobd service is disabled in system boot configuration, +run the following command: +$ sudo systemctl is-enabled oddjobd +Output should indicate the oddjobd service has either not been installed, +or has been disabled at all runlevels, as shown in the example below: +$ sudo systemctl is-enabled oddjobd disabled + +Run the following command to verify oddjobd is not active (i.e. not running) through current runtime configuration: +$ sudo systemctl is-active oddjobd + +If the service is not running the command will return the following output: +inactive + +The service will also be masked, to check that the oddjobd is masked, run the following command: +$ sudo systemctl show oddjobd | grep "LoadState\|UnitFileState" + +If the service is masked the command will return the following outputs: + +LoadState=masked + +UnitFileState=masked + Is it the case that the "oddjobd" is loaded and not masked? + + + + Verify that the interactive user account passwords last change time is not in the future +The following command should return no output +$ sudo expiration=$(cat /etc/shadow|awk -F ':' '{print $3}'); +for edate in ${expiration[@]}; do if [[ $edate > $(( $(date +%s)/86400 )) ]]; +then echo "Expiry date in future"; +fi; done + Is it the case that any interactive user password that has last change time in the future? + + + + Run the following command to determine if the tftp-server package is installed: +$ rpm -q tftp-server + Is it the case that the package is installed? + + + + Verify Oracle Linux 9 takes the appropriate action when the audit files have reached maximum size. + +Check that Oracle Linux 9 takes the appropriate action when the audit files have reached maximum size with the following command: + +$ sudo grep max_log_file_action /etc/audit/auditd.conf + +max_log_file_action = + Is it the case that the value of the "max_log_file_action" option is not "ROTATE", "SINGLE", or the line is commented out, ask the system administrator to indicate how the system takes appropriate action when an audit storage volume is full. If there is no evidence of appropriate action? + + + + Verify the system-wide shared library directories are group-owned by "root" with the following command: + +$ sudo find /lib /lib64 /usr/lib /usr/lib64 ! -group root -type d -exec stat -c "%n %G" '{}' \; + +If any system-wide shared library directory is returned and is not group-owned by a required system account, this is a finding. + Is it the case that any system-wide shared library directory is returned and is not group-owned by a required system account? + + + + Check that AIDE is properly configured to protect the integrity of the +audit tools by running the following command: + +# sudo cat /etc/aide.conf | grep /usr/sbin/au + +/usr/sbin/auditctl p+i+n+u+g+s+b+acl+xattrs+sha512 +/usr/sbin/auditd p+i+n+u+g+s+b+acl+xattrs+sha512 +/usr/sbin/ausearch p+i+n+u+g+s+b+acl+xattrs+sha512 +/usr/sbin/aureport p+i+n+u+g+s+b+acl+xattrs+sha512 +/usr/sbin/autrace p+i+n+u+g+s+b+acl+xattrs+sha512 + +/usr/sbin/rsyslogd p+i+n+u+g+s+b+acl+xattrs+sha512 +/usr/sbin/augenrules p+i+n+u+g+s+b+acl+xattrs+sha512 + + +If AIDE is configured properly to protect the integrity of the audit tools, +all lines listed above will be returned from the command. + +If one or more lines are missing, this is a finding. + Is it the case that integrity checks of the audit tools are missing or incomplete? + + + + To determine if the system is configured to audit calls to the +init_module system call, run the following command: +$ sudo grep "init_module" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. +To determine if the system is configured to audit calls to the +finit_module system call, run the following command: +$ sudo grep "finit_module" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. +To determine if the system is configured to audit calls to the +delete_module system call, run the following command: +$ sudo grep "delete_module" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. + Is it the case that no line is returned? + + + + Verify "firewalld" is configured to employ a deny-all, allow-by-exception policy for allowing connections to other systems with the following commands: + +$ sudo firewall-cmd --state + +running + +$ sudo firewall-cmd --get-active-zones + +[custom] +interfaces: ens33 + +$ sudo firewall-cmd --info-zone=[custom] | grep target + +target: DROP + Is it the case that no zones are active on the interfaces or if the target is set to a different option other than "DROP"? + + + + Verify the audit tools are group-owned by "root" to prevent any unauthorized access, deletion, or modification. + +Check the group-owner of each audit tool by running the following command: + +$ sudo stat -c "%G %n" /sbin/auditctl /sbin/aureport /sbin/ausearch /sbin/autrace /sbin/auditd /sbin/rsyslogd /sbin/augenrules + +root /sbin/auditctl +root /sbin/aureport +root /sbin/ausearch +root /sbin/autrace +root /sbin/auditd +root /sbin/rsyslogd +root /sbin/augenrules + Is it the case that any audit tools are not group-owned by root? + + + + To check the permissions of /etc/shells, +run the command: +$ ls -l /etc/shells +If properly configured, the output should indicate the following permissions: +0644 + Is it the case that /etc/shells does not have unix mode 0644? + + + + To check the permissions of /etc/ssh/*.pub, +run the command: +$ ls -l /etc/ssh/*.pub +If properly configured, the output should indicate the following permissions: +-rw-r--r-- + Is it the case that /etc/ssh/*.pub does not have unix mode -rw-r--r--? + + + + To ensure LoginGraceTime is set correctly, run the following command: +$ sudo grep LoginGraceTime /etc/ssh/sshd_config +If properly configured, the output should be: +LoginGraceTime +If the option is set to a number greater than 0, then the unauthenticated session will be disconnected +after the configured number seconds. + Is it the case that it is commented out or not configured properly? + + + + The owner of all log files written by rsyslog should be + +root. + +These log files are determined by the second part of each Rule line in +/etc/rsyslog.conf and typically all appear in /var/log. +To see the owner of a given log file, run the following command: +$ ls -l LOGFILE + Is it the case that the owner is not correct? + + + + + +Run the following command to determine the current status of the +postfix service: +$ sudo systemctl is-active postfix +If the service is running, it should return the following: active + Is it the case that the system is not a cross domain solution and the service is not enabled? + + + + Verify Oracle Linux 9 generates audit records for all account creations, modifications, disabling, and termination events that affect "/etc/security/opasswd" with the following command: + +$ sudo auditctl -l | grep + +-w -p wa -k logins + Is it the case that the command does not return a line, or the line is commented out? + + + + To verify that the installed operating system is supported, run +the following command: + +$ grep -i "oracle" /etc/oracle-release + +Oracle Linux 9 + Is it the case that the installed operating system is not supported? + + + + To ensure the user home directory is not group-writable or world-readable, run the following: +# ls -ld /home/USER + Is it the case that the user home directory is group-writable or world-readable? + + + + To check the permissions of /etc/sysctl.d, +run the command: +$ ls -l /etc/sysctl.d +If properly configured, the output should indicate the following permissions: +0755 + Is it the case that /etc/sysctl.d does not have unix mode 0755? + + + + To check the ownership of /etc/ssh/sshd_config, +run the command: +$ ls -lL /etc/ssh/sshd_config +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/ssh/sshd_config does not have an owner of root? + + + + To check the permissions of /boot/grub2/grub.cfg, run the command: +$ sudo ls -lL /boot/grub2/grub.cfg +If properly configured, the output should indicate the following +permissions: -rwx------ + Is it the case that it does not? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "shutdown" command with the following command: + +$ sudo auditctl -l | grep shutdown + +-a always,exit -F path=/shutdown -F perm=x -F auid>=1000 -F auid!=unset -k privileged-shutdown + Is it the case that the command does not return a line, or the line is commented out? + + + + + +Run the following command to determine the current status of the +firewalld service: +$ sudo systemctl is-active firewalld +If the service is running, it should return the following: active + Is it the case that the "firewalld" service is disabled, masked, or not started.? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "chacl" command with the following command: + +$ sudo auditctl -l | grep chacl + +-a always,exit -F path=/usr/bin/chacl -F perm=x -F auid>=1000 -F auid!=unset -k perm_mod + Is it the case that the command does not return a line, or the line is commented out? + + + + Run the following command to determine if the quagga package is installed: +$ rpm -q quagga + Is it the case that the package is installed? + + + + Verify Oracle Linux 9 disables the chrony daemon from acting as a server with the following command: +$ grep -w port /etc/chrony.conf +port 0 + Is it the case that the "port" option is not set to "0", is commented out, or is missing? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "ssh-agent" command with the following command: + +$ sudo auditctl -l | grep ssh-agent + +-a always,exit -F path=/usr/bin/ssh-agent -F perm=x -F auid>=1000 -F auid!=unset -k privileged-ssh-agent + Is it the case that the command does not return a line, or the line is commented out? + + + + Check to see if Online Certificate Status Protocol (OCSP) +is enabled and using the proper digest value on the system with the following command: +$ sudo grep certificate_verification /etc/sssd/sssd.conf /etc/sssd/conf.d/*.conf | grep -v "^#" +If configured properly, output should look like + + certificate_verification = ocsp_dgst= + + Is it the case that certificate_verification in sssd is not configured? + + + + To check the group ownership of /etc/sestatus.conf, +run the command: +$ ls -lL /etc/sestatus.conf +If properly configured, the output should indicate the following group-owner: +root + Is it the case that /etc/sestatus.conf does not have a group owner of root? + + + + Run the following command to determine if the talk package is installed: +$ rpm -q talk + Is it the case that the package is installed? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_FORTIFY_SOURCE /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_SLAB_MERGE_DEFAULT /boot/config.* + + Configs with value 'n' are not explicitly set in the file, so either commented lines or no + lines should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To check if RekeyLimit is set correctly, run the +following command: + +$ sudo grep RekeyLimit /etc/ssh/sshd_config + +If configured properly, output should be +RekeyLimit + Is it the case that it is commented out or is not set? + + + + Verify Oracle Linux 9 generates an audit record for unsuccessful attempts to use the open_by_handle_at system call. + +If the auditd daemon is configured to use the "augenrules" program to to read audit rules during daemon startup (the default), run the following command: + +$ sudo grep -r open_by_handle_at /etc/audit/rules.d + +If the auditd daemon is configured to use the "auditctl" utility to read audit rules during daemon startup, run the following command: + +$ sudo grep open_by_handle_at /etc/audit/audit.rules + +The output should be the following: + +-a always,exit -F arch=b32 -S open_by_handle_at -F exit=-EPERM -F auid>=1000 -F auid!=unset -k access +-a always,exit -F arch=b64 -S open_by_handle_at -F exit=-EPERM -F auid>=1000 -F auid!=unset -k access +-a always,exit -F arch=b32 -S open_by_handle_at -F exit=-EACCES -F auid>=1000 -F auid!=unset -k access +-a always,exit -F arch=b64 -S open_by_handle_at -F exit=-EACCES -F auid>=1000 -F auid!=unset -k access + Is it the case that the command does not return a line, or the line is commented out? + + + + To check the permissions of /etc/cron.hourly, +run the command: +$ ls -l /etc/cron.hourly +If properly configured, the output should indicate the following permissions: +-rwx------ + Is it the case that /etc/cron.hourly does not have unix mode -rwx------? + + + + Verify the pam_faillock.so module is present in the "/etc/pam.d/password-auth" file: + +$ sudo grep pam_faillock.so /etc/pam.d/password-auth + +auth required pam_faillock.so preauth +auth required pam_faillock.so authfail +account required pam_faillock.so + Is it the case that the pam_faillock.so module is not present in the "/etc/pam.d/password-auth" file with the "preauth" line listed before pam_unix.so? + + + + To verify that Audit Daemon is configured to flush to disk after +every records, run the following command: +$ sudo grep freq /etc/audit/auditd.conf +The output should return the following: +freq = + Is it the case that freq isn't set to <sub idref="var_auditd_freq" />? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_MODULE_SIG_ALL /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + The runtime status of the net.ipv6.conf.all.accept_ra_pinfo kernel parameter can be queried +by running the following command: +$ sysctl net.ipv6.conf.all.accept_ra_pinfo +0. + + Is it the case that the correct value is not returned? + + + + Run the following command to determine if the openssh-clients package is installed: $ rpm -q openssh-clients + Is it the case that the package is not installed? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_UNMAP_KERNEL_AT_EL0 /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To verify the LDAP client backend demands a valid certificate from the server in +remote LDAP access sessions, run the following command: +$ sudo grep ldap_tls_reqcert /etc/sssd/sssd.conf +The output should return the following: +ldap_tls_reqcert = demand + Is it the case that the TLS reqcert is not set to demand? + + + + Verify Oracle Linux 9 prevents the use of dictionary words for passwords with the following command: + +$ sudo grep dictcheck /etc/security/pwquality.conf /etc/pwquality.conf.d/*.conf + +/etc/security/pwquality.conf:dictcheck=1 + Is it the case that "dictcheck" does not have a value other than "0", or is commented out? + + + + To check the ownership of /boot/grub2/user.cfg, +run the command: +$ ls -lL /boot/grub2/user.cfg +If properly configured, the output should indicate the following owner: +root + Is it the case that /boot/grub2/user.cfg does not have an owner of root? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_SCHED_STACK_END_CHECK /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + Run the following command to determine if the logrotate package is installed: $ rpm -q logrotate + Is it the case that the package is not installed? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_PAGE_POISONING_NO_SANITY /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To ensure that users cannot change session idle and lock settings, run the following: +$ grep 'idle-delay' /etc/dconf/db/local.d/locks/* +If properly configured, the output should return: +/org/gnome/desktop/session/idle-delay + Is it the case that idle-delay is not locked? + + + + To check the permissions of /etc/shadow-, +run the command: +$ ls -l /etc/shadow- +If properly configured, the output should indicate the following permissions: +---------- + Is it the case that /etc/shadow- does not have unix mode ----------? + + + + Inspect the firewalld trusted and default zones and verify the loopback traffic is restricted +to the lo interface by running the following command: + +$ sudo firewall-cmd --list-rich-rules --zone=trusted + +The following rich-rules should be listed: + +rule family="ipv4" source address="127.0.0.1" destination not address="127.0.0.1" drop +rule family="ipv6" source address="::1" destination not address="127.0.0.1" drop + + Is it the case that loopback traffic is not restricted? + + + + +Run the following command to get the current configured value for polyinstantiation_enabled +SELinux boolean: +$ getsebool polyinstantiation_enabled +The expected cofiguration is . +"on" means true, and "off" means false + Is it the case that polyinstantiation_enabled is not set as expected? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_MODULE_SIG_KEY /boot/config.* + + For each kernel installed, a line with value "" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To find the location of the AIDE database file, run the following command: +$ sudo ls -l DBDIR/database_file_name + Is it the case that there is no database file? + + + + To check the group ownership of /etc/sudoers.d, +run the command: +$ ls -lL /etc/sudoers.d +If properly configured, the output should indicate the following group-owner: +root + Is it the case that /etc/sudoers.d does not have a group owner of root? + + + + Run the following command to determine if the vsftpd package is installed: +$ rpm -q vsftpd + Is it the case that the package is installed? + + + + To verify the inactive setting, run the following command: +$ grep 'inactive\|pam_unix' /etc/pam.d/system-auth | grep -w auth +The output should indicate the inactive configuration option is set +to an appropriate integer between 1 and +; and should appear +before the pam_unix.so module as shown in the example below: +$ grep 'inactive\|pam_unix' /etc/pam.d/system-auth | grep -w auth +auth required pam_lastlog.so inactive= +auth sufficient pam_unix.so + Is it the case that the value of inactive is incorrect or is not set before pam_unix.so? + + + + To verify the inactive setting, run the following command: +$ grep 'inactive\|pam_unix' /etc/pam.d/password-auth | grep -w auth +The output should indicate the inactive configuration option is set +to an appropriate integer between 1 and +; and should appear +before the pam_unix.so module as shown in the example below: +$ grep 'inactive\|pam_unix' /etc/pam.d/password-auth | grep -w auth +auth required pam_lastlog.so inactive= +auth sufficient pam_unix.so + Is it the case that the value of inactive is incorrect or is not set before pam_unix.so? + + + + To verify that kernel parameter 'crypto.fips_enabled' is set properly, run the following command: +sysctl crypto.fips_enabled +The output should contain the following: +crypto.fips_enabled = 1 + Is it the case that crypto.fips_enabled is not 1? + + + + To check the ownership of /etc/crontab, +run the command: +$ ls -lL /etc/crontab +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/crontab does not have an owner of root? + + + + System executables are stored in the following directories by default: +/bin +/sbin +/usr/bin +/usr/sbin +/usr/local/bin +/usr/local/sbin +To find system executables directories that are group-writable or +world-writable, run the following command for each directory DIR +which contains system executables: +$ sudo find -L DIR -perm /022 -type d + Is it the case that any of these files are group-writable or world-writable? + + + + Verify that Oracle Linux 9 enforces a minimum -character password length with the following command: + +$ grep minlen /etc/security/pwquality.conf + +minlen = + Is it the case that the command does not return a "minlen" value of "<sub idref="var_password_pam_minlen" />" or greater, does not return a line, or the line is commented out? + + + + To check the group ownership of /etc/ipsec.d, +run the command: +$ ls -lL /etc/ipsec.d +If properly configured, the output should indicate the following group-owner: +root + Is it the case that /etc/ipsec.d does not have a group owner of root? + + + + To check the ownership of /etc/cron.allow, +run the command: +$ ls -lL /etc/cron.allow +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/cron.allow does not have an owner of root? + + + + Verify Oracle Linux 9 is configured to lock the root account after +unsuccessful logon attempts with the command: + +$ grep even_deny_root /etc/security/faillock.conf +even_deny_root + Is it the case that the "even_deny_root" option is not set, is missing or commented out? + + + + The runtime status of the net.ipv6.conf.default.accept_ra_defrtr kernel parameter can be queried +by running the following command: +$ sysctl net.ipv6.conf.default.accept_ra_defrtr +0. + + Is it the case that the correct value is not returned? + + + + Verify Oracle Linux 9 generates an audit record for unsuccessful attempts to use the creat system call. + +If the auditd daemon is configured to use the "augenrules" program to to read audit rules during daemon startup (the default), run the following command: + +$ sudo grep -r creat /etc/audit/rules.d + +If the auditd daemon is configured to use the "auditctl" utility to read audit rules during daemon startup, run the following command: + +$ sudo grep creat /etc/audit/audit.rules + +The output should be the following: + +-a always,exit -F arch=b32 -S creat -F exit=-EPERM -F auid>=1000 -F auid!=unset -k access +-a always,exit -F arch=b64 -S creat -F exit=-EPERM -F auid>=1000 -F auid!=unset -k access +-a always,exit -F arch=b32 -S creat -F exit=-EACCES -F auid>=1000 -F auid!=unset -k access +-a always,exit -F arch=b64 -S creat -F exit=-EACCES -F auid>=1000 -F auid!=unset -k access + Is it the case that the command does not return a line, or the line is commented out? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_HARDENED_USERCOPY /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + These settings can be verified by running the following: +$ gsettings get org.gnome.desktop.media-handling automount-open +If properly configured, the output for automount-openshould be false. +To ensure that users cannot enable automount opening in GNOME3, run the following: +$ grep 'automount-open' /etc/dconf/db/local.d/locks/* +If properly configured, the output for automount-open should be /org/gnome/desktop/media-handling/automount-open + Is it the case that GNOME automounting is not disabled? + + + + To determine how the SSH daemon's PubkeyAuthentication option is set, run the following command: + +$ sudo grep -i PubkeyAuthentication /etc/ssh/sshd_config + +If a line indicating no is returned, then the required value is set. + + Is it the case that the required value is not set? + + + + Verify that Oracle Linux 9 is configured to take action in the event of allocated audit record storage volume reaches 95 percent of the repository maximum audit record storage capacity with the following command: + +$ sudo grep admin_space_left_action /etc/audit/auditd.conf + +admin_space_left_action = single + +If the value of the "admin_space_left_action" is not set to "single", or if the line is commented out, ask the System Administrator to indicate how the system is providing real-time alerts to the SA and ISSO. + Is it the case that there is no evidence that real-time alerts are configured on the system? + + + + Run the following command to check if the line is present: +grep pam_wheel /etc/pam.d/su +The output should contain the following line: +auth required pam_wheel.so use_uid group= + Is it the case that the line is not in the file or it is commented? + + + + Verify the "/etc/security/faillock.conf" file is configured use a non-default faillock directory to ensure contents persist after reboot: + +$ sudo grep 'dir =' /etc/security/faillock.conf + +dir = /var/log/faillock + Is it the case that the "dir" option is not set to a non-default documented tally log directory, is missing or commented out? + + + + To ensure the tally directory is configured correctly, run the following command: +$ sudo grep 'dir =' /etc/security/faillock.conf +The output should show that dir is set to something other than "/var/run/faillock" + Is it the case that the "dir" option is not set to a non-default documented tally log directory, is missing or commented out? + + + + Inspect the form of default GRUB 2 command line for the Linux operating system +in /etc/default/grub. If it includes init_on_alloc=1, then the parameter will be configured for newly installed kernels. First check if the GRUB recovery is enabled: $ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub If this option is set to true, then check that a line is output by the following command: -$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*pti=on.*' /etc/default/grub +$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*init_on_alloc=1.*' /etc/default/grub If the recovery is disabled, check the line with -$ sudo grep 'GRUB_CMDLINE_LINUX.*pti=on.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. +$ sudo grep 'GRUB_CMDLINE_LINUX.*init_on_alloc=1.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. Run the following command: -$ sudo grubby --info=ALL | grep args | grep -v 'pti=on' +$ sudo grubby --info=ALL | grep args | grep -v 'init_on_alloc=1' The command should not return any output. - Is it the case that Kernel page-table isolation is not enabled? - - - - Inspect the form of default GRUB 2 command line for the Linux operating system -in /etc/default/grub. If it includes rng_core.default_quality=, + Is it the case that the kernel is not configured to zero out memory before allocation? + + + + Only strong MACs should be used. To verify that only strong +MACs are in use, run the following command: +$ sudo grep -i macs /etc/ssh/sshd_config +The output should contain only those MACs which are strong, namely, + hash functions. + Is it the case that MACs option is commented out or not using strong hash algorithms? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "umount" command with the following command: + +$ sudo auditctl -l | grep umount + +-a always,exit -F path=/usr/bin/umount -F perm=x -F auid>=1000 -F auid!=unset -k privileged-umount + Is it the case that the command does not return a line, or the line is commented out? + + + + Inspect the form of default GRUB 2 command line for the Linux operating system +in /etc/default/grub. If it includes audit_backlog_limit=8192, then the parameter will be configured for newly installed kernels. First check if the GRUB recovery is enabled: $ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub If this option is set to true, then check that a line is output by the following command: -$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*rng_core.default_quality=.*' /etc/default/grub +$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*audit_backlog_limit=8192.*' /etc/default/grub If the recovery is disabled, check the line with -$ sudo grep 'GRUB_CMDLINE_LINUX.*rng_core.default_quality=.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. +$ sudo grep 'GRUB_CMDLINE_LINUX.*audit_backlog_limit=8192.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. Run the following command: -$ sudo grubby --info=ALL | grep args | grep -v 'rng_core.default_quality=' +$ sudo grubby --info=ALL | grep args | grep -v 'audit_backlog_limit=8192' The command should not return any output. - Is it the case that trust on hardware random number generator is not configured appropriately? - - - - Inspect the form of default GRUB 2 command line for the Linux operating system -in /etc/default/grub. If it includes slab_nomerge=yes, -then the parameter will be configured for newly installed kernels. -First check if the GRUB recovery is enabled: -$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub -If this option is set to true, then check that a line is output by the following command: -$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*slab_nomerge=yes.*' /etc/default/grub -If the recovery is disabled, check the line with -$ sudo grep 'GRUB_CMDLINE_LINUX.*slab_nomerge=yes.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. -Run the following command: -$ sudo grubby --info=ALL | grep args | grep -v 'slab_nomerge=yes' -The command should not return any output. - Is it the case that merging of slabs with similar size is enabled? - - - - Inspect the form of default GRUB 2 command line for the Linux operating system -in /etc/default/grub. If it includes spec_store_bypass_disable=, -then the parameter will be configured for newly installed kernels. -First check if the GRUB recovery is enabled: -$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub -If this option is set to true, then check that a line is output by the following command: -$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*spec_store_bypass_disable=.*' /etc/default/grub -If the recovery is disabled, check the line with -$ sudo grep 'GRUB_CMDLINE_LINUX.*spec_store_bypass_disable=.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. -Run the following command: -$ sudo grubby --info=ALL | grep args | grep -v 'spec_store_bypass_disable=' -The command should not return any output. - Is it the case that SSB is not configured appropriately? - - - - Inspect the form of default GRUB 2 command line for the Linux operating system + Is it the case that audit backlog limit is not configured? + + + + Run the following command to determine if the postfix package is installed: $ rpm -q postfix + Is it the case that the package is not installed? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_BUG_ON_DATA_CORRUPTION /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To check the group ownership of /etc/cron.deny, +run the command: +$ ls -lL /etc/cron.deny +If properly configured, the output should indicate the following group-owner: +root + Is it the case that /etc/cron.deny does not have a group owner of root? + + + + The runtime status of the kernel.unprivileged_bpf_disabled kernel parameter can be queried +by running the following command: +$ sysctl kernel.unprivileged_bpf_disabled +1. + + Is it the case that the correct value is not returned? + + + + The runtime status of the kernel.sysrq kernel parameter can be queried +by running the following command: +$ sysctl kernel.sysrq +0. + + Is it the case that the correct value is not returned? + + + + + +Run the following command to determine the current status of the +systemd-journald service: +$ sudo systemctl is-active systemd-journald +If the service is running, it should return the following: active + Is it the case that the systemd-journald service is not running? + + + + Verify that Oracle Linux 9 enforces password complexity by requiring that at least one special character with the following command: + +$ sudo grep ocredit /etc/security/pwquality.conf /etc/security/pwquality.conf.d/*.conf + +ocredit = + Is it the case that value of "ocredit" is a positive number or is commented out? + + + + Verify that all local interactive user initialization file executable search path statements do not contain statements that will reference a working directory other than user home directories with the following commands: + +$ sudo grep -i path= /home/*/.* + +/home/[localinteractiveuser]/.bash_profile:PATH=$PATH:$HOME/.local/bin:$HOME/bin + Is it the case that any local interactive user initialization files have executable search path statements that include directories outside of their home directory and is not documented with the ISSO as an operational requirement? + + + + Verify the audit log directories have a correct mode or less permissive mode. + +Find the location of the audit logs: + +$ sudo grep "^log_file" /etc/audit/auditd.conf + + +Find the group that owns audit logs: + +$ sudo grep "^log_group" /etc/audit/auditd.conf + + +Run the following command to check the mode of the system audit logs: + +$ sudo stat -c "%a %n" [audit_log_directory] + +Replace "[audit_log_directory]" to the correct audit log directory path, by default this location is "/var/log/audit". + + +If the log_group is "root" or is not set, the correct permissions are 0700, otherwise they are 0750. + Is it the case that audit logs have a more permissive mode? + + + + To determine the config value the kernel was built with, run the following command: +$ grep CONFIG_DEFAULT_MMAP_MIN_ADDR /boot/config.* +For each kernel installed, a line with value should be returned. +If the system architecture is x86_64, the value should be 65536. +If the system architecture is aarch64, the value should be 32768. + Is it the case that the kernel was not built with the required value? + + + + These settings can be verified by running the following: +$ gsettings get org.gnome.desktop.media-handling automount +If properly configured, the output for automount should be false. +To ensure that users cannot enable automount in GNOME3, run the following: +$ grep 'automount' /etc/dconf/db/local.d/locks/* +If properly configured, the output for automount should be /org/gnome/desktop/media-handling/automount + Is it the case that GNOME automounting is not disabled? + + + + Verify Oracle Linux 9 generates an audit record for unsuccessful attempts to use the open system call. + +If the auditd daemon is configured to use the "augenrules" program to to read audit rules during daemon startup (the default), run the following command: + +$ sudo grep -r open /etc/audit/rules.d + +If the auditd daemon is configured to use the "auditctl" utility to read audit rules during daemon startup, run the following command: + +$ sudo grep open /etc/audit/audit.rules + +The output should be the following: + +-a always,exit -F arch=b32 -S open -F exit=-EPERM -F auid>=1000 -F auid!=unset -k access +-a always,exit -F arch=b64 -S open -F exit=-EPERM -F auid>=1000 -F auid!=unset -k access +-a always,exit -F arch=b32 -S open -F exit=-EACCES -F auid>=1000 -F auid!=unset -k access +-a always,exit -F arch=b64 -S open -F exit=-EACCES -F auid>=1000 -F auid!=unset -k access + Is it the case that the command does not return a line, or the line is commented out? + + + + To determine how the SSH daemon's HostbasedAuthentication option is set, run the following command: + +$ sudo grep -i HostbasedAuthentication /etc/ssh/sshd_config + +If a line indicating no is returned, then the required value is set. + + Is it the case that the required value is not set? + + + + +To properly set the owner of /var/log/audit, run the command: +$ sudo chown root /var/log/audit + +To properly set the owner of /var/log/audit/*, run the command: +$ sudo chown root /var/log/audit/* + Is it the case that ? + + + + Verify the nosuid option is configured for the /boot mount point, + run the following command: + $ sudo mount | grep '\s/boot\s' + . . . /boot . . . nosuid . . . + + Is it the case that the "/boot" file system does not have the "nosuid" option set? + + + + To verify that Audit Daemon is configured to write logs to the disk, run the +following command: +$ sudo grep write_logs /etc/audit/auditd.conf +The output should return the following: +write_logs = yes + Is it the case that write_logs isn't set to yes? + + + + Verify Oracle Linux 9 notifies the SA and ISSO (at a minimum) when allocated audit record storage volume reaches 75 percent of the repository maximum audit record storage capacity with the following command: + +$ sudo grep -w space_left_action /etc/audit/auditd.conf + +space_left_action = + +If the value of the "space_left_action" is not set to "", or if the line is commented out, ask the System Administrator to indicate how the system is providing real-time alerts to the SA and ISSO. + Is it the case that there is no evidence that real-time alerts are configured on the system? + + + + The runtime status of the net.ipv6.conf.all.max_addresses kernel parameter can be queried +by running the following command: +$ sysctl net.ipv6.conf.all.max_addresses +1. + + Is it the case that the correct value is not returned? + + + + The runtime status of the net.ipv4.conf.all.arp_filter kernel parameter can be queried +by running the following command: +$ sysctl net.ipv4.conf.all.arp_filter +. + + Is it the case that the correct value is not returned? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_MODULE_SIG_FORCE /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + Verify the system commands contained in the following directories are owned by "root" with the following command: + +$ sudo find -L /bin /sbin /usr/bin /usr/sbin /usr/libexec /usr/local/bin /usr/local/sbin ! -user root -exec ls -l {} \; + Is it the case that any system commands are found to not be owned by root? + + + + To verify the password reuse setting is compliant, run the following command: +$ grep remember /etc/pam.d/system-auth +The output should show the following at the end of the line: +remember= + + +In newer systems, the pam_pwhistory PAM module options can also be set in +"/etc/security/pwhistory.conf" file. Use the following command to verify: +$ grep remember /etc/security/pwhistory.conf +remember = + +The pam_pwhistory remember option must be configured only in one file. + Is it the case that the value of remember is not equal to or greater than the expected value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_LEGACY_VSYSCALL_EMULATE /boot/config.* + + Configs with value 'n' are not explicitly set in the file, so either commented lines or no + lines should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To verify that the Audit is correctly configured according to recommended rules, check the content of the file with the following command: +cat /etc/audit/rules.d/30-ospp-v42-1-create-failed.rules +The output has to be exactly as follows: +## Unsuccessful file creation (open with O_CREAT) +-a always,exit -F arch=b32 -S openat,open_by_handle_at -F a2&0100 -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-create +-a always,exit -F arch=b64 -S openat,open_by_handle_at -F a2&0100 -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-create +-a always,exit -F arch=b32 -S open -F a1&0100 -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-create +-a always,exit -F arch=b64 -S open -F a1&0100 -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-create +-a always,exit -F arch=b32 -S creat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-create +-a always,exit -F arch=b64 -S creat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-create +-a always,exit -F arch=b32 -S openat,open_by_handle_at -F a2&0100 -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-create +-a always,exit -F arch=b64 -S openat,open_by_handle_at -F a2&0100 -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-create +-a always,exit -F arch=b32 -S open -F a1&0100 -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-create +-a always,exit -F arch=b64 -S open -F a1&0100 -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-create +-a always,exit -F arch=b32 -S creat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-create +-a always,exit -F arch=b64 -S creat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-create + Is it the case that the file does not exist or the content differs? + + + + To check the group ownership of /boot/grub2/user.cfg, +run the command: +$ ls -lL /boot/grub2/user.cfg +If properly configured, the output should indicate the following group-owner: +root + Is it the case that /boot/grub2/user.cfg does not have a group owner of root? + + + + To ensure that the GPG key is installed, run: +$ rpm -q --queryformat "%{SUMMARY}\n" gpg-pubkey +The command should return the string below: +gpg(Oracle OSS group (Open Source Software group) <build@oss.oracle.com> + Is it the case that the Oracle GPG Key is not installed? + + + + To verify that Audit Daemon is configured to include local events, run the +following command: +$ sudo grep local_events /etc/audit/auditd.conf +The output should return the following: +local_events = yes + Is it the case that local_events isn't set to yes? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_STACKPROTECTOR /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + Verify the grpquota option is configured for the /home mount point, + run the following command: + $ sudo mount | grep '\s/home\s' + . . . /home . . . grpquota . . . + + Is it the case that the "/home" file system does not have the "grpquota" option set? + + + + Verify Oracle Linux 9 use the "pam_pwhistory.so" module in the /etc/pam.d/password-auth file +and is configured to prohibit password reuse for a minimum of +generations. + +Verify the "/etc/pam.d/password-auth" file with the following command: + +$ grep pam_pwhistory.so /etc/pam.d/password-auth +password pam_pwhistory.so use_authtok remember= + + +Verify the "/etc/security/pwhistory.conf" file using the following command: + +$ grep remember /etc/security/pwhistory.conf +remember = + +The pam_pwhistory.so "remember" option must be configured only in one file. + Is it the case that the pam_pwhistory.so module is not used, the "remember" module option is not set in +/etc/pam.d/password-auth or in /etc/security/pwhistory.conf, or is set in both files, or is set +with a value less than "<sub idref="var_password_pam_remember" />"? + + + + Run the following command to determine if the openssh-server package is installed: $ rpm -q openssh-server + Is it the case that the package is not installed? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "postdrop" command with the following command: + +$ sudo auditctl -l | grep postdrop + +-a always,exit -F path=/usr/bin/postdrop -F perm=x -F auid>=1000 -F auid!=unset -k privileged-postdrop + Is it the case that the command does not return a line, or the line is commented out? + + + + Verify Oracle Linux 9 generates audit records for all account creations, modifications, disabling, and termination events that affect "/etc/sudoers.d/" with the following command: + +$ sudo auditctl -l | grep/etc/sudoers.d + +-w /etc/sudoers.d/ -p wa -k identity + Is it the case that the command does not return a line, or the line is commented out? + + + + The runtime status of the net.ipv6.conf.all.forwarding kernel parameter can be queried +by running the following command: +$ sysctl net.ipv6.conf.all.forwarding +0. +The ability to forward packets is only appropriate for routers. + Is it the case that IP forwarding value is "1" and the system is not router? + + + + To determine if the system is configured to audit attempts to +alter time via the /etc/localtime file, run the following +command: +$ sudo auditctl -l | grep "watch=/etc/localtime" +If the system is configured to audit this activity, it will return a line. + Is it the case that the system is not configured to audit time changes? + + + + The runtime status of the net.ipv4.conf.all.forwarding kernel parameter can be queried +by running the following command: +$ sysctl net.ipv4.conf.all.forwarding +0. +The ability to forward packets is only appropriate for routers. + Is it the case that IP forwarding value is "1" and the system is not router? + + + + Run the following command to determine if the fapolicyd package is installed: $ rpm -q fapolicyd + Is it the case that the fapolicyd package is not installed? + + + + +To ensure the login warning banner text is properly set, run the following: +$ grep banner-message-text /etc/dconf/db/local.d/* +If properly configured, the proper banner text will appear. +To ensure the login warning banner text is locked and cannot be changed by a user, run the following: +$ grep banner-message-text /etc/dconf/db/local.d/locks/* +If properly configured, the output should be /org/gnome/login-screen/banner-message-text. + Is it the case that it does not? + + + + Inspect the form of default GRUB 2 command line for the Linux operating system in /etc/default/grub. If it includes spectre_v2=on, then the parameter will be configured for newly installed kernels. First check if the GRUB recovery is enabled: @@ -238874,543 +260133,125 @@ Run the following command: $ sudo grubby --info=ALL | grep args | grep -v 'spectre_v2=on' The command should not return any output. Is it the case that spectre_v2 mitigation is not enforced? - - - - Ensure that debug-shell service is not enabled with the following command: -grep systemd\.debug-shell=1 /boot/grub2/grubenv /etc/default/grub -If the command returns a line, it means that debug-shell service is being enabled. - Is it the case that the comand returns a line? - - - - Inspect the form of default GRUB 2 command line for the Linux operating system -in /etc/default/grub. If it includes vsyscall=none, -then the parameter will be configured for newly installed kernels. -First check if the GRUB recovery is enabled: -$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub -If this option is set to true, then check that a line is output by the following command: -$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*vsyscall=none.*' /etc/default/grub -If the recovery is disabled, check the line with -$ sudo grep 'GRUB_CMDLINE_LINUX.*vsyscall=none.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. -Run the following command: -$ sudo grubby --info=ALL | grep args | grep -v 'vsyscall=none' -The command should not return any output. - Is it the case that vsyscalls are enabled? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_ACPI_CUSTOM_METHOD /boot/config.* - - Configs with value 'n' are not explicitly set in the file, so either commented lines or no - lines should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_BINFMT_MISC /boot/config.* - - Configs with value 'n' are not explicitly set in the file, so either commented lines or no - lines should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_BUG /boot/config.* + + + + The runtime status of the net.ipv6.conf.all.accept_source_route kernel parameter can be queried +by running the following command: +$ sysctl net.ipv6.conf.all.accept_source_route +0. + + Is it the case that the correct value is not returned? + + + + The runtime status of the net.ipv6.conf.default.autoconf kernel parameter can be queried +by running the following command: +$ sysctl net.ipv6.conf.default.autoconf +0. + + Is it the case that the correct value is not returned? + + + + The runtime status of the vm.mmap_min_addr kernel parameter can be queried +by running the following command: +$ sysctl vm.mmap_min_addr +65536. + + Is it the case that the correct value is not returned? + + + + To check the permissions of /etc/ipsec.conf, +run the command: +$ ls -l /etc/ipsec.conf +If properly configured, the output should indicate the following permissions: +0644 + Is it the case that /etc/ipsec.conf does not have unix mode 0644? + + + + The runtime status of the net.ipv4.tcp_syncookies kernel parameter can be queried +by running the following command: +$ sysctl net.ipv4.tcp_syncookies +1. + + Is it the case that the correct value is not returned? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_GCC_PLUGIN_STRUCTLEAK /boot/config.* For each kernel installed, a line with value "y" should be returned. Is it the case that the kernel was not built with the required value? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_COMPAT_BRK /boot/config.* - - Configs with value 'n' are not explicitly set in the file, so either commented lines or no - lines should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_COMPAT_VDSO /boot/config.* - - Configs with value 'n' are not explicitly set in the file, so either commented lines or no - lines should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_DEBUG_CREDENTIALS /boot/config.* + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_ARM64_SW_TTBR0_PAN /boot/config.* For each kernel installed, a line with value "y" should be returned. Is it the case that the kernel was not built with the required value? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_DEBUG_FS /boot/config.* - - Configs with value 'n' are not explicitly set in the file, so either commented lines or no - lines should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_DEBUG_LIST /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_DEBUG_NOTIFIERS /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_DEBUG_SG /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_DEFAULT_MMAP_MIN_ADDR /boot/config.* - - For each kernel installed, a line with value "65536" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_DEVKMEM /boot/config.* - - Configs with value 'n' are not explicitly set in the file, so either commented lines or no - lines should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_HIBERNATION /boot/config.* - - Configs with value 'n' are not explicitly set in the file, so either commented lines or no - lines should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To determine the config value the kernel was built with, run the following command: + + + + If the system uses IPv6, this is not applicable. + +If the system is configured to prevent the usage of the ipv6 on +network interfaces, it will contain a line of the form: +net.ipv6.conf.default.disable_ipv6 = 1 +Such lines may be inside any file in the /etc/sysctl.d directory. +This permits insertion of the IPv6 kernel module (which other parts of the +system expect to be present), but otherwise keeps network interfaces +from using IPv6. Run the following command to search for such lines in all +files in /etc/sysctl.d: +$ grep -r ipv6 /etc/sysctl.d + Is it the case that the ipv6 support is disabled by default on network interfaces? + + + + Verify the nosuid option is configured for the /srv mount point, + run the following command: + $ sudo mount | grep '\s/srv\s' + . . . /srv . . . nosuid . . . + + Is it the case that the "/srv" file system does not have the "nosuid" option set? + + + + To ensure the user list is disabled, run the following command: +$ grep disable-user-list /etc/dconf/db/local.d/* +The output should be true. +To ensure that users cannot enable displaying the user list, run the following: +$ grep disable-user-list /etc/dconf/db/local.d/locks/* +If properly configured, the output should be /org/gnome/login-screen/disable-user-list + Is it the case that disable-user-list has not been configured or is not disabled? + + + + To determine the config value the kernel was built with, run the following command: $ grep CONFIG_IA32_EMULATION /boot/config.* Configs with value 'n' are not explicitly set in the file, so either commented lines or no lines should be returned. Is it the case that the kernel was not built with the required value? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_IPV6 /boot/config.* - - Configs with value 'n' are not explicitly set in the file, so either commented lines or no - lines should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_KEXEC /boot/config.* - - Configs with value 'n' are not explicitly set in the file, so either commented lines or no - lines should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_LEGACY_PTYS /boot/config.* - - Configs with value 'n' are not explicitly set in the file, so either commented lines or no - lines should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_MODULE_SIG /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_MODULE_SIG_ALL /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_MODULE_SIG_FORCE /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_MODULE_SIG_HASH /boot/config.* - - For each kernel installed, a line with value "" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_MODULE_SIG_KEY /boot/config.* - - For each kernel installed, a line with value "" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_MODULE_SIG_SHA512 /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_PAGE_POISONING_NO_SANITY /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_PAGE_POISONING_ZERO /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_PAGE_TABLE_ISOLATION /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_PANIC_ON_OOPS /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_PANIC_TIMEOUT /boot/config.* - - For each kernel installed, a line with value "" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_PROC_KCORE /boot/config.* - - Configs with value 'n' are not explicitly set in the file, so either commented lines or no - lines should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_RANDOMIZE_BASE /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_RANDOMIZE_MEMORY /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_RETPOLINE /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_SECCOMP /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_SECCOMP_FILTER /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_SECURITY /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_SECURITY_DMESG_RESTRICT /boot/config.* - - Configs with value 'n' are not explicitly set in the file, so either commented lines or no - lines should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_SECURITY_WRITABLE_HOOKS /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_SECURITY_YAMA /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_SLUB_DEBUG /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_SYN_COOKIES /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_UNMAP_KERNEL_AT_EL0 /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_X86_VSYSCALL_EMULATION /boot/config.* - - Configs with value 'n' are not explicitly set in the file, so either commented lines or no - lines should be returned. - - Is it the case that the kernel was not built with the required value? - - - - Verify that cron is logging to rsyslog, -run the following command: -grep -rni "cron\.\*" /etc/rsyslog.* -cron.* /var/log/cron - Is it the case that cron is not logging to rsyslog? - - - - Verify the operating system authenticates the remote logging server for off-loading audit logs with the following command: + + + + Verify that GRUB_DISABLE_RECOVERY is set to true in /etc/default/grub to disable recovery boot. +Run the following command: -$ sudo grep -i '$ActionSendStreamDriverAuthMode' /etc/rsyslog.conf /etc/rsyslog.d/*.conf -The output should be -$/etc/rsyslog.conf:$ActionSendStreamDriverAuthMode x509/name - Is it the case that $ActionSendStreamDriverAuthMode in /etc/rsyslog.conf is not set to x509/name? - - - - Verify the operating system encrypts audit records off-loaded onto a different system -or media from the system being audited with the following commands: - -$ sudo grep -i '$ActionSendStreamDriverMode' /etc/rsyslog.conf /etc/rsyslog.d/*.conf - -The output should be: - -/etc/rsyslog.conf:$ActionSendStreamDriverMode 1 - Is it the case that rsyslogd ActionSendStreamDriverMode is not set to 1? - - - - Verify the operating system encrypts audit records off-loaded onto a different system -or media from the system being audited with the following commands: - -$ sudo grep -i '$DefaultNetstreamDriver' /etc/rsyslog.conf /etc/rsyslog.d/*.conf - -The output should be: - -/etc/rsyslog.conf:$DefaultNetstreamDriver gtls - Is it the case that rsyslogd DefaultNetstreamDriver not set to gtls? - - - - The group-owner of all log files written by rsyslog should be - -root. - -These log files are determined by the second part of each Rule line in -/etc/rsyslog.conf and typically all appear in /var/log. -To see the group-owner of a given log file, run the following command: -$ ls -l LOGFILE - Is it the case that the group-owner is not correct? - - - - The owner of all log files written by rsyslog should be - -root. - -These log files are determined by the second part of each Rule line in -/etc/rsyslog.conf and typically all appear in /var/log. -To see the owner of a given log file, run the following command: -$ ls -l LOGFILE - Is it the case that the owner is not correct? - - - - The file permissions for all log files written by rsyslog should -be set to 640, or more restrictive. These log files are determined by the -second part of each Rule line in /etc/rsyslog.conf and typically -all appear in /var/log. To see the permissions of a given log -file, run the following command: -$ ls -l LOGFILE -The permissions should be 640, or more restrictive. - Is it the case that the permissions are not correct? - - - - To verify that remote access methods are logging to rsyslog, -run the following command: -grep -rE '(auth.\*|authpriv.\*|daemon.\*)' /etc/rsyslog.* -The output should contain auth.*, authpriv.*, and daemon.* -pointing to a log file. - Is it the case that remote access methods are not logging to rsyslog? - - - - - -Run the following command to determine the current status of the -systemd-journald service: -$ sudo systemctl is-active systemd-journald -If the service is running, it should return the following: active - Is it the case that the systemd-journald service is not running? - - - - To determine the status and frequency of logrotate, run the following command: -$ sudo grep logrotate /var/log/cron* -If logrotate is configured properly, output should include references to -/etc/cron.daily. - Is it the case that logrotate is not configured to run daily? - - - - Run the following command to determine if the logrotate package is installed: $ rpm -q logrotate - Is it the case that the package is not installed? - - - - Run the following command to determine the current status of the logrotate timer: $ sudo systemctl is-active logrotate.timer If the timer is running, it should return the following: active - Is it the case that logrotate timer is not enabled? - - - - Run the following command to determine if the syslog-ng-core package is installed: $ rpm -q syslog-ng-core - Is it the case that the package is not installed? - - - - Verify that the system is not accepting "rsyslog" messages from other systems unless it is +$ sudo grep GRUB_DISABLE_RECOVERY /etc/default/grub + Is it the case that GRUB_DISABLE_RECOVERY is not set to true or is missing? + + + + Verify that the system is not accepting "rsyslog" messages from other systems unless it is documented as a log aggregation server. Display the contents of the rsyslog configuration files: find /etc -maxdepth 2 -regex '/etc/rsyslog\(\.conf\|\.d\/.*\.conf\)' -exec cat '{}' \; @@ -239433,137 +260274,836 @@ input(type="imtcp" port="514") input(type="imudp" port="514") Is it the case that rsyslog accepts remote messages and is not documented as a log aggregation system? - - - - + + + + To verify all accounts have unique names, run the following command: +$ sudo getent passwd | awk -F: '{ print $1}' | uniq -d +No output should be returned. + Is it the case that a line is returned? + + + + To check the group ownership of /etc/cron.weekly, +run the command: +$ ls -lL /etc/cron.weekly +If properly configured, the output should indicate the following group-owner: +root + Is it the case that /etc/cron.weekly does not have a group owner of root? + + + + Check that Oracle Linux 9 has the packages for smart card support installed. -Run the following command to determine the current status of the -syslog-ng service: -$ sudo systemctl is-active syslog-ng -If the service is running, it should return the following: active - Is it the case that the "syslog-ng" service is disabled, masked, or not started.? - - - - To ensure logs are sent to a remote host, examine the file -/etc/rsyslog.conf. -If using UDP, a line similar to the following should be present: - *.* @ -If using TCP, a line similar to the following should be present: - *.* @@ -If using RELP, a line similar to the following should be present: - *.* :omrelp: - Is it the case that no evidence that the audit logs are being off-loaded to another system or media? - - - - To verify that rsyslog's Forwarding Output Module is configured -to use TLS for logging to remote server, run the following command: -$ grep omfwd /etc/rsyslog.conf /etc/rsyslog.d/*.conf -The output should include record similar to -action(type="omfwd" protocol="tcp" Target="<remote system>" port="6514" - StreamDriver="gtls" StreamDriverMode="1" StreamDriverAuthMode="x509/name" streamdriver.CheckExtendedKeyPurpose="on") +Run the following command to determine if the openssl-pkcs11 package is installed: +$ rpm -q openssl-pkcs11 + Is it the case that smartcard software is not installed? + + + + To verify if the OpenSSH server uses defined ciphers in the Crypto Policy, run: +$ grep -Po '(-oCiphers=\S+)' /etc/crypto-policies/back-ends/opensshserver.config +and verify that the line matches: +-oCiphers= + Is it the case that Crypto Policy for OpenSSH Server is not configured correctly? + + + + To check the group ownership of /boot/grub2/grub.cfg, +run the command: +$ ls -lL /boot/grub2/grub.cfg +If properly configured, the output should indicate the following group-owner: +root + Is it the case that /boot/grub2/grub.cfg does not have a group owner of root? + + + + Inspect the form of default GRUB 2 command line for the Linux operating system +in /etc/default/grub. If it includes pti=on, +then the parameter will be configured for newly installed kernels. +First check if the GRUB recovery is enabled: +$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub +If this option is set to true, then check that a line is output by the following command: +$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*pti=on.*' /etc/default/grub +If the recovery is disabled, check the line with +$ sudo grep 'GRUB_CMDLINE_LINUX.*pti=on.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. +Run the following command: +$ sudo grubby --info=ALL | grep args | grep -v 'pti=on' +The command should not return any output. + Is it the case that Kernel page-table isolation is not enabled? + + + + To check the system for the existence of any .netrc files, +run the following command: +$ sudo find /home -xdev -name .netrc + Is it the case that any .netrc files exist? + + + + Verify Oracle Linux 9 generates audit records for all account creations, modifications, disabling, and termination events that affect "/var/log/tallylog" with the following command: -where the <remote system> present in the configuration line above must be a valid IP address or a host name of the remote logging server. - Is it the case that omfwd is not configured with gtls and AuthMode? - - - - To verify that rsyslog's Forwarding Output Module has CA certificate -configured for its TLS connections to remote server, run the following command: -$ grep DefaultNetstreamDriverCAFile /etc/rsyslog.conf /etc/rsyslog.d/*.conf -The output should include record similar to -global(DefaultNetstreamDriverCAFile="/etc/pki/tls/cert.pem") -where the path to the CA file (/etc/pki/tls/cert.pem in case above) must point to the correct CA certificate. - Is it the case that CA certificate for rsyslog remote logging via TLS is not set? - - - - Run the following command to determine if the rsyslog-gnutls package is installed: -$ rpm -q rsyslog-gnutls +$ sudo auditctl -l | grep /var/log/tallylog + +-w /var/log/tallylog -p wa -k logins + Is it the case that the command does not return a line, or the line is commented out? + + + + +Determine the audit log group by running the following command: + +$ sudo grep -P '^[ ]*log_group[ ]+=.*$' /etc/audit/auditd.conf + +Then, check that all directories within the /var/log/audit directory are owned by the group specified as log_group or by root if the log_group is not specified. +Run the following command: + +$ sudo find /var/log/audit -type d -printf "%p %g\n" + +All listed directories must be owned by the log_group or by root if the log_group is not specified. + Is it the case that there is a directory owned by different group? + + + + To verify the assigned home directory of all interactive user home directories +have a mode of 0750 or less permissive, run the following command: +$ sudo ls -l /home +Inspect the output for any directories with incorrect permissions. + Is it the case that they are more permissive? + + + + Run the following command to determine if the nss-tools package is installed: $ rpm -q nss-tools + Is it the case that the package is not installed? + + + + To verify that auditing of privileged command use is configured, run the +following command: +$ sudo grep '\bat\b' /etc/audit/audit.rules /etc/audit/rules.d/* +It should return a relevant line in the audit rules. + Is it the case that the command does not return a line, or the line is commented out? + + + + To check the group ownership of /etc/ssh/*_key, +run the command: +$ ls -lL /etc/ssh/*_key +If properly configured, the output should indicate the following group-owner: +root + Is it the case that /etc/ssh/*_key does not have a group owner of root? + + + + To check that the sshd service is disabled in system boot configuration, +run the following command: +$ sudo systemctl is-enabled sshd +Output should indicate the sshd service has either not been installed, +or has been disabled at all runlevels, as shown in the example below: +$ sudo systemctl is-enabled sshd disabled + +Run the following command to verify sshd is not active (i.e. not running) through current runtime configuration: +$ sudo systemctl is-active sshd + +If the service is not running the command will return the following output: +inactive + +The service will also be masked, to check that the sshd is masked, run the following command: +$ sudo systemctl show sshd | grep "LoadState\|UnitFileState" + +If the service is masked the command will return the following outputs: + +LoadState=masked + +UnitFileState=masked + Is it the case that the "sshd" is loaded and not masked? + + + + Run the following command to ensure that /var/tmp is configured as a +polyinstantiated directory: +$ sudo grep /var/tmp /etc/security/namespace.conf +The output should return the following: +/var/tmp /var/tmp/tmp-inst/ level root,adm + Is it the case that is not configured? + + + + To check the ownership of /etc/cron.daily, +run the command: +$ ls -lL /etc/cron.daily +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/cron.daily does not have an owner of root? + + + + Run the following command to determine the current status of the logrotate timer: $ sudo systemctl is-active logrotate.timer If the timer is running, it should return the following: active + Is it the case that logrotate timer is not enabled? + + + + To verify the assigned home directory of all interactive users is group- +owned by that users primary GID, run the following command: +# ls -ld $(awk -F: '($3>=1000)&&($7 !~ /nologin/){print $6}' /etc/passwd) + Is it the case that the group ownership is incorrect? + + + + Inspect the file /etc/sysconfig/iptables to determine +the default policy for the INPUT chain. It should be set to DROP: +$ sudo grep ":INPUT" /etc/sysconfig/iptables + Is it the case that the default policy for the INPUT chain is not set to DROP? + + + + The existence of the file /etc/hosts.equiv or a file named +.rhosts inside a user home directory indicates the presence +of an Rsh trust relationship. + Is it the case that these files exist? + + + + To find world-writable directories that lack the sticky bit, run the following command: +$ sudo find / -type d \( -perm -0002 -a ! -perm -1000 \) -print 2>/dev/null +fixtext: |- +Configure all world-writable directories to have the sticky bit set to prevent unauthorized and unintended information transferred via shared system resources. + +Set the sticky bit on all world-writable directories using the command, replace "[World-Writable Directory]" with any directory path missing the sticky bit: + +$ chmod a+t [World-Writable Directory] +srg_requirement: +A sticky bit must be set on all Oracle Linux 9 public directories to prevent unauthorized and unintended information transferred via shared system resources. + Is it the case that any world-writable directories are missing the sticky bit? + + + + The runtime status of the net.ipv6.conf.all.autoconf kernel parameter can be queried +by running the following command: +$ sysctl net.ipv6.conf.all.autoconf +0. + + Is it the case that the correct value is not returned? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_PAGE_TABLE_ISOLATION /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "kmod" command with the following command: + +$ sudo auditctl -l | grep kmod + +-a always,exit -F path=/usr/bin/kmod -F perm=x -F auid>=1000 -F auid!=unset -k privileged-kmod + Is it the case that the command does not return a line, or the line is commented out? + + + + Run the following command to determine if the telnet-server package is installed: +$ rpm -q telnet-server Is it the case that the package is installed? - - - - Run the following command to determine if the rsyslog package is installed: $ rpm -q rsyslog + + + + To check the ownership of /etc/selinux, +run the command: +$ ls -lL /etc/selinux +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/selinux does not have an owner of root? + + + + Run the following command to determine if the openscap-scanner package is installed: $ rpm -q openscap-scanner Is it the case that the package is not installed? - - - - + + + + Verify Oracle Linux 9 enforces a delay of at least seconds between console logon prompts following a failed logon attempt with the following command: -Run the following command to determine the current status of the -rsyslog service: -$ sudo systemctl is-active rsyslog -If the service is running, it should return the following: active - Is it the case that the "rsyslog" service is disabled, masked, or not started.? - - - - Run the following command to determine if the firewalld package is installed: $ rpm -q firewalld - Is it the case that the package is not installed? - - - - +$ sudo grep -i "FAIL_DELAY" /etc/login.defs +FAIL_DELAY + Is it the case that the value of "FAIL_DELAY" is not set to "<sub idref="var_accounts_fail_delay" />" or greater, or the line is commented out? + + + + To determine if the system is configured to audit calls to the +delete_module system call, run the following command: +$ sudo grep "delete_module" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. -Run the following command to determine the current status of the -firewalld service: -$ sudo systemctl is-active firewalld -If the service is running, it should return the following: active - Is it the case that the "firewalld" service is disabled, masked, or not started.? - - - - Inspect the list of enabled firewall ports and verify they are configured correctly by running + Is it the case that no line is returned? + + + + To check the ownership of /etc/shadow, +run the command: +$ ls -lL /etc/shadow +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/shadow does not have an owner of root? + + + + To check the ownership of /etc/crypttab, +run the command: +$ ls -lL /etc/crypttab +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/crypttab does not have an owner of root? + + + + To check the permissions of /etc/chrony.keys, +run the command: +$ ls -l /etc/chrony.keys +If properly configured, the output should indicate the following permissions: +0640 + Is it the case that /etc/chrony.keys does not have unix mode 0640? + + + + Shared libraries are stored in the following directories: +/lib +/lib64 +/usr/lib +/usr/lib64 + +To find shared libraries that are group-writable or world-writable, +run the following command for each directory DIR which contains shared libraries: +$ sudo find -L DIR -perm /022 -type d + Is it the case that any of these files are group-writable or world-writable? + + + + To determine if the system is configured to audit calls to the +fchown system call, run the following command: +$ sudo grep "fchown" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. + + Is it the case that no line is returned? + + + + To check that the atd service is disabled in system boot configuration, +run the following command: +$ sudo systemctl is-enabled atd +Output should indicate the atd service has either not been installed, +or has been disabled at all runlevels, as shown in the example below: +$ sudo systemctl is-enabled atd disabled + +Run the following command to verify atd is not active (i.e. not running) through current runtime configuration: +$ sudo systemctl is-active atd + +If the service is not running the command will return the following output: +inactive + +The service will also be masked, to check that the atd is masked, run the following command: +$ sudo systemctl show atd | grep "LoadState\|UnitFileState" + +If the service is masked the command will return the following outputs: + +LoadState=masked + +UnitFileState=masked + Is it the case that the "atd" is loaded and not masked? + + + + Verify Oracle Linux 9 generates audit records for all account creations, modifications, disabling, and termination events that affect "/etc/sudoers" with the following command: + +$ sudo auditctl -l | grep /etc/sudoers + +-w /etc/sudoers -p wa -k identity + Is it the case that the command does not return a line, or the line is commented out? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_STACKPROTECTOR_STRONG /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + Inspect the list of enabled firewall ports and verify they are configured correctly by running the following command: $ sudo firewall-cmd --list-all Ask the System Administrator for the site or program Ports, Protocols, and Services Management Component Local Service Assessment (PPSM CLSA). Verify the services allowed by the firewall match the PPSM CLSA. Is it the case that there are additional ports, protocols, or services that are not in the PPSM CLSA, or there are ports, protocols, or services that are prohibited by the PPSM Category Assurance List (CAL), or there are no firewall rules configured? - - - - Verify "firewalld" is configured to employ a deny-all, allow-by-exception policy for allowing connections to other systems with the following commands: + + + + Run the following command to determine if the policycoreutils-python-utils package is installed: $ rpm -q policycoreutils-python-utils + Is it the case that the package is not installed? + + + + To determine that AIDE is configured for FIPS 140-2 file hashing, run the following command: +$ grep sha512 /etc/aide.conf +Verify that the sha512 option is added to the correct ruleset. + Is it the case that the sha512 option is missing or not added to the correct ruleset? + + + + Verify that there are no shosts.equiv files on the system, run the following command: +$ find / -name shosts.equiv + Is it the case that shosts.equiv files exist? + + + + Make sure that the kernel is not disabling SMAP with the following +commands. +grep -q nosmap /boot/config-`uname -r` +If the command returns a line, it means that SMAP is being disabled. + Is it the case that the kernel is configured to disable SMAP? + + + + -$ sudo firewall-cmd --state +Run the following command to determine the current status of the +iptables service: +$ sudo systemctl is-active iptables +If the service is running, it should return the following: active + Is it the case that ? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_SECURITY /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + +If the system is configured to prevent the loading of the can kernel module, +it will contain lines inside any file in /etc/modprobe.d or the deprecated /etc/modprobe.conf. +These lines instruct the module loading system to run another program (such as /bin/false) upon a module install event. -running +These lines can also instruct the module loading system to ignore the can kernel module via blacklist keyword. -$ sudo firewall-cmd --get-active-zones +Run the following command to search for such lines in all files in /etc/modprobe.d and the deprecated /etc/modprobe.conf: +$ grep -r can /etc/modprobe.conf /etc/modprobe.d + Is it the case that no line is returned? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_REFCOUNT_FULL /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + -[custom] -interfaces: ens33 +Run the following command to determine the current status of the +rsyslog service: +$ sudo systemctl is-active rsyslog +If the service is running, it should return the following: active + Is it the case that the "rsyslog" service is disabled, masked, or not started.? + + + + To check for serial port entries which permit root login, +run the following command: +$ sudo grep ^ttyS/[0-9] /etc/securetty +If any output is returned, then root login over serial ports is permitted. + Is it the case that root login over serial ports is permitted? + + + + Verify the audit system is configured to take an appropriate action when the internal event queue is full: +$ sudo grep -i overflow_action /etc/audit/auditd.conf -$ sudo firewall-cmd --info-zone=[custom] | grep target +The output should contain overflow_action = syslog -target: DROP - Is it the case that no zones are active on the interfaces or if the target is set to a different option other than "DROP"? - - - - Inspect the file /etc/firewalld/firewalld.conf to determine -the default zone for the firewalld. It should be set to DefaultZone=drop: -$ sudo grep DefaultZone /etc/firewalld/firewalld.conf - Is it the case that the default zone is not set to DROP? - - - - Verify "nftables" is configured to allow rate limits on any connection to the system with the following command: +If the value of the "overflow_action" option is not set to syslog, +single, halt or the line is commented out, ask the System Administrator +to indicate how the audit logs are off-loaded to a different system or media. + Is it the case that auditd overflow action is not set correctly? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "su" command with the following command: -Verify "firewalld" has "nftables" set as the default backend: +$ sudo auditctl -l | grep su -$ sudo grep -i firewallbackend /etc/firewalld/firewalld.conf +-a always,exit -F path=/usr/bin/su -F perm=x -F auid>=1000 -F auid!=unset -k privileged-su + Is it the case that the command does not return a line, or the line is commented out? + + + + To ensure only SNMPv3 or newer is used, run the following command: +$ sudo grep 'rocommunity\|rwcommunity\|com2sec' /etc/snmp/snmpd.conf | grep -v "^#" +There should be no output. + Is it the case that there is output? + + + + The runtime status of the net.ipv4.conf.all.accept_redirects kernel parameter can be queried +by running the following command: +$ sysctl net.ipv4.conf.all.accept_redirects +0. -# FirewallBackend -FirewallBackend=nftables - Is it the case that the "nftables" is not set as the "firewallbackend"? - - - - Verify that Oracle Linux 9 does not have unauthorized IP tunnels configured. + Is it the case that the correct value is not returned? + + + + To check the ownership of /etc/sudoers.d, +run the command: +$ ls -lL /etc/sudoers.d +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/sudoers.d does not have an owner of root? + + + + To obtain a list of all users and the content of their shadow password field, run the command: +$ sudo readarray -t systemaccounts +Verify if all accounts are locked. + Is it the case that system accounts are not locked? + + + + To determine how the SSH daemon's PrintLastLog option is set, run the following command: + +$ sudo grep -i PrintLastLog /etc/ssh/sshd_config + +If a line indicating yes is returned, then the required value is set. + + Is it the case that the required value is not set? + + + + To verify the nosuid option is configured for all NFS mounts, run +the following command: +$ mount | grep nfs +All NFS mounts should show the nosuid setting in parentheses. This +is not applicable if NFS is not implemented. + Is it the case that the setting does not show? + + + + System executables are stored in the following directories by default: +/bin +/sbin +/usr/bin +/usr/local/bin +/usr/local/sbin +/usr/sbin +For each of these directories, run the following command to find files +not owned by root: +$ sudo find -L DIR/ ! -user root -type d -exec chown root {} \; + Is it the case that any system executables directories are found to not be owned by root? + + + + The runtime status of the net.ipv6.conf.all.accept_ra_rtr_pref kernel parameter can be queried +by running the following command: +$ sysctl net.ipv6.conf.all.accept_ra_rtr_pref +0. + + Is it the case that the correct value is not returned? + + + + To check if RekeyLimit is set correctly, run the following command: +$ sudo grep RekeyLimit /etc/ssh/ssh_config.d/*.conf +If configured properly, output should be +/etc/ssh/ssh_config.d/02-rekey-limit.conf: +RekeyLimit +Check also the main configuration file with the following command: +$ sudo grep RekeyLimit /etc/ssh/ssh_config +The command should not return any output. + Is it the case that it is commented out or is not set? + + + + Verify that sshd isn't configured to ignore the system wide cryptographic policy. + +Check that the CRYPTO_POLICY variable is not set or is commented out in the +/etc/sysconfig/sshd. + +Run the following command: + +$ sudo grep CRYPTO_POLICY /etc/sysconfig/sshd + Is it the case that the CRYPTO_POLICY variable is set or is not commented out in the /etc/sysconfig/sshd? + + + + Verify the audit system prevents unauthorized changes with the following command: + +$ sudo grep "^\s*[^#]" /etc/audit/audit.rules | tail -1 +-e 2 + + Is it the case that the audit system is not set to be immutable by adding the "-e 2" option to the end of "/etc/audit/audit.rules"? + + + + To verify that SSSD is configured for PAM services, run the following command: +$ sudo grep services /etc/sssd/sssd.conf +If configured properly, output should be similar to +services = pam + Is it the case that it does not exist or 'pam' is not added to the 'services' option under the 'sssd' section? + + + + To check the minimum password length, run the command: +$ grep PASS_MIN_LEN /etc/login.defs +The DoD requirement is 15. + Is it the case that it is not set to the required value? + + + + To check the permissions of /etc/at.allow, +run the command: +$ ls -l /etc/at.allow +If properly configured, the output should indicate the following permissions: +-rw-r----- + Is it the case that /etc/at.allow does not have unix mode -rw-r-----? + + + + To check the group ownership of /etc/crypttab, +run the command: +$ ls -lL /etc/crypttab +If properly configured, the output should indicate the following group-owner: +root + Is it the case that /etc/crypttab does not have a group owner of root? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_SLAB_FREELIST_HARDENED /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + The runtime status of the kernel.panic_on_oops kernel parameter can be queried +by running the following command: +$ sysctl kernel.panic_on_oops +1. + + Is it the case that the correct value is not returned? + + + + Run the following command to ensure the default FORWARD policy is DROP: +grep ":FORWARD" /etc/sysconfig/iptables +The output should be similar to the following: +$ sudo grep ":FORWARD" /etc/sysconfig/iptables +:FORWARD DROP [0:0 + Is it the case that the default policy for the FORWARD chain is not set to DROP? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_BUG /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To check the group ownership of /etc/shadow, +run the command: +$ ls -lL /etc/shadow +If properly configured, the output should indicate the following group-owner: +root + Is it the case that /etc/shadow does not have a group owner of root? + + + + To ensure that XDMCP is disabled in /etc/gdm/custom.conf, run the following command: +grep -Pzo "\[xdmcp\]\nEnable=false" /etc/gdm/custom.conf +The output should return the following: + +[xdmcp] +Enable=false + + Is it the case that the Enable is not set to false or is missing in the xdmcp section of the /etc/gdm/custom.conf gdm configuration file? + + + + To ensure ClientAliveInterval is set correctly, run the following command: + +$ sudo grep ClientAliveCountMax /etc/ssh/sshd_config + +If properly configured, the output should be: +ClientAliveCountMax 0 + +In this case, the SSH timeout occurs precisely when +the ClientAliveInterval is set. + Is it the case that it is commented out or not configured properly? + + + + To check that the rdisc service is disabled in system boot configuration, +run the following command: +$ sudo systemctl is-enabled rdisc +Output should indicate the rdisc service has either not been installed, +or has been disabled at all runlevels, as shown in the example below: +$ sudo systemctl is-enabled rdisc disabled + +Run the following command to verify rdisc is not active (i.e. not running) through current runtime configuration: +$ sudo systemctl is-active rdisc + +If the service is not running the command will return the following output: +inactive + +The service will also be masked, to check that the rdisc is masked, run the following command: +$ sudo systemctl show rdisc | grep "LoadState\|UnitFileState" + +If the service is masked the command will return the following outputs: + +LoadState=masked + +UnitFileState=masked + Is it the case that the "rdisc" is loaded and not masked? + + + + Verify that Oracle Linux 9 enforces password complexity rules for the root account. + +Check if root user is required to use complex passwords with the following command: + +$ grep enforce_for_root /etc/security/pwquality.conf /etc/security/pwquality.conf.d/*.conf + +/etc/security/pwquality.conf:enforce_for_root + Is it the case that "enforce_for_root" is commented or missing? + + + + Run the following command to determine if the tuned package is installed: +$ rpm -q tuned + Is it the case that the package is installed? + + + + To check if the system motd banner is compliant, +run the following command: +$ cat /etc/motd + Is it the case that it does not display the required banner? + + + + To check the permissions of /etc/audit/auditd.conf, +run the command: +$ ls -l /etc/audit/auditd.conf +If properly configured, the output should indicate the following permissions: +-rw-r----- + Is it the case that /etc/audit/auditd.conf does not have unix mode -rw-r-----? + + + + Verify the NX (no-execution) bit flag is set on the system. + +Check that the no-execution bit flag is set with the following commands: + +$ sudo dmesg | grep NX + +[ 0.000000] NX (Execute Disable) protection: active + +If "dmesg" does not show "NX (Execute Disable) protection" active, check the cpuinfo settings with the following command: + +$ sudo grep flags /proc/cpuinfo +flags : fpu vme de pse tsc ms nx rdtscp lm constant_ts + +The output should contain the "nx" flag. + Is it the case that NX is disabled? + + + + Verify the operating system routinely checks the baseline configuration for unauthorized changes. + +To determine that periodic AIDE execution has been scheduled, run the following command: +$ grep aide /etc/crontab +The output should return something similar to the following: +05 4 * * * root /usr/sbin/aide --check + +NOTE: The usage of special cron times, such as @daily or @weekly, is acceptable. + Is it the case that AIDE is not configured to scan periodically? + + + + Verify that Oracle Linux 9 contains no duplicate User IDs (UIDs) for interactive users. + +Check that the operating system contains no duplicate UIDs for interactive users with the following command: + +$ sudo awk -F ":" 'list[$3]++{print $1, $3}' /etc/passwd + Is it the case that output is produced and the accounts listed are interactive user accounts? + + + + Run the following command to determine if the bind package is installed: +$ rpm -q bind + Is it the case that the package is installed? + + + + Verify that a separate file system/partition has been created for /dev/shm with the following command: + +$ mountpoint /dev/shm + + Is it the case that "/dev/shm is not a mountpoint" is returned? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_MODIFY_LDT_SYSCALL /boot/config.* + + Configs with value 'n' are not explicitly set in the file, so either commented lines or no + lines should be returned. + + Is it the case that the kernel was not built with the required value? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "setfiles" command with the following command: + +$ sudo auditctl -l | grep setfiles + +-a always,exit -F path=/usr/sbin/setfiles -F perm=x -F auid>=1000 -F auid!=unset -k privileged-unix-update + Is it the case that the command does not return a line, or the line is commented out? + + + + +Run the following command to determine if the auditadm_exec_content SELinux boolean is enabled: +$ getsebool auditadm_exec_content +If properly configured, the output should show the following: +auditadm_exec_content --> on + Is it the case that auditadm_exec_content is not enabled? + + + + Run the following command to determine if the McAfeeTP package is installed: $ rpm -q McAfeeTP + Is it the case that the package is not installed? + + + + Verify that Oracle Linux 9 does not have unauthorized IP tunnels configured. # yum list installed libreswan @@ -239582,253 +261122,408 @@ If the "IPsec" service is active, check for configured IPsec connections (conn), grep -rni conn /etc/ipsec.conf /etc/ipsec.d/ Verify any returned results for organizational approval. Is it the case that the IPSec tunnels are not approved? - - - - Run the following command to determine if the libreswan package is installed: $ rpm -q libreswan - Is it the case that the package is not installed? - - - - If IPv6 is disabled, this is not applicable. + + + + To ensure the screensaver is configured to be blank, run the following command: +$ gsettings get org.gnome.desktop.screensaver picture-uri +If properly configured, the output should be ''. +To ensure that users cannot set the screensaver background, run the following: +$ grep picture-uri /etc/dconf/db/local.d/locks/* +If properly configured, the output should be /org/gnome/desktop/screensaver/picture-uri + Is it the case that it is not set or configured properly? + + + + Run the following command to determine if the gssproxy package is installed: +$ rpm -q gssproxy + Is it the case that the package is installed? + + + + Verify that Oracle Linux 9 has a DNS mode configured in Network Manager. +$ NetworkManager --print-config +[main] +dns= + Is it the case that the dns key under main does not exist or is not set to "none" or "default"? + + + + Verify the nosuid option is configured for the /opt mount point, + run the following command: + $ sudo mount | grep '\s/opt\s' + . . . /opt . . . nosuid . . . -Run the following command to determine the current status of the -ip6tables service: -$ sudo systemctl is-active ip6tables -If the service is running, it should return the following: active - Is it the case that ? - - - - + Is it the case that the "/opt" file system does not have the "nosuid" option set? + + + + To ensure write permissions are disabled for group and other + for each element in root's path, run the following command: +# ls -ld DIR + Is it the case that group or other write permissions exist? + + + + Verify Oracle Linux 9 is configured to lock an account until released by an administrator +after unsuccessful logon +attempts with the command: -Run the following command to determine the current status of the -iptables service: -$ sudo systemctl is-active iptables -If the service is running, it should return the following: active - Is it the case that ? - - - - If IPv6 is disabled, this is not applicable. +$ grep 'unlock_time =' /etc/security/faillock.conf +unlock_time = + Is it the case that the "unlock_time" option is not set to "<sub idref="var_accounts_passwords_pam_faillock_unlock_time" />", +the line is missing, or commented out? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_SECURITY_YAMA /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To verify that OpenSSL uses the system crypto policy, check out that the OpenSSL config file +/etc/pki/tls/openssl.cnf contains the [ crypto_policy ] section with the +.include = /etc/crypto-policies/back-ends/opensslcnf.config directive: -Inspect the file /etc/sysconfig/ip6tables to determine -the default policy for the INPUT chain. It should be set to DROP: -$ sudo grep ":INPUT" /etc/sysconfig/ip6tables - Is it the case that the default policy for the INPUT chain is not set to DROP? - - - - Verify that the ipv6 loopback interface has required rules in order: -$ iptables -L INPUT -v -n - Is it the case that ipv6 loopback traffic is not configured? - - - - Run the following commands and verify output: +$ sudo grep '\.include\s* /etc/crypto-policies/back-ends/opensslcnf.config$' /etc/pki/tls/openssl.cnf. + Is it the case that the OpenSSL config file doesn't contain the whole section, +or the section doesn't contain the <pre>.include = /etc/crypto-policies/back-ends/opensslcnf.config</pre> directive? + + + + Determine where the audit logs are stored with the following command: -# iptables -L INPUT -v -n | grep lo | grep ACCEPT +$ sudo grep -iw log_file /etc/audit/auditd.conf +log_file = /var/log/audit/audit.log -# iptables -L INPUT -v -n | grep 127.0.0.0\/8 | grep DROP +Determine the owner of the audit log directory by using the output of the above command +(default: "/var/log/audit/"). Run the following command with the correct audit log directory +path: +$ sudo ls -ld /var/log/audit -# iptables -L OUTPUT -v -n | grep lo | grep ACCEPT +drwx------ 2 root root 23 Jun 11 11:56 /var/log/audit - Is it the case that loopback traffic is not configured? - - - - Inspect the file /etc/sysconfig/iptables to determine -the default policy for the INPUT chain. It should be set to DROP: -$ sudo grep ":INPUT" /etc/sysconfig/iptables - Is it the case that the default policy for the INPUT chain is not set to DROP? - - - - Run the following command to ensure the default FORWARD policy is DROP: -grep ":FORWARD" /etc/sysconfig/iptables -The output should be similar to the following: -$ sudo grep ":FORWARD" /etc/sysconfig/iptables -:FORWARD DROP [0:0 - Is it the case that the default policy for the FORWARD chain is not set to DROP? - - - - The runtime status of the net.ipv6.conf.all.accept_ra kernel parameter can be queried +The audit log directory must be owned by "root" + Is it the case that the directory is not owned by root? + + + + To verify all local initialization files for interactive users are owned by the +primary user, run the following command: +$ sudo ls -al /home/USER/.* +The user initialization files should be owned by USER. + Is it the case that they are not? + + + + Check that the symlink exists and target the correct Kerberos crypto policy, with the following command: +file /etc/krb5.conf.d/crypto-policies +If command ouput shows the following line, Kerberos is configured to use the system-wide crypto policy. +/etc/krb5.conf.d/crypto-policies: symbolic link to /etc/crypto-policies/back-ends/krb5.config + Is it the case that the symlink does not exist or points to a different target? + + + + The runtime status of the net.ipv4.conf.all.drop_gratuitous_arp kernel parameter can be queried by running the following command: -$ sysctl net.ipv6.conf.all.accept_ra -0. - - Is it the case that the correct value is not returned? - - - - The runtime status of the net.ipv6.conf.all.accept_ra_defrtr kernel parameter can be queried -by running the following command: -$ sysctl net.ipv6.conf.all.accept_ra_defrtr -0. - - Is it the case that the correct value is not returned? - - - - The runtime status of the net.ipv6.conf.all.accept_ra_pinfo kernel parameter can be queried -by running the following command: -$ sysctl net.ipv6.conf.all.accept_ra_pinfo -0. - - Is it the case that the correct value is not returned? - - - - The runtime status of the net.ipv6.conf.all.accept_ra_rtr_pref kernel parameter can be queried -by running the following command: -$ sysctl net.ipv6.conf.all.accept_ra_rtr_pref -0. - - Is it the case that the correct value is not returned? - - - - The runtime status of the net.ipv6.conf.all.accept_redirects kernel parameter can be queried -by running the following command: -$ sysctl net.ipv6.conf.all.accept_redirects -0. - - Is it the case that the correct value is not returned? - - - - The runtime status of the net.ipv6.conf.all.accept_source_route kernel parameter can be queried -by running the following command: -$ sysctl net.ipv6.conf.all.accept_source_route -0. - - Is it the case that the correct value is not returned? - - - - The runtime status of the net.ipv6.conf.all.autoconf kernel parameter can be queried -by running the following command: -$ sysctl net.ipv6.conf.all.autoconf -0. - - Is it the case that the correct value is not returned? - - - - The runtime status of the net.ipv6.conf.all.forwarding kernel parameter can be queried -by running the following command: -$ sysctl net.ipv6.conf.all.forwarding -0. -The ability to forward packets is only appropriate for routers. - Is it the case that IP forwarding value is "1" and the system is not router? - - - - The runtime status of the net.ipv6.conf.all.max_addresses kernel parameter can be queried -by running the following command: -$ sysctl net.ipv6.conf.all.max_addresses +$ sysctl net.ipv4.conf.all.drop_gratuitous_arp 1. Is it the case that the correct value is not returned? - - - - The runtime status of the net.ipv6.conf.all.router_solicitations kernel parameter can be queried -by running the following command: -$ sysctl net.ipv6.conf.all.router_solicitations -0. + + + + To determine that AIDE is verifying ACLs, run the following command: +$ grep acl /etc/aide.conf +Verify that the acl option is added to the correct ruleset. + Is it the case that the acl option is missing or not added to the correct ruleset? + + + + Inspect the form of default GRUB 2 command line for the Linux operating system +in /etc/default/grub. If it includes audit=1, +then the parameter will be configured for newly installed kernels. +First check if the GRUB recovery is enabled: +$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub +If this option is set to true, then check that a line is output by the following command: +$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*audit=1.*' /etc/default/grub +If the recovery is disabled, check the line with +$ sudo grep 'GRUB_CMDLINE_LINUX.*audit=1.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. +Run the following command: +$ sudo grubby --info=ALL | grep args | grep -v 'audit=1' +The command should not return any output. + Is it the case that auditing is not enabled at boot time? + + + + To check if the system login banner is compliant, +run the following command: - Is it the case that the correct value is not returned? - - - - The runtime status of the net.ipv6.conf.default.accept_ra kernel parameter can be queried -by running the following command: -$ sysctl net.ipv6.conf.default.accept_ra -0. +$ cat /etc/issue + Is it the case that it does not display the required banner? + + + + +If the system is configured to prevent the loading of the atm kernel module, +it will contain lines inside any file in /etc/modprobe.d or the deprecated /etc/modprobe.conf. +These lines instruct the module loading system to run another program (such as /bin/false) upon a module install event. - Is it the case that the correct value is not returned? - - - - The runtime status of the net.ipv6.conf.default.accept_ra_defrtr kernel parameter can be queried -by running the following command: -$ sysctl net.ipv6.conf.default.accept_ra_defrtr -0. +These lines can also instruct the module loading system to ignore the atm kernel module via blacklist keyword. - Is it the case that the correct value is not returned? - - - - The runtime status of the net.ipv6.conf.default.accept_ra_pinfo kernel parameter can be queried +Run the following command to search for such lines in all files in /etc/modprobe.d and the deprecated /etc/modprobe.conf: +$ grep -r atm /etc/modprobe.conf /etc/modprobe.d + Is it the case that no line is returned? + + + + To verify that rsyslog's Forwarding Output Module has CA certificate +configured for its TLS connections to remote server, run the following command: +$ grep DefaultNetstreamDriverCAFile /etc/rsyslog.conf /etc/rsyslog.d/*.conf +The output should include record similar to +global(DefaultNetstreamDriverCAFile="/etc/pki/tls/cert.pem") +where the path to the CA file (/etc/pki/tls/cert.pem in case above) must point to the correct CA certificate. + Is it the case that CA certificate for rsyslog remote logging via TLS is not set? + + + + To verify that the audit system collects unauthorized file accesses, run the following commands: +$ sudo grep EACCES /etc/audit/audit.rules +$ sudo grep EPERM /etc/audit/audit.rules + Is it the case that 32-bit and 64-bit system calls to creat, open, openat, open_by_handle_at, truncate, and ftruncate are not audited during EACCES and EPERM? + + + + To verify that the Audit is correctly configured according to recommended rules, check the content of the file with the following command: +cat /etc/audit/rules.d/30-ospp-v42-5-perm-change-failed.rules +The output has to be exactly as follows: +## Unsuccessful permission change +-a always,exit -F arch=b32 -S chmod,fchmod,fchmodat,setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-perm-change +-a always,exit -F arch=b64 -S chmod,fchmod,fchmodat,setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-perm-change +-a always,exit -F arch=b32 -S chmod,fchmod,fchmodat,setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-perm-change +-a always,exit -F arch=b64 -S chmod,fchmod,fchmodat,setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-perm-change + Is it the case that the file does not exist or the content differs? + + + + The runtime status of the kernel.kexec_load_disabled kernel parameter can be queried by running the following command: -$ sysctl net.ipv6.conf.default.accept_ra_pinfo -0. - - Is it the case that the correct value is not returned? - - - - The runtime status of the net.ipv6.conf.default.accept_ra_rtr_pref kernel parameter can be queried -by running the following command: -$ sysctl net.ipv6.conf.default.accept_ra_rtr_pref -0. - - Is it the case that the correct value is not returned? - - - - The runtime status of the net.ipv6.conf.default.accept_redirects kernel parameter can be queried -by running the following command: -$ sysctl net.ipv6.conf.default.accept_redirects -0. - - Is it the case that the correct value is not returned? - - - - The runtime status of the net.ipv6.conf.default.accept_source_route kernel parameter can be queried -by running the following command: -$ sysctl net.ipv6.conf.default.accept_source_route -0. - - Is it the case that the correct value is not returned? - - - - The runtime status of the net.ipv6.conf.default.autoconf kernel parameter can be queried -by running the following command: -$ sysctl net.ipv6.conf.default.autoconf -0. - - Is it the case that the correct value is not returned? - - - - The runtime status of the net.ipv6.conf.default.max_addresses kernel parameter can be queried -by running the following command: -$ sysctl net.ipv6.conf.default.max_addresses +$ sysctl kernel.kexec_load_disabled 1. Is it the case that the correct value is not returned? - - - - The runtime status of the net.ipv6.conf.default.router_solicitations kernel parameter can be queried + + + + Verify the umask setting is configured correctly in the /etc/bashrc file with the following command: + +$ sudo grep "umask" /etc/bashrc + +umask + Is it the case that the value for the "umask" parameter is not "<sub idref="var_accounts_user_umask" />", or the "umask" parameter is missing or is commented out? + + + + To verify that root's primary group is zero run the following command: + + grep '^root:' /etc/passwd | cut -d : -f 4 + +The command should return: + +0 + + Is it the case that root has a primary gid not equal to zero? + + + + Inspect /etc/audit/auditd.conf and locate the following line to +determine if the system is configured correctly: +space_left SIZE_in_MB + Is it the case that the system is not configured a specfic size in MB to notify administrators of an issue? + + + + The tftp package can be removed with the following command: $ sudo yum erase tftp + Is it the case that ? + + + + To check which SSH protocol version is allowed, check version of +openssh-server with following command: +$ rpm -qi openssh-server | grep Version +Versions equal to or higher than 7.4 have deprecated the RhostsRSAAuthentication option. +If version is lower than 7.4, run the following command to check configuration: +To determine how the SSH daemon's RhostsRSAAuthentication option is set, run the following command: + +$ sudo grep -i RhostsRSAAuthentication /etc/ssh/sshd_config + +If a line indicating no is returned, then the required value is set. + + Is it the case that the required value is not set? + + + + To check the permissions of /etc/cron.daily, +run the command: +$ ls -l /etc/cron.daily +If properly configured, the output should indicate the following permissions: +-rwx------ + Is it the case that /etc/cron.daily does not have unix mode -rwx------? + + + + The runtime status of the net.ipv4.conf.all.send_redirects kernel parameter can be queried by running the following command: -$ sysctl net.ipv6.conf.default.router_solicitations +$ sysctl net.ipv4.conf.all.send_redirects 0. Is it the case that the correct value is not returned? - - - - If the system uses IPv6, this is not applicable. + + + + To verify whether audispd plugin off-loads audit records onto a different +system or media from the system being audited, run the following command: + +$ sudo grep -i remote_server /etc/audit/audisp-remote.conf + +The output should return something similar to where REMOTE_SYSTEM +is an IP address or hostname: +remote_server = REMOTE_SYSTEM + +Determine which partition the audit records are being written to with the +following command: + +$ sudo grep log_file /etc/audit/auditd.conf +log_file = /var/log/audit/audit.log + +Check the size of the partition that audit records are written to with the +following command and verify whether it is sufficiently large: + +$ sudo df -h /var/log/audit/ +/dev/sda2 24G 10.4G 13.6G 43% /var/log/audit + Is it the case that audispd is not sending logs to a remote system and the local partition has inadequate space? + + + + Verify the system commands contained in the following directories are group-owned by "root", or a required system account, with the following command: + +$ sudo find -L /bin /sbin /usr/bin /usr/sbin /usr/local/bin /usr/local/sbin ! -group root -exec ls -l {} \; + Is it the case that any system commands are returned and is not group-owned by a required system account? + + + + Run the following command to determine if the dovecot package is installed: +$ rpm -q dovecot + Is it the case that the package is installed? + + + + To check the permissions of /etc/group, +run the command: +$ ls -l /etc/group +If properly configured, the output should indicate the following permissions: +-rw-r--r-- + Is it the case that /etc/group does not have unix mode -rw-r--r--? + + + + To verify that remote access methods are logging to rsyslog, +run the following command: +grep -rE '(auth.\*|authpriv.\*|daemon.\*)' /etc/rsyslog.* +The output should contain auth.*, authpriv.*, and daemon.* +pointing to a log file. + Is it the case that remote access methods are not logging to rsyslog? + + + + System commands are stored in the following directories: +/bin +/sbin +/usr/bin +/usr/sbin +/usr/local/bin +/usr/local/sbin +For each of these directories, run the following command to find directories not +owned by root: +$ sudo find -L $DIR ! -group root -type d -exec chgrp root {} \; + Is it the case that any of these directories are not group owned by root? + + + + To check the ownership of /etc/iptables, +run the command: +$ ls -lL /etc/iptables +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/iptables does not have an owner of root? + + + + The runtime status of the fs.suid_dumpable kernel parameter can be queried +by running the following command: +$ sysctl fs.suid_dumpable +0. + + Is it the case that the correct value is not returned? + + + + +To properly set the group owner of /etc/audit/, run the command: +$ sudo chgrp root /etc/audit/ + +To properly set the group owner of /etc/audit/rules.d/, run the command: +$ sudo chgrp root /etc/audit/rules.d/ + Is it the case that ? + + + + To determine how the SSH daemon's KerberosAuthentication option is set, run the following command: + +$ sudo grep -i KerberosAuthentication /etc/ssh/sshd_config + +If a line indicating no is returned, then the required value is set. + + Is it the case that the required value is not set? + + + + Verify Oracle Linux 9 disables storing core dumps for all users by issuing the following command: + +$ grep -i storage /etc/systemd/coredump.conf + +Storage=none + Is it the case that Storage is not set to none or is commented out and the need for core dumps is not documented with the Information System Security Officer (ISSO) as an operational requirement for all domains that have the "core" item assigned? + + + + The runtime status of the net.ipv4.conf.all.route_localnet kernel parameter can be queried +by running the following command: +$ sysctl net.ipv4.conf.all.route_localnet +0. + + Is it the case that the correct value is not returned? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "chage" command with the following command: + +$ sudo auditctl -l | grep chage + +-a always,exit -F path=/usr/bin/chage -F perm=x -F auid>=1000 -F auid!=unset -k privileged-chage + Is it the case that the command does not return a line, or the line is commented out? + + + + If the system uses IPv6, this is not applicable. If the system is configured to disable the ipv6 kernel module, it will contain a line @@ -239842,1312 +261537,120 @@ lines in all files in /etc/modprobe.d and the deprecated /etc/modprobe.conf: $ grep -r ipv6 /etc/modprobe.conf /etc/modprobe.d Is it the case that the ipv6 kernel module is not disabled? - - - - If the system uses IPv6, this is not applicable. - -If the system is configured to prevent the usage of the ipv6 on -network interfaces, it will contain a line of the form: -net.ipv6.conf.all.disable_ipv6 = 1 -Such lines may be inside any file in the /etc/sysctl.d directory. -This permits insertion of the IPv6 kernel module (which other parts of the -system expect to be present), but otherwise keeps all network interfaces -from using IPv6. Run the following command to search for such lines in all -files in /etc/sysctl.d: -$ grep -r ipv6 /etc/sysctl.d - Is it the case that the ipv6 support is disabled on all network interfaces? - - - - If the system uses IPv6, this is not applicable. - -If the system is configured to prevent the usage of the ipv6 on -network interfaces, it will contain a line of the form: -net.ipv6.conf.default.disable_ipv6 = 1 -Such lines may be inside any file in the /etc/sysctl.d directory. -This permits insertion of the IPv6 kernel module (which other parts of the -system expect to be present), but otherwise keeps network interfaces -from using IPv6. Run the following command to search for such lines in all -files in /etc/sysctl.d: -$ grep -r ipv6 /etc/sysctl.d - Is it the case that the ipv6 support is disabled by default on network interfaces? - - - - The runtime status of the net.ipv4.conf.all.accept_local kernel parameter can be queried -by running the following command: -$ sysctl net.ipv4.conf.all.accept_local -0. - - Is it the case that the correct value is not returned? - - - - The runtime status of the net.ipv4.conf.all.accept_redirects kernel parameter can be queried -by running the following command: -$ sysctl net.ipv4.conf.all.accept_redirects -0. - - Is it the case that the correct value is not returned? - - - - The runtime status of the net.ipv4.conf.all.accept_source_route kernel parameter can be queried -by running the following command: -$ sysctl net.ipv4.conf.all.accept_source_route -0. - - Is it the case that the correct value is not returned? - - - - The runtime status of the net.ipv4.conf.all.arp_filter kernel parameter can be queried -by running the following command: -$ sysctl net.ipv4.conf.all.arp_filter -. - - Is it the case that the correct value is not returned? - - - - The runtime status of the net.ipv4.conf.all.arp_ignore kernel parameter can be queried -by running the following command: -$ sysctl net.ipv4.conf.all.arp_ignore -. - - Is it the case that the correct value is not returned? - - - - The runtime status of the net.ipv4.conf.all.drop_gratuitous_arp kernel parameter can be queried -by running the following command: -$ sysctl net.ipv4.conf.all.drop_gratuitous_arp -1. - - Is it the case that the correct value is not returned? - - - - The runtime status of the net.ipv4.conf.all.log_martians kernel parameter can be queried -by running the following command: -$ sysctl net.ipv4.conf.all.log_martians -1. - - Is it the case that the correct value is not returned? - - - - The runtime status of the net.ipv4.conf.all.route_localnet kernel parameter can be queried -by running the following command: -$ sysctl net.ipv4.conf.all.route_localnet -0. - - Is it the case that the correct value is not returned? - - - - The runtime status of the net.ipv4.conf.all.rp_filter parameter can be queried -by running the following command: -$ sysctl net.ipv4.conf.all.rp_filter -The output of the command should indicate either: -net.ipv4.conf.all.rp_filter = 1 -or: -net.ipv4.conf.all.rp_filter = 2 -The output of the command should not indicate: -net.ipv4.conf.all.rp_filter = 0 - -The preferable way how to assure the runtime compliance is to have -correct persistent configuration, and rebooting the system. - -The persistent sysctl parameter configuration is performed by specifying the appropriate -assignment in any file located in the /etc/sysctl.d directory. -Verify that there is not any existing incorrect configuration by executing the following command: -$ grep -r '^\s*net.ipv4.conf.all.rp_filter\s*=' /etc/sysctl.conf /etc/sysctl.d -The command should not find any assignments other than: -net.ipv4.conf.all.rp_filter = 1 -or: -net.ipv4.conf.all.rp_filter = 2 - -Conflicting assignments are not allowed. - Is it the case that the net.ipv4.conf.all.rp_filter is not set to 1 or 2 or is configured to be 0? - - - - The runtime status of the net.ipv4.conf.all.secure_redirects kernel parameter can be queried -by running the following command: -$ sysctl net.ipv4.conf.all.secure_redirects -0. - - Is it the case that the correct value is not returned? - - - - The runtime status of the net.ipv4.conf.all.shared_media kernel parameter can be queried -by running the following command: -$ sysctl net.ipv4.conf.all.shared_media -0. - - Is it the case that the correct value is not returned? - - - - The runtime status of the net.ipv4.conf.default.accept_redirects kernel parameter can be queried -by running the following command: -$ sysctl net.ipv4.conf.default.accept_redirects -0. - - Is it the case that the correct value is not returned? - - - - The runtime status of the net.ipv4.conf.default.accept_source_route kernel parameter can be queried -by running the following command: -$ sysctl net.ipv4.conf.default.accept_source_route -0. - - Is it the case that the correct value is not returned? - - - - The runtime status of the net.ipv4.conf.default.log_martians kernel parameter can be queried -by running the following command: -$ sysctl net.ipv4.conf.default.log_martians -1. - - Is it the case that the correct value is not returned? - - - - The runtime status of the net.ipv4.conf.default.rp_filter kernel parameter can be queried -by running the following command: -$ sysctl net.ipv4.conf.default.rp_filter -1. - - Is it the case that the correct value is not returned? - - - - The runtime status of the net.ipv4.conf.default.secure_redirects kernel parameter can be queried -by running the following command: -$ sysctl net.ipv4.conf.default.secure_redirects -0. - - Is it the case that the correct value is not returned? - - - - The runtime status of the net.ipv4.conf.default.shared_media kernel parameter can be queried -by running the following command: -$ sysctl net.ipv4.conf.default.shared_media -0. - - Is it the case that the correct value is not returned? - - - - The runtime status of the net.ipv4.icmp_echo_ignore_broadcasts kernel parameter can be queried -by running the following command: -$ sysctl net.ipv4.icmp_echo_ignore_broadcasts -1. - - Is it the case that the correct value is not returned? - - - - The runtime status of the net.ipv4.icmp_ignore_bogus_error_responses kernel parameter can be queried -by running the following command: -$ sysctl net.ipv4.icmp_ignore_bogus_error_responses -1. - - Is it the case that the correct value is not returned? - - - - The runtime status of the net.ipv4.ip_local_port_range kernel parameter can be queried + + + + The runtime status of the net.ipv4.ip_local_port_range kernel parameter can be queried by running the following command: $ sysctl net.ipv4.ip_local_port_range 32768 65535. Is it the case that the correct value is not returned? - - - - To verify that the operating system protects against or limits the effects of DoS -attacks by ensuring implementation of rate-limiting measures -on impacted network interfaces, run the following command: -# grep 'net.ipv4.tcp_invalid_ratelimit' /etc/sysctl.conf /etc/sysctl.d/* -The command should output the following line: -/etc/sysctl.conf:net.ipv4.tcp_invalid_ratelimit = -The file where the line has been found can differ, but it must be either /etc/sysctl.conf -or a file located under the /etc/sysctl.d/ directory. - Is it the case that rate limiting of duplicate TCP acknowledgments is not configured? - - - - The runtime status of the net.ipv4.tcp_rfc1337 kernel parameter can be queried -by running the following command: -$ sysctl net.ipv4.tcp_rfc1337 -1. - - Is it the case that the correct value is not returned? - - - - The runtime status of the net.ipv4.tcp_syncookies kernel parameter can be queried -by running the following command: -$ sysctl net.ipv4.tcp_syncookies -1. - - Is it the case that the correct value is not returned? - - - - The runtime status of the net.ipv4.conf.all.send_redirects kernel parameter can be queried -by running the following command: -$ sysctl net.ipv4.conf.all.send_redirects -0. - - Is it the case that the correct value is not returned? - - - - The runtime status of the net.ipv4.conf.default.send_redirects kernel parameter can be queried -by running the following command: -$ sysctl net.ipv4.conf.default.send_redirects -0. - - Is it the case that the correct value is not returned? - - - - The runtime status of the net.ipv4.ip_forward kernel parameter can be queried -by running the following command: -$ sysctl net.ipv4.ip_forward -0. -The ability to forward packets is only appropriate for routers. - Is it the case that the correct value is not returned? - - - - + + + + Run the following command to determine the current status of the -ufw service: -$ sudo systemctl is-active ufw +rngd service: +$ sudo systemctl is-active rngd +If the service is running, it should return the following: active + Is it the case that the "rngd" service is disabled, masked, or not started.? + + + + + +Run the following command to determine the current status of the +sssd service: +$ sudo systemctl is-active sssd If the service is running, it should return the following: active Is it the case that the service is not enabled? - - - - -If the system is configured to prevent the loading of the atm kernel module, -it will contain lines inside any file in /etc/modprobe.d or the deprecated /etc/modprobe.conf. -These lines instruct the module loading system to run another program (such as /bin/true) upon a module install event. - -These lines can also instruct the module loading system to ignore the atm kernel module via blacklist keyword. - -Run the following command to search for such lines in all files in /etc/modprobe.d and the deprecated /etc/modprobe.conf: -$ grep -r atm /etc/modprobe.conf /etc/modprobe.d - Is it the case that no line is returned? - - - - -If the system is configured to prevent the loading of the can kernel module, -it will contain lines inside any file in /etc/modprobe.d or the deprecated /etc/modprobe.conf. -These lines instruct the module loading system to run another program (such as /bin/true) upon a module install event. - -These lines can also instruct the module loading system to ignore the can kernel module via blacklist keyword. - -Run the following command to search for such lines in all files in /etc/modprobe.d and the deprecated /etc/modprobe.conf: -$ grep -r can /etc/modprobe.conf /etc/modprobe.d - Is it the case that no line is returned? - - - - -If the system is configured to prevent the loading of the firewire-core kernel module, -it will contain lines inside any file in /etc/modprobe.d or the deprecated /etc/modprobe.conf. -These lines instruct the module loading system to run another program (such as /bin/true) upon a module install event. - -These lines can also instruct the module loading system to ignore the firewire-core kernel module via blacklist keyword. - -Run the following command to search for such lines in all files in /etc/modprobe.d and the deprecated /etc/modprobe.conf: -$ grep -r firewire-core /etc/modprobe.conf /etc/modprobe.d - Is it the case that no line is returned? - - - - -If the system is configured to prevent the loading of the rds kernel module, -it will contain lines inside any file in /etc/modprobe.d or the deprecated /etc/modprobe.conf. -These lines instruct the module loading system to run another program (such as /bin/true) upon a module install event. - -These lines can also instruct the module loading system to ignore the rds kernel module via blacklist keyword. - -Run the following command to search for such lines in all files in /etc/modprobe.d and the deprecated /etc/modprobe.conf: -$ grep -r rds /etc/modprobe.conf /etc/modprobe.d - Is it the case that no line is returned? - - - - -If the system is configured to prevent the loading of the sctp kernel module, -it will contain lines inside any file in /etc/modprobe.d or the deprecated /etc/modprobe.conf. -These lines instruct the module loading system to run another program (such as /bin/true) upon a module install event. - -These lines can also instruct the module loading system to ignore the sctp kernel module via blacklist keyword. - -Run the following command to search for such lines in all files in /etc/modprobe.d and the deprecated /etc/modprobe.conf: -$ grep -r sctp /etc/modprobe.conf /etc/modprobe.d - Is it the case that no line is returned? - - - - + + + + If the system is configured to prevent the loading of the tipc kernel module, it will contain lines inside any file in /etc/modprobe.d or the deprecated /etc/modprobe.conf. -These lines instruct the module loading system to run another program (such as /bin/true) upon a module install event. +These lines instruct the module loading system to run another program (such as /bin/false) upon a module install event. These lines can also instruct the module loading system to ignore the tipc kernel module via blacklist keyword. Run the following command to search for such lines in all files in /etc/modprobe.d and the deprecated /etc/modprobe.conf: $ grep -r tipc /etc/modprobe.conf /etc/modprobe.d Is it the case that no line is returned? - - - - -If the system is configured to prevent the loading of the bluetooth kernel module, -it will contain lines inside any file in /etc/modprobe.d or the deprecated /etc/modprobe.conf. -These lines instruct the module loading system to run another program (such as /bin/true) upon a module install event. + + + + Verify the "/etc/security/faillock.conf" file is configured to log user name information when unsuccessful logon attempts occur: -These lines can also instruct the module loading system to ignore the bluetooth kernel module via blacklist keyword. +$ sudo grep audit /etc/security/faillock.conf -Run the following command to search for such lines in all files in /etc/modprobe.d and the deprecated /etc/modprobe.conf: -$ grep -r bluetooth /etc/modprobe.conf /etc/modprobe.d - Is it the case that no line is returned? - - - - Verify that there are no wireless interfaces configured on the system -with the following command: +audit + Is it the case that the "audit" option is not set, is missing or commented out? + + + + Verify Oracle Linux 9 is configured to lock an account after +unsuccessful logon attempts with the command: -Note: This requirement is Not Applicable for systems that do not have physical wireless network radios. +$ grep 'deny =' /etc/security/faillock.conf +deny = . + Is it the case that the "deny" option is not set to "<sub idref="var_accounts_passwords_pam_faillock_deny" />" +or less (but not "0"), is missing or commented out? + + + + To verify that there are no .shosts files +on the system, run the following command: +$ sudo find / -name '.shosts' + Is it the case that .shosts files exist? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "setfacl" command with the following command: -$ nmcli device status -DEVICE TYPE STATE CONNECTION -virbr0 bridge connected virbr0 -wlp7s0 wifi connected wifiSSID -enp6s0 ethernet disconnected -- -p2p-dev-wlp7s0 wifi-p2p disconnected -- -lo loopback unmanaged -- -virbr0-nic tun unmanaged -- - Is it the case that a wireless interface is configured and has not been documented and approved by the Information System Security Officer (ISSO)? - - - - Verify that DNS servers have been configured properly, perform the following: -$ sudo grep nameserver /etc/resolv.conf - Is it the case that less than two lines are returned that are not commented out? - - - - Verify that Promiscuous mode of an interface is disabled, run the following command: -$ ip link | grep PROMISC - Is it the case that any network device is in promiscuous mode? - - - - To check the group ownership of /etc/group-, -run the command: -$ ls -lL /etc/group- -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/group- does not have a group owner of root? - - - - To check the group ownership of /etc/gshadow-, -run the command: -$ ls -lL /etc/gshadow- -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/gshadow- does not have a group owner of root? - - - - To check the group ownership of /etc/passwd-, -run the command: -$ ls -lL /etc/passwd- -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/passwd- does not have a group owner of root? - - - - To check the group ownership of /etc/shadow-, -run the command: -$ ls -lL /etc/shadow- -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/shadow- does not have a group owner of root? - - - - To check the group ownership of /etc/group, -run the command: -$ ls -lL /etc/group -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/group does not have a group owner of root? - - - - To check the group ownership of /etc/gshadow, -run the command: -$ ls -lL /etc/gshadow -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/gshadow does not have a group owner of root? - - - - To check the group ownership of /etc/passwd, -run the command: -$ ls -lL /etc/passwd -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/passwd does not have a group owner of root? - - - - To check the group ownership of /etc/shadow, -run the command: -$ ls -lL /etc/shadow -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/shadow does not have a group owner of root? - - - - To check the ownership of /etc/group-, -run the command: -$ ls -lL /etc/group- -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/group- does not have an owner of root? - - - - To check the ownership of /etc/gshadow-, -run the command: -$ ls -lL /etc/gshadow- -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/gshadow- does not have an owner of root? - - - - To check the ownership of /etc/passwd-, -run the command: -$ ls -lL /etc/passwd- -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/passwd- does not have an owner of root? - - - - To check the ownership of /etc/shadow-, -run the command: -$ ls -lL /etc/shadow- -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/shadow- does not have an owner of root? - - - - To check the ownership of /etc/group, -run the command: -$ ls -lL /etc/group -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/group does not have an owner of root? - - - - To check the ownership of /etc/gshadow, -run the command: -$ ls -lL /etc/gshadow -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/gshadow does not have an owner of root? - - - - To check the ownership of /etc/passwd, -run the command: -$ ls -lL /etc/passwd -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/passwd does not have an owner of root? - - - - To check the ownership of /etc/shadow, -run the command: -$ ls -lL /etc/shadow -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/shadow does not have an owner of root? - - - - To check the permissions of /etc/group-, -run the command: -$ ls -l /etc/group- -If properly configured, the output should indicate the following permissions: --rw-r--r-- - Is it the case that /etc/group- does not have unix mode -rw-r--r--? - - - - To check the permissions of /etc/gshadow-, -run the command: -$ ls -l /etc/gshadow- -If properly configured, the output should indicate the following permissions: ----------- - Is it the case that /etc/gshadow- does not have unix mode ----------? - - - - To check the permissions of /etc/passwd-, -run the command: -$ ls -l /etc/passwd- -If properly configured, the output should indicate the following permissions: --rw-r--r-- - Is it the case that /etc/passwd- does not have unix mode -rw-r--r--? - - - - To check the permissions of /etc/shadow-, -run the command: -$ ls -l /etc/shadow- -If properly configured, the output should indicate the following permissions: ----------- - Is it the case that /etc/shadow- does not have unix mode ----------? - - - - To check the permissions of /etc/group, -run the command: -$ ls -l /etc/group -If properly configured, the output should indicate the following permissions: --rw-r--r-- - Is it the case that /etc/group does not have unix mode -rw-r--r--? - - - - To check the permissions of /etc/gshadow, -run the command: -$ ls -l /etc/gshadow -If properly configured, the output should indicate the following permissions: ----------- - Is it the case that /etc/gshadow does not have unix mode ----------? - - - - To check the permissions of /etc/passwd, -run the command: -$ ls -l /etc/passwd -If properly configured, the output should indicate the following permissions: --rw-r--r-- - Is it the case that /etc/passwd does not have unix mode -rw-r--r--? - - - - To check the permissions of /etc/shadow, -run the command: -$ ls -l /etc/shadow -If properly configured, the output should indicate the following permissions: ----------- - Is it the case that /etc/shadow does not have unix mode ----------? - - - - To check the group ownership of /var/log, -run the command: -$ ls -lL /var/log -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /var/log does not have a group owner of root? - - - - To check the group ownership of /var/log/messages, -run the command: -$ ls -lL /var/log/messages -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /var/log/messages does not have a group owner of root? - - - - To check the group ownership of /var/log/syslog, -run the command: -$ ls -lL /var/log/syslog -If properly configured, the output should indicate the following group-owner: -adm - Is it the case that /var/log/syslog does not have a group owner of adm? - - - - To check the ownership of /var/log, -run the command: -$ ls -lL /var/log -If properly configured, the output should indicate the following owner: -root - Is it the case that /var/log does not have an owner of root? - - - - To check the ownership of /var/log/messages, -run the command: -$ ls -lL /var/log/messages -If properly configured, the output should indicate the following owner: -root - Is it the case that /var/log/messages does not have an owner of root? - - - - To check the ownership of /var/log/syslog, -run the command: -$ ls -lL /var/log/syslog -If properly configured, the output should indicate the following owner: -syslog - Is it the case that /var/log/syslog does not have an owner of syslog? - - - - To check the permissions of /var/log, -run the command: -$ ls -l /var/log -If properly configured, the output should indicate the following permissions: -drwxr-xr-x - Is it the case that /var/log does not have unix mode drwxr-xr-x? - - - - To check the permissions of /var/log/messages, -run the command: -$ ls -l /var/log/messages -If properly configured, the output should indicate the following permissions: --rw-r----- - Is it the case that /var/log/messages does not have unix mode -rw-r-----? - - - - To check the permissions of /var/log/syslog, -run the command: -$ ls -l /var/log/syslog -If properly configured, the output should indicate the following permissions: --rw-r----- - Is it the case that /var/log/syslog does not have unix mode -rw-r-----? - - - - Verify the system-wide shared library directories are group-owned by "root" with the following command: +$ sudo auditctl -l | grep setfacl -$ sudo find /lib /lib64 /usr/lib /usr/lib64 ! -group root -type d -exec stat -c "%n %G" '{}' \; - -If any system-wide shared library directory is returned and is not group-owned by a required system account, this is a finding. - Is it the case that any system-wide shared library directory is returned and is not group-owned by a required system account? - - - - System executables are stored in the following directories by default: -/bin -/sbin -/usr/bin -/usr/local/bin -/usr/local/sbin -/usr/sbin -For each of these directories, run the following command to find files -not owned by root: -$ sudo find -L DIR/ ! -user root -type d -exec chown root {} \; - Is it the case that any system executables directories are found to not be owned by root? - - - - Verify the system-wide shared library directories are owned by "root" with the following command: - -$ sudo find /lib /lib64 /usr/lib /usr/lib64 ! -user root -type d -exec stat -c "%n %U" '{}' \; - Is it the case that any system-wide shared library directory is not owned by root? - - - - System executables are stored in the following directories by default: -/bin -/sbin -/usr/bin -/usr/sbin -/usr/local/bin -/usr/local/sbin -To find system executables directories that are group-writable or -world-writable, run the following command for each directory DIR -which contains system executables: -$ sudo find -L DIR -perm /022 -type d - Is it the case that any of these files are group-writable or world-writable? - - - - Shared libraries are stored in the following directories: -/lib -/lib64 -/usr/lib -/usr/lib64 - -To find shared libraries that are group-writable or world-writable, -run the following command for each directory DIR which contains shared libraries: -$ sudo find -L DIR -perm /022 -type d - Is it the case that any of these files are group-writable or world-writable? - - - - Verify the system commands contained in the following directories are group-owned by "root", or a required system account, with the following command: - -$ sudo find -L /bin /sbin /usr/bin /usr/sbin /usr/local/bin /usr/local/sbin ! -group root -exec ls -l {} \; - Is it the case that any system commands are returned and is not group-owned by a required system account? - - - - Verify the system commands contained in the following directories are owned by "root" with the following command: - -$ sudo find -L /bin /sbin /usr/bin /usr/sbin /usr/libexec /usr/local/bin /usr/local/sbin ! -user root -exec ls -l {} \; - Is it the case that any system commands are found to not be owned by root? - - - - Verify the system-wide shared library files are owned by "root" with the following command: - -$ sudo find -L /lib /lib64 /usr/lib /usr/lib64 ! -user root -exec ls -l {} \; - Is it the case that any system wide shared library file is not owned by root? - - - - Verify the system commands contained in the following directories have mode "755" or less permissive with the following command: - -$ sudo find -L /bin /sbin /usr/bin /usr/sbin /usr/libexec /usr/local/bin /usr/local/sbin -perm /022 -exec ls -l {} \; - Is it the case that any system commands are found to be group-writable or world-writable? - - - - Verify the system-wide shared library files contained in the following directories have mode "755" or less permissive with the following command: - -$ sudo find -L /lib /lib64 /usr/lib /usr/lib64 -perm /022 -type f -exec ls -l {} \; - Is it the case that any system-wide shared library file is found to be group-writable or world-writable? - - - - Verify the system-wide shared library files are group-owned by "root" with the following command: - -$ sudo find -L /lib /lib64 /usr/lib /usr/lib64 ! -group root -exec ls -l {} \; - Is it the case that any system wide shared library file is returned and is not group-owned by a required system account? - - - - The following command will discover and print world-writable directories that -are not owned by root. Run it once for each local partition PART: -$ sudo find PART -xdev -type d -perm -0002 -uid +0 -print - Is it the case that there are world-writable directories not owned by root? - - - - To find world-writable directories that lack the sticky bit, run the following command: -$ sudo find / -type d \( -perm -0002 -a ! -perm -1000 \) -print 2>/dev/null -fixtext: |- -Configure all world-writable directories to have the sticky bit set to prevent unauthorized and unintended information transferred via shared system resources. - -Set the sticky bit on all world-writable directories using the command, replace "[World-Writable Directory]" with any directory path missing the sticky bit: - -$ chmod a+t [World-Writable Directory] -srg_requirement: -A sticky bit must be set on all Oracle Linux 9 public directories to prevent unauthorized and unintended information transferred via shared system resources. - Is it the case that any world-writable directories are missing the sticky bit? - - - - To check the permissions of /etc/audit/auditd.conf, -run the command: -$ ls -l /etc/audit/auditd.conf -If properly configured, the output should indicate the following permissions: --rw-r----- - Is it the case that /etc/audit/auditd.conf does not have unix mode -rw-r-----? - - - - To check the permissions of /etc/audit/rules.d/*.rules, -run the command: -$ ls -l /etc/audit/rules.d/*.rules -If properly configured, the output should indicate the following permissions: --rw-r----- - Is it the case that /etc/audit/rules.d/*.rules does not have unix mode -rw-r-----? - - - - To check the permissions of /boot/Sysem.map-*, -run the command: -$ ls -l /boot/Sysem.map-* -If properly configured, the output should indicate the following permissions: --rw------- - Is it the case that ? - - - - To find SGID files, run the following command: -$ sudo find / -xdev -type f -perm -2000 - Is it the case that there is output? - - - - To find SUID files, run the following command: -$ sudo find / -xdev -type f -perm -4000 - Is it the case that only authorized files appear in the output of the find command? - - - - To find world-writable files, run the following command: -$ sudo find / -xdev -type f -perm -002 - Is it the case that there is output? - - - - The following command will discover and print any -files on local partitions which do not belong to a valid group. -$ df --local -P | awk '{if (NR!=1) print $6}' | sudo xargs -I '{}' find '{}' -xdev -nogroup - -Either remove all files and directories from the system that do not have a valid group, -or assign a valid group with the chgrp command: -$ sudo chgrp group file - Is it the case that there is output? - - - - The following command will discover and print any -files on local partitions which do not belong to a valid user. -$ df --local -P | awk {'if (NR!=1) print $6'} | sudo xargs -I '{}' find '{}' -xdev -nouser - -Either remove all files and directories from the system that do not have a -valid user, or assign a valid user to all unowned files and directories on -the system with the chown command: -$ sudo chown user file - Is it the case that files exist that are not owned by a valid user? - - - - The runtime status of the fs.protected_hardlinks kernel parameter can be queried +-a always,exit -F path=/usr/bin/setfacl -F perm=x -F auid>=1000 -F auid!=unset -k perm_mod + Is it the case that the command does not return a line, or the line is commented out? + + + + The runtime status of the net.ipv4.icmp_echo_ignore_broadcasts kernel parameter can be queried by running the following command: -$ sysctl fs.protected_hardlinks +$ sysctl net.ipv4.icmp_echo_ignore_broadcasts 1. Is it the case that the correct value is not returned? - - - - The runtime status of the fs.protected_symlinks kernel parameter can be queried -by running the following command: -$ sysctl fs.protected_symlinks -1. - - Is it the case that the correct value is not returned? - - - - -If the system is configured to prevent the loading of the cramfs kernel module, -it will contain lines inside any file in /etc/modprobe.d or the deprecated /etc/modprobe.conf. -These lines instruct the module loading system to run another program (such as /bin/true) upon a module install event. - -These lines can also instruct the module loading system to ignore the cramfs kernel module via blacklist keyword. - -Run the following command to search for such lines in all files in /etc/modprobe.d and the deprecated /etc/modprobe.conf: -$ grep -r cramfs /etc/modprobe.conf /etc/modprobe.d - Is it the case that no line is returned? - - - - -If the system is configured to prevent the loading of the usb-storage kernel module, -it will contain lines inside any file in /etc/modprobe.d or the deprecated /etc/modprobe.conf. -These lines instruct the module loading system to run another program (such as /bin/true) upon a module install event. - -These lines can also instruct the module loading system to ignore the usb-storage kernel module via blacklist keyword. - -Run the following command to search for such lines in all files in /etc/modprobe.d and the deprecated /etc/modprobe.conf: -$ grep -r usb-storage /etc/modprobe.conf /etc/modprobe.d - Is it the case that no line is returned? - - - - To check that the autofs service is disabled in system boot configuration, -run the following command: -$ sudo systemctl is-enabled autofs -Output should indicate the autofs service has either not been installed, -or has been disabled at all runlevels, as shown in the example below: -$ sudo systemctl is-enabled autofs disabled - -Run the following command to verify autofs is not active (i.e. not running) through current runtime configuration: -$ sudo systemctl is-active autofs - -If the service is not running the command will return the following output: -inactive - -The service will also be masked, to check that the autofs is masked, run the following command: -$ sudo systemctl show autofs | grep "LoadState\|UnitFileState" - -If the service is masked the command will return the following outputs: - -LoadState=masked - -UnitFileState=masked - Is it the case that the "autofs" is loaded and not masked? - - - - Verify the nodev option is configured for the /boot mount point, - run the following command: - $ sudo mount | grep '\s/boot\s' - . . . /boot . . . nodev . . . - - Is it the case that the "/boot" file system does not have the "nodev" option set? - - - - Verify the noexec option is configured for the /boot mount point, - run the following command: - $ sudo mount | grep '\s/boot\s' - . . . /boot . . . noexec . . . - - Is it the case that the "/boot" file system does not have the "noexec" option set? - - - - Verify the nosuid option is configured for the /boot mount point, - run the following command: - $ sudo mount | grep '\s/boot\s' - . . . /boot . . . nosuid . . . - - Is it the case that the "/boot" file system does not have the "nosuid" option set? - - - - Verify the nodev option is configured for the /dev/shm mount point, - run the following command: - $ sudo mount | grep '\s/dev/shm\s' - . . . /dev/shm . . . nodev . . . - - Is it the case that the "/dev/shm" file system does not have the "nodev" option set? - - - - Verify the noexec option is configured for the /dev/shm mount point, - run the following command: - $ sudo mount | grep '\s/dev/shm\s' - . . . /dev/shm . . . noexec . . . - - Is it the case that the "/dev/shm" file system does not have the "noexec" option set? - - - - Verify the nosuid option is configured for the /dev/shm mount point, - run the following command: - $ sudo mount | grep '\s/dev/shm\s' - . . . /dev/shm . . . nosuid . . . - - Is it the case that the "/dev/shm" file system does not have the "nosuid" option set? - - - - Verify the grpquota option is configured for the /home mount point, - run the following command: - $ sudo mount | grep '\s/home\s' - . . . /home . . . grpquota . . . - - Is it the case that the "/home" file system does not have the "grpquota" option set? - - - - Verify the nodev option is configured for the /home mount point, - run the following command: - $ sudo mount | grep '\s/home\s' - . . . /home . . . nodev . . . - - Is it the case that the "/home" file system does not have the "nodev" option set? - - - - Verify the noexec option is configured for the /home mount point, - run the following command: - $ sudo mount | grep '\s/home\s' - . . . /home . . . noexec . . . - - Is it the case that the "/home" file system does not have the "noexec" option set? - - - - Verify the nosuid option is configured for the /home mount point, - run the following command: - $ sudo mount | grep '\s/home\s' - . . . /home . . . nosuid . . . - - Is it the case that the "/home" file system does not have the "nosuid" option set? - - - - Verify the usrquota option is configured for the /home mount point, - run the following command: - $ sudo mount | grep '\s/home\s' - . . . /home . . . usrquota . . . - - Is it the case that the "/home" file system does not have the "usrquota" option set? - - - - To verify the nodev option is configured for non-root local partitions, run the following command: -$ sudo mount | grep '^/dev\S* on /\S' | grep --invert-match 'nodev' -The output shows local non-root partitions mounted without the nodev option, and there should be no output at all. - - Is it the case that some mounts appear among output lines? - - - - Verify file systems that are used for removable media are mounted with the "nodev" option with the following command: - -$ sudo more /etc/fstab - -UUID=2bc871e4-e2a3-4f29-9ece-3be60c835222 /mnt/usbflash vfat noauto,owner,ro,nosuid,nodev,noexec 0 0 - Is it the case that a file system found in "/etc/fstab" refers to removable media and it does not have the "nodev" option set? - - - - To verify that binaries cannot be directly executed from removable media, run the following command: -$ grep -v noexec /etc/fstab -The resulting output will show partitions which do not have the noexec flag. Verify all partitions -in the output are not removable media. - Is it the case that removable media partitions are present? - - - - Verify file systems that are used for removable media are mounted with the "nosuid" option with the following command: - -$ sudo more /etc/fstab - -UUID=2bc871e4-e2a3-4f29-9ece-3be60c835222 /mnt/usbflash vfat noauto,owner,ro,nosuid,nodev,noexec 0 0 - Is it the case that file system found in "/etc/fstab" refers to removable media and it does not have the "nosuid" option set? - - - - Verify the nosuid option is configured for the /opt mount point, - run the following command: - $ sudo mount | grep '\s/opt\s' - . . . /opt . . . nosuid . . . - - Is it the case that the "/opt" file system does not have the "nosuid" option set? - - - - Verify the nosuid option is configured for the /srv mount point, - run the following command: - $ sudo mount | grep '\s/srv\s' - . . . /srv . . . nosuid . . . - - Is it the case that the "/srv" file system does not have the "nosuid" option set? - - - - Verify the nodev option is configured for the /tmp mount point, - run the following command: - $ sudo mount | grep '\s/tmp\s' - . . . /tmp . . . nodev . . . - - Is it the case that the "/tmp" file system does not have the "nodev" option set? - - - - Verify the noexec option is configured for the /tmp mount point, - run the following command: - $ sudo mount | grep '\s/tmp\s' - . . . /tmp . . . noexec . . . - - Is it the case that the "/tmp" file system does not have the "noexec" option set? - - - - Verify the nosuid option is configured for the /tmp mount point, - run the following command: - $ sudo mount | grep '\s/tmp\s' - . . . /tmp . . . nosuid . . . - - Is it the case that the "/tmp" file system does not have the "nosuid" option set? - - - - Verify the nodev option is configured for the /var/log/audit mount point, - run the following command: - $ sudo mount | grep '\s/var/log/audit\s' - . . . /var/log/audit . . . nodev . . . - - Is it the case that the "/var/log/audit" file system does not have the "nodev" option set? - - - - Verify the noexec option is configured for the /var/log/audit mount point, - run the following command: - $ sudo mount | grep '\s/var/log/audit\s' - . . . /var/log/audit . . . noexec . . . - - Is it the case that the "/var/log/audit" file system does not have the "noexec" option set? - - - - Verify the nosuid option is configured for the /var/log/audit mount point, - run the following command: - $ sudo mount | grep '\s/var/log/audit\s' - . . . /var/log/audit . . . nosuid . . . - - Is it the case that the "/var/log/audit" file system does not have the "nosuid" option set? - - - - Verify the nodev option is configured for the /var/log mount point, - run the following command: - $ sudo mount | grep '\s/var/log\s' - . . . /var/log . . . nodev . . . - - Is it the case that the "/var/log" file system does not have the "nodev" option set? - - - - Verify the noexec option is configured for the /var/log mount point, - run the following command: - $ sudo mount | grep '\s/var/log\s' - . . . /var/log . . . noexec . . . - - Is it the case that the "/var/log" file system does not have the "noexec" option set? - - - - Verify the nosuid option is configured for the /var/log mount point, - run the following command: - $ sudo mount | grep '\s/var/log\s' - . . . /var/log . . . nosuid . . . - - Is it the case that the "/var/log" file system does not have the "nosuid" option set? - - - - Verify the nodev option is configured for the /var mount point, - run the following command: - $ sudo mount | grep '\s/var\s' - . . . /var . . . nodev . . . - - Is it the case that the "/var" file system does not have the "nodev" option set? - - - - Verify the noexec option is configured for the /var mount point, - run the following command: - $ sudo mount | grep '\s/var\s' - . . . /var . . . noexec . . . - - Is it the case that the "/var" file system does not have the "noexec" option set? - - - - Verify the nosuid option is configured for the /var mount point, - run the following command: - $ sudo mount | grep '\s/var\s' - . . . /var . . . nosuid . . . - - Is it the case that the "/var" file system does not have the "nosuid" option set? - - - - Verify the nodev option is configured for the /var/tmp mount point, - run the following command: - $ sudo mount | grep '\s/var/tmp\s' - . . . /var/tmp . . . nodev . . . - - Is it the case that the "/var/tmp" file system does not have the "nodev" option set? - - - - Verify the noexec option is configured for the /var/tmp mount point, - run the following command: - $ sudo mount | grep '\s/var/tmp\s' - . . . /var/tmp . . . noexec . . . - - Is it the case that the "/var/tmp" file system does not have the "noexec" option set? - - - - Verify the nosuid option is configured for the /var/tmp mount point, - run the following command: - $ sudo mount | grep '\s/var/tmp\s' - . . . /var/tmp . . . nosuid . . . - - Is it the case that the "/var/tmp" file system does not have the "nosuid" option set? - - - - Verify Oracle Linux 9 disables core dump backtraces by issuing the following command: + + + + Verify Oracle Linux 9 disables core dump backtraces by issuing the following command: $ grep -i process /etc/systemd/coredump.conf ProcessSizeMax=0 Is it the case that the "ProcessSizeMax" item is missing, commented out, or the value is anything other than "0" and the need for core dumps is not documented with the Information System Security Officer (ISSO) as an operational requirement for all domains that have the "core" item assigned? - - - - Verify Oracle Linux 9 disables storing core dumps for all users by issuing the following command: - -$ grep -i storage /etc/systemd/coredump.conf - -Storage=none - Is it the case that Storage is not set to none or is commented out and the need for core dumps is not documented with the Information System Security Officer (ISSO) as an operational requirement for all domains that have the "core" item assigned? - - - - Verify that core dumps are disabled for all users, run the following command: -$ grep core /etc/security/limits.conf -* hard core 0 - Is it the case that the "core" item is missing, commented out, or the value is anything other than "0" and the need for core dumps is not documented with the Information System Security Officer (ISSO) as an operational requirement for all domains that have the "core"? - - - - To verify that acquiring, saving, and processing core dumps is disabled, run the -following command: -$ systemctl status systemd-coredump.socket -The output should be similar to: -● systemd-coredump.socket - Loaded: masked (Reason: Unit systemd-coredump.socket is masked.) - Active: inactive (dead) ... - - Is it the case that unit systemd-coredump.socket is not masked or running? - - - - The runtime status of the fs.suid_dumpable kernel parameter can be queried -by running the following command: -$ sysctl fs.suid_dumpable -0. - - Is it the case that the correct value is not returned? - - - - The runtime status of the kernel.kptr_restrict kernel parameter can be queried + + + + To determine if the system is configured to make login UIDs immutable, run +one of the following commands. +If the auditd daemon is configured to use the +augenrules program to read audit rules during daemon startup (the +default), run the following: +sudo grep immutable /etc/audit/rules.d/*.rules +If the auditd daemon is configured to use the auditctl +utility to read audit rules during daemon startup, run the following command: +sudo grep immutable /etc/audit/audit.rules +The following line should be returned: +--loginuid-immutable + Is it the case that the system is not configured to make login UIDs immutable? + + + + The runtime status of the kernel.kptr_restrict kernel parameter can be queried by running the following command: $ sysctl kernel.kptr_restrict The output of the command should indicate either: @@ -241171,665 +261674,291 @@ kernel.kptr_restrict = 2 Conflicting assignments are not allowed. Is it the case that the kernel.kptr_restrict is not set to 1 or 2 or is configured to be 0? - - - - The runtime status of the kernel.randomize_va_space kernel parameter can be queried + + + + To determine how the SSH daemon's StrictModes option is set, run the following command: + +$ sudo grep -i StrictModes /etc/ssh/sshd_config + +If a line indicating yes is returned, then the required value is set. + + Is it the case that the required value is not set? + + + + To check the ownership of /etc/cron.deny, +run the command: +$ ls -lL /etc/cron.deny +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/cron.deny does not have an owner of root? + + + + The runtime status of the net.ipv4.conf.all.shared_media kernel parameter can be queried by running the following command: -$ sysctl kernel.randomize_va_space -2. - - Is it the case that the correct value is not returned? - - - - Verify the NX (no-execution) bit flag is set on the system. - -Check that the no-execution bit flag is set with the following commands: - -$ sudo dmesg | grep NX - -[ 0.000000] NX (Execute Disable) protection: active - -If "dmesg" does not show "NX (Execute Disable) protection" active, check the cpuinfo settings with the following command: - -$ sudo grep flags /proc/cpuinfo -flags : fpu vme de pse tsc ms nx rdtscp lm constant_ts - -The output should contain the "nx" flag. - Is it the case that NX is disabled? - - - - Inspect the form of default GRUB 2 command line for the Linux operating system -in /etc/default/grub. If it includes page_poison=1, -then the parameter will be configured for newly installed kernels. -First check if the GRUB recovery is enabled: -$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub -If this option is set to true, then check that a line is output by the following command: -$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*page_poison=1.*' /etc/default/grub -If the recovery is disabled, check the line with -$ sudo grep 'GRUB_CMDLINE_LINUX.*page_poison=1.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. -Run the following command: -$ sudo grubby --info=ALL | grep args | grep -v 'page_poison=1' -The command should not return any output. - Is it the case that page allocator poisoning is not enabled? - - - - Inspect the form of default GRUB 2 command line for the Linux operating system -in /etc/default/grub. If it includes slub_debug=, -then the parameter will be configured for newly installed kernels. -First check if the GRUB recovery is enabled: -$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub -If this option is set to true, then check that a line is output by the following command: -$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*slub_debug=.*' /etc/default/grub -If the recovery is disabled, check the line with -$ sudo grep 'GRUB_CMDLINE_LINUX.*slub_debug=.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. -Run the following command: -$ sudo grubby --info=ALL | grep args | grep -v 'slub_debug=' -The command should not return any output. - Is it the case that SLUB/SLAB poisoning is not enabled? - - - - If the device or Oracle Linux 9 does not have a camera installed, this requirement is not applicable. - -This requirement is not applicable to mobile devices (smartphones and tablets), where the use of the camera is a local AO decision. - -This requirement is not applicable to dedicated VTC suites located in approved VTC locations that are centrally managed. - -For an external camera, if there is not a method for the operator to manually disconnect the camera at the end of collaborative computing sessions, this is a finding. - -For a built-in camera, the camera must be protected by a camera cover (e.g., laptop camera cover slide) when not in use. If the built-in camera is not protected with a camera cover, or is not physically disabled, this is a finding. - -If the camera is not disconnected, covered, or physically disabled, determine if it is being disabled via software with the following commands: - -Verify the operating system disables the ability to load the uvcvideo kernel module. - -$ sudo grep -r uvcvideo /etc/modprobe.d/* | grep "/bin/true" - -install uvcvideo /bin/true - Is it the case that the command does not return any output, or the line is commented out, and the collaborative computing device has not been authorized for use? - - - - The runtime status of the kernel.core_pattern kernel parameter can be queried -by running the following command: -$ sysctl kernel.core_pattern -|/bin/false. - - Is it the case that the returned line does not have a value of "|/bin/false", or a line is not -returned and the need for core dumps is not documented with the Information -System Security Officer (ISSO) as an operational requirement? - - - - The runtime status of the kernel.core_uses_pid kernel parameter can be queried -by running the following command: -$ sysctl kernel.core_uses_pid -0. - Is it the case that the returned line does not have a value of 0? - - - - The runtime status of the kernel.dmesg_restrict kernel parameter can be queried -by running the following command: -$ sysctl kernel.dmesg_restrict -1. - - Is it the case that the correct value is not returned? - - - - The runtime status of the kernel.kexec_load_disabled kernel parameter can be queried -by running the following command: -$ sysctl kernel.kexec_load_disabled -1. - - Is it the case that the correct value is not returned? - - - - The runtime status of the kernel.modules_disabled kernel parameter can be queried -by running the following command: -$ sysctl kernel.modules_disabled -1. - - Is it the case that the correct value is not returned? - - - - The runtime status of the kernel.panic_on_oops kernel parameter can be queried -by running the following command: -$ sysctl kernel.panic_on_oops -1. - - Is it the case that the correct value is not returned? - - - - The runtime status of the kernel.perf_cpu_time_max_percent kernel parameter can be queried -by running the following command: -$ sysctl kernel.perf_cpu_time_max_percent -1. - - Is it the case that the correct value is not returned? - - - - The runtime status of the kernel.perf_event_max_sample_rate kernel parameter can be queried -by running the following command: -$ sysctl kernel.perf_event_max_sample_rate -1. - - Is it the case that the correct value is not returned? - - - - The runtime status of the kernel.perf_event_paranoid kernel parameter can be queried -by running the following command: -$ sysctl kernel.perf_event_paranoid -2. - - Is it the case that the correct value is not returned? - - - - The runtime status of the kernel.pid_max kernel parameter can be queried -by running the following command: -$ sysctl kernel.pid_max -65536. - - Is it the case that the correct value is not returned? - - - - The runtime status of the kernel.sysrq kernel parameter can be queried -by running the following command: -$ sysctl kernel.sysrq +$ sysctl net.ipv4.conf.all.shared_media 0. Is it the case that the correct value is not returned? - - - - The runtime status of the kernel.unprivileged_bpf_disabled kernel parameter can be queried + + + + To check the password warning age, run the command: +$ grep PASS_WARN_AGE /etc/login.defs +The DoD requirement is 7. + Is it the case that it is not set to the required value? + + + + To verify the sec option is configured for all NFS mounts, run the following command: +$ grep "sec=" /etc/exports +All configured NFS exports should show the sec=krb5:krb5i:krb5p setting in parentheses. +This is not applicable if NFS is not implemented. + Is it the case that the setting is not configured, has the 'sys' option added, or does not have all Kerberos options added? + + + + To check the group ownership of /etc/passwd-, +run the command: +$ ls -lL /etc/passwd- +If properly configured, the output should indicate the following group-owner: +root + Is it the case that /etc/passwd- does not have a group owner of root? + + + + The runtime status of the net.ipv4.tcp_rfc1337 kernel parameter can be queried by running the following command: -$ sysctl kernel.unprivileged_bpf_disabled +$ sysctl net.ipv4.tcp_rfc1337 1. Is it the case that the correct value is not returned? - - - - The runtime status of the kernel.yama.ptrace_scope kernel parameter can be queried -by running the following command: -$ sysctl kernel.yama.ptrace_scope -1. - - Is it the case that the correct value is not returned? - - - - The runtime status of the net.core.bpf_jit_harden kernel parameter can be queried -by running the following command: -$ sysctl net.core.bpf_jit_harden -2. - - Is it the case that the correct value is not returned? - - - - Verify that Oracle Linux 9 disables the use of user namespaces with the following commands: - -Note: User namespaces are used primarily for Linux containers. If containers are in use, this requirement is not applicable. - -The runtime status of the user.max_user_namespaces kernel parameter can be queried -by running the following command: -$ sysctl user.max_user_namespaces -0. - - Is it the case that the correct value is not returned? - - - - The runtime status of the vm.mmap_min_addr kernel parameter can be queried -by running the following command: -$ sysctl vm.mmap_min_addr -65536. - - Is it the case that the correct value is not returned? - - - - + + + + To verify the nodev option is configured for all NFS mounts, run +the following command: +$ mount | grep nfs +All NFS mounts should show the nodev setting in parentheses. This +is not applicable if NFS is not implemented. + Is it the case that the setting does not show? + + + + To determine whether yum has been configured to disable +gpgcheck for any repos, inspect all files in +/etc/yum.repos.d and ensure the following does not appear in any +sections: +gpgcheck=0 +A value of 0 indicates that gpgcheck has been disabled for that repo. + Is it the case that GPG checking is disabled? + + + + To determine if requiretty has been configured for sudo, run the following command: +$ sudo grep -ri "^[\s]*Defaults.*\brequiretty\b.*" /etc/sudoers /etc/sudoers.d/ +The command should return a matching output. + Is it the case that requiretty is not enabled in sudo? + + + + Run the following command to get the current configured value for deny_execmem SELinux boolean: $ getsebool deny_execmem The expected cofiguration is . "on" means true, and "off" means false Is it the case that deny_execmem is not set as expected? - - - - -Run the following command to get the current configured value for polyinstantiation_enabled -SELinux boolean: -$ getsebool polyinstantiation_enabled -The expected cofiguration is . -"on" means true, and "off" means false - Is it the case that polyinstantiation_enabled is not set as expected? - - - - -Run the following command to get the current configured value for secure_mode_insmod -SELinux boolean: -$ getsebool secure_mode_insmod -The expected cofiguration is . -"on" means true, and "off" means false - Is it the case that secure_mode_insmod is not set as expected? - - - - -Run the following command to determine if the selinuxuser_execheap SELinux boolean is disabled: -$ getsebool selinuxuser_execheap -If properly configured, the output should show the following: -selinuxuser_execheap --> off - Is it the case that selinuxuser_execheap is not disabled? - - - - -Run the following command to determine if the selinuxuser_execmod SELinux boolean is enabled: -$ getsebool selinuxuser_execmod -If properly configured, the output should show the following: -selinuxuser_execmod --> on - Is it the case that selinuxuser_execmod is not enabled? - - - - -Run the following command to determine if the selinuxuser_execstack SELinux boolean is disabled: -$ getsebool selinuxuser_execstack -If properly configured, the output should show the following: -selinuxuser_execstack --> off - Is it the case that selinuxuser_execstack is not disabled? - - - - -Run the following command to determine if the ssh_sysadm_login SELinux boolean is disabled: -$ getsebool ssh_sysadm_login -If properly configured, the output should show the following: -ssh_sysadm_login --> off - Is it the case that ssh_sysadm_login is not disabled? - - - - Inspect /etc/default/grub for any instances of selinux=0 -in the kernel boot arguments. Presence of selinux=0 indicates -that SELinux is disabled at boot time. - Is it the case that SELinux is disabled at boot time? - - - - Run the following command to determine if the policycoreutils-python-utils package is installed: $ rpm -q policycoreutils-python-utils - Is it the case that the package is not installed? - - - - Run the following command to determine if the policycoreutils package is installed: $ rpm -q policycoreutils - Is it the case that the policycoreutils package is not installed? - - - - Run the following command to determine if the setroubleshoot-plugins package is installed: -$ rpm -q setroubleshoot-plugins - Is it the case that the package is installed? - - - - Run the following command to determine if the setroubleshoot-server package is installed: -$ rpm -q setroubleshoot-server - Is it the case that the package is installed? - - - - Ensure there are no unconfined daemons running on the system, -the following command should produce no output: -$ sudo ps -eZ | grep "unconfined_service_t" - Is it the case that There are unconfined daemons running on the system? - - - - Ensure that Oracle Linux 9 does not disable SELinux. + + + + Verify Oracle Linux 9 generates an audit record for unsuccessful attempts to use the truncate system call. -Check if "SELinux" is active and in "enforcing" or "permissive" mode with the following command: +If the auditd daemon is configured to use the "augenrules" program to to read audit rules during daemon startup (the default), run the following command: -$ sudo getenforce -Enforcing --OR- -Permissive - Is it the case that SELinux is disabled? - - - - Verify the SELINUX on Oracle Linux 9 is using the policy with the following command: +$ sudo grep -r truncate /etc/audit/rules.d -$ sestatus | grep policy +If the auditd daemon is configured to use the "auditctl" utility to read audit rules during daemon startup, run the following command: -Loaded policy name: - Is it the case that the loaded policy name is not "<sub idref="var_selinux_policy_name" />"? - - - - Ensure that Oracle Linux 9 verifies correct operation of security functions. +$ sudo grep truncate /etc/audit/audit.rules -Check if "SELinux" is active and in "" mode with the following command: +The output should be the following: -$ sudo getenforce - - Is it the case that SELINUX is not set to enforcing? - - - - Check the system partitions to determine if they are encrypted with the following command: -blkid - -Output will be similar to: -/dev/sda1: UUID=" ab12c3de-4f56-789a-8f33-3850cc8ce3a2 -" TYPE="crypto_LUKS" -/dev/sda2: UUID=" bc98d7ef-6g54-321h-1d24-9870de2ge1a2 -" TYPE="crypto_LUKS" - -The boot partition and pseudo-file systems, such as /proc, /sys, and tmpfs, -are not required to use disk encryption and are not a finding. - Is it the case that partitions do not have a type of crypto_LUKS? - - - - Verify that a separate file system/partition has been created for /dev/shm with the following command: - -$ mountpoint /dev/shm - - Is it the case that "/dev/shm is not a mountpoint" is returned? - - - - Verify that a separate file system/partition has been created for /home with the following command: - -$ mountpoint /home - - Is it the case that "/home is not a mountpoint" is returned? - - - - Verify that a separate file system/partition has been created for /srv with the following command: - -$ mountpoint /srv - - Is it the case that "/srv is not a mountpoint" is returned? - - - - Verify that a separate file system/partition has been created for /tmp with the following command: - -$ mountpoint /tmp - - Is it the case that "/tmp is not a mountpoint" is returned? - - - - Verify that a separate file system/partition has been created for /var with the following command: - -$ mountpoint /var - - Is it the case that "/var is not a mountpoint" is returned? - - - - Verify that a separate file system/partition has been created for /var/log with the following command: - -$ mountpoint /var/log - - Is it the case that "/var/log is not a mountpoint" is returned? - - - - Verify that a separate file system/partition has been created for /var/log/audit with the following command: - -$ mountpoint /var/log/audit - - Is it the case that "/var/log/audit is not a mountpoint" is returned? - - - - Verify that a separate file system/partition has been created for /var/tmp with the following command: - -$ mountpoint /var/tmp - - Is it the case that "/var/tmp is not a mountpoint" is returned? - - - - To ensure disable and restart on the login screen are disabled, run the following command: -$ grep disable-restart-buttons /etc/dconf/db/gdm.d/* -The output should be true. -To ensure that users cannot enable disable and restart on the login screen, run the following: -$ grep disable-restart-buttons /etc/dconf/db/gdm.d/locks/* -If properly configured, the output should be /org/gnome/login-screen/disable-restart-buttons - Is it the case that disable-restart-buttons has not been configured or is not disabled? - - - - To ensure the user list is disabled, run the following command: -$ grep disable-user-list /etc/dconf/db/gdm.d/* -The output should be true. -To ensure that users cannot enable displaying the user list, run the following: -$ grep disable-user-list /etc/dconf/db/gdm.d/locks/* -If properly configured, the output should be /org/gnome/login-screen/disable-user-list - Is it the case that disable-user-list has not been configured or is not disabled? - - - - To ensure screen locking on smartcard removal is enabled, run the following command: -$ grep removal-action /etc/dconf/db/local.d/* -The output should be 'lock-screen'. -To ensure that users cannot disable screen locking on smartcard removal, run the following: -$ grep removal-action /etc/dconf/db/local.d/locks/* -If properly configured, the output should be /org/gnome/settings-daemon/peripherals/smartcard/removal-action - Is it the case that removal-action has not been configured? - - - - To verify that automatic logins are disabled, run the following command: -$ grep -Pzoi "^\[daemon]\\nautomaticlogin.*" /etc/gdm/custom.conf -The output should show the following: -[daemon] -AutomaticLoginEnable=false - Is it the case that GDM allows users to automatically login? - - - - To ensure that XDMCP is disabled in /etc/gdm/custom.conf, run the following command: -grep -Pzo "\[xdmcp\]\nEnable=false" /etc/gdm/custom.conf -The output should return the following: - -[xdmcp] -Enable=false - - Is it the case that the Enable is not set to false or is missing in the xdmcp section of the /etc/gdm/custom.conf gdm configuration file? - - - - These settings can be verified by running the following: -$ gsettings get org.gnome.desktop.media-handling automount-open -If properly configured, the output for automount-openshould be false. -To ensure that users cannot enable automount opening in GNOME3, run the following: -$ grep 'automount-open' /etc/dconf/db/local.d/locks/* -If properly configured, the output for automount-open should be /org/gnome/desktop/media-handling/automount-open - Is it the case that GNOME automounting is not disabled? - - - - These settings can be verified by running the following: -$ gsettings get org.gnome.desktop.media-handling autorun-never -If properly configured, the output for autorun-nevershould be true. -To ensure that users cannot enable autorun in GNOME3, run the following: -$ grep 'autorun-never' /etc/dconf/db/local.d/locks/* -If properly configured, the output for autorun-never should be /org/gnome/desktop/media-handling/autorun-never - Is it the case that GNOME autorun is not disabled? - - - - To ensure that remote access requires credentials, run the following command: -$ gsettings get org.gnome.Vino authentication-methods -If properly configured, the output should be false. -To ensure that users cannot disable credentials for remote access, run the following: -$ grep authentication-methods /etc/dconf/db/local.d/locks/* -If properly configured, the output should be -/org/gnome/Vino/authentication-methods - Is it the case that wireless network notification is enabled and not disabled? - - - - To ensure that remote access connections are encrypted, run the following command: -$ gsettings get org.gnome.Vino require-encrpytion -If properly configured, the output should be true. -To ensure that users cannot disable encrypted remote connections, run the following: -$ grep require-encryption /etc/dconf/db/local.d/locks/* -If properly configured, the output should be -/org/gnome/Vino/require-encryption - Is it the case that remote access connections are not encrypted? - - - - To check the screensaver mandatory use status, run the following command: -$ gsettings get org.gnome.desktop.screensaver idle-activation-enabled -If properly configured, the output should be true. -To ensure that users cannot disable the screensaver idle inactivity setting, run the following: -$ grep idle-activation-enabled /etc/dconf/db/local.d/locks/* -If properly configured, the output should be /org/gnome/desktop/screensaver/idle-activation-enabled - Is it the case that idle-activation-enabled is not enabled or configured? - - - - To check the current idle time-out value, run the following command: -$ gsettings get org.gnome.desktop.session idle-delay -If properly configured, the output should be 'uint32 '. -To ensure that users cannot change the screensaver inactivity timeout setting, run the following: -$ grep idle-delay /etc/dconf/db/local.d/locks/* -If properly configured, the output should be /org/gnome/desktop/session/idle-delay - Is it the case that idle-delay is set to 0 or a value greater than <sub idref="inactivity_timeout_value" />? - - - - To check that the screen locks immediately when activated, run the following command: -$ gsettings get org.gnome.desktop.screensaver lock-delay -If properly configured, the output should be 'uint32 '. - Is it the case that the screensaver lock delay is missing, or is set to a value greater than <sub idref="var_screensaver_lock_delay" />? - - - - To check the status of the idle screen lock activation, run the following command: - -$ gsettings get org.gnome.desktop.screensaver lock-enabled -If properly configured, the output should be true. -To ensure that users cannot change how long until the screensaver locks, run the following: -$ grep lock-enabled /etc/dconf/db/local.d/locks/* -If properly configured, the output for lock-enabled should be /org/gnome/desktop/screensaver/lock-enabled - Is it the case that screensaver locking is not enabled and/or has not been set or configured correctly? - - - - To ensure that users cannot change how long until the screensaver locks, run the following: -$ grep lock-enabled /etc/dconf/db/local.d/locks/* -If properly configured, the output for lock-enabled should be /org/gnome/desktop/screensaver/lock-enabled - Is it the case that screensaver locking is not locked? - - - - To ensure the screensaver is configured to be blank, run the following command: -$ gsettings get org.gnome.desktop.screensaver picture-uri -If properly configured, the output should be ''. - -To ensure that users cannot set the screensaver background, run the following: -$ grep picture-uri /etc/dconf/db/local.d/locks/* -If properly configured, the output should be /org/gnome/desktop/screensaver/picture-uri - Is it the case that it is not set or configured properly? - - - - To ensure that users cannot change session idle and lock settings, run the following: -$ grep 'lock-delay' /etc/dconf/db/local.d/locks/* -If properly configured, the output should return: -/org/gnome/desktop/screensaver/lock-delay - Is it the case that GNOME3 session settings are not locked or configured properly? - - - - To ensure that users cannot change session idle and lock settings, run the following: -$ grep 'idle-delay' /etc/dconf/db/local.d/locks/* -If properly configured, the output should return: -/org/gnome/desktop/session/idle-delay - Is it the case that idle-delay is not locked? - - - - To ensure the system is configured to ignore the Ctrl-Alt-Del sequence, +-a always,exit -F arch=b32 -S truncate -F exit=-EPERM -F auid>=1000 -F auid!=unset -k access +-a always,exit -F arch=b64 -S truncate -F exit=-EPERM -F auid>=1000 -F auid!=unset -k access +-a always,exit -F arch=b32 -S truncate -F exit=-EACCES -F auid>=1000 -F auid!=unset -k access +-a always,exit -F arch=b64 -S truncate -F exit=-EACCES -F auid>=1000 -F auid!=unset -k access + Is it the case that the command does not return a line, or the line is commented out? + + + + To ensure the system is configured to ignore the Ctrl-Alt-Del sequence, run the following command: $ gsettings get org.gnome.settings-daemon.plugins.media-keys logout $ grep logout /etc/dconf/db/local.d/locks/* If properly configured, the output should be /org/gnome/settings-daemon/plugins/media-keys/logout Is it the case that GNOME3 is configured to reboot when Ctrl-Alt-Del is pressed? - - - - In order to be sure that the databases are up-to-date, run the -dconf update -command as the administrator. - Is it the case that The system-wide dconf databases are up-to-date with regards to respective keyfiles? - - - - To verify that the DConf User profile is configured correctly, run the following -command: + + + + The following command will list which files on the system have permissions different from what +is expected by the RPM database: +$ rpm -Va | awk '{ if (substr($0,2,1)=="M") print $NF }' + Is it the case that there is output? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "sudo" command with the following command: -$ cat /etc/dconf/profile/user -The output should show the following: -user-db:user -system-db:local -system-db:site -system-db:distro - Is it the case that DConf User profile does not exist or is not configured correctly? - - - - To verify that the installed operating system is supported, run -the following command: +$ sudo auditctl -l | grep sudo -$ grep -i "oracle" /etc/oracle-release +-a always,exit -F path=/usr/bin/sudo -F perm=x -F auid>=1000 -F auid!=unset -k privileged-sudo + Is it the case that the command does not return a line, or the line is commented out? + + + + Inspect the form of default GRUB 2 command line for the Linux operating system +in /etc/default/grub. If it includes mce=0, +then the parameter will be configured for newly installed kernels. +First check if the GRUB recovery is enabled: +$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub +If this option is set to true, then check that a line is output by the following command: +$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*mce=0.*' /etc/default/grub +If the recovery is disabled, check the line with +$ sudo grep 'GRUB_CMDLINE_LINUX.*mce=0.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. +Run the following command: +$ sudo grubby --info=ALL | grep args | grep -v 'mce=0' +The command should not return any output. + Is it the case that MCE tolerance is not set to zero? + + + + Run the following command to determine if the rng-tools package is installed: $ rpm -q rng-tools + Is it the case that the package is not installed? + + + + The runtime status of the net.ipv4.conf.all.rp_filter parameter can be queried +by running the following command: +$ sysctl net.ipv4.conf.all.rp_filter +The output of the command should indicate either: +net.ipv4.conf.all.rp_filter = 1 +or: +net.ipv4.conf.all.rp_filter = 2 +The output of the command should not indicate: +net.ipv4.conf.all.rp_filter = 0 -Oracle Linux 9 - Is it the case that the installed operating system is not supported? - - - - To verify that BIND uses the system crypto policy, check out that the BIND config file -/etc/named.conf contains the include "/etc/crypto-policies/back-ends/bind.config"; -directive: -$ sudo grep 'include "/etc/crypto-policies/back-ends/bind.config";' /etc/named.conf -Verify that the directive is at the bottom of the options section of the config file. - Is it the case that BIND is installed and the BIND config file doesn't contain the -<pre>include "/etc/crypto-policies/back-ends/bind.config";</pre> directive? - - - - To verify that cryptography policy has been configured correctly, run the +The preferable way how to assure the runtime compliance is to have +correct persistent configuration, and rebooting the system. + +The persistent sysctl parameter configuration is performed by specifying the appropriate +assignment in any file located in the /etc/sysctl.d directory. +Verify that there is not any existing incorrect configuration by executing the following command: +$ grep -r '^\s*net.ipv4.conf.all.rp_filter\s*=' /etc/sysctl.conf /etc/sysctl.d +The command should not find any assignments other than: +net.ipv4.conf.all.rp_filter = 1 +or: +net.ipv4.conf.all.rp_filter = 2 + +Conflicting assignments are not allowed. + Is it the case that the net.ipv4.conf.all.rp_filter is not set to 1 or 2 or is configured to be 0? + + + + To determine how the SSH daemon's IgnoreRhosts option is set, run the following command: + +$ sudo grep -i IgnoreRhosts /etc/ssh/sshd_config + +If a line indicating yes is returned, then the required value is set. + + Is it the case that the required value is not set? + + + + Run the following command to ensure the TMOUT value is configured for all users +on the system: + +$ sudo grep TMOUT /etc/profile /etc/profile.d/*.sh + +The output should return the following: +TMOUT= + Is it the case that value of TMOUT is not less than or equal to expected setting? + + + + To determine how the SSH daemon's LogLevel option is set, run the following command: + +$ sudo grep -i LogLevel /etc/ssh/sshd_config + +If a line indicating INFO is returned, then the required value is set. + + Is it the case that the required value is not set? + + + + To verify that the Audit is correctly configured according to recommended rules, check the content of the file with the following command: +cat /etc/audit/rules.d/30-ospp-v42-6-owner-change-success.rules +The output has to be exactly as follows: +## Successful ownership change +-a always,exit -F arch=b32 -S lchown,fchown,chown,fchownat -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-owner-change +-a always,exit -F arch=b64 -S lchown,fchown,chown,fchownat -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-owner-change + Is it the case that the file does not exist or the content differs? + + + + To determine whether the SSH server includes configuration files from the right directory, run the following command: +$ sudo grep -i '^Include' /etc/ssh/sshd_config +If a line Include /etc/ssh/sshd_config.d/*.conf is returned, then the configuration file inclusion is set correctly. + Is it the case that you don't include other configuration files from the main configuration file? + + + + Verify Oracle Linux 9 generates audit records for all account creations, modifications, disabling, and termination events that affect "/etc/security/opasswd" with the following command: + +$ sudo auditctl -l | grep -E '(/etc/security/opasswd)' + +-w /etc/security/opasswd -p wa -k identity + Is it the case that the command does not return a line, or the line is commented out? + + + + To check the permissions of /etc/sestatus.conf, +run the command: +$ ls -l /etc/sestatus.conf +If properly configured, the output should indicate the following permissions: +0644 + Is it the case that /etc/sestatus.conf does not have unix mode 0644? + + + + To determine that AIDE is verifying extended file attributes, run the following command: +$ grep xattrs /etc/aide.conf +Verify that the xattrs option is added to the correct ruleset. + Is it the case that the xattrs option is missing or not added to the correct ruleset? + + + + Verify that Oracle Linux 9 has configured the minimum time period between password changes for each user account is one day or greater with the following command: + +$ sudo awk -F: '$4 < 1 {print $1 " " $4}' /etc/shadow + Is it the case that any results are returned that are not associated with a system account? + + + + Verify that the SA and ISSO (at a minimum) are notified when the audit storage volume is full. + +Check which action Oracle Linux 9 takes when the audit storage volume is full with the following command: + +$ sudo grep max_log_file_action /etc/audit/auditd.conf +max_log_file_action = + Is it the case that the value of the "max_log_file_action" option is set to "ignore", "rotate", or "suspend", or the line is commented out? + + + + To verify that cryptography policy has been configured correctly, run the following command: $ update-crypto-policies --show The output should return . @@ -241843,3103 +261972,2394 @@ Subsequently, check if matching libraries have drop in files in the /etc/crypto- $ ls /etc/crypto-policies/local.d/ | awk -F'-' '{print $1}' | uniq | sort Outputs of two previous commands should match. Is it the case that cryptographic policy is not configured or is configured incorrectly? - - - - Check that the symlink exists and target the correct Kerberos crypto policy, with the following command: -file /etc/krb5.conf.d/crypto-policies -If command ouput shows the following line, Kerberos is configured to use the system-wide crypto policy. -/etc/krb5.conf.d/crypto-policies: symbolic link to /etc/crypto-policies/back-ends/krb5.config - Is it the case that the symlink does not exist or points to a different target? - - - - Verify that the IPSec service uses the system crypto policy. + + + + Verify Oracle Linux 9 generates audit records for all account creations, modifications, disabling, and termination events that affect "/var/log/lastlog" with the following command: -If the ipsec service is not installed is not applicable. - -Check to see if the "IPsec" service is active with the following command: - -$ systemctl status ipsec - -ipsec.service - Internet Key Exchange (IKE) Protocol Daemon for IPsec -Loaded: loaded (/usr/lib/systemd/system/ipsec.service; disabled) -Active: inactive (dead) - -If the "IPsec" service is active, check to see if it is using the system crypto policy with the following command: - -$ sudo grep include /etc/ipsec.conf /etc/ipsec.d/*.conf - -/etc/ipsec.conf:include /etc/crypto-policies/back-ends/libreswan.config - Is it the case that the "IPsec" service is active and the ipsec configuration file does not contain does not contain <tt>include /etc/crypto-policies/back-ends/libreswan.config</tt>? - - - - To verify that OpenSSL uses the system crypto policy, check out that the OpenSSL config file -/etc/pki/tls/openssl.cnf contains the [ crypto_policy ] section with the -.include = /etc/crypto-policies/back-ends/opensslcnf.config directive: - -$ sudo grep '\.include\s* /etc/crypto-policies/back-ends/opensslcnf.config$' /etc/pki/tls/openssl.cnf. - Is it the case that the OpenSSL config file doesn't contain the whole section, -or the section doesn't contain the <pre>.include = /etc/crypto-policies/back-ends/opensslcnf.config</pre> directive? - - - - To verify if the OpenSSL uses defined TLS Crypto Policy, run: -$ grep -P '^(TLS\.)?MinProtocol' /etc/crypto-policies/back-ends/opensslcnf.config -and verify that the value is -TLSv1.2 - Is it the case that cryptographic policy for openssl is not configured or is configured incorrectly? - - - - Verify that sshd isn't configured to ignore the system wide cryptographic policy. - -Check that the CRYPTO_POLICY variable is not set or is commented out in the -/etc/sysconfig/sshd. +$ sudo auditctl -l | grep /var/log/lastlog +-w /var/log/lastlog -p wa -k logins + Is it the case that the command does not return a line, or the line is commented out? + + + + Inspect the form of default GRUB 2 command line for the Linux operating system +in /etc/default/grub. If it includes iommu=force, +then the parameter will be configured for newly installed kernels. +First check if the GRUB recovery is enabled: +$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub +If this option is set to true, then check that a line is output by the following command: +$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*iommu=force.*' /etc/default/grub +If the recovery is disabled, check the line with +$ sudo grep 'GRUB_CMDLINE_LINUX.*iommu=force.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. Run the following command: +$ sudo grubby --info=ALL | grep args | grep -v 'iommu=force' +The command should not return any output. + Is it the case that I/OMMU is not activated? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_DEVKMEM /boot/config.* + + Configs with value 'n' are not explicitly set in the file, so either commented lines or no + lines should be returned. + + Is it the case that the kernel was not built with the required value? + + + + Run the following command and verify that time sources are only configured with server directive: +# grep -E "^(server|pool)" /etc/chrony.conf +A line with the appropriate server should be returned, any line returned starting with pool is a finding. + Is it the case that an authoritative remote time server is not configured or configured with pool directive? + + + + To check the permissions of /var/log/messages, +run the command: +$ ls -l /var/log/messages +If properly configured, the output should indicate the following permissions: +-rw------- + Is it the case that /var/log/messages does not have unix mode -rw-------? + + + + Verify Oracle Linux 9 enforces 24 hours/one day as the minimum password lifetime for new user accounts. -$ sudo grep CRYPTO_POLICY /etc/sysconfig/sshd - Is it the case that the CRYPTO_POLICY variable is set or is not commented out in the /etc/sysconfig/sshd? - - - - To verify if the OpenSSH Client uses defined Crypto Policy, run: -$ cat /etc/ssh/ssh_config.d/02-ospp.conf -and verify that the line matches -Match final all -RekeyLimit 512M 1h -GSSAPIAuthentication no -Ciphers aes256-ctr,aes256-cbc,aes128-ctr,aes128-cbc -PubkeyAcceptedKeyTypes ssh-rsa,ecdsa-sha2-nistp384,ecdsa-sha2-nistp256 -MACs hmac-sha2-512,hmac-sha2-256 -KexAlgorithms ecdh-sha2-nistp521,ecdh-sha2-nistp384,ecdh-sha2-nistp256,diffie-hellman-group14-sha1 - Is it the case that Crypto Policy for OpenSSH Client is not configured according to CC requirements? - - - - To verify if the OpenSSH client uses defined Cipher suite in the Crypto Policy, run: -$ grep -i ciphers /etc/crypto-policies/back-ends/openssh.config -and verify that the line matches: -Ciphers - Is it the case that Crypto Policy for OpenSSH client is not configured correctly? - - - - To verify if the OpenSSH server uses defined ciphers in the Crypto Policy, run: -$ grep -Po '(-oCiphers=\S+)' /etc/crypto-policies/back-ends/opensshserver.config -and verify that the line matches: --oCiphers= - Is it the case that Crypto Policy for OpenSSH Server is not configured correctly? - - - - To verify if the OpenSSH client uses defined MACs in the Crypto Policy, run: -$ grep -i macs /etc/crypto-policies/back-ends/openssh.config -and verify that the line matches: -MACs hmac-sha2-512,hmac-sha2-256 - Is it the case that Crypto Policy for OpenSSH client is not configured correctly? - - - - To verify if the OpenSSH server uses defined MACs in the Crypto Policy, run: -$ grep -Po '(-oMACs=\S+)' /etc/crypto-policies/back-ends/opensshserver.config -and verify that the line matches: --oMACS=hmac-sha2-512,hmac-sha2-256,hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com - Is it the case that Crypto Policy for OpenSSH Server is not configured correctly? - - - - Run the following command to determine if the crypto-policies package is installed: $ rpm -q crypto-policies +Check for the value of "PASS_MIN_DAYS" in "/etc/login.defs" with the following command: + +$ grep -i pass_min_days /etc/login.defs + +PASS_MIN_DAYS + Is it the case that the "PASS_MIN_DAYS" parameter value is not "<sub idref="var_accounts_minimum_age_login_defs" />" or greater, or is commented out? + + + + Run the following command to determine if the libreswan package is installed: $ rpm -q libreswan Is it the case that the package is not installed? - - - - To verify that McAfee Endpoint Security for Linux is -running, run the following command: -$ sudo ps -ef | grep -i mfetpd - Is it the case that virus scanning software is not running? - - - - Run the following command to determine if the McAfeeTP package is installed: $ rpm -q McAfeeTP - Is it the case that the package is not installed? - - - - To verify that McAfee HIPS is installed, run the following command(s): -$ rpm -q MFEhiplsm - Is it the case that the HBSS HIPS module is not installed? - - - - Verify that the system backups user data. - Is it the case that it is not? - - - - Inspect the system to determine if intrusion detection software has been installed. -Verify this intrusion detection software is active. - Is it the case that no host-based intrusion detection tools are installed? - - - - To verify that the Dracut FIPS module is enabled, run the following command: -grep "add_dracutmodules" /etc/dracut.conf.d/40-fips.conf -The output should look like this: -add_dracutmodules+=" fips " - Is it the case that the Dracut FIPS module is not enabled? - - - - To verify that FIPS mode is enabled properly, run the following command: -fips-mode-setup --check + + + + Ensure that debug-shell service is not enabled with the following command: +grep systemd\.debug-shell=1 /boot/grub2/grubenv /etc/default/grub +If the command returns a line, it means that debug-shell service is being enabled. + Is it the case that the comand returns a line? + + + + Using a non-privileged account, verify that users cannot modify or change +network settings with the nmcli command with the following command: +$ nmcli general permissions The output should contain the following: -FIPS mode is enabled. -To verify that the cryptographic policy has been configured correctly, run the +PERMISSION VALUE +org.freedesktop.NetworkManager.enable-disable-network auth +org.freedesktop.NetworkManager.enable-disable-wifi auth +org.freedesktop.NetworkManager.enable-disable-wwan auth +org.freedesktop.NetworkManager.enable-disable-wimax auth +org.freedesktop.NetworkManager.sleep-wake auth +org.freedesktop.NetworkManager.network-control auth +org.freedesktop.NetworkManager.wifi.share.protected auth +org.freedesktop.NetworkManager.wifi.share.open auth +org.freedesktop.NetworkManager.settings.modify.system auth +org.freedesktop.NetworkManager.settings.modify.own auth +org.freedesktop.NetworkManager.settings.modify.hostname auth +org.freedesktop.NetworkManager.settings.modify.global-dns auth +org.freedesktop.NetworkManager.reload auth +org.freedesktop.NetworkManager.checkpoint-rollback auth +org.freedesktop.NetworkManager.enable-disable-statistics auth +org.freedesktop.NetworkManager.enable-disable-connectivity-check auth +org.freedesktop.NetworkManager.wifi.scan auth + + Is it the case that non-privileged users can modify or change network settings? + + + + Verify the nodev option is configured for the /boot mount point, + run the following command: + $ sudo mount | grep '\s/boot\s' + . . . /boot . . . nodev . . . + + Is it the case that the "/boot" file system does not have the "nodev" option set? + + + + Verify that Oracle Linux 9 enforces password complexity by requiring that at least one numeric character be used. + +Check the value for "dcredit" with the following command: + +$ sudo grep dcredit /etc/security/pwquality.conf /etc/security/pwquality.conf.d/*.conf + +/etc/security/pwquality.conf:dcredit = + Is it the case that the value of "dcredit" is a positive number or is commented out? + + + + To determine how the SSH daemon's PubkeyAuthentication option is set, run the following command: + +$ sudo grep -i PubkeyAuthentication /etc/ssh/sshd_config + +If a line indicating yes is returned, then the required value is set. + + Is it the case that the required value is not set? + + + + The runtime status of the net.ipv4.conf.default.secure_redirects kernel parameter can be queried +by running the following command: +$ sysctl net.ipv4.conf.default.secure_redirects +0. + + Is it the case that the correct value is not returned? + + + + To verify that the Audit is correctly configured according to recommended rules, check the content of the file with the following command: +cat /etc/audit/rules.d/10-base-config.rules +The output has to be exactly as follows: +## First rule - delete all +-D + +## Increase the buffers to survive stress events. +## Make this bigger for busy systems +-b 8192 + +## This determine how long to wait in burst of events +--backlog_wait_time 60000 + +## Set failure mode to syslog +-f 1 + Is it the case that the file does not exist or the content differs? + + + + Verify the nodev option is configured for the /home mount point, + run the following command: + $ sudo mount | grep '\s/home\s' + . . . /home . . . nodev . . . + + Is it the case that the "/home" file system does not have the "nodev" option set? + + + + To check the status of the idle screen lock activation, run the following command: + +$ gsettings get org.gnome.desktop.screensaver lock-enabled +If properly configured, the output should be true. +To ensure that users cannot change how long until the screensaver locks, run the following: +$ grep lock-enabled /etc/dconf/db/local.d/locks/* +If properly configured, the output for lock-enabled should be /org/gnome/desktop/screensaver/lock-enabled + Is it the case that screensaver locking is not enabled and/or has not been set or configured correctly? + + + + Inspect the form of default GRUB 2 command line for the Linux operating system +in /etc/default/grub. If it includes page_poison=1, +then the parameter will be configured for newly installed kernels. +First check if the GRUB recovery is enabled: +$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub +If this option is set to true, then check that a line is output by the following command: +$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*page_poison=1.*' /etc/default/grub +If the recovery is disabled, check the line with +$ sudo grep 'GRUB_CMDLINE_LINUX.*page_poison=1.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. +Run the following command: +$ sudo grubby --info=ALL | grep args | grep -v 'page_poison=1' +The command should not return any output. + Is it the case that page allocator poisoning is not enabled? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "sudoedit" command with the following command: + +$ sudo auditctl -l | grep sudoedit + +-a always,exit -F path=/usr/bin/sudoedit -F perm=x -F auid>=1000 -F auid!=unset -k privileged-sudoedit + Is it the case that the command does not return a line, or the line is commented out? + + + + +If the system is configured to prevent the loading of the sctp kernel module, +it will contain lines inside any file in /etc/modprobe.d or the deprecated /etc/modprobe.conf. +These lines instruct the module loading system to run another program (such as /bin/false) upon a module install event. + +These lines can also instruct the module loading system to ignore the sctp kernel module via blacklist keyword. + +Run the following command to search for such lines in all files in /etc/modprobe.d and the deprecated /etc/modprobe.conf: +$ grep -r sctp /etc/modprobe.conf /etc/modprobe.d + Is it the case that no line is returned? + + + + To verify that auditing is configured for system administrator actions, run the following command: +$ sudo auditctl -l | grep "watch=/etc/sudoers\|watch=/etc/sudoers.d\|-w /etc/sudoers\|-w /etc/sudoers.d" + Is it the case that there is not output? + + + + To determine if the system is configured to audit calls to the +fchownat system call, run the following command: +$ sudo grep "fchownat" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. + + Is it the case that no line is returned? + + + + To check the ownership of /etc/cron.d, +run the command: +$ ls -lL /etc/cron.d +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/cron.d does not have an owner of root? + + + + Run the following command and verify remote server is configured properly: +# grep -E "^(server|pool)" /etc/chrony.conf + Is it the case that a remote time server is not configured? + + + + To verify all files and directories in interactive user home directory are +group-owned by a group the user is a member of, run the following command: -$ update-crypto-policies --show -The output should return . - Is it the case that FIPS mode is not enabled? - - - - To verify /etc/system-fips exists, run the following command: -ls -l /etc/system-fips -The output should be similar to the following: --rw-r--r--. 1 root root 36 Nov 26 11:31 /etc/system-fips - Is it the case that /etc/system-fips does not exist? - - - - To verify that kernel parameter 'crypto.fips_enabled' is set properly, run the following command: -sysctl crypto.fips_enabled -The output should contain the following: -crypto.fips_enabled = 1 - Is it the case that crypto.fips_enabled is not 1? - - - - To find the location of the AIDE database file, run the following command: -$ sudo ls -l DBDIR/database_file_name - Is it the case that there is no database file? - - - - Check that AIDE is properly configured to protect the integrity of the -audit tools by running the following command: +$ sudo ls -lLR /home/USER + Is it the case that the group ownership is incorrect? + + + + If the system does not have SELinux enabled and enforcing a targeted policy, or if the +pam_faillock.so module is not configured for use, this requirement is not applicable. -# sudo cat /etc/aide.conf | grep /usr/sbin/au +Verify the location of the non-default tally directory for the pam_faillock.so module with +the following command: -/usr/sbin/auditctl p+i+n+u+g+s+b+acl+xattrs+sha512 -/usr/sbin/auditd p+i+n+u+g+s+b+acl+xattrs+sha512 -/usr/sbin/ausearch p+i+n+u+g+s+b+acl+xattrs+sha512 -/usr/sbin/aureport p+i+n+u+g+s+b+acl+xattrs+sha512 -/usr/sbin/autrace p+i+n+u+g+s+b+acl+xattrs+sha512 +$ sudo grep -w dir /etc/security/faillock.conf -/usr/sbin/rsyslogd p+i+n+u+g+s+b+acl+xattrs+sha512 +dir = /var/log/faillock -/usr/sbin/augenrules p+i+n+u+g+s+b+acl+xattrs+sha512 +Check the security context type of the non-default tally directory with the following command: +$ sudo ls -Zd /var/log/faillock -If AIDE is configured properly to protect the integrity of the audit tools, -all lines listed above will be returned from the command. +unconfined_u:object_r:faillog_t:s0 /var/log/faillock + Is it the case that the security context type of the non-default tally directory is not "faillog_t"? + + + + To check the ownership of /etc/shells, +run the command: +$ ls -lL /etc/shells +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/shells does not have an owner of root? + + + + Verify that the interactive user account passwords are using a strong +password hash with the following command: -If one or more lines are missing, this is a finding. - Is it the case that integrity checks of the audit tools are missing or incomplete? - - - - Verify the operating system routinely checks the baseline configuration for unauthorized changes. +$ sudo cut -d: -f2 /etc/shadow -To determine that periodic AIDE execution has been scheduled, run the following command: -$ grep aide /etc/crontab -The output should return something similar to the following: -05 4 * * * root /usr/sbin/aide --check +$6$kcOnRq/5$NUEYPuyL.wghQwWssXRcLRFiiru7f5JPV6GaJhNC2aK5F3PZpE/BCCtwrxRc/AInKMNX3CdMw11m9STiql12f/ -NOTE: The usage of special cron times, such as @daily or @weekly, is acceptable. - Is it the case that AIDE is not configured to scan periodically? - - - - To determine that periodic AIDE execution has been scheduled, run the following command: -$ grep aide /etc/crontab -The output should return something similar to the following: -05 4 * * * root /usr/sbin/aide --check | /bin/mail -s "$(hostname) - AIDE Integrity Check" root@localhost -The email address that the notifications are sent to can be changed by overriding -. - Is it the case that AIDE has not been configured or has not been configured to notify personnel of scan details? - - - - To determine that AIDE is verifying ACLs, run the following command: -$ grep acl /etc/aide.conf -Verify that the acl option is added to the correct ruleset. - Is it the case that the acl option is missing or not added to the correct ruleset? - - - - To determine that AIDE is verifying extended file attributes, run the following command: -$ grep xattrs /etc/aide.conf -Verify that the xattrs option is added to the correct ruleset. - Is it the case that the xattrs option is missing or not added to the correct ruleset? - - - - Verify the audit tools are group-owned by "root" to prevent any unauthorized access, deletion, or modification. +Password hashes ! or * indicate inactive accounts not +available for logon and are not evaluated. + Is it the case that any interactive user password hash does not begin with "$6"? + + + + To verify that automatic logins are disabled, run the following command: +$ grep -Pzoi "^\[daemon]\\nautomaticlogin.*" /etc/gdm/custom.conf +The output should show the following: +[daemon] +AutomaticLoginEnable=false + Is it the case that GDM allows users to automatically login? + + + + Verify that Oracle Linux 9 enforces a -day maximum password lifetime for new user accounts by running the following command: -Check the group-owner of each audit tool by running the following command: +$ grep -i pass_max_days /etc/login.defs -$ sudo stat -c "%G %n" /sbin/auditctl /sbin/aureport /sbin/ausearch /sbin/autrace /sbin/auditd /sbin/rsyslogd /sbin/augenrules +PASS_MAX_DAYS + Is it the case that the "PASS_MAX_DAYS" parameter value is greater than "<sub idref="var_accounts_maximum_age_login_defs" />", or commented out? + + + + To determine if the system is configured to audit calls to the +fchmodat system call, run the following command: +$ sudo grep "fchmodat" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. -root /sbin/auditctl -root /sbin/aureport -root /sbin/ausearch -root /sbin/autrace -root /sbin/auditd -root /sbin/rsyslogd -root /sbin/augenrules - Is it the case that any audit tools are not group-owned by root? - - - - Verify the audit tools are owned by "root" to prevent any unauthorized access, deletion, or modification. - -Check the owner of each audit tool by running the following command: - -$ sudo stat -c "%U %n" /sbin/auditctl /sbin/aureport /sbin/ausearch /sbin/autrace /sbin/auditd /sbin/rsyslogd /sbin/augenrules - -root /sbin/auditctl -root /sbin/aureport -root /sbin/ausearch -root /sbin/autrace -root /sbin/auditd -root /sbin/rsyslogd -root /sbin/augenrules - Is it the case that any audit tools are not owned by root? - - - - Verify the audit tools are protected from unauthorized access, deletion, or modification by checking the permissive mode. - -Check the octal permission of each audit tool by running the following command: - -$ sudo stat -c "%U %n" /sbin/auditctl /sbin/aureport /sbin/ausearch /sbin/autrace /sbin/auditd /sbin/rsyslogd /sbin/augenrules - Is it the case that any of these files have more permissive permissions than 0755? - - - - Run the following command to determine if the aide package is installed: $ rpm -q aide - Is it the case that the package is not installed? - - - - The following command will list which files on the system -have file hashes different from what is expected by the RPM database. -$ rpm -Va --noconfig | awk '$1 ~ /..5/ && $2 != "c"' - Is it the case that there is output? - - - - The following command will list which files on the system have ownership different from what -is expected by the RPM database: -$ rpm -Va | rpm -Va --nofiledigest | awk '{ if (substr($0,6,1)=="U" || substr($0,7,1)=="G") print $NF }' - Is it the case that there is output? - - - - The following command will list which files on the system have permissions different from what -is expected by the RPM database: -$ rpm -Va | awk '{ if (substr($0,2,1)=="M") print $NF }' - Is it the case that there is output? - - - - Run the following command to determine if the sudo package is installed: $ rpm -q sudo - Is it the case that the package is not installed? - - - - To determine if NOEXEC has been configured for sudo, run the following command: -$ sudo grep -ri "^[\s]*Defaults.*\bnoexec\b.*" /etc/sudoers /etc/sudoers.d/ -The command should return a matching output. - Is it the case that noexec is not enabled in sudo? - - - - To determine if requiretty has been configured for sudo, run the following command: -$ sudo grep -ri "^[\s]*Defaults.*\brequiretty\b.*" /etc/sudoers /etc/sudoers.d/ -The command should return a matching output. - Is it the case that requiretty is not enabled in sudo? - - - - To determine if use_pty has been configured for sudo, run the following command: -$ sudo grep -ri "^[\s]*Defaults.*\buse_pty\b.*" /etc/sudoers /etc/sudoers.d/ -The command should return a matching output. - Is it the case that use_pty is not enabled in sudo? - - - - To determine if logfile has been configured for sudo, run the following command: -$ sudo grep -ri "^[\s]*Defaults\s*\blogfile\b.*" /etc/sudoers /etc/sudoers.d/ -The command should return a matching output. - Is it the case that logfile is not enabled in sudo? - - - - To determine if !authenticate has not been configured for sudo, run the following command: -$ sudo grep -r \!authenticate /etc/sudoers /etc/sudoers.d/ -The command should return no output. - Is it the case that !authenticate is specified in the sudo config files? - - - - To determine if NOPASSWD has been configured for sudo, run the following command: -$ sudo grep -ri nopasswd /etc/sudoers /etc/sudoers.d/ -The command should return no output. - Is it the case that nopasswd is specified in the sudo config files? - - - - To determine if NOPASSWD or !authenticate have been configured for -sudo, run the following command: -$ sudo grep -ri "nopasswd\|\!authenticate" /etc/sudoers /etc/sudoers.d/ -The command should return no output. - Is it the case that nopasswd and/or !authenticate is enabled in sudo? - - - - Verify the operating system requires re-authentication -when using the "sudo" command to elevate privileges, run the following command: -sudo grep -ri '^Defaults.*timestamp_timeout' /etc/sudoers /etc/sudoers.d -The output should be: -/etc/sudoers:Defaults timestamp_timeout=0 or "timestamp_timeout" is set to a positive number. -If conflicting results are returned, this is a finding. - Is it the case that timestamp_timeout is not set with the appropriate value for sudo? - - - - Determine if "sudoers" file restricts sudo access run the following commands: -$ sudo grep -PR '^\s*ALL\s+ALL\=\(ALL\)\s+ALL\s*$' /etc/sudoers /etc/sudoers.d/* -$ sudo grep -PR '^\s*ALL\s+ALL\=\(ALL\:ALL\)\s+ALL\s*$' /etc/sudoers /etc/sudoers.d/* - Is it the case that either of the commands returned a line? - - - - To determine if NOPASSWD has been configured for the vdsm user for sudo, -run the following command: -$ sudo grep -ri nopasswd /etc/sudoers.d/ -The command should return output only for the vdsm user. - Is it the case that nopasswd is set for any users beyond vdsm? - - - - To determine if arguments that commands can be executed with are restricted, run the following command: -$ sudo grep -PR '^(?:\s*[^#=]+)=(?:\s*(?:\([^\)]+\))?\s*(?!\s*\()[^,\s]+(?:[ \t]+[^,\s]+)+[ \t]*,)*(\s*(?:\([^\)]+\))?\s*(?!\s*\()[^,\s]+[ \t]*(?:,|$))' /etc/sudoers /etc/sudoers.d/ -The command should return no output. - Is it the case that /etc/sudoers file contains user specifications that allow execution of commands with any arguments? - - - - To determine if negation is used to define commands users are allowed to execute using sudo, run the following command: + Is it the case that no line is returned? + + + + To determine if negation is used to define commands users are allowed to execute using sudo, run the following command: $ sudo grep -PR '^(?:\s*[^#=]+)=(?:\s*(?:\([^\)]+\))?\s*(?!\s*\()[^,!\n][^,\n]+,)*\s*(?:\([^\)]+\))?\s*(?!\s*\()(!\S+).*' /etc/sudoers /etc/sudoers.d/ The command should return no output. Is it the case that /etc/sudoers file contains rules that define the set of allowed commands using negation? - - - - To determine if the users are allowed to run commands as root, run the following commands: -$ sudo grep -PR '^\s*((?!root\b)[\w]+)\s*(\w+)\s*=\s*(.*,)?\s*[^\(\s]' /etc/sudoers /etc/sudoers.d/ -and -$ sudo grep -PR '^\s*((?!root\b)[\w]+)\s*(\w+)\s*=\s*(.*,)?\s*\([\w\s]*\b(root|ALL)\b[\w\s]*\)' /etc/sudoers /etc/sudoers.d/ -Both commands should return no output. - Is it the case that /etc/sudoers file contains rules that allow non-root users to run commands as root? - - - - Run the following command to Verify that the sudoers security policy is configured to use the invoking user's password for privilege escalation: - sudo cvtsudoers -f sudoers /etc/sudoers | grep -E '^Defaults !?(rootpw|targetpw|runaspw)' -or if cvtsudoers not supported: - sudo find /etc/sudoers /etc/sudoers.d \( \! -name '*~' -a \! -name '*.*' \) -exec grep -E --with-filename '^[[:blank:]]*Defaults[[:blank:]](.*[[:blank:]])?!?\b(rootpw|targetpw|runaspw)' -- {} \; -If no results are returned, this is a finding. -If conflicting results are returned, this is a finding. -If "Defaults !targetpw" is not defined, this is a finding. -If "Defaults !rootpw" is not defined, this is a finding. -If "Defaults !runaspw" is not defined, this is a finding. - Is it the case that invoke user passwd when using sudo? - - - - Run the following command to determine if the gnutls-utils package is installed: $ rpm -q gnutls-utils - Is it the case that the package is not installed? - - - - Run the following command to determine if the gssproxy package is installed: -$ rpm -q gssproxy - Is it the case that the package is installed? - - - - Run the following command to determine if the iprutils package is installed: + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_SLUB_DEBUG /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + Inspect /etc/default/grub for any instances of +systemd.confirm_spawn=(1|yes|true|on) in the kernel boot arguments. +Presence of a systemd.confirm_spawn=(1|yes|true|on) indicates +that interactive boot is enabled at boot time and verify that +GRUB_DISABLE_RECOVERY=true to disable recovery boot. + Is it the case that Interactive boot is enabled at boot time? + + + + To check the permissions of /boot/grub2/user.cfg, +run the command: +$ ls -l /boot/grub2/user.cfg +If properly configured, the output should indicate the following permissions: +-rw------- + Is it the case that /boot/grub2/user.cfg does not have unix mode -rw-------? + + + + To check the permissions of /etc/shadow, +run the command: +$ ls -l /etc/shadow +If properly configured, the output should indicate the following permissions: +---------- + Is it the case that /etc/shadow does not have unix mode ----------? + + + + To verify that the Audit is correctly configured according to recommended rules, check the content of the file with the following command: +cat /etc/audit/rules.d/30-ospp-v42-4-delete-success.rules +The output has to be exactly as follows: +## Successful file delete +-a always,exit -F arch=b32 -S unlink,unlinkat,rename,renameat -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-delete +-a always,exit -F arch=b64 -S unlink,unlinkat,rename,renameat -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-delete + Is it the case that the file does not exist or the content differs? + + + + Run the following command to determine if the iprutils package is installed: $ rpm -q iprutils Is it the case that the package is installed? - - - - Run the following command to determine if the krb5-workstation package is installed: -$ rpm -q krb5-workstation + + + + The runtime status of the kernel.perf_event_max_sample_rate kernel parameter can be queried +by running the following command: +$ sysctl kernel.perf_event_max_sample_rate +1. + + Is it the case that the correct value is not returned? + + + + Verify that Oracle Linux 9 loads the driver with the following command: + +$ grep card_drivers /etc/opensc.conf + +card_drivers = ; + Is it the case that "<sub idref="var_smartcard_drivers" />" is not listed as a card driver, or there is no line returned for "card_drivers"? + + + + The runtime status of the net.ipv4.conf.all.accept_source_route kernel parameter can be queried +by running the following command: +$ sysctl net.ipv4.conf.all.accept_source_route +0. + + Is it the case that the correct value is not returned? + + + + Verify that Oracle Linux 9 's INACTIVE conforms to site policy (no more than 30 days) with the following command: + +$ sudo awk -F: '$7 > 30 {print $1 " " $7}' /etc/shadow + Is it the case that the value of INACTIVE is greater than the expected value or is -1? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_DEBUG_FS /boot/config.* + + Configs with value 'n' are not explicitly set in the file, so either commented lines or no + lines should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To check the ownership of /boot/grub2/grub.cfg, +run the command: +$ ls -lL /boot/grub2/grub.cfg +If properly configured, the output should indicate the following owner: +root + Is it the case that /boot/grub2/grub.cfg does not have an owner of root? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "restorecon" command with the following command: + +$ sudo auditctl -l | grep restorecon + +-a always,exit -F path=/usr/sbin/restorecon -F perm=x -F auid>=1000 -F auid!=unset -k privileged-restorecon + Is it the case that the command does not return a line, or the line is commented out? + + + + Verify Oracle Linux 9 generates an audit record for unsuccessful attempts to use the ftruncate system call. + +If the auditd daemon is configured to use the "augenrules" program to to read audit rules during daemon startup (the default), run the following command: + +$ sudo grep -r ftruncate /etc/audit/rules.d + +If the auditd daemon is configured to use the "auditctl" utility to read audit rules during daemon startup, run the following command: + +$ sudo grep ftruncate /etc/audit/audit.rules + +The output should be the following: + +-a always,exit -F arch=b32 -S ftruncate -F exit=-EPERM -F auid>=1000 -F auid!=unset -k access +-a always,exit -F arch=b64 -S ftruncate -F exit=-EPERM -F auid>=1000 -F auid!=unset -k access +-a always,exit -F arch=b32 -S ftruncate -F exit=-EACCES -F auid>=1000 -F auid!=unset -k access +-a always,exit -F arch=b64 -S ftruncate -F exit=-EACCES -F auid>=1000 -F auid!=unset -k access + Is it the case that the command does not return a line, or the line is commented out? + + + + Run the following command to determine if the setroubleshoot-plugins package is installed: +$ rpm -q setroubleshoot-plugins Is it the case that the package is installed? - - - - Run the following command to determine if the nss-tools package is installed: $ rpm -q nss-tools - Is it the case that the package is not installed? - - - - Run the following command to determine if the openscap-scanner package is installed: $ rpm -q openscap-scanner - Is it the case that the package is not installed? - - - - Run the following command to determine if the rear package is installed: $ rpm -q rear - Is it the case that the package is not installed? - - - - Run the following command to determine if the rng-tools package is installed: $ rpm -q rng-tools - Is it the case that the package is not installed? - - - - Run the following command to determine if the scap-security-guide package is installed: $ rpm -q scap-security-guide - Is it the case that the package is not installed? - - - - Run the following command to determine if the tuned package is installed: -$ rpm -q tuned - Is it the case that the package is installed? - - - - Verify Oracle Linux 9 removes all software components after updated versions have been installed. + + + + +If the system is configured to prevent the loading of the dccp kernel module, +it will contain lines inside any file in /etc/modprobe.d or the deprecated /etc/modprobe.conf. +These lines instruct the module loading system to run another program (such as /bin/false) upon a module install event. + +These lines can also instruct the module loading system to ignore the dccp kernel module via blacklist keyword. + +Run the following command to search for such lines in all files in /etc/modprobe.d and the deprecated /etc/modprobe.conf: +$ grep -r dccp /etc/modprobe.conf /etc/modprobe.d + Is it the case that no line is returned? + + + + Verify all local interactive users on Oracle Linux 9 are assigned a home +directory upon creation with the following command: +$ grep -i create_home /etc/login.defs +CREATE_HOME yes + Is it the case that the value for "CREATE_HOME" parameter is not set to "yes", the line is missing, or the line is commented out? + + + + To ensure the MaxAuthTries parameter is set, run the following command: +$ sudo grep MaxAuthTries /etc/ssh/sshd_config +If properly configured, output should be: +MaxAuthTries + Is it the case that it is commented out or not configured properly? + + + + Verify file systems that are used for removable media are mounted with the "nodev" option with the following command: + +$ sudo more /etc/fstab + +UUID=2bc871e4-e2a3-4f29-9ece-3be60c835222 /mnt/usbflash vfat noauto,owner,ro,nosuid,nodev,noexec 0 0 + Is it the case that a file system found in "/etc/fstab" refers to removable media and it does not have the "nodev" option set? + + + + To verify the local initialization files of all local interactive users are group- +owned by the appropriate user, inspect the primary group of the respective +users in /etc/passwd and verify all initialization files under the +respective users home directory. Check the group owner of all local interactive users +initialization files. + Is it the case that they are not? + + + + To check the ownership of /etc/nftables, +run the command: +$ ls -lL /etc/nftables +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/nftables does not have an owner of root? + + + + To check the ownership of /etc/shadow-, +run the command: +$ ls -lL /etc/shadow- +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/shadow- does not have an owner of root? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_PAGE_POISONING_ZERO /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To check if pam_pwquality.so is enabled in system-auth, run the following command: +$ grep pam_pwquality /etc/pam.d/system-auth +The output should be similar to the following: +password requisite pam_pwquality.so + Is it the case that pam_pwquality.so is not enabled in system-auth? + + + + Verify Oracle Linux 9 is configured to limit the "pwquality" retry option to . -$ grep clean_requirements_on_remove /etc/yum.conf -clean_requirements_on_remove=1 - Is it the case that '"clean_requirements_on_remove" is not set to "1"'? - - - - To verify that packages comprising the available updates will be automatically installed by dnf-automatic, run the following command: -$ sudo grep apply_updates /etc/dnf/automatic.conf -The output should return the following: -apply_updates = yes - Is it the case that apply_updates is not set to yes? - - - - To verify that only security updates will be automatically installed by dnf-automatic, run the following command: -$ sudo grep upgrade_type /etc/dnf/automatic.conf -The output should return the following: -upgrade_type = security - Is it the case that the upgrade_type is not set to security? - - - - Verify that yum verifies the signature of packages from a repository prior to install with the following command: +Check for the use of the "pwquality" retry option in the pwquality.conf file with the following command: +$ grep retry /etc/security/pwquality.conf + Is it the case that the value of "retry" is set to "0" or greater than "<sub idref="var_password_pam_retry" />", or is missing? + + + + +Run the following command to determine if the authlogin_radius SELinux boolean is disabled: +$ getsebool authlogin_radius +If properly configured, the output should show the following: +authlogin_radius --> off + Is it the case that authlogin_radius is not disabled? + + + + To check the ownership of /etc/sysctl.d, +run the command: +$ ls -lL /etc/sysctl.d +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/sysctl.d does not have an owner of root? + + + + Verify the Oracle Linux 9 "fapolicyd" employs a deny-all, permit-by-exception policy. -$ grep gpgcheck /etc/yum.conf +Check that "fapolicyd" is in enforcement mode with the following command: -gpgcheck=1 +$ sudo grep permissive /etc/fapolicyd/fapolicyd.conf -If "gpgcheck" is not set to "1", or if the option is missing or commented out, ask the System Administrator how the certificates for patches and other operating system components are verified. - Is it the case that there is no process to validate certificates that is approved by the organization? - - - - Verify that yum verifies the signature of local packages prior to install with the following command: +permissive = 0 -$ grep localpkg_gpgcheck /etc/yum.conf +Check that fapolicyd employs a deny-all policy on system mounts with the following commands: +$ sudo tail /etc/fapolicyd/compiled.rules -localpkg_gpgcheck=1 +allow exe=/usr/bin/python3.7 : ftype=text/x-python +deny_audit perm=any pattern=ld_so : all +deny perm=any all : all + Is it the case that fapolicyd is not running in enforcement mode with a deny-all, permit-by-exception policy? + + + + Verify the nosuid option is configured for the /var/log mount point, + run the following command: + $ sudo mount | grep '\s/var/log\s' + . . . /var/log . . . nosuid . . . -If "localpkg_gpgcheck" is not set to "1", or if the option is missing or commented out, ask the System Administrator how the certificates for patches and other operating system components are verified. - Is it the case that there is no process to validate certificates for local packages that is approved by the organization? - - - - To determine whether yum has been configured to disable -gpgcheck for any repos, inspect all files in -/etc/yum.repos.d and ensure the following does not appear in any -sections: -gpgcheck=0 -A value of 0 indicates that gpgcheck has been disabled for that repo. - Is it the case that GPG checking is disabled? - - - - To ensure that the GPG key is installed, run: -$ rpm -q --queryformat "%{SUMMARY}\n" gpg-pubkey -The command should return the string below: -gpg(Oracle OSS group (Open Source Software group) <build@oss.oracle.com> - Is it the case that the Oracle GPG Key is not installed? - - - - Run the following command to determine if the dnf-automatic package is installed: $ rpm -q dnf-automatic - Is it the case that the package is not installed? - - - - Verify Oracle Linux 9 security patches and updates are installed and up to date. -Updates are required to be applied with a frequency determined by organizational policy. + Is it the case that the "/var/log" file system does not have the "nosuid" option set? + + + + Verify that a separate file system/partition has been created for /home with the following command: +$ mountpoint /home + Is it the case that "/home is not a mountpoint" is returned? + + + + To verify the sec option is configured for all NFS mounts, run the following command: +$ mount | grep "sec=" +All NFS mounts should show the sec=krb5:krb5i:krb5p setting in parentheses. +This is not applicable if NFS is not implemented. + Is it the case that the setting is not configured, has the 'sys' option added, or does not have all Kerberos options added? + + + + Inspect the form of default GRUB 2 command line for the Linux operating system +in /etc/default/grub. If it includes spec_store_bypass_disable=, +then the parameter will be configured for newly installed kernels. +First check if the GRUB recovery is enabled: +$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub +If this option is set to true, then check that a line is output by the following command: +$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*spec_store_bypass_disable=.*' /etc/default/grub +If the recovery is disabled, check the line with +$ sudo grep 'GRUB_CMDLINE_LINUX.*spec_store_bypass_disable=.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. +Run the following command: +$ sudo grubby --info=ALL | grep args | grep -v 'spec_store_bypass_disable=' +The command should not return any output. + Is it the case that SSB is not configured appropriately? + + + + The runtime status of the net.ipv4.conf.default.accept_redirects kernel parameter can be queried +by running the following command: +$ sysctl net.ipv4.conf.default.accept_redirects +0. -Typical update frequency may be overridden by Information Assurance Vulnerability Alert (IAVA) notifications from CYBERCOM. - Is it the case that Oracle Linux 9 is in non-compliance with the organizational patching policy? - - - - Run the following command to determine the current status of the dnf-automatic timer: $ sudo systemctl is-active dnf-automatic.timer If the timer is running, it should return the following: active - Is it the case that the dnf-automatic.timer is not enabled? - - - - To check if the installed Operating System is 64-bit, run the following command: -$ uname -m -The output should be one of the following: x86_64, aarch64, ppc64le or s390x. -If the output is i686 or i386 the operating system is 32-bit. -Check if the installed CPU supports 64-bit operating systems by running the following command: -$ lscpu | grep "CPU op-mode" -If the output contains 64bit, the CPU supports 64-bit operating systems. - Is it the case that the installed operating sytem is 32-bit but the CPU supports operation in 64-bit? - - - - - - - - - combine_ovals.py from SCAP Security Guide - ssg: [0, 1, 69], python: 3.9.16 - 5.11 - 2023-09-14T00:00:00 - - - - - Alibaba Cloud Linux 2 - - Oracle Linux 9 - - - The operating system installed on the system is Alibaba Cloud Linux 2 - - - - - - - - - Alibaba Cloud Linux 3 - - Oracle Linux 9 - - - The operating system installed on the system is Alibaba Cloud Linux 3 - - - - - - - - - Anolis OS 8 - - Oracle Linux 9 - - - The operating system installed on the system is Anolis OS 8 - - - - - - - - - Debian Linux 10 - - Oracle Linux 9 - - - The operating system installed on the system is Debian 10 - - - - - - - - - Debian Linux 11 - - Oracle Linux 9 - - - The operating system installed on the system is Debian 11 - - - - - - - - - openSUSE Leap 15 - - Oracle Linux 9 - - - The operating system installed on the system is openSUSE Leap 15. - - - - - - - - - openSUSE Leap 42 - - Oracle Linux 9 - - - - - The operating system installed on the system is openSUSE Leap 42. - - - - - - - - - Ubuntu 22.04 LTS - - Oracle Linux 9 - - - The operating system installed on the system is Ubuntu 22.04 LTS - - - - - - - - - UnionTech OS Server 20 - - Oracle Linux 9 - - - The operating system installed on the system is UnionTech OS Server 20 - - - - - - - - - Red Hat Virtualization 4 - - Oracle Linux 9 - - - The application installed installed on the system is - Red Hat Virtualization 4. - - - - - - - - - Package grub2 is installed - - Oracle Linux 9 - - Checks if package grub2-common is installed. - - - - - - - - - - - - - Package providing /etc/login.defs is installed - - Oracle Linux 9 - - Checks if package providing /etc/login.defs and is installed. - - - - - - - - - Check if the system doesn't act as an oVirt host or manager - - Oracle Linux 9 - - Check if the system has neither ovirt-host nor ovirt-engine installed. - - - - - - - - Check if the system acts as an oVirt host or manager - - Oracle Linux 9 - - Check if the system has ovirt-host or ovirt-engine installed - - - - - - - - - - WiFi interface is present - - Oracle Linux 9 - - Checks if any wifi interface is present. - - - - - - - - - Check if the scan target is a container - - Oracle Linux 9 - - Check for presence of files characterizing container filesystems. - - - - - - - - - - Check if the scan target is a machine - - Oracle Linux 9 - - Check for absence of files characterizing container filesystems. - - - - - - - - - Kerberos server is older than 1.17-18 - - Oracle Linux 9 - - - Check if version of Kerberos server is lesser than 1.17-18 - - - - - - - - - Kerberos workstation is older than 1.17-18 - - Oracle Linux 9 - - - Check if version of Kerberos workstation is lesser than 1.17-18 - - - - - - - - - Test that the architecture is aarch64 - - Oracle Linux 9 - - Check that architecture of kernel in /proc/sys/kernel/osrelease is aarch64 - - - - - - - - Test for different architecture than aarch64 - - Oracle Linux 9 - - Check that architecture of kernel in /proc/sys/kernel/osrelease is not aarch64 - - - - - - - - Test for different architecture than s390x - - Oracle Linux 9 - - Check that architecture of kernel in /proc/sys/kernel/osrelease is not s390x - - - - - - - - Test that the architecture is ppc64le - - Oracle Linux 9 - - Check that architecture of kernel in /proc/sys/kernel/osrelease is ppc64le - - - - - - - - Test that the architecture is s390x - - Oracle Linux 9 - - Check that architecture of kernel in /proc/sys/kernel/osrelease is s390x - - - - - - - - SSSD is configured to use LDAP - - Oracle Linux 9 - - Identification provider is not set to ad within /etc/sssd/sssd.conf - - - - - - - - - Non-UEFI system boot mode check - - Oracle Linux 9 - - Check if System boot mode is non-UEFI. - - - - - - - - - UEFI system boot mode check - - Oracle Linux 9 - - Check if system boot mode is UEFI. - - - - - - - - - Anolis OS 23 - - Oracle Linux 9 - - - The operating system installed on the system is Anolis OS 23 - - - - - - - - - CentOS 7 - - Oracle Linux 9 - - - The operating system installed on the system is - CentOS 7 - - - - - - - - - CentOS 8 - - Oracle Linux 9 - - - The operating system installed on the system is - CentOS 8 - - - - - - - - - - CentOS Stream 9 - - Oracle Linux 9 - - - The operating system installed on the system is - CentOS Stream 9 - - - - - - - - - - Debian - - Oracle Linux 9 - - The operating system installed is a Debian System - - - - - - - - - Installed operating system is Fedora - - Oracle Linux 9 - - - - - - - The operating system installed on the system is Fedora - - - - - - - - - - - - Oracle Linux 9 - - Installed OS is OL - - - - - - - - Oracle Linux 7 - - Oracle Linux 9 - - - The operating system installed on the system is - Oracle Linux 7 - - - - - - - - - - - Oracle Linux 8 - - Oracle Linux 9 - - - The operating system installed on the system is - Oracle Linux 8 - - - - - - - - - - - Oracle Linux 9 - - Oracle Linux 9 - - - The operating system installed on the system is - Oracle Linux 9 - - - - - - - - - - - openSUSE - - Oracle Linux 9 - - The operating system installed on the system is openSUSE. - - - - - - - - - Installed operating system is part of the Unix family - - Oracle Linux 9 - - The operating system installed on the system is part of the Unix OS family - - - - - - - - Red Hat Enterprise Linux CoreOS - - Oracle Linux 9 - - - The operating system installed on the system is - Red Hat Enterprise Linux CoreOS release 4 - - - - - - - - - - - Red Hat Enterprise Linux CoreOS RHEL9 Based - - Oracle Linux 9 - - - The operating system installed on the system is - Red Hat Enterprise Linux CoreOS RHEL9 Based - - - - - - - - - - Oracle Linux 9 - - Installed OS is RHEL - - - - - - - - Red Hat Enterprise Linux 7 - - Oracle Linux 9 - - - The operating system installed on the system is - Red Hat Enterprise Linux 7 - - - - - - - - - - - - - - - - - - Red Hat Enterprise Linux 8 - - Oracle Linux 9 - - - The operating system installed on the system is - Red Hat Enterprise Linux 8 - - - - - - - - - - - - - - - Red Hat Enterprise Linux 8.0 - - Oracle Linux 9 - - - The operating system installed on the system is Red Hat Enterprise Linux 8.0 - - - - - - - - Red Hat Enterprise Linux 8.1 - - Oracle Linux 9 - - - The operating system installed on the system is Red Hat Enterprise Linux 8.1 - - - - - - - - Red Hat Enterprise Linux 8.2 - - Oracle Linux 9 - - - The operating system installed on the system is Red Hat Enterprise Linux 8.2 - - - - - - - - Red Hat Enterprise Linux 8.3 - - Oracle Linux 9 - - - The operating system installed on the system is Red Hat Enterprise Linux 8.3 - - - - - - - - Red Hat Enterprise Linux 8.4 - - Oracle Linux 9 - - - The operating system installed on the system is Red Hat Enterprise Linux 8.4 - - - - - - - - Red Hat Enterprise Linux 8.5 - - Oracle Linux 9 - - - The operating system installed on the system is Red Hat Enterprise Linux 8.5 - - - - - - - - Red Hat Enterprise Linux 8.6 - - Oracle Linux 9 - - - The operating system installed on the system is Red Hat Enterprise Linux 8.6 - - - - - - - - Red Hat Enterprise Linux 8.7 - - Oracle Linux 9 - - - The operating system installed on the system is Red Hat Enterprise Linux 8.7 - - - - - - - - Red Hat Enterprise Linux 8.8 - - Oracle Linux 9 - - - The operating system installed on the system is Red Hat Enterprise Linux 8.8 - - - - - - - - Red Hat Enterprise Linux 8.9 - - Oracle Linux 9 - - - The operating system installed on the system is Red Hat Enterprise Linux 8.9 - - - - - - - - Red Hat Enterprise Linux 8.10 - - Oracle Linux 9 - - - The operating system installed on the system is Red Hat Enterprise Linux 8.10 - - - - - - - - Red Hat Enterprise Linux 9 - - Oracle Linux 9 - - - The operating system installed on the system is - Red Hat Enterprise Linux 9 - - - - - - - - - - - - - - - Red Hat Virtualization 4 - - Oracle Linux 9 - - - The operating system installed on the system is - Red Hat Virtualization Host 4.4+ or Red Hat Enterprise Host. - - - - - - - - - Scientific Linux 7 - - Oracle Linux 9 - - - The operating system installed on the system is - Scientific Linux 7 - - - - - - - - - SUSE Linux Enterprise 12 - - Oracle Linux 9 - - - - The operating system installed on the system is - SUSE Linux Enterprise 12. - - - - - - - - - - - - - SUSE Linux Enterprise 15 - - Oracle Linux 9 - - - - The operating system installed on the system is - SUSE Linux Enterprise 15. - - - - - - - - - - - - - - - Ubuntu - - Oracle Linux 9 - - The operating system installed is an Ubuntu System - - - - - - - - - - Ubuntu 16.04 LTS - - Oracle Linux 9 - - - The operating system installed on the system is Ubuntu 16.04 LTS - - - - - - - - - Ubuntu 18.04 LTS - - Oracle Linux 9 - - - The operating system installed on the system is Ubuntu 18.04 LTS - - - - - - - - - Ubuntu 20.04 LTS - - Oracle Linux 9 - - - The operating system installed on the system is Ubuntu 20.04 LTS - - - - - - - - - System uses zIPL - - Oracle Linux 9 - - Checks if system uses zIPL bootloader. - - - - - - - - - Check if the environment is a OSBuild pipeline - - Oracle Linux 9 - - Check the value of environment variable container. - - - - - - - - - IPv6 is enabled on system - - Oracle Linux 9 - - - - - - - - - - - Mountpoint /home is active (mounted) or configured in /etc/fstab - - Oracle Linux 9 - - - - - - - - - - - - - - - Mountpoint /opt is active (mounted) or configured in /etc/fstab - - Oracle Linux 9 - - - - - - - - - - - - - - - Mountpoint /srv is active (mounted) or configured in /etc/fstab - - Oracle Linux 9 - - - - - - - - - - - - - - - Mountpoint /tmp is active (mounted) or configured in /etc/fstab - - Oracle Linux 9 - - - - - - - - - - - - - - - Mountpoint /var/log/audit is active (mounted) or configured in /etc/fstab - - Oracle Linux 9 - - - - - - - - - - - - - - - Mountpoint /var/log is active (mounted) or configured in /etc/fstab - - Oracle Linux 9 - - - - - - - - - - - - - - - Mountpoint /var/tmp is active (mounted) or configured in /etc/fstab - - Oracle Linux 9 - - - - - - - - - - - - - - - Mountpoint /var is active (mounted) or configured in /etc/fstab - - Oracle Linux 9 - - - - - - - - - - - - - - - Operating System is ol - - Oracle Linux 9 - - The installed operating system is Oracle Linux - - - - - - - - - Operating System is rhel - - Oracle Linux 9 - - The installed operating system is Red Hat Enterprise Linux - - - - - - - - - Operating System is rhel - - Oracle Linux 9 - - The installed operating system is Red Hat Enterprise Linux - - - - - - - - - Package audit is installed - - Oracle Linux 9 - - The RPM package audit should be installed. - - - - - - - - Package chrony is installed - - Oracle Linux 9 - - The RPM package chrony should be installed. - - - - - - - - Package firewalld is installed - - Oracle Linux 9 - - The RPM package firewalld should be installed. - - - - - - - - Package gdm is installed - - Oracle Linux 9 - - The RPM package gdm should be installed. - - - - - - - - Package iptables is installed - - Oracle Linux 9 - - The RPM package iptables should be installed. - - - - - - - - Package libuser is installed - - Oracle Linux 9 - - The RPM package libuser should be installed. - - - - - - - - Package nftables is installed - - Oracle Linux 9 - - The RPM package nftables should be installed. - - - - - - - - Package ntp is installed - - Oracle Linux 9 - - The RPM package ntp should be installed. - - - - - - - - Package pam is installed - - Oracle Linux 9 - - The RPM package pam should be installed. - - - - - - - - Package postfix is installed - - Oracle Linux 9 - - The RPM package postfix should be installed. - - - - - - - - Package shadow-utils is installed - - Oracle Linux 9 - - The RPM package shadow-utils should be installed. - - - - - - - - Package sssd-common is installed - - Oracle Linux 9 - - The RPM package sssd-common should be installed. - - - - - - - - Package sudo is installed - - Oracle Linux 9 - - The RPM package sudo should be installed. - - - - - - - - Package systemd is installed - - Oracle Linux 9 - - The RPM package systemd should be installed. - - - - - - - - Package tftp-server is installed - - Oracle Linux 9 - - The RPM package tftp-server should be installed. - - - - - - - - Package tmux is installed - - Oracle Linux 9 - - The RPM package tmux should be installed. - - - - - - - - Package ufw is installed - - Oracle Linux 9 - - The RPM package ufw should be installed. - - - - - - - - Package usbguard is installed - - Oracle Linux 9 - - The RPM package usbguard should be installed. - - - - - - - - Package yum is installed - - Oracle Linux 9 - - The RPM package yum should be installed. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - alinux-release - - - alinux-release - - - anolis-release - - - /etc/debian_version - ^10.[0-9]+$ - 1 - - - /etc/debian_version - ^11.[0-9]+$ - 1 - - - openSUSE-release - - - openSUSE-release - - - /etc/lsb-release - ^DISTRIB_CODENAME=jammy$ - 1 - - - uos-release - - - rhvm-appliance - - - grub2-common - - - /sys/firmware/opal - - - shadow-utils - - - ovirt-host - - - ovirt-engine - - - /proc/net/wireless - - - /.dockerenv - - - /run/.containerenv - - - krb5-server - - - krb5-workstation - - - /proc/sys/kernel/osrelease - ^.*\.(.*)$ - 1 - - - /proc/sys/kernel/osrelease - ^.*\.(.*)$ - 1 - - - /proc/sys/kernel/osrelease - ^.*\.(.*)$ - 1 - - - /etc/sssd/sssd.conf - ^[\s]*\[domain\/[^]]*]([^\n\[\]]*\n+)+?[\s]*id_provider[ \t]*=[ \t]*((?i)ad)[ \t]*$ - 1 - - - /sys/firmware/efi - - - - anolis-release - - - centos-release - - - /etc/os-release - ^ID="(\w+)"$ - 1 - - - /etc/os-release - ^VERSION_ID="(\d)"$ - 1 - - - /etc/os-release - ^ID="(\w+)"$ - 1 - - - /etc/os-release - ^VERSION_ID="(\d)"$ - 1 - - - /etc/debian_version - - - fedora-release.* - - - /etc/system-release-cpe - ^cpe:\/o:fedoraproject:fedora:[\d]+$ - 1 - - - /etc/os-release - ^ID=["']?(\w+)["']?$ - 1 - - - oraclelinux-release - - - oraclelinux-release - - - oraclelinux-release - - - openSUSE-release - - - - /etc/os-release - ^ID="(\w+)"$ - 1 - - - /etc/os-release - ^VERSION_ID="(\d)\.\d+"$ - 1 - - - /etc/os-release - ^RHEL_VERSION="(\d).*"$ - 1 - - - /etc/os-release - ^ID=["']?(\w+)["']?$ - 1 - - - - redhat-release-client - - - redhat-release-workstation - - - redhat-release-server - - - redhat-release-computenode - - - /etc/redhat-release - ^Red Hat Enterprise Linux release (\d)\.\d+$ - 1 - - - - redhat-release - - - redhat-release - - - redhat-release - - - redhat-release - - - redhat-release - - - redhat-release - - - redhat-release - - - redhat-release - - - redhat-release - - - redhat-release - - - redhat-release - - - redhat-release - - - /etc/redhat-release - ^Red Hat Enterprise Linux release (\d)\.\d+$ - 1 - - - - redhat-release - - - /etc/redhat-release - ^Red Hat Enterprise Linux release (\d)\.\d+$ - 1 - - - redhat-release-virtualization-host - - - sl-release - - - - sled-release - - - sles-release - - - SLES_SAP-release - - - - sled-release - - - sles-release - - - SLES_SAP-release - - - SUSE-Manager-Server-release - - - SLE_HPC-release - - - /etc/lsb-release - - - /etc/lsb-release - ^DISTRIB_ID=Ubuntu$ - 1 - - - /etc/lsb-release - ^DISTRIB_CODENAME=xenial$ - 1 - - - /etc/lsb-release - ^DISTRIB_CODENAME=bionic$ - 1 - - - /etc/lsb-release - ^DISTRIB_CODENAME=focal$ - 1 - - - s390utils-base - - - - container - - - - /etc/default/grub - ^\s*GRUB_CMDLINE_LINUX=".*ipv6\.disable=(\d).*$ - 1 - - - /home - - - /etc/fstab - ^[\s]*[\S]+[\s]+/home[\s]+[\S]+[\s]+([\S]+) - 1 - - - /opt - - - /etc/fstab - ^[\s]*[\S]+[\s]+/opt[\s]+[\S]+[\s]+([\S]+) - 1 - - - /srv - - - /etc/fstab - ^[\s]*[\S]+[\s]+/srv[\s]+[\S]+[\s]+([\S]+) - 1 - - - /tmp - - - /etc/fstab - ^[\s]*[\S]+[\s]+/tmp[\s]+[\S]+[\s]+([\S]+) - 1 - - - /var/log/audit - - - /etc/fstab - ^[\s]*[\S]+[\s]+/var/log/audit[\s]+[\S]+[\s]+([\S]+) - 1 - - - /var/log - - - /etc/fstab - ^[\s]*[\S]+[\s]+/var/log[\s]+[\S]+[\s]+([\S]+) - 1 - - - /var/tmp - - - /etc/fstab - ^[\s]*[\S]+[\s]+/var/tmp[\s]+[\S]+[\s]+([\S]+) - 1 - - - /var - - - /etc/fstab - ^[\s]*[\S]+[\s]+/var[\s]+[\S]+[\s]+([\S]+) - 1 - - - /etc/os-release - ^ID=["']?(\w+)["']?$ - 1 - - - /etc/os-release - ^VERSION_ID=["']?([\w.]+)["']?$ - 1 - - - /etc/os-release - ^ID=["']?(\w+)["']?$ - 1 - - - /etc/os-release - ^VERSION_ID=["']?([\w.]+)["']?$ - 1 - - - /etc/os-release - ^ID=["']?(\w+)["']?$ - 1 - - - /etc/os-release - ^VERSION_ID=["']?([\w.]+)["']?$ - 1 - - - audit - - - chrony - - - firewalld - - - gdm - - - iptables - - - libuser - - - nftables - - - ntp - - - pam - - - postfix - - - shadow-utils - - - sssd-common - - - sudo - - - systemd - - - tftp-server - - - tmux - - - ufw - - - usbguard - - - yum - - - - - ^2.*$ - - - ^3.*$ - - - ^8.*$ - - - ^15.*$ - - - ^42.*$ - - - ^20.*$ - - - ^4.*$ - - - 0:1.17-18 - - - 0:1.17-18 - - - ^aarch64$ - - - ^ppc64le$ - - - ^s390x$ - - - ^23.*$ - - - ^7.*$ - - - centos - - - 8 - - - centos - - - 9 - - - ol - - - ^7.*$ - - - ^8.*$ - - - ^9.*$ - - - openSUSE-release - - - unix - - - rhcos - - - 4 - - - 9 - - - rhel - - - unix - - - ^7.*$ - - - ^7.*$ - - - ^7.*$ - - - ^7.*$ - - - 7 - - - unix - - - ^8.*$ - - - ^8.0*$ - - - ^8.1*$ - - - ^8.2*$ - - - ^8.3*$ - - - ^8.4*$ - - - ^8.5*$ - - - ^8.6*$ - - - ^8.7*$ - - - ^8.8*$ - - - ^8.9*$ - - - ^8.10*$ - - - 8 - - - unix - - - ^9.*$ - - - 9 - - - 0:4.4 - - - ^7.*$ - - - unix - - - ^12.*$ - - - ^12.*$ - - - ^12.*$ - - - unix - - - ^15.*$ - - - ^15.*$ - - - ^15.*$ - - - ^4.*$ - - - ^15.*$ - - - bwrap-osbuild - - - ppc64le - - - 0 - - - ol - - - 9.0 - - - rhel - - - 9.0 - - - rhel - - - 8.4 - - - - - \ No newline at end of file + Is it the case that the correct value is not returned? + + + + To verify that auditing of privileged command use is configured, run the +following command: +$ sudo grep usernetctl /etc/audit/audit.rules /etc/audit/rules.d/* +It should return a relevant line in the audit rules. + Is it the case that the command does not return a line, or the line is commented out? + + + + Verify the operating system is not configured to bypass password requirements for privilege +escalation. Check the configuration of the "/etc/pam.d/sudo" file with the following command: +$ sudo grep pam_succeed_if /etc/pam.d/sudo + Is it the case that system is configured to bypass password requirements for privilege escalation? + + + + To check the ownership of /etc/ssh/*.pub, +run the command: +$ ls -lL /etc/ssh/*.pub +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/ssh/*.pub does not have an owner of root? + + + + + + + + + build_cpe.py from SCAP Security Guide + ssg: [0, 1, 76], python: 3.9.21 + 5.11 + 2025-05-06T00:00:00 + + + + + + + Oracle Linux 9 + + Bootable container or bootc system + + + + + + + + + + + Package grub2 is installed + + Oracle Linux 9 + + + Checks if package grub2-common is installed. + + + + + + + + + + + + WiFi interface is present + + Oracle Linux 9 + + + Checks if any wifi interface is present. + + + + + + + + Check if the scan target is a container + + Oracle Linux 9 + + + Check for presence of files characterizing container filesystems. + + + + + + + + + Check if the scan target is a machine + + Oracle Linux 9 + + + Check for absence of files characterizing container filesystems. + + + + + + + + Remote NFS file system mount is defined + + Oracle Linux 9 + + + At least one remote NFS file system mount is defined in /etc/fstab + + + + + + + + Test that the architecture is aarch64 + + Oracle Linux 9 + + Check that architecture of kernel in /proc/sys/kernel is aarch64 + + + + + + + + Test for different architecture than s390x + + Oracle Linux 9 + + Check that architecture of kernel in /proc/sys/kernel/osrelease is not s390x + + + + + + + + Test that the architecture is ppc64le + + Oracle Linux 9 + + Check that architecture of kernel in /proc/sys/kernel is ppc64le + + + + + + + + Test that the architecture is s390x + + Oracle Linux 9 + + Check that architecture of kernel in /proc/sys/kernel is s390x + + + + + + + + Test that the architecture is x86_64 + + Oracle Linux 9 + + Check that architecture of kernel in /proc/sys/kernel is x86_64 + + + + + + + + Running kernel has fips mode enabled + + Oracle Linux 9 + + + Check if sysctl crypto.fips_enabled = 1 + + + + + + + + SELinux status check + + Oracle Linux 9 + + + Check if System has SELinux enabled. + + + + + + + + + SSSD is configured to use LDAP + + Oracle Linux 9 + + + Identification provider is not set to ad within /etc/sssd/sssd.conf + + + + + + + + Non-UEFI system boot mode check + + Oracle Linux 9 + + + Check if System boot mode is non-UEFI. + + + + + + + + UEFI system boot mode check + + Oracle Linux 9 + + + Check if system boot mode is UEFI. + + + + + + + + + + Oracle Linux 9 + + The kernel is installed + + + + + + + + + Oracle Linux 9 + + Oracle Linux 9 + + + The operating system installed on the system is + Oracle Linux 9 + + + + + + + + + + + Installed operating system is part of the Unix family + + Oracle Linux 9 + + The operating system installed on the system is part of the Unix OS family + + + + + + + + Check if the environment is a OSBuild pipeline + + Oracle Linux 9 + + + Check the value of environment variable container. + + + + + + + + IPv6 is enabled on system + + Oracle Linux 9 + + + + + + + + + + + Mountpoint /home is active (mounted) or configured in /etc/fstab + + Oracle Linux 9 + + + + + + + + + + + + + + + Mountpoint /opt is active (mounted) or configured in /etc/fstab + + Oracle Linux 9 + + + + + + + + + + + + + + + Mountpoint /srv is active (mounted) or configured in /etc/fstab + + Oracle Linux 9 + + + + + + + + + + + + + + + Mountpoint /tmp is active (mounted) or configured in /etc/fstab + + Oracle Linux 9 + + + + + + + + + + + + + + + Mountpoint /var/log/audit is active (mounted) or configured in /etc/fstab + + Oracle Linux 9 + + + + + + + + + + + + + + + Mountpoint /var/log is active (mounted) or configured in /etc/fstab + + Oracle Linux 9 + + + + + + + + + + + + + + + Mountpoint /var/tmp is active (mounted) or configured in /etc/fstab + + Oracle Linux 9 + + + + + + + + + + + + + + + Mountpoint /var is active (mounted) or configured in /etc/fstab + + Oracle Linux 9 + + + + + + + + + + + + + + + Operating System is ol + + Oracle Linux 9 + + The installed operating system is Oracle Linux + + + + + + + + + Operating System is ol + + Oracle Linux 9 + + The installed operating system is Oracle Linux + + + + + + + + + Operating System is ol + + Oracle Linux 9 + + The installed operating system is Oracle Linux + + + + + + + + + Operating System is rhel + + Oracle Linux 9 + + The installed operating system is Red Hat Enterprise Linux + + + + + + + + + Operating System is rhel + + Oracle Linux 9 + + The installed operating system is Red Hat Enterprise Linux + + + + + + + + + Operating System is rhel + + Oracle Linux 9 + + The installed operating system is Red Hat Enterprise Linux + + + + + + + + + Operating System is rhel + + Oracle Linux 9 + + The installed operating system is Red Hat Enterprise Linux + + + + + + + + + Package audit is installed + + Oracle Linux 9 + + The RPM package audit should be installed. + + + + + + + + Package autofs is installed + + Oracle Linux 9 + + The RPM package autofs should be installed. + + + + + + + + Package avahi is installed + + Oracle Linux 9 + + The RPM package avahi should be installed. + + + + + + + + Package bash is installed + + Oracle Linux 9 + + The RPM package bash should be installed. + + + + + + + + Package bind is installed + + Oracle Linux 9 + + The RPM package bind should be installed. + + + + + + + + Package chrony is installed + + Oracle Linux 9 + + The RPM package chrony should be installed. + + + + + + + + Package firewalld is installed + + Oracle Linux 9 + + The RPM package firewalld should be installed. + + + + + + + + Package gdm is installed + + Oracle Linux 9 + + The RPM package gdm should be installed. + + + + + + + + Package iptables is installed + + Oracle Linux 9 + + The RPM package iptables should be installed. + + + + + + + + Package libreswan is installed + + Oracle Linux 9 + + The RPM package libreswan should be installed. + + + + + + + + Package libuser is installed + + Oracle Linux 9 + + The RPM package libuser should be installed. + + + + + + + + Package logrotate is installed + + Oracle Linux 9 + + The RPM package logrotate should be installed. + + + + + + + + Package net-snmp is installed + + Oracle Linux 9 + + The RPM package net-snmp should be installed. + + + + + + + + Package NetworkManager is installed + + Oracle Linux 9 + + The RPM package NetworkManager should be installed. + + + + + + + + Package nftables is installed + + Oracle Linux 9 + + The RPM package nftables should be installed. + + + + + + + + Package ntp is installed + + Oracle Linux 9 + + The RPM package ntp should be installed. + + + + + + + + Package pam is installed + + Oracle Linux 9 + + The RPM package pam should be installed. + + + + + + + + Package polkit is installed + + Oracle Linux 9 + + The RPM package polkit should be installed. + + + + + + + + Package postfix is installed + + Oracle Linux 9 + + The RPM package postfix should be installed. + + + + + + + + Package rsh-server is installed + + Oracle Linux 9 + + The RPM package rsh-server should be installed. + + + + + + + + Package rsyslog is installed + + Oracle Linux 9 + + The RPM package rsyslog should be installed. + + + + + + + + Package shadow-utils is installed + + Oracle Linux 9 + + The RPM package shadow-utils should be installed. + + + + + + + + Package net-snmp is installed + + Oracle Linux 9 + + The RPM package net-snmp should be installed. + + + + + + + + Package squid is installed + + Oracle Linux 9 + + The RPM package squid should be installed. + + + + + + + + Package sssd-common is installed + + Oracle Linux 9 + + The RPM package sssd-common should be installed. + + + + + + + + Package sudo is installed + + Oracle Linux 9 + + The RPM package sudo should be installed. + + + + + + + + Package systemd is installed + + Oracle Linux 9 + + The RPM package systemd should be installed. + + + + + + + + Package telnet-server is installed + + Oracle Linux 9 + + The RPM package telnet-server should be installed. + + + + + + + + Package tftp-server is installed + + Oracle Linux 9 + + The RPM package tftp-server should be installed. + + + + + + + + Package ufw is installed + + Oracle Linux 9 + + The RPM package ufw should be installed. + + + + + + + + Package usbguard is installed + + Oracle Linux 9 + + The RPM package usbguard should be installed. + + + + + + + + Package yum is installed + + Oracle Linux 9 + + The RPM package yum should be installed. + + + + + + + + The firewalld is disabled on the system + + Oracle Linux 9 + + The firewalld service should be disabled. + + + + + + + + + + + + The iptables is disabled on the system + + Oracle Linux 9 + + The iptables service should be disabled. + + + + + + + + + + + + The ufw is disabled on the system + + Oracle Linux 9 + + The ufw service should be disabled. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + kernel + + + rpm-ostree + + + bootc + + + openshift-kubelet + + + grub2-common + + + /sys/firmware/opal + + + /proc/net/wireless + + + /.dockerenv + + + /run/.containerenv + + + /etc/fstab + ^\s*\[?[\.\w:-]+\]?[:=][/\w-]+\s+[/\w\\-]+\s+nfs[4]?\s+(.*)$ + 1 + + + /proc/sys/kernel/(osrelease|arch) + ^.*\.aarch64$|^aarch64$ + 1 + + + /proc/sys/kernel/(osrelease|arch) + ^.*\.ppc64le$|^ppc64le$ + 1 + + + /proc/sys/kernel/(osrelease|arch) + ^.*\.s390x$|^s390x$ + 1 + + + /proc/sys/kernel/(osrelease|arch) + ^.*\.x86_64$|^x86_64$ + 1 + + + crypto.fips_enabled + + + /etc/selinux/config + ^SELINUX=(.*)$ + 1 + + + /sys/fs/selinux + + + + /etc/sssd/sssd.conf + ^[\s]*\[domain\/[^]]*]([^\n\[\]]*\n+)+?[\s]*id_provider[ \t]*=[ \t]*((?i)ldap)[ \t]*$ + 1 + + + /sys/firmware/efi + + + + kernel + + + kernel-uek + + + oraclelinux-release + + + + + container + + + + /etc/default/grub + ^\s*GRUB_CMDLINE_LINUX=".*ipv6\.disable=(\d).*$ + 1 + + + /home + + + /etc/fstab + ^[\s]*[\S]+[\s]+/home[\s]+[\S]+[\s]+([\S]+) + 1 + + + /opt + + + /etc/fstab + ^[\s]*[\S]+[\s]+/opt[\s]+[\S]+[\s]+([\S]+) + 1 + + + /srv + + + /etc/fstab + ^[\s]*[\S]+[\s]+/srv[\s]+[\S]+[\s]+([\S]+) + 1 + + + /tmp + + + /etc/fstab + ^[\s]*[\S]+[\s]+/tmp[\s]+[\S]+[\s]+([\S]+) + 1 + + + /var/log/audit + + + /etc/fstab + ^[\s]*[\S]+[\s]+/var/log/audit[\s]+[\S]+[\s]+([\S]+) + 1 + + + /var/log + + + /etc/fstab + ^[\s]*[\S]+[\s]+/var/log[\s]+[\S]+[\s]+([\S]+) + 1 + + + /var/tmp + + + /etc/fstab + ^[\s]*[\S]+[\s]+/var/tmp[\s]+[\S]+[\s]+([\S]+) + 1 + + + /var + + + /etc/fstab + ^[\s]*[\S]+[\s]+/var[\s]+[\S]+[\s]+([\S]+) + 1 + + + /etc/os-release + ^ID=["']?(\w+)["']?$ + 1 + + + /etc/os-release + ^VERSION_ID=["']?([\w.]+)["']?$ + 1 + + + /etc/os-release + ^ID=["']?(\w+)["']?$ + 1 + + + /etc/os-release + ^VERSION_ID=["']?([\w.]+)["']?$ + 1 + + + /etc/os-release + ^ID=["']?(\w+)["']?$ + 1 + + + /etc/os-release + ^VERSION_ID=["']?([\w.]+)["']?$ + 1 + + + /etc/os-release + ^ID=["']?(\w+)["']?$ + 1 + + + /etc/os-release + ^VERSION_ID=["']?([\w.]+)["']?$ + 1 + + + /etc/os-release + ^ID=["']?(\w+)["']?$ + 1 + + + /etc/os-release + ^VERSION_ID=["']?([\w.]+)["']?$ + 1 + + + /etc/os-release + ^ID=["']?(\w+)["']?$ + 1 + + + /etc/os-release + ^VERSION_ID=["']?([\w.]+)["']?$ + 1 + + + /etc/os-release + ^ID=["']?(\w+)["']?$ + 1 + + + /etc/os-release + ^VERSION_ID=["']?([\w.]+)["']?$ + 1 + + + audit + + + autofs + + + avahi + + + bash + + + bind + + + chrony + + + firewalld + + + gdm + + + iptables + + + libreswan + + + libuser + + + logrotate + + + net-snmp + + + NetworkManager + + + nftables + + + ntp + + + pam + + + polkit + + + postfix + + + rsh-server + + + rsyslog + + + shadow-utils + + + net-snmp + + + squid + + + sssd-common + + + sudo + + + systemd + + + telnet-server + + + tftp-server + + + ufw + + + usbguard + + + yum + + + ^firewalld\.(service|socket)$ + ActiveState + + + ^firewalld\.(service|socket)$ + LoadState + + + firewalld + + + ^iptables\.(service|socket)$ + ActiveState + + + ^iptables\.(service|socket)$ + LoadState + + + iptables + + + ^ufw\.(service|socket)$ + ActiveState + + + ^ufw\.(service|socket)$ + LoadState + + + ufw + + + + + 1 + + + ^(enforcing|permissive)$ + + + ^9.*$ + + + unix + + + bwrap-osbuild + + + ppc64le + + + 0 + + + ol + + + 8.7 + + + ol + + + 9 + + + ol + + + 9.0 + + + rhel + + + 8.7 + + + rhel + + + 9.0 + + + rhel + + + 8.4 + + + rhel + + + 9.0 + + + inactive|failed + + + masked + + + inactive|failed + + + masked + + + inactive|failed + + + masked + + + + + From 82894d88b6d9ffa36715e8854225b4e30a1b1d39 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Thu, 7 Aug 2025 14:40:58 -0400 Subject: [PATCH 300/315] ecdsa instead of ed25519 --- salt/_runners/setup_hypervisor.py | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/salt/_runners/setup_hypervisor.py b/salt/_runners/setup_hypervisor.py index 9d7116d59..929801783 100644 --- a/salt/_runners/setup_hypervisor.py +++ b/salt/_runners/setup_hypervisor.py @@ -38,7 +38,7 @@ Examples: Notes: - Verifies Security Onion license - Downloads and validates Oracle Linux KVM image if needed - - Generates Ed25519 SSH keys if not present + - Generates ECDSA SSH keys if not present - Creates/recreates VM based on environment changes - Forces hypervisor configuration via highstate after successful setup (when minion_id provided) @@ -46,7 +46,7 @@ Examples: The setup process includes: 1. License validation 2. Oracle Linux KVM image download and checksum verification - 3. SSH key generation for secure VM access + 3. ECDSA SSH key generation for secure VM access 4. Cloud-init configuration for VM provisioning 5. VM creation with specified disk size 6. Hypervisor configuration via highstate (when minion_id provided and setup successful) @@ -74,7 +74,7 @@ import sys import time import yaml from cryptography.hazmat.primitives import serialization -from cryptography.hazmat.primitives.asymmetric import ed25519 +from cryptography.hazmat.primitives.asymmetric import ec # Configure logging log = logging.getLogger(__name__) log.setLevel(logging.DEBUG) @@ -232,7 +232,7 @@ def _check_ssh_keys_exist(): bool: True if both private and public keys exist, False otherwise """ key_dir = '/etc/ssh/auth_keys/soqemussh' - key_path = f'{key_dir}/id_ed25519' + key_path = f'{key_dir}/id_ecdsa' pub_key_path = f'{key_path}.pub' dest_dir = '/opt/so/saltstack/local/salt/libvirt/ssh/keys' dest_path = os.path.join(dest_dir, os.path.basename(pub_key_path)) @@ -250,7 +250,7 @@ def _setup_ssh_keys(): """ try: key_dir = '/etc/ssh/auth_keys/soqemussh' - key_path = f'{key_dir}/id_ed25519' + key_path = f'{key_dir}/id_ecdsa' pub_key_path = f'{key_path}.pub' # Check if keys already exist @@ -266,9 +266,9 @@ def _setup_ssh_keys(): os.makedirs(key_dir, exist_ok=True) os.chmod(key_dir, 0o700) - # Generate new ed25519 key pair + # Generate new ECDSA key pair using SECP256R1 curve log.info("Generating new SSH keys") - private_key = ed25519.Ed25519PrivateKey.generate() + private_key = ec.generate_private_key(ec.SECP256R1()) public_key = private_key.public_key() # Serialize private key @@ -540,7 +540,7 @@ def setup_environment(vm_name: str = 'sool9', disk_size: str = '220G', minion_id Notes: - Verifies Security Onion license - Downloads and validates Oracle Linux KVM image if needed - - Generates Ed25519 SSH keys if not present + - Generates ECDSA SSH keys if not present - Creates/recreates VM based on environment changes - Forces hypervisor configuration via highstate after successful setup (when minion_id is provided) @@ -765,7 +765,7 @@ def create_vm(vm_name: str, disk_size: str = '220G'): _set_ownership_and_perms(vm_dir, mode=0o750) # Read the SSH public key - pub_key_path = '/opt/so/saltstack/local/salt/libvirt/ssh/keys/id_ed25519.pub' + pub_key_path = '/opt/so/saltstack/local/salt/libvirt/ssh/keys/id_ecdsa.pub' try: with salt.utils.files.fopen(pub_key_path, 'r') as f: ssh_pub_key = f.read().strip() @@ -844,7 +844,7 @@ output: all: ">> /var/log/cloud-init.log" # configure interaction with ssh server -ssh_genkeytypes: ['ed25519', 'rsa'] +ssh_genkeytypes: ['ecdsa', 'rsa'] # set timezone for VM timezone: UTC @@ -1038,7 +1038,7 @@ def regenerate_ssh_keys(): Notes: - Validates Security Onion license - Removes existing keys if present - - Generates new Ed25519 key pair + - Generates new ECDSA key pair - Sets secure permissions (600 for private, 644 for public) - Distributes public key to required locations @@ -1048,7 +1048,7 @@ def regenerate_ssh_keys(): 2. Checks for existing SSH keys 3. Removes old keys if present 4. Creates required directories with secure permissions - 5. Generates new Ed25519 key pair + 5. Generates new ECDSA key pair 6. Sets appropriate file permissions 7. Distributes public key to required locations @@ -1067,7 +1067,7 @@ def regenerate_ssh_keys(): # Remove existing keys key_dir = '/etc/ssh/auth_keys/soqemussh' - key_path = f'{key_dir}/id_ed25519' + key_path = f'{key_dir}/id_ecdsa' pub_key_path = f'{key_path}.pub' dest_dir = '/opt/so/saltstack/local/salt/libvirt/ssh/keys' dest_path = os.path.join(dest_dir, os.path.basename(pub_key_path)) From c5db0a7195ced047e89bd54f33ce896dd6e13cd8 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Thu, 7 Aug 2025 15:02:45 -0400 Subject: [PATCH 301/315] more ed25519 to ecdsa --- salt/libvirt/ssh/files/config | 2 +- salt/libvirt/ssh/users.sls | 2 +- salt/manager/hypervisor.sls | 6 +++--- salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja | 2 +- setup/so-setup | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/salt/libvirt/ssh/files/config b/salt/libvirt/ssh/files/config index de6cb7b34..9b8f89442 100644 --- a/salt/libvirt/ssh/files/config +++ b/salt/libvirt/ssh/files/config @@ -1,2 +1,2 @@ Match user soqemussh - IdentityFile /etc/ssh/auth_keys/soqemussh/id_ed25519 + IdentityFile /etc/ssh/auth_keys/soqemussh/id_ecdsa diff --git a/salt/libvirt/ssh/users.sls b/salt/libvirt/ssh/users.sls index 173a3e095..8bbf2ca7e 100644 --- a/salt/libvirt/ssh/users.sls +++ b/salt/libvirt/ssh/users.sls @@ -46,7 +46,7 @@ create_soqemussh_user: soqemussh_pub_key: ssh_auth.present: - user: soqemussh - - source: salt://libvirt/ssh/keys/id_ed25519.pub + - source: salt://libvirt/ssh/keys/id_ecdsa.pub {% endif %} diff --git a/salt/manager/hypervisor.sls b/salt/manager/hypervisor.sls index 315775446..080d0699c 100644 --- a/salt/manager/hypervisor.sls +++ b/salt/manager/hypervisor.sls @@ -16,9 +16,9 @@ # Check if hypervisor environment has been set up {% set ssh_user_exists = salt['user.info']('soqemussh') %} -{% set ssh_keys_exist = salt['file.file_exists']('/etc/ssh/auth_keys/soqemussh/id_ed25519') and - salt['file.file_exists']('/etc/ssh/auth_keys/soqemussh/id_ed25519.pub') and - salt['file.file_exists']('/opt/so/saltstack/local/salt/libvirt/ssh/keys/id_ed25519.pub') %} +{% set ssh_keys_exist = salt['file.file_exists']('/etc/ssh/auth_keys/soqemussh/id_ecdsa') and + salt['file.file_exists']('/etc/ssh/auth_keys/soqemussh/id_ecdsa.pub') and + salt['file.file_exists']('/opt/so/saltstack/local/salt/libvirt/ssh/keys/id_ecdsa.pub') %} {% set base_image_exists = salt['file.file_exists']('/nsm/libvirt/boot/OL9U5_x86_64-kvm-b253.qcow2') %} {% set vm_files_exist = salt['file.directory_exists']('/opt/so/saltstack/local/salt/libvirt/images/sool9') and salt['file.file_exists']('/opt/so/saltstack/local/salt/libvirt/images/sool9/sool9.qcow2') and diff --git a/salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja b/salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja index 94cc85117..025e23d89 100644 --- a/salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja +++ b/salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja @@ -11,7 +11,7 @@ sool9_{{host}}: base_domain: sool9 ip_source: qemu-agent ssh_username: soqemussh - private_key: /etc/ssh/auth_keys/soqemussh/id_ed25519 + private_key: /etc/ssh/auth_keys/soqemussh/id_ecdsa sudo: True deploy_command: sh /tmp/.saltcloud-*/deploy.sh script_args: -r -F -x python3 stable 3006.9 diff --git a/setup/so-setup b/setup/so-setup index f955917bc..347a7165c 100755 --- a/setup/so-setup +++ b/setup/so-setup @@ -755,7 +755,7 @@ if ! [[ -f $install_opt_file ]]; then logCmd "salt-key -ya $MINION_ID" logCmd "salt-call saltutil.sync_all" # we need to sync the runner and generate the soqemussh user keys so that first highstate after license created - # doesnt have a state failure for soqemussh_pub_key source for id_ed25519.pub missing + # doesnt have a state failure for soqemussh_pub_key source for id_ecdsa.pub missing if [[ $is_manager || $is_managerhype ]]; then logCmd "salt-run saltutil.sync_all" logCmd "salt-run setup_hypervisor.regenerate_ssh_keys" From 9617da1791507d64302bf2e7b9a638832a8d3109 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Thu, 7 Aug 2025 16:13:59 -0400 Subject: [PATCH 302/315] remove managerhype from whiptail --- setup/so-whiptail | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/setup/so-whiptail b/setup/so-whiptail index 57bd10b8c..4c92f6a48 100755 --- a/setup/so-whiptail +++ b/setup/so-whiptail @@ -654,10 +654,9 @@ whiptail_install_type_dist_new() { Note: MANAGER is the recommended option for most users. MANAGERSEARCH should only be used in very specific situations. EOM - install_type=$(whiptail --title "$whiptail_title" --menu "$mngr_msg" 20 75 3 \ + install_type=$(whiptail --title "$whiptail_title" --menu "$mngr_msg" 20 75 2 \ "MANAGER" "New grid, requires separate search node(s) " \ "MANAGERSEARCH" "New grid, separate search node(s) are optional " \ - "MANAGERHYPE" "Manager with hypervisor - Security Onion Pro required " \ 3>&1 1>&2 2>&3 ) From ae0ffc4977eb560685022328d30564fc83320257 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Tue, 12 Aug 2025 09:32:42 -0400 Subject: [PATCH 303/315] 2.4.170 --- DOWNLOAD_AND_VERIFY_ISO.md | 22 ++++++++++---------- sigs/securityonion-2.4.170-20250812.iso.sig | Bin 0 -> 566 bytes 2 files changed, 11 insertions(+), 11 deletions(-) create mode 100644 sigs/securityonion-2.4.170-20250812.iso.sig diff --git a/DOWNLOAD_AND_VERIFY_ISO.md b/DOWNLOAD_AND_VERIFY_ISO.md index 2e0b2aa5d..e05cf651c 100644 --- a/DOWNLOAD_AND_VERIFY_ISO.md +++ b/DOWNLOAD_AND_VERIFY_ISO.md @@ -1,17 +1,17 @@ -### 2.4.160-20250625 ISO image released on 2025/06/25 +### 2.4.170-20250812 ISO image released on 2025/06/25 ### Download and Verify -2.4.160-20250625 ISO image: -https://download.securityonion.net/file/securityonion/securityonion-2.4.160-20250625.iso +2.4.170-20250812 ISO image: +https://download.securityonion.net/file/securityonion/securityonion-2.4.170-20250812.iso -MD5: 78CF5602EFFAB84174C56AD2826E6E4E -SHA1: FC7EEC3EC95D97D3337501BAA7CA8CAE7C0E15EA -SHA256: 0ED965E8BEC80EE16AE90A0F0F96A3046CEF2D92720A587278DDDE3B656C01C2 +MD5: 50ECAAD05736298452DECEAE074FA773 +SHA1: 1B1EB520DE61ECC4BF34E512DAFE307317D7666A +SHA256: 87D176A48A58BAD1C2D57196F999BED23DE9B526226E3754F0C166C866CCDC1A Signature for ISO image: -https://github.com/Security-Onion-Solutions/securityonion/raw/2.4/main/sigs/securityonion-2.4.160-20250625.iso.sig +https://github.com/Security-Onion-Solutions/securityonion/raw/2.4/main/sigs/securityonion-2.4.170-20250812.iso.sig Signing key: https://raw.githubusercontent.com/Security-Onion-Solutions/securityonion/2.4/main/KEYS @@ -25,22 +25,22 @@ wget https://raw.githubusercontent.com/Security-Onion-Solutions/securityonion/2. Download the signature file for the ISO: ``` -wget https://github.com/Security-Onion-Solutions/securityonion/raw/2.4/main/sigs/securityonion-2.4.160-20250625.iso.sig +wget https://github.com/Security-Onion-Solutions/securityonion/raw/2.4/main/sigs/securityonion-2.4.170-20250812.iso.sig ``` Download the ISO image: ``` -wget https://download.securityonion.net/file/securityonion/securityonion-2.4.160-20250625.iso +wget https://download.securityonion.net/file/securityonion/securityonion-2.4.170-20250812.iso ``` Verify the downloaded ISO image using the signature file: ``` -gpg --verify securityonion-2.4.160-20250625.iso.sig securityonion-2.4.160-20250625.iso +gpg --verify securityonion-2.4.170-20250812.iso.sig securityonion-2.4.170-20250812.iso ``` The output should show "Good signature" and the Primary key fingerprint should match what's shown below: ``` -gpg: Signature made Wed 25 Jun 2025 10:13:33 AM EDT using RSA key ID FE507013 +gpg: Signature made Fri 08 Aug 2025 06:24:56 PM EDT using RSA key ID FE507013 gpg: Good signature from "Security Onion Solutions, LLC " gpg: WARNING: This key is not certified with a trusted signature! gpg: There is no indication that the signature belongs to the owner. diff --git a/sigs/securityonion-2.4.170-20250812.iso.sig b/sigs/securityonion-2.4.170-20250812.iso.sig new file mode 100644 index 0000000000000000000000000000000000000000..df29c07b52de66ebd153c31a66ed6f44888ed7f0 GIT binary patch literal 566 zcmV-60?GY}0y6{v0SEvc79j-41gSkXz6^6dp_W8^5Ma0dP;e6k0%(?bH~5PT3| zxBgIY6OMZi|9c42+U)G%bR9qJ+x;7VidQ}2%)OCKP;{%ny8AXNqr#E^ z{z+v02l;K>WQ%rt!yQ<`*L1LfATKOPXvrJhkaVa{#4BvQ8ze%F(X(Jec zjsF(|lLOTUVf zLs#JgYHT~~pGp`UerUeTH}OfPWT2dD)&F-pa+nsu=T03t3R6YehVjO&ji2wIS?RN< zsDOkfs@!CZpJu?IQas<&k*!#uY=F zrt=PAT3}yFD#g4qzPnwHr0EWq6kBB;?r+4VUNxe&nhs6LB4_6m&9A+WiCY_Nu}rv8 z4Nm#=2vq30npWr6^ilaoYZA*ux)b}p2a9?4ls9| Date: Tue, 12 Aug 2025 09:40:18 -0400 Subject: [PATCH 304/315] 2.4.170 --- DOWNLOAD_AND_VERIFY_ISO.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DOWNLOAD_AND_VERIFY_ISO.md b/DOWNLOAD_AND_VERIFY_ISO.md index e05cf651c..6b966957c 100644 --- a/DOWNLOAD_AND_VERIFY_ISO.md +++ b/DOWNLOAD_AND_VERIFY_ISO.md @@ -1,4 +1,4 @@ -### 2.4.170-20250812 ISO image released on 2025/06/25 +### 2.4.170-20250812 ISO image released on 2025/08/12 ### Download and Verify From 6381444fdc3cb37e1ad9d5bb92b5dec049270e8d Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Tue, 12 Aug 2025 10:58:11 -0400 Subject: [PATCH 305/315] Update VERSION --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 032d0bb01..1ff799fad 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.4.170 +2.4.180 From d02093295b8ca8306376d2a80a4824e559a06d00 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Tue, 12 Aug 2025 10:59:17 -0400 Subject: [PATCH 306/315] Update 2-4.yml --- .github/DISCUSSION_TEMPLATE/2-4.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/DISCUSSION_TEMPLATE/2-4.yml b/.github/DISCUSSION_TEMPLATE/2-4.yml index dca40818a..273430e7d 100644 --- a/.github/DISCUSSION_TEMPLATE/2-4.yml +++ b/.github/DISCUSSION_TEMPLATE/2-4.yml @@ -30,6 +30,7 @@ body: - 2.4.150 - 2.4.160 - 2.4.170 + - 2.4.180 - Other (please provide detail below) validations: required: true From baf0f7ba95dfdfc41187d818bd1ceecea82ef877 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Tue, 12 Aug 2025 14:08:15 -0400 Subject: [PATCH 307/315] firewall allow hypervisor for managersearch and standalone --- salt/firewall/defaults.yaml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/salt/firewall/defaults.yaml b/salt/firewall/defaults.yaml index 9caaf725a..0c43b8c0b 100644 --- a/salt/firewall/defaults.yaml +++ b/salt/firewall/defaults.yaml @@ -909,6 +909,15 @@ firewall: - elastic_agent_control - elastic_agent_data - elastic_agent_update + hypervisor: + portgroups: + - yum + - docker_registry + - influxdb + - elastic_agent_control + - elastic_agent_data + - elastic_agent_update + - sensoroni customhostgroup0: portgroups: [] customhostgroup1: @@ -961,6 +970,9 @@ firewall: desktop: portgroups: - salt_manager + hypervisor: + portgroups: + - salt_manager self: portgroups: - syslog @@ -1113,6 +1125,15 @@ firewall: - elastic_agent_control - elastic_agent_data - elastic_agent_update + hypervisor: + portgroups: + - yum + - docker_registry + - influxdb + - elastic_agent_control + - elastic_agent_data + - elastic_agent_update + - sensoroni customhostgroup0: portgroups: [] customhostgroup1: @@ -1168,6 +1189,9 @@ firewall: desktop: portgroups: - salt_manager + hypervisor: + portgroups: + - salt_manager self: portgroups: - syslog From c1a5c2b2d1093e216312eb185c05237bc02bf65b Mon Sep 17 00:00:00 2001 From: reyesj2 <94730068+reyesj2@users.noreply.github.com> Date: Tue, 12 Aug 2025 14:39:35 -0500 Subject: [PATCH 308/315] set elasticfleet aritifact registry artifact file permissions --- salt/elasticfleet/artifact_registry.sls | 3 +++ salt/elasticfleet/config.sls | 3 +++ salt/elasticfleet/enabled.sls | 2 ++ 3 files changed, 8 insertions(+) diff --git a/salt/elasticfleet/artifact_registry.sls b/salt/elasticfleet/artifact_registry.sls index 565bdbb46..36481799d 100644 --- a/salt/elasticfleet/artifact_registry.sls +++ b/salt/elasticfleet/artifact_registry.sls @@ -9,3 +9,6 @@ fleetartifactdir: - user: 947 - group: 939 - makedirs: True + - recurse: + - user + - group diff --git a/salt/elasticfleet/config.sls b/salt/elasticfleet/config.sls index f347a3c80..3bdd495c1 100644 --- a/salt/elasticfleet/config.sls +++ b/salt/elasticfleet/config.sls @@ -9,6 +9,9 @@ {% from 'elasticfleet/map.jinja' import ELASTICFLEETMERGED %} {% set node_data = salt['pillar.get']('node_data') %} +include: + - elasticfleet.artifact_registry + # Add EA Group elasticfleetgroup: group.present: diff --git a/salt/elasticfleet/enabled.sls b/salt/elasticfleet/enabled.sls index 5a52f3a41..0ca54ccb8 100644 --- a/salt/elasticfleet/enabled.sls +++ b/salt/elasticfleet/enabled.sls @@ -67,6 +67,8 @@ so-elastic-fleet-auto-configure-artifact-urls: elasticagent_syncartifacts: file.recurse: - name: /nsm/elastic-fleet/artifacts/beats + - user: 947 + - group: 947 - source: salt://beats {% endif %} From 3c5a03d7b603683214e03241263e5fb20e549c90 Mon Sep 17 00:00:00 2001 From: reyesj2 <94730068+reyesj2@users.noreply.github.com> Date: Tue, 12 Aug 2025 15:35:30 -0500 Subject: [PATCH 309/315] fix /nsm/pcap no group/user ownership --- salt/pcap/init.sls | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/salt/pcap/init.sls b/salt/pcap/init.sls index 20b9bc2b7..dffeac85c 100644 --- a/salt/pcap/init.sls +++ b/salt/pcap/init.sls @@ -18,11 +18,19 @@ include: # This directory needs to exist regardless of whether STENO is enabled or not, in order for # Sensoroni to be able to look at old steno PCAP data + +# if stenographer has never run as the pcap engine no 941 user is created, so we use socore as a placeholder. +# /nsm/pcap is empty until stenographer is used as pcap engine +{% set pcap_id = 941 %} +{% set user_list = salt['user.list_users']() %} +{% if 'stenographer' not in user_list %} +{% set pcap_id = 939 %} +{% endif %} pcapdir: file.directory: - name: /nsm/pcap - - user: 941 - - group: 941 + - user: {{ pcap_id }} + - group: {{ pcap_id }} - makedirs: True pcapoutdir: From a19b99268df5971bca58a54fb7b8ea0fc313ff27 Mon Sep 17 00:00:00 2001 From: reyesj2 <94730068+reyesj2@users.noreply.github.com> Date: Tue, 12 Aug 2025 15:44:50 -0500 Subject: [PATCH 310/315] don't create unused zeek home directory --- salt/zeek/config.sls | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/salt/zeek/config.sls b/salt/zeek/config.sls index 761c6f7d3..b3ea97507 100644 --- a/salt/zeek/config.sls +++ b/salt/zeek/config.sls @@ -22,7 +22,8 @@ zeek: user.present: - uid: 937 - gid: 937 - - home: /home/zeek + - home: /opt/so/conf/zeek + - createhome: False # Create some directories zeekpolicydir: From 50b34a116aa566cc355fc3a3c325a3fb2b48cfde Mon Sep 17 00:00:00 2001 From: reyesj2 <94730068+reyesj2@users.noreply.github.com> Date: Thu, 14 Aug 2025 15:02:59 -0500 Subject: [PATCH 311/315] disable rpm verify hash, salt packages are modified before install for salt bootstrap process --- salt/stig/files/sos-oscap.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/salt/stig/files/sos-oscap.xml b/salt/stig/files/sos-oscap.xml index f1e17bcbd..46e80e412 100644 --- a/salt/stig/files/sos-oscap.xml +++ b/salt/stig/files/sos-oscap.xml @@ -886,7 +886,7 @@ DISA STIG for Oracle Linux 9 V1R1. - + @@ -1195,7 +1195,7 @@ DISA STIG for Oracle Linux 9 V1R1. - + @@ -1473,7 +1473,7 @@ standard DISA STIG for Oracle Linux 9 profile. - + @@ -1782,7 +1782,7 @@ standard DISA STIG for Oracle Linux 9 profile. - + From f09eff530ebaf0733e828a9ff566db931b149b30 Mon Sep 17 00:00:00 2001 From: reyesj2 <94730068+reyesj2@users.noreply.github.com> Date: Thu, 14 Aug 2025 15:17:01 -0500 Subject: [PATCH 312/315] profile upd --- salt/stig/files/sos-oscap.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/salt/stig/files/sos-oscap.xml b/salt/stig/files/sos-oscap.xml index 46e80e412..4e699dedf 100644 --- a/salt/stig/files/sos-oscap.xml +++ b/salt/stig/files/sos-oscap.xml @@ -1232,7 +1232,7 @@ DISA STIG for Oracle Linux 9 V1R1. - + @@ -1818,7 +1818,7 @@ standard DISA STIG for Oracle Linux 9 profile. - + From af1fe86586e2655bde2e729ec79279239fa192de Mon Sep 17 00:00:00 2001 From: reyesj2 <94730068+reyesj2@users.noreply.github.com> Date: Fri, 15 Aug 2025 15:16:36 -0500 Subject: [PATCH 313/315] update chrony config --- salt/ntp/chrony.conf | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/salt/ntp/chrony.conf b/salt/ntp/chrony.conf index 46432915f..551bd5ebe 100644 --- a/salt/ntp/chrony.conf +++ b/salt/ntp/chrony.conf @@ -1,7 +1,7 @@ # NTP server list {%- for SERVER in NTPCONFIG.servers %} -server {{ SERVER }} iburst +server {{ SERVER }} iburst maxpoll 10 {%- endfor %} # Config options @@ -9,3 +9,5 @@ driftfile /var/lib/chrony/drift makestep 1.0 3 rtcsync logdir /var/log/chrony +port 0 +cmdport 0 \ No newline at end of file From 292e1ad782a94a5ad778dedf6e10324aa352d64a Mon Sep 17 00:00:00 2001 From: reyesj2 <94730068+reyesj2@users.noreply.github.com> Date: Fri, 15 Aug 2025 15:19:31 -0500 Subject: [PATCH 314/315] use chrony system default --- salt/stig/files/sos-oscap.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/salt/stig/files/sos-oscap.xml b/salt/stig/files/sos-oscap.xml index 4e699dedf..f3f9f446f 100644 --- a/salt/stig/files/sos-oscap.xml +++ b/salt/stig/files/sos-oscap.xml @@ -1428,7 +1428,7 @@ DISA STIG for Oracle Linux 9 V1R1. - + @@ -2014,7 +2014,7 @@ standard DISA STIG for Oracle Linux 9 profile. - + From f7a1a3a1725aa945cde7e1f76c00db34cc6b8305 Mon Sep 17 00:00:00 2001 From: reyesj2 <94730068+reyesj2@users.noreply.github.com> Date: Fri, 15 Aug 2025 16:07:54 -0500 Subject: [PATCH 315/315] gui / nongui profile --- salt/stig/enabled.sls | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/salt/stig/enabled.sls b/salt/stig/enabled.sls index c35c91a55..0e5448f7d 100644 --- a/salt/stig/enabled.sls +++ b/salt/stig/enabled.sls @@ -13,7 +13,11 @@ {% from 'allowed_states.map.jinja' import allowed_states %} {% if sls.split('.')[0] in allowed_states and GLOBALS.os == 'OEL' %} {% if 'stg' in salt['pillar.get']('features', []) %} - {% set OSCAP_PROFILE_NAME = 'xccdf_org.ssgproject.content_profile_stig' %} + {% if GLOBALS.role != 'so-desktop' %} + {% set OSCAP_PROFILE_NAME = 'xccdf_org.ssgproject.content_profile_stig' %} + {% else %} + {% set OSCAP_PROFILE_NAME = 'xccdf_org.ssgproject.content_profile_stig_gui' %} + {% endif %} {% set OSCAP_PROFILE_LOCATION = '/opt/so/conf/stig/sos-oscap.xml' %} {% set OSCAP_OUTPUT_DIR = '/opt/so/log/stig' %} oscap_packages: @@ -49,7 +53,7 @@ update_stig_profile: {% if not salt['file.file_exists'](OSCAP_OUTPUT_DIR ~ '/pre-oscap-report.html') %} run_initial_scan: cmd.run: - - name: 'oscap xccdf eval --profile {{ OSCAP_PROFILE_NAME }} --results {{ OSCAP_OUTPUT_DIR }}/pre-oscap-results.xml --report {{ OSCAP_OUTPUT_DIR }}/pre-oscap-report.html {{ OSCAP_PROFILE_LOCATION }}' + - name: 'oscap xccdf eval --profile {{ OSCAP_PROFILE_NAME }} --results {{ OSCAP_OUTPUT_DIR }}/pre-oscap-results.xml --report {{ OSCAP_OUTPUT_DIR }}/pre-oscap-report.html /usr/share/xml/scap/ssg/content/ssg-ol9-ds.xml' - success_retcodes: - 2 {% endif %}

+ + + +
+ Skip to content + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+ + + + + +
+ + + + + + + + + +
+
+
+ + + + + + + + + + + + +
+ +
+ +
+ +
+ + + + / + + securityonion + + + Public +
+ + +
+ +
+ + +
+
+ +
+
+ + + + +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + +

Latest commit

 

History

History
152 KB

certifi-2022.12.7-py3-none-any.whl

File metadata and controls

152 KB
+
+ + + + +
+ +
+ +
+
+ +
+ +
+

Footer

+ + + + +
+
+ + + + + © 2024 GitHub, Inc. + +
+ + +
+
+ + + + + + + + + + + + + + + + + + + +